Package elisa :: Package plugins :: Package bad :: Package raval_frontend :: Package raval_widgets :: Module finite_circular_list
[hide private]
[frames] | no frames]

Source Code for Module elisa.plugins.bad.raval_frontend.raval_widgets.finite_circular_list

  1  # -*- mode: python; coding: utf-8 -*- 
  2  # 
  3  # Pigment Python tools 
  4  # 
  5  # Copyright © 2006-2008 Fluendo Embedded S.L. 
  6  # 
  7  # This library is free software; you can redistribute it and/or 
  8  # modify it under the terms of the GNU Lesser General Public 
  9  # License as published by the Free Software Foundation; either 
 10  # version 2 of the License, or (at your option) any later version. 
 11  # 
 12  # This library is distributed in the hope that it will be useful, 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 15  # Lesser General Public License for more details. 
 16  # 
 17  # You should have received a copy of the GNU Lesser General Public 
 18  # License along with this library; if not, write to the 
 19  # Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
 20  # Boston, MA 02111-1307, USA. 
 21   
 22  import math 
 23  import time as mod_time 
 24   
 25  import pgm 
 26  from pgm.graph.group import Group 
 27  from pgm.graph.image import Image 
 28  from pgm.timing import implicit 
 29  from pgm.utils import maths 
 30  from pgm.widgets.list_ng import List 
 31  from pgm.widgets import const 
 32   
