+ _NO_POSITION = -1, -1
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self._eventBox = gtk.EventBox()
+ self._eventBox.connect("button_press_event", self._on_button_press)
+ self._eventBox.connect("button_release_event", self._on_button_release)
+ self._eventBox.connect("motion_notify_event", self._on_motion_notify)
+
+ self._isPortrait = True
+ self._clickPosition = self._NO_POSITION
+
+ @property
+ def toplevel(self):
+ return self._eventBox
+
+ def set_orientation(self, orientation):
+ if orientation == gtk.ORIENTATION_VERTICAL:
+ self._isPortrait = True
+ elif orientation == gtk.ORIENTATION_HORIZONTAL:
+ self._isPortrait = False
+ else:
+ raise NotImplementedError(orientation)
+
+ def is_active(self):
+ return self._clickPosition != self._NO_POSITION
+
+ def get_state(self, newCoord):
+ if self._clickPosition == self._NO_POSITION:
+ return ""
+
+ if self._isPortrait:
+ delta = (
+ newCoord[0] - self._clickPosition[0],
+ - (newCoord[1] - self._clickPosition[1])
+ )
+ else:
+ delta = (
+ newCoord[1] - self._clickPosition[1],
+ - (newCoord[0] - self._clickPosition[0])
+ )
+ absDelta = (abs(delta[0]), abs(delta[1]))
+ if max(*absDelta) < self.MINIMUM_MOVEMENT:
+ return "clicking"
+
+ if absDelta[0] < absDelta[1]:
+ if 0 < delta[1]:
+ return "up"
+ else:
+ return "down"
+ else:
+ if 0 < delta[0]:
+ return "right"
+ else:
+ return "left"
+
+ @misc_utils.log_exception(_moduleLogger)
+ def _on_button_press(self, widget, event):
+ if self._clickPosition != self._NO_POSITION:
+ _moduleLogger.debug("Ignoring double click")
+ self._clickPosition = event.get_coords()
+
+ self.emit("navigating", "clicking")
+
+ @misc_utils.log_exception(_moduleLogger)
+ def _on_button_release(self, widget, event):
+ assert self._clickPosition != self._NO_POSITION
+ try:
+ mousePosition = event.get_coords()
+ state = self.get_state(mousePosition)
+ assert state
+ self.emit("action", state)
+ finally:
+ self._clickPosition = self._NO_POSITION
+
+ @misc_utils.log_exception(_moduleLogger)
+ def _on_motion_notify(self, widget, event):
+ if self._clickPosition == self._NO_POSITION:
+ return
+
+ mousePosition = event.get_coords()
+ newState = self.get_state(mousePosition)
+ self.emit("navigating", newState)
+
+
+gobject.type_register(NavigationBox)
+
+
+class StreamPresenter(object):
+