Skip to main content

ferroui_base/animation/
i_transition.rs

1use crate::animation::{Animatable, IClock, TransitionBase};
2use crate::reactive::IDisposable;
3use crate::{BoxedValue, FerroObject, FerroProperty, ObjectType, Ref, Upcast};
4use std::rc::Rc;
5
6/// Interface for transition objects: animates a property from its old value
7/// to its new value whenever the value changes.
8pub trait ITransition: 'static {
9    /// Applies the transition to the specified control: animates the
10    /// transition's property from `old_value` to `new_value`, which hold
11    /// exactly the value type of the property. Disposing the result ends the
12    /// transition.
13    fn apply(
14        &self,
15        control: &Animatable,
16        clock: Rc<dyn IClock>,
17        old_value: &BoxedValue,
18        new_value: &BoxedValue,
19    ) -> Rc<dyn IDisposable>;
20
21    /// The property to be animated. Panics when the transition has none.
22    fn property(&self) -> &'static FerroProperty;
23
24    fn set_property(&self, value: &'static FerroProperty);
25
26    /// A description of the transition for diagnostics.
27    fn debug_display(&self) -> String {
28        "ITransition".to_string()
29    }
30
31    /// The identity of the transition: handles to the same transition
32    /// object compare equal.
33    #[doc(hidden)]
34    fn reference_id(&self) -> *const () {
35        self as *const Self as *const ()
36    }
37
38    /// The object of the object model that implements the contract, if one
39    /// does: the equivalent of `is`/`as` on the interface. Cast the object to
40    /// the class looked for (`as_object()?.cast::<T>()`).
41    fn as_object(&self) -> Option<crate::Ref<crate::FerroObject>> {
42        None
43    }
44}
45
46impl PartialEq for dyn ITransition {
47    #[inline]
48    fn eq(&self, other: &Self) -> bool {
49        self.reference_id() == other.reference_id()
50    }
51}
52
53impl std::fmt::Debug for dyn ITransition {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        f.write_str(&self.debug_display())
56    }
57}
58
59/// The interface handle of a transition object.
60struct TransitionRef(Ref<TransitionBase>);
61
62impl ITransition for TransitionRef {
63    fn apply(
64        &self,
65        control: &Animatable,
66        clock: Rc<dyn IClock>,
67        old_value: &BoxedValue,
68        new_value: &BoxedValue,
69    ) -> Rc<dyn IDisposable> {
70        self.0.apply(control, clock, old_value, new_value)
71    }
72
73    fn property(&self) -> &'static FerroProperty {
74        match self.0.property() {
75            Some(property) => property,
76            None => panic!("Transition has no property specified."),
77        }
78    }
79
80    fn set_property(&self, value: &'static FerroProperty) {
81        self.0.set_property(Some(value))
82    }
83
84    fn debug_display(&self) -> String {
85        self.0.debug_display()
86    }
87
88    fn reference_id(&self) -> *const () {
89        let object: &FerroObject = &self.0;
90        object as *const FerroObject as *const ()
91    }
92
93    fn as_object(&self) -> Option<Ref<FerroObject>> {
94        Some(self.0.clone().upcast())
95    }
96}
97
98impl<T: ObjectType + Upcast<TransitionBase>> From<Ref<T>> for Rc<dyn ITransition> {
99    #[inline]
100    fn from(value: Ref<T>) -> Self {
101        Rc::new(TransitionRef(value.upcast()))
102    }
103}
104
105impl<T: ObjectType + Upcast<TransitionBase>> From<&Ref<T>> for Rc<dyn ITransition> {
106    #[inline]
107    fn from(value: &Ref<T>) -> Self {
108        Rc::new(TransitionRef(value.clone().upcast()))
109    }
110}