pierro/widget/
animation.rs

1
2use crate::{Color, Id, Vec2, UI};
3
4pub trait Animatable: Copy + Clone + Default {
5
6    fn similar(&self, other: Self) -> bool;
7    fn lerp(&self, other: Self, t: f32) -> Self;
8
9}
10
11#[derive(Default)]
12struct AnimationState<T: Animatable>(T);
13
14pub fn animate<T: Animatable + 'static>(ui: &mut UI, node: Id, target: T, rate: f32) -> T {
15    if !ui.memory().has::<AnimationState<T>>(node) {
16        ui.memory().get::<AnimationState<T>>(node).0 = target;
17        return target;
18    }
19
20    let state = ui.memory().get::<AnimationState<T>>(node);
21    state.0 = state.0.lerp(target, rate);
22    let value = state.0;
23    if !state.0.similar(target) {
24        ui.request_redraw();
25        value
26    } else {
27        state.0 = target;
28        target
29    }
30}
31
32impl Animatable for f32 {
33
34    fn similar(&self, other: Self) -> bool {
35        (*self - other).abs() < 0.005
36    }
37
38    fn lerp(&self, other: Self, t: f32) -> Self {
39        *self + (other - *self) * t
40    }
41
42}
43
44impl Animatable for Vec2 {
45
46    fn similar(&self, other: Self) -> bool {
47        self.distance(other) < 0.05
48    }
49
50    fn lerp(&self, other: Self, t: f32) -> Self {
51        *self + (other - *self) * t
52    }
53
54}
55
56impl Animatable for Color {
57
58    fn similar(&self, other: Self) -> bool {
59        self.r.similar(other.r) && self.g.similar(other.g) && self.b.similar(other.b) && self.a.similar(other.a)
60    }
61
62    fn lerp(&self, other: Self, t: f32) -> Self {
63        Self::rgba(
64            self.r.lerp(other.r, t), 
65            self.g.lerp(other.g, t), 
66            self.b.lerp(other.b, t),
67            self.a.lerp(other.a, t)
68        )
69    }
70
71}