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;
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}
18
19impl ExpressionAnimationInstance {
20    pub fn new(
21        expression: std::sync::Arc<Expression>,
22        target: ServerObjectId,
23        final_value: Option<ExpressionVariant>,
24        parameters: Rc<PropertySetSnapshot>,
25    ) -> Rc<ExpressionAnimationInstance> {
26        Rc::new_cyclic(|this: &Weak<ExpressionAnimationInstance>| ExpressionAnimationInstance {
27            base: AnimationInstanceBase::new(this.clone(), target, parameters),
28            expression,
29            starting_value: Cell::new(ExpressionVariant::default()),
30            final_value,
31        })
32    }
33
34    fn evaluate_core(&self, _now: Duration, current_value: ExpressionVariant) -> ExpressionVariant {
35        let starting_value = self.starting_value.get();
36        self.base.with_target_expression_object(|target| {
37            let ctx = ExpressionEvaluationContext {
38                parameters: Some(&**self.base.parameters()),
39                target,
40                foreign_function_interface: Some(BuiltInExpressionFfi::instance()),
41                starting_value,
42                final_value: self.final_value.unwrap_or(starting_value),
43                current_value,
44            };
45            self.expression.evaluate(&ctx)
46        })
47    }
48}
49
50impl IServerClockItem for ExpressionAnimationInstance {
51    fn on_tick(&self) {
52        self.base.on_tick()
53    }
54}
55
56impl IAnimationInstance for ExpressionAnimationInstance {
57    fn target_object(&self) -> ServerObjectId {
58        self.base.target_object()
59    }
60
61    fn resolve(&self, compositor: &Rc<ServerCompositor>) {
62        self.base.resolve(compositor)
63    }
64
65    fn evaluate(&self, now: Duration, current_value: ExpressionVariant) -> ExpressionVariant {
66        self.base.begin_evaluate();
67        self.evaluate_core(now, current_value)
68    }
69
70    fn initialize(&self, _started_at: Duration, starting_value: ExpressionVariant, property: &'static CompositionProperty) {
71        self.starting_value.set(starting_value);
72        let mut hs = HashSet::new();
73        self.expression.collect_references(&mut hs);
74        self.base.initialize(property, &hs);
75    }
76
77    fn activate(&self) {
78        self.base.activate()
79    }
80
81    fn deactivate(&self) {
82        self.base.deactivate()
83    }
84
85    fn invalidate(&self) {
86        self.base.invalidate()
87    }
88}