comparison pyink/frameline.py @ 1153:5abf419d66e5

Refactory methods of state awared drawing to frameline_draw_state
author Thinker K.F. Li <thinker@codemud.net>
date Mon, 27 Dec 2010 15:37:03 +0800
parents d333baa702a9
children 1c9ef65c74b2
comparison
equal deleted inserted replaced
1152:d333baa702a9 1153:5abf419d66e5
269 win.draw_line(gc, line_x1, 1, line_x2, 1) 269 win.draw_line(gc, line_x1, 1, line_x2, 1)
270 win.draw_line(gc, line_x1, w_h - 2, line_x2, w_h - 2) 270 win.draw_line(gc, line_x1, w_h - 2, line_x2, w_h - 2)
271 pass 271 pass
272 pass 272 pass
273 273
274 ## Show frame status of a layer 274
275 # 275 ## \brief Drawing frameline according state of a frameline.
276 # \section frameline_sigs Signals 276 #
277 # - 'frame-button-pree' for user press on a frame. 277 # Thsi class calls methods of class frameline_draw to drawing frameline. But,
278 # - callback(widget, frame_idx, button) 278 # this class is state awared. It according states of an instance to determines
279 # 279 # calling methods and arguments. This class decorates methods of
280 # All methos that change state of the frameline, must call methods to update 280 # frameline_draw class according states of an instance.
281 # the screen. 281 #
282 # 282 # This classs reading state of a frameline, but it does not change and control
283 class frameline(frameline_draw): 283 # states. The deriving classes are responsible to change and control states.
284 _sig_frame_but_press = None 284 #
285 285 class frameline_draw_state(frameline_draw):
286 # tween types 286 # tween types
287 TWEEN_TYPE_NONE = 0 287 TWEEN_TYPE_NONE = 0
288 TWEEN_TYPE_MOVE = 1 288 TWEEN_TYPE_MOVE = 1
289 TWEEN_TYPE_SHAPE = 2 289 TWEEN_TYPE_SHAPE = 2
290 290
291 FRAME_BUT_PRESS = 'frame-button-press' 291 def __init__(self, num_frames):
292 292 frameline_draw.__init__(self)
293 def __new__(clz, *args): 293
294 fl_obj = frameline_draw.__new__(clz, *args)
295
296 if not clz._sig_frame_but_press:
297 but_press = gobject.signal_new(frameline.FRAME_BUT_PRESS,
298 frameline._type,
299 gobject.SIGNAL_RUN_FIRST,
300 gobject.TYPE_NONE,
301 (gobject.TYPE_INT,
302 gobject.TYPE_INT))
303 clz._sig_frame_but_press = but_press
304 pass
305 return fl_obj
306
307 def __init__(self, num_frames=20):
308 self.connect('button-press-event', self._press_hdl)
309 self.connect('expose-event', self._fl_expose)
310 self.connect('motion-notify-event', self._motion_hdl)
311 self._num_frames = num_frames 294 self._num_frames = num_frames
312 self._keys = [] 295 self._keys = []
313 self._active_frame = -1 296 self._active_frame = -1
314 self._last_hover = -1 # frame index of last hover
315 self._drawing = False 297 self._drawing = False
316 pass
317
318 def __len__(self):
319 return self._num_frames
320
321 def _find_keyframe(self, idx):
322 key_indic = [key.idx for key in self._keys]
323 key_pos = key_indic.index(idx)
324 return key_pos
325
326 def _find_keyframe_floor(self, frame_idx):
327 pos = 0
328 keys = [key.idx for key in self._keys]
329 keys.append(frame_idx)
330 keys.sort()
331 keys.reverse()
332 pos = (len(keys) - 1) - keys.index(frame_idx) - 1
333 return pos
334
335 ## \brief Find the range a continous tween.
336 #
337 def _find_tween_range(self, key_pos):
338 key = self._keys[key_pos]
339 if not (key.left_tween or key.right_tween):
340 raise ValueError, 'the keyframe is not in a tween'
341
342 #
343 # Initialize tween type and first_pos
344 #
345 if key.right_tween:
346 tween_type = key.right_tween_type
347 first_pos = key_pos
348 else:
349 # key.left_tween is True since the key is in a tween.
350 first_pos = key_pos -1
351 key = self._keys[first_pos]
352 tween_type = key.right_tween_type
353 pass
354
355 #
356 # Find first_pos
357 #
358 while first_pos and key.left_tween:
359 right_pos = first_pos - 1
360 right_key = self._keys[right_pos]
361 if right_key.right_tween_type != tween_type:
362 break
363 first_pos = right_pos
364 key = right_key
365 pass
366
367 #
368 # Find last_pos
369 #
370 max_pos = len(self._keys) - 1
371 last_pos = key_pos
372 key = self._keys[last_pos]
373 while last_pos < max_pos and self._keys[last_pos].right_tween:
374 if key.right_tween_type != tween_type:
375 break
376 last_pos = last_pos + 1
377 key = self._keys[last_pos]
378 pass
379
380 return first_pos, last_pos
381
382 def _press_hdl(self, widget, event):
383 frame = event.x / self._frame_width
384 but = event.button
385 self.emit(frameline.FRAME_BUT_PRESS, frame, but)
386 pass
387
388 def hide_hover(self):
389 if self._active_frame != self._last_hover:
390 self._draw_normal_frame(self._last_hover)
391 pass
392 pass 298 pass
393
394 def _motion_hdl(self, widget, event):
395 frame_idx = int(event.x / self._frame_width)
396 if self._last_hover != -1:
397 self._draw_frame(self._last_hover)
398 if self._last_hover == self._active_frame:
399 self._draw_active_frame()
400 pass
401 pass
402
403 if frame_idx < self._num_frames and frame_idx >= 0:
404 self._draw_hover_frame(frame_idx)
405 if self._last_hover == self._active_frame:
406 self._draw_active_frame()
407 pass
408 self._last_hover = frame_idx
409 else:
410 self._last_hover = -1
411 pass
412 pass
413
414 def _fl_expose(self, widget, event):
415 win = self.window
416 x, y, w, h, depth = win.get_geometry()
417 if not hasattr(self, '_gc'):
418 self._gc = gtk.gdk.GC(win)
419 #
420 # register for button press event
421 #
422 emask = win.get_events()
423 emask = emask | gtk.gdk.BUTTON_PRESS_MASK | \
424 gtk.gdk.POINTER_MOTION_MASK
425 win.set_events(emask)
426 self._drawing = True
427 pass
428 self.update()
429 pass
430 299
431 def _draw_keyframe(self, frame_idx): 300 def _draw_keyframe(self, frame_idx):
432 # Only keyframes that is not right-side of NONE type tween should be 301 # Only keyframes that is not right-side of NONE type tween should be
433 # draw. 302 # draw.
434 pos = self._find_keyframe(frame_idx) 303 pos = self._find_keyframe(frame_idx)
555 def _draw_hover_frame(self, frame_idx): 424 def _draw_hover_frame(self, frame_idx):
556 if not self._drawing: 425 if not self._drawing:
557 return 426 return
558 self._draw_hover(frame_idx) 427 self._draw_hover(frame_idx)
559 pass 428 pass
429
430 ## \brief Start future drawing actions
431 #
432 def start_drawing(self):
433 if not hasattr(self, '_gc'):
434 win = self.window
435 self._gc = gtk.gdk.GC(win)
436 #
437 # register for button press event
438 #
439 emask = win.get_events()
440 emask = emask | gtk.gdk.BUTTON_PRESS_MASK | \
441 gtk.gdk.POINTER_MOTION_MASK
442 win.set_events(emask)
443 pass
444 self._drawing = True
445 pass
446
447 ## \brief Stop any future drawing actions
448 #
449 # When doing massive udpate, to stop drawing the screen make
450 # application more effecient. The screen is updated by calling
451 # update() method after massive update and calliing start_drawing().
452 #
453 def stop_drawing(self):
454 self._drawing = False
455 pass
456 pass
457
458
459 ## Show frame status of a layer
460 #
461 # \section frameline_sigs Signals
462 # - 'frame-button-pree' for user press on a frame.
463 # - callback(widget, frame_idx, button)
464 #
465 # All methos that change state of the frameline, must call methods to update
466 # the screen.
467 #
468 class frameline(frameline_draw_state):
469 _sig_frame_but_press = None
470
471 FRAME_BUT_PRESS = 'frame-button-press'
472
473 def __new__(clz, *args):
474 fl_obj = frameline_draw_state.__new__(clz, *args)
475
476 if not clz._sig_frame_but_press:
477 but_press = gobject.signal_new(frameline.FRAME_BUT_PRESS,
478 frameline._type,
479 gobject.SIGNAL_RUN_FIRST,
480 gobject.TYPE_NONE,
481 (gobject.TYPE_INT,
482 gobject.TYPE_INT))
483 clz._sig_frame_but_press = but_press
484 pass
485 return fl_obj
486
487 def __init__(self, num_frames=20):
488 frameline_draw_state.__init__(self, num_frames)
489
490 self.connect('button-press-event', self._press_hdl)
491 self.connect('expose-event', self._fl_expose)
492 self.connect('motion-notify-event', self._motion_hdl)
493 self._last_hover = -1 # frame index of last hover
494 pass
495
496 def __len__(self):
497 return self._num_frames
498
499 def _find_keyframe(self, idx):
500 key_indic = [key.idx for key in self._keys]
501 key_pos = key_indic.index(idx)
502 return key_pos
503
504 def _find_keyframe_floor(self, frame_idx):
505 pos = 0
506 keys = [key.idx for key in self._keys]
507 keys.append(frame_idx)
508 keys.sort()
509 keys.reverse()
510 pos = (len(keys) - 1) - keys.index(frame_idx) - 1
511 return pos
512
513 ## \brief Find the range a continous tween.
514 #
515 def _find_tween_range(self, key_pos):
516 key = self._keys[key_pos]
517 if not (key.left_tween or key.right_tween):
518 raise ValueError, 'the keyframe is not in a tween'
519
520 #
521 # Initialize tween type and first_pos
522 #
523 if key.right_tween:
524 tween_type = key.right_tween_type
525 first_pos = key_pos
526 else:
527 # key.left_tween is True since the key is in a tween.
528 first_pos = key_pos -1
529 key = self._keys[first_pos]
530 tween_type = key.right_tween_type
531 pass
532
533 #
534 # Find first_pos
535 #
536 while first_pos and key.left_tween:
537 right_pos = first_pos - 1
538 right_key = self._keys[right_pos]
539 if right_key.right_tween_type != tween_type:
540 break
541 first_pos = right_pos
542 key = right_key
543 pass
544
545 #
546 # Find last_pos
547 #
548 max_pos = len(self._keys) - 1
549 last_pos = key_pos
550 key = self._keys[last_pos]
551 while last_pos < max_pos and self._keys[last_pos].right_tween:
552 if key.right_tween_type != tween_type:
553 break
554 last_pos = last_pos + 1
555 key = self._keys[last_pos]
556 pass
557
558 return first_pos, last_pos
559
560 def _press_hdl(self, widget, event):
561 frame = event.x / self._frame_width
562 but = event.button
563 self.emit(frameline.FRAME_BUT_PRESS, frame, but)
564 pass
565
566 def hide_hover(self):
567 if self._active_frame != self._last_hover:
568 self._draw_normal_frame(self._last_hover)
569 pass
570 pass
571
572 def _motion_hdl(self, widget, event):
573 frame_idx = int(event.x / self._frame_width)
574 if self._last_hover != -1:
575 self._draw_frame(self._last_hover)
576 if self._last_hover == self._active_frame:
577 self._draw_active_frame()
578 pass
579 pass
580
581 if frame_idx < self._num_frames and frame_idx >= 0:
582 self._draw_hover_frame(frame_idx)
583 if self._last_hover == self._active_frame:
584 self._draw_active_frame()
585 pass
586 self._last_hover = frame_idx
587 else:
588 self._last_hover = -1
589 pass
590 pass
591
592 def _fl_expose(self, widget, event):
593 win = self.window
594 self.start_drawing()
595 self.update()
596 pass
560 597
561 def set_tween_type(self, frame_idx, tween_type): 598 def set_tween_type(self, frame_idx, tween_type):
562 pos = self._find_keyframe(frame_idx) 599 pos = self._find_keyframe(frame_idx)
563 key = self._keys[pos] 600 key = self._keys[pos]
564 assert key.right_tween 601 assert key.right_tween
568 605
569 self._draw_active_frame() 606 self._draw_active_frame()
570 pass 607 pass
571 608
572 def update(self): 609 def update(self):
573 if not self._drawing:
574 return
575
576 win = self.window
577 x, y, w, h, depth = win.get_geometry()
578 self._draw_all_frames() 610 self._draw_all_frames()
579 self._draw_active_frame() 611 self._draw_active_frame()
580 pass 612 pass
581 613
582 ## Add a key frame 614 ## Add a key frame
641 pass 673 pass
642 674
643 ## Tween the key frame specified by an index and the key frame at right. 675 ## Tween the key frame specified by an index and the key frame at right.
644 # 676 #
645 # \see http://www.entheosweb.com/Flash/shape_tween.asp 677 # \see http://www.entheosweb.com/Flash/shape_tween.asp
646 def tween(self, idx, tween_type=TWEEN_TYPE_NONE): 678 def tween(self, idx, tween_type=frameline_draw_state.TWEEN_TYPE_NONE):
647 pos = self._find_keyframe(idx) 679 pos = self._find_keyframe(idx)
648 key = self._keys[pos] 680 key = self._keys[pos]
649 681
650 try: 682 try:
651 right_key = self._keys[pos + 1] 683 right_key = self._keys[pos + 1]
720 self._active_frame = -1 752 self._active_frame = -1
721 pass 753 pass
722 754
723 def set_num_frames(self, num): 755 def set_num_frames(self, num):
724 self._num_frames = num 756 self._num_frames = num
725 self._
726 pass 757 pass
727 758
728 def reset(self): 759 def reset(self):
729 self._keys = [] 760 self._keys = []
730 self._active_frame = -1 761 self._active_frame = -1
731 self._draw_all_frames() 762 self._draw_all_frames()
732 pass
733
734 ## \brief Start future drawing actions
735 #
736 def start_drawing(self):
737 self._drawing = True
738 pass
739
740 ## \brief Stop any future drawing actions
741 #
742 # When doing massive udpate, to stop drawing the screen make
743 # application more effecient. The screen is updated by calling
744 # update() method after massive update and calliing start_drawing().
745 #
746 def stop_drawing(self):
747 self._drawing = False
748 pass 763 pass
749 pass 764 pass
750 765
751 if __name__ == '__main__': 766 if __name__ == '__main__':
752 window = gtk.Window(gtk.WINDOW_TOPLEVEL) 767 window = gtk.Window(gtk.WINDOW_TOPLEVEL)