Package advene :: Package gui :: Module widget
[hide private]
[frames] | no frames]

Source Code for Module advene.gui.widget

   1  # 
   2  # Advene: Annotate Digital Videos, Exchange on the NEt 
   3  # Copyright (C) 2008 Olivier Aubert <olivier.aubert@liris.cnrs.fr> 
   4  # 
   5  # Advene is free software; you can redistribute it and/or modify 
   6  # it under the terms of the GNU General Public License as published by 
   7  # the Free Software Foundation; either version 2 of the License, or 
   8  # (at your option) any later version. 
   9  # 
  10  # Advene is distributed in the hope that it will be useful, 
  11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  13  # GNU General Public License for more details. 
  14  # 
  15  # You should have received a copy of the GNU General Public License 
  16  # along with Advene; if not, write to the Free Software 
  17  # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
  18  # 
  19  """Reusable widgets. 
  20   
  21  Note that, contrary to a common pattern found in the Advene sources 
  22  (where the real widget is stored as the self.widget attribute), each 
  23  of the widgets defined in this module is a gtk.Widget. 
  24   
  25  Documentation: 
  26  http://www.tortall.net/mu/wiki/CairoTutorial 
  27   
  28  http://www.pygtk.org/pygtk2reference/class-pangocairocairocontext.html 
  29  http://www.nabble.com/Image-Manipulation-under-pyGTK-t3484319.html 
  30  http://lists.freedesktop.org/archives/cairo/2007-February/009810.html 
  31  http://www.tortall.net/mu/wiki/CairoTutorial#understanding-text 
  32  http://nzlinux.virtuozzo.co.nz/blogs/2005/08/18/using-pangocairo/ 
  33  http://laszlok2.blogspot.com/2006/05/prince-of-cairo_28.html 
  34  """ 
  35   
  36  import struct 
  37   
  38  import gtk 
  39  import cairo 
  40  import pango 
  41  import gobject 
  42   
  43  # Advene part 
  44  import advene.core.config as config 
  45  from advene.gui.util import png_to_pixbuf 
  46  from advene.gui.util import encode_drop_parameters 
  47  import advene.util.helper as helper 
  48  from advene.model.annotation import Annotation 
  49   
  50  import advene.gui.popup 
  51   
  52  active_color=gtk.gdk.color_parse ('#fdfd4b') 
  53   
