diff options
author | Jamie Boisture <jboisture@jboisture-laptop.(none)> | 2009-07-24 22:00:00 (GMT) |
---|---|---|
committer | Jamie Boisture <jboisture@jboisture-laptop.(none)> | 2009-07-24 22:00:00 (GMT) |
commit | ca210cf65d417c9d6710cde14560233f4d847c77 (patch) | |
tree | 8e15d5a4586d8957eac55c91268b8fa87331b3d0 | |
parent | 0d622e6c2fe08c9d06ac03aa6d28e49b2f66da21 (diff) |
added the gasp library to /library/pippy
-rw-r--r-- | library/pippy/gasp/__init__.py | 2 | ||||
-rw-r--r-- | library/pippy/gasp/api.py | 534 | ||||
-rw-r--r-- | library/pippy/gasp/backend.py | 619 | ||||
-rw-r--r-- | library/pippy/gasp/color.py | 145 |
4 files changed, 1300 insertions, 0 deletions
diff --git a/library/pippy/gasp/__init__.py b/library/pippy/gasp/__init__.py new file mode 100644 index 0000000..15651e6 --- /dev/null +++ b/library/pippy/gasp/__init__.py @@ -0,0 +1,2 @@ +from api import * +import color diff --git a/library/pippy/gasp/api.py b/library/pippy/gasp/api.py new file mode 100644 index 0000000..9a88ce7 --- /dev/null +++ b/library/pippy/gasp/api.py @@ -0,0 +1,534 @@ +import backend +import math +import random +import time + +# diffrent update_when values +NOTHING = "Nothing" +MOUSE_PRESSED = "Mouse_Pressed" +KEY_PRESSED = "Key_Pressed" + +#============================ SCREEN FUNCTIONS ============================== + +class Screen: + """ + Defines the graphics window in which objects can be created + """ + def __init__(self, width, height, + title="Gasp", background=(255,255,255), back_end=None): + global backend + backend = back_end + self.width = width + self.height = height + self.title = title + self.background = backend.color_convert(background) + + # backend.check_screen_atts(self) # checks the variables + backend.create_screen(self) + + + +def begin_graphics(width=-1, height=-1, title="Gasp", + background=(255,255,255), back_end=backend): + """ + Initialize a graphics window in GASP + """ + global screen + screen = Screen(width, height, title, background, back_end) + +def end_graphics(): + """ + Close the graphics window + """ + backend.end() + +def clear_screen(): + """ + Removes all objects from the graphics window + """ + backend.clear_screen() + + +def remove_from_screen(obj): + """ + Removes a specified object from the graphics window + """ + backend.remove(obj) + +#================================ Point ===================================== + +class Point: + """ + Creates a point object with an x and y attribute + """ + def __init__(self, *args): + if len(args) == 1: + self.x, self.y = args[0] + else: + self.x, self.y = args + + def __str__(self): + return "A Point instance at (%i, %i) \n" %(self.x, self.y) + + def distance(self, other): + ''' The distance between two points ''' + return math.sqrt(float((other.x - self.x))**2 + + (float(other.y - self.y))**2) + + +def make_it_a_point(point): + """ + Takes something and makes it into a point if it isn't one already + """ + if isinstance(point, Point): + return point + else: + return Point(point) + + + +class Shape: + def __init__(self, center, filled=False, color=(0,0,0), thickness=1): + self.center = make_it_a_point(center) + self.filled = filled + self.color = backend.color_convert(color) + self.thickness = thickness + self.rot = 0 + self.key = time.time()*random.random() + + def move_by(self,x,y): + if self.on_screen: + self.topleft = (self.topleft[0]+x,self.topleft[1]+y) + self.center = Point(self.center.x+x,self.center.y+y) + else: move_by(self,x,y) + + def move_to(self,pos): + if self.on_screen: + x,y = pos[0]-self.center.x,pos[1]-self.center.y + self.topleft = (self.topleft[0]+x,self.topleft[1]+y) + self.center = Point(self.center.x+x,self.center.y+y) + else: move_to(self,pos) + + def draw(self,context): + context.save() + x,y = backend.flip_coords(self.topleft) + context.translate(x,y-self.surface.get_height()) + if self.rot != 0: + context.translate(self.surface.get_width()/2,self.surface.get_height()/2) + context.rotate(self.rot) + context.translate(-1*self.surface.get_width()/2,-1*self.surface.get_height()/2) + context.set_source_surface(self.surface) + context.paint() + context.restore() + +class Plot(Shape): + """ + Allows screen objects to be placed in the graphics window + """ + def __init__(self, pos, color=(0,0,0), size=1): + self.center = make_it_a_point(pos) + self.color = color + self.size = size + self.key = time.time()*random.random() + self.on_screen = False + screen.action_objects.put([["plot",self],"new object"]) + + +class Line(Shape): + """ + Allows the creation of lines in the graphics window + """ + def __init__(self, start, end, color=(0,0,0),thickness=1): + self.start = make_it_a_point(start) + self.end = make_it_a_point(end) + self.center = make_it_a_point(((start[0]+end[0])/2,(start[1]+end[1])/2)) + self.color = backend.color_convert(color) + self.thickness=thickness + self.key = time.time()*random.random() + self.on_screen = False + screen.action_objects.put([["line",self],"new object"]) + + def move_by(self,x,y): + if self.on_screen: + self.topleft = (self.topleft[0]+x,self.topleft[1]+y) + self.center = Point(self.center.x+x,self.center.y+y) + else: move_by(self,x,y) + + def move_to(self,pos): + if self.on_screen: + x,y = pos[0]-self.center.x,pos[1]-self.center.y + self.topleft = (self.topleft[0]+x,self.topleft[1]+y) + self.center = Point(self.center.x+x,self.center.y+y) + else: move_to(self,pos) + + def __repr__(self): + return "A Line instance from (%d, %d) to (%d, %d)" % \ + (self.start.x, self.start.y, self.end.x, self.end.y) + +class Box(Shape): + """ + Allows the creation of squares and rectangles in the graphics window + """ + def __init__(self, lower_left_corner, width, height, + filled=False, color=(0,0,0), thickness=1): + self.center = Point((int(lower_left_corner[0] + width/2.0), + int(lower_left_corner[1] + height/2.0))) + self.height = height + self.width = width + self.on_screen = False + Shape.__init__(self, self.center, filled, color, thickness) + screen.action_objects.put([["box",self],"new object"]) + + def move_to(self,pos): + if self.on_screen: + x,y = pos[0]-self.topleft[0],pos[1]-self.topleft[1] + self.topleft = (self.topleft[0]+x,self.topleft[1]+y) + self.center = Point(self.center.x+x,self.center.y+y) + else: + move_to(self,pos) + + def __repr__(self): + return "Box instance at (%d, %d) with width %d and height %d" % \ + (self.center.x, self.center.y, self.width, self.height) + +class Polygon(Shape): + """ + Allows the creation of polygons in the graphics window + """ + def __init__(self, points, filled=False, color=(0,0,0),thickness=1): + self.thickness = thickness + self.points = points + x_values = [] + y_values = [] + for point in self.points: + x_values.append(point[0]) + y_values.append(point[1]) + self.height = (max(y_values) - min(y_values))+self.thickness*2 + self.width = (max(x_values) - min(x_values))+self.thickness*2 + self.topleft = (min(x_values)-self.thickness, min(y_values)-self.thickness) + self.center = Point(self.width/2 + min(x_values), self.height/2 + + min(y_values)) + self.on_screen = False + Shape.__init__(self, self.center, filled, color) + screen.action_objects.put([["polygon",self],"new object"]) + + def __repr__(self): + return "Polygon instance at (%i, %i) with the points:\n %t" % \ + (self.center.x , self.center.y, self.points) + +class Circle(Shape): + """ + Allows the creation of circles in the graphics window + """ + def __init__(self, center, radius, + filled=False, color=(0,0,0), thickness=1): + Shape.__init__(self, center, filled, color, thickness) + self.radius = radius + self.on_screen = False + screen.action_objects.put([["circle",self],"new object"]) + #backend.create_circle(self) + + def __repr__(self): + return "Circle instance at (%d, %d) with radius %d" % \ + (self.center.x, self.center.y, self.radius) + +class Arc(Shape): + """ + Allows the creation of arcs in the graphics window + """ + def __init__(self, center, radius, start_angle, end_angle, + filled=False, color=(0,0,0), thickness=1): + Shape.__init__(self, center, filled, color, thickness) + self.radius = radius + self.start_angle = 360-start_angle + self.end_angle = 360-end_angle + self.on_screen = False + screen.action_objects.put([["arc",self],"new object"]) + + def __repr__(self): + return "Arc instance at (%d, %d) with start angle %d and end angle %d" \ + % (self.center.x, self.center.y, self.start_angle, self.end_angle) + + + +class Oval(Shape): + """ + Allows the creation of circles in the graphics window + """ + def __init__(self, center, width, height, + filled=False, color=(0,0,0), thickness=1): + Shape.__init__(self, center, filled, color, thickness) + self.width = width + self.height = height + self.on_screen = False + screen.action_objects.put([["oval",self],"new object"]) + + def __repr__(self): + return "Oval instance at (%d, %d) with width %d and height %d" % \ + (self.center.x, self.center.y, self.width, self.height) + +class Image(Shape): + """ + Allows the placing of images in the graphics window + """ + def __init__(self, file_path, center, width=0, height=0): + self.path_name = file_path + self.center = Point(backend.flip_coords(center)) + self.width = width + self.height = height + self.key = time.time()*random.random() + self.on_screen = False + screen.action_objects.put([["image",self],"new object"]) + + def draw(self,context): + context.save() + context.translate(*self.topleft) + context.translate(self.width/2,self.height/2) + context.rotate(self.rot) + context.translate(-1*self.width/2,-1*self.height/2) + context.save() + context.scale(self.scale[0],self.scale[1]) + context.set_source_pixbuf(self.pixbuf,0,0) + context.paint() + context.restore() + context.restore() + + def move_by(self,x,y): + if self.on_screen: + self.topleft = (self.topleft[0]+x,self.topleft[1]-y) + self.center = Point(self.center.x+x,self.center.y-y) + else: + move_by(self,x,y) + + def move_to(self,pos): + if self.on_screen: + x,y = pos[0]-self.center.x,pos[1]-self.center.y + self.topleft = (self.topleft[0]+x,self.topleft[1]-y) + self.center = Point(self.center.x+x,self.center.y-y) + else: + move_to(self,pos) + + def __repr__(self): + return "Image instance at (%i, %i) from the file %s" % \ + (self.center.x, self.center.y, self.path_name) + + +def move_to(obj, pos): + """ + Moves a screen object to a specified location + """ + screen.action_objects.put([obj,"move_to",pos]) + + +def move_by(obj, dx, dy): + """ + Moves a screen object by specified X and Y amounts + """ + screen.action_objects.put([obj,"move_by",(dx,dy)]) + +def get_text_length(text): + return backend.get_text_length(text) + + +def rotate_to(obj, angle): + """ + Rotates a screen object to a specified angle + """ + screen.action_objects.put([obj,"rotate_to",math.radians(angle)]) + + +def rotate_by(obj, angle): + """ + Rotates a screen object by a specified angle + """ + screen.action_objects.put([obj,"rotate_by",math.radians(angle)]) + + +# =============================== Text ====================================== + +class Text(Shape): + """ + Allows the creation of text in the graphics window + """ + def __init__(self, text, pos, color=(0,0,0), size=12): + self.text = text + self.color = backend.color_convert(color) + self.size = size + self.pos = backend.flip_coords(pos) + self.key = time.time()*random.random() + self.on_screen = False + screen.action_objects.put([["text",self],"new object"]) + #screen.action_objects.put(obj) + #screen.objects.append(obj) + + def draw(self, context): + context.save() + context.move_to(*self.pos) + if self.rot != 0: + context.rotate(self.rot) + context.set_source_rgb(*self.color) + context.set_font_size(self.size) + context.show_text(self.text) + context.restore() + + + def move_to(self,pos): + self.pos = backend.flip_coords(pos) + move_to(self,pos) + + def move_by(self,dx,dy): + self.pos = (self.pos[0]+dx,self.pos[1]-dy) + move_by(self,dx,dy) + +# ============================ Text Entry ================================== + +def Text_Entry(message="Enter Text:", pos=(0,0), color=(0,0,0), size=12): + entry = backend.Entry(message,pos,color,size) + return entry.entry + + +"""# =============================== Sound ===================================== + +class Sound: + "" + Allows the creation and playback of sounds + "" + def __init__(self, file_path): + self.path = file_path + self.filename = ''.join(file_path.split('.')[:-1]).split('/')[-1] + + def play(self): + backend.play_sound(self) + + def stop(self): + backend.stop_sound(self) + + +def create_sound(file_path): + "" + Creates a sound object from a file + "" + return Sound(file_path) + + +def play_sound(sound): + "" + Starts to play a specified sound object + "" + sound.play() + + +def stop_sound(sound): + "" + Stops the playback of a specified sound object + "" + sound.stop()""" + +# =========================== Event Functions ============================== + +def mouse_position(): + """ + Returns a Point() at the mouse's current position + """ + pos = backend.mouse_pos() + return backend.flip_coords((int(pos[0]),int(pos[1]))) + + +def mouse_buttons(): + """ + Returns a dictionary of the current state of the mouse buttons + """ + return backend.mouse_state() + + +def keys_pressed(): + """ + Returns a list of all of the keys being pressed + """ + return backend.keys() + +def key_pressed(key): + return key in backend.keys() + +def screen_size(): + return backend.get_screen_size() + +# ============================= GASP TOOLS ================================== + +def screen_shot(filename="screen_shot"): + """ + Saves a screenshot to a specified file name + """ + backend.screen_picture(filename) + +def random_between(num1, num2): + if (num1 == num2): + return num1 + elif (num1 > num2): + return random.randint(num2, num1) + else: + return random.randint(num1, num2) + +read_string = raw_input + + +def read_number(prompt='Please enter a number: '): + """ + Prompts the user to enter a number + """ + while True: + try: + result = eval(raw_input(prompt)) + if isinstance(result, (float, int)): + return result + print "But that wasn't a number!" + except: + print "But that wasn't a number!" + + +def read_yesorno(prompt='Yes or no? '): + """ + Asks the user to enter yes or no + """ + while True: + result = raw_input(prompt) + result = result.lower() + if result=='yes' or result=='y': return True + if result=='no' or result=='n': return False + print "Please answer yes or no." + +# =============================== Time ===================================== + +def set_speed(speed): + """ + Sets program frame rate in frames per second + """ + backend.set_frame_rate(speed) + + +def update_when(event_type): + """ + Event Types include + 'key_pressed' + 'mouse_clicked' + 'next_tick' + """ + if event_type == "key_pressed": + return backend.update_when(event_type) + else: backend.update_when(event_type) + +def sleep(duration): + """ + Sleeps for a length of time + """ + backend.sleep(duration) + + +# ============================== main ===================================== + +if __name__ == "__main__": + """ + If api.py is run independently, this runs the test suite + """ + import doctest + doctest.testmod() diff --git a/library/pippy/gasp/backend.py b/library/pippy/gasp/backend.py new file mode 100644 index 0000000..1118bbf --- /dev/null +++ b/library/pippy/gasp/backend.py @@ -0,0 +1,619 @@ +import os +import sys +import math +import multiprocessing +import gobject +import time +import gtk +import cairo + + +# diffrent update_when values +NOTHING = "Nothing" +MOUSE_PRESSED = "Mouse_Pressed" +KEY_PRESSED = "Key_Pressed" +screen = None + +#============================= SCREEN FUNCTIONS ================================ + +def check_screen_atts(screen_obj): + + try: # checks width attribute + width = int(screen_obj.width) + self.width = width + except: + raise GaspException("Width is not a viable type. Width = %d " % screen_obj.width) + + try: # checks height attribute + height = int(height) + self.height = height + except: + raise GaspException("Height is not a vaiable type. Height = %d" % screen_obj.height) + + +def shutdown(type, value, traceback): + end() + sys.__excepthook__(type, value, traceback) + + +def create_screen(screen_obj): # takes a Screen() objects. + global screen + #create the screen obj + screen = screen_obj + + #create the window and set its size and title + screen.window = gtk.Window() + screen.window.set_title(screen.title) + if screen.width < 0 or screen.height < 0: + screen.window.maximize() + screen.width = screen.window.get_screen().get_width() + screen.height = screen.window.get_screen().get_height() + screen.window.set_default_size(screen.width, screen.height) + screen.window.set_resizable(False) + + #create the drawing area + screen.drawing_area = gtk.DrawingArea() + screen.window.add(screen.drawing_area) + screen.drawing_area.set_size_request(screen.width,screen.height) + screen.drawing_area.show() + + screen.frame_rate = 40 + screen.last_tick = time.time() + + #set up the event handling + screen.drawing_area.set_events( gtk.gdk.EXPOSURE_MASK + | gtk.gdk.BUTTON1_MOTION_MASK + | gtk.gdk.BUTTON_PRESS_MASK + | gtk.gdk.BUTTON_RELEASE_MASK + | gtk.gdk.POINTER_MOTION_MASK + | gtk.gdk.POINTER_MOTION_HINT_MASK) + screen.drawing_area.connect("motion_notify_event", mouse_move) + screen.drawing_area.connect('button-press-event', mouse_press) + screen.drawing_area.connect('button-release-event', mouse_release) + screen.window.connect("key-press-event",key_pressed) + screen.window.connect("key-release-event",key_released) + screen.window.connect('delete-event', quit) + screen.keys_pressed = [] + screen.mouse_pos = (-1,-1) + screen.mouse_state = {"left":0,"middle":0,"right":0} + screen.mouse_buttons = ["left","middle","right"] + + #set the window icon and show the window + screen.window.show() + + #create the buffer to draw to + screen.buffer = gtk.gdk.Pixmap(screen.drawing_area.window, screen.width, screen.height) + screen.gc = gtk.gdk.GC(screen.buffer) + screen.objects = [] + screen.action_objects = multiprocessing.Queue() + screen.keys = multiprocessing.Queue() + screen.process = multiprocessing.current_process() + screen.mouse = multiprocessing.Queue() + + #start the thread that will update the gui by calling main_iteration + screen.updater = Updater(screen) + + screen.screenshot = False + screen.filename = "" + screen.update_when = NOTHING + screen.update1 = multiprocessing.Queue() + screen.update2 = multiprocessing.Queue() + #if this is called to often key and mouse events will be slow + screen.sprites = 0 + + screen.text_entry = None + screen.entry_done = multiprocessing.Queue() + screen.updater.daemon = True + screen.updater.start() + +def quit(widget=None, event=None): + screen.updater.running = False + for queue in [screen.action_objects, screen.keys, screen.mouse, screen.update1, screen.update2, screen.entry_done]: + while not queue.empty(): + queue.get() + os.popen("kill " +str(os.getppid())) + #screen.process.terminate() + +class Updater( multiprocessing.Process ): + """thread that handles the updateing of the GUI + This thread does not update the graphics""" + def __init__(self,screen): + self.screen = screen + multiprocessing.Process.__init__(self) + self.objects = [] + self.sprites = 0 + + def create_obj(self,obj): + if obj[0] == "circle": + create_circle(obj[1]) + self.objects.append(obj[1]) + elif obj[0] == "box": + create_box(obj[1]) + self.objects.append(obj[1]) + elif obj[0] == "plot": + plot(obj[1]) + self.objects.append(obj[1]) + elif obj[0] == "line": + create_line(obj[1]) + self.objects.append(obj[1]) + elif obj[0] == "polygon": + create_polygon(obj[1]) + self.objects.append(obj[1]) + elif obj[0] == "arc": + create_arc(obj[1]) + self.objects.append(obj[1]) + elif obj[0] == "oval": + create_oval(obj[1]) + self.objects.append(obj[1]) + elif obj[0] == "image": + create_image(obj[1]) + self.objects.append(obj[1]) + elif obj[0] == "text": + create_text(obj[1]) + self.objects.append(obj[1]) + + def update(self,widget=None, event=None): + self.check_queues() + if not self.running: return False + context = self.screen.buffer.cairo_create() #create a cairo context the draw to buffer + #draw background + context.set_source_rgb(*self.screen.background) + context.rectangle(0, 0, *self.screen.drawing_area.window.get_size()) + context.fill() + #draw all of the objects on screen + if screen.text_entry: + screen.text_entry.draw(context) + else: + for i in self.objects: + i.draw(context) + #take a screenshot it must be hear because it requires an active cairo context + if self.screen.screenshot: + print "taking screen shot" + self.screen.screenshot = False + surf = context.get_target() + surf.write_to_png(self.screen.filename) + #draw the buffer onto the actual drawing area + self.screen.drawing_area.window.draw_drawable(self.screen.gc,self.screen.buffer,0,0,0,0,-1,-1,) + #return True + #make sure that the number of sprites on screen hasn't changed + if self.sprites == len(self.objects): + return True + #if the number of sprites has changed it will end this time out + #and begin a new one with more or less time difference depending + #on the number of sprites on screen + #this makes sure it is not updated to often + if self.sprites != len(self.objects): + gobject.timeout_add(40+len(self.objects)/10,self.update) + self.sprites = len(self.objects) + return False + + def check_queues(self): + while not self.screen.update1.empty(): + self.screen.update_when = self.screen.update1.get() + while not self.screen.action_objects.empty(): + obj=screen.action_objects.get() + if obj[1] =="end_graphics": + self.running = False + elif obj[1] == "text entry": + self.screen.text_entry = obj[0] + elif obj[1] =="remove_all": + self.objects = [] + elif obj[1] == "screen shot": + self.screen.screenshot = True + self.screen.filename = obj[0] + elif obj[1] == "new object": + self.create_obj(obj[0]) + else: + for i in self.objects: + if i.key == obj[0].key: + if obj[1] == "remove": + self.objects.remove(i) + if obj[1] == "move_to": + i.move_to(obj[2]) + if obj[1] == "move_by": + i.move_by(obj[2][0],obj[2][1]) + if obj[1] == "rotate_by": + i.rot += obj[2] + if obj[1] == "rotate_to": + i.rot = obj[2] + + def run(self): + gobject.timeout_add(40, self.update) #this will call update periodically + self.running = True + #while threading.enumerate()[0].isAlive() and self.running: + #if threading.activeCount() < 2: self.killPID() + while self.running: + sleep(1.0/100.0) + gtk.main_iteration(False) + + +#============================== EVENT HANDLER FUNCTIONS =============================== + +def key_pressed(widget, event): + if event.keyval == 65307: quit() + if screen.text_entry: + if event.keyval == 65293: + screen.entry_done.put(screen.text_entry.entry) + screen.text_entry = None + elif event.keyval == 65288: + screen.text_entry.entry = screen.text_entry.entry[:-1] + else: + screen.text_entry.entry += event.string + else: + string = "" + if event.keyval == 65364:string = "down" + elif event.keyval == 65362:string = "up" + elif event.keyval == 65361:string = "left" + elif event.keyval == 65363:string = "right" + elif event.keyval == 65293:string = "enter" + elif event.keyval == 65506:string = "shift" + elif event.keyval == 65289:string = "tab" + else:string = event.string + if not string in screen.keys_pressed: screen.keys.put([string,"pressed"]) + if screen.update_when == KEY_PRESSED: screen.update2.put(NOTHING) + +def key_released(widget, event): + string = "" + if event.keyval == 65364:string = "down" + elif event.keyval == 65362:string = "up" + elif event.keyval == 65361:string = "left" + elif event.keyval == 65363:string = "right" + elif event.keyval == 65293:string = "enter" + elif event.keyval == 65506:string = "shift" + elif event.keyval == 65289:string = "tab" + else:string = event.string + screen.keys.put([string,"released"]) + +def mouse_press(widget, event): + screen.mouse.put(["press",screen.mouse_buttons[event.button-1],1]) + if screen.update_when == MOUSE_PRESSED: + screen.update_when = NOTHING + + +def mouse_release(widget, event): + screen.mouse.put(["press",screen.mouse_buttons[event.button-1],0]) + +def mouse_move(widget, event): + screen.mouse.put(["position",(event.x,event.y)]) + + + +def require_screen(func): + def wrapper(*args): + if not screen: + raise GaspException("No graphics window initialized. Please call begin_graphics().") + return func(*args) + + return wrapper + + +#============================== SHAPE FUNCTIONS =============================== +@require_screen +def plot(obj): # must be passed a Plot() + obj.rot = 0 + obj.topleft = (obj.center.x-obj.size,obj.center.y-obj.size) + obj.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,int(obj.size*2),int(obj.size*2)) + context = cairo.Context(obj.surface) + context.set_source_rgb(*obj.color) + context.rectangle(0,0,obj.size*2,obj.size*2) + context.fill_preserve() + obj.on_screen = True + #screen.objects.append(obj) + +@require_screen +def create_line(obj): # Must take a line object + thickness = obj.thickness + obj.topleft = (min(obj.start.x,obj.end.x)-thickness,min(obj.start.y,obj.end.y)-thickness) + obj.width = abs(obj.start.x-obj.end.x)+thickness*2 + obj.height = abs(obj.start.y-obj.end.y)+thickness*2 + obj.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(obj.width),int(obj.height)) + context = cairo.Context(obj.surface) + context.set_source_rgb(*obj.color) + context.set_line_width(thickness) + context.move_to(obj.start.x-obj.topleft[0],obj.height - (obj.start.y-obj.topleft[1])) + context.line_to(obj.end.x-obj.topleft[0],obj.height - (obj.end.y-obj.topleft[1])) + context.stroke() + context.arc(obj.start.x-obj.topleft[0],obj.height - (obj.start.y-obj.topleft[1]),thickness/2, 0, 2.0 * math.pi) + context.fill() + context.arc(obj.end.x-obj.topleft[0],obj.height - (obj.end.y-obj.topleft[1]),thickness/2, 0, 2.0 * math.pi) + context.fill() + obj.thickness = 1 + obj.rot = 0 + obj.on_screen = True + #screen.objects.append(obj) + +@require_screen +def create_box(obj): # Must take a box object + obj.topleft = (obj.center.x-obj.width/2,obj.center.y-obj.height/2) + obj.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,int(obj.width+obj.thickness*2),int(obj.height+obj.thickness*2)) + context = cairo.Context(obj.surface) + context.set_source_rgb(*obj.color) + context.set_line_width(obj.thickness) + context.rectangle(obj.thickness,obj.thickness,obj.width,obj.height) + if obj.filled: context.fill_preserve() + else: context.stroke() + obj.on_screen = True + #screen.objects.append(obj) + +@require_screen +def create_polygon(obj): # Must take a polygon object + obj.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(obj.width),int(obj.height)) + context = cairo.Context(obj.surface) + context.set_source_rgb(*obj.color) + context.set_line_width(obj.thickness) + context.move_to(obj.points[0][0]-obj.topleft[0],obj.height - (obj.points[0][1]-obj.topleft[1])) + i = 1 + while i < len(obj.points): + context.line_to(obj.points[i][0]-obj.topleft[0],obj.height-(obj.points[i][1]-obj.topleft[1])) + i+=1 + context.line_to(obj.points[0][0]-obj.topleft[0],obj.height - (obj.points[0][1]-obj.topleft[1])) + if obj.filled: context.fill_preserve() + else: context.stroke() + obj.on_screen = True + #screen.objects.append(obj) + +@require_screen +def create_circle(obj): # Must take a circle objects + obj.width = obj.radius*2+2*obj.thickness + obj.height = obj.width + obj.topleft = (obj.center.x-obj.width/2,obj.center.y-obj.height/2) + obj.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,int(obj.width),int(obj.height)) + context = cairo.Context(obj.surface) + context.set_source_rgb(*obj.color) + context.set_line_width(obj.thickness) + context.arc(obj.width/2,obj.height/2, obj.radius, 0, 2.0 * math.pi) + if obj.filled: context.fill_preserve() + else: context.stroke() + obj.on_screen = True + #screen.updater.add(obj) + #screen.new_objects.put(obj) + #screen.objects.append(obj) + +@require_screen +def create_arc(obj): + obj.width = obj.radius*2+2*obj.thickness + obj.height = obj.width + obj.topleft = (obj.center.x-obj.width/2,obj.center.y-obj.height/2) + obj.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,int(obj.width),int(obj.height)) + context = cairo.Context(obj.surface) + context.set_source_rgb(*obj.color) + context.set_line_width(obj.thickness) + context.arc(obj.width/2,obj.height/2, obj.radius, math.radians(obj.end_angle), math.radians(obj.start_angle)) + context.stroke() + if obj.filled: + angle = obj.end_angle + context.set_line_width(3.5) + context.move_to(obj.width/2,obj.height/2) + while angle < obj.start_angle: + context.line_to(obj.width/2+math.cos(math.radians(angle))*obj.radius,obj.height/2+math.sin(math.radians(angle))*obj.radius) + angle+=4 + angle = obj.start_angle + context.line_to(obj.width/2+math.cos(math.radians(angle))*obj.radius,obj.height/2+math.sin(math.radians(angle))*obj.radius) + context.line_to(obj.width/2,obj.height/2) + context.fill_preserve() + obj.on_screen = True + #screen.objects.append(obj) + +@require_screen +def create_oval(obj): # Must take an oval object + radius = obj.width + obj.topleft = (obj.center.x-(2*obj.width+obj.thickness)/2,obj.center.y-(2*obj.height+obj.thickness)/2) + obj.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,int(2*obj.width+obj.thickness),int(2*obj.height+obj.thickness)) + context = cairo.Context(obj.surface) + scale = (1,1.0*obj.height/obj.width) + context.set_source_rgb(*obj.color) + context.set_line_width(obj.thickness) + context.save() + context.scale(scale[0],scale[1]) + context.arc((2*obj.width+obj.thickness)/(2*scale[0]), (2*obj.height+obj.thickness)/(2*scale[1]), radius, 0, 2 * math.pi) + context.restore() + if obj.filled: context.fill() + else: context.stroke() + obj.on_screen = True + #screen.objects.append(obj) + +@require_screen +def create_image(obj): # must take an image object + obj.rot = 0 + obj.pixbuf = gtk.gdk.pixbuf_new_from_file(obj.path_name) + width = obj.pixbuf.get_width() + height = obj.pixbuf.get_height() + if obj.width != 0 and obj.height != 0: + obj.scale = (float(obj.width)/width, float(obj.height)/height) + else: + obj.scale = (1,1) + obj.width = width + obj.height = height + obj.topleft = (obj.center.x-obj.width/2,obj.center.y-obj.height/2) + obj.on_screen = True + #screen.objects.append(obj) + +def create_text(obj): + temp_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,1,1) + context = cairo.Context(temp_surface) + context.set_font_size(obj.size) + x,y,obj.length,obj.height = context.text_extents(obj.text)[:4] + obj.topleft = (int(obj.pos[0]),int(obj.pos[1])) + obj.rot = 0 + obj.on_screen = True + +def get_text_length(text): + temp_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,1,1) + context = cairo.Context(temp_surface) + context.set_font_size(text.size) + x,y,length,height = context.text_extents(text.text)[:4] + return length + +class Entry: + """ + Allows the creation of text in the graphics window + """ + def __init__(self, message, pos, color, size): + self.message = message + self.color = color_convert(color) + self.size = size + self.pos = flip_coords(pos) + self.entry = "" + screen.text_entry = self + screen.action_objects.put([self,"text entry"]) + self.done = False + while not self.done: + if not screen.entry_done.empty(): + self.entry = screen.entry_done.get() + self.done = True + pass + + def draw(self, context): + context.save() + context.move_to(*self.pos) + context.set_source_rgb(*self.color) + context.set_font_size(self.size) + context.show_text(self.message+" "+self.entry) + context.restore() + + + +"""#================================== Sound ===================================== + +def create_sound(obj): # needs to be a sound object. + try: + pygame.mixer.init() + except: + print "sound is all ready init" + pass + obj.sound = pygame.mixer.Sound(obj.path) + + +def play_sound(obj): + obj.sound.play() + + +def stop_sound(obj): + obj.sound.stop()""" + + +# ============================== Event Functions ============================== + + +@require_screen +def keys(): #returns all the keys currently being pressed + while not screen.keys.empty(): + key = screen.keys.get() + if key[1] == "pressed": + screen.keys_pressed.append(key[0]) + if key[1] == "released" and key[0] in screen.keys_pressed: + screen.keys_pressed.remove(key[0]) + return screen.keys_pressed + +def mouse_pos(): + while not screen.mouse.empty(): + event = screen.mouse.get() + if event[0] == "press": + screen.mouse_state[event[1]]=event[2] + if event[0] == "position": + screen.mouse_pos = event[1] + return screen.mouse_pos + +def mouse_state(): + while not screen.mouse.empty(): + event = screen.mouse.get() + if event[0] == "press": + screen.mouse_state[event[1]]=event[2] + if event[0] == "position": + screen.mouse_pos = event[1] + return screen.mouse_state + +def get_screen_size(): + return (screen.width,screen.height) + + + +# ============================ Exception Handling ============================ + +class GaspException(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + + +# =============================== BACKEND TOOLS =============================== +@require_screen +def screen_picture(file_name): + screen.action_objects.put([file_name,"screen shot"]) + +@require_screen +def flip_coords(point): + """ + Changes (0, 0) from topleft bottomleft. + """ + try: + return (point[0],screen.height-point[1]) + except: return (point.x,screen.height-point.y) + + +def color_convert(color): + """ + convert the colors to the formate the cairo takes + """ + return (color[0]/255.0,color[1]/255.0,color[2]/255.0) + + + +@require_screen +def end(): + screen.action_objects.put([None, "end_graphics"]) + for queue in [screen.action_objects, screen.keys, screen.mouse, screen.update1, screen.update2, screen.entry_done]: + while not queue.empty(): + queue.get() + sys.exit() + +@require_screen +def remove(obj): + screen.action_objects.put([obj,"remove"]) + +@require_screen +def clear_screen(): + screen.action_objects.put([None,"remove_all"]) + + +# ============================== Time ======================================== +@require_screen +def update_when(event_type): + + if event_type == "key_pressed": + screen.update_when = KEY_PRESSED + screen.update1.put(KEY_PRESSED) + + elif event_type == "mouse_pressed": + screen.update_when = MOUSE_PRESSED + + elif event_type == "next_tick": + while time.time() < screen.last_tick+1.0/screen.frame_rate: + pass + screen.last_tick = time.time() + + if screen.update_when == KEY_PRESSED: + while True: + while not screen.update2.empty(): + screen.update_when = screen.update2.get() + keys_p = keys() + if len(keys_p) != 0 and screen.update_when == NOTHING: + screen.update_when = NOTHING + return keys_p[0] + old_state = mouse_state() + while screen.update_when == MOUSE_PRESSED: + state = mouse_state() + for key in state.get_keys(): + if state[key] != old_state[key] and state[key] == 1: + screen.update_when = NOTHING + + +@require_screen +def set_frame_rate(fps): + screen.frame_rate = fps + + +def sleep(duration): + time.sleep(duration) diff --git a/library/pippy/gasp/color.py b/library/pippy/gasp/color.py new file mode 100644 index 0000000..dfd3928 --- /dev/null +++ b/library/pippy/gasp/color.py @@ -0,0 +1,145 @@ +""" +color.py : Constants for colors (RBG values) + +copyright: James Hancock, 2008 +""" + +ALICEBLUE = (240, 248, 255) +ANTIQUEWHITE = (250, 235, 215) +AQUA = (0, 255, 255) +AZURE = (240, 255, 212) +BEIGE = (245, 245, 220) +BISQUE = (245, 245, 220) +BLACK = (0, 0, 0) +BLANCHEDALMOND = (255, 255, 205) +BLUE = (0, 0, 255) +BLUEVIOLET = (138, 43, 226) +BROWN = (165, 42, 42) +BURLYWOOD = (222, 184, 135) +CADETBLUE = (95, 158, 160) +CHARTREUSE = (127, 255, 0) +CHOCOLATE = (210, 105, 30) +CORAL = (255, 127, 80) +CORNFLOWERBLUE = (100, 149, 237) +CORNSILK = (255, 248, 220) +CRIMSON = (220, 20, 60) +CYAN = (0, 255, 255) +DARKBLUE = (0, 0, 139) +DARKCYAN = (0, 139, 139) +DARKGOLDENROD = (184, 134, 11) +DARKGRAY = (169, 169, 169) +DARKGREEN = (0, 100, 0) +DARKKHAKI = (189, 183, 107) +DARKMAGENTA = (139, 0, 139) +DARKOLIVEGREEN = (85, 107, 47) +DARKORANGE = (255, 140, 0) +DARKORCHID = (155, 50, 204) +DARKRED = (139, 0, 0) +DARKSALMON = (233, 150, 122) +DARKSEAGREEN = (143, 188, 143) +DARKSLATEBLUE = (72, 61, 139) +DARKSLATEGRAY = (47, 79, 79) +DARKTURQUOISE = (0, 206, 209) +DARKVIOLET = (148, 0, 211) +DEEPPINK = (255, 20, 147) +DEEPSKYBLUE = (0, 191, 255) +DIMGRAY = (105, 105, 105) +DODGERBLUE = (30, 144, 255) +FIREBRICK = (178, 34, 34) +FLORALWHITE = (255, 250, 240) +FORESTGREEN = (34, 139, 34) +FUCHSIA = (255, 0, 255) +GAINSBORO = (220, 220, 220) +GHOSTWHITE = (248, 248, 255) +GOLD = (255, 215, 0) +GOLDENROD = (218, 165, 32) +GRAY = (218, 165, 32) +GREEN = (0, 128, 0) +GREENYELLOW = (173, 255, 47) +HONEYDEW = (240, 255, 240) +HOTPINK = (255, 105, 180) +INDIANRED = (205, 92, 92) +INDIGO = (75, 0, 130) +IVORY = (255, 240, 240) +KHAKI = (240, 230, 140) +LAVENDER = (230, 230, 250) +LAVENDERBLUSH = (255, 240, 245) +LAWNGREEN = (124, 252, 245) +LEMONCHIFFON = (255, 250, 205) +LIGHTBLUE = (173, 216, 230) +LIGHTCORAL = (240, 128, 128) +LIGHTCYAN = (224, 255, 255) +LIGHTGOLDENRODYELLOW = (250, 250, 210) +LIGHTGREEN = (144, 238, 144) +LIGHTGRAY = (211, 211, 211) +LIGHTPINK = (255, 182, 193) +LIGHTSALMON = (255, 160, 122) +LIGHTSEAGREEN = (32, 178, 170) +LIGHTSKYBLUE = (135, 206, 250) +LIGHTSLATEGRAY = (119, 136, 153) +LIGHTSTEELBLUE = (176, 196, 222) +LIGHTYELLOW = (255, 255, 224) +LIME = (0, 255, 0) +LIMEGREEN = (50, 205, 50) +LINEN = (250, 240, 230) +MAGENTA = (255, 0, 255) +MAROON = (128, 0, 0) +MEDIUMAQUAMARINE = (102, 205, 170) +MEDIUMBLUE = (0, 0, 205) +MEDIUMORCHID = (186, 85, 211) +MEDIUMPURPLE = (147, 112, 219) +MEDIUMSEAGREEN = (60, 179, 113) +MEDIUMSLATEBLUE = (123, 104, 238) +MEDIUMSPRINGGREEN = (0, 250, 154) +MEDIUMTURQOISE = (72, 209, 204) +MEDIUMVIOLETRED = (199, 21, 133) +MIDNIGHTBLUE = (25, 25, 112) +MINTCREAM = (245, 255, 250) +MISTYROSE = (255, 228, 225) +MOCCASIN = (255, 225, 181) +NAVAJOWHITE = (255, 222, 173) +NAVY = (0, 0, 128) +OLDLACE = (253, 245, 230) +OLIVE = (128, 128, 0) +OLIVEDRAB = (107, 142, 35) +ORANGE = (255, 165, 0) +ORANGERED = (255, 69, 0) +ORCHID = (218, 122, 214) +PALEGOLDENROD = (238, 232, 170) +PALEGREEN = (152, 251, 152) +PALETURQOISE = (175, 238, 238) +PALEVIOLETRED = (219, 112, 147) +PAPAYAWHIP = (255, 239, 213) +PEACHPUFF = (255, 239, 213) +PERU = (205, 133, 63) +PINK = (255, 192, 203) +PLUM = (211, 160, 221) +POWDERBLUE = (176, 224, 230) +PURPLE = (128, 0, 128) +RED = (255, 0, 0) +ROSYBROWN = (188, 143, 143) +ROYALBLUE = (65, 105, 225) +SADDLEBROWN = (139, 69, 19) +SALMON = (250, 128, 114) +SANDYBROWN = (244, 164, 96) +SEAGREEN = (46, 139, 87) +SEASHELL = (255, 245, 238) +SIENNA = (160, 82, 45) +SILVER = (192, 192, 192) +SKYBLUE = (135, 206, 235) +SLATEBLUE = (106, 90, 205) +SLATEGRAY = (112, 128, 144) +SNOW = (255, 250, 250) +SPRINGGREEN = (0, 255, 127) +STEELBLUE = (70, 130, 180) +TAN = (210, 180, 140) +TEAL = (0, 128, 128) +THISTLE = (216, 191, 216) +TOMATO = (253, 99, 71) +TURQUOISE = (64, 224, 208) +VIOLET = (238, 130, 238) +WHEAT = (245, 222, 170) +WHITE = (255, 255, 255) +WHITESMOKE = (245, 245, 245) +YELLOW = (255, 255, 0) +YELLOWGREEN = (154, 205, 50) |