Skip to main content

dioxus_motion/
keyframes.rs

1use crate::Duration;
2use crate::animations::core::Animatable;
3use tracing::error;
4
5pub type EasingFn = fn(f32, f32, f32, f32) -> f32;
6
7#[derive(Debug, thiserror::Error)]
8pub enum KeyframeError {
9    #[error("Failed to compare keyframe offsets (possible NaN value)")]
10    InvalidOffset,
11}
12
13#[derive(Clone)]
14pub struct Keyframe<T: Animatable> {
15    pub value: T,
16    pub offset: f32,
17    pub easing: Option<EasingFn>,
18}
19
20#[derive(Clone)]
21pub struct KeyframeAnimation<T: Animatable> {
22    pub keyframes: Vec<Keyframe<T>>,
23    pub duration: Duration,
24}
25
26impl<T: Animatable> KeyframeAnimation<T> {
27    pub fn new(duration: Duration) -> Self {
28        Self {
29            keyframes: Vec::new(),
30            duration,
31        }
32    }
33
34    pub fn add_keyframe(
35        mut self,
36        value: T,
37        offset: f32,
38        easing: Option<EasingFn>,
39    ) -> Result<Self, KeyframeError> {
40        self.keyframes.push(Keyframe {
41            value,
42            offset: offset.clamp(0.0, 1.0),
43            easing,
44        });
45        self.keyframes.sort_by(|a, b| {
46            a.offset.partial_cmp(&b.offset).unwrap_or_else(|| {
47                error!(
48                    "Failed to compare keyframe offsets: {} vs {}",
49                    a.offset, b.offset
50                );
51                std::cmp::Ordering::Equal
52            })
53        });
54        if self.keyframes.iter().any(|k| k.offset.is_nan()) {
55            error!("Keyframe sorting failed: InvalidOffset (NaN offset)");
56            return Err(KeyframeError::InvalidOffset);
57        }
58        Ok(self)
59    }
60}