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