Skip to main content

dioxus_motion/
manager.rs

1use crate::Duration;
2use crate::animations::core::Animatable;
3use crate::keyframes::KeyframeAnimation;
4use crate::motion::Motion;
5use crate::prelude::AnimationConfig;
6use crate::sequence::AnimationSequence;
7
8use dioxus::{
9    prelude::{ReadStore, Store, use_store},
10    signals::ReadableExt,
11};
12
13const CURRENT_SCOPE: u16 = 0;
14const RUNNING_SCOPE: u16 = 1;
15
16fn current_ref<T: Animatable + Send + 'static>(motion: &Motion<T>) -> &T {
17    &motion.current
18}
19
20fn current_mut<T: Animatable + Send + 'static>(motion: &mut Motion<T>) -> &mut T {
21    &mut motion.current
22}
23
24fn running_ref<T: Animatable + Send + 'static>(motion: &Motion<T>) -> &bool {
25    &motion.running
26}
27
28fn running_mut<T: Animatable + Send + 'static>(motion: &mut Motion<T>) -> &mut bool {
29    &mut motion.running
30}
31
32#[derive(Clone, Copy)]
33pub struct MotionHandle<T: Animatable + Send + 'static> {
34    state: Store<Motion<T>>,
35}
36
37impl<T: Animatable + Send + 'static> MotionHandle<T> {
38    pub(crate) fn new_hook(initial: T) -> Self {
39        Self {
40            state: use_store(|| Motion::new(initial)),
41        }
42    }
43
44    fn new_detached(initial: T) -> Self {
45        Self {
46            state: Store::new(Motion::new(initial)),
47        }
48    }
49
50    pub fn current(self) -> ReadStore<T> {
51        let scope =
52            self.state
53                .into_selector()
54                .child(CURRENT_SCOPE, current_ref::<T>, current_mut::<T>);
55        let store: Store<T, _> = scope.into();
56        store.into()
57    }
58
59    pub fn running(self) -> ReadStore<bool> {
60        let scope =
61            self.state
62                .into_selector()
63                .child(RUNNING_SCOPE, running_ref::<T>, running_mut::<T>);
64        let store: Store<bool, _> = scope.into();
65        store.into()
66    }
67
68    pub(crate) fn epsilon(&self) -> f32 {
69        self.state.peek().get_epsilon()
70    }
71
72    fn write_motion<R>(&mut self, f: impl FnOnce(&mut Motion<T>) -> R) -> R {
73        let selector = self.state.into_selector();
74        let mut motion = selector.write_untracked();
75        let previous_current = motion.current;
76        let previous_running = motion.running;
77
78        let result = f(&mut motion);
79        let next_current = motion.current;
80        let next_running = motion.running;
81        drop(motion);
82        let epsilon = self.epsilon();
83
84        if (next_current - previous_current).magnitude() > epsilon {
85            selector.child_unmapped(CURRENT_SCOPE).mark_dirty();
86        }
87
88        if next_running != previous_running {
89            selector.child_unmapped(RUNNING_SCOPE).mark_dirty();
90        }
91
92        result
93    }
94}
95
96pub trait AnimationManager<T: Animatable + Send + 'static>: Clone + Copy {
97    fn new(initial: T) -> Self;
98    fn animate_to(&mut self, target: T, config: AnimationConfig);
99    fn animate_sequence(&mut self, sequence: AnimationSequence<T>);
100    fn animate_keyframes(&mut self, animation: KeyframeAnimation<T>);
101    fn update(&mut self, dt: f32) -> bool;
102    fn get_value(&self) -> T;
103    fn is_running(&self) -> bool;
104    fn reset(&mut self);
105    fn stop(&mut self);
106    fn delay(&mut self, duration: Duration);
107}
108
109impl<T: Animatable + Send + 'static> AnimationManager<T> for MotionHandle<T> {
110    fn new(initial: T) -> Self {
111        Self::new_detached(initial)
112    }
113
114    fn animate_to(&mut self, target: T, config: AnimationConfig) {
115        self.write_motion(|motion| motion.animate_to(target, config));
116    }
117
118    fn animate_sequence(&mut self, sequence: AnimationSequence<T>) {
119        self.write_motion(|motion| motion.animate_sequence(sequence));
120    }
121
122    fn animate_keyframes(&mut self, animation: KeyframeAnimation<T>) {
123        self.write_motion(|motion| motion.animate_keyframes(animation));
124    }
125
126    fn update(&mut self, dt: f32) -> bool {
127        self.write_motion(|motion| motion.update(dt))
128    }
129
130    fn get_value(&self) -> T {
131        self.current().cloned()
132    }
133
134    fn is_running(&self) -> bool {
135        self.running().cloned()
136    }
137
138    fn reset(&mut self) {
139        self.write_motion(Motion::reset);
140    }
141
142    #[track_caller]
143    fn stop(&mut self) {
144        self.write_motion(Motion::stop);
145    }
146
147    fn delay(&mut self, duration: Duration) {
148        self.write_motion(|motion| motion.delay(duration));
149    }
150}