Source code for domonic.lerpy.tween
from domonic.events import EventDispatcher, TweenEvent
from domonic.javascript import window
from domonic.lerpy import get_timer
from domonic.lerpy.easing import *
class TweenEquation:
def __init__(self, ease, extra=None):
self.ease = ease
self.extra = extra
class TweenData:
def __init__(self, prop, target, equation=None):
self.prop = prop
self.target = target
self.equation = equation
self.start = 0
self.change = 0
[docs]class Tween(EventDispatcher):
"""
Tween is a complex lerp but you don't have do the math cos robert penner did already.
Just pass an easing equation from the easing package
i.e
twn = Tween(someObj, { 'x':10, 'y':5, 'z':3}, 6, Linear.easeIn )
will tween the objects properties over the given time using Linear.easeIn
"""
FPS = 60
_tweening = False
_paused = False
_target = None
_values = None
_equations = None
_duration = 0
_delay = 0
_position = 0
_loop = False
_timeStart = 0
_timePaused = 0
_timePrevious = 0
def __init__(self, target=None, values=None, duration=0, equations=None, delay=0, loop=False):
self.target = target
self.values = values
self.duration = duration
self.equations = equations
self.delay = delay
self.loop = loop
self._intID = None
super().__init__()
@property
def tweening(self):
return self._foo
@property
def paused(self):
return self._paused
@property
def position(self):
if self._position < 0:
return 0
elif self._position > 100:
return 100
else:
return self._position
@property
def target(self):
return self._target
@target.setter
def target(self, target):
self._target = target
@property
def values(self):
v = {}
for value in self._values:
v[value.prop] = value.target
return v
@values.setter
def values(self, values):
if values != None:
self._values = []
for s in values:
self._values.append(TweenData(s, values[s]))
self.equations = self._equations
@property
def duration(self):
return self._duration # /1000
@duration.setter
def duration(self, duration):
self._duration = duration # * 1000
@property
def equations(self):
return self._equations
@equations.setter
def equations(self, equations):
if equations != None:
self._equations = equations
e = equations if type(equations) == list else [equations]
i = 0
for v in self._values:
i = len(e) - 1 if i > len(e) - 1 else i
if callable(e[i]):
p = TweenEquation(e[i])
else:
p = TweenEquation(e[i].fn, {"a": e[i].a, "b": e[i].b})
v.equation = p
i += 1
@property
def delay(self):
return self._delay # / 1000
@delay.setter
def delay(self, delay):
self._delay = delay # * 1000
@property
def loop(self):
return self._loop
@loop.setter
def loop(self, loop):
"""Set to True if you want it to loop"""
self._loop = loop
def start(self):
self._timeStart = get_timer() # TODO!! ---
self._timePaused = 0
self._timePrevious = self._timeStart
self._position = 0
for v in self._values:
v.start = self._target[v.prop]
v.change = v.target - v.start
self._tweening = True
self._paused = False
self._intID = window.setInterval(self._update, 1000 / Tween.FPS, TweenEvent(TweenEvent.TIMER))
self.dispatchEvent(TweenEvent(TweenEvent.START, self))
def stop(self):
self._tweening = False
self.dispatchEvent(TweenEvent(TweenEvent.STOP, self))
# NOTE
# window.clearInterval(self._intID )
# clearInt fails. because join won't allow as a 'return' happens just after the stop
self._intID.stopped.set() # call stopped on the thread so program exits
[docs] def pause(self):
"""Pauses the tween from changing the values"""
# TODO - pause should modify timer so it DOESNT jump frames. at mo does the opposite.
# seems to not increment. then suddenly jumps to catch up with where it should be
self._paused = True
self.dispatchEvent(TweenEvent(TweenEvent.PAUSE if self._paused else TweenEvent.UNPAUSE, self))
[docs] def unpause(self):
"""unpauses the tween"""
self._paused = False
self.dispatchEvent(TweenEvent(TweenEvent.UNPAUSE, self))
def reset(self):
for v in self._values:
self._target[v.prop] = v.start
self._update(get_timer())
self.dispatchEvent(TweenEvent(TweenEvent.RESET, self))
def _update(self, event):
timeCurrent = get_timer()
if self._tweening:
if not self._paused:
self.dispatchEvent(TweenEvent(TweenEvent.UPDATE_START, self))
time = timeCurrent - self._timePaused - self._timeStart
self._position = 100 / (self._duration + self._delay) * time
if time < self._delay:
return
time -= self._delay
if time > self._duration:
for v in self._values:
self._target[v.prop] = v.target
if self._loop:
self._timeStart = timeCurrent
self._timePaused = 0
self._timePrevious = self._timeStart
self._position = 0
self.reset()
else:
self.dispatchEvent(TweenEvent(TweenEvent.UPDATE_END, self))
self.stop()
self.dispatchEvent(TweenEvent(TweenEvent.COMPLETE, self))
return
for v in self._values:
e = v.equation
x = e.extra
a = x.a if x != None else 0
b = x.b if x != None else 0
self._target[v.prop] = e.ease(time, v.start, v.change, self._duration, a, b)
self.dispatchEvent(TweenEvent(TweenEvent.UPDATE_END, self))
else:
self._timePaused += timeCurrent - self._timePrevious
self._timePrevious = timeCurrent
# def _dispatchEvent(self, event):
# if event.type == TweenEvent.UPDATE_START:
# self._timeStart = get_timer()
# self._timePaused = 0
# self._timePrevious = self._timeStart
# self._position = 0
# self.dispatchEvent(event)
# elif event.type == TweenEvent.UPDATE_END:
# self.dispatchEvent(event)
# elif event.type == TweenEvent.START:
# self.dispatchEvent(event)
# elif event.type == TweenEvent.STOP:
# self.dispatchEvent(event)
# elif event.type == TweenEvent.PAUSE:
# self.dispatchEvent(event)
# elif event.type == TweenEvent.UNPAUSE:
# self.dispatchEvent(event)
# elif event.type == TweenEvent.RESET:
# self.dispatchEvent(event)
# elif event.type == TweenEvent.COMPLETE:
# self.dispatchEvent(event)
# elif event.type == TweenEvent.UPDATE:
# self.dispatchEvent(event)
# else:
# super(Tween, self)._dispatchEvent(event)