Package dtk :: Package ui :: Module slider

Source Code for Module dtk.ui.slider

  1  #! /usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  # Copyright (C) 2011 ~ 2012 Deepin, Inc. 
  5  #               2011 ~ 2012 Wang Yong 
  6  #  
  7  # Author:     Wang Yong <lazycat.manatee@gmail.com> 
  8  # Maintainer: Wang Yong <lazycat.manatee@gmail.com> 
  9  #  
 10  # This program is free software: you can redistribute it and/or modify 
 11  # it under the terms of the GNU General Public License as published by 
 12  # the Free Software Foundation, either version 3 of the License, or 
 13  # any later version. 
 14  #  
 15  # This program is distributed in the hope that it will be useful, 
 16  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 17  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 18  # GNU General Public License for more details. 
 19  #  
 20  # You should have received a copy of the GNU General Public License 
 21  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 22   
 23  from draw import draw_pixbuf 
 24  from timeline import Timeline, CURVE_SINE 
 25  from utils import move_window, is_in_rect 
 26  from window import Window 
 27  import gobject 
 28  import gtk 
 29   
30 -class Slider(gtk.Viewport):
31 ''' 32 Slider. 33 34 @undocumented: size_allocate_cb 35 ''' 36 37 active_widget = None 38 _size_cache = None 39
40 - def __init__(self, slide_callback=None):
41 ''' 42 Initialize Slider class. 43 44 @param slide_callback: Callback when slider change image, arguments: (index, widget), default is None. 45 ''' 46 gtk.Viewport.__init__(self) 47 self.slide_callback = slide_callback 48 self.timeouts = dict() 49 50 self.set_shadow_type(gtk.SHADOW_NONE) 51 52 self.layout = gtk.HBox(True) 53 self.content = gtk.EventBox() 54 self.content.add(self.layout) 55 56 self.container = gtk.Fixed() 57 self.container.add(self.content) 58 self.add(self.container) 59 60 self.connect('size-allocate', self.size_allocate_cb)
61
62 - def slide_to(self, widget):
63 ''' 64 Slide to given widget. 65 66 @param widget: Widget in slider. 67 ''' 68 self.active_widget = widget 69 70 def update(source, status): 71 pos = end_position - start_position 72 adjustment.set_value(start_position + int(round(status * pos)))
73 74 adjustment = self.get_hadjustment() 75 start_position = adjustment.get_value() 76 end_position = widget.get_allocation().x 77 78 if start_position != end_position: 79 timeline = Timeline(500, CURVE_SINE) 80 timeline.connect('update', update) 81 timeline.run() 82 83 if self.slide_callback: 84 self.slide_callback(self.layout.get_children().index(widget), widget)
85
86 - def size_allocate_cb(self, source, allocation):
87 ''' 88 Internal function for `size-allocate` signal. 89 ''' 90 if self._size_cache != allocation and self.active_widget: 91 adjustment = self.get_hadjustment() 92 adjustment.set_value(self.active_widget.get_allocation().x) 93 94 self._size_cache = allocation 95 96 width = (len(self.layout.get_children()) or 1) * allocation.width 97 self.content.set_size_request(width, allocation.height)
98
99 - def append_widget(self, widget):
100 ''' 101 Append widget. 102 103 @param widget: Widget to append in slider. 104 ''' 105 self.layout.pack_start(widget, True, True, 0)
106
107 - def add_slide_timeout(self, widget, milliseconds):
108 """ 109 Adds a timeout for ``widget`` to slide in after ``seconds``. 110 111 @param widget: Add widget. 112 @param milliseconds: Delay time. 113 """ 114 if widget in self.timeouts: 115 raise RuntimeError("A timeout for '%s' was already added" % widget) 116 117 callback = lambda: self.slide_to(widget) 118 self.timeouts[widget] = (gobject.timeout_add(milliseconds, callback), 119 milliseconds)
120
121 - def remove_slide_timeout(self, widget):
122 """ 123 Removes a timeout previously added by ``add_slide_timeout``. 124 125 @param widget: Remove widget from slider. 126 """ 127 try: 128 gobject.source_remove(self.timeouts.pop(widget)[0]) 129 except KeyError: 130 pass
131 132
133 - def reset_slide_timeout(self, widget, milliseconds=None):
134 """ 135 Shorthand to ``remove_slide_timeout`` plus ``add_slide_timeout``. 136 137 @param widget: Slider wiget. 138 @param milliseconds: New delay value. 139 """ 140 if milliseconds is None: 141 try: 142 milliseconds = self.timeouts[widget][1] 143 except KeyError: 144 pass 145 else: 146 self.remove_slide_timeout(widget) 147 self.add_slide_timeout(widget, milliseconds)
148
149 - def try_remove_slide_timeout(self, widget):
150 ''' 151 Try remove slide timeout that match given widget. 152 153 @param widget: Match widget. 154 ''' 155 try: 156 self.remove_slide_timeout(widget) 157 except RuntimeError: 158 pass
159
160 - def try_reset_slide_timeout(self, widget, *args, **kwargs):
161 """ 162 Like ``reset_slide_timeout``, but fails silently 163 if the timeout for``widget`` does not exist. 164 165 """ 166 if widget in self.timeouts: 167 self.reset_slide_timeout(widget, *args, **kwargs)
168 169 gobject.type_register(Slider) 170
171 -class Wizard(Window):
172 ''' 173 Wizard. 174 175 @undocumented: button_press_slider 176 @undocumented: button_press_navigatebar 177 @undocumented: expose_navigatebar 178 ''' 179
180 - def __init__(self, 181 slider_files, 182 navigate_files, 183 finish_callback=None, 184 window_width=548, 185 window_height=373, 186 navigatebar_height=58, 187 slide_delay=4000, 188 close_area_width=32, 189 close_area_height=32, 190 ):
191 ''' 192 Initialize Wizard class. 193 194 @param slider_files: Big slide image file list. 195 @param navigate_files: Small navigate image file list. 196 @param finish_callback: Callback when finish show. 197 @param window_width: Default window width. 198 @param window_height: Default window height. 199 @param navigatebar_height: Navigatebar height. 200 @param slide_delay: Delay of slide, in milliseconds. 201 @param close_area_width: Width of top-right close area. 202 @param close_area_height: Height of top-right close area. 203 ''' 204 # Init. 205 Window.__init__(self) 206 self.slider_files = slider_files 207 self.finish_callback = finish_callback 208 self.window_width = window_width 209 self.window_height = window_height 210 self.navigatebar_height = navigatebar_height 211 self.slider_number = len(self.slider_files) 212 self.slide_index = 0 213 self.slide_delay = slide_delay # milliseconds 214 self.close_area_width = close_area_width 215 self.close_area_height = close_area_height 216 217 # Init navigate pixbufs. 218 self.select_pixbufs = [] 219 self.unselect_pixbufs = [] 220 for (select_file, unselect_file) in navigate_files: 221 self.select_pixbufs.append(gtk.gdk.pixbuf_new_from_file(select_file)) 222 self.unselect_pixbufs.append(gtk.gdk.pixbuf_new_from_file(unselect_file)) 223 self.navigate_item_width = self.select_pixbufs[0].get_width() 224 225 # Set window attributes. 226 self.set_resizable(False) 227 self.set_position(gtk.WIN_POS_CENTER) 228 self.set_size_request(self.window_width, self.window_height) 229 230 # Add widgets. 231 self.main_box = gtk.VBox() 232 self.slider = Slider(self.set_slide_page) 233 self.navigatebar = gtk.EventBox() 234 self.navigatebar.set_visible_window(False) 235 self.navigatebar.set_size_request(-1, self.navigatebar_height) 236 self.main_box.pack_start(self.slider, True, True) 237 self.main_box.pack_start(self.navigatebar, True, True) 238 self.main_align = gtk.Alignment() 239 self.main_align.set(0.5, 0.5, 1, 1) 240 self.main_align.set_padding(0, 0, 0, 0) 241 self.main_align.add(self.main_box) 242 self.window_frame.add(self.main_align) 243 244 # Start animation. 245 self.slider_widgets = [] 246 for (index, slider_file) in enumerate(self.slider_files): 247 widget = gtk.image_new_from_file(slider_file) 248 self.slider_widgets.append(widget) 249 self.slider.append_widget(widget) 250 self.slider.add_slide_timeout(widget, index * self.slide_delay) 251 252 self.slider.connect("button-press-event", self.button_press_slider) 253 self.navigatebar.connect("button-press-event", self.button_press_navigatebar) 254 self.navigatebar.connect("expose-event", self.expose_navigatebar)
255
256 - def button_press_slider(self, widget, event):
257 ''' 258 Internal callback for slider's `button-press-event` signal. 259 ''' 260 rect = widget.allocation 261 (window_x, window_y) = widget.get_toplevel().window.get_origin() 262 if (self.slide_index == self.slider_number - 1 263 and is_in_rect((event.x_root, event.y_root), 264 (window_x + rect.width - self.close_area_width, 265 window_y, 266 self.close_area_width, 267 self.close_area_height))): 268 if self.finish_callback: 269 self.finish_callback() 270 271 self.destroy() 272 else: 273 widget.connect("button-press-event", lambda w, e: move_window(w, e, self))
274
275 - def button_press_navigatebar(self, widget, event):
276 ''' 277 Internal callback for navigatebar's `button-press-event` signal. 278 ''' 279 # Init. 280 rect = widget.allocation 281 282 # Get navigate index. 283 navigate_index = int(event.x / (rect.width / self.slider_number)) 284 285 # Remove slider timeout. 286 for widget in self.slider_widgets: 287 self.slider.try_remove_slide_timeout(widget) 288 289 # Slide select widget. 290 self.slider.slide_to(self.slider_widgets[navigate_index]) 291 292 # Reset timeout. 293 if navigate_index < self.slider_number - 1: 294 for (index, widget) in enumerate(self.slider_widgets[navigate_index::]): 295 self.slider.add_slide_timeout(widget, index * self.slide_delay)
296
297 - def expose_navigatebar(self, widget, event):
298 ''' 299 Internal callback for `expose-event` signal. 300 ''' 301 # Init. 302 cr = widget.window.cairo_create() 303 rect = widget.allocation 304 305 # Render unselect item. 306 for (index, unselect_pixbuf) in enumerate(self.unselect_pixbufs): 307 if index != self.slide_index: 308 draw_pixbuf(cr, unselect_pixbuf, 309 rect.x + index * self.navigate_item_width, 310 rect.y) 311 312 # Render select item. 313 draw_pixbuf(cr, self.select_pixbufs[self.slide_index], 314 rect.x + self.slide_index * self.navigate_item_width, 315 rect.y) 316 317 return True
318
319 - def set_slide_page(self, index, widget):
320 ''' 321 Set slide page. 322 323 @param index: Index to set. 324 @param widget: The widget you want to set. 325 ''' 326 self.slide_index = index 327 self.navigatebar.queue_draw()
328 329 gobject.type_register(Wizard) 330 331 if __name__ == "__main__": 332 window = gtk.Window() 333 window.set_size_request(752, 452) 334 window.connect("destroy", lambda w: gtk.main_quit()) 335 336 image1 = gtk.image_new_from_file("/test/Download/ubiquity-slideshow-deepin-11.12.2/slideshows/deepin-zh-hans/slides/screenshots/1.png") 337 image2 = gtk.image_new_from_file("/test/Download/ubiquity-slideshow-deepin-11.12.2/slideshows/deepin-zh-hans/slides/screenshots/2.png") 338 image3 = gtk.image_new_from_file("/test/Download/ubiquity-slideshow-deepin-11.12.2/slideshows/deepin-zh-hans/slides/screenshots/3.png") 339 image4 = gtk.image_new_from_file("/test/Download/ubiquity-slideshow-deepin-11.12.2/slideshows/deepin-zh-hans/slides/screenshots/4.png") 340 341 slider = Slider() 342 slider.append_widget(image1) 343 slider.append_widget(image2) 344 slider.append_widget(image3) 345 slider.append_widget(image4) 346 window.add(slider) 347 348 slider.add_slide_timeout(image1, 1) 349 slider.add_slide_timeout(image2, 2) 350 slider.add_slide_timeout(image3, 3) 351 slider.add_slide_timeout(image4, 4) 352 353 window.show_all() 354 gtk.main() 355