diff options
Diffstat (limited to 'lib/pytweener.py')
-rw-r--r-- | lib/pytweener.py | 343 |
1 files changed, 0 insertions, 343 deletions
diff --git a/lib/pytweener.py b/lib/pytweener.py deleted file mode 100644 index f5cacd7..0000000 --- a/lib/pytweener.py +++ /dev/null @@ -1,343 +0,0 @@ -# pyTweener -# -# Tweening functions for python -# -# Heavily based on caurina Tweener: http://code.google.com/p/tweener/ -# -# Released under M.I.T License - see above url -# Python version by Ben Harling 2009 -# All kinds of slashing and dashing by Toms Baugis 2010 -import math -import collections -import datetime as dt -import time -import re - -class Tweener(object): - def __init__(self, default_duration = None, tween = None): - """Tweener - This class manages all active tweens, and provides a factory for - creating and spawning tween motions.""" - self.current_tweens = collections.defaultdict(set) - self.default_easing = tween or Easing.Cubic.ease_in_out - self.default_duration = default_duration or 1.0 - - def has_tweens(self): - return len(self.current_tweens) > 0 - - - def add_tween(self, obj, duration = None, easing = None, on_complete = None, on_update = None, **kwargs): - """ - Add tween for the object to go from current values to set ones. - Example: add_tween(sprite, x = 500, y = 200, duration = 0.4) - This will move the sprite to coordinates (500, 200) in 0.4 seconds. - For parameter "easing" you can use one of the pytweener.Easing - functions, or specify your own. - The tweener can handle numbers, dates and color strings in hex ("#ffffff"). - This function performs overwrite style conflict solving - in case - if a previous tween operates on same attributes, the attributes in - question are removed from that tween. - """ - if duration is None: - duration = self.default_duration - - easing = easing or self.default_easing - - tw = Tween(obj, duration, easing, on_complete, on_update, **kwargs ) - - if obj in self.current_tweens: - for current_tween in tuple(self.current_tweens[obj]): - prev_keys = set((key for (key, tweenable) in current_tween.tweenables)) - dif = prev_keys & set(kwargs.keys()) - - for key, tweenable in tuple(current_tween.tweenables): - if key in dif: - current_tween.tweenables.remove((key, tweenable)) - - if not current_tween.tweenables: - current_tween.finish() - self.current_tweens[obj].remove(current_tween) - - - self.current_tweens[obj].add(tw) - return tw - - - def get_tweens(self, obj): - """Get a list of all tweens acting on the specified object - Useful for manipulating tweens on the fly""" - return self.current_tweens.get(obj, None) - - def kill_tweens(self, obj = None): - """Stop tweening an object, without completing the motion or firing the - on_complete""" - if obj: - try: - del self.current_tweens[obj] - except: - pass - else: - self.current_tweens = collections.defaultdict(set) - - def remove_tween(self, tween): - """"remove given tween without completing the motion or firing the on_complete""" - if tween.target in self.current_tweens and tween in self.current_tweens[tween.target]: - self.current_tweens[tween.target].remove(tween) - if not self.current_tweens[tween.target]: - del self.current_tweens[tween.target] - - def finish(self): - """jump the the last frame of all tweens""" - for obj in self.current_tweens: - for tween in self.current_tweens[obj]: - tween.finish() - self.current_tweens = {} - - def update(self, delta_seconds): - """update tweeners. delta_seconds is time in seconds since last frame""" - - for obj in tuple(self.current_tweens): - for tween in tuple(self.current_tweens[obj]): - done = tween._update(delta_seconds) - if done: - self.current_tweens[obj].remove(tween) - if tween.on_complete: tween.on_complete(tween.target) - - if not self.current_tweens[obj]: - del self.current_tweens[obj] - - return self.current_tweens - - -class Tween(object): - __slots__ = ('tweenables', 'target', 'delta', 'duration', 'ease', 'delta', - 'on_complete', 'on_update', 'complete') - - def __init__(self, obj, duration, easing, on_complete, on_update, **kwargs): - """Tween object use Tweener.add_tween( ... ) to create""" - self.duration = duration - self.target = obj - self.ease = easing - - # list of (property, start_value, delta) - self.tweenables = set() - for key, value in kwargs.items(): - self.tweenables.add((key, Tweenable(self.target.__dict__[key], value))) - - self.delta = 0 - self.on_complete = on_complete - self.on_update = on_update - self.complete = False - - def finish(self): - self._update(self.duration) - - def _update(self, ptime): - """Update tween with the time since the last frame""" - self.delta = self.delta + ptime - if self.delta > self.duration: - self.delta = self.duration - - if self.delta == self.duration: - for key, tweenable in self.tweenables: - self.target.__setattr__(key, tweenable.target_value) - else: - fraction = self.ease(self.delta / self.duration) - - for key, tweenable in self.tweenables: - self.target.__setattr__(key, tweenable.update(fraction)) - - if self.delta == self.duration or len(self.tweenables) == 0: - self.complete = True - - if self.on_update: - self.on_update(self.target) - - return self.complete - - - - -class Tweenable(object): - """a single attribute that has to be tweened from start to target""" - __slots__ = ('start_value', 'change', 'decode_func', 'target_value', 'update') - - hex_color_normal = re.compile("#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})") - hex_color_short = re.compile("#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])") - - - def __init__(self, start_value, target_value): - self.decode_func = lambda x: x - self.target_value = target_value - - def float_update(fraction): - return self.start_value + self.change * fraction - - def date_update(fraction): - return dt.date.fromtimestamp(self.start_value + self.change * fraction) - - def datetime_update(fraction): - return dt.datetime.fromtimestamp(self.start_value + self.change * fraction) - - def color_update(fraction): - val = [max(min(self.start_value[i] + self.change[i] * fraction, 255), 0) for i in range(3)] - return "#%02x%02x%02x" % (val[0], val[1], val[2]) - - - if isinstance(start_value, int) or isinstance(start_value, float): - self.start_value = start_value - self.change = target_value - start_value - self.update = float_update - else: - if isinstance(start_value, dt.datetime) or isinstance(start_value, dt.date): - if isinstance(start_value, dt.datetime): - self.update = datetime_update - else: - self.update = date_update - - self.decode_func = lambda x: time.mktime(x.timetuple()) - self.start_value = self.decode_func(start_value) - self.change = self.decode_func(target_value) - self.start_value - - elif isinstance(start_value, basestring) \ - and (self.hex_color_normal.match(start_value) or self.hex_color_short.match(start_value)): - self.update = color_update - if self.hex_color_normal.match(start_value): - self.decode_func = lambda val: [int(match, 16) - for match in self.hex_color_normal.match(val).groups()] - - elif self.hex_color_short.match(start_value): - self.decode_func = lambda val: [int(match + match, 16) - for match in self.hex_color_short.match(val).groups()] - - if self.hex_color_normal.match(target_value): - target_value = [int(match, 16) - for match in self.hex_color_normal.match(target_value).groups()] - else: - target_value = [int(match + match, 16) - for match in self.hex_color_short.match(target_value).groups()] - - self.start_value = self.decode_func(start_value) - self.change = [target - start for start, target in zip(self.start_value, target_value)] - - - -"""Robert Penner's classes stripped from the repetetive c,b,d mish-mash -(discovery of Patryk Zawadzki). This way we do the math once and apply to -all the tweenables instead of repeating it for each attribute -""" - -def inverse(method): - def real_inverse(t, *args, **kwargs): - t = 1 - t - return 1 - method(t, *args, **kwargs) - return real_inverse - -def symmetric(ease_in, ease_out): - def real_symmetric(t, *args, **kwargs): - if t < 0.5: - return ease_in(t * 2, *args, **kwargs) / 2 - - return ease_out((t - 0.5) * 2, *args, **kwargs) / 2 + 0.5 - return real_symmetric - -class Symmetric(object): - def __init__(self, ease_in = None, ease_out = None): - self.ease_in = ease_in or inverse(ease_out) - self.ease_out = ease_out or inverse(ease_in) - self.ease_in_out = symmetric(self.ease_in, self.ease_out) - - -class Easing(object): - """Class containing easing classes to use together with the tweener. - All of the classes have :func:`ease_in`, :func:`ease_out` and - :func:`ease_in_out` functions.""" - - Linear = Symmetric(lambda t: t, lambda t: t) - Quad = Symmetric(lambda t: t*t) - Cubic = Symmetric(lambda t: t*t*t) - Quart = Symmetric(lambda t: t*t*t*t) - Quint = Symmetric(lambda t: t*t*t*t*t) - Strong = Quint #oh i wonder why but the ported code is the same as in Quint - - Circ = Symmetric(lambda t: 1 - math.sqrt(1 - t * t)) - Sine = Symmetric(lambda t: 1 - math.cos(t * (math.pi / 2))) - - - def _back_in(t, s=1.70158): - return t * t * ((s + 1) * t - s) - Back = Symmetric(_back_in) - - - def _bounce_out(t): - if t < 1 / 2.75: - return 7.5625 * t * t - elif t < 2 / 2.75: - t = t - 1.5 / 2.75 - return 7.5625 * t * t + 0.75 - elif t < 2.5 / 2.75: - t = t - 2.25 / 2.75 - return 7.5625 * t * t + .9375 - else: - t = t - 2.625 / 2.75 - return 7.5625 * t * t + 0.984375 - Bounce = Symmetric(ease_out = _bounce_out) - - - def _elastic_in(t, springiness = 0, wave_length = 0): - if t in(0, 1): - return t - - wave_length = wave_length or (1 - t) * 0.3 - - if springiness <= 1: - springiness = t - s = wave_length / 4 - else: - s = wave_length / (2 * math.pi) * math.asin(t / springiness) - - t = t - 1 - return -(springiness * math.pow(2, 10 * t) * math.sin((t * t - s) * (2 * math.pi) / wave_length)) - Elastic = Symmetric(_elastic_in) - - - def _expo_in(t): - if t in (0, 1): return t - return math.pow(2, 10 * t) * 0.001 - Expo = Symmetric(_expo_in) - - - -class _Dummy(object): - def __init__(self, a, b, c): - self.a = a - self.b = b - self.c = c - -if __name__ == "__main__": - import datetime as dt - - tweener = Tweener() - objects = [] - - for i in range(10000): - objects.append(_Dummy(dt.datetime.now(), i-100, i-100)) - - - total = dt.datetime.now() - - t = dt.datetime.now() - print "Adding 10000 objects..." - for i, o in enumerate(objects): - tweener.add_tween(o, a = dt.datetime.now() - dt.timedelta(days=3), - b = i, - c = i, - duration = 1.0, - easing=Easing.Circ.ease_in_out) - print dt.datetime.now() - t - - t = dt.datetime.now() - print "Updating 10 times......" - for i in range(11): #update 1000 times - tweener.update(0.1) - print dt.datetime.now() - t |