#!/usr/bin/env python from __future__ import division import gtk import cairo from math import radians from threading import Thread import src as mt class Rectangle(mt.RectangularArea): def __init__(self, x, y, width, height, color=(1, 0, 0)): super(Rectangle, self).__init__(x, y, width, height) self.w = width self.h = height self.scale = 1 self.angle = 0 self.color = color self.t = cairo.Matrix() self.t.translate(x, y) self.on_drag(self.move) self.on_pinch(self.resize) #self.on_rotate(self.rotate) def move(self, g): print 'move:', g self.translate(*g.get_translation()) self.ttrans(*g.get_translation()) refresh() def resize(self, g): print 'resize:', g x, y = g.get_position() scale = g.get_scale() self.ttrans(x, y) self.tscale(scale) self.ttrans(-x, -y) self.translate(x - x * scale, y - y * scale) self.width *= scale self.height *= scale refresh() def rotate(self, g): print 'rotate:', g x, y = g.get_position() self.ttrans(x, y) self.trot(-g.get_angle()) self.ttrans(-x, -y) refresh() def ttrans(self, tx, ty): t = cairo.Matrix() t.translate(tx, ty) self.t = t * self.t def tscale(self, s): t = cairo.Matrix() t.scale(s, s) self.t = t * self.t def trot(self, a): t = cairo.Matrix() t.rotate(a) self.t = t * self.t def draw(self, cr): cr.transform(self.t) cr.rectangle(0, 0, self.w, self.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() def quit(*args): gtk.main_quit() # 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()