Skip to main content

ferroui_base/animation/
animator_key_frame.rs

1use crate::animation::{Animatable, Cue, IAnimationSetter, IAnimator, KeySpline};
2use crate::reactive::{Disposable, IDisposable, IObservable, ObservableExt};
3use crate::styling::SetterValue;
4use crate::{
5    ferro_class, ferro_impl_classes, ferro_property, instantiate, AnyValue, BoxedValue, DirectProperty, FerroObject,
6    FerroObjectImpl, FerroProperty, PropertyValue, Ref,
7};
8use std::any::TypeId;
9use std::cell::{Cell, RefCell};
10use std::fmt;
11use std::rc::Rc;
12
13/// Creates the animator a key frame belongs to.
14pub type AnimatorFactory = Rc<dyn Fn() -> Rc<dyn IAnimator>>;
15
16/// Defines a key frame that is used for an animator.
17#[repr(C)]
18pub struct AnimatorKeyFrame {
19    base: FerroObject,
20    animator_type: Option<TypeId>,
21    animator_factory: Option<AnimatorFactory>,
22    cue: Cue,
23    key_spline: Option<Ref<KeySpline>>,
24    fill_before: Cell<bool>,
25    fill_after: Cell<bool>,
26    property: Cell<Option<&'static FerroProperty>>,
27    value: RefCell<Option<BoxedValue>>,
28}
29
30ferro_class!(AnimatorKeyFrame: FerroObject);
31ferro_impl_classes!(AnimatorKeyFrame: FerroObjectImpl);
32
33crate::ferro_properties! { impl AnimatorKeyFrame {
34    ferro_property!(
35        /// Defines the `Value` property.
36        pub fn value_property() -> DirectProperty<AnimatorKeyFrame, Option<BoxedValue>> {
37            FerroProperty::register_direct::<AnimatorKeyFrame, _>(
38                "Value",
39                |k| k.value(),
40                Some(|k, v| k.set_value(v)),
41                None,
42            )
43        }
44    );
45} }
46
47impl AnimatorKeyFrame {
48    /// Creates a key frame for the animator type `animator_type`, which
49    /// `animator_factory` creates.
50    pub fn new(
51        animator_type: Option<TypeId>,
52        animator_factory: Option<AnimatorFactory>,
53        cue: Cue,
54        key_spline: Option<Ref<KeySpline>>,
55    ) -> Ref<Self> {
56        instantiate(Self {
57            base: FerroObject::construct(),
58            animator_type,
59            animator_factory,
60            cue,
61            key_spline,
62            fill_before: Cell::new(false),
63            fill_after: Cell::new(false),
64            property: Cell::new(None),
65            value: RefCell::new(None),
66        })
67    }
68
69    /// The type of the animator the key frame belongs to.
70    pub fn animator_type(&self) -> Option<TypeId> {
71        self.animator_type
72    }
73
74    /// The factory of the animator the key frame belongs to.
75    pub fn animator_factory(&self) -> Option<AnimatorFactory> {
76        self.animator_factory.clone()
77    }
78
79    /// The position of the key frame within an iteration.
80    #[inline]
81    pub fn cue(&self) -> Cue {
82        self.cue
83    }
84
85    /// The spline applied to the progress towards this key frame.
86    #[inline]
87    pub fn key_spline(&self) -> Option<&Ref<KeySpline>> {
88        self.key_spline.as_ref()
89    }
90
91    /// Whether the value of this key frame applies before its cue.
92    #[inline]
93    pub fn fill_before(&self) -> bool {
94        self.fill_before.get()
95    }
96
97    pub fn set_fill_before(&self, value: bool) {
98        self.fill_before.set(value)
99    }
100
101    /// Whether the value of this key frame applies after its cue.
102    #[inline]
103    pub fn fill_after(&self) -> bool {
104        self.fill_after.get()
105    }
106
107    pub fn set_fill_after(&self, value: bool) {
108        self.fill_after.set(value)
109    }
110
111    /// The property the key frame animates.
112    pub fn property(&self) -> Option<&'static FerroProperty> {
113        self.property.get()
114    }
115
116    /// The value of the key frame: a value of exactly the animated
117    /// property's value type, or `None`.
118    pub fn value(&self) -> Option<BoxedValue> {
119        self.value.borrow().clone()
120    }
121
122    pub fn set_value(&self, value: Option<BoxedValue>) {
123        self.set_and_raise(Self::value_property(), &self.value, value);
124    }
125
126    /// Calls `f` with the value of the key frame without cloning it.
127    #[inline]
128    pub(crate) fn with_value<R>(&self, f: impl FnOnce(Option<&dyn AnyValue>) -> R) -> R {
129        let value = self.value.borrow();
130        f(value.as_deref())
131    }
132
133    /// Takes the property and the value from `setter`. When the setter's
134    /// value is a source of values, the key frame's value follows it for as
135    /// long as the returned handle is not disposed.
136    pub fn bind_setter(&self, setter: &dyn IAnimationSetter, target_control: &Animatable) -> Rc<dyn IDisposable> {
137        self.property.set(setter.property());
138
139        match setter.value() {
140            Some(SetterValue::Binding(source)) => {
141                let source: Rc<dyn IObservable<Option<BoxedValue>>> = source.select(Some);
142                self.bind_direct(Self::value_property(), source)
143            }
144            Some(SetterValue::BindingBase(binding)) => {
145                let anchor: Ref<FerroObject> = target_control.to_ref().upcast();
146                let expression =
147                    self.bind_binding_with_anchor(Self::value_property().as_property(), &*binding, Some(&anchor));
148                Disposable::create(move || expression.dispose())
149            }
150            Some(SetterValue::Value(value)) => {
151                self.set_value(Some(value));
152                Disposable::empty()
153            }
154            Some(SetterValue::Template(_)) | None => {
155                self.set_value(None);
156                Disposable::empty()
157            }
158        }
159    }
160
161    /// The value of the key frame as a `T`. Panics when the key frame has no
162    /// value or the value is of another type.
163    pub fn get_typed_value<T: PropertyValue>(&self) -> T {
164        self.with_value(|value| match value {
165            None => panic!("KeyFrame value can't be null."),
166            Some(value) => match value.downcast_ref::<T>() {
167                Some(value) => value.clone(),
168                None => panic!("KeyFrame value doesnt match property type."),
169            },
170        })
171    }
172}
173
174impl fmt::Display for AnimatorKeyFrame {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        write!(f, "AnimatorKeyFrame")?;
177        if let Some(property) = self.property.get() {
178            write!(f, " Property = {property},")?;
179        }
180        write!(f, " Cue = {}", self.cue.cue_value())
181    }
182}