|
@@ -1,14 +1,19 @@
|
|
|
|
|
+from functools import partial
|
|
|
|
|
+
|
|
|
from geometry import Positionable
|
|
from geometry import Positionable
|
|
|
from logger import Logger
|
|
from logger import Logger
|
|
|
from trackers import create_tracker
|
|
from trackers import create_tracker
|
|
|
|
|
+from abc import ABCMeta, abstractmethod
|
|
|
|
|
|
|
|
|
|
|
|
|
class Widget(Positionable, Logger):
|
|
class Widget(Positionable, Logger):
|
|
|
"""
|
|
"""
|
|
|
- A widget represents a 2D object on the screen in which gestures can occur.
|
|
|
|
|
- Handlers for a specific gesture type can be bound to a widget. The widget
|
|
|
|
|
- will
|
|
|
|
|
|
|
+ Abstract class for widget implementations. A widget represents a 2D object
|
|
|
|
|
+ on the screen in which gestures can occur. Handlers for a specific gesture
|
|
|
|
|
+ type can be bound to a widget.
|
|
|
"""
|
|
"""
|
|
|
|
|
+ __metaclass__ = ABCMeta
|
|
|
|
|
+
|
|
|
def __init__(self, x=None, y=None):
|
|
def __init__(self, x=None, y=None):
|
|
|
Positionable.__init__(self, x, y)
|
|
Positionable.__init__(self, x, y)
|
|
|
|
|
|
|
@@ -22,21 +27,41 @@ class Widget(Positionable, Logger):
|
|
|
self.parent = None
|
|
self.parent = None
|
|
|
self.children = []
|
|
self.children = []
|
|
|
|
|
|
|
|
- def get_offset(self, offset_parent=None):
|
|
|
|
|
|
|
+ def get_root_widget(self):
|
|
|
|
|
+ """
|
|
|
|
|
+ Traverse up in the widget tree to find the root widget.
|
|
|
|
|
+ """
|
|
|
|
|
+ if self.parent:
|
|
|
|
|
+ return self.parent.get_root_widget()
|
|
|
|
|
+
|
|
|
|
|
+ return self
|
|
|
|
|
+
|
|
|
|
|
+ def get_screen_offset(self):
|
|
|
"""
|
|
"""
|
|
|
- Get the offset position relative to an offset parent. If no offset
|
|
|
|
|
- parent is specified, the parent widget is used. If no parent widget is
|
|
|
|
|
- assigned, return absolute coordinates.
|
|
|
|
|
|
|
+ Get the position relative to the screen.
|
|
|
"""
|
|
"""
|
|
|
- x, y = self.get_position()
|
|
|
|
|
|
|
+ root = self.get_root_widget()
|
|
|
|
|
+ return root + self.get_offset(root)
|
|
|
|
|
|
|
|
|
|
+ def get_offset(self, offset_parent=None):
|
|
|
|
|
+ """
|
|
|
|
|
+ Get the position relative to an offset parent. If no offset parent is
|
|
|
|
|
+ specified, the position relative to the root widget is returned. The
|
|
|
|
|
+ position of the root widget itself is (0, 0).
|
|
|
|
|
+ """
|
|
|
if not offset_parent:
|
|
if not offset_parent:
|
|
|
- if not self.parent:
|
|
|
|
|
- return x, y
|
|
|
|
|
|
|
+ offset_parent = self.get_root_widget()
|
|
|
|
|
|
|
|
- offset_parent = self.parent
|
|
|
|
|
|
|
+ if not self.parent:
|
|
|
|
|
+ if offset_parent is self:
|
|
|
|
|
+ return 0, 0
|
|
|
|
|
|
|
|
- ox, oy = offset_parent.get_position()
|
|
|
|
|
|
|
+ ox, oy = offset_paret
|
|
|
|
|
+ x = y = 0
|
|
|
|
|
+ else:
|
|
|
|
|
+ ox, oy = offset_parent
|
|
|
|
|
+ x = self.x
|
|
|
|
|
+ y = self.y
|
|
|
|
|
|
|
|
return x - ox, y - oy
|
|
return x - ox, y - oy
|
|
|
|
|
|
|
@@ -59,7 +84,7 @@ class Widget(Positionable, Logger):
|
|
|
Set a new parent widget. If a parent widget has already been assigned,
|
|
Set a new parent widget. If a parent widget has already been assigned,
|
|
|
remove the widget from that parent first.
|
|
remove the widget from that parent first.
|
|
|
"""
|
|
"""
|
|
|
- if self.parent:
|
|
|
|
|
|
|
+ if widget and self.parent:
|
|
|
self.parent.remove_widget(self)
|
|
self.parent.remove_widget(self)
|
|
|
|
|
|
|
|
self.parent = widget
|
|
self.parent = widget
|
|
@@ -95,13 +120,16 @@ class Widget(Positionable, Logger):
|
|
|
for gtype in self.trackers[gesture_type].gesture_types:
|
|
for gtype in self.trackers[gesture_type].gesture_types:
|
|
|
del self.handlers[gtype]
|
|
del self.handlers[gtype]
|
|
|
|
|
|
|
|
- def bind(self, gesture_type, handler, remove_existing=False):
|
|
|
|
|
|
|
+ def bind(self, gesture_type, handler, remove_existing=False, **kwargs):
|
|
|
"""
|
|
"""
|
|
|
Bind a handler to the specified type of gesture. Create a tracker for
|
|
Bind a handler to the specified type of gesture. Create a tracker for
|
|
|
- the gesture type if it does not exists yet.
|
|
|
|
|
|
|
+ the gesture type if it does not exists yet. Ik a new tracker is
|
|
|
|
|
+ created, configure is with any keyword arguments that have been
|
|
|
|
|
+ specified.
|
|
|
"""
|
|
"""
|
|
|
if gesture_type not in self.handlers:
|
|
if gesture_type not in self.handlers:
|
|
|
tracker = create_tracker(gesture_type, self)
|
|
tracker = create_tracker(gesture_type, self)
|
|
|
|
|
+ tracker.configure(**kwargs)
|
|
|
self.trackers[gesture_type] = tracker
|
|
self.trackers[gesture_type] = tracker
|
|
|
self.handlers[gesture_type] = []
|
|
self.handlers[gesture_type] = []
|
|
|
|
|
|
|
@@ -124,8 +152,9 @@ class Widget(Positionable, Logger):
|
|
|
raise AttributeError("'%s' has no attribute '%s'"
|
|
raise AttributeError("'%s' has no attribute '%s'"
|
|
|
% (self.__class__.__name__, name))
|
|
% (self.__class__.__name__, name))
|
|
|
|
|
|
|
|
- return lambda handler: self.bind(name[3:], handler)
|
|
|
|
|
|
|
+ return partial(self.bind, name[3:])
|
|
|
|
|
|
|
|
|
|
+ @abstractmethod
|
|
|
def contains_event(self, event):
|
|
def contains_event(self, event):
|
|
|
"""
|
|
"""
|
|
|
Check if the coordinates of an event are contained within this widget.
|
|
Check if the coordinates of an event are contained within this widget.
|
|
@@ -140,13 +169,20 @@ class Widget(Positionable, Logger):
|
|
|
if not self.children:
|
|
if not self.children:
|
|
|
self.propagate_event(event)
|
|
self.propagate_event(event)
|
|
|
else:
|
|
else:
|
|
|
|
|
+ event.set_offset(self.get_offset())
|
|
|
|
|
+ child_found = False
|
|
|
|
|
+
|
|
|
for child in self.children:
|
|
for child in self.children:
|
|
|
if child.contains_event(event):
|
|
if child.contains_event(event):
|
|
|
|
|
+ child_found = True
|
|
|
child.delegate_event(event)
|
|
child.delegate_event(event)
|
|
|
|
|
|
|
|
if event.is_propagation_stopped():
|
|
if event.is_propagation_stopped():
|
|
|
break
|
|
break
|
|
|
|
|
|
|
|
|
|
+ if not child_found:
|
|
|
|
|
+ self.propagate_event(event)
|
|
|
|
|
+
|
|
|
def propagate_event(self, event):
|
|
def propagate_event(self, event):
|
|
|
for tracker in set(self.trackers.itervalues()):
|
|
for tracker in set(self.trackers.itervalues()):
|
|
|
tracker.handle_event(event)
|
|
tracker.handle_event(event)
|