/examples/demo/touchtracer/main.py

https://github.com/kivy/kivy · Python · 170 lines · 156 code · 5 blank · 9 comment · 3 complexity · 78da4aaedc16b46f6296493133860342 MD5 · raw file

  1. '''
  2. Touch Tracer Line Drawing Demonstration
  3. =======================================
  4. This demonstrates tracking each touch registered to a device. You should
  5. see a basic background image. When you press and hold the mouse, you
  6. should see cross-hairs with the coordinates written next to them. As
  7. you drag, it leaves a trail. Additional information, like pressure,
  8. will be shown if they are in your device's touch.profile.
  9. .. note::
  10. A function `calculate_points` handling the points which will be drawn
  11. has by default implemented a delay of 5 steps. To get more precise visual
  12. results lower the value of the optional keyword argument `steps`.
  13. This program specifies an icon, the file icon.png, in its App subclass.
  14. It also uses the particle.png file as the source for drawing the trails which
  15. are white on transparent. The file touchtracer.kv describes the application.
  16. The file android.txt is used to package the application for use with the
  17. Kivy Launcher Android application. For Android devices, you can
  18. copy/paste this directory into /sdcard/kivy/touchtracer on your Android device.
  19. '''
  20. __version__ = '1.0'
  21. import kivy
  22. kivy.require('1.0.6')
  23. from kivy.app import App
  24. from kivy.uix.floatlayout import FloatLayout
  25. from kivy.uix.label import Label
  26. from kivy.graphics import Color, Rectangle, Point, GraphicException
  27. from kivy.metrics import dp
  28. from random import random
  29. from math import sqrt
  30. def calculate_points(x1, y1, x2, y2, steps=5):
  31. dx = x2 - x1
  32. dy = y2 - y1
  33. dist = sqrt(dx * dx + dy * dy)
  34. if dist < steps:
  35. return
  36. o = []
  37. m = dist / steps
  38. for i in range(1, int(m)):
  39. mi = i / m
  40. lastx = x1 + dx * mi
  41. lasty = y1 + dy * mi
  42. o.extend([lastx, lasty])
  43. return o
  44. class Touchtracer(FloatLayout):
  45. def normalize_pressure(self, pressure):
  46. print(pressure)
  47. # this might mean we are on a device whose pressure value is
  48. # incorrectly reported by SDL2, like recent iOS devices.
  49. if pressure == 0.0:
  50. return 1
  51. return dp(pressure * 10)
  52. def on_touch_down(self, touch):
  53. win = self.get_parent_window()
  54. ud = touch.ud
  55. ud['group'] = g = str(touch.uid)
  56. pointsize = 5
  57. print(touch.profile)
  58. if 'pressure' in touch.profile:
  59. ud['pressure'] = touch.pressure
  60. pointsize = self.normalize_pressure(touch.pressure)
  61. ud['color'] = random()
  62. with self.canvas:
  63. Color(ud['color'], 1, 1, mode='hsv', group=g)
  64. ud['lines'] = [
  65. Rectangle(pos=(touch.x, 0), size=(1, win.height), group=g),
  66. Rectangle(pos=(0, touch.y), size=(win.width, 1), group=g),
  67. Point(points=(touch.x, touch.y), source='particle.png',
  68. pointsize=pointsize, group=g)]
  69. ud['label'] = Label(size_hint=(None, None))
  70. self.update_touch_label(ud['label'], touch)
  71. self.add_widget(ud['label'])
  72. touch.grab(self)
  73. return True
  74. def on_touch_move(self, touch):
  75. if touch.grab_current is not self:
  76. return
  77. ud = touch.ud
  78. ud['lines'][0].pos = touch.x, 0
  79. ud['lines'][1].pos = 0, touch.y
  80. index = -1
  81. while True:
  82. try:
  83. points = ud['lines'][index].points
  84. oldx, oldy = points[-2], points[-1]
  85. break
  86. except IndexError:
  87. index -= 1
  88. points = calculate_points(oldx, oldy, touch.x, touch.y)
  89. # if pressure changed create a new point instruction
  90. if 'pressure' in ud:
  91. old_pressure = ud['pressure']
  92. if (
  93. not old_pressure
  94. or not .99 < (touch.pressure / old_pressure) < 1.01
  95. ):
  96. g = ud['group']
  97. pointsize = self.normalize_pressure(touch.pressure)
  98. with self.canvas:
  99. Color(ud['color'], 1, 1, mode='hsv', group=g)
  100. ud['lines'].append(
  101. Point(points=(), source='particle.png',
  102. pointsize=pointsize, group=g))
  103. if points:
  104. try:
  105. lp = ud['lines'][-1].add_point
  106. for idx in range(0, len(points), 2):
  107. lp(points[idx], points[idx + 1])
  108. except GraphicException:
  109. pass
  110. ud['label'].pos = touch.pos
  111. import time
  112. t = int(time.time())
  113. if t not in ud:
  114. ud[t] = 1
  115. else:
  116. ud[t] += 1
  117. self.update_touch_label(ud['label'], touch)
  118. def on_touch_up(self, touch):
  119. if touch.grab_current is not self:
  120. return
  121. touch.ungrab(self)
  122. ud = touch.ud
  123. self.canvas.remove_group(ud['group'])
  124. self.remove_widget(ud['label'])
  125. def update_touch_label(self, label, touch):
  126. label.text = 'ID: %s\nPos: (%d, %d)\nClass: %s' % (
  127. touch.id, touch.x, touch.y, touch.__class__.__name__)
  128. label.texture_update()
  129. label.pos = touch.pos
  130. label.size = label.texture_size[0] + 20, label.texture_size[1] + 20
  131. class TouchtracerApp(App):
  132. title = 'Touchtracer'
  133. icon = 'icon.png'
  134. def build(self):
  135. return Touchtracer()
  136. def on_pause(self):
  137. return True
  138. if __name__ == '__main__':
  139. TouchtracerApp().run()