ferroui_base/animation/
transition_base.rs1use crate::animation::easings::Easing;
2use crate::animation::{Animatable, IClock, TimeSpan};
3use crate::reactive::IDisposable;
4use crate::{
5 ferro_class, ferro_property, BoxedValue, DirectProperty, FerroObject, FerroObjectImpl, FerroObjectImplExt,
6 FerroProperty, FerroPropertyChangedEventArgs,
7};
8use std::any::TypeId;
9use std::cell::{Cell, RefCell};
10use std::rc::Rc;
11
12#[repr(C)]
14pub struct TransitionBase {
15 base: FerroObject,
16 duration: Cell<TimeSpan>,
17 delay: Cell<TimeSpan>,
18 easing: RefCell<Easing>,
19 prop: Cell<Option<&'static FerroProperty>>,
20}
21
22ferro_class! {
23 TransitionBase: FerroObject, virtuals TransitionBaseImpl: FerroObjectImpl {
24 fn apply(this, control: &Animatable, clock: Rc<dyn IClock>, old_value: &BoxedValue, new_value: &BoxedValue) -> Rc<dyn IDisposable>;
27 fn value_type(this) -> (TypeId, &'static str);
30 }
31}
32crate::ferro_class_info!(TransitionBase { interfaces: [std::rc::Rc<dyn crate::animation::ITransition>] });
33
34impl FerroObjectImpl for TransitionBase {
35 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
36 Self::parent_on_property_changed(this, change);
37
38 if change.property() == Self::property_property().as_property() {
39 if let Some(new_value) = change.get_new_value::<Option<&'static FerroProperty>>() {
40 let (value_type, value_type_name) = this.value_type();
41 if new_value.property_type() != value_type {
42 panic!(
45 "Invalid property type \"{}\" for this transition: {}.",
46 value_type_name,
47 this.get_type().name()
48 );
49 }
50 }
51 }
52 }
53}
54
55impl TransitionBaseImpl for TransitionBase {
56 fn apply(
57 _this: &Self,
58 _control: &Animatable,
59 _clock: Rc<dyn IClock>,
60 _old_value: &BoxedValue,
61 _new_value: &BoxedValue,
62 ) -> Rc<dyn IDisposable> {
63 panic!("TransitionBase is abstract: 'apply' must be implemented by the deriving class")
64 }
65
66 fn value_type(_this: &Self) -> (TypeId, &'static str) {
67 panic!("TransitionBase is abstract: 'value_type' must be implemented by the deriving class")
68 }
69}
70
71crate::ferro_properties! { impl TransitionBase {
72 ferro_property!(
73 pub fn duration_property() -> DirectProperty<TransitionBase, TimeSpan> {
75 FerroProperty::register_direct::<TransitionBase, _>(
76 "Duration",
77 |o| o.duration(),
78 Some(|o, v| o.set_duration(v)),
79 TimeSpan::ZERO,
80 )
81 }
82 );
83
84 ferro_property!(
85 pub fn delay_property() -> DirectProperty<TransitionBase, TimeSpan> {
87 FerroProperty::register_direct::<TransitionBase, _>(
88 "Delay",
89 |o| o.delay(),
90 Some(|o, v| o.set_delay(v)),
91 TimeSpan::ZERO,
92 )
93 }
94 );
95
96 ferro_property!(
97 pub fn easing_property() -> DirectProperty<TransitionBase, Easing> {
99 FerroProperty::register_direct::<TransitionBase, _>(
100 "Easing",
101 |o| o.easing(),
102 Some(|o, v| o.set_easing(v)),
103 Easing::default(),
104 )
105 }
106 );
107
108 ferro_property!(
109 pub fn property_property() -> DirectProperty<TransitionBase, Option<&'static FerroProperty>> {
111 FerroProperty::register_direct::<TransitionBase, _>(
112 "Property",
113 |o| o.property(),
114 Some(|o, v| o.set_property(v)),
115 None,
116 )
117 }
118 );
119} }
120
121impl TransitionBase {
122 pub fn construct() -> Self {
124 Self {
125 base: FerroObject::construct(),
126 duration: Cell::new(TimeSpan::ZERO),
127 delay: Cell::new(TimeSpan::ZERO),
128 easing: RefCell::new(Easing::default()),
129 prop: Cell::new(None),
130 }
131 }
132
133 pub fn duration(&self) -> TimeSpan {
135 self.duration.get()
136 }
137
138 pub fn set_duration(&self, value: TimeSpan) {
139 self.set_and_raise_cell(Self::duration_property(), &self.duration, value);
140 }
141
142 pub fn delay(&self) -> TimeSpan {
144 self.delay.get()
145 }
146
147 pub fn set_delay(&self, value: TimeSpan) {
148 self.set_and_raise_cell(Self::delay_property(), &self.delay, value);
149 }
150
151 pub fn easing(&self) -> Easing {
153 self.easing.borrow().clone()
154 }
155
156 pub fn set_easing(&self, value: impl Into<Easing>) {
157 self.set_and_raise(Self::easing_property(), &self.easing, value.into());
158 }
159
160 pub fn property(&self) -> Option<&'static FerroProperty> {
162 self.prop.get()
163 }
164
165 pub fn set_property(&self, value: Option<&'static FerroProperty>) {
166 self.set_and_raise_cell(Self::property_property(), &self.prop, value);
167 }
168
169 pub fn debug_display(&self) -> String {
171 let mut result = self.get_type().name().to_string();
172 if let Some(property) = self.prop.get() {
173 result.push_str(&format!(" Property = {property},"));
174 }
175 result.push_str(&format!(" Duration = {}", self.duration.get()));
176 result
177 }
178}