################################################################################ # # This file is part of Gato (Graph Animation Toolbox) # # file: AnimationHistory.py # author: Alexander Schliep (schliep@molgen.mpg.de) # # Copyright (C) 1998-2005, Alexander Schliep, Winfried Hochstaettler and # Copyright 1998-2001 ZAIK/ZPR, Universitaet zu Koeln # # Contact: schliep@molgen.mpg.de, wh@zpr.uni-koeln.de # # Information: http://gato.sf.net # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the Free # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # # This file is version $Revision: 1.3 $ # from $Date: 2005/02/22 11:12:45 $ # last change by $Author: schliep $. # ################################################################################ import time from GatoGlobals import gBlinkRate class AnimationCommand: def __init__(self, method, target, args, undo_method=None, undo_args=None): self.target = target self.method = method self.args = args self.undo_method = undo_method self.undo_args = undo_args def Do(self): apply(self.method, self.target + self.args) def Undo(self): if self.undo_method == None: apply(self.method, self.target + self.undo_args) else: apply(self.undo_method, self.target + self.undo_args) class AnimationHistory: """AnimationHistory provides a history of animation commands, and a undo and redo facility. It is to be used as a wrapper around a GraphDisplay and it will happily dispatch all calls to GraphDisplay. Animation commands for which undo/redo is provided, have to be methods of AnimationHistory """ def __init__(self, animator): self.animator = animator self.history = [] self.history_index = None #========== Provide Undo/Redo for animation commands from GraphDisplay ====== def SetVertexColor(self, v, color): # print 'SetVertexColor', v, color animation = AnimationCommand(self.animator.SetVertexColor, (v,), (color,), undo_args=(self.animator.GetVertexColor(v),)) animation.Do() self.append(animation) #SetAllVerticesColor #SetAllEdgesColor def SetEdgeColor(self,tail, head, color): # print 'SetEdgeColor', tail, head, color animation = AnimationCommand(self.animator.SetEdgeColor, (tail,head), (color,), undo_args=(self.animator.GetEdgeColor(tail,head),)) animation.Do() self.append(animation) def BlinkVertex(self, v, color=None): # print 'BlinkVertex', v, color animation = AnimationCommand(self.animator.BlinkVertex, (v,), (color,)) animation.Do() self.append(animation) def BlinkEdge(self, tail, head, color=None): # print 'BlinkEdge', tail, head, color animation = AnimationCommand(self.animator.BlinkEdge, (tail,head), (color,)) animation.Do() self.append(animation) def SetVertexFrameWidth(self,v,val): # print 'SetVertexFrameWidth', v, val animation = AnimationCommand(self.animator.SetVertexFrameWidth, (v,), (val,), undo_args=(self.animator.GetVertexFrameWidth(v),)) animation.Do() self.append(animation) def SetVertexAnnotation(self,v,annotation,color="black"): # print 'SetVertexAnnotation',v,annotation,color animation = AnimationCommand(self.animator.SetVertexAnnotation, (v,), (annotation,), undo_args=(self.animator.GetVertexAnnotation(v),)) animation.Do() self.append(animation) #========== Handle all other methods from GraphDisplay ===================== def __getattr__(self,arg): # This is broken. Calls to self.animator methods as args in self.animator method # calls should fail. tmp = getattr(self.animator,arg) if callable(tmp): self.methodName = arg self.method = tmp return getattr(self,'caller') else: return self.animator.__dict__[arg] def caller(self,*args): # print self.methodName,"(",args,")" return apply(self.method,args) #========== AnimationHistory methods ======================================= def Undo(self): if self.history_index == None: # Have never undone anything self.history_index = len(self.history) - 1 if self.history_index >= 0: self.history[self.history_index][1].Undo() self.history_index -= 1 def Do(self): if self.history_index is None: return if self.history_index >= len(self.history): self.history_index = None else: self.history[self.history_index][1].Do() self.history_index += 1 def DoAll(self): # Catchup if self.history_index is not None: for time, cmd in self.history[self.history_index:]: cmd.Do() self.history_index = None def Replay(self): if len(self.history) > 1: self.history[-1][1].Undo() self.animator.update() self.animator.canvas.after(10*gBlinkRate) self.history[-1][1].Do() self.animator.update() self.animator.canvas.after(10*gBlinkRate) self.history[-1][1].Undo() self.animator.update() self.animator.canvas.after(10*gBlinkRate) self.history[-1][1].Do() self.animator.update() def append(self, animation): #print "AnimationHistory: appending animation", animation.method self.history.append((time.time(), animation))