#!/usr/bin/env python from __future__ import division import gtk import cairo from math import radians from threading import Thread import src as mt def quit(*args): gtk.main_quit() class Rectangle(mt.RectangularWidget): def __init__(self, x, y, width, height, color=(1, 0, 0)): super(Rectangle, self).__init__(x, y, width, height) self.angle = 0 self.scale = 1 self.color = color self.on_drag(self.move) def move(self, g): print 'drag rectangle', g.get_translation() self.translate(*g.get_translation()) print self refresh() def scale(self, angle): self.scale *= scale def rotate(self, angle): self.angle += angle def get_transformation_matrix(self): t = cairo.Matrix() t.translate(*self) t.rotate(self.angle) t.scale(self.scale, self.scale) return t def draw(self, cr): cr.transform(self.get_transformation_matrix()) w, h = self.get_size() cr.rectangle(-w / 2, -h / 2, w, h) cr.set_source_rgb(*self.color) cr.fill() fullscreen = False W, H = mt.screen.screen_size def create_context_window(w, h, callback): def create_context(area, event): """Add Cairo context to GTK window and draw initial state.""" global cr cr = area.window.cairo_create() draw() def move_window(win, event): """Synchronize root multi-touch widget with GTK window.""" root.set_position(*event.get_coords()) root.set_size(event.width, event.height) draw() def handle_key(win, event): """Handle key event. 'f' toggles fullscreen, 'q' exits the program.""" if event.keyval >= 256: return key = chr(event.keyval) if key == 'f': global fullscreen (win.unfullscreen if fullscreen else win.fullscreen)() fullscreen = not fullscreen elif key == 'q': quit() # Root widget (will be synchronized with GTK window) global root root = mt.RectangularWidget(0, 0, w, h) # GTK window global window window = gtk.Window() window.set_title('Cairo test') window.connect('destroy', quit) window.connect('key-press-event', handle_key) window.connect('configure-event', move_window) window.connect('show', callback) # Drawing area, needed by cairo context for drawing area = gtk.DrawingArea() area.set_size_request(w, h) area.connect('expose-event', create_context) window.add(area) area.show() window.show() def draw(*args): print 'draw' # Background cr.rectangle(0, 0, *root.get_size()) cr.set_source_rgb(0, 1, 0) cr.fill() # Drawable objects (use save and restore to allow transformations) for obj in draw_objects: cr.save() obj.draw(cr) cr.restore() def refresh(): window.queue_draw() # Initialization window = cr = root = None draw_objects = [] def on_show(window): def root_dtap(g): print 'double tapped on root' root.on_double_tap(root_dtap) # Create blue rectangle rect = Rectangle(300, 200, 250, 150, color=(0, 0, 1)) draw_objects.append(rect) root.add_widget(rect) def rect_tap(g): print 'tapped on rectangle' rect.on_tap(rect_tap, propagate_up_event=False) if __name__ == '__main__': # Parse arguments from tests.parse_arguments import create_parser, parse_args parse_args(create_parser()) # Create a window with a Cairo context in it and a multi-touch widget # syncronized with it create_context_window(640, 460, on_show) # Run multi-touch gesture server in separate thread server = mt.EventServer(root) mt_thread = Thread(target=server.start) mt_thread.daemon = True mt_thread.start() # Initialize threads in GTK so that the thread started above will work gtk.gdk.threads_init() # Start main loop in current thread gtk.main()