def drag_start(self, item, target, event): if not self._view.element.selected: self._view.timeline.selection.setToObj(self._view.element, SELECT) tx = self._view.props.parent.get_transform() # store y offset for later priority calculation self._y_offset = tx[5] # zero y component of mousdown coordiante self._mousedown = Point(self._mousedown[0], 0)
def from_event(self, event): return Point(*self.convert_from_pixels(event.x, event.y))
def pos(self, item): bounds = item.get_bounds() return Point(bounds.x1, bounds.y1)
def to_item_space(self, item, point): return Point(*self._canvas.convert_to_item_space(item, *point))
def from_item_event(self, item, event): return Point(*self._canvas.convert_from_item_space( item, *self.from_event(event)))
def from_event(self, event): """returns the coordinates of an event""" return Point(*self._canvas.convert_from_pixels(event.x, event.y))
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""" # note we SHOULD be using the gtk function for this, but it doesn't appear # to be exposed in pygtk __DRAG_THRESHOLD__ = Point(0, 0) _view = receiver() _dragging = None _canvas = None _cursor = None _ptr_within = False _last_click = None _initial = None _mousedown = None _last_event = None _pending_drag_start = None _pending_drag_end = False _shift_down = False _control_down = False _handle_enter_leave = True _handle_mouse_up_down = True _handle_motion_notify = True 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 to_item_space(self, item, point): return Point(*self._canvas.convert_to_item_space(item, *point)) def pos(self, item): bounds = item.get_bounds() return Point(bounds.x1, bounds.y1) ## signal handlers @handler(_view, "enter_notify_event") def enter_notify_event(self, item, target, event): self._event_common(item, target, event) self._canvas.grab_focus(item) if self._cursor and item is target: event.window.set_cursor(self._cursor) if not self._dragging: self.enter(item, target) self._ptr_within = True return self._handle_enter_leave or self._dragging @handler(_view, "leave_notify_event") def leave_notify_event(self, item, target, event): self._event_common(item, target, event) self._canvas.keyboard_ungrab(item, event.time) self._ptr_within = False if not self._dragging: self.leave(item, target) event.window.set_cursor(ARROW) return self._handle_enter_leave or self._dragging @handler(_view, "button_press_event") def button_press_event(self, item, target, event): self._event_common(item, target, 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._initial = self.pos(target) self._pending_drag_start = (item, target, event) return self._handle_mouse_up_down @handler(_view, "motion_notify_event") def motion_notify_event(self, item, target, event): self._event_common(item, target, event) if self._dragging: if self._pending_drag_start is not None: pending_drag_start, self._pending_drag_start = \ self._pending_drag_start, None self._pending_drag_end = True self._drag_start(*pending_drag_start) self.set_pos( self._dragging, self.transform(self._mousedown + self.from_item_event(item, event))) return self._handle_motion_notify else: self.hover(item, target, event) return False @handler(_view, "button_release_event") def button_release_event(self, item, target, event): self._event_common(item, target, event) self._drag_end(item, self._dragging, event) self._dragging = None return self._handle_mouse_up_down @handler(_view, "key_press_event") def key_press_event(self, item, target, event): self._event_common(item, target, event) kv = event.keyval if kv in (gtk.keysyms.Shift_L, gtk.keysyms.Shift_R): self._shift_down = True elif kv in (gtk.keysyms.Control_L, gtk.keysyms.Control_R): self._control_down = True return self.key_press(kv) @handler(_view, "key_release_event") def key_release_event(self, item, target, event): self._event_common(item, target, event) kv = event.keyval if kv in (gtk.keysyms.Shift_L, gtk.keysyms.Shift_R): self._shift_down = False elif kv in (gtk.keysyms.Control_L, gtk.keysyms.Control_R): self._control_down = False return self.key_release(kv) ## internal callbacks def _event_common(self, item, target, event): if not self._canvas: self._canvas = item.get_canvas() self._last_event = event s = event.get_state() self._shift_down = s & gtk.gdk.SHIFT_MASK self._control_down = s & gtk.gdk.CONTROL_MASK def _drag_start(self, item, target, event): self.drag_start(item, target, event) def _drag_end(self, item, target, event): self._pending_drag_start = None pending_drag_end, self._pending_drag_end = self._pending_drag_end, False if pending_drag_end: self.drag_end(item, target, event) if self._ptr_within and self._drag_threshold(): 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 event.window.set_cursor(self._cursor) else: event.window.set_cursor(ARROW) def _drag_threshold(self): last = self.pos(self._dragging) difference = abs(self._initial - last) if abs(self._initial - last) > self.__DRAG_THRESHOLD__: return False return True ## protected interface for subclasses def click(self, pos): pass def double_click(self, pos): pass def drag_start(self, item, target, event): pass def drag_end(self, item, target, event): pass def set_pos(self, obj, pos): obj.props.x, obj.props.y = pos def transform(self, pos): return pos def enter(self, item, target): pass def leave(self, item, target): pass def key_press(self, keyval): pass def key_release(self, keyval): pass def hover(self, item, target, event): pass
def from_event(self, event): x, y = event.x, event.y x += self.app.gui.timeline.hadj.get_value() return Point(*self.convert_from_pixels(x, y))