animato_timeline/
group.rs1use crate::{At, Sequence, Timeline};
4use alloc::format;
5use alloc::vec::Vec;
6use animato_core::{
7 AnimationIntrospection, AnimationKind, Inspectable, Playable, PlaybackState, Update,
8};
9use animato_tween::StaggerPattern;
10use core::fmt;
11
12pub struct AnimationGroup {
14 inner: Timeline,
15}
16
17impl fmt::Debug for AnimationGroup {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 f.debug_struct("AnimationGroup")
20 .field("inner", &self.inner)
21 .finish()
22 }
23}
24
25impl AnimationGroup {
26 pub fn from_timeline(timeline: Timeline) -> Self {
28 Self { inner: timeline }
29 }
30
31 pub fn parallel<A>(animations: Vec<A>) -> Self
33 where
34 A: Playable + Send + 'static,
35 {
36 let mut timeline = Timeline::new();
37 for (index, animation) in animations.into_iter().enumerate() {
38 timeline = timeline.add(format!("item_{index}"), animation, At::Start);
39 }
40 Self::from_timeline(timeline)
41 }
42
43 pub fn sequence<A>(animations: Vec<A>) -> Self
45 where
46 A: Playable + Send + 'static,
47 {
48 let mut sequence = Sequence::new();
49 for (index, animation) in animations.into_iter().enumerate() {
50 sequence = sequence.then(format!("item_{index}"), animation);
51 }
52 Self::from_timeline(sequence.build())
53 }
54
55 pub fn stagger<A>(animations: Vec<A>, pattern: StaggerPattern) -> Self
57 where
58 A: Playable + Send + 'static,
59 {
60 let total = animations.len();
61 let mut timeline = Timeline::new();
62 for (index, animation) in animations.into_iter().enumerate() {
63 timeline = timeline.add(
64 format!("item_{index}"),
65 animation,
66 At::Absolute(pattern.delay(index, total)),
67 );
68 }
69 Self::from_timeline(timeline)
70 }
71
72 pub fn timeline(&self) -> &Timeline {
74 &self.inner
75 }
76
77 pub fn timeline_mut(&mut self) -> &mut Timeline {
79 &mut self.inner
80 }
81
82 pub fn play(&mut self) {
84 self.inner.play();
85 }
86
87 pub fn pause(&mut self) {
89 self.inner.pause();
90 }
91
92 pub fn resume(&mut self) {
94 self.inner.resume();
95 }
96
97 pub fn reset(&mut self) {
99 self.inner.reset();
100 }
101
102 pub fn seek(&mut self, progress: f32) {
104 self.inner.seek(progress);
105 }
106
107 pub fn reverse(&mut self) {
109 let progress = self.inner.progress();
110 self.inner.seek(1.0 - progress);
111 }
112
113 pub fn set_time_scale(&mut self, scale: f32) {
115 self.inner.set_time_scale(scale);
116 }
117
118 pub fn duration(&self) -> f32 {
120 self.inner.duration()
121 }
122
123 pub fn progress(&self) -> f32 {
125 self.inner.progress()
126 }
127
128 pub fn is_complete(&self) -> bool {
130 self.inner.is_complete()
131 }
132
133 #[cfg(feature = "std")]
135 pub fn on_complete(mut self, f: impl FnMut() + Send + 'static) -> Self {
136 self.inner = self.inner.on_complete(f);
137 self
138 }
139}
140
141impl Update for AnimationGroup {
142 fn update(&mut self, dt: f32) -> bool {
143 self.inner.update(dt)
144 }
145}
146
147impl Playable for AnimationGroup {
148 fn duration(&self) -> f32 {
149 self.inner.duration()
150 }
151
152 fn reset(&mut self) {
153 AnimationGroup::reset(self);
154 }
155
156 fn seek_to(&mut self, progress: f32) {
157 self.seek(progress);
158 }
159
160 fn is_complete(&self) -> bool {
161 AnimationGroup::is_complete(self)
162 }
163
164 fn as_any(&self) -> &dyn core::any::Any {
165 self
166 }
167
168 fn as_any_mut(&mut self) -> &mut dyn core::any::Any {
169 self
170 }
171}
172
173impl Inspectable for AnimationGroup {
174 fn introspect(&self) -> AnimationIntrospection {
175 AnimationIntrospection::new(
176 AnimationKind::Group,
177 self.progress(),
178 self.inner.elapsed(),
179 Some(self.duration()),
180 match self.inner.state() {
181 crate::TimelineState::Idle => PlaybackState::Idle,
182 crate::TimelineState::Playing => PlaybackState::Playing,
183 crate::TimelineState::Paused => PlaybackState::Paused,
184 crate::TimelineState::Completed => PlaybackState::Complete,
185 },
186 None,
187 )
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194 use animato_tween::Tween;
195
196 #[test]
197 fn parallel_completes_when_last_child_finishes() {
198 let mut group = AnimationGroup::parallel(alloc::vec![
199 Tween::new(0.0_f32, 1.0).duration(0.5).build(),
200 Tween::new(0.0_f32, 1.0).duration(1.0).build(),
201 ]);
202 group.play();
203 assert!(group.update(0.75));
204 assert!(!group.update(0.25));
205 }
206
207 #[test]
208 fn sequence_orders_children() {
209 let mut group = AnimationGroup::sequence(alloc::vec![
210 Tween::new(0.0_f32, 10.0).duration(1.0).build(),
211 Tween::new(0.0_f32, 20.0).duration(1.0).build(),
212 ]);
213 group.play();
214 group.update(1.5);
215 assert_eq!(
216 group
217 .timeline()
218 .get::<Tween<f32>>("item_0")
219 .expect("first")
220 .value(),
221 10.0
222 );
223 assert_eq!(
224 group
225 .timeline()
226 .get::<Tween<f32>>("item_1")
227 .expect("second")
228 .value(),
229 10.0
230 );
231 }
232}