comparison pyink/domview_ui.py @ 1243:d5f70928e9f1

Move MBScene_domview_ui and MBScene_domview to separated modules. - domview.py is where MBScene_domview and MBScene_domview_monitor are. - domview_ui.py is where MBScene_domview_ui and MBScene_frameline_stack are. - keep modules small to make better collaberation.
author Thinker K.F. Li <thinker@codemud.net>
date Mon, 10 Jan 2011 16:32:16 +0800
parents
children b241f9768833
comparison
equal deleted inserted replaced
1242:1b1eb8f9a866 1243:d5f70928e9f1
1 import gtk
2 from tween import TweenObject
3 from frameline import frameline, frameruler
4 from domview import MBScene_domview
5
6
7 ## \brief Maintain a stack of frameline UI component.
8 #
9 # Every layer is assocated with a frameline. Framelines are showed/stacked in
10 # virtical. Framelines of lower layers are placed at lower position on the
11 # screen. This class provide a set of API to access framelines with layer and
12 # frame index number. You access/set content of frameline by specifing layer
13 # index and frame index.
14 #
15 class MBScene_frameline_stack(object):
16 _frameline_tween_types = (frameline.TWEEN_TYPE_NONE,
17 frameline.TWEEN_TYPE_SHAPE)
18 _num_frames_of_line = 100
19
20 _framelines = None
21
22 def __init__(self, *args, **kws):
23 super(MBScene_frameline_stack, self).__init__(*args, **kws)
24
25 self._last_mouse_over_frameline = None
26 self._last_active_frameline = None
27 self._active_frame_callback = None
28 pass
29
30 def _change_hover_frameline(self, widget, event):
31 """
32 Hide all hover frames. This is a hack. We should use the lost focus
33 event instead in the future to reduce the overhead.
34 """
35 if self._last_mouse_over_frameline and \
36 widget != self._last_mouse_over_frameline:
37 self._last_mouse_over_frameline.mouse_leave()
38 pass
39 self._last_mouse_over_frameline = widget
40 pass
41
42 ## \brief Switch to new active frameline.
43 #
44 # Hide active frame mark for the active frame of old active frameline. It
45 # always shows at most one active frame mark. When a frame is activated,
46 # all active frame mark of other frameline should be hidden.
47 #
48 def _active_frameline(self, frameline):
49 last = self._last_active_frameline
50
51 if last and last != frameline:
52 last.deactive()
53 pass
54
55 self._last_active_frameline = frameline
56 pass
57
58 ## \brief Called for changing of active frame.
59 #
60 # This handle deactive previous frameline that owns an active frame when a
61 # frame in another frameline is activated.
62 #
63 def _change_active_frame(self, frameline, frame_idx, button):
64 frameline.active_frame(frame_idx)
65 self._active_frameline(frameline)
66
67 if self._active_frame_callback:
68 layer_idx = frameline.layer_idx
69 self._active_frame_callback(layer_idx, frame_idx)
70 pass
71 pass
72
73 ## \brief Add a frameline into the frameline box for the given layer.
74 #
75 def _add_frameline(self, layer_idx):
76 if layer_idx > len(self._framelines):
77 raise ValueError, 'layer number should be a consequence'
78
79 vbox = self._frameline_vbox
80
81 line = frameline(self._num_frames_of_line)
82 line.set_size_request(self._num_frames_of_line * 10, 20)
83
84 hbox = gtk.HBox()
85 label = gtk.Label('')
86 label.set_size_request(100,0)
87 hbox.pack_start(label,expand=False, fill=True)
88 hbox.pack_start(line)
89 vbox.pack_start(hbox, False)
90
91 # Put later one on the top of earier one, but after the ruler.
92 position = len(self._framelines) - layer_idx + 1
93 vbox.reorder_child(hbox, position)
94
95 self._framelines[layer_idx: layer_idx] = [line]
96
97 for idx in range(layer_idx, len(self._framelines)):
98 self._framelines[idx].layer_idx = idx
99 pass
100
101 line.label = label
102 line.connect('motion-notify-event', self._change_hover_frameline)
103 line.connect(frameline.FRAME_BUT_PRESS, self._change_active_frame)
104 pass
105
106 ## \brief Remove the given frameline from the frameline box.
107 #
108 def _remove_frameline(self, layer_idx):
109 vbox = self._frameline_vbox
110 line = self._framelines[layer_idx]
111
112 hbox = line.parent
113 vbox.remove(hbox)
114 del self._framelines[layer_idx]
115
116 for idx in range(layer_idx, len(self._framelines)):
117 self._framelines[idx].layer_idx = idx
118 pass
119 pass
120
121 def _init_framelines(self):
122 self._framelines = []
123
124 box = gtk.ScrolledWindow()
125 self._frameline_box = box
126 box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
127 box.set_size_request(-1, 150)
128 vbox = gtk.VBox()
129 self._frameline_vbox = vbox
130 box.add_with_viewport(vbox)
131
132 nframes = self._num_frames_of_line
133
134 #
135 # Set up a ruler
136 #
137 ruler = frameruler(nframes)
138 ruler.set_size_request(nframes * 10, 20)
139 ruler.show()
140 hbox = gtk.HBox()
141 label=gtk.Label('')
142 label.set_size_request(100,0)
143 hbox.pack_start(label,expand=False,fill=True)
144 hbox.pack_start(ruler)
145 vbox.pack_start(hbox, False)
146 pass
147
148 ## \brief Show framelines on the screen.
149 #
150 # When a frameline was inserted or removed, it would not be showed
151 # immediately. This function is used to notify toolkit to update the
152 # screen and drawing framelines.
153 def _show_framelines(self):
154 self._frameline_vbox.show_all()
155 pass
156
157 ## \brief Make given frame as current active frame.
158 #
159 def active_frame(self, layer_idx, frame_idx):
160 frameline = self._framelines[layer_idx]
161 self._active_frameline(frameline)
162 frameline.active_frame(frame_idx)
163 pass
164
165 ## \brief Get layer and frame index of current active frame.
166 #
167 # \return (-1, -1) for no active, (layer_idx, frame_idx) for current
168 # active.
169 def get_active_layer_frame(self):
170 if self._last_active_frameline:
171 layer_idx = self._last_active_frameline.layer_idx
172 frame_idx = self._last_active_frameline.get_active_frame()
173 if frame_idx != -1:
174 return layer_idx, frame_idx
175 pass
176 return -1, -1
177
178 ## \brief Get information of the key frame at left-side.
179 #
180 # The key frame, returned, is at the place of the give frame or its
181 # left-side.
182 def get_left_key_tween(self, layer_idx, frame_idx):
183 frameline = self._framelines[layer_idx]
184 start, end, fl_tween_type = frameline.get_frame_block_floor(frame_idx)
185 tween_type = self._frameline_tween_types.index(fl_tween_type)
186 return start, end, tween_type
187
188 ## \brief Return information of a key frame and its tweening.
189 #
190 # This method return the key frame that the given frame is, or is in its
191 # tween.
192 #
193 # \return (start, end, tween_type)
194 def get_key_tween(self, layer_idx, frame_idx):
195 frameline = self._framelines[layer_idx]
196 start, end, fl_tween_type = frameline.get_frame_block(frame_idx)
197
198 tween_type = self._frameline_tween_types.index(fl_tween_type)
199 return start, end, tween_type
200
201 def get_all_key_tween_of_layer(self, layer_idx):
202 frameline = self._framelines[layer_idx]
203 info = frameline.get_frame_blocks()
204 tweens = [(tween[0], tween[1],
205 self._frameline_tween_types.index(tween[2]))
206 for tween in info]
207 return tweens
208
209 ## \brief Tweening key frame to a give size
210 #
211 # The tween can be changed by tweening it again.
212 def tween(self, layer_idx, key_frame_idx, tween_len,
213 tween_type=TweenObject.TWEEN_TYPE_NORMAL):
214 assert tween_len > 0
215 frameline = self._framelines[layer_idx]
216 right_frame_idx = key_frame_idx + tween_len - 1
217 fl_tween_type = self._frameline_tween_types[tween_type]
218
219 start, end, old_fl_tween_type = \
220 frameline.get_frame_block(key_frame_idx)
221 if start != key_frame_idx:
222 ValueError, 'invalid key frame (%d)' % (key_frame_idx)
223 if start < end:
224 frameline.unmark_keyframe(end)
225 pass
226 frameline.mark_keyframe(right_frame_idx)
227 frameline.tween(start, fl_tween_type)
228 pass
229
230 ## \brief Unmark a key frame.
231 #
232 # Once a key frame was unmark, the associated tween was also removed
233 # totally.
234 #
235 def unmark_keyframe(self, layer_idx, frame_idx):
236 frameline = self._framelines[layer_idx]
237 start, end, fl_tween_type = frameline.get_frame_block(frame_idx)
238 if start != frame_idx:
239 raise ValueError, 'no such key (%d, %d)' % (layer_idx, frame_idx)
240
241 frameline.unmark_keyframe(frame_idx)
242 if start < end:
243 frameline.unmark_keyframe(end)
244 pass
245 pass
246
247 ## \brief Makr a key frame.
248 #
249 # Make a frame as a key frame.
250 #
251 def mark_keyframe(self, layer_idx, frame_idx):
252 frameline = self._framelines[layer_idx]
253 frameline.mark_keyframe(frame_idx)
254 pass
255
256 ## \brief Get data associated with the given key frame.
257 #
258 # The given frame index must be exactly a key frame.
259 #
260 def get_keyframe_data(self, layer_idx, frame_idx):
261 frameline = self._framelines[layer_idx]
262 data = frameline.get_frame_data(frame_idx)
263 return data
264
265 ## \brief Set/associate data with the given key frame.
266 #
267 def set_keyframe_data(self, layer_idx, frame_idx, data):
268 frameline = self._framelines[layer_idx]
269 frameline.set_frame_data(frame_idx, data)
270 pass
271
272 ## \brief Insert frames before specified frame.
273 #
274 # Specified frame and frames after it are shift right for \ref num
275 # positions to make a space for new frames.
276 #
277 def insert_frames(self, layer_idx, frame_idx, num):
278 assert num > 0
279 assert frame_idx >= 0
280 frameline = self._framelines[layer_idx]
281 for i in range(num):
282 frameline.add_frame(frame_idx)
283 pass
284 pass
285
286 ## \brief Remove a number of frames from the frameline.
287 #
288 # All key frames and associated tween info covered by removing range would
289 # be removed.
290 #
291 def rm_frames(self, layer_idx, frame_idx, num):
292 assert num > 0
293 assert frame_idx >= 0
294
295 frameline = self._framelines[layer_idx]
296
297 #
298 # Remove right key frame of last tween which left one will be removed.
299 #
300 last_rm = frame_idx + num - 1 # last removed frame
301 try:
302 start, end, tween_type = frameline.get_frame_block(last_rm)
303 except ValueError: # last removed frame is not in any tween
304 pass
305 else:
306 if start >= frame_idx and end > last_rm:
307 # Left key frame of the tween was removed, but not right one.
308 frameline.untween(start)
309 frameline.unmark_keyframe(end)
310 pass
311 pass
312
313 #
314 # Remove left key of the tween that right key frame is in removing
315 # range.
316 #
317 try:
318 start, end, tween_type = frameline.get_frame_block(frame_idx)
319 except ValueError:
320 pass
321 else:
322 if start < frame_idx and end <= last_rm:
323 # right key frame is in removing range but left one.
324 frameline.untween(start)
325 frameline.unmark_keyframe(start)
326 frameline.unmark_keyframe(end)
327 pass
328 pass
329
330 for i in range(num):
331 frameline.rm_frame(frame_idx)
332 pass
333 pass
334
335 ## \brief Set label for a layer.
336 #
337 def set_layer_label(self, layer_idx, txt):
338 frameline = self._framelines[layer_idx]
339 frameline.label.set_text(txt)
340 pass
341
342 ## \brief Register a callback for active frame event.
343 #
344 # The callback would be called when a frame is activated.
345 #
346 def register_active_frame_callback(self, cb):
347 self._active_frame_callback = cb
348 pass
349 pass
350
351 ## \brief Bridge of DOM-tree to syncrhonize data-model and UI.
352 #
353 # This class is a wrapper
354 class MBScene_domview_ui(object):
355 _tween_type_names = ('normal', 'scale')
356
357 def __init__(self):
358 super(MBScene_domview_ui, self).__init__()
359 self._fl_stack = MBScene_frameline_stack()
360 self._dom = MBScene_domview()
361 pass
362
363 ## \brief Update content of a frameline from scenes of respective layer.
364 #
365 def _update_frameline_content(self, layer_idx):
366 fl_stack = self._fl_stack
367 scene_nodes = self._dom.get_all_scene_node_of_layer(layer_idx)
368 for scene_node in scene_nodes:
369 start, end, tween_name = self._dom._parse_one_scene(scene_node)
370
371 fl_stack.mark_keyframe(layer_idx, start)
372 fl_stack.set_keyframe_data(layer_idx, start, scene_node)
373 if start != end:
374 tween_type = self._tween_type_names.index(tween_name)
375 tween_len = end - start + 1
376 fl_stack.tween(layer_idx, start, tween_len, tween_type)
377 pass
378 pass
379 pass
380
381 ## \brief Add a frameline for every found layer.
382 #
383 # This method is called to create a frameline for every layer found when
384 # loading a document.
385 #
386 def _add_frameline_for_every_layer(self):
387 for layer_idx in range(self._dom.get_layer_num()):
388 layer_group_node = self._dom.get_layer_group(layer_idx)
389 label = layer_group_node.getAttribute('inkscape:label')
390
391 self._fl_stack._add_frameline(layer_idx)
392 self._fl_stack.set_layer_label(layer_idx, label)
393
394 self._update_frameline_content(layer_idx)
395 pass
396 pass
397
398 ## \brief This method is called to handle a new document.
399 #
400 def handle_doc_root(self, doc, root):
401 self._dom.handle_doc_root(doc, root)
402 self._fl_stack._init_framelines()
403 self._add_frameline_for_every_layer()
404 self._fl_stack._show_framelines()
405 pass
406
407 ## \brief Mark given frame as a key frame.
408 #
409 def mark_key(self, layer_idx, key_idx):
410 scene_group = self._dom.add_scene_group(layer_idx)
411 scene_group_id = scene_group.getAttribute('id')
412
413 scene_node = self._dom.add_scene_node(key_idx, key_idx)
414 self._dom.chg_scene_node(scene_node, ref=scene_group_id)
415
416 self._fl_stack.mark_keyframe(layer_idx, key_idx)
417 self._fl_stack.set_keyframe_data(layer_idx, key_idx, scene_node)
418 pass
419
420 ## \brief Tweening a key frame.
421 #
422 # To tween a key spanning several frames at right-side.
423 # The tween of a key frame can be changed by tweening it again.
424 #
425 def tween(self, layer_idx, key_frame_idx, tween_len,
426 tween_type=TweenObject.TWEEN_TYPE_NORMAL):
427 self._fl_stack.tween(layer_idx, key_frame_idx, tween_len, tween_type)
428
429 end_frame_idx = key_frame_idx + tween_len - 1
430 scene_node = self._fl_stack.get_keyframe_data(layer_idx, key_frame_idx)
431 tween_name = self._tween_type_names[tween_type]
432 self._dom.chg_scene_node(scene_node, end=end_frame_idx,
433 tween_type=tween_name)
434 pass
435
436 ## \brief Change tween info of a key frame
437 #
438 def chg_tween(self, layer_idx, key_frame_idx,
439 tween_len=None, tween_type=None):
440 scene_node = self._fl_stack.get_keyframe_data(layer_idx, key_frame_idx)
441 start, end, old_tween_type = \
442 self._fl_stack.get_key_tween(layer_idx, key_frame_idx)
443
444 if tween_len is not None:
445 end = start + tween_len - 1
446 self._dom.chg_scene_node(scene_node, end=end)
447 pass
448 if tween_type is not None:
449 tween_name = self._tween_type_names[tween_type]
450 self._dom.chg_scene_node(scene_node, tween_type=tween_name)
451 pass
452
453 if tween_type is None:
454 tween_type = old_tween_type
455 pass
456
457 tween_len = end - start + 1
458 self._fl_stack.tween(layer_idx, start, tween_len, tween_type)
459 pass
460
461 ## \brief Unmark a frame from a key frame.
462 #
463 def unmark_key(self, layer_idx, key_frame_idx):
464 scene_node = self._fl_stack.get_keyframe_data(layer_idx, key_frame_idx)
465 self._dom.rm_scene_node_n_group(scene_node)
466
467 self._fl_stack.unmark_keyframe(layer_idx, key_frame_idx)
468 pass
469
470 ## \brief Insert frames at specified position.
471 #
472 # All frame at and after given position will shift right.
473 #
474 def insert_frames(self, layer_idx, frame_idx, num):
475 self._fl_stack.insert_frames(layer_idx, frame_idx, num)
476 self._dom.insert_frames(layer_idx, frame_idx, num)
477 pass
478
479 ## \brief Insert frames at specified position.
480 #
481 # All frame at and after given position will shift left, except nearest
482 # \ref num frames are removed.
483 #
484 def rm_frames(self, layer_idx, frame_idx, num):
485 self._fl_stack.insert_frames(layer_idx, frame_idx, num)
486 self._dom.rm_frames(layer_idx, frame_idx, num)
487 pass
488
489 ## \brief Insert a layer at given position.
490 #
491 # Original layer \ref layer_idx and later ones would be shifted to make a
492 # space for the new layer.
493 #
494 def insert_layer(self, layer_idx):
495 self._dom.insert_layer(layer_idx)
496 self._fl_stack._add_frameline(layer_idx)
497 self._fl_stack._show_framelines()
498 pass
499
500 ## \brief Remove given layer.
501 #
502 def rm_layer(self, layer_idx):
503 self._dom.rm_layer(layer_idx)
504 self._fl_stack._remove_frameline(layer_idx)
505 self._fl_stack._show_framelines()
506 pass
507
508 def set_active_layer_frame(self, layer_idx, frame_idx):
509 self._fl_stack.active_frame(layer_idx, frame_idx)
510 pass
511
512 ## \bref Return current active frame and its layer.
513 #
514 # \return (layer_idx, frame_idx) of active frame, or (-1, -1) when no
515 # active one.
516 def get_active_layer_frame(self):
517 layer_idx, frame_idx = self._fl_stack.get_active_layer_frame()
518 return layer_idx, frame_idx
519
520 def get_layer_num(self):
521 return self._dom.get_layer_num()
522
523 ## \brief Return associated group node for a key frame.
524 #
525 # The given frame index must be exactly a key frame.
526 #
527 def get_key_group(self, layer_idx, frame_idx):
528 scene_node = self._fl_stack.get_keyframe_data(layer_idx, frame_idx)
529 scene_group_id = scene_node.getAttribute('ref')
530 scene_group_node = self._dom.get_node(scene_group_id)
531 return scene_group_node
532
533 ## \brief Find an associated key frame and tween info for a group ID.
534 #
535 def find_key_from_group(self, scene_group_id):
536 layer_idx, scene_node = \
537 self._dom.find_layer_n_scene_of_node(scene_group_id)
538 start, end, tween_name = self._dom._parse_one_scene(scene_node)
539 tween_type = self._tween_type_names.index(tween_name)
540 return layer_idx, (start, end, tween_type)
541
542 ## \brief Return key and tween info for given frame index.
543 #
544 # The return key is at given frame, or its tween covers given frame.
545 #
546 def get_key(self, layer_idx, frame_idx):
547 start, end, tween_type = \
548 self._fl_stack.get_key_tween(layer_idx, frame_idx)
549 return start, end, tween_type
550
551 def get_left_key(self, layer_idx, frame_idx):
552 start, end, tween_type = \
553 self._fl_stack.get_left_key_tween(layer_idx, frame_idx)
554 return start, end, tween_type
555
556 ## \brief Return information of key frames in the given layer.
557 #
558 def get_layer_keys(self, layer_idx):
559 key_tweens = self._fl_stack.get_all_key_tween_of_layer(layer_idx)
560 return key_tweens
561
562 ## \brief Return widget showing frames and layers.
563 #
564 def get_frame_ui_widget(self):
565 return self._fl_stack._frameline_box
566
567 ## \brief Register a callback for activating a frame event.
568 #
569 # The callback function is called when a frame is activated.
570 #
571 def register_active_frame_callback(self, cb):
572 self._fl_stack.register_active_frame_callback(cb)
573 pass
574
575 ## \brief Get duplicate group of a layer.
576 #
577 def get_layer_dup_group(self, layer_idx):
578 data = self._dom.get_layer_data(layer_idx)
579 if not data:
580 data = dict()
581 self._dom.set_layer_data(layer_idx, data)
582 pass
583
584 dup_group = None
585 if data.has_key('dup_group_id'):
586 try:
587 dup_group = self._dom.get_node(data['dup_group_id'])
588 except KeyError:
589 pass
590 pass
591
592 if not dup_group:
593 # Search dup group from children of the layer group
594 layer_group = self._dom.get_layer_group(layer_idx)
595 for child in layer_group.childList():
596 try:
597 label = child.getAttribute('inkscape:label')
598 except:
599 pass
600 else:
601 if label == 'dup':
602 data['dup_group_id'] = child
603 return child
604 pass
605 pass
606
607 # Or create a new dup group for the layer
608 dup_group = self._dom.create_layer_dup_group(layer_idx)
609 data['dup_group_id'] = dup_group.getAttribute('id')
610 pass
611
612 return dup_group
613
614 def get_max_frame(self):
615 max_frame = self._dom.get_max_frame()
616 return max_frame
617 pass
618