use std::time::Duration;
use crate::clock::{AnimClock, ClockState};
use crate::direction::PlaybackDirection;
use crate::ease::Ease;
use crate::interpolate::Interpolate;
use crate::repeat::{RepeatCount, RepeatStrategy};
#[derive(Debug, Clone, PartialEq)]
pub struct Tween<T: Interpolate> {
from: T,
to: T,
ease: Ease,
clock: AnimClock,
}
impl<T: Interpolate> Tween<T> {
#[inline]
pub fn set(value: T) -> Self {
Self {
from: value.clone(),
to: value,
ease: Ease::Linear,
clock: AnimClock::new(Duration::ZERO),
}
}
#[inline]
pub fn from_to(from: T, to: T, duration: Duration) -> Self {
Self {
from,
to,
ease: Ease::default(),
clock: AnimClock::new(duration),
}
}
#[inline]
pub fn ease(mut self, ease: Ease) -> Self {
self.ease = ease;
self
}
#[inline]
pub fn repeat(mut self, repeat_count: impl Into<RepeatCount>) -> Self {
self.clock = self.clock.with_repeat_count(repeat_count);
self
}
#[inline]
pub fn repeat_strategy(mut self, repeat_strategy: RepeatStrategy) -> Self {
self.clock = self.clock.with_repeat_strategy(repeat_strategy);
self
}
#[inline]
pub fn yoyo(mut self, yoyo: bool) -> Self {
if yoyo {
self.clock = self.clock.with_repeat_strategy(RepeatStrategy::MirroredRepeat);
} else {
self.clock = self.clock.with_repeat_strategy(RepeatStrategy::Repeat);
}
self
}
#[inline]
pub fn direction(mut self, direction: PlaybackDirection) -> Self {
self.clock = self.clock.with_direction(direction);
self
}
#[inline]
pub fn from_value(&self) -> &T {
&self.from
}
#[inline]
pub fn to_value(&self) -> &T {
&self.to
}
#[inline]
pub fn easing(&self) -> Ease {
self.ease
}
#[inline]
pub fn clock(&self) -> &AnimClock {
&self.clock
}
#[inline]
pub fn clock_mut(&mut self) -> &mut AnimClock {
&mut self.clock
}
#[inline]
pub fn is_completed(&self) -> bool {
self.clock.is_completed()
}
#[inline]
pub fn progress(&self) -> f32 {
self.clock.cycle_fraction()
}
#[inline]
pub fn eased_progress(&self) -> f32 {
self.ease.sample(self.clock.mirrored_cycle_fraction())
}
#[inline]
pub fn value(&self) -> T {
let eased_ratio = self.eased_progress();
self.from.interpolate(&self.to, eased_ratio)
}
pub fn sample_at(&self, time: Duration) -> T {
let mut temp_clock = self.clock.clone();
temp_clock.seek(time);
let eased_ratio = self.ease.sample(temp_clock.mirrored_cycle_fraction());
self.from.interpolate(&self.to, eased_ratio)
}
pub fn step(&mut self, delta: Duration) -> (T, ClockState) {
let state = self.clock.tick(delta);
(self.value(), state)
}
pub fn seek(&mut self, time: Duration) -> T {
self.clock.seek(time);
self.value()
}
#[inline]
pub fn reverse(&mut self) {
self.clock.reverse();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tween_set_immediate() {
let mut tween = Tween::set(42.0f32);
assert!(tween.is_completed());
assert_eq!(tween.value(), 42.0);
let (val, state) = tween.step(Duration::from_secs(1));
assert_eq!(val, 42.0);
assert_eq!(state, ClockState::Completed);
}
#[test]
fn test_tween_from_to_linear() {
let mut tween = Tween::from_to(0.0f32, 100.0f32, Duration::from_secs(4))
.ease(Ease::Linear);
assert_eq!(tween.value(), 0.0);
assert!(!tween.is_completed());
let (v25, state) = tween.step(Duration::from_secs(1));
assert_eq!(state, ClockState::Active);
assert_eq!(v25, 25.0);
let (v50, state) = tween.step(Duration::from_secs(1));
assert_eq!(state, ClockState::Active);
assert_eq!(v50, 50.0);
let (v75, state) = tween.step(Duration::from_secs(1));
assert_eq!(state, ClockState::Active);
assert_eq!(v75, 75.0);
let (v100, state) = tween.step(Duration::from_secs(1));
assert_eq!(state, ClockState::Completed);
assert_eq!(v100, 100.0);
assert!(tween.is_completed());
}
#[test]
fn test_tween_sample_at() {
let tween = Tween::from_to(10.0f64, 50.0f64, Duration::from_secs(2))
.ease(Ease::Linear);
assert_eq!(tween.sample_at(Duration::ZERO), 10.0);
assert_eq!(tween.sample_at(Duration::from_secs(1)), 30.0);
assert_eq!(tween.sample_at(Duration::from_secs(2)), 50.0);
assert_eq!(tween.value(), 10.0);
}
#[test]
fn test_tween_yoyo() {
let mut tween = Tween::from_to(0.0f32, 10.0f32, Duration::from_secs(1))
.ease(Ease::Linear)
.repeat(2)
.yoyo(true);
assert_eq!(tween.value(), 0.0);
let (v, _) = tween.step(Duration::from_millis(500));
assert_eq!(v, 5.0);
let (v, _) = tween.step(Duration::from_millis(500));
assert_eq!(v, 10.0);
let (v, _) = tween.step(Duration::from_millis(500));
assert_eq!(v, 5.0);
let (v, state) = tween.step(Duration::from_millis(500));
assert_eq!(v, 0.0);
assert_eq!(state, ClockState::Completed);
assert!(tween.is_completed());
}
#[test]
fn test_tween_seek_and_reverse() {
let mut tween = Tween::from_to([0.0f32, 0.0f32], [100.0f32, 200.0f32], Duration::from_secs(4))
.ease(Ease::Linear);
let v = tween.seek(Duration::from_secs(2));
assert_eq!(v, [50.0, 100.0]);
tween.reverse();
let (v, state) = tween.step(Duration::from_secs(1));
assert_eq!(state, ClockState::Active);
assert_eq!(v, [25.0, 50.0]);
}
}