ferroui_base/animation/
animator_key_frame.rs1use 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
13pub type AnimatorFactory = Rc<dyn Fn() -> Rc<dyn IAnimator>>;
15
16#[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 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 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 pub fn animator_type(&self) -> Option<TypeId> {
71 self.animator_type
72 }
73
74 pub fn animator_factory(&self) -> Option<AnimatorFactory> {
76 self.animator_factory.clone()
77 }
78
79 #[inline]
81 pub fn cue(&self) -> Cue {
82 self.cue
83 }
84
85 #[inline]
87 pub fn key_spline(&self) -> Option<&Ref<KeySpline>> {
88 self.key_spline.as_ref()
89 }
90
91 #[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 #[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 pub fn property(&self) -> Option<&'static FerroProperty> {
113 self.property.get()
114 }
115
116 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 #[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 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 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}