#!/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.RectangularArea): def __init__(self, x, y, width, height, color=(1, 0, 0)): super(Rectangle, self).__init__(x, y, width, height) self.angle = 1.0 self.color = color self.t = cairo.Matrix() self.t.translate(*self) self.on_drag(self.move) self.on_pinch(self.resize) #self.on_rotate(self.rotate) def move(self, g): self.translate(*g.get_translation()) print 'drag rectangle', self refresh() def resize(self, g): print 'resize:', g.get_scale() self.t.scale(g.get_scale(), g.get_scale()) refresh() def rotate(self, g): w, h = self.get_size() #self.t.translate(-w / 2, -h / 2) self.t.rotate(-g.get_angle()) #self.t.translate(w / 2, h / 2) print tuple(g) x, y = g * .01 print x, y #self.rot.translate(-x, -y) refresh() 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): w, h = self.get_size() cr.transform(self.t) cr.rectangle(0, 0, 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 state.""" global cr cr = area.window.cairo_create() draw() def move_window(win, event): """Synchronize root multi-touch area 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 area (will be synchronized with GTK window) global root root = mt.RectangularArea(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): if not cr: return # 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_area(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 area # syncronized with it create_context_window(640, 460, on_show) # Run multi-touch gesture server in separate thread driver = mt.create_driver(root) mt_thread = Thread(target=driver.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()