animate_core/mode/
alternate.rs1use crate::macros::impl_ops;
2use crate::{Animate, AnimateState, FRAME_TIME, IS_ANIMATING, Lerp};
3use std::sync::atomic::Ordering;
4
5#[derive(Debug)]
6pub struct Alternate<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> Alternate<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 Alternate<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 if self.0.duration > 0.0 {
41 let now = FRAME_TIME.load(Ordering::Relaxed);
42 let elapsed = now.saturating_sub(start_t) as f64;
43 let cycle = (elapsed / self.0.duration) as u64;
44 let t_raw = (elapsed % self.0.duration) / self.0.duration;
45 let t = if cycle % 2 == 0 { t_raw } else { 1.0 - t_raw };
46
47 inner.current = (self.0.interp)(&inner.start, &inner.target, (self.0.easing)(t));
48 }
49 IS_ANIMATING.store(true, Ordering::Relaxed);
50 }
51 }
52
53 fn get(&self) -> &T {
54 &self.0.inner.current
55 }
56
57 fn set(&mut self, target: T) {
58 let now = FRAME_TIME.load(Ordering::Relaxed);
59 let inner = &mut self.0.inner;
60
61 inner.target = target;
62 inner.started_at = Some(now);
63 inner.pending = true;
64 }
65
66 fn target(&self) -> &T {
67 &self.0.inner.target
68 }
69}
70
71impl_ops!(Alternate);