Package libavg :: Module anim

Source Code for Module libavg.anim

  1  # libavg - Media Playback Engine. 
  2  # Copyright (C) 2003-2008 Ulrich von Zadow 
  3  # 
  4  # This library is free software; you can redistribute it and/or 
  5  # modify it under the terms of the GNU Lesser General Public 
  6  # License as published by the Free Software Foundation; either 
  7  # version 2 of the License, or (at your option) any later version. 
  8  # 
  9  # This library is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 12  # Lesser General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU Lesser General Public 
 15  # License along with this library; if not, write to the Free Software 
 16  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 17  # 
 18  # Current versions can be found at www.libavg.de 
 19  # 
 20   
 21  """ 
 22  Provides a framework for time-based animations. Deprecated - there is a better 
 23  framework in the avg module. 
 24  """ 
 25   
 26  import math 
 27   
 28  avg = None 
 29  g_Player = None 
 30   
 31  # Map of all active SimpleAnimations: (node, attribute)->SimpleAnimation 
 32  g_ActiveAnimations = {} 
 33   
 34  try: 
 35      from . import avg 
 36  except ValueError: 
 37      pass 
 38   
 39   
40 -def getNumRunningAnims():
41 return len(g_ActiveAnimations)
42
43 -def abortAnim(node, attrName):
44 global g_ActiveAnimations 45 if g_ActiveAnimations.has_key((node, attrName)): 46 curAnim = g_ActiveAnimations.get((node, attrName)) 47 curAnim._remove()
48 49 g_DeprecationWarned = False 50
51 -def deprecationWarning():
52 global g_DeprecationWarned 53 if not(g_DeprecationWarned): 54 g_DeprecationWarned = True 55 print "The anim package is deprecated and will be removed in the next release; use the anim classes in the avg namespace instead."
56
57 -class SimpleAnim:
58 """ 59 Base class for animations that change libavg node attributes by interpolating 60 over a set amount of time. Constructing an animation object starts the 61 animation. If abort() isn't needed, there is no need to hold on to the object - 62 it will exist exactly as long as the animation lasts and then disappear. 63 64 The animation framework makes sure that only one animation per attribute of a 65 node runs at any given time. If a second one is started, the first one is 66 silently aborted. 67 """
68 - def __init__(self, node, attrName, duration, useInt, onStop, onStart):
69 global g_Player 70 global g_ActiveAnimations 71 72 deprecationWarning() 73 g_Player = avg.Player.get() 74 self.node = node 75 self.attrName = attrName 76 self.duration = duration 77 self.onStart = onStart 78 self.onStop = onStop 79 self.onAbort = lambda: None 80 self.useInt = useInt
81
82 - def setHandler(self, onStop, onAbort):
83 self.onStop = onStop 84 self.onAbort = onAbort
85
86 - def start(self, keepAttr=False):
87 abortAnim(self.node, self.attrName) 88 g_ActiveAnimations[(self.node, self.attrName)] = self 89 if keepAttr: 90 self._calcStartTime() 91 else: 92 self.startTime = g_Player.getFrameTime() 93 self.__interval = g_Player.setOnFrameHandler(self._step) 94 self.__done = False 95 if self.onStart: 96 self.onStart() 97 if self.duration == 0: 98 self._regularStop() 99 elif self.duration: 100 self.__stopTimeout = g_Player.setTimeout(self.duration, self._regularStop) 101 self._step()
102
103 - def abort(self):
104 """ 105 Stops the animation. Does not call onStop() 106 """ 107 if not(self.isDone()): 108 self._remove() 109 if self.onAbort: 110 self.onAbort()
111
112 - def isDone(self):
113 """ 114 Returns True if the animation has run its course. 115 """ 116 return self.__done
117
118 - def _remove(self):
119 global g_ActiveAnimations 120 self.__done = True 121 g_ActiveAnimations.pop((self.node, self.attrName)) 122 g_Player.clearInterval(self.__interval) 123 if self.duration: 124 g_Player.clearInterval(self.__stopTimeout)
125 126
127 -class LinearAnim(SimpleAnim):
128 """ 129 Class that animates an attribute of a libavg node by interpolating linearly 130 between start and end values. 131 """
132 - def __init__(self, node, attrName, duration, startValue, endValue, useInt=False, 133 onStop=None, onStart=None):
134 """ 135 @param node: The libavg node object to animate. 136 @param attrName: The name of the attribute to change. Must be a numeric 137 attribute. 138 @param duration: The length of the animation in milliseconds. 139 @param startValue: Initial value of the attribute. 140 @param endValue: Value of the attribute after duration has elapsed. 141 @param useInt: If True, the attribute is always set to an integer value. 142 @param onStop: Python callable to invoke when duration has elapsed and 143 the animation has finished. This can be used to chain 144 animations together by using lambda to create a second animation. 145 """ 146 self.__startValue = startValue 147 self.__endValue = endValue 148 SimpleAnim.__init__(self, node, attrName, duration, useInt, onStop, onStart)
149
150 - def _step(self):
151 if not(self.isDone()): 152 part = ((float(g_Player.getFrameTime())-self.startTime)/self.duration) 153 if part > 1.0: 154 part = 1.0 155 curValue = self.__startValue+(self.__endValue-self.__startValue)*part 156 if self.useInt: 157 curValue = int(curValue+0.5) 158 setattr(self.node, self.attrName, curValue)
159
160 - def _regularStop(self):
161 setattr(self.node, self.attrName, self.__endValue) 162 self._remove() 163 if self.onStop != None: 164 self.onStop()
165
166 - def _calcStartTime(self):
167 curVal = getattr(self.node, self.attrName) 168 part = float(curVal-self.__startValue)/(self.__endValue-self.__startValue) 169 self.startTime = g_Player.getFrameTime()-part*self.duration
170 171
172 -class EaseInOutAnim(SimpleAnim):
173 - def __init__(self, node, attrName, duration, startValue, endValue, 174 easeInDuration, easeOutDuration, useInt=False, onStop=None, 175 onStart=None):
176 self.__startValue = startValue 177 self.__endValue = endValue 178 self.__easeInDuration = float(easeInDuration)/duration 179 self.__easeOutDuration = float(easeOutDuration)/duration 180 SimpleAnim.__init__(self, node, attrName, duration, useInt, onStop, onStart)
181
182 - def _step(self):
183 if not(self.isDone()): 184 t = (float(g_Player.getFrameTime())-self.startTime)/self.duration; 185 part = self.__ease(t, self.__easeInDuration, self.__easeOutDuration) 186 curValue = self.__startValue+(self.__endValue-self.__startValue)*part 187 if self.useInt: 188 curValue = int(curValue+0.5) 189 setattr(self.node, self.attrName, curValue)
190
191 - def _regularStop(self):
192 setattr(self.node, self.attrName, self.__endValue) 193 self._remove() 194 if self.onStop != None: 195 self.onStop()
196
197 - def _calcStartTime(self):
198 #XXX: This calculates an inaccurate start time 199 curVal = getattr(self.node, self.attrName) 200 part = float(curVal-self.__startValue)/(self.__endValue-self.__startValue) 201 self.startTime = g_Player.getFrameTime()-part*self.duration
202
203 - def __ease(self, t, easeInDuration, easeOutDuration):
204 # All times here are normalized to be between 0 and 1 205 if t > 1: 206 t=1 207 accelDist = easeInDuration*2/math.pi 208 decelDist = easeOutDuration*2/math.pi 209 if t<easeInDuration: 210 # Acceleration stage 211 nt=t/easeInDuration 212 s=math.sin(-math.pi/2+nt*math.pi/2)+1; 213 dist=s*accelDist; 214 elif t > 1-easeOutDuration: 215 # Deceleration stage 216 nt = (t-(1-easeOutDuration))/easeOutDuration 217 s = math.sin(nt*math.pi/2) 218 dist = accelDist+(1-easeInDuration-easeOutDuration)+s*decelDist 219 else: 220 # Linear stage 221 dist = accelDist+t-easeInDuration 222 return dist/(accelDist+(1-easeInDuration-easeOutDuration)+decelDist)
223 224
225 -class SplineAnim(SimpleAnim):
226 """ 227 Class that animates an attribute of a libavg node by interpolating 228 between start and end values using a cubic spline. 229 """
230 - def __init__(self, node, attrName, duration, startValue, startSpeed, endValue, 231 endSpeed, useInt=False, onStop=None, onStart=None):
232 """ 233 @param node: The libavg node object to animate. 234 @param attrName: The name of the attribute to change. Must be a numeric 235 attribute. 236 @param duration: The length of the animation in milliseconds. 237 @param startValue: Initial value of the attribute. 238 @param startSpeed: Initial speed of the animation. 239 @param endValue: Value of the attribute after duration has elapsed. 240 @param endSpeed: Final speed of the animation. 241 @param useInt: If True, the attribute is always set to an integer value. 242 @param onStop: Python callable to invoke when duration has elapsed and 243 the animation has finished. This can be used to chain 244 animations together by using lambda to create a second animation. 245 """ 246 self.__startValue = startValue+0.0 247 self.__startSpeed = startSpeed 248 self.__endValue = endValue 249 self.__endSpeed = endSpeed 250 self.__a = -2*(self.__endValue-self.__startValue)+self.__startSpeed+self.__endSpeed 251 self.__b = 3*(self.__endValue-self.__startValue)-2*self.__startSpeed-self.__endSpeed 252 self.__c = self.__startSpeed 253 self.__d = self.__startValue 254 SimpleAnim.__init__(self, node, attrName, duration, useInt, onStop, onStart)
255
256 - def _step(self):
257 if not(self.isDone()): 258 part = ((float(g_Player.getFrameTime())-self.startTime)/self.duration) 259 if part > 1.0: 260 part = 1.0 261 curValue = ((self.__a*part+self.__b)*part+self.__c)*part+self.__d 262 if self.useInt: 263 curValue = int(curValue+0.5) 264 setattr(self.node, self.attrName, curValue)
265
266 - def _regularStop(self):
267 setattr(self.node, self.attrName, self.__endValue) 268 self._remove() 269 if self.onStop != None: 270 self.onStop()
271
272 - def _calcStartTime(self):
273 #XXX: This calculates an inaccurate start time 274 curVal = getattr(self.node, self.attrName) 275 part = float(curVal-self.__startValue)/(self.__endValue-self.__startValue) 276 self.startTime = g_Player.getFrameTime()-part*self.duration
277 278
279 -def fadeOut(node, duration, onStop = None):
280 """ 281 Fades the opacity of a node to zero. 282 @param node: The node to fade. 283 @param duration: Length of the fade in milliseconds. 284 """ 285 fader = LinearAnim(node, "opacity", duration, node.opacity, 0, onStop = onStop) 286 fader.start() 287 return fader
288
289 -def fadeIn(node, duration, max=1.0, onStop = None):
290 """ 291 Fades the opacity of a node. 292 @param node: The node to fade. 293 @param duration: Length of the fade in milliseconds. 294 @param max: The opacity of the node at the end of the fade. 295 """ 296 fader = LinearAnim(node, "opacity", duration, node.opacity, max, onStop = onStop) 297 fader.start() 298 return fader
299 300
301 -class ContinuousAnim(SimpleAnim):
302 """ 303 Class that animates an attribute of a libavg node continuously and 304 linearly. The animation will not stop until the abort() method is called. 305 A possible use case is the continuous rotation of an object. 306 """
307 - def __init__(self, node, attrName, startValue, speed, useInt=False, 308 onStart=None):
309 """ 310 @param node: The libavg node object to animate. 311 @param attrName: The name of the attribute to change. Must be a numeric 312 attribute. 313 @param startValue: Initial value of the attribute. 314 @param speed: Animation speed, value to be added per second. 315 @param useInt: If True, the attribute is always set to an integer value. 316 """ 317 self.__startValue = startValue 318 self.__speed = speed 319 SimpleAnim.__init__(self, node, attrName, None, useInt, None, onStart)
320
321 - def _step(self):
322 time = (float(g_Player.getFrameTime())-self.startTime)/1000 323 curValue = self.__startValue+time*self.__speed 324 if self.useInt: 325 curValue = int(curValue+0.5) 326 setattr(self.node, self.attrName, curValue)
327
328 - def _calcStartTime(self):
329 curVal = getattr(self.node, self.attrName) 330 self.__startValue = curVal
331 332
333 -class WaitAnim:
334 - def __init__(self, duration=None, onStop=None, onStart=None):
335 self.__duration = duration 336 self.onStart = onStart 337 self.onStop = onStop 338 self.onAbort = None 339 self.__isDone = True
340
341 - def setHandler(self, onStop, onAbort):
342 self.onStop = onStop 343 self.onAbort = onAbort
344
345 - def start(self, keepAttr=False):
346 self.__isDone = False 347 if self.onStart: 348 self.onStart() 349 if self.__duration: 350 self.__stopTimeout = g_Player.setTimeout(self.__duration, self.__regularStop) 351 else: 352 self.__stopTimeout = None
353
354 - def abort(self):
355 if self.__stopTimeout: 356 g_Player.clearInterval(self.__stopTimeout) 357 if not(self.__isDone): 358 self.__isDone = True 359 if self.onAbort: 360 self.onAbort()
361
362 - def isDone(self):
363 return self.__isDone
364
365 - def _calcStartTime(self):
366 pass
367
368 - def __regularStop(self):
369 g_Player.clearInterval(self.__stopTimeout) 370 self.__isDone = True 371 self.onStop()
372 373
374 -class ParallelAnim:
375 - def __init__(self, anims, onStop=None, onStart=None, maxAge=None):
376 self.__anims = anims 377 self.onStart = onStart 378 self.onStop = onStop 379 self.__maxAge = maxAge 380 self.__isDone = False
381
382 - def setHandler(self, onStop, onAbort):
383 self.onStop = onStop 384 self.onAbort = onAbort
385
386 - def start(self, keepAttr=False):
387 self.__isDone = False 388 if self.onStart: 389 self.onStart() 390 self.__runningAnims = self.__anims[:] 391 if self.__maxAge: 392 self.__maxAgeTimeout = g_Player.setTimeout(self.__maxAge, 393 self.__maxAgeReached) 394 for anim in self.__runningAnims: 395 stopHandler = lambda anim=anim: self.__animStopped(anim) 396 anim.setHandler(onStop = stopHandler, onAbort = stopHandler) 397 anim.start(keepAttr)
398
399 - def abort(self):
400 if not(self.__isDone): 401 self.__isDone = True 402 for anim in self.__runningAnims: 403 anim.abort() 404 if self.onAbort: 405 self.onAbort() 406 if self.__maxAge: 407 g_Player.clearInterval(self.__maxAgeTimeout)
408
409 - def isDone(self):
410 return self.__isDone
411
412 - def __maxAgeReached(self):
413 if not(self.__isDone): 414 for anim in self.__runningAnims: 415 anim.abort() 416 self.onStop() 417 self.__isDone = True
418
419 - def __animStopped(self, anim):
420 self.__runningAnims.remove(anim) 421 if len(self.__runningAnims) == 0 and not(self.__isDone): 422 self.onStop() 423 self.__isDone = True 424 if self.__maxAge: 425 g_Player.clearInterval(self.__maxAgeTimeout)
426 427
428 -class StateAnim:
429 - def __init__(self, states, transitions, initialState=None):
430 self.__states = states 431 for name in states: 432 states[name].setHandler(self.__onStateDone, None) 433 self.__transitions = transitions 434 self.__curState = None 435 self.__debug = False 436 if initialState: 437 self.setState(initialState)
438
439 - def delete(self):
440 if self.__debug: 441 print self, " delete" 442 self.setState(None)
443
444 - def setState(self, stateName, keepAttr=False):
445 if self.__debug: 446 print self, " setState: ", self.__curState, "-->", stateName 447 if self.__curState == stateName: 448 return 449 if self.__curState: 450 self.__states[self.__curState].abort() 451 self.__curState = stateName 452 if stateName: 453 self.__states[stateName].start(keepAttr)
454
455 - def getState(self):
456 return self.__curState
457
458 - def setDebug(self, debug):
459 self.__debug = debug
460
461 - def __onStateDone(self):
462 if self.__curState in self.__transitions: 463 transition = self.__transitions[self.__curState] 464 if transition.callback: 465 transition.callback() 466 stateName = transition.nextAnimName 467 if self.__debug: 468 print self, " StateDone: ", self.__curState, "-->", stateName 469 self.__curState = stateName 470 self.__states[stateName].start() 471 else: 472 if self.__debug: 473 print self, " StateDone: ", self.__curState, "--> None" 474 self.__curState = None
475 476
477 -class AnimTransition:
478 - def __init__(self, nextAnimName, callback = None):
479 self.nextAnimName = nextAnimName 480 self.callback = callback
481 482
483 -def init(g_avg):
484 global avg 485 global g_ActiveAnimations 486 avg = g_avg 487 g_ActiveAnimations = {}
488