1use crate::{
2 Composition, Duration, Easing, FillMode, Interpolate, Keyframe, Keyframes, MotionValue,
3 PlaybackState, Spring, SpringConfig, Time, Timeline, Timing, TimingError,
4};
5use std::{
6 fmt,
7 sync::{Arc, Mutex, MutexGuard, PoisonError},
8};
9
10#[derive(Clone, Debug, PartialEq)]
11pub struct Tween {
12 pub duration: Duration,
13 pub delay: Duration,
14 pub easing: Easing,
15}
16
17impl Tween {
18 #[must_use]
19 pub const fn new(duration: Duration) -> Self {
20 Self {
21 duration,
22 delay: Duration::ZERO,
23 easing: Easing::Linear,
24 }
25 }
26
27 #[must_use]
28 pub const fn delay(mut self, delay: Duration) -> Self {
29 self.delay = delay;
30 self
31 }
32
33 #[must_use]
34 pub fn easing(mut self, easing: Easing) -> Self {
35 self.easing = easing;
36 self
37 }
38}
39
40#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
41pub enum MotionState {
42 #[default]
43 Idle,
44 Running,
45 Paused,
46 Finished,
47 Canceled,
48}
49
50#[derive(Clone)]
51pub struct Motion<T>(Arc<Mutex<MotionInner<T>>>);
52
53#[derive(Clone, Debug, PartialEq)]
54pub struct MotionBinding<T> {
55 pub motion: Motion<T>,
56 pub composition: Composition,
57 pub priority: i32,
58}
59
60impl<T> MotionBinding<T> {
61 #[must_use]
62 pub fn new(motion: Motion<T>) -> Self {
63 Self {
64 motion,
65 composition: Composition::Replace,
66 priority: 0,
67 }
68 }
69
70 #[must_use]
71 pub const fn composition(mut self, composition: Composition) -> Self {
72 self.composition = composition;
73 self
74 }
75
76 #[must_use]
77 pub const fn priority(mut self, priority: i32) -> Self {
78 self.priority = priority;
79 self
80 }
81}
82
83impl<T> From<Motion<T>> for MotionBinding<T> {
84 fn from(motion: Motion<T>) -> Self {
85 Self::new(motion)
86 }
87}
88
89struct MotionInner<T> {
90 value: T,
91 target: T,
92 driver: Driver<T>,
93 state: MotionState,
94 last_frame: Option<Time>,
95 resume_pending: bool,
96 completed_iterations: u64,
97}
98
99enum Driver<T> {
100 None,
101 PendingTween { from: T, tween: Tween },
102 Timeline(Timeline<T>),
103 Spring(Spring<T>),
104}
105
106impl<T: fmt::Debug> fmt::Debug for Motion<T> {
107 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
108 let inner = self.lock();
109 formatter
110 .debug_struct("Motion")
111 .field("value", &inner.value)
112 .field("target", &inner.target)
113 .field("state", &inner.state)
114 .finish_non_exhaustive()
115 }
116}
117
118impl<T> PartialEq for Motion<T> {
119 fn eq(&self, other: &Self) -> bool {
120 Arc::ptr_eq(&self.0, &other.0)
121 }
122}
123
124impl<T> Motion<T> {
125 fn lock(&self) -> MutexGuard<'_, MotionInner<T>> {
126 self.0.lock().unwrap_or_else(PoisonError::into_inner)
127 }
128
129 #[must_use]
130 pub fn new(value: T) -> Self
131 where
132 T: Clone,
133 {
134 Self(Arc::new(Mutex::new(MotionInner {
135 value: value.clone(),
136 target: value,
137 driver: Driver::None,
138 state: MotionState::Idle,
139 last_frame: None,
140 resume_pending: false,
141 completed_iterations: 0,
142 })))
143 }
144
145 #[must_use]
146 pub fn value(&self) -> T
147 where
148 T: Clone,
149 {
150 self.lock().value.clone()
151 }
152
153 #[must_use]
154 pub fn target(&self) -> T
155 where
156 T: Clone,
157 {
158 self.lock().target.clone()
159 }
160
161 #[must_use]
162 pub fn state(&self) -> MotionState {
163 self.lock().state
164 }
165
166 #[must_use]
167 pub fn is_active(&self) -> bool {
168 self.state() == MotionState::Running
169 }
170
171 #[must_use]
172 pub fn completed_iterations(&self) -> u64 {
173 self.lock().completed_iterations
174 }
175
176 #[must_use]
177 pub fn identity(&self) -> usize {
178 Arc::as_ptr(&self.0).cast::<()>() as usize
179 }
180
181 pub fn set(&self, value: T)
182 where
183 T: Clone,
184 {
185 let mut inner = self.lock();
186 inner.value = value.clone();
187 inner.target = value;
188 inner.driver = Driver::None;
189 inner.state = MotionState::Idle;
190 inner.last_frame = None;
191 inner.completed_iterations = 0;
192 }
193
194 pub fn cancel(&self) {
195 let mut inner = self.lock();
196 inner.driver = Driver::None;
197 inner.state = MotionState::Canceled;
198 inner.last_frame = None;
199 }
200
201 pub fn finish(&self)
202 where
203 T: Clone,
204 {
205 let mut inner = self.lock();
206 inner.value = inner.target.clone();
207 inner.driver = Driver::None;
208 inner.state = MotionState::Finished;
209 inner.last_frame = None;
210 }
211
212 pub fn pause(&self) {
213 let mut inner = self.lock();
214 if inner.state != MotionState::Running {
215 return;
216 }
217 let last_frame = inner.last_frame;
218 if let (Driver::Timeline(timeline), Some(now)) = (&mut inner.driver, last_frame) {
219 timeline.pause(now);
220 }
221 inner.state = MotionState::Paused;
222 }
223
224 pub fn resume(&self) {
225 let mut inner = self.lock();
226 if inner.state == MotionState::Paused {
227 inner.state = MotionState::Running;
228 inner.resume_pending = true;
229 inner.last_frame = None;
230 }
231 }
232
233 pub fn play(&self, timeline: Timeline<T>)
234 where
235 T: Clone + Interpolate,
236 {
237 let mut inner = self.lock();
238 inner.target = timeline.terminal_value();
239 inner.driver = Driver::Timeline(timeline);
240 inner.state = MotionState::Running;
241 inner.last_frame = None;
242 inner.resume_pending = true;
243 inner.completed_iterations = 0;
244 }
245}
246
247impl<T: Clone + Interpolate + PartialEq> Motion<T> {
248 pub fn animate_to(&self, target: T, tween: Tween) {
249 let mut inner = self.lock();
250 if tween.duration == Duration::ZERO {
251 inner.value = target.clone();
252 inner.target = target;
253 inner.driver = Driver::None;
254 inner.state = MotionState::Finished;
255 inner.last_frame = None;
256 inner.completed_iterations = 0;
257 return;
258 }
259 let from = inner.value.clone();
260 inner.target = target;
261 inner.driver = Driver::PendingTween { from, tween };
262 inner.state = MotionState::Running;
263 inner.last_frame = None;
264 inner.resume_pending = false;
265 inner.completed_iterations = 0;
266 }
267
268 pub fn restart(&self, from: T, target: T, tween: Tween) {
269 self.set(from);
270 self.animate_to(target, tween);
271 }
272
273 pub fn advance(&self, now: Time) -> Result<bool, TimingError> {
274 let mut inner = self.lock();
275 if inner.state != MotionState::Running {
276 return Ok(false);
277 }
278 if let Driver::PendingTween { from, tween } = &inner.driver {
279 let frames = Keyframes::new(vec![
280 Keyframe::new(0.0, from.clone()).easing(tween.easing.clone()),
281 Keyframe::new(1.0, inner.target.clone()),
282 ])?;
283 let mut timeline = Timeline::new(
284 frames,
285 Timing::new(tween.duration)
286 .delay(tween.delay)
287 .fill(FillMode::Both),
288 )?;
289 timeline.play(now);
290 inner.driver = Driver::Timeline(timeline);
291 }
292 if inner.resume_pending {
293 if let Driver::Timeline(timeline) = &mut inner.driver {
294 match timeline.state() {
295 PlaybackState::Idle | PlaybackState::Finished | PlaybackState::Canceled => {
296 timeline.play(now);
297 }
298 PlaybackState::Paused => timeline.resume(now),
299 PlaybackState::Running => {}
300 }
301 }
302 inner.resume_pending = false;
303 }
304 let sample = match &mut inner.driver {
305 Driver::Timeline(timeline) => Some(timeline.sample(now)),
306 _ => None,
307 };
308 let mut changed = false;
309 if let Some(sample) = sample {
310 inner.completed_iterations = inner
311 .completed_iterations
312 .saturating_add(sample.events.iterations);
313 if let Some(value) = sample.value {
314 changed = value != inner.value;
315 inner.value = value;
316 }
317 if sample.state == PlaybackState::Finished {
318 inner.value = inner.target.clone();
319 inner.driver = Driver::None;
320 inner.state = MotionState::Finished;
321 inner.last_frame = None;
322 return Ok(true);
323 }
324 }
325 inner.last_frame = Some(now);
326 Ok(changed)
327 }
328}
329
330impl<T: MotionValue> Motion<T> {
331 #[must_use]
332 pub fn velocity(&self) -> T {
333 match &self.lock().driver {
334 Driver::Spring(spring) => spring.velocity(),
335 _ => T::zero(),
336 }
337 }
338
339 pub fn spring_to(&self, target: T, config: SpringConfig) -> Result<(), crate::PhysicsError> {
340 let mut inner = self.lock();
341 let velocity = match &inner.driver {
342 Driver::Spring(spring) => spring.velocity(),
343 _ => T::zero(),
344 };
345 let spring = Spring::new(inner.value, target, velocity, config)?;
346 inner.target = target;
347 inner.state = if spring.is_active() {
348 MotionState::Running
349 } else {
350 MotionState::Finished
351 };
352 inner.driver = if spring.is_active() {
353 Driver::Spring(spring)
354 } else {
355 Driver::None
356 };
357 inner.last_frame = None;
358 inner.completed_iterations = 0;
359 Ok(())
360 }
361
362 pub fn restart_spring(
363 &self,
364 from: T,
365 target: T,
366 config: SpringConfig,
367 ) -> Result<(), crate::PhysicsError> {
368 self.set(from);
369 self.spring_to(target, config)
370 }
371
372 pub fn advance_spring(&self, now: Time) -> bool {
373 let mut inner = self.lock();
374 if inner.state != MotionState::Running {
375 return false;
376 }
377 let elapsed = inner
378 .last_frame
379 .map_or(Duration::ZERO, |last| now.duration_since(last));
380 let (changed, value, active) = match &mut inner.driver {
381 Driver::Spring(spring) => {
382 let changed = spring.advance(elapsed);
383 (changed, spring.value(), spring.is_active())
384 }
385 _ => return false,
386 };
387 inner.value = value;
388 inner.last_frame = Some(now);
389 if !active {
390 inner.driver = Driver::None;
391 inner.state = MotionState::Finished;
392 inner.last_frame = None;
393 }
394 changed
395 }
396}
397
398pub trait MotionTrack {
399 fn identity(&self) -> usize;
400 fn is_active(&self) -> bool;
401 fn advance(&self, now: Time) -> bool;
402 fn finish(&self);
403 fn cancel(&self);
404}
405
406impl<T> MotionTrack for Motion<T>
407where
408 T: MotionValue + Clone + Interpolate + 'static,
409{
410 fn identity(&self) -> usize {
411 self.identity()
412 }
413
414 fn is_active(&self) -> bool {
415 self.is_active()
416 }
417
418 fn advance(&self, now: Time) -> bool {
419 let is_spring = matches!(&self.lock().driver, Driver::Spring(_));
420 if is_spring {
421 self.advance_spring(now)
422 } else {
423 self.advance(now).unwrap_or_else(|_| {
424 self.cancel();
425 false
426 })
427 }
428 }
429
430 fn finish(&self) {
431 self.finish();
432 }
433
434 fn cancel(&self) {
435 self.cancel();
436 }
437}