ferroui_base/rendering/composition/animations/i_animation_instance.rs
1use crate::rendering::composition::expressions::ExpressionVariant;
2use crate::rendering::composition::server::{CompositionProperty, IServerClockItem, ServerCompositor, ServerObjectId};
3use std::rc::Rc;
4use std::time::Duration;
5
6/// A running animation of one property of a server object.
7///
8/// An instance is created on the UI thread by the animation it belongs to,
9/// crosses to the server in the batch that starts it, and is driven there.
10/// It names its target, and the objects its reference parameters refer to,
11/// by id: the UI thread never holds a server object. The ids are resolved
12/// on the server by [`resolve`](Self::resolve), which the animations of the
13/// target call before [`initialize`](Self::initialize).
14pub trait IAnimationInstance: IServerClockItem + 'static {
15 /// The object whose property is animated.
16 fn target_object(&self) -> ServerObjectId;
17
18 /// Resolves the server objects the instance refers to by id, on the
19 /// compositor that drives it. Called once, on the server, before the
20 /// instance is initialized; an instance that refers to no object needs
21 /// nothing.
22 fn resolve(&self, _compositor: &Rc<ServerCompositor>) {}
23
24 /// The value of the animation at `now`.
25 fn evaluate(&self, now: Duration, current_value: ExpressionVariant) -> ExpressionVariant;
26
27 /// Attaches the instance to the property it animates.
28 fn initialize(&self, started_at: Duration, starting_value: ExpressionVariant, property: &'static CompositionProperty);
29
30 fn activate(&self);
31
32 fn deactivate(&self);
33
34 fn invalidate(&self);
35
36 /// The value the animated property is set to when the animation is
37 /// stopped by `StopAnimation` (its stop behavior), given the current
38 /// value of the property; `None` leaves the current value.
39 fn value_on_stop(&self, _current_value: ExpressionVariant) -> Option<ExpressionVariant> {
40 None
41 }
42
43 /// Tells the batches the animation belongs to that it is over (it is
44 /// stopped, replaced or its target is disposed). Releasing again does
45 /// nothing; an animation that belongs to no batch does nothing.
46 fn release_completion(&self) {}
47
48 /// Puts the instance under the control of an
49 /// [`AnimationController`](super::AnimationController), named by the id of
50 /// the controller's property set: from now on the controller pauses,
51 /// resumes, scrubs and speeds up the animation; if the progress of the
52 /// controller was assigned, the animation moves there at its next
53 /// evaluation. An instance that cannot be controlled (an expression
54 /// animation) ignores it.
55 fn attach_controller(&self, _controller: ServerObjectId) {}
56
57 /// The instance as an animation of components of its property
58 /// (`Offset.X`), if it is one: such animations of one property are
59 /// merged on the server.
60 fn as_subchannel(&self) -> Option<&super::SubchannelAnimationInstance> {
61 None
62 }
63}
64
65/// An animation instance on its way to the server.
66///
67/// An instance belongs to the server: it resolves server objects and keeps
68/// its state in cells, so it cannot cross threads. What the UI thread
69/// creates and a batch carries is the factory of the instance, which holds
70/// what the instance is made of (all of it `Send`) and is called on the
71/// server.
72pub struct AnimationInstanceFactory(Box<dyn FnOnce() -> Rc<dyn IAnimationInstance> + Send>);
73
74impl AnimationInstanceFactory {
75 pub fn new(create: impl FnOnce() -> Rc<dyn IAnimationInstance> + Send + 'static) -> Self {
76 Self(Box::new(create))
77 }
78
79 /// Creates the instance. Called on the thread that runs it.
80 pub fn create(self) -> Rc<dyn IAnimationInstance> {
81 (self.0)()
82 }
83}