|
@@ -4,15 +4,71 @@ from ..tracker import GestureTracker, Gesture
|
|
|
from ..geometry import Positionable, MovingPositionable
|
|
from ..geometry import Positionable, MovingPositionable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+class RotationGesture(Gesture, Positionable):
|
|
|
|
|
+ """
|
|
|
|
|
+ A rotation gesture has a angle in radians and a rotational centroid.
|
|
|
|
|
+ """
|
|
|
|
|
+ _type = 'rotate'
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, event, centroid, angle):
|
|
|
|
|
+ Gesture.__init__(self, event)
|
|
|
|
|
+ Positionable.__init__(self, *centroid.get_position())
|
|
|
|
|
+ self.angle = angle
|
|
|
|
|
+
|
|
|
|
|
+ def __str__(self):
|
|
|
|
|
+ return '<RotationGesture at (%s, %s) angle=%s>' \
|
|
|
|
|
+ % (self.x, self.y, self.angle)
|
|
|
|
|
+
|
|
|
|
|
+ def get_angle(self):
|
|
|
|
|
+ return self.angle
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class PinchGesture(Gesture, Positionable):
|
|
|
|
|
+ """
|
|
|
|
|
+ A pinch gesture has a scale (1.0 means no scaling) and a centroid from
|
|
|
|
|
+ which the scaling originates.
|
|
|
|
|
+ """
|
|
|
|
|
+ _type = 'pinch'
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, event, centroid, scale):
|
|
|
|
|
+ Gesture.__init__(self, event)
|
|
|
|
|
+ Positionable.__init__(self, *centroid.get_position())
|
|
|
|
|
+ self.scale = scale
|
|
|
|
|
+
|
|
|
|
|
+ def __str__(self):
|
|
|
|
|
+ return '<PinchGesture at (%s, %s) scale=%s>' \
|
|
|
|
|
+ % (self.x, self.y, self.scale)
|
|
|
|
|
+
|
|
|
|
|
+ def get_scale(self):
|
|
|
|
|
+ return self.scale
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class DragGesture(Gesture, Positionable):
|
|
|
|
|
+ """
|
|
|
|
|
+ A momevent gesture has an initial position, and a translation from that
|
|
|
|
|
+ position.
|
|
|
|
|
+ """
|
|
|
|
|
+ _type = 'drag'
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, event, initial_position, translation):
|
|
|
|
|
+ Gesture.__init__(self, event)
|
|
|
|
|
+ Positionable.__init__(self, *initial_position.get_position())
|
|
|
|
|
+ self.translation = translation
|
|
|
|
|
+
|
|
|
|
|
+ def __str__(self):
|
|
|
|
|
+ return '<DragGesture at (%s, %s) translation=(%s, %s)>' \
|
|
|
|
|
+ % (self.get_position() + self.translation.get_position())
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
class TransformationTracker(GestureTracker):
|
|
class TransformationTracker(GestureTracker):
|
|
|
"""
|
|
"""
|
|
|
Tracker for linear transformations. This implementation detects rotation,
|
|
Tracker for linear transformations. This implementation detects rotation,
|
|
|
scaling and translation using the centroid of all touch points.
|
|
scaling and translation using the centroid of all touch points.
|
|
|
"""
|
|
"""
|
|
|
- gesture_types = ['rotate', 'pinch', 'move']
|
|
|
|
|
|
|
+ supported_gestures = [RotationGesture, PinchGesture, DragGesture]
|
|
|
|
|
|
|
|
- def __init__(self, window=None):
|
|
|
|
|
- super(TransformationTracker, self).__init__(window)
|
|
|
|
|
|
|
+ def __init__(self, widget=None):
|
|
|
|
|
+ super(TransformationTracker, self).__init__(widget)
|
|
|
|
|
|
|
|
# All touch points performing the transformation
|
|
# All touch points performing the transformation
|
|
|
self.points = []
|
|
self.points = []
|
|
@@ -40,87 +96,33 @@ class TransformationTracker(GestureTracker):
|
|
|
else:
|
|
else:
|
|
|
self.centroid = MovingPositionable(x, y)
|
|
self.centroid = MovingPositionable(x, y)
|
|
|
|
|
|
|
|
- def on_point_down(self, point):
|
|
|
|
|
- self.points.append(point)
|
|
|
|
|
|
|
+ def on_point_down(self, event):
|
|
|
|
|
+ self.points.append(event.point)
|
|
|
self.update_centroid()
|
|
self.update_centroid()
|
|
|
|
|
|
|
|
- def on_point_move(self, point):
|
|
|
|
|
|
|
+ def on_point_move(self, event):
|
|
|
|
|
+ point = event.point
|
|
|
l = len(self.points)
|
|
l = len(self.points)
|
|
|
|
|
|
|
|
if l > 1:
|
|
if l > 1:
|
|
|
# Rotation (around the previous centroid)
|
|
# Rotation (around the previous centroid)
|
|
|
- if self.is_type_bound('rotate'):
|
|
|
|
|
- rotation = point.rotation_around(self.centroid) / l
|
|
|
|
|
- self.trigger(RotationGesture(self.centroid, rotation))
|
|
|
|
|
|
|
+ rotation = point.rotation_around(self.centroid) / l
|
|
|
|
|
+ self.trigger(RotationGesture(event, self.centroid, rotation))
|
|
|
|
|
|
|
|
# Scale
|
|
# Scale
|
|
|
- if self.is_type_bound('pinch'):
|
|
|
|
|
- prev = point.get_previous_position().distance_to(self.centroid)
|
|
|
|
|
- dist = point.distance_to(self.centroid)
|
|
|
|
|
- dist = prev + (dist - prev) / l
|
|
|
|
|
- scale = dist / prev
|
|
|
|
|
- self.trigger(PinchGesture(self.centroid, scale))
|
|
|
|
|
|
|
+ prev = point.get_previous_position().distance_to(self.centroid)
|
|
|
|
|
+ dist = point.distance_to(self.centroid)
|
|
|
|
|
+ dist = prev + (dist - prev) / l
|
|
|
|
|
+ scale = dist / prev
|
|
|
|
|
+ self.trigger(PinchGesture(event, self.centroid, scale))
|
|
|
|
|
|
|
|
# Update centroid before movement can be detected
|
|
# Update centroid before movement can be detected
|
|
|
self.update_centroid()
|
|
self.update_centroid()
|
|
|
|
|
|
|
|
# Movement
|
|
# Movement
|
|
|
- self.trigger(MovementGesture(self.centroid,
|
|
|
|
|
- self.centroid.translation()))
|
|
|
|
|
|
|
+ self.trigger(DragGesture(event, self.centroid,
|
|
|
|
|
+ self.centroid.translation()))
|
|
|
|
|
|
|
|
- def on_point_up(self, point):
|
|
|
|
|
- self.points.remove(point)
|
|
|
|
|
|
|
+ def on_point_up(self, event):
|
|
|
|
|
+ self.points.remove(event.point)
|
|
|
self.update_centroid()
|
|
self.update_centroid()
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-class RotationGesture(Positionable, Gesture):
|
|
|
|
|
- """
|
|
|
|
|
- A rotation gesture has a angle in radians and a rotational centroid.
|
|
|
|
|
- """
|
|
|
|
|
- _type = 'rotate'
|
|
|
|
|
-
|
|
|
|
|
- def __init__(self, centroid, angle):
|
|
|
|
|
- Positionable.__init__(self, *centroid.get_position())
|
|
|
|
|
- self.angle = angle
|
|
|
|
|
-
|
|
|
|
|
- def __str__(self):
|
|
|
|
|
- return '<RotationGesture at (%s, %s) angle=%s>' \
|
|
|
|
|
- % (self.x, self.y, self.angle)
|
|
|
|
|
-
|
|
|
|
|
- def get_angle(self):
|
|
|
|
|
- return self.angle
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-class PinchGesture(Positionable, Gesture):
|
|
|
|
|
- """
|
|
|
|
|
- A pinch gesture has a scale (1.0 means no scaling) and a centroid from
|
|
|
|
|
- which the scaling originates.
|
|
|
|
|
- """
|
|
|
|
|
- _type = 'pinch'
|
|
|
|
|
-
|
|
|
|
|
- def __init__(self, centroid, scale):
|
|
|
|
|
- Positionable.__init__(self, *centroid.get_position())
|
|
|
|
|
- self.scale = scale
|
|
|
|
|
-
|
|
|
|
|
- def __str__(self):
|
|
|
|
|
- return '<PinchGesture at (%s, %s) scale=%s>' \
|
|
|
|
|
- % (self.x, self.y, self.scale)
|
|
|
|
|
-
|
|
|
|
|
- def get_scale(self):
|
|
|
|
|
- return self.scale
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-class MovementGesture(Positionable, Gesture):
|
|
|
|
|
- """
|
|
|
|
|
- A momevent gesture has an initial position, and a translation from that
|
|
|
|
|
- position.
|
|
|
|
|
- """
|
|
|
|
|
- _type = 'move'
|
|
|
|
|
-
|
|
|
|
|
- def __init__(self, initial_position, translation):
|
|
|
|
|
- Positionable.__init__(self, *initial_position.get_position())
|
|
|
|
|
- self.translation = translation
|
|
|
|
|
-
|
|
|
|
|
- def __str__(self):
|
|
|
|
|
- return '<MovementGesture at (%s, %s) translation=(%s, %s)>' \
|
|
|
|
|
- % (self.get_position() + self.translation.get_position())
|
|
|