comparison pyink/frameline.py @ 944:b0edd13779ee

Implement a frameline widget
author Thinker K.F. Li <thinker@codemud.net>
date Tue, 16 Nov 2010 12:12:21 +0800
parents
children 8db3dd03508f
comparison
equal deleted inserted replaced
943:82321f404b5f 944:b0edd13779ee
1 import pygtk
2 pygtk.require("2.0")
3 import gtk
4 import gtk.gdk
5 import gobject
6
7 def color_to_rgb(v):
8 return (((v >> 16) & 0xff) * 65535 / 0xff,
9 ((v >> 8) & 0xff) * 65535 / 0xff,
10 (v & 0xff) * 65535 / 0xff)
11
12 class keyframe(object):
13 def __init__(self, frame_idx):
14 self.idx = frame_idx
15 self.left_tween = False
16 self.right_tween = False
17 self.right_tween_type = 0
18 pass
19 pass
20
21 ## Show frame status of a layer
22 #
23 class frameline(gtk.DrawingArea):
24 _type_id = 0
25 _frame_width = 10 # Width for each frame is 10 pixels
26 _select_color = 0xee2222 # color of border of selected frame
27 _key_mark_color = 0x000000 # color of marks for key frames.
28 _key_mark_sz = 4 # width and height of a key frame mark
29 _tween_color = 0x000000 # color of tween line
30 _tween_bgcolors = [0x80ff80, 0xff8080] # bg colors of tween frames
31 # Colors for normal frames
32 _normal_bgcolors = [0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xcccccc]
33 _normal_border = 0xaaaaaa # border color of normal frames.
34 _active_border = 0xff3030 # border color of an active frame
35
36 def __new__(clz, *args):
37 if not frameline._type_id:
38 frameline._type_id = gobject.type_register(frameline)
39 pass
40 fl_obj = gobject.new(frameline._type_id)
41 return fl_obj
42
43 def __init__(self, num_frames=20):
44 self.connect('expose_event', self._fl_expose)
45 self._num_frames = num_frames
46 self._keys = []
47 self._active_frame = -1
48 pass
49
50 def _fl_expose(self, widget, event):
51 print 'Expose %s' % (repr(event))
52 win = self.window
53 x, y, w, h, depth = win.get_geometry()
54 print ' Geometry of window: %dx%d+%d+%d' % (w, h, x, y)
55 self.update()
56 pass
57
58 def _draw_tween(self, first_key, last_key):
59 win = self.window
60 w_x, w_y, w_w, w_h, depth = win.get_geometry()
61
62 #
63 # Get background color of a tween
64 #
65 bg_idx = first_key.right_tween_type
66 bg_color_v = self._tween_bgcolors[bg_idx]
67 bg_color_rgb = color_to_rgb(bg_color_v)
68 bg_color = gtk.gdk.Color(*bg_color_rgb)
69
70 gc = self._gc
71 gc.set_rgb_fg_color(bg_color)
72
73 draw_x = first_key.idx * self._frame_width + 1
74 draw_w = (last_key.idx - first_key.idx + 1) * self._frame_width - 1
75
76 win.draw_rectangle(gc, True, draw_x, 0, draw_w, w_h)
77 pass
78
79 def _draw_frame(self, idx):
80 win = self.window
81 w_x, w_y, w_w, w_h, depth = win.get_geometry()
82
83 gc = self._gc
84 bg_idx = idx % len(self._normal_bgcolors)
85 rgb = color_to_rgb(self._normal_bgcolors[bg_idx])
86 color = gtk.gdk.Color(*rgb)
87 gc.set_rgb_fg_color(color)
88
89 f_x = self._frame_width * idx
90 win.draw_rectangle(gc, True, f_x + 1, 0, self._frame_width, w_h)
91 next_f_x = f_x + self._frame_width
92
93 border_rgb = color_to_rgb(self._normal_border)
94 border_color = gtk.gdk.Color(*border_rgb)
95 gc.set_rgb_fg_color(border_color)
96 gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
97 gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
98 win.draw_line(gc, next_f_x, 0, next_f_x, w_h)
99 pass
100
101 def _draw_frames(self):
102 win = self.window
103 gc = gtk.gdk.GC(win)
104 self._gc = gc
105
106 i = 0
107 key_i = 0
108 try:
109 key = self._keys[key_i]
110 except IndexError:
111 key = keyframe(self._num_frames)
112 pass
113 num_frames = self._num_frames
114 while i < num_frames:
115 if key.idx == i:
116 #
117 # Skip tween keys
118 #
119 first_tween_key = key
120 while key.idx == i or key.left_tween:
121 last_tween_key = key
122 key_i = key_i + 1
123 try:
124 key = self._keys[key_i]
125 except IndexError:
126 key = keyframe(self._num_frames)
127 pass
128 pass
129
130 if first_tween_key != last_tween_key:
131 self._draw_tween(first_tween_key, last_tween_key)
132
133 i = last_tween_key.idx + 1
134 pass
135 else:
136 self._draw_frame(i)
137 i = i + 1
138 pass
139 pass
140 pass
141
142 def _draw_keyframes(self):
143 win = self.window
144 w_x, w_y, w_w, w_h, depth = win.get_geometry()
145
146 color_v = self._key_mark_color
147 color_rgb = color_to_rgb(color_v)
148 color = gtk.gdk.Color(*color_rgb)
149
150 gc = self._gc
151 gc.set_rgb_fg_color(color)
152
153 for key in self._keys:
154 mark_sz = self._key_mark_sz
155 mark_x = int((key.idx + 0.5) * self._frame_width - mark_sz / 2)
156 mark_y = w_h * 2 / 3 - mark_sz / 2
157
158 win.draw_rectangle(gc, True, mark_x, mark_y, mark_sz, mark_sz)
159 pass
160 pass
161
162 def _draw_active(self):
163 win = self.window
164 w_x, w_y, w_w, w_h, depth = win.get_geometry()
165
166 color_v = self._active_border
167 color_rgb = color_to_rgb(color_v)
168 color = gtk.gdk.Color(*color_rgb)
169
170 gc = self._gc
171 gc.set_rgb_fg_color(color)
172
173 idx = self._active_frame
174 line_x1 = idx * self._frame_width
175 line_x2 = line_x1 + self._frame_width
176
177 win.draw_line(gc, line_x1, 0, line_x1, w_h)
178 win.draw_line(gc, line_x2, 0, line_x2, w_h)
179 pass
180
181 def update(self):
182 win = self.window
183 x, y, w, h, depth = win.get_geometry()
184
185 self._draw_frames()
186 self._draw_keyframes()
187 if self._active_frame != -1:
188 self._draw_active()
189 pass
190 pass
191
192 def add_keyframe(self, idx):
193 key_indic = [key.idx for key in self._keys]
194 if idx in key_indic:
195 return
196
197 key_indic.append(idx)
198 key_indic.sort()
199 insert_pos = key_indic.index(idx)
200
201 key = keyframe(idx)
202 self._keys[insert_pos:insert_pos] = [key]
203 if insert_pos > 0 and self._keys[insert_pos - 1].right_tween:
204 key.left_tween = True
205 pass
206 if insert_pos < (len(self._keys) - 1) and \
207 self._keys[insert_pos + 1].left_tween:
208 key.right_tween = True
209 pass
210 pass
211
212 ## Tween the key frame specified by an index and the frame at right.
213 #
214 # \see http://www.entheosweb.com/Flash/shape_tween.asp
215 def tween(self, idx, _type=0):
216 key_indic = [key.idx for key in self._keys]
217 pos = key_indic.index(idx)
218 key = self._keys[pos]
219
220 try:
221 right_key = self._keys[pos + 1]
222 except IndexError:
223 raise ValueError, 'No right key frame'
224
225 key.right_tween = True
226 right_key.left_tween = True
227 key.right_tween_type = _type
228 pass
229
230 ## Set active frame
231 #
232 # The active frame is the frame that is working on.
233 #
234 def active_frame(self, idx):
235 if idx < 0 or idx >= self._num_frames:
236 raise IndexError, 'value of index (%d) is out of range' % (idx)
237
238 self._active_frame = idx
239 pass
240
241 def deactive(self):
242 self._active_frame = -1
243 pass
244
245 def set_num_frames(self, num):
246 self._num_frames = num
247 pass
248
249 def __len__(self):
250 return self._num_frames
251 pass
252
253 if __name__ == '__main__':
254 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
255 fl = frameline(40)
256 fl.set_size_request(300, 30)
257 fl.add_keyframe(3)
258 fl.add_keyframe(9)
259 fl.add_keyframe(15)
260 fl.add_keyframe(20)
261 fl.tween(3)
262 fl.tween(15, 1)
263 fl.active_frame(15)
264 print 'num of frames: %d' % (len(fl))
265
266 window.add(fl)
267 fl.show()
268 window.show()
269 gtk.main()
270 pass