-
Notifications
You must be signed in to change notification settings - Fork 0
/
leaphandapp.py
107 lines (89 loc) · 3.4 KB
/
leaphandapp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"""
This module houses a minimal mixin class that provider a pre-touch crosshair
graphics for positioning of the hand for the LeapHand input provider.
"""
from kivy.core.window import Window
from kivy.graphics import Color, Line
from kivy.lang import Builder
from kivy.factory import Factory
from textwrap import dedent
from time import time
from kivy.clock import Clock
Builder.load_string(dedent("""
<LeapHandCrosshair@Widget>:
cross_color: [0.2, 1, 1, 1]
size: 12.0, 12.0
pos_hint: {}
size_hint: [None, None]
last_update: 0
canvas:
Color:
rgba: self.cross_color
Line:
width: 2
points: self.x, self.y + 0.5 * self.height, self.right, self.y + 0.5 * self.height # noqa: E501
Line:
width: 2
points: self.x + 0.5 * self.width, self.y, self.x + 0.5 * self.width, self.top
"""))
class LeapHandOverlay:
"""
This class handles the rendering of the pre-touch crosshairs for
positioning the LeapHand prior to starting the touch event (via a grab).
"""
def __init__(self, root):
Window.bind(on_motion=self.on_motion)
self._crosshairs = {}
self.root = root
Clock.schedule_interval(self._clean_up, 2)
def _clean_up(self, dt):
""" Remove any of the crosshairs if they are not currently active."""
ch = self._crosshairs.copy()
for key, cross in ch.items():
if time() - cross.last_update > 2:
cross.parent.remove_widget(cross)
self._crosshairs.pop(key)
def _get_crosshair(self, hand, is_touch):
"""Return the LeapHandCrossHair widget for displaying the position."""
widget = self._crosshairs.get(hand)
if widget is None:
widget = Factory.LeapHandCrosshair()
self._crosshairs[hand] = widget
self.root.add_widget(widget)
widget.cross_color = [0.2, 1, 0, 1] if is_touch else \
[0.5, 0.5, 0.5, 0.75]
return widget
@staticmethod
def get_pos(motion):
""" Return the position in screen co-ordinates for the motion event."""
return motion.sx * Window.width, motion.sy * Window.height
def place_crosshair(self, pos, hand, is_touch):
""" Draw the crosshairs indicating the hands current positions."""
widget = self._get_crosshair(hand, is_touch)
widget.last_update = time()
widget.pos = pos[0] - 0.5 * widget.width, \
pos[1] - 0.5 * widget.height
def on_motion(self, widget, etype, motionevent):
"""Draw the crosshairs at the position of the hands."""
if hasattr(motionevent, "hand"):
self.place_crosshair(
self.get_pos(motionevent),
motionevent.hand,
motionevent.is_touch)
class LeapHandApp:
"""
Mixin class for rendering a pre-touch crosshair graphic for positioning of
the hand when using the LeapHand input provider.
Usage
=====
When declaring your Kivy app, add this mixing as the superclas of your
main application object. e.g.::
from kivy.app import App
class LeaptracerApp(LeapHandApp, App):
...
"""
leaphand_overlay = None
def on_start(self):
self.leaphand_overlay = LeapHandOverlay(self.root)
print(f"leaphandoverlay.py: on_start. Binding to {self.root}")
return super().on_start() # pylint: disable=no-member