cairotest.py 3.9 KB

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