| Home | Trees | Indices | Help |
|
|---|
|
|
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
55 """ Widget emulating a color button widget
56 """
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
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
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
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
158
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
170 """Return the needed size of the widget.
171
172 Method to be implemented by subclasses
173 """
174 return self.default_size
175
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
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
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
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