use crate::{AnimationHandle, Duration};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ActiveStateTransition<S>
where
S: Copy + Eq,
{
handle: AnimationHandle,
from: S,
to: S,
started_at: Duration,
duration: Option<Duration>,
}
impl<S> ActiveStateTransition<S>
where
S: Copy + Eq,
{
pub(crate) const fn new(
handle: AnimationHandle,
from: S,
to: S,
started_at: Duration,
duration: Option<Duration>,
) -> Self {
Self {
handle,
from,
to,
started_at,
duration,
}
}
#[must_use]
pub const fn handle(&self) -> AnimationHandle {
self.handle
}
#[must_use]
pub const fn from(&self) -> S {
self.from
}
#[must_use]
pub const fn to(&self) -> S {
self.to
}
#[must_use]
pub const fn started_at(&self) -> Duration {
self.started_at
}
#[must_use]
pub const fn duration(&self) -> Option<Duration> {
self.duration
}
#[must_use]
pub fn progress_at(&self, timestamp: Duration) -> StateTransitionProgress<S> {
let elapsed = timestamp
.checked_sub(self.started_at)
.unwrap_or(Duration::ZERO);
let progress = self
.duration
.map(|duration| normalized_progress(elapsed, duration));
StateTransitionProgress {
handle: self.handle,
from: self.from,
to: self.to,
elapsed,
duration: self.duration,
progress,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StateTransitionProgress<S>
where
S: Copy + Eq,
{
handle: AnimationHandle,
from: S,
to: S,
elapsed: Duration,
duration: Option<Duration>,
progress: Option<f32>,
}
impl<S> StateTransitionProgress<S>
where
S: Copy + Eq,
{
#[must_use]
pub const fn handle(&self) -> AnimationHandle {
self.handle
}
#[must_use]
pub const fn from(&self) -> S {
self.from
}
#[must_use]
pub const fn to(&self) -> S {
self.to
}
#[must_use]
pub const fn elapsed(&self) -> Duration {
self.elapsed
}
#[must_use]
pub const fn duration(&self) -> Option<Duration> {
self.duration
}
#[must_use]
pub const fn progress(&self) -> Option<f32> {
self.progress
}
}
fn normalized_progress(elapsed: Duration, duration: Duration) -> f32 {
let duration_ms = duration.as_millis();
if duration_ms <= 0.0 {
return 1.0;
}
#[allow(
clippy::cast_possible_truncation,
reason = "State transition progress is normalized for UI consumption."
)]
{
(elapsed.as_millis() / duration_ms).clamp(0.0, 1.0) as f32
}
}