ranim_core/
animation.rs

1//! Evaluation and animation
2//!
3//! The evaluation core of an animation is a `E: Eval<T>`.
4//!
5//! When constructing an animation, we need [`AnimationInfo`] besides the evaluation core, which is
6//! [`AnimationCell<T>`].
7//!
8//! When satisfies `T: Extract<Target = CoreItem>`, [`AnimationCell<T>`] can be converted to a [`CoreItemAnimation`].
9
10use crate::{
11    core_item::{AnyExtractCoreItem, CoreItem, DynItem},
12    utils::rate_functions::linear,
13};
14
15use std::fmt::Debug;
16
17// MARK: Eval
18// ANCHOR: Eval-eval_alpha
19// ANCHOR: Eval
20/// This is the core of any animation, an animation is basically a function on time.
21///
22/// This represents a normalized animation function for type `T`, which accepts
23/// a progress value `alpha` in range [0, 1] and returns the evaluation result in type `T`.
24pub trait Eval<T> {
25    /// Evaluates at the given progress value `alpha` in range [0, 1].
26    fn eval_alpha(&self, alpha: f64) -> T;
27    // ANCHOR_END: Eval-eval_alpha
28    /// Construct an [`AnimationCell<T>`] with default [`AnimationInfo`]
29    fn into_animation_cell(self) -> AnimationCell<T>
30    where
31        Self: Sized + 'static,
32    {
33        AnimationCell {
34            inner: Box::new(self),
35            info: AnimationInfo::default(),
36            anim_name: std::any::type_name::<Self>().to_string(),
37        }
38    }
39}
40// ANCHOR_END: Eval
41
42// MARK: AnimationInfo
43// ANCHOR: AnimationInfo
44/// Info of an animation.
45///
46/// When [`AnimationInfo::enabled`] is `false`, the animation will not be evaluated.
47#[derive(Debug, Clone)]
48pub struct AnimationInfo {
49    /// The rate function used for evaluating, default value: [`linear`]
50    pub rate_func: fn(f64) -> f64,
51    /// Start sec, default value: 0.0
52    pub start_sec: f64,
53    /// The duration seconds, default value: 1.0
54    pub duration_secs: f64,
55    /// Is enabled, default value: true
56    pub enabled: bool,
57}
58
59impl Default for AnimationInfo {
60    fn default() -> Self {
61        Self {
62            rate_func: linear,
63            start_sec: 0.0,
64            duration_secs: 1.0,
65            enabled: true,
66        }
67    }
68}
69// ANCHOR_END: AnimationInfo
70
71impl AnimationInfo {
72    /// Get the range of the animation
73    pub fn range(&self) -> std::ops::Range<f64> {
74        self.start_sec..self.start_sec + self.duration_secs
75    }
76    /// Get the inclusive range of the animation
77    pub fn range_inclusive(&self) -> std::ops::RangeInclusive<f64> {
78        self.start_sec..=self.start_sec + self.duration_secs
79    }
80    // ANCHOR: AnimationInfo-map_alpha
81    /// Map the outer alpha to inner alpha
82    pub fn map_alpha(&self, alpha: f64) -> f64 {
83        (self.rate_func)(alpha)
84    }
85    // ANCHOR_END: AnimationInfo-map_alpha
86    // ANCHOR: AnimationInfo-map_sec_to_alpha
87    /// Map the global sec to outer alpha
88    ///
89    /// note that this uses a range_inclusive
90    pub fn map_sec_to_alpha(&self, sec: f64) -> Option<f64> {
91        if self.range_inclusive().contains(&sec) {
92            let alpha = (sec - self.start_sec) / self.duration_secs;
93            let alpha = if alpha.is_nan() { 1.0 } else { alpha };
94            Some(alpha)
95        } else {
96            None
97        }
98    }
99    // ANCHOR_END: AnimationInfo-map_sec_to_alpha
100}
101
102impl AnimationInfo {
103    /// A builder func to modify [`AnimationInfo::start_sec`]
104    pub fn at(mut self, at_sec: f64) -> Self {
105        self.start_sec = at_sec;
106        self
107    }
108    /// A builder func to modify [`AnimationInfo::rate_func`]
109    pub fn with_rate_func(mut self, rate_func: fn(f64) -> f64) -> Self {
110        self.rate_func = rate_func;
111        self
112    }
113    /// A builder func to modify [`AnimationInfo::duration_secs`]
114    pub fn with_duration(mut self, secs: f64) -> Self {
115        self.duration_secs = secs;
116        self
117    }
118    /// A builder func to modify [`AnimationInfo::enabled`]
119    pub fn with_enabled(mut self, enabled: bool) -> Self {
120        self.enabled = enabled;
121        self
122    }
123}
124
125// MARK: AnimationCell
126// ANCHOR: AnimationCell
127/// A cell of an animation
128pub struct AnimationCell<T> {
129    inner: Box<dyn Eval<T>>,
130    /// The animation info
131    pub info: AnimationInfo,
132    // ANCHOR_END: AnimationCell
133    anim_name: String,
134}
135
136impl<T> AnimationCell<T> {
137    /// A builder func to modify [`AnimationInfo::start_sec`]
138    pub fn at(mut self, at_sec: f64) -> Self {
139        self.info = self.info.at(at_sec);
140        self
141    }
142    /// A builder func to modify [`AnimationInfo::rate_func`]
143    pub fn with_rate_func(mut self, rate_func: fn(f64) -> f64) -> Self {
144        self.info = self.info.with_rate_func(rate_func);
145        self
146    }
147    /// A builder func to modify [`AnimationInfo::duration_secs`]
148    pub fn with_duration(mut self, duration_secs: f64) -> Self {
149        self.info = self.info.with_duration(duration_secs);
150        self
151    }
152    /// A builder func to modify [`AnimationInfo::enabled`]
153    pub fn with_enabled(mut self, enabled: bool) -> Self {
154        self.info = self.info.with_enabled(enabled);
155        self
156    }
157    /// Apply the animation to the item and return the animation itself
158    pub fn apply_to(self, item: &mut T) -> Self {
159        self.apply_alpha_to(item, 1.0)
160    }
161    /// Apply the animation to the item at the given alpha and return the animation itself
162    pub fn apply_alpha_to(self, item: &mut T, alpha: f64) -> Self {
163        *item = self.eval_alpha(alpha);
164        self
165    }
166}
167
168// ANCHOR: AnimationCell-Eval
169impl<T> Eval<T> for AnimationCell<T> {
170    fn eval_alpha(&self, alpha: f64) -> T {
171        self.inner.eval_alpha(self.info.map_alpha(alpha))
172    }
173}
174// ANCHOR_END: AnimationCell-Eval
175
176// MARK: CoreItemAnimation
177/// Animation of core items.
178pub trait CoreItemAnimation {
179    /// Get the animation info
180    fn anim_info(&self) -> &AnimationInfo;
181    /// Get the name of the animation
182    fn anim_name(&self) -> &str;
183    /// Evaluate to [`DynItem`]
184    fn eval_alpha_dyn(&self, alpha: f64) -> DynItem;
185    /// Evaluate to [`DynItem`] at global sec
186    fn eval_global_sec_dyn(&self, sec: f64) -> Option<DynItem> {
187        self.anim_info()
188            .map_sec_to_alpha(sec)
189            .map(|alpha| self.eval_alpha_dyn(alpha))
190    }
191    /// Evaluate to [`CoreItem`]s
192    fn eval_alpha_core_item(&self, alpha: f64) -> Vec<CoreItem>;
193    /// Evaluate to [`CoreItem`]s at global sec
194    fn eval_global_sec_core_item(&self, sec: f64) -> Option<Vec<CoreItem>> {
195        self.anim_info()
196            .map_sec_to_alpha(sec)
197            .map(|alpha| self.eval_alpha_core_item(alpha))
198    }
199}
200
201// ANCHOR: AnimationCell-CoreItemAnimation
202// ANCHOR: AnimationCell-CoreItemAnimation-eval_alpha
203impl<T: AnyExtractCoreItem> CoreItemAnimation for AnimationCell<T> {
204    fn eval_alpha_dyn(&self, alpha: f64) -> DynItem {
205        DynItem(Box::new(self.eval_alpha(alpha)))
206    }
207    fn eval_alpha_core_item(&self, alpha: f64) -> Vec<CoreItem> {
208        self.eval_alpha(alpha).extract()
209    }
210    // ANCHOR_END: AnimationCell-CoreItemAnimation-eval_alpha
211    fn anim_info(&self) -> &AnimationInfo {
212        &self.info
213    }
214    fn anim_name(&self) -> &str {
215        &self.anim_name
216    }
217}
218// ANCHOR_END: AnimationCell-CoreItemAnimation
219
220// MARK: StaticAnim
221/// The requirement for [`StaticAnim`]
222pub trait StaticAnimRequirement: Clone {}
223
224impl<T: Clone> StaticAnimRequirement for T {}
225
226/// The helper methods for [`Static`], i.e. evaluates to the same value
227pub trait StaticAnim: StaticAnimRequirement {
228    /// Show the item
229    fn show(&self) -> AnimationCell<Self>;
230    /// Hide the item
231    fn hide(&self) -> AnimationCell<Self>;
232}
233
234impl<T: StaticAnimRequirement + 'static> StaticAnim for T {
235    fn show(&self) -> AnimationCell<Self> {
236        Static(self.clone())
237            .into_animation_cell()
238            .with_duration(0.0)
239    }
240    fn hide(&self) -> AnimationCell<Self> {
241        Static(self.clone())
242            .into_animation_cell()
243            .with_enabled(false)
244            .with_duration(0.0)
245    }
246}
247
248// ANCHOR: Static
249/// A static animation.
250pub struct Static<T>(pub T);
251
252impl<T: Clone> Eval<T> for Static<T> {
253    fn eval_alpha(&self, _alpha: f64) -> T {
254        self.0.clone()
255    }
256}
257// ANCHOR_END: Static