Commit 3c8c49a4 authored by UVA Multi-touch's avatar UVA Multi-touch

Started fixing cairo test program.

parent 918eb1b3
......@@ -27,6 +27,8 @@ class Area(Positionable, Logger):
self.parent = None
self.children = []
self.delegate_queue = {}
def get_root_area(self):
"""
Traverse up in the area tree to find the root area.
......@@ -36,24 +38,24 @@ class Area(Positionable, Logger):
return self
def get_screen_position(self):
def get_screen_offset(self):
"""
Get the position relative to the screen.
"""
if not self.parent:
return self.get_position()
ox, oy = self.parent.get_screen_position()
ox, oy = self.parent.get_screen_offset()
return ox + self.x, oy + self.y
def get_root_position(self):
def get_root_offset(self):
"""
Get the position relative to the root area.
"""
if not self.parent:
return 0, 0
ox, oy = self.parent.get_root_position()
ox, oy = self.parent.get_root_offset()
return ox + self.x, oy + self.y
def get_offset(self, offset_area):
......@@ -178,23 +180,19 @@ class Area(Positionable, Logger):
propagation, return so that its siblings and the parent area will not
delegate the event to their trackers.
"""
child_found = False
event.add_offset(*self.get_position())
#print 'delegated in %s: %s' % (self, event)
if self.children:
# Delegate to children in reverse order because areas that are
# added later, should be placed over previously added siblings
for child in reversed(self.children):
event.set_area(self)
if child.contains_event(event):
child_found = True
child.delegate_event(event)
delegate_to = [c for c in self.children
if c.contains_event(event)]
if event.is_propagation_stopped():
return
if delegate_to:
self.delegate_queue[event] = delegate_to
if not child_found:
self.propagate_event(event)
self.propagate_event(event)
def propagate_event(self, event):
"""
......@@ -202,7 +200,14 @@ class Area(Positionable, Logger):
propagate it to the parent area (if any). Propagation can be stopped by
a tracker.
"""
event.set_area(self)
if event in self.delegate_queue:
child = self.delegate_queue[event].pop()
if not self.delegate_queue[event]:
del self.delegate_queue[event]
child.delegate_event(event)
return
for tracker in self.trackers:
tracker.handle_event(event)
......@@ -211,6 +216,8 @@ class Area(Positionable, Logger):
return
if self.parent and not event.is_propagation_stopped():
event.add_offset(-self.x, -self.y)
#print 'propagated to %s: %s' % (self.parent, event)
self.parent.propagate_event(event)
def handle_gesture(self, gesture):
......
......@@ -21,7 +21,8 @@ class EventDriver(Logger):
Delegate an event that has been triggered by the event driver to the
area tree.
"""
self.root_area.delegate_event(event)
if self.root_area.contains_event(event):
self.root_area.delegate_event(event)
def start(self):
"""
......
......@@ -18,7 +18,6 @@ class Event(Positionable):
super(Event, self).__init__(*touch_object)
self.touch_object = touch_object
self.stopped = self.stopped_immidiate = False
self.area = None
def __getattr__(self, name):
if name in OBJECT_NAMES \
......@@ -28,22 +27,6 @@ class Event(Positionable):
raise AttributeError("'%s' object has no attribute '%s'"
% (self.__class__.__name__, name))
def set_area(self, area):
self.area = area
def get_area(self):
return self.area
def get_root_position(self):
return self.get_offset(self.area.get_root_area())
def get_position(self):
return self.get_offset(self.area)
def get_offset(self, area):
ox, oy = area.get_screen_position()
return self.x - ox, self.y - oy
def get_type(self):
return self._type
......
......@@ -19,7 +19,7 @@ class Positionable(object):
return repr(self)
def __iter__(self):
return iter((self.x, self.y))
return iter(self.get_position())
def __add__(self, other):
ox, oy = other
......@@ -38,19 +38,24 @@ class Positionable(object):
def __pow__(self, exp):
return Positionable(self.x ** exp, self.y ** exp)
def get_position(self):
return self.x, self.y
def set_position(self, x, y):
self.x = x
self.y = y
def get_position(self):
return self.x, self.y
def add_offset(self, add_x, add_y):
self.x -= add_x
self.y -= add_y
def distance_to(self, other):
"""
Calculate the Pythagorian distance from this positionable to another.
"""
x, y = self.get_position()
ox, oy = other
return ((ox - self.x) ** 2 + (oy - self.y) ** 2) ** .5
return ((ox - x) ** 2 + (oy - y) ** 2) ** .5
def translate(self, x, y):
self.set_position(self.x + x, self.y + y)
......@@ -78,6 +83,10 @@ class MovingPositionable(Positionable):
Positionable.set_position(self, x, y)
def add_offset(self, add_x, add_y):
Positionable.add_offset(self, add_x, add_y)
self.prev.add_offset(add_x, add_y)
def get_previous_position(self):
return self.prev
......@@ -106,9 +115,9 @@ class MovingPositionable(Positionable):
positionable.
"""
px, py = self.prev
return Positionable(self.x - px, self.y - py)
return self.x - px, self.y - py
def movement_distance(self):
def translation_distance(self):
return self.distance_to(self.prev)
......
......@@ -86,7 +86,7 @@ class TapTracker(GestureTracker):
self.last_tap = None
def on_point_down(self, event):
self.reg[event.point.get_id()] = time.time(), event
self.reg[event.point.get_id()] = time.time(), event.get_position()
def on_point_move(self, event):
oid = event.point.get_id()
......
......@@ -10,10 +10,11 @@ class RotationGesture(Gesture, Positionable):
"""
_type = 'rotate'
def __init__(self, event, centroid, angle):
def __init__(self, event, centroid, angle, n=1):
Gesture.__init__(self, event)
Positionable.__init__(self, *centroid.get_position())
self.angle = angle
self.n = n
def __str__(self):
return '<RotationGesture at (%s, %s) angle=%s>' \
......@@ -30,10 +31,11 @@ class PinchGesture(Gesture, Positionable):
"""
_type = 'pinch'
def __init__(self, event, centroid, scale):
def __init__(self, event, centroid, scale, n=1):
Gesture.__init__(self, event)
Positionable.__init__(self, *centroid.get_position())
self.scale = scale
self.n = n
def __str__(self):
return '<PinchGesture at (%s, %s) scale=%s>' \
......@@ -80,11 +82,9 @@ class TransformationTracker(GestureTracker):
self.points = []
# Current and previous centroid of all touch points
self.prev_centroid = self.centroid = None
self.centroid = None
def update_centroid(self):
self.prev_centroid = self.centroid
if not self.points:
self.centroid = None
return
......@@ -102,9 +102,6 @@ class TransformationTracker(GestureTracker):
else:
self.centroid = MovingPositionable(x, y)
#wx, wy = self.area.get_screen_offset()
#self.centroid.translate(-wx, -wy)
def on_point_down(self, event):
self.points.append(event.point)
self.update_centroid()
......@@ -118,26 +115,26 @@ class TransformationTracker(GestureTracker):
l = len(self.points)
if l > 1:
offset_centroid = self.centroid - self.area.get_screen_offset()
print self.centroid, self.area, offset_centroid
# Rotation (around the previous centroid)
rotation = point.rotation_around(self.centroid) / l
self.trigger(RotationGesture(event, self.centroid, rotation))
self.trigger(RotationGesture(event, offset_centroid, rotation, l))
# Scale
prev = point.get_previous_position().distance_to(self.centroid)
dist = point.distance_to(self.centroid)
prev = self.centroid.distance_to(point.get_previous_position())
dist = self.centroid.distance_to(point)
dist = prev + (dist - prev) / l
scale = dist / prev
self.trigger(PinchGesture(event, self.centroid, scale))
self.trigger(PinchGesture(event, offset_centroid, scale, l))
# Update centroid before movement can be detected
self.update_centroid()
# Update centroid before movement can be detected
self.update_centroid()
# Movement using multiple touch points
self.trigger(DragGesture(event, self.centroid,
self.centroid.translation(), l))
else:
# Movement using one touch point
self.trigger(DragGesture(event, point, point.translation()))
# Movement using multiple touch points
self.trigger(DragGesture(event, self.centroid,
self.centroid.translation(), l))
def on_point_up(self, event):
if event.point not in self.points:
......
......@@ -8,54 +8,70 @@ from threading import Thread
import src as mt
def quit(*args):
gtk.main_quit()
class Rectangle(mt.RectangularArea):
def __init__(self, x, y, width, height, color=(1, 0, 0)):
super(Rectangle, self).__init__(x, y, width, height)
self.angle = 1.0
self.w = width
self.h = height
self.scale = 1
self.angle = 0
self.color = color
self.t = cairo.Matrix()
self.t.translate(*self)
self.t.translate(x, y)
self.on_drag(self.move)
self.on_pinch(self.resize)
#self.on_rotate(self.rotate)
self.on_rotate(self.rotate)
def move(self, g):
print 'move:', g
self.translate(*g.get_translation())
print 'drag rectangle', self
self.ttrans(*g.get_translation())
refresh()
def resize(self, g):
print 'resize:', g.get_scale()
self.t.scale(g.get_scale(), g.get_scale())
print 'resize:', g
x, y = g.get_position()
scale = g.get_scale()
self.ttrans(x, y)
self.tscale(scale)
self.ttrans(-x, -y)
self.width *= scale
self.height *= scale
refresh()
def rotate(self, g):
w, h = self.get_size()
#self.t.translate(-w / 2, -h / 2)
self.t.rotate(-g.get_angle())
#self.t.translate(w / 2, h / 2)
print tuple(g)
x, y = g * .01
print x, y
#self.rot.translate(-x, -y)
print 'rotate:', g
x, y = g.get_position()
self.ttrans(x, y)
self.trot(-g.get_angle())
self.ttrans(-x, -y)
refresh()
def get_transformation_matrix(self):
def ttrans(self, tx, ty):
t = cairo.Matrix()
t.translate(*self)
t.rotate(self.angle)
t.scale(self.scale, self.scale)
return t
t.translate(tx, ty)
self.t = t * self.t
#self.t = self.t * t
def tscale(self, s):
t = cairo.Matrix()
t.scale(s, s)
self.t = t * self.t
def trot(self, a):
t = cairo.Matrix()
t.rotate(a)
self.t = t * self.t
def draw(self, cr):
w, h = self.get_size()
cr.transform(self.t)
cr.rectangle(0, 0, w, h)
cr.rectangle(0, 0, self.w, self.h)
cr.set_source_rgb(*self.color)
cr.fill()
......@@ -134,6 +150,10 @@ def refresh():
window.queue_draw()
def quit(*args):
gtk.main_quit()
# Initialization
window = cr = root = None
draw_objects = []
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment