use std::time::{Duration, Instant};
use super::{AnimationState, EasingFn};
use crate::style::animation::easing;
#[derive(Clone)]
pub struct Tween {
pub from: f32,
pub to: f32,
pub duration: Duration,
easing: EasingFn,
start_time: Option<Instant>,
pause_time: Option<Instant>,
state: AnimationState,
pub delay: Duration,
pub repeat: u32,
repeat_count: u32,
pub reverse: bool,
current_direction: bool, }
impl Tween {
pub fn new(from: f32, to: f32, duration: Duration) -> Self {
Self {
from,
to,
duration,
easing: easing::linear,
start_time: None,
pause_time: None,
state: AnimationState::Pending,
delay: Duration::ZERO,
repeat: 0,
repeat_count: 0,
reverse: false,
current_direction: false,
}
}
pub fn easing(mut self, easing: EasingFn) -> Self {
self.easing = easing;
self
}
pub fn delay(mut self, delay: Duration) -> Self {
self.delay = delay;
self
}
pub fn repeat(mut self, count: u32) -> Self {
self.repeat = count;
self
}
pub fn reverse(mut self, reverse: bool) -> Self {
self.reverse = reverse;
self
}
pub fn start(&mut self) {
self.start_time = Some(Instant::now());
self.state = AnimationState::Running;
self.repeat_count = 0;
self.current_direction = false;
}
pub fn pause(&mut self) {
if self.state == AnimationState::Running {
self.pause_time = Some(Instant::now());
self.state = AnimationState::Paused;
}
}
pub fn resume(&mut self) {
if self.state == AnimationState::Paused {
if let (Some(start), Some(pause)) = (self.start_time, self.pause_time) {
let elapsed_before_pause = pause.duration_since(start);
self.start_time = Some(Instant::now() - elapsed_before_pause);
}
self.pause_time = None;
self.state = AnimationState::Running;
}
}
pub fn reset(&mut self) {
self.start_time = None;
self.pause_time = None;
self.state = AnimationState::Pending;
self.repeat_count = 0;
self.current_direction = false;
}
pub fn state(&self) -> AnimationState {
self.state
}
pub fn is_running(&self) -> bool {
self.state == AnimationState::Running
}
pub fn is_completed(&self) -> bool {
self.state == AnimationState::Completed
}
pub fn value(&mut self) -> f32 {
if self.state == AnimationState::Pending {
return self.from;
}
if self.state != AnimationState::Running {
return if self.current_direction {
self.from
} else {
self.to
};
}
let Some(start) = self.start_time else {
return self.from;
};
let elapsed = start.elapsed();
if elapsed < self.delay {
return self.from;
}
let elapsed_after_delay = elapsed - self.delay;
let progress = elapsed_after_delay.as_secs_f32() / self.duration.as_secs_f32();
if progress >= 1.0 {
if self.repeat > 0 && self.repeat_count < self.repeat {
self.repeat_count += 1;
self.start_time = Some(Instant::now());
if self.reverse {
self.current_direction = !self.current_direction;
}
return if self.current_direction {
self.to
} else {
self.from
};
}
self.state = AnimationState::Completed;
return if self.current_direction {
self.from
} else {
self.to
};
}
let eased = (self.easing)(progress);
if self.current_direction {
self.to + (self.from - self.to) * eased
} else {
self.from + (self.to - self.from) * eased
}
}
pub fn progress(&self) -> f32 {
let Some(start) = self.start_time else {
return 0.0;
};
let elapsed = start.elapsed();
if elapsed < self.delay {
return 0.0;
}
let elapsed_after_delay = elapsed - self.delay;
(elapsed_after_delay.as_secs_f32() / self.duration.as_secs_f32()).clamp(0.0, 1.0)
}
}
impl Default for Tween {
fn default() -> Self {
Self::new(0.0, 1.0, Duration::from_millis(300))
}
}
#[derive(Clone)]
pub struct Animation {
pub name: String,
pub tweens: Vec<Tween>,
}
impl Animation {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
tweens: Vec::new(),
}
}
pub fn tween(mut self, tween: Tween) -> Self {
self.tweens.push(tween);
self
}
pub fn start(&mut self) {
for tween in &mut self.tweens {
tween.start();
}
}
pub fn pause(&mut self) {
for tween in &mut self.tweens {
tween.pause();
}
}
pub fn resume(&mut self) {
for tween in &mut self.tweens {
tween.resume();
}
}
pub fn reset(&mut self) {
for tween in &mut self.tweens {
tween.reset();
}
}
pub fn is_completed(&self) -> bool {
self.tweens.iter().all(|t| t.is_completed())
}
}
pub struct Animations;
impl Animations {
pub fn fade_in(duration: Duration) -> Tween {
Tween::new(0.0, 1.0, duration).easing(easing::ease_out)
}
pub fn fade_out(duration: Duration) -> Tween {
Tween::new(1.0, 0.0, duration).easing(easing::ease_in)
}
pub fn slide_in_left(distance: f32, duration: Duration) -> Tween {
Tween::new(-distance, 0.0, duration).easing(easing::ease_out_cubic)
}
pub fn slide_in_right(distance: f32, duration: Duration) -> Tween {
Tween::new(distance, 0.0, duration).easing(easing::ease_out_cubic)
}
pub fn scale_up(duration: Duration) -> Tween {
Tween::new(0.0, 1.0, duration).easing(easing::back_out)
}
pub fn bounce(duration: Duration) -> Tween {
Tween::new(0.0, 1.0, duration).easing(easing::bounce_out)
}
pub fn pulse(duration: Duration) -> Tween {
Tween::new(1.0, 1.2, duration)
.easing(easing::ease_in_out)
.reverse(true)
.repeat(u32::MAX)
}
}