diff --git a/animation.go b/animation.go new file mode 100644 index 0000000..41f5b0d --- /dev/null +++ b/animation.go @@ -0,0 +1,78 @@ +package zntg + +import "time" + +// Animation is a struct that keeps track of time for animation. +type Animation struct { + // The interval of the animation + Interval time.Duration + + active bool + start time.Time + lastUpdate time.Duration +} + +// NewAnimation creates an Animation given the specified interval. The animation is immediately started. +func NewAnimation(interval time.Duration) Animation { + return Animation{ + Interval: interval, + + active: true, + start: time.Now(), + } +} + +// NewAnimationPtr creates an Animation given the specified interval and returns a pointer to it. The animation is immediately started. +func NewAnimationPtr(interval time.Duration) *Animation { + ani := NewAnimation(interval) + return &ani +} + +// Animate checks if enough time as elapsed to animate a single interval and advances the single interval. +func (a *Animation) Animate() bool { + since := time.Since(a.start) + if !a.active || since < a.lastUpdate+a.Interval { + return false + } + a.lastUpdate += a.Interval + return true +} + +// AnimateDelta checks how many natural intervals have elapsed and advances that many intervals. Returns the total of time that has been advanced and the number of intervals. +func (a *Animation) AnimateDelta() (time.Duration, int) { + if !a.active { + return 0, 0 + } + since := time.Since(a.start) + n := (since - a.lastUpdate) / a.Interval + delta := n * a.Interval + a.lastUpdate += delta + return delta, int(n) +} + +// AnimateFn calls fn for every interval and advances that interval for every interval that has elapsed until it caught up again. +func (a *Animation) AnimateFn(fn func()) { + if !a.active { + return + } + since := time.Since(a.start) + for a.active && since > a.lastUpdate+a.Interval { + fn() + a.lastUpdate += a.Interval + } +} + +// Pause pauses the animation causing the Animate{,Delta,Fn} methods to do nothing. +func (a *Animation) Pause() { + a.active = false +} + +// Start starts the animation (when paused or not started yet). +func (a *Animation) Start() { + if a.active { + return + } + a.active = true + a.start = time.Now() + a.lastUpdate = 0 +}