cairotest.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #!/usr/bin/env python
  2. from __future__ import division
  3. import gtk
  4. import cairo
  5. from math import radians
  6. from threading import Thread
  7. import src as mt
  8. class Rectangle(mt.RectangularArea):
  9. def __init__(self, x, y, width, height, color=(1, 0, 0)):
  10. super(Rectangle, self).__init__(x, y, width, height)
  11. self.w = width
  12. self.h = height
  13. self.scale = 1
  14. self.angle = 0
  15. self.color = color
  16. self.t = cairo.Matrix()
  17. self.t.translate(x, y)
  18. self.on_drag(self.move)
  19. self.on_pinch(self.resize)
  20. #self.on_rotate(self.rotate)
  21. def move(self, g):
  22. print 'move:', g
  23. self.translate(*g.get_translation())
  24. self.ttrans(*g.get_translation())
  25. refresh()
  26. def resize(self, g):
  27. print 'resize:', g
  28. x, y = g.get_position()
  29. scale = g.get_scale()
  30. self.ttrans(x, y)
  31. self.tscale(scale)
  32. self.ttrans(-x, -y)
  33. self.translate(x - x * scale, y - y * scale)
  34. self.width *= scale
  35. self.height *= scale
  36. refresh()
  37. def rotate(self, g):
  38. print 'rotate:', g
  39. x, y = g.get_position()
  40. self.ttrans(x, y)
  41. self.trot(-g.get_angle())
  42. self.ttrans(-x, -y)
  43. refresh()
  44. def ttrans(self, tx, ty):
  45. t = cairo.Matrix()
  46. t.translate(tx, ty)
  47. self.t = t * self.t
  48. def tscale(self, s):
  49. t = cairo.Matrix()
  50. t.scale(s, s)
  51. self.t = t * self.t
  52. def trot(self, a):
  53. t = cairo.Matrix()
  54. t.rotate(a)
  55. self.t = t * self.t
  56. def draw(self, cr):
  57. cr.transform(self.t)
  58. cr.rectangle(0, 0, self.w, self.h)
  59. cr.set_source_rgb(*self.color)
  60. cr.fill()
  61. fullscreen = False
  62. W, H = mt.screen.screen_size
  63. def create_context_window(w, h, callback):
  64. def create_context(area, event):
  65. """Add Cairo context to GTK window and draw state."""
  66. global cr
  67. cr = area.window.cairo_create()
  68. draw()
  69. def move_window(win, event):
  70. """Synchronize root multi-touch area with GTK window."""
  71. root.set_position(*event.get_coords())
  72. root.set_size(event.width, event.height)
  73. draw()
  74. def handle_key(win, event):
  75. """Handle key event. 'f' toggles fullscreen, 'q' exits the program."""
  76. if event.keyval >= 256:
  77. return
  78. key = chr(event.keyval)
  79. if key == 'f':
  80. global fullscreen
  81. (win.unfullscreen if fullscreen else win.fullscreen)()
  82. fullscreen = not fullscreen
  83. elif key == 'q':
  84. quit()
  85. # Root area (will be synchronized with GTK window)
  86. global root
  87. root = mt.RectangularArea(0, 0, w, h)
  88. # GTK window
  89. global window
  90. window = gtk.Window()
  91. window.set_title('Cairo test')
  92. window.connect('destroy', quit)
  93. window.connect('key-press-event', handle_key)
  94. window.connect('configure-event', move_window)
  95. window.connect('show', callback)
  96. # Drawing area, needed by cairo context for drawing
  97. area = gtk.DrawingArea()
  98. area.set_size_request(w, h)
  99. area.connect('expose-event', create_context)
  100. window.add(area)
  101. area.show()
  102. window.show()
  103. def draw(*args):
  104. if not cr:
  105. return
  106. # Background
  107. cr.rectangle(0, 0, *root.get_size())
  108. cr.set_source_rgb(0, 1, 0)
  109. cr.fill()
  110. # Drawable objects (use save and restore to allow transformations)
  111. for obj in draw_objects:
  112. cr.save()
  113. obj.draw(cr)
  114. cr.restore()
  115. def refresh():
  116. window.queue_draw()
  117. def quit(*args):
  118. gtk.main_quit()
  119. # Initialization
  120. window = cr = root = None
  121. draw_objects = []
  122. def on_show(window):
  123. def root_dtap(g): print 'double tapped on root'
  124. root.on_double_tap(root_dtap)
  125. # Create blue rectangle
  126. rect = Rectangle(300, 200, 250, 150, color=(0, 0, 1))
  127. draw_objects.append(rect)
  128. root.add_area(rect)
  129. def rect_tap(g): print 'tapped on rectangle'
  130. rect.on_tap(rect_tap, propagate_up_event=False)
  131. if __name__ == '__main__':
  132. # Parse arguments
  133. from tests.parse_arguments import create_parser, parse_args
  134. parse_args(create_parser())
  135. # Create a window with a Cairo context in it and a multi-touch area
  136. # syncronized with it
  137. create_context_window(640, 460, on_show)
  138. # Run multi-touch gesture server in separate thread
  139. driver = mt.create_driver(root)
  140. mt_thread = Thread(target=driver.start)
  141. mt_thread.daemon = True
  142. mt_thread.start()
  143. # Initialize threads in GTK so that the thread started above will work
  144. gtk.gdk.threads_init()
  145. # Start main loop in current thread
  146. gtk.main()