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}