Skip to main content

ferroui_base/animation/transitions/
effect_transition.rs

1use crate::animation::animators::{BlurEffectAnimator, DropShadowEffectAnimator};
2use crate::animation::{AnimatorTransitionObservable, Transition, TransitionBase, TransitionObservableBase};
3use crate::ferro_transition_class;
4use crate::media::effects::{IEffect, ImmutableBlurEffect, ImmutableDropShadowDirectionEffect};
5use crate::media::Color;
6use crate::reactive::IObservable;
7use std::rc::Rc;
8
9ferro_transition_class!(
10    /// Transition class that handles effect properties.
11    ///
12    /// Blur effects transition to and from blur effects, drop shadows to
13    /// and from drop shadows; a missing effect stands for an effect of the
14    /// other value's kind that has no visible result.
15    EffectTransition: Option<Rc<dyn IEffect>>
16);
17
18type EffectValue = Option<Rc<dyn IEffect>>;
19
20/// Pairs the values up for an animator of one kind of effect: `None` when
21/// the values are not both of that kind (or absent).
22fn try_with_kind(
23    old_value: &EffectValue,
24    new_value: &EffectValue,
25    is_kind: impl Fn(&dyn IEffect) -> bool,
26    default_value: impl FnOnce() -> Rc<dyn IEffect>,
27) -> Option<(EffectValue, EffectValue)> {
28    let of_kind = |value: &EffectValue| value.as_ref().is_some_and(|effect| is_kind(&**effect));
29
30    if of_kind(old_value) {
31        if of_kind(new_value) {
32            Some((old_value.clone(), new_value.clone()))
33        } else if new_value.is_none() {
34            Some((old_value.clone(), Some(default_value())))
35        } else {
36            None
37        }
38    } else if of_kind(new_value) {
39        Some((Some(default_value()), new_value.clone()))
40    } else {
41        None
42    }
43}
44
45impl Transition<EffectValue> for EffectTransition {
46    fn do_transition(
47        this: &Self,
48        progress: Rc<dyn IObservable<f64>>,
49        old_value: EffectValue,
50        new_value: EffectValue,
51    ) -> Rc<dyn IObservable<EffectValue>> {
52        if old_value.is_some() || new_value.is_some() {
53            if let Some((old_i, new_i)) = try_with_kind(
54                &old_value,
55                &new_value,
56                |effect| effect.as_blur_effect().is_some(),
57                || Rc::new(ImmutableBlurEffect::new(0.0)),
58            ) {
59                return AnimatorTransitionObservable::create(
60                    BlurEffectAnimator::interpolate_core,
61                    progress,
62                    this.easing(),
63                    old_i,
64                    new_i,
65                );
66            }
67
68            if let Some((old_i, new_i)) = try_with_kind(
69                &old_value,
70                &new_value,
71                |effect| effect.as_drop_shadow_effect().is_some(),
72                || Rc::new(ImmutableDropShadowDirectionEffect::new(0.0, 0.0, 0.0, Color::default(), 0.0)),
73            ) {
74                return AnimatorTransitionObservable::create(
75                    DropShadowEffectAnimator::interpolate_core,
76                    progress,
77                    this.easing(),
78                    old_i,
79                    new_i,
80                );
81            }
82        }
83
84        TransitionObservableBase::new(progress, this.easing(), move |progress| {
85            if progress >= 0.5 {
86                new_value.clone()
87            } else {
88                old_value.clone()
89            }
90        })
91    }
92}