mod morph;
pub use morph::{build_morph, sample, sample_layout, MorphTransition};
use uzor::ui::animation::math::timeline::Animatable;
#[derive(Debug, Clone, PartialEq)]
pub struct GlyphState {
pub ch: String,
pub pos: (f64, f64),
pub opacity: f32,
pub scale: f32,
pub rotation: f32,
}
impl Animatable for GlyphState {
fn lerp(&self, target: &Self, t: f64) -> Self {
GlyphState {
ch: self.ch.clone(),
pos: self.pos.lerp(&target.pos, t),
opacity: self.opacity.lerp(&target.opacity, t),
scale: self.scale.lerp(&target.scale, t),
rotation: self.rotation.lerp(&target.rotation, t),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lerp_at_zero_and_one_returns_the_endpoints_exactly() {
let a = GlyphState { ch: "x".to_owned(), pos: (0.0, 0.0), opacity: 1.0, scale: 1.0, rotation: 0.0 };
let b = GlyphState { ch: "x".to_owned(), pos: (10.0, 20.0), opacity: 0.0, scale: 2.0, rotation: 0.5 };
let at0 = a.lerp(&b, 0.0);
assert_eq!(at0.pos, a.pos);
assert_eq!(at0.opacity, a.opacity);
assert_eq!(at0.scale, a.scale);
let at1 = a.lerp(&b, 1.0);
assert_eq!(at1.pos, b.pos);
assert_eq!(at1.opacity, b.opacity);
assert_eq!(at1.scale, b.scale);
}
#[test]
fn lerp_at_half_is_the_midpoint() {
let a = GlyphState { ch: "x".to_owned(), pos: (0.0, 0.0), opacity: 0.0, scale: 1.0, rotation: 0.0 };
let b = GlyphState { ch: "x".to_owned(), pos: (10.0, 20.0), opacity: 1.0, scale: 1.0, rotation: 0.0 };
let mid = a.lerp(&b, 0.5);
assert_eq!(mid.pos, (5.0, 10.0));
assert!((mid.opacity - 0.5).abs() < 1e-6);
}
}