Skip to main content

use_ui_motion/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4/// Motion duration in milliseconds.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
6pub struct MotionDuration(u32);
7
8impl MotionDuration {
9    pub fn from_millis(value: u32) -> Self {
10        Self(value)
11    }
12
13    pub fn millis(self) -> u32 {
14        self.0
15    }
16
17    pub fn is_instant(self) -> bool {
18        self.0 == 0
19    }
20}
21
22/// Semantic motion curve.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
24pub enum MotionCurve {
25    Linear,
26    Ease,
27    EaseIn,
28    EaseOut,
29    EaseInOut,
30}
31
32/// User motion preference.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
34pub enum MotionPreference {
35    NoPreference,
36    Reduced,
37}
38
39impl MotionPreference {
40    pub fn allows_motion(self) -> bool {
41        matches!(self, Self::NoPreference)
42    }
43}
44
45/// Easing metadata.
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub struct Easing {
48    curve: MotionCurve,
49    duration: MotionDuration,
50}
51
52impl Easing {
53    pub fn new(curve: MotionCurve, duration: MotionDuration) -> Self {
54        Self { curve, duration }
55    }
56
57    pub fn curve(self) -> MotionCurve {
58        self.curve
59    }
60
61    pub fn duration(self) -> MotionDuration {
62        self.duration
63    }
64}
65
66/// Transition intent.
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
68pub enum TransitionKind {
69    Enter,
70    Exit,
71    Move,
72    Resize,
73    Fade,
74    Scale,
75}
76
77/// Runtime-independent animation state labels.
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
79pub enum AnimationState {
80    Idle,
81    Pending,
82    Running,
83    Paused,
84    Finished,
85    Cancelled,
86}
87
88impl AnimationState {
89    pub fn is_terminal(self) -> bool {
90        matches!(self, Self::Finished | Self::Cancelled)
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::{AnimationState, Easing, MotionCurve, MotionDuration, MotionPreference};
97
98    #[test]
99    fn checks_motion_helpers() {
100        let duration = MotionDuration::from_millis(150);
101        let easing = Easing::new(MotionCurve::EaseOut, duration);
102
103        assert_eq!(duration.millis(), 150);
104        assert!(!duration.is_instant());
105        assert!(MotionDuration::from_millis(0).is_instant());
106        assert_eq!(easing.curve(), MotionCurve::EaseOut);
107        assert_eq!(easing.duration(), duration);
108    }
109
110    #[test]
111    fn checks_motion_preference_and_state() {
112        assert!(MotionPreference::NoPreference.allows_motion());
113        assert!(!MotionPreference::Reduced.allows_motion());
114        assert!(AnimationState::Finished.is_terminal());
115        assert!(!AnimationState::Running.is_terminal());
116    }
117}