Mercurial > MadButterfly
diff pyink/frameline.py @ 1150:6586cd10c92f
Refactory frameline.py
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Sun, 26 Dec 2010 19:17:12 +0800 |
parents | 3ec0ad89e443 |
children | d333baa702a9 |
line wrap: on
line diff
--- a/pyink/frameline.py Fri Dec 24 15:40:16 2010 +0800 +++ b/pyink/frameline.py Sun Dec 26 19:17:12 2010 +0800 @@ -1,3 +1,5 @@ +# -*- indent-tabs-mode: t; tab-width: 8; python-indent: 4; fill-column: 79 -*- +# vim: sw=4:ts=8:sts=4:textwidth=79 import pygtk pygtk.require("2.0") import gtk @@ -16,7 +18,7 @@ self.left_tween = False self.right_tween = False self.right_tween_type = 0 - self.ref='' + self.ref = '' pass pass @@ -109,6 +111,9 @@ # - 'frame-button-pree' for user press on a frame. # - callback(widget, frame_idx, button) # +# All methos that change state of the frameline, must call methods to update +# the screen. +# class frameline(gtk.DrawingArea): _type = 0 _frame_width = 10 # Width for each frame is 10 pixels @@ -116,17 +121,18 @@ _key_mark_color = 0x000000 # color of marks for key frames. _key_mark_sz = 4 # width and height of a key frame mark _tween_color = 0x808080 # color of tween line - _tween_bgcolors = [0x80ff80, 0xff8080,0xffff80] # bg colors of tween frames + # bg colors of tween frames + _tween_bgcolors = [0x80ff80, 0xff8080, 0xffff80] # Colors for normal frames _normal_bgcolors = [0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xcccccc] _normal_border = 0xaaaaaa # border color of normal frames. _active_border = 0xff3030 # border color of an active frame _hover_border_color = 0xa0a0a0 # border when the pointer over a frame + # tween types - _tween_type_none=0 - _tween_type_move=1 - _tween_type_shape=2 - + TWEEN_TYPE_NONE = 0 + TWEEN_TYPE_MOVE = 1 + TWEEN_TYPE_SHAPE = 2 FRAME_BUT_PRESS = 'frame-button-press' @@ -155,20 +161,100 @@ self._drawing = False pass + def __len__(self): + return self._num_frames + + def _find_keyframe(self, idx): + key_indic = [key.idx for key in self._keys] + key_pos = key_indic.index(idx) + return key_pos + + def _find_keyframe_floor(self, frame_idx): + pos = 0 + keys = [key.idx for key in self._keys] + keys.append(frame_idx) + keys.sort() + keys.reverse() + pos = (len(keys) - 1) - keys.index(frame_idx) - 1 + return pos + + ## \brief Find the range a continous tween. + # + def _find_tween_range(self, key_pos): + key = self._keys[key_pos] + if not (key.left_tween or key.right_tween): + raise ValueError, 'the keyframe is not in a tween' + + # + # Initialize tween type and first_pos + # + if key.right_tween: + tween_type = key.right_tween_type + first_pos = key_pos + else: + # key.left_tween is True since the key is in a tween. + first_pos = key_pos -1 + key = self._keys[first_pos] + tween_type = key.right_tween_type + pass + + # + # Find first_pos + # + while first_pos and key.left_tween: + right_pos = first_pos - 1 + right_key = self._keys[right_pos] + if right_key.right_tween_type != tween_type: + break + first_pos = right_pos + key = right_key + pass + + # + # Find last_pos + # + max_pos = len(self._keys) - 1 + last_pos = key_pos + key = self._keys[last_pos] + while last_pos < max_pos and self._keys[last_pos].right_tween: + if key.right_tween_type != tween_type: + break + last_pos = last_pos + 1 + key = self._keys[last_pos] + pass + + return first_pos, last_pos + def _press_hdl(self, widget, event): frame = event.x / self._frame_width but = event.button self.emit(frameline.FRAME_BUT_PRESS, frame, but) pass + def hide_hover(self): if self._active_frame != self._last_hover: self._draw_normal_frame(self._last_hover) + pass + pass def _motion_hdl(self, widget, event): - frame = int(event.x / self._frame_width) - - if frame < self._num_frames and frame >= 0: - self._draw_hover(frame) + frame_idx = int(event.x / self._frame_width) + if self._last_hover != -1: + self._draw_frame(self._last_hover) + if self._last_hover == self._active_frame: + self._draw_active_frame() + pass + pass + + if frame_idx < self._num_frames and frame_idx >= 0: + self._draw_hover_frame(frame_idx) + if self._last_hover == self._active_frame: + self._draw_active_frame() + pass + self._last_hover = frame_idx + else: + self._last_hover = -1 + pass pass def _fl_expose(self, widget, event): @@ -188,12 +274,11 @@ self.update() pass - def _draw_tween(self, first_key, last_key): - if not self._drawing: - return - + def _draw_tween(self, first_pos, last_pos): win = self.window w_x, w_y, w_w, w_h, depth = win.get_geometry() + first_key = self._keys[first_pos] + last_key = self._keys[last_pos] # # Get background color of a tween @@ -229,9 +314,6 @@ pass def _draw_normal_frame(self, idx): - if not self._drawing: - return - win = self.window w_x, w_y, w_w, w_h, depth = win.get_geometry() @@ -255,10 +337,7 @@ ## \brief Draw a bottom line from start to the point before stop frame. # - def _draw_bottom_line(self, start, stop): - if not self._drawing: - return - + def _draw_bottom_line(self, start_idx, stop_idx): win = self.window w_x, w_y, w_w, w_h, depth = win.get_geometry() gc = self._gc @@ -266,66 +345,41 @@ border_rgb = color_to_rgb(self._normal_border) border_color = gtk.gdk.Color(*border_rgb) gc.set_rgb_fg_color(border_color) - start_x = start * self._frame_width - stop_x = stop * self._frame_width + start_x = start_idx * self._frame_width + stop_x = stop_idx * self._frame_width win.draw_line(gc, start_x, w_h - 1, stop_x, w_h - 1) pass - def _draw_all_frames(self): - if not self._drawing: - return - + def _draw_active(self, idx): win = self.window w_x, w_y, w_w, w_h, depth = win.get_geometry() + + color_v = self._active_border + color_rgb = color_to_rgb(color_v) + color = gtk.gdk.Color(*color_rgb) + gc = self._gc + gc.set_rgb_fg_color(color) - i = 0 - key_i = 0 - try: - key = self._keys[key_i] - except IndexError: - key = keyframe(self._num_frames) - pass - num_frames = self._num_frames - while i < num_frames: - if key.idx == i and key.right_tween: - # - # Skip tween keys - # - first_tween_key = key - while key.idx == i or key.left_tween: - last_tween_key = key - key_i = key_i + 1 - try: - key = self._keys[key_i] - except IndexError: - key = keyframe(self._num_frames) - pass - pass + line_x1 = idx * self._frame_width + line_x2 = line_x1 + self._frame_width - if first_tween_key != last_tween_key: - self._draw_tween(first_tween_key, last_tween_key) - - i = last_tween_key.idx + 1 - pass - else: - if key.idx == i: - key_i=key_i+1 - try: - key = self._keys[key_i] - except: - key = keyframe(self._num_frames) - self._draw_normal_frame(i) - i = i + 1 - pass - pass - - self._draw_bottom_line(0, num_frames) - pass + win.draw_line(gc, line_x1, 0, line_x1, w_h) + win.draw_line(gc, line_x2, 0, line_x2, w_h) + win.draw_line(gc, line_x1, w_h - 1, line_x2, w_h - 1) + win.draw_line(gc, line_x1, 0, line_x2, 0) + pass def _draw_keyframe(self, frame_idx): - if not self._drawing: - return + # Only keyframes that is not right-side of NONE type tween should be + # draw. + pos = self._find_keyframe(frame_idx) + key = self._keys[pos] + if key.left_tween and not key.right_tween: + left_key = self._keys[pos - 1] + if left_key.right_tween_type == 0: + return + pass win = self.window w_x, w_y, w_w, w_h, depth = win.get_geometry() @@ -345,157 +399,14 @@ pass def _draw_keyframes(self): - if not self._drawing: - return - - win = self.window - w_x, w_y, w_w, w_h, depth = win.get_geometry() - - color_v = self._key_mark_color - color_rgb = color_to_rgb(color_v) - color = gtk.gdk.Color(*color_rgb) - - gc = self._gc - gc.set_rgb_fg_color(color) - for key in self._keys: - if key.left_tween is True and lastkey.right_tween_type == frameline._tween_type_none: - continue - - mark_sz = self._key_mark_sz - mark_x = int((key.idx + 0.5) * self._frame_width - mark_sz / 2) - mark_y = w_h * 2 / 3 - mark_sz / 2 - - win.draw_rectangle(gc, True, mark_x, mark_y, mark_sz, mark_sz) - lastkey = key + self._draw_keyframe(key.idx) pass pass - def _draw_active(self): - if not self._drawing: - return - - if self._active_frame == -1: - return - - win = self.window - w_x, w_y, w_w, w_h, depth = win.get_geometry() - - color_v = self._active_border - color_rgb = color_to_rgb(color_v) - color = gtk.gdk.Color(*color_rgb) - - gc = self._gc - gc.set_rgb_fg_color(color) - - idx = self._active_frame - line_x1 = idx * self._frame_width - line_x2 = line_x1 + self._frame_width - - win.draw_line(gc, line_x1, 0, line_x1, w_h) - win.draw_line(gc, line_x2, 0, line_x2, w_h) - win.draw_line(gc, line_x1, w_h - 1, line_x2, w_h - 1) - win.draw_line(gc, line_x1, 0, line_x2, 0) - pass - - ## \brief Find the range a continous tween. - # - def _find_tween_range(self, key_pos): - first_pos = key_pos - while first_pos and self._keys[first_pos].left_tween: - first_pos = first_pos - 1 - pass - - max_pos = len(self._keys) - 1 - - last_pos = key_pos - while last_pos < max_pos and self._keys[last_pos].right_tween: - last_pos = last_pos + 1 - pass - - return first_pos, last_pos - - ## \brief Redraw a frame specified by an index. - # - def _redraw_frame(self, frame_idx): - if not self._drawing: - return - - keys = [key.idx for key in self._keys] - if len(keys): - try: - pos = keys.index(frame_idx) - except ValueError: - keys.append(frame_idx) - keys.sort() - pos = keys.index(frame_idx) - 1 - pass - if pos < 0: - pos = 0 - pass - key = self._keys[pos] - else: - key = None - pass - - if key and (key.right_tween or \ - (key.left_tween and key.idx == frame_idx)): - # - # in tween - # - first_pos, last_pos = self._find_tween_range(pos) - first_key = self._keys[first_pos] - last_key = self._keys[last_pos] - - self._draw_tween(first_key, last_key) - self._draw_bottom_line(first_key.idx, last_key.idx + 1) - - for i in range(first_pos, last_pos + 1): - key = self._keys[i] - if key.left_tween is False or lastkey.right_tween_type != frameline._tween_type_none: - self._draw_keyframe(key.idx) - lastkey = key - pass - pass - else: # not in tween - self._draw_normal_frame(frame_idx) - self._draw_bottom_line(frame_idx, frame_idx + 1) - if key and (key.idx == frame_idx): - self._draw_keyframe(frame_idx) - pass - pass - pass - def set_tween_type(self,frame_idx,typ): - found=False - for i in range(0,len(self._keys)): - if self._keys[i].idx == frame_idx: - idx = i - found = True - break - if not found: return - key = self._keys[idx] - if typ == 'normal': - type = self._tween_type_none - elif typ == 'relocate': - type = self._tween_type_move - elif typ == 'scale': - type = self._tween_type_shape - if key.left_tween is False and key.right_tween is True: - key.right_tween_type = type - - ## \brief Show a mark for the pointer for a frame. # def _draw_hover(self, frame_idx): - if not self._drawing: - return - - if self._last_hover != -1: - self._redraw_frame(self._last_hover) - pass - - self._draw_active() - win = self.window w_x, w_y, w_w, w_h, depth = win.get_geometry() gc = self._gc @@ -511,10 +422,125 @@ win.draw_line(gc, line_x2, 1, line_x2, w_h - 2) win.draw_line(gc, line_x1, 1, line_x2, 1) win.draw_line(gc, line_x1, w_h - 2, line_x2, w_h - 2) + pass + + ## \brief Redraw a frame specified by an index. + # + def _draw_frame(self, frame_idx): + if not self._drawing: + return - self._last_hover = frame_idx + pos = self._find_keyframe_floor(frame_idx) + try: + key = self._keys[pos] + except IndexError: + key = None + pass + + if key and (key.right_tween or + (key.left_tween and key.idx == frame_idx)): + # + # in tween + # + first_pos, last_pos = self._find_tween_range(pos) + first_key = self._keys[first_pos] + last_key = self._keys[last_pos] + + self._draw_tween_of_key(first_pos) + else: # not in tween + self._draw_normal_frame(frame_idx) + self._draw_bottom_line(frame_idx, frame_idx + 1) + if key and (key.idx == frame_idx): + self._draw_keyframe(frame_idx) + pass + pass pass + def _draw_all_frames(self): + if not self._drawing: + return + + i = 0 + key_pos = 0 + try: + key = self._keys[key_pos] + except IndexError: + key = keyframe(self._num_frames) + pass + num_frames = self._num_frames + while i < num_frames: + if key.idx == i and key.right_tween: + # + # Skip tween keys + # + first_tween_pos, last_tween_pos = \ + self._find_tween_range(key_pos) + self._draw_tween(first_tween_pos, last_tween_pos) + last_tween_key = self._keys[last_tween_pos] + i = last_tween_key.idx + 1 + else: + self._draw_normal_frame(i) + if key.idx == i: + key_pos = key_pos+1 + try: + key = self._keys[key_pos] + except: + key = keyframe(self._num_frames) + pass + pass + i = i + 1 + pass + pass + + self._draw_bottom_line(0, num_frames) + + self._draw_keyframes() + pass + + def _draw_tween_of_key(self, key_pos): + if not self._drawing: + return + + first_pos, last_pos = self._find_tween_range(key_pos) + first_key = self._keys[first_pos] + last_key = self._keys[last_pos] + + self._draw_tween(first_pos, last_pos) + self._draw_bottom_line(first_key.idx, last_key.idx + 1) + + for i in range(first_pos, last_pos + 1): + key = self._keys[i] + self._draw_keyframe(key.idx) + pass + pass + + def _draw_active_frame(self): + if not self._drawing: + return + + if self._active_frame == -1: + return + + self._draw_active(self._active_frame) + pass + + def _draw_hover_frame(self, frame_idx): + if not self._drawing: + return + self._draw_hover(frame_idx) + pass + + def set_tween_type(self, frame_idx, tween_type): + pos = self._find_keyframe(frame_idx) + key = self._keys[pos] + assert key.right_tween + + key.right_tween_type = tween_type + self._draw_tween_of_key(pos) + + self._draw_active_frame() + pass + def update(self): if not self._drawing: return @@ -522,21 +548,22 @@ win = self.window x, y, w, h, depth = win.get_geometry() self._draw_all_frames() - self._draw_keyframes() - if self._active_frame != -1: - self._draw_active() - pass + self._draw_active_frame() pass ## Add a key frame # # A key frame is the frame that user specify actions. For # example, move a object or add new objects at the frame. - def add_keyframe(self, idx,ref=None): - key_indic = [key.idx for key in self._keys] - if idx in key_indic: - return - + def add_keyframe(self, idx, ref=None): + try: + pos = self._find_keyframe(idx) # it is not already a keyframe. + except ValueError: + pass + else: + raise ValueError, 'the frame is already a key frame' + + key_indic = [key.idx for key in self._keys] key_indic.append(idx) key_indic.sort() insert_pos = key_indic.index(idx) @@ -552,78 +579,99 @@ key.right_tween = True pass - self._draw_keyframe(idx) + if self._drawing: + self._draw_keyframe(idx) + pass pass def rm_keyframe(self, idx): - found=False - for i in range(0,len(self._keys)): - if self._keys[i].idx == idx: - idx = i - found = True - break - if not found: return - key = self._keys[idx] + key_pos = self._find_keyframe(idx) + key = self._keys[key_pos] + del self._keys[key_pos] if key.right_tween ^ key.left_tween: # # tween in one side # if key.right_tween: - right_key = self._keys[idx] + right_key = self._keys[key_pos] right_key.left_tween = False redraw_range = (right_key.idx, idx + 1) else: - left_key = self._keys[idx - 1] + left_key = self._keys[key_pos - 1] left_key.right_key = False redraw_range = (idx, left_key.idx + 1) pass for i in range(*redraw_range): - self._redraw_frame(i) + self._draw_frame(i) pass else: - self._redraw_frame(idx) + self._draw_frame(idx) pass - del self._keys[idx] - self._draw_active() + self._draw_active_frame() pass ## Tween the key frame specified by an index and the key frame at right. # # \see http://www.entheosweb.com/Flash/shape_tween.asp - def tween(self, idx, _type='normal'): - key_indic = [key.idx for key in self._keys] - pos = key_indic.index(idx) + def tween(self, idx, tween_type=TWEEN_TYPE_NONE): + pos = self._find_keyframe(idx) key = self._keys[pos] try: right_key = self._keys[pos + 1] except IndexError: - raise ValueError, 'No right key frame' + raise ValueError, 'no right key frame' key.right_tween = True right_key.left_tween = True - if _type == 'normal': - key.right_tween_type = self._tween_type_none - elif _type == 'relocate': - key.right_tween_type = self._tween_type_move - elif _type == 'scale': - key.right_tween_type = self._tween_type_shape + key.right_tween_type = tween_type + + self._draw_tween_of_key(pos) + self._draw_active_frame() pass - def get_tween_type(self,idx): + + def get_tween_type(self, idx): for i in range(0,len(self._keys)): key = self._keys[i] if key.left_tween is True: continue if key.idx == idx: - if key.right_tween_type == self._tween_type_none: - return 'normal' - elif key.right_tween_type == self._tween_type_move: - return 'relocate' - elif key.right_tween_type == self._tween_type_shape: - return 'scale' - + return key.right_tween_type + pass + pass + + def get_frame_blocks(self): + blocks = [] + for pos, key in enumerate(self._keys): + if key.right_tween: + next_key = self._keys[pos + 1] + block = (key.idx, next_key.idx, key.right_tween_type) + elif not key.left_tween: + block = (key.idx, key.idx, 0) + pass + blocks.append(block) + pass + return blocks + def get_frame_block(self, idx): + pos = self._find_keyframe_floor(idx) + if pos != -1: + key = self._keys[pos] + if key.idx == idx: + return key.idx, key.idx, 0 + elif key.right_tween: + next_key = self._keys[pos + 1] + return key.idx, next_key.idx, key.right_tween_type + pass + raise ValueError, \ + 'the frame specified by idx is not in any tween or a key frame' + + def get_frame_data(self, idx): + pos = self._find_keyframe(idx) + key = self._keys[pos] + return key.ref + ## Set active frame # # The active frame is the frame that is working on. @@ -633,49 +681,28 @@ raise IndexError, 'value of index (%d) is out of range' % (idx) if self._active_frame != -1: - self._redraw_frame(self._active_frame) + self._draw_frame(self._active_frame) pass self._active_frame = idx - self._draw_active() + self._draw_active_frame() pass def deactive(self): - self._redraw_frame(self._active_frame) + self._draw_frame(self._active_frame) self._active_frame = -1 pass def set_num_frames(self, num): self._num_frames = num + self._ pass def reset(self): self._keys = [] + self._active_frame = -1 + self._draw_all_frames() pass - def addScenes(self,rdoc,node): - for i in range(0,len(self._keys)): - key = self._keys[i] - if key.left_tween is True: continue - if key.right_tween is True: - ss = rdoc.createElement("ns0:scene") - node.appendChild(ss) - ss.setAttribute("start", str(key.idx+1)) - ss.setAttribute("ref",key.ref.attribute("id")) - ss.setAttribute("end", str(self._keys[i+1].idx+1)) - if self._keys[i].right_tween_type == self._tween_type_none: - ss.setAttribute("type", "normal") - elif self._keys[i].right_tween_type == self._tween_type_move: - ss.setAttribute("type", "relocate") - elif self._keys[i].right_tween_type == self._tween_type_shape: - ss.setAttribute("type", "scale") - else: - ss = rdoc.createElement("ns0:scene") - node.appendChild(ss) - ss.setAttribute("start", str(key.idx+1)) - ss.setAttribute("ref",key.ref.attribute("id")) - ss.setAttribute("type", "normal") - - ## \brief Start future drawing actions # def start_drawing(self): @@ -691,9 +718,6 @@ def stop_drawing(self): self._drawing = False pass - - def __len__(self): - return self._num_frames pass if __name__ == '__main__':