8 import util.misc as misc_utils
11 _moduleLogger = logging.getLogger(__name__)
14 class NavigationBox(gobject.GObject):
18 gobject.SIGNAL_RUN_LAST,
20 (gobject.TYPE_STRING, ),
23 gobject.SIGNAL_RUN_LAST,
25 (gobject.TYPE_STRING, ),
34 gobject.GObject.__init__(self)
35 self._eventBox = gtk.EventBox()
36 self._eventBox.connect("button_press_event", self._on_button_press)
37 self._eventBox.connect("button_release_event", self._on_button_release)
38 self._eventBox.connect("motion_notify_event", self._on_motion_notify)
40 self._isPortrait = True
41 self._clickPosition = self._NO_POSITION
47 def set_orientation(self, orientation):
48 if orientation == gtk.ORIENTATION_VERTICAL:
49 self._isPortrait = True
50 elif orientation == gtk.ORIENTATION_HORIZONTAL:
51 self._isPortrait = False
53 raise NotImplementedError(orientation)
56 return self._clickPosition != self._NO_POSITION
58 def get_state(self, newCoord):
59 if self._clickPosition == self._NO_POSITION:
64 newCoord[0] - self._clickPosition[0],
65 - (newCoord[1] - self._clickPosition[1])
69 newCoord[1] - self._clickPosition[1],
70 - (newCoord[0] - self._clickPosition[0])
72 absDelta = (abs(delta[0]), abs(delta[1]))
73 if max(*absDelta) < self.MINIMUM_MOVEMENT:
76 if absDelta[0] < absDelta[1]:
87 @misc_utils.log_exception(_moduleLogger)
88 def _on_button_press(self, widget, event):
89 if self._clickPosition != self._NO_POSITION:
90 _moduleLogger.debug("Ignoring double click")
91 self._clickPosition = event.get_coords()
93 self.emit("navigating", "clicking")
95 @misc_utils.log_exception(_moduleLogger)
96 def _on_button_release(self, widget, event):
97 assert self._clickPosition != self._NO_POSITION
99 mousePosition = event.get_coords()
100 state = self.get_state(mousePosition)
103 self._clickPosition = self._NO_POSITION
104 self.emit("action", state)
106 @misc_utils.log_exception(_moduleLogger)
107 def _on_motion_notify(self, widget, event):
108 if self._clickPosition == self._NO_POSITION:
111 mousePosition = event.get_coords()
112 newState = self.get_state(mousePosition)
113 self.emit("navigating", newState)
116 gobject.type_register(NavigationBox)
119 class StreamPresenter(object):
121 def __init__(self, store):
124 self._image = gtk.DrawingArea()
125 self._image.connect("expose_event", self._on_expose)
127 self._isPortrait = True
129 self._backgroundImage = None
132 self._buttonImage = None
139 def set_orientation(self, orientation):
140 if orientation == gtk.ORIENTATION_VERTICAL:
141 self._isPortrait = True
142 elif orientation == gtk.ORIENTATION_HORIZONTAL:
143 self._isPortrait = False
145 raise NotImplementedError(orientation)
147 cairoContext = self._image.window.cairo_create()
148 if not self._isPortrait:
149 cairoContext.transform(cairo.Matrix(0, 1, 1, 0, 0, 0))
150 self._draw_presenter(cairoContext)
152 def set_state(self, stateImage):
153 if stateImage == self._imageName:
155 self._imageName = stateImage
156 self._buttonImage = self._store.get_surface_from_store(stateImage)
158 cairoContext = self._image.window.cairo_create()
159 if not self._isPortrait:
160 cairoContext.transform(cairo.Matrix(0, 1, 1, 0, 0, 0))
161 self._draw_presenter(cairoContext)
163 def set_context(self, backgroundImage, title, subtitle):
164 self._backgroundImage = self._store.get_surface_from_store(backgroundImage)
167 backWidth = self._backgroundImage.get_width()
168 backHeight = self._backgroundImage.get_height()
170 backHeight = self._backgroundImage.get_width()
171 backWidth = self._backgroundImage.get_height()
172 self._image.set_size_request(backWidth, backHeight)
174 cairoContext = self._image.window.cairo_create()
175 if not self._isPortrait:
176 cairoContext.transform(cairo.Matrix(0, 1, 1, 0, 0, 0))
177 self._draw_presenter(cairoContext)
179 @misc_utils.log_exception(_moduleLogger)
180 def _on_expose(self, widget, event):
181 cairoContext = self._image.window.cairo_create()
182 if not self._isPortrait:
183 cairoContext.transform(cairo.Matrix(0, 1, 1, 0, 0, 0))
184 self._draw_presenter(cairoContext)
186 def _draw_presenter(self, cairoContext):
188 rect = self._image.get_allocation()
189 cairoContext.rectangle(
195 cairoContext.set_source_rgb(0, 0, 0)
200 if self._backgroundImage is not None:
201 cairoContext.set_source_surface(
202 self._backgroundImage,
209 if self._title or self._subtitle:
210 backWidth = self._backgroundImage.get_width()
211 backHeight = self._backgroundImage.get_height()
213 pangoContext = self._image.create_pango_context()
214 textLayout = pango.Layout(pangoContext)
216 textLayout.set_markup(self._subtitle)
217 textWidth, textHeight = textLayout.get_pixel_size()
218 subtitleTextX = backWidth / 2 - textWidth / 2
219 subtitleTextY = backHeight - textHeight - self._buttonImage.get_height()
220 cairoContext.move_to(subtitleTextX, subtitleTextY)
221 cairoContext.set_source_rgb(0, 0, 0)
222 cairoContext.show_layout(textLayout)
224 textLayout.set_markup(self._title)
225 textWidth, textHeight = textLayout.get_pixel_size()
226 textX = backWidth / 2 - textWidth / 2
227 textY = subtitleTextY - textHeight
228 cairoContext.move_to(textX, textY)
229 cairoContext.set_source_rgb(0, 0, 0)
230 cairoContext.show_layout(textLayout)
232 self._draw_state(cairoContext)
234 def _draw_state(self, cairoContext):
235 if self._backgroundImage is None or self._buttonImage is None:
237 backWidth = self._backgroundImage.get_width()
238 backHeight = self._backgroundImage.get_height()
240 cairoContext.set_source_surface(
242 backWidth / 2 - self._buttonImage.get_width() / 2,
243 backHeight - self._buttonImage.get_height() + 5,
248 class StreamMiniPresenter(object):
250 def __init__(self, store):
253 self._button = gtk.Image()
259 def set_orientation(self, orientation):
262 def set_state(self, stateImage):
263 self._store.set_image_from_store(self._button, stateImage)
265 def set_context(self, backgroundImage, title, subtitle):