Skip to main content

animate_core/mode/
once.rs

1use crate::macros::impl_ops;
2use crate::{Animate, AnimateState, FRAME_TIME, IS_ANIMATING, Lerp};
3use std::sync::atomic::Ordering;
4
5#[derive(Debug)]
6pub struct Once<T, E, I>(pub(crate) AnimateState<T, E, I>)
7where
8    T: Lerp + PartialEq,
9    E: Fn(f64) -> f64,
10    I: Fn(&T, &T, f64) -> T;
11
12impl<T, E, I> Once<T, E, I>
13where
14    T: Lerp + PartialEq + Default,
15    E: Fn(f64) -> f64,
16    I: Fn(&T, &T, f64) -> T,
17{
18    pub fn new(initial: T, duration: f64, easing: E, interp: I) -> Self {
19        Self(AnimateState::new(initial, duration, easing, interp))
20    }
21}
22
23impl<T, E, I> Animate for Once<T, E, I>
24where
25    T: Lerp + PartialEq + Default,
26    E: Fn(f64) -> f64,
27    I: Fn(&T, &T, f64) -> T,
28{
29    type Value = T;
30
31    fn update(&mut self) {
32        let inner = &mut self.0.inner;
33
34        if inner.pending {
35            inner.start = std::mem::take(&mut inner.current);
36            inner.pending = false;
37        }
38
39        if let Some(start_t) = inner.started_at {
40            let now = FRAME_TIME.load(Ordering::Relaxed);
41            let elapsed = now.saturating_sub(start_t) as f64;
42            let t = (elapsed / self.0.duration).clamp(0.0, 1.0);
43
44            inner.current = (self.0.interp)(&inner.start, &inner.target, (self.0.easing)(t));
45
46            if t >= 1.0 {
47                inner.started_at = None;
48            } else {
49                IS_ANIMATING.store(true, Ordering::Relaxed);
50            }
51        }
52    }
53
54    fn get(&self) -> &T {
55        &self.0.inner.current
56    }
57
58    fn set(&mut self, target: T) {
59        let now = FRAME_TIME.load(Ordering::Relaxed);
60        let inner = &mut self.0.inner;
61
62        inner.target = target;
63        inner.started_at = Some(now);
64        inner.pending = true;
65    }
66
67    fn target(&self) -> &T {
68        let inner = &self.0.inner;
69        if inner.started_at.is_none() {
70            &inner.current
71        } else {
72            &inner.target
73        }
74    }
75}
76
77impl_ops!(Once);