Skip to main content

ferroui_base/rendering/composition/interactions/
interaction_tracker_inertia_modifier.rs

1//! The inertia modifiers of an [`InteractionTracker`](super::InteractionTracker):
2//! `InteractionTrackerInertiaModifier` and its subclasses.
3
4use crate::rendering::composition::animations::ExpressionAnimation;
5use crate::rendering::composition::Compositor;
6use std::cell::RefCell;
7use std::rc::Rc;
8
9/// A modifier of the inertia of one axis of an interaction tracker
10/// (`InteractionTrackerInertiaModifier`): what
11/// [`configure_position_x_inertia_modifiers`](super::InteractionTracker::configure_position_x_inertia_modifiers)
12/// and its siblings take.
13///
14/// When the tracker enters inertia it evaluates the conditions of the
15/// modifiers of an axis in order; the first modifier whose condition is
16/// `true` applies to the axis for the whole inertia.
17///
18/// Deviation (winui-composition.md): WinUI also has
19/// `InteractionTrackerInertiaNaturalMotion`, which runs a
20/// `ScalarNaturalMotionAnimation`; the natural motion animations are not
21/// ported yet, so that subclass is missing.
22#[derive(Clone)]
23pub enum InteractionTrackerInertiaModifier {
24    /// `InteractionTrackerInertiaRestingValue`: replaces the resting value.
25    RestingValue(Rc<InteractionTrackerInertiaRestingValue>),
26    /// `InteractionTrackerInertiaMotion`: replaces the motion.
27    Motion(Rc<InteractionTrackerInertiaMotion>),
28}
29
30impl InteractionTrackerInertiaModifier {
31    /// The condition of the modifier.
32    pub fn condition(&self) -> Option<Rc<ExpressionAnimation>> {
33        match self {
34            Self::RestingValue(modifier) => modifier.condition(),
35            Self::Motion(modifier) => modifier.condition(),
36        }
37    }
38}
39
40impl From<Rc<InteractionTrackerInertiaRestingValue>> for InteractionTrackerInertiaModifier {
41    fn from(value: Rc<InteractionTrackerInertiaRestingValue>) -> Self {
42        Self::RestingValue(value)
43    }
44}
45
46impl From<Rc<InteractionTrackerInertiaMotion>> for InteractionTrackerInertiaModifier {
47    fn from(value: Rc<InteractionTrackerInertiaMotion>) -> Self {
48        Self::Motion(value)
49    }
50}
51
52/// An inertia modifier that changes where the inertia comes to rest
53/// (`InteractionTrackerInertiaRestingValue`): when `Condition` is `true`,
54/// the axis comes to rest at the value of `RestingValue`, evaluated once
55/// when the inertia starts.
56///
57/// Both expressions read the tracker as `this.Target`
58/// (`this.Target.NaturalRestingPosition.X`, `this.Target.Position`, ...).
59pub struct InteractionTrackerInertiaRestingValue {
60    compositor: Rc<Compositor>,
61    condition: RefCell<Option<Rc<ExpressionAnimation>>>,
62    resting_value: RefCell<Option<Rc<ExpressionAnimation>>>,
63}
64
65impl InteractionTrackerInertiaRestingValue {
66    /// `InteractionTrackerInertiaRestingValue.Create(compositor)`.
67    pub fn create(compositor: &Rc<Compositor>) -> Rc<InteractionTrackerInertiaRestingValue> {
68        Rc::new(InteractionTrackerInertiaRestingValue {
69            compositor: compositor.clone(),
70            condition: RefCell::new(None),
71            resting_value: RefCell::new(None),
72        })
73    }
74
75    /// The compositor of the modifier.
76    pub fn compositor(&self) -> &Rc<Compositor> {
77        &self.compositor
78    }
79
80    /// The expression that decides whether the modifier applies: a
81    /// boolean expression.
82    pub fn condition(&self) -> Option<Rc<ExpressionAnimation>> {
83        self.condition.borrow().clone()
84    }
85
86    pub fn set_condition(&self, value: Option<Rc<ExpressionAnimation>>) {
87        *self.condition.borrow_mut() = value;
88    }
89
90    /// The expression of the resting value of the axis: a scalar
91    /// expression.
92    pub fn resting_value(&self) -> Option<Rc<ExpressionAnimation>> {
93        self.resting_value.borrow().clone()
94    }
95
96    pub fn set_resting_value(&self, value: Option<Rc<ExpressionAnimation>>) {
97        *self.resting_value.borrow_mut() = value;
98    }
99}
100
101/// An inertia modifier that replaces the motion of the inertia
102/// (`InteractionTrackerInertiaMotion`): when `Condition` is `true`, the
103/// value of the axis is the value of `Motion`, evaluated every frame of the
104/// inertia, until it stops changing.
105///
106/// Deviation (winui-composition.md): WinUI does not document what the value
107/// of `Motion` is; here it is the value of the axis for the frame (a
108/// position for the position axes, a scale for the scale axis).
109pub struct InteractionTrackerInertiaMotion {
110    compositor: Rc<Compositor>,
111    condition: RefCell<Option<Rc<ExpressionAnimation>>>,
112    motion: RefCell<Option<Rc<ExpressionAnimation>>>,
113}
114
115impl InteractionTrackerInertiaMotion {
116    /// `InteractionTrackerInertiaMotion.Create(compositor)`.
117    pub fn create(compositor: &Rc<Compositor>) -> Rc<InteractionTrackerInertiaMotion> {
118        Rc::new(InteractionTrackerInertiaMotion {
119            compositor: compositor.clone(),
120            condition: RefCell::new(None),
121            motion: RefCell::new(None),
122        })
123    }
124
125    /// The compositor of the modifier.
126    pub fn compositor(&self) -> &Rc<Compositor> {
127        &self.compositor
128    }
129
130    /// The expression that decides whether the modifier applies: a
131    /// boolean expression.
132    pub fn condition(&self) -> Option<Rc<ExpressionAnimation>> {
133        self.condition.borrow().clone()
134    }
135
136    pub fn set_condition(&self, value: Option<Rc<ExpressionAnimation>>) {
137        *self.condition.borrow_mut() = value;
138    }
139
140    /// The expression of the motion: a scalar expression.
141    pub fn motion(&self) -> Option<Rc<ExpressionAnimation>> {
142        self.motion.borrow().clone()
143    }
144
145    pub fn set_motion(&self, value: Option<Rc<ExpressionAnimation>>) {
146        *self.motion.borrow_mut() = value;
147    }
148}