ferroui_base/animation/animators/
effect_animator.rs1use crate::animation::animators::{apply_with_visual, Animator, AnimatorBase, ColorAnimator, DoubleAnimator};
2use crate::animation::{Animatable, Animation, AnimatorFactory, AnimatorKeyFrame, IAnimator, IClock};
3use crate::logging::{LogArea, LogEventLevel, Logger};
4use crate::media::effects::{
5 IBlurEffect, IDropShadowEffect, IEffect, ImmutableBlurEffect, ImmutableDropShadowDirectionEffect,
6 ImmutableDropShadowEffect,
7};
8use crate::reactive::{IDisposable, IObservable};
9use crate::Visual;
10use std::any::TypeId;
11use std::rc::Rc;
12
13type EffectValue = Option<Rc<dyn IEffect>>;
14
15fn effect_of(frame: &AnimatorKeyFrame) -> EffectValue {
16 frame.with_value(|value| value.and_then(|value| value.downcast_ref::<EffectValue>()).and_then(|effect| effect.clone()))
17}
18
19#[derive(Default)]
23pub struct EffectAnimator {
24 base: AnimatorBase,
25}
26
27impl EffectAnimator {
28 pub fn new() -> Self {
29 Self::default()
30 }
31
32 fn try_create_animator<TAnimator: Animator + Default>(
33 &self,
34 is_kind: impl Fn(&dyn IEffect) -> bool,
35 ) -> Option<Rc<dyn IAnimator>> {
36 let mut created_animator: Option<Rc<TAnimator>> = None;
37 let factory: AnimatorFactory = Rc::new(|| Rc::new(TAnimator::default()));
38
39 for key_frame in self.base.to_vec() {
40 if !effect_of(&key_frame).is_some_and(|effect| is_kind(&*effect)) {
41 return None;
42 }
43
44 let animator = created_animator.get_or_insert_with(|| {
45 let animator = Rc::new(TAnimator::default());
46 animator.base().set_property(self.base.property());
47 animator
48 });
49 let copy = AnimatorKeyFrame::new(
50 Some(TypeId::of::<TAnimator>()),
51 Some(factory.clone()),
52 key_frame.cue(),
53 key_frame.key_spline().cloned(),
54 );
55 copy.set_value(key_frame.value());
56 copy.set_fill_before(key_frame.fill_before());
57 copy.set_fill_after(key_frame.fill_after());
58 IAnimator::add(&**animator, copy);
59 }
60
61 created_animator.map(|animator| animator as Rc<dyn IAnimator>)
62 }
63
64 pub fn ensure_registered() {}
67}
68
69impl Animator for EffectAnimator {
70 type Value = EffectValue;
71
72 fn base(&self) -> &AnimatorBase {
73 &self.base
74 }
75
76 fn apply(
77 this: &Rc<Self>,
78 animation: &Animation,
79 control: &Animatable,
80 clock: Option<Rc<dyn IClock>>,
81 match_: Rc<dyn IObservable<bool>>,
82 on_complete: Option<Rc<dyn Fn()>>,
83 should_pause_on_invisible: bool,
84 ) -> Option<Rc<dyn IDisposable>> {
85 let animator = this
86 .try_create_animator::<BlurEffectAnimator>(|effect| effect.as_blur_effect().is_some())
87 .or_else(|| this.try_create_animator::<DropShadowEffectAnimator>(|effect| effect.as_drop_shadow_effect().is_some()));
88 if let Some(animator) = animator {
89 return animator.apply(animation, control, clock, match_, on_complete, should_pause_on_invisible);
90 }
91
92 if let Some(logger) = Logger::try_get(LogEventLevel::Error, LogArea::ANIMATIONS) {
93 logger.log(None, "The animation's keyframe value types set is not supported.");
94 }
95
96 let visual_target = control.downcast_ref::<Visual>().map(Visual::to_ref);
97 Some(apply_with_visual(
98 this,
99 animation,
100 control,
101 clock,
102 match_,
103 on_complete,
104 should_pause_on_invisible,
105 visual_target,
106 ))
107 }
108
109 fn interpolate(&self, progress: f64, old_value: &EffectValue, new_value: &EffectValue) -> EffectValue {
111 if progress >= 0.5 {
112 new_value.clone()
113 } else {
114 old_value.clone()
115 }
116 }
117}
118
119#[derive(Default)]
122pub struct BlurEffectAnimator {
123 base: AnimatorBase,
124}
125
126impl BlurEffectAnimator {
127 pub fn new() -> Self {
128 Self::default()
129 }
130
131 pub fn interpolate_blur(progress: f64, old_value: &dyn IBlurEffect, new_value: &dyn IBlurEffect) -> ImmutableBlurEffect {
133 ImmutableBlurEffect::new(DoubleAnimator::interpolate_core(progress, &old_value.radius(), &new_value.radius()))
134 }
135
136 pub fn interpolate_core(progress: f64, old_value: &EffectValue, new_value: &EffectValue) -> EffectValue {
138 let old = old_value.as_ref().and_then(|effect| effect.as_blur_effect());
139 let n = new_value.as_ref().and_then(|effect| effect.as_blur_effect());
140 match (old, n) {
141 (Some(old), Some(n)) => Some(Rc::new(Self::interpolate_blur(progress, old, n))),
142 _ => {
143 if progress >= 0.5 {
144 new_value.clone()
145 } else {
146 old_value.clone()
147 }
148 }
149 }
150 }
151}
152
153impl Animator for BlurEffectAnimator {
154 type Value = EffectValue;
155
156 fn base(&self) -> &AnimatorBase {
157 &self.base
158 }
159
160 fn interpolate(&self, progress: f64, old_value: &EffectValue, new_value: &EffectValue) -> EffectValue {
161 Self::interpolate_core(progress, old_value, new_value)
162 }
163}
164
165#[derive(Default)]
168pub struct DropShadowEffectAnimator {
169 base: AnimatorBase,
170}
171
172impl DropShadowEffectAnimator {
173 pub fn new() -> Self {
174 Self::default()
175 }
176
177 pub fn interpolate_drop_shadow(
180 progress: f64,
181 old_value: &dyn IDropShadowEffect,
182 new_value: &dyn IDropShadowEffect,
183 ) -> Rc<dyn IEffect> {
184 let blur = DoubleAnimator::interpolate_core(progress, &old_value.blur_radius(), &new_value.blur_radius());
185 let color = ColorAnimator::interpolate_core(progress, &old_value.color(), &new_value.color());
186 let opacity = DoubleAnimator::interpolate_core(progress, &old_value.opacity(), &new_value.opacity());
187
188 if let (Some(old_direction), Some(new_direction)) =
189 (old_value.as_direction_drop_shadow_effect(), new_value.as_direction_drop_shadow_effect())
190 {
191 return Rc::new(ImmutableDropShadowDirectionEffect::new(
192 DoubleAnimator::interpolate_core(progress, &old_direction.direction(), &new_direction.direction()),
193 DoubleAnimator::interpolate_core(progress, &old_direction.shadow_depth(), &new_direction.shadow_depth()),
194 blur,
195 color,
196 opacity,
197 ));
198 }
199
200 Rc::new(ImmutableDropShadowEffect::new(
201 DoubleAnimator::interpolate_core(progress, &old_value.offset_x(), &new_value.offset_x()),
202 DoubleAnimator::interpolate_core(progress, &old_value.offset_y(), &new_value.offset_y()),
203 blur,
204 color,
205 opacity,
206 ))
207 }
208
209 pub fn interpolate_core(progress: f64, old_value: &EffectValue, new_value: &EffectValue) -> EffectValue {
211 let old = old_value.as_ref().and_then(|effect| effect.as_drop_shadow_effect());
212 let n = new_value.as_ref().and_then(|effect| effect.as_drop_shadow_effect());
213 match (old, n) {
214 (Some(old), Some(n)) => Some(Self::interpolate_drop_shadow(progress, old, n)),
215 _ => {
216 if progress >= 0.5 {
217 new_value.clone()
218 } else {
219 old_value.clone()
220 }
221 }
222 }
223 }
224}
225
226impl Animator for DropShadowEffectAnimator {
227 type Value = EffectValue;
228
229 fn base(&self) -> &AnimatorBase {
230 &self.base
231 }
232
233 fn interpolate(&self, progress: f64, old_value: &EffectValue, new_value: &EffectValue) -> EffectValue {
234 Self::interpolate_core(progress, old_value, new_value)
235 }
236}