ferroui_base/animation/
animation_animator_registry.rs1use 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 animators: Vec<Registration>,
15 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 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 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 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 pub(crate) fn get_animator_type(property: &'static FerroProperty) -> Option<(TypeId, AnimatorFactory)> {
114 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}