summaryrefslogtreecommitdiff
path: root/cad/src/experimental/demoapp_0.1/demoapp/widgets/ChildHolder.py
blob: 812ecef97052bbee589c5481903bdb77b7528600 (plain)
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