Skip to main content

ferroui_base/rendering/composition/animations/
expression_animation_instance.rs

1use super::{AnimationInstanceBase, IAnimationInstance, PropertySetSnapshot};
2use crate::rendering::composition::expressions::{
3    BuiltInExpressionFfi, Expression, ExpressionEvaluationContext, ExpressionVariant,
4};
5use crate::rendering::composition::server::{CompositionProperty, IServerClockItem, ServerCompositor, ServerObjectId};
6use std::cell::{Cell, RefCell};
7use std::collections::HashSet;
8use std::rc::{Rc, Weak};
9use std::time::Duration;
10
11/// Server-side counterpart of [`ExpressionAnimation`](super::ExpressionAnimation) with values baked-in.
12pub struct ExpressionAnimationInstance {
13    base: AnimationInstanceBase,
14    expression: std::sync::Arc<Expression>,
15    starting_value: Cell<ExpressionVariant>,
16    final_value: Option<ExpressionVariant>,
17    /// The initial value expressions, applied when the instance is
18    /// initialized.
19    initial_values: RefCell<Vec<(String, Expression)>>,
20}
21
22impl ExpressionAnimationInstance {
23    pub fn new(
24        expression: std::sync::Arc<Expression>,
25        target: ServerObjectId,
26        final_value: Option<ExpressionVariant>,
27        parameters: Rc<PropertySetSnapshot>,
28    ) -> Rc<ExpressionAnimationInstance> {
29        Rc::new_cyclic(|this: &Weak<ExpressionAnimationInstance>| ExpressionAnimationInstance {
30            base: AnimationInstanceBase::new(this.clone(), target, parameters),
31            expression,
32            starting_value: Cell::new(ExpressionVariant::default()),
33            final_value,
34            initial_values: RefCell::new(Vec::new()),
35        })
36    }
37
38    /// Sets the initial value expressions of the animation, applied to the
39    /// target when the instance is initialized.
40    pub fn set_initial_value_expressions(&self, expressions: Vec<(String, Expression)>) {
41        *self.initial_values.borrow_mut() = expressions;
42    }
43
44    fn evaluate_core(&self, _now: Duration, current_value: ExpressionVariant) -> ExpressionVariant {
45        let starting_value = self.starting_value.get();
46        self.base.with_target_expression_object(|target| {
47            let ctx = ExpressionEvaluationContext {
48                parameters: Some(&**self.base.parameters()),
49                target,
50                foreign_function_interface: Some(BuiltInExpressionFfi::instance()),
51                starting_value,
52                final_value: self.final_value.unwrap_or(starting_value),
53                current_value,
54            };
55            self.expression.evaluate(&ctx)
56        })
57    }
58}
59
60impl IServerClockItem for ExpressionAnimationInstance {
61    fn on_tick(&self) {
62        self.base.on_tick()
63    }
64}
65
66impl IAnimationInstance for ExpressionAnimationInstance {
67    fn target_object(&self) -> ServerObjectId {
68        self.base.target_object()
69    }
70
71    fn resolve(&self, compositor: &Rc<ServerCompositor>) {
72        self.base.resolve(compositor)
73    }
74
75    fn evaluate(&self, now: Duration, current_value: ExpressionVariant) -> ExpressionVariant {
76        self.base.begin_evaluate();
77        self.evaluate_core(now, current_value)
78    }
79
80    fn initialize(&self, _started_at: Duration, starting_value: ExpressionVariant, property: &'static CompositionProperty) {
81        let initial_values = std::mem::take(&mut *self.initial_values.borrow_mut());
82        let starting_value = self.base.apply_initial_values(&initial_values, property, starting_value);
83        self.starting_value.set(starting_value);
84        let mut hs = HashSet::new();
85        self.expression.collect_references(&mut hs);
86        self.base.initialize(property, &hs);
87    }
88
89    fn activate(&self) {
90        self.base.activate()
91    }
92
93    fn deactivate(&self) {
94        self.base.deactivate()
95    }
96
97    fn invalidate(&self) {
98        self.base.invalidate()
99    }
100}