Skip to main content

ferroui_base/animation/animators/
transform_operations_animator.rs

1use crate::animation::AnimatorKeyFrame;
2use crate::media::transformation::TransformOperations;
3use crate::media::ITransform;
4use crate::Ref;
5use std::rc::Rc;
6
7/// Interpolates transform operation lists.
8///
9/// This is the interpolation behind
10/// [`TransformOperationsTransition`](crate::animation::TransformOperationsTransition).
11/// It is not registered for any property type, so key frame animations do
12/// not select it.
13#[derive(Default)]
14pub struct TransformOperationsAnimator;
15
16impl TransformOperationsAnimator {
17    pub fn new() -> Self {
18        Self
19    }
20
21    /// Interpolates between two operation lists using the specified
22    /// progress.
23    pub fn interpolate(
24        &self,
25        progress: f64,
26        old_value: &Rc<TransformOperations>,
27        new_value: &Rc<TransformOperations>,
28    ) -> Rc<TransformOperations> {
29        TransformOperations::interpolate(old_value, new_value, progress)
30    }
31
32    /// The operation list of a transform; the identity when the transform
33    /// is absent or not an operation list.
34    pub(crate) fn ensure_operations(value: &Option<Rc<dyn ITransform>>) -> Rc<TransformOperations> {
35        let Some(value) = value else { return TransformOperations::identity() };
36        match value.as_any().downcast_ref::<TransformOperations>() {
37            Some(operations) => {
38                let mut builder = TransformOperations::create_builder(operations.operations().len());
39                for operation in operations.operations() {
40                    builder.append(operation.clone());
41                }
42                builder.build()
43            }
44            None => TransformOperations::identity(),
45        }
46    }
47
48    /// Validates a key frame: its value must be an operation list.
49    pub fn validate(&self, item: &Ref<AnimatorKeyFrame>) {
50        let valid = item.with_value(|value| {
51            value
52                .and_then(|value| value.downcast_ref::<Option<Rc<dyn ITransform>>>())
53                .and_then(|value| value.as_ref())
54                .is_some_and(|value| value.as_any().is::<TransformOperations>())
55        });
56        if !valid {
57            panic!("{} must have a value of type TransformOperations.", **item);
58        }
59    }
60}