ferroui_base/animation/
transition_observable_base.rs1use crate::animation::easings::Easing;
2use crate::reactive::{SingleSubscriberObservableBase, IDisposable, IObservable, IObserver, ObservableError};
3use std::cell::RefCell;
4use std::rc::{Rc, Weak};
5
6pub struct TransitionObservableBase<T: 'static, F: Fn(f64) -> T + 'static> {
9 this: Weak<Self>,
10 core: SingleSubscriberObservableBase<T>,
11 easing: Easing,
12 progress: Rc<dyn IObservable<f64>>,
13 progress_subscription: RefCell<Option<Rc<dyn IDisposable>>>,
14 produce_value: F,
15}
16
17impl<T: 'static, F: Fn(f64) -> T + 'static> TransitionObservableBase<T, F> {
18 pub fn new(progress: Rc<dyn IObservable<f64>>, easing: Easing, produce_value: F) -> Rc<Self> {
21 Rc::new_cyclic(|this| Self {
22 this: this.clone(),
23 core: SingleSubscriberObservableBase::new(),
24 easing,
25 progress,
26 progress_subscription: RefCell::new(None),
27 produce_value,
28 })
29 }
30
31 pub fn progress(&self) -> &Rc<dyn IObservable<f64>> {
33 &self.progress
34 }
35
36 fn subscribed(&self) {
37 let Some(this) = self.this.upgrade() else { return };
38 let subscription = self.progress.subscribe(this);
39 if self.core.has_observer() {
41 *self.progress_subscription.borrow_mut() = Some(subscription);
42 } else {
43 subscription.dispose();
44 }
45 }
46
47 fn unsubscribed(&self) {
48 let subscription = self.progress_subscription.borrow_mut().take();
49 if let Some(subscription) = subscription {
50 subscription.dispose();
51 }
52 }
53}
54
55impl<T: 'static, F: Fn(f64) -> T + 'static> IObservable<T> for TransitionObservableBase<T, F> {
56 fn subscribe(&self, observer: Rc<dyn IObserver<T>>) -> Rc<dyn IDisposable> {
57 self.core.subscribe(observer, || self.subscribed());
58 self.this.upgrade().expect("the observable is alive while it is being subscribed to")
59 }
60}
61
62impl<T: 'static, F: Fn(f64) -> T + 'static> IDisposable for TransitionObservableBase<T, F> {
63 fn dispose(&self) {
64 self.core.dispose(|| self.unsubscribed());
65 }
66}
67
68impl<T: 'static, F: Fn(f64) -> T + 'static> IObserver<f64> for TransitionObservableBase<T, F> {
69 fn on_completed(&self) {
70 self.core.publish_completed(|| self.unsubscribed());
71 }
72
73 fn on_error(&self, error: ObservableError) {
74 self.core.publish_error(error, || self.unsubscribed());
75 }
76
77 fn on_next(&self, value: f64) {
78 let progress = self.easing.ease(value);
79 self.core.publish_next((self.produce_value)(progress));
80 }
81}