This repository has been archived by the owner on Apr 29, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcontroller.py
144 lines (113 loc) · 4.1 KB
/
controller.py
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from receiver import receiver, handler
from point import Point
import gtk
# Controllers are reusable and implement specific behaviors. Currently this
# Includes only click, and drag. Multiple controllers could be attached to a
# given view, but might interfere with each other if they attempt to handle
# the same set of signals. It is probably better to define a new controller
# that explictly combines the functionality of both when custom behavior is
# desired.
class Controller(object):
"""A controller which implements drag-and-drop bahavior on connected view
objects. Subclasses may override the drag_start, drag_end, pos, and
set_pos methods"""
_view = receiver()
_dragging = None
_canvas = None
_cursor = None
_ptr_within = False
_last_click = None
_mousedown = None
_last_event = None
def __init__(self, view=None):
object.__init__(self)
self._view = view
## convenience functions
def from_event(self, event):
"""returns the coordinates of an event"""
return Point(*self._canvas.convert_from_pixels(event.x, event.y))
def from_item_event(self, item, event):
return Point(*self._canvas.convert_from_item_space(item,
*self.from_event(event)))
def pos(self, item):
bounds = item.get_bounds()
return Point(bounds.x1, bounds.y1)
def size(self, item):
bounds = item.get_bounds()
return Point(bounds.x2, bounds.y2) - Point(bounds.x1, bounds.y1)
def center(self, item):
return self.pos(item) + self.size(item) // 2
def last_xy(self):
return self.transform(self._mousedown + self.from_event(
self._last_event))
## signal handlers
@handler(_view, "enter_notify_event")
def enter_notify_event(self, item, target, event):
self._last_event = event
if self._cursor:
event.window.set_cursor(self._cursor)
self.enter(item, target)
self._ptr_within = True
return True
@handler(_view, "leave_notify_event")
def leave_notify_event(self, item, target, event):
self._last_event = event
self._ptr_within = False
if not self._dragging:
self.leave(item, target)
return True
@handler(_view, "button_press_event")
def button_press_event(self, item, target, event):
self._last_event = event
if not self._canvas:
self._canvas = item.get_canvas()
self._mousedown = self.pos(item) - self.transform(self.from_item_event(
item, event))
self._dragging = target
self._drag_start(item, target, event)
return True
@handler(_view, "motion_notify_event")
def motion_notify_event(self, item, target, event):
self._last_event = event
if self._dragging:
self.set_pos(self._dragging,
self.transform(self._mousedown + self.from_item_event(item,
event)))
return True
return False
@handler(_view, "button_release_event")
def button_release_event(self, item, target, event):
self._last_event = event
self._drag_end(item, self._dragging, event)
self._dragging = None
return True
## internal callbacks
def _drag_start(self, item, target, event):
self.drag_start()
def _drag_end(self, item, target, event):
self.drag_end()
if self._ptr_within:
point = self.from_item_event(item, event)
if self._last_click and (event.time - self._last_click < 400):
self.double_click(point)
else:
self.click(point)
self._last_click = event.time
## protected interface for subclasses
def click(self, pos):
pass
def double_click(self, pos):
pass
def drag_start(self):
pass
def drag_end(self):
pass
def set_pos(self, obj, pos):
x, y = pos
self._view.set_simple_transform(x, y, 1.0, 0.0)
def transform(self, pos):
return pos
def enter(self, item, target):
pass
def leave(self, item, target):
pass