Skip to main content

eazy_tweener/
control.rs

1//! Playback control interface for animations.
2//!
3//! Defines the [`Controllable`] trait shared by [`Tween`] and [`Timeline`],
4//! providing a unified interface for playback control.
5
6/// The current state of an animation.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub enum TweenState {
9  /// Animation has not started or has been reset.
10  #[default]
11  Idle,
12  /// Animation is actively playing.
13  Playing,
14  /// Animation is paused and can be resumed.
15  Paused,
16  /// Animation has finished playing.
17  Complete,
18}
19
20impl TweenState {
21  /// Check if the animation is currently active (playing).
22  pub fn is_active(&self) -> bool {
23    matches!(self, Self::Playing)
24  }
25
26  /// Check if the animation has completed.
27  pub fn is_complete(&self) -> bool {
28    matches!(self, Self::Complete)
29  }
30
31  /// Check if the animation is paused.
32  pub fn is_paused(&self) -> bool {
33    matches!(self, Self::Paused)
34  }
35
36  /// Check if the animation is idle (not started or reset).
37  pub fn is_idle(&self) -> bool {
38    matches!(self, Self::Idle)
39  }
40}
41
42/// The playback direction of an animation.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
44pub enum Direction {
45  /// Playing forward (from → to).
46  #[default]
47  Forward,
48  /// Playing in reverse (to → from).
49  Reverse,
50}
51
52impl Direction {
53  /// Toggle the direction.
54  pub fn toggle(&mut self) {
55    *self = match self {
56      Self::Forward => Self::Reverse,
57      Self::Reverse => Self::Forward,
58    };
59  }
60
61  /// Check if playing forward.
62  pub fn is_forward(&self) -> bool {
63    matches!(self, Self::Forward)
64  }
65
66  /// Check if playing in reverse.
67  pub fn is_reverse(&self) -> bool {
68    matches!(self, Self::Reverse)
69  }
70
71  /// Get the time direction multiplier.
72  ///
73  /// Returns 1.0 for forward, -1.0 for reverse.
74  pub fn multiplier(&self) -> f32 {
75    match self {
76      Self::Forward => 1.0,
77      Self::Reverse => -1.0,
78    }
79  }
80}
81
82impl std::ops::Not for Direction {
83  type Output = Self;
84
85  fn not(self) -> Self::Output {
86    match self {
87      Self::Forward => Self::Reverse,
88      Self::Reverse => Self::Forward,
89    }
90  }
91}
92
93/// Shared interface for controllable animations.
94///
95/// Both [`Tween`] and [`Timeline`] implement this trait, allowing
96/// unified control over any animation type.
97pub trait Controllable: Send + Sync {
98  /// Start or resume playback.
99  fn play(&mut self);
100
101  /// Pause playback at the current position.
102  fn pause(&mut self);
103
104  /// Resume from a paused state.
105  fn resume(&mut self);
106
107  /// Toggle the playback direction.
108  fn reverse(&mut self);
109
110  /// Reset to the beginning and start playing.
111  fn restart(&mut self);
112
113  /// Jump to a specific time position.
114  fn seek(&mut self, time: f32);
115
116  /// Stop and reset the animation.
117  fn kill(&mut self);
118
119  /// Get the current progress as a normalized value [0, 1].
120  fn progress(&self) -> f32;
121
122  /// Set the progress directly [0, 1].
123  fn set_progress(&mut self, progress: f32);
124
125  /// Get the total duration in seconds.
126  fn duration(&self) -> f32;
127
128  /// Get the current elapsed time.
129  fn elapsed(&self) -> f32;
130
131  /// Get the current state.
132  fn state(&self) -> TweenState;
133
134  /// Get the current playback direction.
135  fn direction(&self) -> Direction;
136
137  /// Get the time scale multiplier.
138  fn time_scale(&self) -> f32;
139
140  /// Set the time scale multiplier.
141  fn set_time_scale(&mut self, scale: f32);
142
143  /// Advance the animation by delta time.
144  ///
145  /// Returns `true` if the animation is still active after the tick.
146  fn tick(&mut self, delta: f32) -> bool;
147}
148
149#[cfg(test)]
150mod tests {
151  use super::*;
152
153  #[test]
154  fn test_tween_state() {
155    assert!(TweenState::Playing.is_active());
156    assert!(!TweenState::Paused.is_active());
157    assert!(TweenState::Complete.is_complete());
158    assert!(TweenState::Idle.is_idle());
159  }
160
161  #[test]
162  fn test_direction_toggle() {
163    let mut dir = Direction::Forward;
164
165    dir.toggle();
166    assert!(dir.is_reverse());
167
168    dir.toggle();
169    assert!(dir.is_forward());
170  }
171
172  #[test]
173  fn test_direction_multiplier() {
174    assert_eq!(Direction::Forward.multiplier(), 1.0);
175    assert_eq!(Direction::Reverse.multiplier(), -1.0);
176  }
177
178  #[test]
179  fn test_direction_not() {
180    assert_eq!(!Direction::Forward, Direction::Reverse);
181    assert_eq!(!Direction::Reverse, Direction::Forward);
182  }
183}