54 -class GenericColorButtonWidget(gtk.DrawingArea):
55 """ Widget emulating a color button widget 56 """
57 - def __init__(self, element=None, container=None):
58 gtk.DrawingArea.__init__(self) 59 self.set_flags(self.flags() | gtk.CAN_FOCUS) 60 self.element=element 61 62 # If not None, it should contain a gtk.gdk.Color 63 # which will override the normal color 64 self.local_color=None 65 # Alpha will be used to draw features 66 self.alpha=1.0 67 # expose_alpha will be used when rendering the surface on the widget 68 self.expose_alpha=1.0 69 70 # container is the Advene view instance that manages this instance 71 self.container=container 72 if container: 73 self.controller=container.controller 74 else: 75 self.controller=None 76 self.set_events(gtk.gdk.POINTER_MOTION_MASK | 77 gtk.gdk.BUTTON_PRESS_MASK | 78 gtk.gdk.BUTTON_RELEASE_MASK | 79 gtk.gdk.BUTTON1_MOTION_MASK | 80 gtk.gdk.KEY_PRESS_MASK | 81 gtk.gdk.KEY_RELEASE_MASK | 82 gtk.gdk.FOCUS_CHANGE_MASK | 83 gtk.gdk.ENTER_NOTIFY_MASK | 84 gtk.gdk.LEAVE_NOTIFY_MASK | 85 gtk.gdk.SCROLL_MASK) 86 87 self.connect('expose-event', self.expose_cb) 88 self.connect('realize', self.realize_cb) 89 self.connect_after('size-request', self.size_request_cb) 90 self.connect('focus-in-event', self.update_widget) 91 self.connect('focus-out-event', self.update_widget) 92 93 #self.connect('event', self.debug_cb, "Event") 94 #self.connect_after('event', self.debug_cb, "After") 95 96 self.cached_surface = None 97 self.cached_context = None 98 99 self.default_size = (40, 10) 100 # Initialize the size 101 self.set_size_request(*self.needed_size())
102
103 - def _drag_begin(self, widget, context):
104 cm=gtk.gdk.colormap_get_system() 105 w,h=self.needed_size() 106 pixmap=gtk.gdk.Pixmap(None, w, h, cm.get_visual().depth) 107 cr=pixmap.cairo_create() 108 self.draw(cr, w, h) 109 cr.paint_with_alpha(0.0) 110 widget.drag_source_set_icon(cm, pixmap) 111 widget._icon=pixmap 112 def set_cursor(wid, t=None): 113 try: 114 self.container.set_annotation(t) 115 except AttributeError: 116 # The container does not implement the set_annotation method. 117 return False 118 return True
119 pixmap.set_cursor = set_cursor.__get__(w) 120 return True
121
122 - def reset_surface_size(self, width=None, height=None):
123 """Redimension the cached widget content. 124 """ 125 if not self.window: 126 return False 127 s=self.window.get_size() 128 if width is None: 129 width=s[0] 130 if height is None: 131 height=s[1] 132 if width < 0: 133 print "Error: width ", width, " < 0 for ", self.element.id 134 width=5 135 if (self.cached_surface 136 and self.cached_surface.get_width() == width 137 and self.cached_surface.get_height() == height): 138 return True 139 self.cached_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) 140 self.cached_context = cairo.Context(self.cached_surface) 141 self.set_size_request(width, height) 142 self.window.lower() 143 return True
144
145 - def realize_cb(self, widget):
146 """Callback for the realize event. 147 """ 148 if not self.reset_surface_size(*self.needed_size()): 149 return True 150 self.update_widget() 151 return True
152
153 - def size_request_cb(self, widget, requisition):
154 """Callback for the size-request event. 155 """ 156 self.refresh() 157 return False
158
159 - def set_color(self, color=None):
160 """Set a local color for the widget. 161 162 The local color will override the color that could be returned 163 by the container's get_element_color method. 164 """ 165 self.local_color=color 166 self.update_widget() 167 return True
168
169 - def needed_size(self):
170 """Return the needed size of the widget. 171 172 Method to be implemented by subclasses 173 """ 174 return self.default_size
175
176 - def draw(self, context, width, height):
177 """Draw the widget. 178 179 Method to be implemented by subclasses 180 """ 181 context.rectangle(0, 0, width, height) 182 if self.local_color is not None: 183 color=self.local_color 184 rgba=(color.red / 65536.0, color.green / 65536.0, color.blue / 65536.0, self.alpha) 185 else: 186 rgba=(1.0, 1.0, 1.0, self.alpha) 187 context.set_source_rgba(*rgba) 188 context.fill()
189
190 - def update_widget(self, *p):
191 """Update the widget. 192 """ 193 if not self.window: 194 return False 195 if self.cached_context is None: 196 return False 197 198 # First check width 199 w=self.needed_size()[0] 200 if w != self.cached_surface.get_width(): 201 self.reset_surface_size(w, self.needed_size()[1]) 202 203 bwidth=self.cached_surface.get_width() 204 bheight=self.cached_surface.get_height() 205 206 self.draw(self.cached_context, bwidth, bheight) 207 208 self.refresh() 209 return False
210
211 - def refresh(self):
212 """Refresh the widget. 213 """ 214 if self.window and self.cached_surface: 215 width = self.cached_surface.get_width() 216 height = self.cached_surface.get_height() 217 self.window.invalidate_rect(gtk.gdk.Rectangle(0, 0, width, height), False)
218
219 - def expose_cb(self, widget, event):
220 """Handle the expose event. 221 """ 222 if self.cached_surface is None: 223 return False 224 225 context = widget.window.cairo_create() 226 227 # Set a clip region for the expose event 228 context.rectangle(event.area.x, event.area.y, 229 event.area.width, event.area.height) 230 context.clip() 231 232 # copy the annotation_surface onto this context 233 context.set_source_surface(self.cached_surface, 0, 0) 234 context.paint_with_alpha(self.expose_alpha) 235 #self.draw(context, *widget.window.get_size()) 236 return False
237 gobject.type_register(GenericColorButtonWidget) 238
239 -class AnnotationWidget(GenericColorButtonWidget):
240 """ Widget representing an annotation 241 """
242 - def __init__(self, annotation=None, container=None):
243 self.annotation=annotation 244 self.active=False 245 GenericColorButtonWidget.