33 -class FiniteCircularList(List):
34
35 - def __init__(self):
36 super(FiniteCircularList, self).__init__() 37 self.orientation = const.HORIZONTAL 38 self.drag_motion_resolution = 0.01 39 self._initial_selected_item = True
40
41 - def compute_width(self, index):
42 # dividing by 2.0 because the items we insert are groups with an image 43 # and its reflection below, ugly! 44 return self.compute_height(index)/2.0
45
46 - def compute_height(self, index):
47 return self._height / self._visible_range_size
48
49 - def compute_x(self, index):
50 offset = math.pi/2.0 51 a = index/self._visible_range_size*math.pi*2.0 + offset 52 min_x = 0.0 53 max_x = self._width - self._widget_width 54 x = (1.0-math.cos(a))/2.0*(max_x-min_x) + min_x 55 return x
56
57 - def compute_y(self, index):
58 offset = math.pi/2.0 59 a = index/self._visible_range_size*math.pi*2.0 + offset 60 min_y = 0.0 61 max_y = self._height/2.0 62 y = (1.0+math.sin(a))/2.0*(max_y-min_y) + min_y 63 return y
64
65 - def compute_z(self, index):
66 offset = math.pi/2.0 67 a = index/self._visible_range_size*math.pi*2.0 + offset 68 min_z = -400.0 69 max_z = 0.0 70 z = (1.0+math.sin(a))/2.0*(max_z-min_z) + min_z 71 return z
72
73 - def compute_opacity(self, index):
74 offset = math.pi/2.0 75 a = index/self._visible_range_size*math.pi*2.0 + offset 76 min_opacity = 40 77 max_opacity = 255 78 opacity = (1.0+math.sin(a))/2.0*(max_opacity-min_opacity) + min_opacity 79 return opacity
80
81 - def compute_zoom(self, index):
82 offset = math.pi/2.0 83 a = index/self._visible_range_size*math.pi*2.0 + offset 84 min_zoom = 2.0 85 max_zoom = 4.0 86 zoom = (1.0+math.sin(a))/2.0*(max_zoom-min_zoom) + min_zoom 87 return zoom
88
89 - def selected_item__set(self, index):
90 if len(self.widgets) == 0: 91 return 92 93 prev_selected = self._selected_item 94 95 def positive_equivalent(index): 96 index = index % len(self.widgets) 97 if index < 0: 98 index = len(self.widgets) - index 99 return index
100 101 def shortest_path(start, end): 102 delta = end - start 103 if abs(delta) > self.visible_range_size/2.0: 104 if delta > 0: 105 delta -= self.visible_range_size 106 else: 107 delta += self.visible_range_size 108 return delta
109 110 # new selected item clamped to [0, len(self)-1] 111 self._selected_item = positive_equivalent(index) 112 113 # saving the target of the animation and stopping it 114 previous_target = self._animated.visible_range_start 115 self._animated.stop_animations() 116 117 # previous animation delta 118 previous_delta = previous_target - self.visible_range_start 119 # new animation delta 120 new_delta = previous_delta + \ 121 shortest_path(positive_equivalent(previous_target), 122 self._selected_item) 123 124 # reset the current visible_range_start with no visual change 125 self.visible_range_start = positive_equivalent(self.visible_range_start) 126 127 # setup the animation keeping the previous target and adding the 128 # new delta to reach the new selected item 129 if self._initial_selected_item: 130 self._initial_selected_item = False 131 self.visible_range_start = self.visible_range_start + new_delta 132 else: 133 self._animated.visible_range_start = self.visible_range_start + new_delta 134 135 if prev_selected != self._selected_item: 136 self.emit('selected-item-changed', self._selected_item) 137
138 - def range_start_to_selected(self):
139 selected = self.visible_range_start 140 selected = int(round(selected)) 141 return selected
142
143 - def _layout(self):
144 for i, widget in enumerate(self.widgets): 145 position = -self._visible_range_start + i 146 147 zoom = self.compute_zoom(position) 148 width = self._widget_width*zoom 149 height = self._widget_height*zoom 150 151 # update widget properties 152 widget.x = self.compute_x(position)-(width-self._widget_width)/2.0 153 widget.y = self.compute_y(position)-(height-self._widget_height)/2.0 154 widget.z = self.compute_z(position) 155 widget.opacity = self.compute_opacity(position) 156 widget.size = (width, height)
157
158 - def insert(self, index, widget):
159 widget.connect('clicked', self._fcl_child_clicked) 160 super(FiniteCircularList, self).insert(index, widget) 161 widget.visible = True 162 self.visible_range_size = max(1.0, len(self)) 163 self._layout()
164
165 - def pop(self, index):
166 widget = super(FiniteCircularList, self).pop(index) 167 self.visible_range_size = max(1.0, len(self)) 168 self._layout() 169 return widget
170
171 - def _fcl_child_clicked(self, drawable, x, y, z, button, time):
172 index = self.widgets.index(drawable) 173 self.emit('child-clicked', index) 174 175 return True
176
177 - def do_clicked(self, x, y, z, button, time):
178 # always let the children handle the clicks 179 return False
180
181 - def do_drag_motion(self, x, y, z, button, time):
182 # FIXME: copied from pgm.widgets.list_ng only to change the 183 # sensitivity 184 motion = 0 185 186 if self._orientation == const.VERTICAL: 187 motion = y - self._initial[1] 188 self.visible_range_start -= motion / self._widget_height 189 elif self._orientation == const.HORIZONTAL: 190 motion = x - self._initial[0] 191 self.visible_range_start -= motion / self._widget_width / 6.0 192 193 time_delta = time - self._initial[2] 194 if time_delta != 0: 195 self.speed = motion/time_delta*1000.0 196 self.speed = maths.clamp(self.speed, -14.0, 14.0) 197 198 self._initial = (x, y, time) 199 self._drag_accum += abs(motion) 200 201 return True
202 203 deceleration = 8.0
204 - def _decelerate(self):
205 self._previous_time = self._current_time 206 self._current_time = mod_time.time() 207 delta = self._current_time - self._previous_time 208 209 if self.speed > 0.0: 210 self.speed -= self.deceleration*delta 211 if self.speed > 0.0: 212 self.visible_range_start -= self.speed*delta 213 return True 214 215 elif self.speed < 0.0: 216 self.speed += self.deceleration*delta 217 if self.speed < 0.0: 218 self.visible_range_start -= self.speed*delta 219 return True 220 221 self.selected_item = self.range_start_to_selected() 222 return False
223 224 if __name__ == "__main__": 225 import pgm 226 import gobject 227 import gst 228 import glob, sys 229 from pgm.graph.text import Text 230 from pgm.graph.image import Image 231
232 - def create_text(label):
233 txt = Text() 234 txt.label = label 235 txt.font_family = "Bitstream DejaVu" 236 txt.font_height = 0.225 237 txt.fg_color = (255, 255, 255, 255) 238 txt.bg_color = (255, 0, 0, 255) 239 txt.ellipsize = pgm.TEXT_ELLIPSIZE_END 240 txt.visible = True 241 return txt
242
243 - def create_img(img_file):
244 img = Image() 245 img.set_from_file(img_file, 512) 246 img.fg_color = (255, 255, 255, 255) 247 img.bg_color = (100, 200, 100, 155) 248 img.bg_color = (0, 0, 0, 0) 249 img.visible = True 250 return img
251
252 - def create_reflection(master_img):
253 img = Image() 254 img.set_from_image(master_img) 255 img.fg_color = (255, 255, 255, 255) 256 img.bg_color = (100, 100, 200, 155) 257 img.bg_color = (0, 0, 0, 0) 258 # img.width = -master_img.width 259 img.height = master_img.height 260 img.opacity = 30 261 # img.x += master_img.width 262 img.layout = pgm.IMAGE_SCALED 263 img.y += master_img.height 264 img.alignment = pgm.IMAGE_TOP 265 img.visible = True 266 return img
267
268 - def create_video(video_uri):
269 img = Image() 270 img.fg_color = (255, 255, 255, 255) 271 img.bg_color = (0, 0, 0, 0) 272 img.alignment = pgm.IMAGE_LEFT 273 img.visible = True 274 275 # GStreamer pipeline setup 276 pipeline = gst.element_factory_make('playbin') 277 sink = gst.element_factory_make('pgmimagesink') 278 pipeline.set_property('uri', video_uri) 279 pipeline.set_property('video-sink', sink) 280 sink.set_property('image', img) 281 pipeline.set_state(gst.STATE_PLAYING) 282 283 return img
284 285
286 - def on_key_press(viewport, event, widget):
287 if event.type == pgm.KEY_PRESS: 288 # quit on q or ESC 289 if event.keyval == pgm.keysyms.q or \ 290 event.keyval == pgm.keysyms.Escape: 291 pgm.main_quit() 292 293 elif event.keyval == pgm.keysyms.f: 294 viewport.fullscreen = not viewport.fullscreen 295 296 elif event.keyval == pgm.keysyms.Down or \ 297 event.keyval == pgm.keysyms.Right: 298 # widget.selected_item = (widget.selected_item + 1) % len(widget) 299 widget.selected_item += 1 300 301 elif event.keyval == pgm.keysyms.Up or \ 302 event.keyval == pgm.keysyms.Left: 303 # widget.selected_item = (widget.selected_item - 1) % len(widget) 304 widget.selected_item -= 1 305 306 elif event.keyval == pgm.keysyms.space: 307 #widget.insert(0, create_text("T")) 308 def test(): 309 # img = create_img("/home/kaleo/dev/pigment/examples/pictures/fluendo.png") 310 """ 311 list_widget.insert(0, img) 312 list_widget.pop(len(list_widget)-1) 313 """ 314 img = list_widget.pop(0) 315 list_widget.append(img) 316 return True
317 gobject.timeout_add(1000, test) 318 # list_widget.append(img) 319 320 # remove the currently selected item 321 elif event.keyval == pgm.keysyms.Return: 322 print "popping", widget.selected_item 323 widget.pop(widget.selected_item) 324
325 - def on_delete(viewport, event):
326 pgm.main_quit()
327 328 329 # OpenGL viewport creation 330 factory = pgm.ViewportFactory('opengl') 331 gl = factory.create() 332 gl.title = 'Finite circular list widget' 333 334 # Canvas and image drawable creation 335 canvas = pgm.Canvas() 336 337 # Bind the canvas to the OpenGL viewport 338 gl.set_canvas(canvas) 339 gl.show() 340 341 list_widget = FiniteCircularList() 342 list_widget.position = (0.5, 0.0, 0.0) 343 list_widget.width = 3.0 344 list_widget.height = 3.0 345 list_widget.visible = True 346 list_widget.canvas = canvas 347 348 files = sys.argv[1:] 349 for file in files[:5]: 350 print file 351 image = create_img(file) 352 list_widget.append(image) 353 """ 354 # reflection code 355 image.alignment = pgm.IMAGE_BOTTOM 356 reflection = create_reflection(image) 357 g = Group(canvas, pgm.DRAWABLE_MIDDLE) 358 g.add(image) 359 g.add(reflection) 360 g.visible = True 361 list_widget.append(g) 362 """ 363 364 # Let's start a mainloop 365 gl.connect('key-press-event', 366 on_key_press, 367 list_widget) 368 gl.connect('delete-event', on_delete) 369 pgm.main() 370