1use super::{ AnimValue, Transition };
3use std::collections::HashMap;
4use std::hash::Hash;
5use std::time::Duration;
6
7struct Anim {
10 from: AnimValue,
11 to: AnimValue,
12 transition: Transition,
13 elapsed: Duration,
14 premultiplied: bool,
15}
16
17impl Anim {
18 fn value_at(&self) -> AnimValue {
21 let past_delay = self.elapsed.saturating_sub(self.transition.delay);
22 let t = if self.transition.duration.is_zero() {
23 1.0
24 } else {
25 past_delay.as_secs_f32() / self.transition.duration.as_secs_f32()
26 };
27 let eased = self.transition.easing.apply(t);
28 if self.premultiplied {
29 self.from.lerp_premultiplied(self.to, eased)
30 } else {
31 self.from.lerp(self.to, eased)
32 }
33 }
34
35 fn finished(&self) -> bool {
37 self.elapsed >= self.transition.delay + self.transition.duration
38 }
39}
40
41pub struct AnimationManager<K: Eq + Hash + Copy> {
47 active: HashMap<K, Anim>,
48 resting: HashMap<K, AnimValue>,
52}
53
54impl<K: Eq + Hash + Copy> Default for AnimationManager<K> {
55 fn default() -> Self {
56 Self { active: HashMap::new(), resting: HashMap::new() }
57 }
58}
59
60impl<K: Eq + Hash + Copy> AnimationManager<K> {
61 pub fn new() -> Self {
63 Self::default()
64 }
65
66 pub fn set_target(&mut self, key: K, target: AnimValue, transition: Option<Transition>) {
67 self.set_target_impl(key, target, transition, false);
68 }
69
70 pub fn set_color_target(&mut self, key: K, target: AnimValue, transition: Option<Transition>) {
75 self.set_target_impl(key, target, transition, true);
76 }
77
78 fn set_target_impl(
79 &mut self,
80 key: K,
81 target: AnimValue,
82 transition: Option<Transition>,
83 premultiplied: bool
84 ) {
85 let Some(transition) = transition else {
86 self.active.remove(&key);
87 self.resting.insert(key, target);
88 return;
89 };
90
91 match self.active.get_mut(&key) {
92 Some(anim) if anim.to == target => {}
93 Some(anim) => {
94 anim.from = anim.value_at();
95 anim.to = target;
96 anim.transition = transition;
97 anim.elapsed = Duration::ZERO;
98 anim.premultiplied = premultiplied;
99 }
100 None => {
101 let from = self.resting.get(&key).copied().unwrap_or(target);
102 self.resting.insert(key, target);
103
104 if from == target {
105 return;
106 }
107
108 self.active.insert(key, Anim {
109 from,
110 to: target,
111 transition,
112 elapsed: Duration::ZERO,
113 premultiplied,
114 });
115 }
116 }
117 }
118
119 pub fn tick(&mut self, dt: Duration) {
122 for anim in self.active.values_mut() {
123 anim.elapsed += dt;
124 }
125
126 for (key, anim) in self.active.iter() {
127 if anim.finished() {
128 self.resting.insert(*key, anim.to);
129 }
130 }
131
132 self.active.retain(|_, anim| !anim.finished());
133 }
134
135 pub fn value(&self, key: K) -> Option<AnimValue> {
139 self.active.get(&key).map(Anim::value_at)
140 }
141
142 pub fn active_keys(&self) -> impl Iterator<Item = &K> {
147 self.active.keys()
148 }
149
150 pub fn is_animating(&self) -> bool {
153 !self.active.is_empty()
154 }
155}