Skip to main content

ferroui_base/animation/
animation_animator_registry.rs

1use crate::animation::animators::*;
2use crate::animation::{Animation, AnimatorFactory, IAnimationSetter, ICustomAnimator, InterpolatingAnimator};
3use crate::media::Transform;
4use crate::{FerroProperty, PropertyValue};
5use std::any::TypeId;
6use std::cell::RefCell;
7use std::rc::{Rc, Weak};
8
9type Condition = Rc<dyn Fn(&'static FerroProperty) -> bool>;
10type Registration = (Condition, TypeId, AnimatorFactory);
11
12struct Registry {
13    /// Animator selection, in order of precedence.
14    animators: Vec<Registration>,
15    /// The animators assigned to individual setters.
16    setter_animators: Vec<(Weak<dyn IAnimationSetter>, TypeId, AnimatorFactory)>,
17}
18
19fn by_type<T: PropertyValue>() -> Condition {
20    Rc::new(|property| property.property_type() == TypeId::of::<T>())
21}
22
23fn registration<A: Animator + Default>(condition: Condition) -> Registration {
24    (condition, TypeId::of::<A>(), Rc::new(|| Rc::new(A::default())))
25}
26
27fn register_animator<A: Animator + Default>(animators: &mut Vec<Registration>) {
28    animators.insert(0, registration::<A>(by_type::<A::Value>()));
29}
30
31impl Registry {
32    fn new() -> Self {
33        let mut animators: Vec<Registration> = vec![
34            registration::<TransformAnimator>(Rc::new(|property| {
35                property.property_type() == TypeId::of::<f64>()
36                    && Transform::TYPE.is_assignable_from(property.owner_type())
37            })),
38            registration::<BoolAnimator>(by_type::<bool>()),
39            registration::<ByteAnimator>(by_type::<u8>()),
40            registration::<Int16Animator>(by_type::<i16>()),
41            registration::<Int32Animator>(by_type::<i32>()),
42            registration::<Int64Animator>(by_type::<i64>()),
43            registration::<UInt16Animator>(by_type::<u16>()),
44            registration::<UInt32Animator>(by_type::<u32>()),
45            registration::<UInt64Animator>(by_type::<u64>()),
46            registration::<FloatAnimator>(by_type::<f32>()),
47            registration::<DoubleAnimator>(by_type::<f64>()),
48        ];
49
50        register_animator::<EffectAnimator>(&mut animators);
51        register_animator::<BoxShadowAnimator>(&mut animators);
52        register_animator::<BoxShadowsAnimator>(&mut animators);
53        register_animator::<BaseBrushAnimator>(&mut animators);
54        register_animator::<CornerRadiusAnimator>(&mut animators);
55        register_animator::<ColorAnimator>(&mut animators);
56        register_animator::<VectorAnimator>(&mut animators);
57        register_animator::<PointAnimator>(&mut animators);
58        register_animator::<RectAnimator>(&mut animators);
59        register_animator::<RelativePointAnimator>(&mut animators);
60        register_animator::<RelativeScalarAnimator>(&mut animators);
61        register_animator::<SizeAnimator>(&mut animators);
62        register_animator::<ThicknessAnimator>(&mut animators);
63
64        Self { animators, setter_animators: Vec::new() }
65    }
66}
67
68crate::ferro_thread_local! {
69    static REGISTRY: RefCell<Registry> = RefCell::new(Registry::new());
70}
71
72impl Animation {
73    /// Sets the value of the `Animator` attached property for a setter: the
74    /// custom animator that animates the setter's property instead of the
75    /// one selected by the property's type.
76    pub fn set_animator(setter: &Rc<dyn IAnimationSetter>, value: Rc<dyn ICustomAnimator>) {
77        let type_ = value.wrapper_type();
78        let factory: AnimatorFactory = Rc::new(move || value.clone().create_wrapper());
79        REGISTRY.with(|registry| {
80            let mut registry = registry.borrow_mut();
81            registry.setter_animators.retain(|(key, _, _)| key.upgrade().is_some_and(|key| !same_setter(&key, setter)));
82            registry.setter_animators.push((Rc::downgrade(setter), type_, factory));
83        });
84    }
85
86    /// The animator assigned to `setter` with [`set_animator`](Self::set_animator).
87    pub(crate) fn get_animator(setter: &Rc<dyn IAnimationSetter>) -> Option<(TypeId, AnimatorFactory)> {
88        REGISTRY.with(|registry| {
89            registry
90                .borrow()
91                .setter_animators
92                .iter()
93                .find(|(key, _, _)| key.upgrade().is_some_and(|key| same_setter(&key, setter)))
94                .map(|(_, type_, factory)| (*type_, factory.clone()))
95        })
96    }
97
98    /// Registers a user-provided animator for properties of its value type.
99    /// It takes precedence over the animators registered before it.
100    pub fn register_custom_animator<TAnimator: InterpolatingAnimator + Default>() {
101        let type_ = TypeId::of::<crate::animation::i_custom_animator::AnimatorWrapper<TAnimator::Value>>();
102        let factory: AnimatorFactory = Rc::new(|| {
103            let animator: Rc<dyn ICustomAnimator> = Rc::new(TAnimator::default());
104            animator.create_wrapper()
105        });
106        REGISTRY.with(|registry| {
107            registry.borrow_mut().animators.insert(0, (by_type::<TAnimator::Value>(), type_, factory));
108        });
109    }
110
111    /// Selects the animator for a property: the first registration whose
112    /// condition the property meets.
113    pub(crate) fn get_animator_type(property: &'static FerroProperty) -> Option<(TypeId, AnimatorFactory)> {
114        // The conditions are evaluated outside of the registry borrow.
115        let animators: Vec<Registration> = REGISTRY.with(|registry| registry.borrow().animators.clone());
116        animators
117            .into_iter()
118            .find(|(condition, _, _)| condition(property))
119            .map(|(_, type_, factory)| (type_, factory))
120    }
121}
122
123fn same_setter(a: &Rc<dyn IAnimationSetter>, b: &Rc<dyn IAnimationSetter>) -> bool {
124    std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b))
125}