use super::animation_struct::Animation;
use super::keyframes_easing::EasingKeyframes;
use super::keyframes_linear::LinearKeyframes;
use super::keyframes_repeat::RepeatKeyframes;
use super::keyframes_repeat_n::RepeatNKeyframes;
use super::keyframes_reverse::ReverseKeyframes;
use super::keyframes_scale::ScaleKeyframes;
use super::keyframes_sequential::SequentialKeyframes;
use super::keyframes_stay::StayKeyframes;
use crate::animation::keyframes_apply_easing::ApplyEasingKeyframes;
use crate::animation::keyframes_function::FunctionKeyframes;
use crate::animation::keyframes_map::MapKeyframes;
use crate::animation::keyframes_poly::PolyKeyframes;
use crate::animation::keyframes_slice::SliceKeyframes;
use crate::{Distance, Easing, Mix, Time};
use std::iter::once;
pub trait Keyframes<T, X: Time> {
fn get(&self, offset: X::Duration) -> T;
fn duration(&self) -> X::Duration;
fn is_finished(&self, offset: X::Duration) -> bool {
self.is_finite() && self.duration() <= offset
}
fn is_finite(&self) -> bool;
fn start_value(&self) -> T {
self.get(Default::default())
}
fn end_value(&self) -> T {
self.get(self.duration())
}
fn stay(self, duration: X::Duration) -> SequentialKeyframes<T, X, Self, StayKeyframes<T, X>>
where
T: Clone,
Self: Sized,
{
let end_value = self.end_value();
SequentialKeyframes::new(self, StayKeyframes::new(end_value, duration))
}
fn go_to(
self,
target: T,
duration: X::Duration,
) -> SequentialKeyframes<T, X, Self, LinearKeyframes<T, X>>
where
T: Mix + Clone,
Self: Sized,
{
let end_value = self.end_value();
SequentialKeyframes::new(self, LinearKeyframes::new(end_value, target, duration))
}
fn ease_to(
self,
target: T,
duration: X::Duration,
easing: Easing,
) -> SequentialKeyframes<T, X, Self, EasingKeyframes<T, X>>
where
T: Mix + Clone,
Self: Sized,
{
let end_value = self.end_value();
SequentialKeyframes::new(
self,
EasingKeyframes::new(end_value, target, duration, easing),
)
}
fn poly_to(
self,
points: impl IntoIterator<Item = T>,
duration: X::Duration,
easing: Easing,
) -> SequentialKeyframes<T, X, Self, PolyKeyframes<T, X>>
where
Self: Sized,
T: Mix + Clone + Distance,
{
let points = once(self.end_value()).chain(points).collect();
SequentialKeyframes::new(self, PolyKeyframes::new(points, duration, easing))
}
fn function<F: Fn(X::Duration) -> T>(
self,
function: F,
duration: X::Duration,
) -> SequentialKeyframes<T, X, Self, FunctionKeyframes<T, X, F>>
where
Self: Sized,
{
SequentialKeyframes::new(self, FunctionKeyframes::new(function, duration))
}
fn repeat(self) -> RepeatKeyframes<T, X, Self>
where
Self: Sized,
{
RepeatKeyframes::new(self)
}
fn repeat_n(self, n: f32) -> RepeatNKeyframes<T, X, Self>
where
Self: Sized,
{
RepeatNKeyframes::new(self, n)
}
fn reverse(self) -> ReverseKeyframes<T, X, Self>
where
Self: Sized,
{
ReverseKeyframes::new(self)
}
fn scale(self, scale: f32) -> ScaleKeyframes<T, X, Self>
where
Self: Sized,
{
ScaleKeyframes::new(self, scale)
}
fn scale_to(self, new_duration: X::Duration) -> ScaleKeyframes<T, X, Self>
where
Self: Sized,
{
let scale = if self.duration() == Default::default() {
1.0
} else {
X::duration_as_f32(new_duration) / X::duration_as_f32(self.duration())
};
ScaleKeyframes::new(self, scale)
}
fn apply_easing(self, easing: Easing) -> ApplyEasingKeyframes<T, X, Self>
where
Self: Sized,
{
ApplyEasingKeyframes::new(self, easing)
}
fn then<S: Keyframes<T, X>>(self, other: S) -> SequentialKeyframes<T, X, Self, S>
where
Self: Sized,
{
SequentialKeyframes::new(self, other)
}
fn slice(self, start_offset: X::Duration, end_offset: X::Duration) -> SliceKeyframes<T, X, Self>
where
Self: Sized,
{
SliceKeyframes::new(self, (start_offset, end_offset))
}
fn map<R, F>(self, f: F) -> MapKeyframes<T, R, X, Self, F>
where
F: Fn(T) -> R,
Self: Sized,
{
MapKeyframes::new(self, f)
}
fn run(self, start_time: X) -> Animation<T, X, Self>
where
Self: Sized,
{
Animation::start(self, start_time)
}
}
fn max<X: PartialOrd>(v1: X, v2: X) -> X {
if v1 > v2 {
v1
} else {
v2
}
}
impl<X, T, K> Keyframes<(T,), X> for (K,)
where
X: Time,
K: Keyframes<T, X>,
{
fn get(&self, offset: X::Duration) -> (T,) {
(self.0.get(offset),)
}
fn duration(&self) -> X::Duration {
self.0.duration()
}
fn is_finite(&self) -> bool {
self.0.is_finite()
}
}
impl<X, T1, T2, K1, K2> Keyframes<(T1, T2), X> for (K1, K2)
where
X: Time,
K1: Keyframes<T1, X>,
K2: Keyframes<T2, X>,
{
fn get(&self, offset: X::Duration) -> (T1, T2) {
(self.0.get(offset), self.1.get(offset))
}
fn duration(&self) -> X::Duration {
max(self.0.duration(), self.1.duration())
}
fn is_finite(&self) -> bool {
self.0.is_finite() && self.1.is_finite()
}
}
impl<X, T1, T2, T3, K1, K2, K3> Keyframes<(T1, T2, T3), X> for (K1, K2, K3)
where
X: Time,
K1: Keyframes<T1, X>,
K2: Keyframes<T2, X>,
K3: Keyframes<T3, X>,
{
fn get(&self, offset: X::Duration) -> (T1, T2, T3) {
(self.0.get(offset), self.1.get(offset), self.2.get(offset))
}
fn duration(&self) -> X::Duration {
let d0 = self.0.duration();
let d1 = self.1.duration();
let d2 = self.2.duration();
max(d0, max(d1, d2))
}
fn is_finite(&self) -> bool {
self.0.is_finite() && self.1.is_finite() && self.2.is_finite()
}
}
impl<X, T1, T2, T3, T4, K1, K2, K3, K4> Keyframes<(T1, T2, T3, T4), X> for (K1, K2, K3, K4)
where
X: Time,
K1: Keyframes<T1, X>,
K2: Keyframes<T2, X>,
K3: Keyframes<T3, X>,
K4: Keyframes<T4, X>,
{
fn get(&self, offset: X::Duration) -> (T1, T2, T3, T4) {
(
self.0.get(offset),
self.1.get(offset),
self.2.get(offset),
self.3.get(offset),
)
}
fn duration(&self) -> X::Duration {
let d0 = self.0.duration();
let d1 = self.1.duration();
let d2 = self.2.duration();
let d3 = self.3.duration();
max(max(d0, d1), max(d2, d3))
}
fn is_finite(&self) -> bool {
self.0.is_finite() && self.1.is_finite() && self.2.is_finite() && self.3.is_finite()
}
}
pub mod keyframes {
use super::Keyframes;
use crate::animation::keyframes_easing::EasingKeyframes;
use crate::animation::keyframes_function::FunctionKeyframes;
use crate::animation::keyframes_linear::LinearKeyframes;
use crate::animation::keyframes_poly::PolyKeyframes;
use crate::animation::keyframes_stay::StayKeyframes;
use crate::{Distance, Easing, Mix, Time};
pub fn from<T: Clone, X: Time>(point: T) -> impl Keyframes<T, X> {
stay(point, Default::default())
}
pub fn stay<T: Clone, X: Time>(value: T, duration: X::Duration) -> impl Keyframes<T, X> {
StayKeyframes::new(value, duration)
}
pub fn line<T: Mix + Clone, X: Time>(
start: T,
end: T,
duration: X::Duration,
) -> impl Keyframes<T, X> {
LinearKeyframes::new(start, end, duration)
}
pub fn ease<T: Mix + Clone, X: Time>(
start: T,
end: T,
duration: X::Duration,
easing: Easing,
) -> impl Keyframes<T, X> {
EasingKeyframes::new(start, end, duration, easing)
}
pub fn poly<T: Mix + Distance + Clone, X: Time>(
points: Vec<T>,
duration: X::Duration,
easing: Easing,
) -> impl Keyframes<T, X> {
PolyKeyframes::new(points, duration, easing)
}
pub fn function<T, X, F>(f: F, duration: X::Duration) -> impl Keyframes<T, X>
where
X: Time,
F: Fn(X::Duration) -> T,
{
FunctionKeyframes::new(f, duration)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::easing::Easing;
use crate::mix::Mix;
use std::time::{Duration, Instant};
#[derive(Clone, Copy, Debug, PartialEq)]
struct TestItem(f32);
impl Mix for TestItem {
fn mix(self, other: Self, t: f32) -> Self {
TestItem(self.0.mix(other.0, t))
}
}
const ZERO_DURATION: Duration = Duration::from_secs(0);
const ONE_SECOND: Duration = Duration::from_secs(1);
const HALF_SECOND: Duration = Duration::from_millis(500);
const ONE_AND_HALF_SECONDS: Duration = Duration::from_millis(1500);
const TWO_SECONDS: Duration = Duration::from_secs(2);
#[test]
fn none_keyframes() {
let keyframes: StayKeyframes<TestItem, Instant> =
StayKeyframes::new(TestItem(0.0), Duration::from_secs(1));
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.0));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(0.0));
}
#[test]
fn linear_keyframes() {
let keyframes =
LinearKeyframes::<TestItem, Instant>::new(TestItem(0.0), TestItem(1.0), ONE_SECOND);
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.5));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(1.0));
}
#[test]
fn sequential_keyframes() {
let keyframes = SequentialKeyframes::new(
LinearKeyframes::<TestItem, Instant>::new(TestItem(0.0), TestItem(1.0), ONE_SECOND),
LinearKeyframes::new(TestItem(1.0), TestItem(0.0), ONE_SECOND),
);
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.5));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(1.0));
assert_eq!(keyframes.get(ONE_AND_HALF_SECONDS), TestItem(0.5));
assert_eq!(keyframes.get(TWO_SECONDS), TestItem(0.0));
}
#[test]
fn easing_keyframes() {
let keyframes = EasingKeyframes::<TestItem, Instant>::new(
TestItem(0.0),
TestItem(1.0),
ONE_SECOND,
Easing::QuadraticIn,
);
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.25));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(1.0));
}
#[test]
fn reversed_keyframes() {
let keyframes = keyframes::from::<TestItem, Instant>(TestItem(0.0))
.go_to(TestItem(1.0), ONE_SECOND)
.reverse();
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(1.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.5));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(0.0));
}
#[test]
fn map_keyframes() {
let keyframes = keyframes::from::<f32, Instant>(0.0)
.go_to(1.0, ONE_SECOND)
.map(TestItem);
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.5));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(1.0));
}
#[test]
fn scale_keyframes() {
let keyframes = keyframes::from::<f32, Instant>(0.0)
.go_to(1.0, ONE_SECOND)
.scale(2.0);
assert_eq!(keyframes.get(ZERO_DURATION), 0.0);
assert_eq!(keyframes.get(HALF_SECOND), 0.25);
assert_eq!(keyframes.get(ONE_SECOND), 0.5);
assert_eq!(keyframes.get(ONE_SECOND * 2), 1.0);
}
}