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
108
|
from pyglet.event import EVENT_HANDLED
def _rx(child, x):
if getattr(child, 'relative', False):
### WARNING: not yet true for any class!
### todo: always define it, so no getattr needed;
# or better, make a method on child to transform x or y.
return x - child.x
else:
return x
pass
def _ry(child, y):
if getattr(child, 'relative', False):
return y - child.y
else:
return y
pass
class EventDistributorToChildren(object):
"""
Pass events onto the appropriate child out of a collection of children,
known to us only via find_child passed to our constructor,
assuming each child has a correctly set .size and .pos.
"""
# note: see class pyglet.window.event.WindowEventLogger for defs of all window events
child_with_mouse = None
child_with_drag = None
def __init__(self, find_child):
self.find_child = find_child # call with (x,y), returns child or None
def on_mouse_enter(self, x, y):
child = self.find_child(x, y)
self._set_child_with_mouse(child, x, y)
if child:
return EVENT_HANDLED
def _set_child_with_mouse(self, child, x, y):
"""
Maintain self.child_with_mouse, and send enter/leave events to children
when it changes.
@param child: the child with the last unpressed mouse position in it,
or None if that position is not in one of our children
@return: whether this call changed the value of self.child_with_mouse
"""
if child is not self.child_with_mouse:
if self.child_with_mouse:
self.child_with_mouse.dispatch_event('on_mouse_leave',
_rx(self.child_with_mouse, x),
_ry(self.child_with_mouse, y) )
if child:
child.dispatch_event('on_mouse_enter', _rx(child, x), _ry(child, y))
self.child_with_mouse = child
return True # different child
def on_mouse_press(self, x, y, button, modifiers):
child = self.find_child(x, y)
if child:
child.dispatch_event('on_mouse_press', _rx(child, x), _ry(child, y), button, modifiers)
self.child_with_drag = child ##k only appropriate for some children??
return EVENT_HANDLED
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
if self.child_with_drag:
## maybe todo: also only send this if distance gets high enough to count as a drag
self.child_with_drag.dispatch_event('on_mouse_drag',
_rx(self.child_with_drag, x),
_ry(self.child_with_drag, y),
dx, dy, buttons, modifiers )
return EVENT_HANDLED
def on_mouse_release(self, x, y, button, modifiers):
if self.child_with_drag:
self.child_with_drag.dispatch_event('on_mouse_release',
_rx(self.child_with_drag, x),
_ry(self.child_with_drag, y),
button, modifiers )
self.on_mouse_enter(x, y) # seems correct, though perhaps a kluge
# REVIEW: what if x,y not in self, is this still correct?
return EVENT_HANDLED
def on_mouse_motion(self, x, y, dx, dy):
child = self.find_child(x, y)
if self._set_child_with_mouse(child, _rx(child, x), _ry(child, y)):
# different child -- no motion event needed within one,
# leave/enter events cover it
pass
else:
# same child -- tell it about the motion
if child:
child.dispatch_event('on_mouse_motion', _rx(child, x), _ry(child, y), dx, dy)
if child:
return EVENT_HANDLED #k not sure this is accurate in all cases
def on_mouse_leave(self, x, y):
self._set_child_with_mouse(None, -1, -1)
#todo:
def on_mouse_scroll(self, *args):
pass
def on_resize(self, *args):
pass # even when we respond, in this case return None to let window respond too
pass
class ChildHolder(object): # not yet used?
"abstract class"
pass
class SimpleChildHolder(EventDistributorToChildren, ChildHolder): # not yet used?
def __init__(self):
EventDistributorToChildren.__init__(self, self._find_child) # kluge?
def _find_child(self, x, y):
pass # nim
|