Protecting the shutdown path
[watersofshiloah] / src / presenter.py
index 1a23a52..e549c66 100644 (file)
@@ -2,9 +2,9 @@ import logging
 
 import gobject
 import pango
-import cairo
 import gtk
 
+import util.go_utils as go_utils
 import util.misc as misc_utils
 
 
@@ -191,19 +191,21 @@ class StreamPresenter(object):
                pangoContext = self._image.create_pango_context()
 
                titleLayout = pango.Layout(pangoContext)
-               titleLayout.set_markup(self._subtitle)
+               titleLayout.set_markup("<i>%s</i>" % self._subtitle)
                textWidth, textHeight = titleLayout.get_pixel_size()
                subtitleTextX = self._dims[0] / 2 - textWidth / 2
                subtitleTextY = self._dims[1] - textHeight - self._buttonImage.get_height() + 10
 
                subtitleLayout = pango.Layout(pangoContext)
-               subtitleLayout.set_markup(self._title)
+               subtitleLayout.set_markup("<b>%s</b>" % self._title)
                textWidth, textHeight = subtitleLayout.get_pixel_size()
                textX = self._dims[0] / 2 - textWidth / 2
                textY = subtitleTextY - textHeight
 
-               startContent = 30, textY - 5
-               endContent = self._dims[0] - 30,  self._dims[1] - 5
+               xPadding = min((self._dims[0] - textWidth) / 2 - 5, 5)
+               yPadding = 5
+               startContent = xPadding, textY - yPadding
+               endContent = self._dims[0] - xPadding,  self._dims[1] - yPadding
 
                # Control background
                cairoContext.rectangle(
@@ -257,3 +259,144 @@ class StreamMiniPresenter(object):
 
        def set_context(self, backgroundImage, title, subtitle):
                pass
+
+
+class NavControl(gobject.GObject, go_utils.AutoSignal):
+
+       __gsignals__ = {
+               'home' : (
+                       gobject.SIGNAL_RUN_LAST,
+                       gobject.TYPE_NONE,
+                       (),
+               ),
+               'jump-to' : (
+                       gobject.SIGNAL_RUN_LAST,
+                       gobject.TYPE_NONE,
+                       (gobject.TYPE_PYOBJECT, ),
+               ),
+       }
+
+       def __init__(self, player, store):
+               gobject.GObject.__init__(self)
+               self._layout = gtk.HBox()
+               go_utils.AutoSignal.__init__(self, self.toplevel)
+
+               self._store = store
+
+               self._controlButton = store.get_image_from_store(store.STORE_LOOKUP["play"])
+
+               self._controlBox = NavigationBox()
+               self._controlBox.toplevel.add(self._controlButton)
+               self.connect_auto(self._controlBox, "action", self._on_nav_action)
+               self.connect_auto(self._controlBox, "navigating", self._on_navigating)
+
+               self._titleButton = gtk.Label()
+
+               self._displayBox = NavigationBox()
+               self._displayBox.toplevel.add(self._titleButton)
+               self.connect_auto(self._displayBox, "action", self._on_nav_action)
+               self.connect_auto(self._displayBox, "navigating", self._on_navigating)
+
+               self._layout.pack_start(self._controlBox.toplevel, False, False)
+               self._layout.pack_start(self._displayBox.toplevel, True, True)
+               self._player = player
+               self.connect_auto(self._player, "state-change", self._on_player_state_change)
+               self.connect_auto(self._player, "title-change", self._on_player_title_change)
+               self._titleButton.set_label(self._player.title)
+
+       def refresh(self):
+               self._titleButton.set_label(self._player.title)
+               self._set_context(self._player.state)
+
+       def _set_context(self, state):
+               if state == self._player.STATE_PLAY:
+                       stateImage = self._store.STORE_LOOKUP["pause"]
+                       self._store.set_image_from_store(self._controlButton, stateImage)
+                       self.toplevel.show()
+               elif state == self._player.STATE_PAUSE:
+                       stateImage = self._store.STORE_LOOKUP["play"]
+                       self._store.set_image_from_store(self._controlButton, stateImage)
+                       self.toplevel.show()
+               elif state == self._player.STATE_STOP:
+                       self._titleButton.set_label("")
+                       self.toplevel.hide()
+               else:
+                       _moduleLogger.info("Unhandled player state %s" % state)
+                       stateImage = self._store.STORE_LOOKUP["pause"]
+                       self._store.set_image_from_store(self._controlButton, stateImage)
+
+       @property
+       def toplevel(self):
+               return self._layout
+
+       def set_orientation(self, orientation):
+               pass
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_player_state_change(self, player, newState):
+               if self._controlBox.is_active() or self._displayBox.is_active():
+                       return
+
+               self._set_context(newState)
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_player_title_change(self, player, node):
+               _moduleLogger.info("Title change: %s" % self._player.title)
+               self._titleButton.set_label(self._player.title)
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_navigating(self, widget, navState):
+               if navState == "down":
+                       imageName = "home"
+               elif navState == "clicking":
+                       if widget is self._controlBox:
+                               if self._player.state == self._player.STATE_PLAY:
+                                       imageName = "pause_pressed"
+                               else:
+                                       imageName = "play_pressed"
+                       else:
+                               if self._player.state == self._player.STATE_PLAY:
+                                       imageName = "pause"
+                               else:
+                                       imageName = "play"
+               elif self._player.can_navigate:
+                       if navState == "up":
+                               imageName = "play"
+                       elif navState == "left":
+                               imageName = "next"
+                       elif navState == "right":
+                               imageName = "prev"
+               else:
+                       if self._player.state == self._player.STATE_PLAY:
+                               imageName = "pause"
+                       else:
+                               imageName = "play"
+
+               imagePath = self._store.STORE_LOOKUP[imageName]
+               self._store.set_image_from_store(self._controlButton, imagePath)
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_nav_action(self, widget, navState):
+               self._set_context(self._player.state)
+
+               if navState == "clicking":
+                       if widget is self._controlBox:
+                               if self._player.state == self._player.STATE_PLAY:
+                                       self._player.pause()
+                               else:
+                                       self._player.play()
+                       elif widget is self._displayBox:
+                               self.emit("jump-to", self._player.node)
+                       else:
+                               raise NotImplementedError()
+               elif navState == "down":
+                       self.emit("home")
+               elif navState == "up":
+                       pass
+               elif navState == "left":
+                       self._player.next()
+               elif navState == "right":
+                       self._player.back()
+
+
+gobject.type_register(NavControl)