171 lines
5.4 KiB
Python
171 lines
5.4 KiB
Python
'''
|
|
Touch Tracer Line Drawing Demonstration
|
|
=======================================
|
|
|
|
This demonstrates tracking each touch registered to a device. You should
|
|
see a basic background image. When you press and hold the mouse, you
|
|
should see cross-hairs with the coordinates written next to them. As
|
|
you drag, it leaves a trail. Additional information, like pressure,
|
|
will be shown if they are in your device's touch.profile.
|
|
|
|
.. note::
|
|
|
|
A function `calculate_points` handling the points which will be drawn
|
|
has by default implemented a delay of 5 steps. To get more precise visual
|
|
results lower the value of the optional keyword argument `steps`.
|
|
|
|
This program specifies an icon, the file icon.png, in its App subclass.
|
|
It also uses the particle.png file as the source for drawing the trails which
|
|
are white on transparent. The file touchtracer.kv describes the application.
|
|
|
|
The file android.txt is used to package the application for use with the
|
|
Kivy Launcher Android application. For Android devices, you can
|
|
copy/paste this directory into /sdcard/kivy/touchtracer on your Android device.
|
|
|
|
'''
|
|
__version__ = '1.0'
|
|
|
|
import kivy
|
|
kivy.require('1.0.6')
|
|
|
|
from kivy.app import App
|
|
from kivy.uix.floatlayout import FloatLayout
|
|
from kivy.uix.label import Label
|
|
from kivy.graphics import Color, Rectangle, Point, GraphicException
|
|
from kivy.metrics import dp
|
|
from random import random
|
|
from math import sqrt
|
|
|
|
|
|
def calculate_points(x1, y1, x2, y2, steps=5):
|
|
dx = x2 - x1
|
|
dy = y2 - y1
|
|
dist = sqrt(dx * dx + dy * dy)
|
|
if dist < steps:
|
|
return
|
|
o = []
|
|
m = dist / steps
|
|
for i in range(1, int(m)):
|
|
mi = i / m
|
|
lastx = x1 + dx * mi
|
|
lasty = y1 + dy * mi
|
|
o.extend([lastx, lasty])
|
|
return o
|
|
|
|
|
|
class Touchtracer(FloatLayout):
|
|
|
|
def normalize_pressure(self, pressure):
|
|
print(pressure)
|
|
# this might mean we are on a device whose pressure value is
|
|
# incorrectly reported by SDL2, like recent iOS devices.
|
|
if pressure == 0.0:
|
|
return 1
|
|
return dp(pressure * 10)
|
|
|
|
def on_touch_down(self, touch):
|
|
win = self.get_parent_window()
|
|
ud = touch.ud
|
|
ud['group'] = g = str(touch.uid)
|
|
pointsize = 5
|
|
print(touch.profile)
|
|
if 'pressure' in touch.profile:
|
|
ud['pressure'] = touch.pressure
|
|
pointsize = self.normalize_pressure(touch.pressure)
|
|
ud['color'] = random()
|
|
|
|
with self.canvas:
|
|
Color(ud['color'], 1, 1, mode='hsv', group=g)
|
|
ud['lines'] = [
|
|
Rectangle(pos=(touch.x, 0), size=(1, win.height), group=g),
|
|
Rectangle(pos=(0, touch.y), size=(win.width, 1), group=g),
|
|
Point(points=(touch.x, touch.y), source='particle.png',
|
|
pointsize=pointsize, group=g)]
|
|
|
|
ud['label'] = Label(size_hint=(None, None))
|
|
self.update_touch_label(ud['label'], touch)
|
|
self.add_widget(ud['label'])
|
|
touch.grab(self)
|
|
return True
|
|
|
|
def on_touch_move(self, touch):
|
|
if touch.grab_current is not self:
|
|
return
|
|
ud = touch.ud
|
|
ud['lines'][0].pos = touch.x, 0
|
|
ud['lines'][1].pos = 0, touch.y
|
|
|
|
index = -1
|
|
|
|
while True:
|
|
try:
|
|
points = ud['lines'][index].points
|
|
oldx, oldy = points[-2], points[-1]
|
|
break
|
|
except IndexError:
|
|
index -= 1
|
|
|
|
points = calculate_points(oldx, oldy, touch.x, touch.y)
|
|
|
|
# if pressure changed create a new point instruction
|
|
if 'pressure' in ud:
|
|
old_pressure = ud['pressure']
|
|
if (
|
|
not old_pressure
|
|
or not .99 < (touch.pressure / old_pressure) < 1.01
|
|
):
|
|
g = ud['group']
|
|
pointsize = self.normalize_pressure(touch.pressure)
|
|
with self.canvas:
|
|
Color(ud['color'], 1, 1, mode='hsv', group=g)
|
|
ud['lines'].append(
|
|
Point(points=(), source='particle.png',
|
|
pointsize=pointsize, group=g))
|
|
|
|
if points:
|
|
try:
|
|
lp = ud['lines'][-1].add_point
|
|
for idx in range(0, len(points), 2):
|
|
lp(points[idx], points[idx + 1])
|
|
except GraphicException:
|
|
pass
|
|
|
|
ud['label'].pos = touch.pos
|
|
import time
|
|
t = int(time.time())
|
|
if t not in ud:
|
|
ud[t] = 1
|
|
else:
|
|
ud[t] += 1
|
|
self.update_touch_label(ud['label'], touch)
|
|
|
|
def on_touch_up(self, touch):
|
|
if touch.grab_current is not self:
|
|
return
|
|
touch.ungrab(self)
|
|
ud = touch.ud
|
|
self.canvas.remove_group(ud['group'])
|
|
self.remove_widget(ud['label'])
|
|
|
|
def update_touch_label(self, label, touch):
|
|
label.text = 'ID: %s\nPos: (%d, %d)\nClass: %s' % (
|
|
touch.id, touch.x, touch.y, touch.__class__.__name__)
|
|
label.texture_update()
|
|
label.pos = touch.pos
|
|
label.size = label.texture_size[0] + 20, label.texture_size[1] + 20
|
|
|
|
|
|
class TouchtracerApp(App):
|
|
title = 'Touchtracer'
|
|
icon = 'icon.png'
|
|
|
|
def build(self):
|
|
return Touchtracer()
|
|
|
|
def on_pause(self):
|
|
return True
|
|
|
|
|
|
if __name__ == '__main__':
|
|
TouchtracerApp().run()
|