Skip to main content

ferroui_base/animation/transitions/
brush_transition.rs

1use crate::animation::animators::{GradientBrushAnimator, ISolidColorBrushAnimator};
2use crate::animation::{AnimatorTransitionObservable, Transition, TransitionBase, TransitionObservableBase};
3use crate::ferro_transition_class;
4use crate::media::IBrush;
5use crate::reactive::IObservable;
6use std::rc::Rc;
7
8ferro_transition_class!(
9    /// Transition class that handles brush properties.
10    ///
11    /// Only values of solid color and gradient brushes can be transitioned.
12    BrushTransition: Option<Rc<dyn IBrush>>
13);
14
15type Brush = Option<Rc<dyn IBrush>>;
16
17impl Transition<Brush> for BrushTransition {
18    fn do_transition(
19        this: &Self,
20        progress: Rc<dyn IObservable<f64>>,
21        old_value: Brush,
22        new_value: Brush,
23    ) -> Rc<dyn IObservable<Brush>> {
24        let easing = this.easing();
25        let incompatible = |progress, old_value: Brush, new_value: Brush| -> Rc<dyn IObservable<Brush>> {
26            TransitionObservableBase::new(progress, this.easing(), move |progress| {
27                if progress >= 0.5 {
28                    new_value.clone()
29                } else {
30                    old_value.clone()
31                }
32            })
33        };
34
35        let (Some(old_brush), Some(new_brush)) = (&old_value, &new_value) else {
36            return incompatible(progress, old_value, new_value);
37        };
38
39        if old_brush.as_gradient_brush().is_some() {
40            if new_brush.as_gradient_brush().is_some() {
41                return AnimatorTransitionObservable::create(
42                    GradientBrushAnimator::interpolate_core,
43                    progress,
44                    easing,
45                    old_value,
46                    new_value,
47                );
48            } else if let Some(new_solid_color_brush_to_convert) = new_brush.as_solid_color_brush() {
49                let converted_solid_color_brush = GradientBrushAnimator::convert_solid_color_brush_to_gradient(
50                    &**old_brush,
51                    new_solid_color_brush_to_convert,
52                );
53                return AnimatorTransitionObservable::create(
54                    GradientBrushAnimator::interpolate_core,
55                    progress,
56                    easing,
57                    old_value,
58                    Some(converted_solid_color_brush),
59                );
60            }
61        } else if let (Some(_), Some(old_solid_color_brush_to_convert)) =
62            (new_brush.as_gradient_brush(), old_brush.as_solid_color_brush())
63        {
64            let converted_solid_color_brush = GradientBrushAnimator::convert_solid_color_brush_to_gradient(
65                &**new_brush,
66                old_solid_color_brush_to_convert,
67            );
68            return AnimatorTransitionObservable::create(
69                GradientBrushAnimator::interpolate_core,
70                progress,
71                easing,
72                Some(converted_solid_color_brush),
73                new_value,
74            );
75        }
76
77        if old_brush.as_solid_color_brush().is_some() && new_brush.as_solid_color_brush().is_some() {
78            return AnimatorTransitionObservable::create(
79                ISolidColorBrushAnimator::interpolate_core,
80                progress,
81                easing,
82                old_value,
83                new_value,
84            );
85        }
86
87        incompatible(progress, old_value, new_value)
88    }
89}