Skip to main content

ferroui_base/rendering/composition/animations/
key_frame_animation.rs

1use super::{CompositionAnimation, IKeyFrames};
2use crate::animation::easings::{Easing, IEasing};
3use crate::animation::PlaybackDirection;
4use crate::rendering::composition::Compositor;
5use std::cell::{Cell, RefCell};
6use std::ops::Deref;
7use std::rc::Rc;
8use std::time::Duration;
9
10/// A time-based animation with one or more key frames.
11/// These frames are markers, allowing developers to specify values at specific times for the animating property.
12/// KeyFrame animations can be further customized by specifying how the animation interpolates between keyframes.
13///
14/// The classes for the value types (`ScalarKeyFrameAnimation`,
15/// `Vector3KeyFrameAnimation`, ...) embed it and dereference to it; they are
16/// expanded from the key frame animations of the composition schema at the
17/// end of this module.
18pub struct KeyFrameAnimation {
19    base: CompositionAnimation,
20    duration: Cell<Duration>,
21    delay_behavior: Cell<AnimationDelayBehavior>,
22    delay_time: Cell<Duration>,
23    direction: Cell<PlaybackDirection>,
24    iteration_behavior: Cell<AnimationIterationBehavior>,
25    iteration_count: Cell<i32>,
26    stop_behavior: Cell<AnimationStopBehavior>,
27    /// `private protected abstract IKeyFrames KeyFrames`: the key frames of
28    /// the class for the value type.
29    key_frames: RefCell<Box<dyn IKeyFrames>>,
30}
31
32impl Deref for KeyFrameAnimation {
33    type Target = CompositionAnimation;
34
35    fn deref(&self) -> &CompositionAnimation {
36        &self.base
37    }
38}
39
40impl KeyFrameAnimation {
41    pub(crate) fn new(compositor: &Rc<Compositor>, key_frames: Box<dyn IKeyFrames>) -> Self {
42        Self {
43            base: CompositionAnimation::new(compositor),
44            duration: Cell::new(Duration::from_millis(1)),
45            delay_behavior: Cell::new(AnimationDelayBehavior::default()),
46            delay_time: Cell::new(Duration::ZERO),
47            direction: Cell::new(PlaybackDirection::default()),
48            iteration_behavior: Cell::new(AnimationIterationBehavior::default()),
49            iteration_count: Cell::new(1),
50            stop_behavior: Cell::new(AnimationStopBehavior::default()),
51            key_frames: RefCell::new(key_frames),
52        }
53    }
54
55    /// The delay behavior of the key frame animation.
56    pub fn delay_behavior(&self) -> AnimationDelayBehavior {
57        self.delay_behavior.get()
58    }
59
60    pub fn set_delay_behavior(&self, value: AnimationDelayBehavior) {
61        self.delay_behavior.set(value)
62    }
63
64    /// Delay before the animation starts after `start_animation` is called.
65    pub fn delay_time(&self) -> Duration {
66        self.delay_time.get()
67    }
68
69    pub fn set_delay_time(&self, value: Duration) {
70        self.delay_time.set(value)
71    }
72
73    /// The direction the animation is playing.
74    /// The Direction property allows you to drive your animation from start to end or end to start or alternate
75    /// between start and end or end to start if animation has an [`iteration_count`](Self::iteration_count) greater than one.
76    /// This gives an easy way for customizing animation definitions.
77    pub fn direction(&self) -> PlaybackDirection {
78        self.direction.get()
79    }
80
81    pub fn set_direction(&self, value: PlaybackDirection) {
82        self.direction.set(value)
83    }
84
85    /// The duration of the animation.
86    /// Minimum allowed value is 1ms and maximum allowed value is 24 days.
87    pub fn duration(&self) -> Duration {
88        self.duration.get()
89    }
90
91    /// Sets the duration. As upstream, the range check is made on the
92    /// current value rather than on the new one.
93    pub fn set_duration(&self, value: Duration) {
94        let duration = self.duration.get();
95        if duration < Duration::from_millis(1) || duration > Duration::from_secs(24 * 60 * 60) {
96            panic!("Minimum allowed value is 1ms and maximum allowed value is 24 days.");
97        }
98        self.duration.set(value)
99    }
100
101    /// The iteration behavior for the key frame animation.
102    pub fn iteration_behavior(&self) -> AnimationIterationBehavior {
103        self.iteration_behavior.get()
104    }
105
106    pub fn set_iteration_behavior(&self, value: AnimationIterationBehavior) {
107        self.iteration_behavior.set(value)
108    }
109
110    /// The number of times to repeat the key frame animation.
111    pub fn iteration_count(&self) -> i32 {
112        self.iteration_count.get()
113    }
114
115    pub fn set_iteration_count(&self, value: i32) {
116        self.iteration_count.set(value)
117    }
118
119    /// Specifies how to set the property value when animation is stopped
120    pub fn stop_behavior(&self) -> AnimationStopBehavior {
121        self.stop_behavior.get()
122    }
123
124    pub fn set_stop_behavior(&self, value: AnimationStopBehavior) {
125        self.stop_behavior.set(value)
126    }
127
128    /// Inserts an expression keyframe.
129    ///
130    /// `normalized_progress_key` is the time the key frame should occur at,
131    /// expressed as a percentage of the animation Duration. Allowed value
132    /// is from 0.0 to 1.0. `value` is the expression used to calculate the
133    /// value of the key frame. `easing_function` is the easing function to
134    /// use when interpolating between frames; the default easing of the
135    /// compositor when `None`.
136    pub fn insert_expression_key_frame(&self, normalized_progress_key: f32, value: &str, easing_function: Option<Easing>) {
137        let easing = match easing_function {
138            Some(easing) => easing.as_rc().clone(),
139            None => self.compositor().default_easing(),
140        };
141        self.key_frames.borrow_mut().insert_expression_key_frame(normalized_progress_key, value, easing)
142    }
143
144    /// The key frames of the class for value type `T`.
145    pub(crate) fn with_key_frames<T: Copy + Default + 'static, R>(&self, f: impl FnOnce(&mut super::KeyFrames<T>) -> R) -> R {
146        let mut key_frames = self.key_frames.borrow_mut();
147        match key_frames.as_any_mut().downcast_mut::<super::KeyFrames<T>>() {
148            Some(key_frames) => f(key_frames),
149            None => unreachable!("the key frames of a key frame animation are of its value type"),
150        }
151    }
152}
153
154/// Specifies the animation delay behavior.
155#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
156pub enum AnimationDelayBehavior {
157    /// If a DelayTime is specified, it delays starting the animation according to delay time and after delay
158    /// has expired it applies animation to the object property.
159    #[default]
160    SetInitialValueAfterDelay,
161    /// Applies the initial value of the animation (i.e. the value at Keyframe 0) to the object before the delay time
162    /// is elapsed (when there is a DelayTime specified), it then delays starting the animation according to the DelayTime.
163    SetInitialValueBeforeDelay,
164}
165
166/// Specifies if the animation should loop.
167#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
168pub enum AnimationIterationBehavior {
169    /// The animation should loop the specified number of times.
170    #[default]
171    Count,
172    /// The animation should loop forever.
173    Forever,
174}
175
176/// Specifies the behavior of an animation when it stops.
177#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
178pub enum AnimationStopBehavior {
179    /// Leave the animation at its current value.
180    #[default]
181    LeaveCurrentValue,
182    /// Reset the animation to its initial value.
183    SetToInitialValue,
184    /// Set the animation to its final value.
185    SetToFinalValue,
186}
187
188/// Expands the key frame animation classes of the composition schema (see
189/// [`for_each_composition_key_frame_animation`](crate::rendering::composition::generated::for_each_composition_key_frame_animation)):
190/// upstream's generated `{Name}KeyFrameAnimation` classes and their
191/// `Compositor.Create{Name}KeyFrameAnimation` factories.
192macro_rules! key_frame_animation_classes {
193    ($(($name:ident, $create:ident, $ty:ty, $interpolator:ty)),* $(,)?) => {$(
194        #[doc = concat!("A key frame animation of `", stringify!($ty), "` values.")]
195        pub struct $name {
196            base: KeyFrameAnimation,
197        }
198
199        impl Deref for $name {
200            type Target = KeyFrameAnimation;
201
202            fn deref(&self) -> &KeyFrameAnimation {
203                &self.base
204            }
205        }
206
207        impl $name {
208            pub fn new(compositor: &Rc<Compositor>) -> Rc<$name> {
209                Rc::new($name {
210                    base: KeyFrameAnimation::new(compositor, Box::new(super::KeyFrames::<$ty>::new())),
211                })
212            }
213
214            pub fn insert_key_frame_with_easing(
215                &self,
216                normalized_progress_key: f32,
217                value: $ty,
218                easing_function: Rc<dyn IEasing>,
219            ) {
220                self.base.with_key_frames::<$ty, _>(|key_frames| {
221                    key_frames.insert(normalized_progress_key, value, easing_function)
222                })
223            }
224
225            pub fn insert_key_frame(&self, normalized_progress_key: f32, value: $ty) {
226                let easing = self.compositor().default_easing();
227                self.base.with_key_frames::<$ty, _>(|key_frames| {
228                    key_frames.insert(normalized_progress_key, value, easing)
229                })
230            }
231        }
232
233        impl super::ICompositionAnimationBase for $name {
234            fn as_composition_animation(&self) -> Option<&dyn super::ICompositionAnimation> {
235                Some(self)
236            }
237        }
238
239        impl super::ICompositionAnimation for $name {
240            fn target(&self) -> Option<String> {
241                self.base.target()
242            }
243
244            fn create_instance(
245                &self,
246                target_object: crate::rendering::composition::server::ServerObjectId,
247                final_value: Option<crate::rendering::composition::expressions::ExpressionVariant>,
248            ) -> super::AnimationInstanceFactory {
249                let interpolator: &'static (dyn super::IInterpolator<$ty> + Sync) = <$interpolator>::instance();
250                let key_frames = self.base.with_key_frames::<$ty, _>(|key_frames| key_frames.snapshot());
251                let parameters = self.create_snapshot_source();
252                let final_value = final_value.map(|value| {
253                    crate::rendering::composition::expressions::ExpressionVariant::create(
254                        value.cast_or_default::<$ty>(),
255                    )
256                });
257                let delay_behavior = self.delay_behavior();
258                let delay_time = self.delay_time();
259                let direction = self.direction();
260                let duration = self.duration();
261                let iteration_behavior = self.iteration_behavior();
262                let iteration_count = self.iteration_count();
263                let stop_behavior = self.stop_behavior();
264                super::AnimationInstanceFactory::new(move || {
265                    super::KeyFrameAnimationInstance::<$ty>::new(
266                        interpolator,
267                        key_frames,
268                        Rc::new(parameters.build()),
269                        final_value,
270                        target_object,
271                        delay_behavior,
272                        delay_time,
273                        direction,
274                        duration,
275                        iteration_behavior,
276                        iteration_count,
277                        stop_behavior,
278                    )
279                })
280            }
281        }
282
283        impl crate::rendering::composition::AsCompositionObject for $name {
284            fn as_composition_object(&self) -> &crate::rendering::composition::CompositionObject {
285                self.base.object()
286            }
287
288            fn composition_type_name(&self) -> &'static str {
289                stringify!($name)
290            }
291        }
292
293        impl Compositor {
294            pub fn $create(&self) -> Rc<$name> {
295                $name::new(&self.this_handle())
296            }
297        }
298    )*};
299}
300
301crate::rendering::composition::generated::for_each_composition_key_frame_animation!(key_frame_animation_classes);