1use crate::animation::animators::{interpolation_handler, Animator};
2use crate::animation::easings::Easing;
3use crate::animation::{
4 Animatable, Animation, Clock, FillMode, IClock, IterationType, PlayState, PlaybackDirection,
5 TimeSpan,
6};
7use crate::data::BindingPriority;
8use crate::reactive::{
9 IDisposable, IObservable, IObserver, ObservableError, SingleSubscriberObservableBase,
10};
11use crate::{Ref, Visual, WeakRef};
12use std::cell::{Cell, RefCell};
13use std::fmt;
14use std::rc::{Rc, Weak};
15
16const PRECISION_IN_TICKS: i64 = 10_000;
17
18#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct AnimationError(pub String);
22
23impl fmt::Display for AnimationError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 f.write_str(&self.0)
26 }
27}
28
29impl std::error::Error for AnimationError {}
30
31pub(crate) struct AnimationInstance<A: Animator> {
35 this: Weak<AnimationInstance<A>>,
36 core: SingleSubscriberObservableBase<A::Value>,
37 animator: Rc<A>,
38 animation: Ref<Animation>,
39 target_control: WeakRef<Animatable>,
42 visual_target: Option<WeakRef<Visual>>,
43 on_complete_action: Option<Rc<dyn Fn()>>,
44 timer_sub: RefCell<Option<Rc<dyn IDisposable>>>,
45 property_changed_sub: RefCell<Option<Rc<dyn IDisposable>>>,
46 visibility_changed_sub: RefCell<Option<Rc<dyn IDisposable>>>,
47 detached_sub: RefCell<Option<Rc<dyn IDisposable>>>,
48 base_clock: Rc<dyn IClock>,
49 clock: RefCell<Option<Rc<Clock>>>,
50 ease_func: RefCell<Easing>,
51 neutral_value: RefCell<A::Value>,
52 fill_mode: Cell<FillMode>,
53 is_first_frame: Cell<bool>,
54 preview_complete: Cell<bool>,
55 is_in_first_initial_delay: Cell<bool>,
56 last_interp_value: RefCell<A::Value>,
57 initial_kf_value: RefCell<A::Value>,
58 iteration_count: Cell<Option<i64>>,
59 initial_delay: Cell<TimeSpan>,
60 iteration_delay: Cell<TimeSpan>,
61 duration: Cell<TimeSpan>,
62 time_prev: Cell<TimeSpan>,
63 anim_time_prev: Cell<f64>,
64 playback_direction: Cell<PlaybackDirection>,
65 playback_direction_prev: Cell<PlaybackDirection>,
66 speed_ratio: Cell<f64>,
67 speed_ratio_prev: Cell<f64>,
68 time_moves_backwards: Cell<bool>,
69 time_of_last_change: Cell<TimeSpan>,
70 anim_time_of_last_change: Cell<f64>,
71 should_pause_on_invisible: bool,
72}
73
74struct StepObserver<A: Animator>(Rc<AnimationInstance<A>>);
77
78impl<A: Animator> IObserver<TimeSpan> for StepObserver<A> {
79 fn on_next(&self, value: TimeSpan) {
80 self.0.step(value);
81 }
82}
83
84impl<A: Animator> AnimationInstance<A> {
85 pub(crate) fn new(
88 animation: Ref<Animation>,
89 control: &Ref<Animatable>,
90 animator: Rc<A>,
91 base_clock: Rc<dyn IClock>,
92 on_complete: Option<Rc<dyn Fn()>>,
93 should_pause_on_invisible: bool,
94 visual_target: Option<&Ref<Visual>>,
95 ) -> Rc<Self> {
96 let ease_func = animation.easing();
97 let instance = Rc::new_cyclic(|this| Self {
98 this: this.clone(),
99 core: SingleSubscriberObservableBase::new(),
100 animator,
101 animation,
102 target_control: control.downgrade(),
103 visual_target: visual_target.map(Ref::downgrade),
104 on_complete_action: on_complete,
105 timer_sub: RefCell::new(None),
106 property_changed_sub: RefCell::new(None),
107 visibility_changed_sub: RefCell::new(None),
108 detached_sub: RefCell::new(None),
109 base_clock,
110 clock: RefCell::new(None),
111 ease_func: RefCell::new(ease_func),
112 neutral_value: RefCell::new(A::Value::default()),
113 fill_mode: Cell::new(FillMode::None),
114 is_first_frame: Cell::new(true),
115 preview_complete: Cell::new(false),
116 is_in_first_initial_delay: Cell::new(true),
117 last_interp_value: RefCell::new(A::Value::default()),
118 initial_kf_value: RefCell::new(A::Value::default()),
119 iteration_count: Cell::new(None),
120 initial_delay: Cell::new(TimeSpan::ZERO),
121 iteration_delay: Cell::new(TimeSpan::ZERO),
122 duration: Cell::new(TimeSpan::ZERO),
123 time_prev: Cell::new(TimeSpan::ZERO),
124 anim_time_prev: Cell::new(0.0),
125 playback_direction: Cell::new(PlaybackDirection::Normal),
126 playback_direction_prev: Cell::new(PlaybackDirection::Normal),
127 speed_ratio: Cell::new(1.0),
128 speed_ratio_prev: Cell::new(1.0),
129 time_moves_backwards: Cell::new(false),
130 time_of_last_change: Cell::new(TimeSpan::ZERO),
131 anim_time_of_last_change: Cell::new(0.0),
132 should_pause_on_invisible,
133 });
134 if let Err(error) = instance.fetch_properties() {
135 panic!("{error}");
136 }
137 instance
138 }
139
140 fn fetch_properties(&self) -> Result<(), AnimationError> {
141 let animation = &self.animation;
142 *self.ease_func.borrow_mut() = animation.easing();
143
144 self.speed_ratio_prev.set(self.speed_ratio.get());
145 self.speed_ratio.set(animation.speed_ratio());
146
147 if self.speed_ratio.get() < 0.0 {
148 return Err(AnimationError(
149 "SpeedRatio value cannot be negative.".to_string(),
150 ));
151 }
152
153 self.initial_delay.set(animation.delay());
154
155 if self.initial_delay.get() < TimeSpan::ZERO {
156 return Err(AnimationError(
157 "Delay value cannot be negative.".to_string(),
158 ));
159 }
160
161 self.duration.set(animation.duration());
162
163 if self.duration.get() < TimeSpan::ZERO {
164 return Err(AnimationError(
165 "Duration value cannot be negative.".to_string(),
166 ));
167 }
168
169 self.iteration_delay
170 .set(animation.delay_between_iterations());
171
172 if self.iteration_delay.get() < TimeSpan::ZERO {
173 return Err(AnimationError(
174 "DelayBetweenIterations value cannot be negative.".to_string(),
175 ));
176 }
177
178 let iteration_count = animation.iteration_count();
179 if iteration_count.repeat_type() == IterationType::Many {
180 if iteration_count.value() > i64::MAX as u64 {
181 return Err(AnimationError(
182 "IterationCount value cannot be larger than long.MaxValue.".to_string(),
183 ));
184 }
185 self.iteration_count
186 .set(Some(iteration_count.value() as i64));
187 } else {
188 self.iteration_count.set(None);
189 }
190
191 self.playback_direction_prev
192 .set(self.playback_direction.get());
193 self.playback_direction.set(animation.playback_direction());
194 self.fill_mode.set(animation.fill_mode());
195 Ok(())
196 }
197
198 fn unsubscribed(&self) {
199 let timer_sub = self.timer_sub.borrow_mut().take();
203 let Some(timer_sub) = timer_sub else { return };
204
205 if self.can_apply_final_fill() && !self.animation.is_preview() {
207 let value = self.last_interp_value.borrow().clone();
208 self.apply_final_fill(value);
209 }
210
211 let property_changed_sub = self.property_changed_sub.borrow_mut().take();
212 if let Some(subscription) = property_changed_sub {
213 subscription.dispose();
214 }
215 timer_sub.dispose();
216
217 let visibility_changed_sub = self.visibility_changed_sub.borrow_mut().take();
218 if let Some(subscription) = visibility_changed_sub {
219 subscription.dispose();
220 }
221 let detached_sub = self.detached_sub.borrow_mut().take();
222 if let Some(subscription) = detached_sub {
223 subscription.dispose();
224 }
225
226 let clock = self.clock.borrow().clone();
227 if let Some(clock) = clock {
228 clock.set_play_state(PlayState::Stop);
229 }
230 }
231
232 fn subscribed(&self) {
233 let clock = Clock::with_parent(&self.base_clock);
234 *self.clock.borrow_mut() = Some(clock.clone());
235 let Some(this) = self.this.upgrade() else {
236 return;
237 };
238 let timer_sub = clock.subscribe(Rc::new(StepObserver(this)));
239 *self.timer_sub.borrow_mut() = Some(timer_sub);
240
241 if let Some(visual) = self.visual_target.as_ref().and_then(WeakRef::upgrade) {
242 if self.should_pause_on_invisible {
243 let weak_clock = Rc::downgrade(&clock);
244 let weak_visual = visual.downgrade();
245 let subscription = visual.is_effectively_visible_changed(move || {
246 let (Some(clock), Some(visual)) = (weak_clock.upgrade(), weak_visual.upgrade())
247 else {
248 return;
249 };
250 if clock.play_state() == PlayState::Stop {
251 return;
252 }
253 if visual.is_effectively_visible() {
254 if clock.play_state() == PlayState::Pause {
255 clock.set_play_state(PlayState::Run);
256 }
257 } else if clock.play_state() == PlayState::Run {
258 clock.set_play_state(PlayState::Pause);
259 }
260 });
261 *self.visibility_changed_sub.borrow_mut() = Some(subscription);
262
263 if !visual.is_effectively_visible() {
265 clock.set_play_state(PlayState::Pause);
266 }
267 }
268
269 let this = self.this.clone();
271 let subscription = visual.detached_from_visual_tree(move |_| {
272 if let Some(this) = this.upgrade() {
273 this.do_complete(false);
274 }
275 });
276 *self.detached_sub.borrow_mut() = Some(subscription);
277 }
278
279 if let Some(control) = self.target_control.upgrade() {
280 let this = self.this.clone();
281 let property = self.animator.base().property();
282 let subscription = control.property_changed(move |e| {
283 if Some(e.property()) == property && e.priority() > BindingPriority::Animation {
284 if let Some(this) = this.upgrade() {
285 this.update_neutral_value();
286 }
287 }
288 });
289 *self.property_changed_sub.borrow_mut() = Some(subscription);
290 }
291 self.update_neutral_value();
292 }
293
294 pub(crate) fn step(&self, frame_tick: TimeSpan) {
295 let paused = self
296 .clock
297 .borrow()
298 .as_ref()
299 .is_some_and(|clock| clock.play_state() == PlayState::Pause);
300 if paused {
301 return;
302 }
303
304 if self.target_control.upgrade().is_none() {
307 self.do_complete(true);
308 return;
309 }
310
311 if let Err(error) = self.internal_step(frame_tick) {
312 let error: ObservableError = Rc::new(error);
313 self.core.publish_error(error, || self.unsubscribed());
314 }
315 }
316
317 fn can_apply_final_fill(&self) -> bool {
318 matches!(self.fill_mode.get(), FillMode::Forward | FillMode::Both)
319 }
320
321 fn apply_final_fill(&self, interpolated_value: A::Value) {
322 let property = self.animator.base().styled_property::<A::Value>();
323 if let Some(control) = self.target_control.upgrade() {
324 control.set_value(property, interpolated_value);
325 }
326 }
327
328 fn do_complete(&self, stop_as_is: bool) {
329 if self.animation.is_preview() && self.preview_complete.replace(true) {
330 return;
331 }
332 if !stop_as_is {
333 let is_iteration_reversed = Self::is_iteration_reversed(
338 self.is_alternating_playback_direction(),
339 self.iteration_count.get().map(|count| count + 1),
340 );
341 let value =
342 self.find_edge_value(self.is_anim_time_going_backwards(), is_iteration_reversed);
343 *self.last_interp_value.borrow_mut() = value;
344 }
345
346 if self.animation.is_preview() && self.can_apply_final_fill() {
347 self.core
350 .publish_next(self.last_interp_value.borrow().clone());
351 self.unsubscribed();
352 if let Some(on_complete) = &self.on_complete_action {
353 on_complete();
354 }
355 return;
356 }
357 if let Some(on_complete) = &self.on_complete_action {
358 on_complete();
359 }
360 self.core.publish_completed(|| self.unsubscribed());
361 }
362
363 fn do_initial_delay(&self) {
364 if self.is_in_first_initial_delay.get()
365 && !matches!(self.fill_mode.get(), FillMode::Backward | FillMode::Both)
366 {
367 return;
368 }
369
370 let value = self.initial_kf_value.borrow().clone();
371 self.core.publish_next(value);
372 }
373
374 fn do_iteration_delay(&self, is_iteration_reversed: bool) {
375 let value = self.find_edge_value(false, is_iteration_reversed);
376 *self.last_interp_value.borrow_mut() = value.clone();
377 self.core.publish_next(value);
378 }
379
380 fn do_play_states(&self) {
381 let clock_stopped = self
382 .clock
383 .borrow()
384 .as_ref()
385 .is_some_and(|clock| clock.play_state() == PlayState::Stop);
386 if clock_stopped || self.base_clock.play_state() == PlayState::Stop {
387 self.do_complete(true);
388 }
389
390 if self.is_first_frame.get() {
391 let direction = self.animation.playback_direction();
393 self.time_moves_backwards.set(matches!(
394 direction,
395 PlaybackDirection::Reverse | PlaybackDirection::AlternateReverse
396 ));
397
398 let base = self.animator.base();
399 let count = base.count();
400 assert!(count != 0, "Sequence contains no elements");
401 let initial_key_frame = if self.time_moves_backwards.get() {
402 base.get(count - 1)
403 } else {
404 base.get(0)
405 };
406 let initial_value = initial_key_frame
407 .with_value(|value| value.and_then(|value| self.animator.typed_value(value)))
408 .unwrap_or_else(|| self.neutral_value.borrow().clone());
409 *self.initial_kf_value.borrow_mut() = initial_value;
410
411 self.is_first_frame.set(false);
412 }
413 }
414
415 fn is_iteration_reversed(
416 is_alternating_playback_direction: bool,
417 iteration_index: Option<i64>,
418 ) -> bool {
419 if is_alternating_playback_direction {
420 iteration_index.is_none_or(|index| (index & 1) != 0)
423 } else {
424 false
425 }
426 }
427
428 fn find_edge_value(
429 &self,
430 is_anim_time_going_backwards: bool,
431 is_iteration_reversed: bool,
432 ) -> A::Value {
433 let final_ease_value = if is_anim_time_going_backwards ^ is_iteration_reversed {
434 0.0
435 } else {
436 1.0
437 };
438 self.interpolate(final_ease_value)
439 }
440
441 fn interpolate(&self, normalized: f64) -> A::Value {
443 let ease_func = self.ease_func.borrow().clone();
444 let eased_time = ease_func.ease(normalized);
445 let neutral_value = self.neutral_value.borrow().clone();
446 interpolation_handler(&*self.animator, eased_time, &neutral_value)
447 }
448
449 fn is_anim_time_going_backwards(&self) -> bool {
450 matches!(
451 self.playback_direction.get(),
452 PlaybackDirection::Reverse | PlaybackDirection::AlternateReverse
453 )
454 }
455
456 fn is_alternating_playback_direction(&self) -> bool {
457 matches!(
458 self.playback_direction.get(),
459 PlaybackDirection::Alternate | PlaybackDirection::AlternateReverse
460 )
461 }
462
463 fn apply_initial_delay(&self, anim_time: &mut i64) -> bool {
466 let delay = self.initial_delay.get().ticks() / PRECISION_IN_TICKS;
467 if self.iteration_count.get().is_some() {
468 *anim_time -= delay;
469 if *anim_time <= 0 {
470 if *anim_time < -delay {
471 *anim_time = -delay;
472 }
473 return true;
474 }
475 } else {
476 let low = -delay;
478 let high = 0;
479
480 if *anim_time < low {
482 *anim_time += delay;
483 if *anim_time > 0 {
484 *anim_time = 0;
485 return true;
486 }
487 } else if *anim_time > high {
488 *anim_time -= delay;
489 if *anim_time < 0 {
490 *anim_time = 0;
491 return true;
492 }
493 } else {
494 *anim_time = 0;
495 return true;
496 }
497 }
498 false
499 }
500
501 fn apply_limited_clamp(&self, anim_time: &mut f64) {
502 if self.time_moves_backwards.get() {
503 if *anim_time > 0.0 {
504 *anim_time = 0.0;
505 }
506 } else if *anim_time < 0.0 {
507 *anim_time = 0.0;
508 }
509 }
510
511 fn internal_step(&self, time: TimeSpan) -> Result<(), AnimationError> {
512 self.do_play_states();
513 if self.preview_complete.get() {
514 return Ok(());
515 }
516
517 self.fetch_properties()?;
518
519 if self.speed_ratio.get() != self.speed_ratio_prev.get()
520 || self.playback_direction.get() != self.playback_direction_prev.get()
521 {
522 self.time_of_last_change.set(self.time_prev.get());
526 self.anim_time_of_last_change.set(self.anim_time_prev.get());
527 }
528
529 let is_anim_time_going_backwards = self.is_anim_time_going_backwards();
530
531 let speed_ratio = if is_anim_time_going_backwards {
533 -self.speed_ratio.get()
534 } else {
535 self.speed_ratio.get()
536 };
537
538 let time_since_last_change = time - self.time_of_last_change.get();
541 let anim_time_since_last_change =
542 time_since_last_change.ticks() as f64 * speed_ratio / PRECISION_IN_TICKS as f64;
543 let mut anim_time_exact = self.anim_time_of_last_change.get() + anim_time_since_last_change;
544
545 let iteration_count = self.iteration_count.get();
546 if iteration_count.is_some() {
547 self.apply_limited_clamp(&mut anim_time_exact);
549 }
550
551 self.time_prev.set(time);
552 self.anim_time_prev.set(anim_time_exact);
553 let anim_time = anim_time_exact as i64;
554
555 let mut anim_time_positive = if self.time_moves_backwards.get() {
558 -anim_time
559 } else {
560 anim_time
561 };
562
563 if self.initial_delay.get() > TimeSpan::ZERO {
564 let is_currently_inside_delay = self.apply_initial_delay(&mut anim_time_positive);
565 if is_currently_inside_delay {
566 self.do_initial_delay();
567 return Ok(());
568 }
569 self.is_in_first_initial_delay.set(false);
570 }
571
572 let iter_duration = self.duration.get().ticks() / PRECISION_IN_TICKS;
573 let iter_delay = self.iteration_delay.get().ticks() / PRECISION_IN_TICKS;
574 let iter_duration_total = iter_duration + iter_delay;
575
576 if iter_duration <= 0 {
579 self.do_complete(false);
580 return Ok(());
581 }
582
583 let mut iter_index = anim_time_positive / iter_duration_total;
585 let mut iter_time = anim_time_positive % iter_duration_total;
586
587 let mut playback_reversed = anim_time_positive < 0;
588
589 if playback_reversed {
590 iter_index -= 1;
594
595 iter_time = -iter_time;
598 }
599
600 playback_reversed ^= self.time_moves_backwards.get()
601 ^ Self::is_iteration_reversed(
602 self.is_alternating_playback_direction(),
603 Some(iter_index),
604 );
605
606 let iters_until_end = iteration_count.map(|count| count - iter_index);
607
608 if iters_until_end.is_some_and(|iters| iters <= 0) {
610 self.do_complete(false);
611 return Ok(());
612 }
613
614 if iter_time > iter_duration && iter_time <= iter_duration_total && iter_delay > 0 {
615 if iters_until_end.is_some_and(|iters| iters <= 1) {
617 self.do_complete(false);
618 return Ok(());
619 }
620
621 self.do_iteration_delay(playback_reversed);
622 } else if iter_time <= iter_duration {
623 let mut normalized = iter_time as f64 / iter_duration as f64;
625 if playback_reversed {
626 normalized = 1.0 - normalized;
627 }
628
629 let value = self.interpolate(normalized);
630 *self.last_interp_value.borrow_mut() = value.clone();
631 self.core.publish_next(value);
632 }
633 Ok(())
634 }
635
636 fn update_neutral_value(&self) {
637 let property = self.animator.base().styled_property::<A::Value>();
638 let Some(control) = self.target_control.upgrade() else {
639 return;
640 };
641
642 let value = match control.get_base_value(property) {
643 Some(base_value) => base_value,
644 None => control.get_value(property),
645 };
646 *self.neutral_value.borrow_mut() = value;
647 }
648}
649
650impl<A: Animator> IObservable<A::Value> for AnimationInstance<A> {
651 fn subscribe(&self, observer: Rc<dyn IObserver<A::Value>>) -> Rc<dyn IDisposable> {
652 self.core.subscribe(observer, || self.subscribed());
653 self.this
654 .upgrade()
655 .expect("the instance is alive while it is being subscribed to")
656 }
657}
658
659impl<A: Animator> IDisposable for AnimationInstance<A> {
660 fn dispose(&self) {
661 self.core.dispose(|| self.unsubscribed());
662 }
663}