vizia_core/animation/
interpolator.rs

1use morphorm::Units;
2use vizia_style::{
3    Angle, BackgroundSize, ClipPath, Color, ColorStop, Display, Filter, FontSize, Gradient, Length,
4    LengthOrPercentage, LengthPercentageOrAuto, LengthValue, LineDirection, LinearGradient,
5    Opacity, PercentageOrNumber, Rect, Scale, Shadow, Transform, Translate, RGBA,
6};
7
8use skia_safe::Matrix;
9
10use crate::style::ImageOrGradient;
11
12/// A trait which describes how a property is interpolated for animations.
13pub(crate) trait Interpolator {
14    fn interpolate(start: &Self, end: &Self, t: f32) -> Self;
15}
16
17// Implementations of `Interpolator` for various properties.
18impl Interpolator for f32 {
19    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
20        start + (end - start) * t
21    }
22}
23
24impl Interpolator for i32 {
25    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
26        ((start + (end - start)) as f32 * t).round() as i32
27    }
28}
29
30impl Interpolator for (f32, f32) {
31    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
32        (f32::interpolate(&start.0, &end.0, t), f32::interpolate(&start.1, &end.1, t))
33    }
34}
35
36impl Interpolator for Units {
37    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
38        let s = match start {
39            Units::Pixels(val) => val,
40            Units::Percentage(val) => val,
41            Units::Stretch(val) => val,
42            Units::Auto => return *end,
43        };
44
45        match end {
46            Units::Pixels(e) => Units::Pixels(f32::interpolate(s, e, t)),
47            Units::Percentage(e) => Units::Percentage(f32::interpolate(s, e, t)),
48            Units::Stretch(e) => Units::Stretch(f32::interpolate(s, e, t)),
49            Units::Auto => *end,
50        }
51    }
52}
53
54impl Interpolator for Display {
55    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
56        if t < 0.5 {
57            *start
58        } else {
59            *end
60        }
61    }
62}
63
64impl Interpolator for Opacity {
65    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
66        Opacity(start.0 + (end.0 - start.0) * t)
67    }
68}
69
70impl Interpolator for Color {
71    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
72        let r = (end.r() as f64 - start.r() as f64).mul_add(t as f64, start.r() as f64) as u8;
73        let g = (end.g() as f64 - start.g() as f64).mul_add(t as f64, start.g() as f64) as u8;
74        let b = (end.b() as f64 - start.b() as f64).mul_add(t as f64, start.b() as f64) as u8;
75        let a = (end.a() as f64 - start.a() as f64).mul_add(t as f64, start.a() as f64) as u8;
76        Color::rgba(r, g, b, a)
77    }
78}
79
80impl Interpolator for RGBA {
81    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
82        let r = (end.r() as f64 - start.r() as f64).mul_add(t as f64, start.r() as f64) as u8;
83        let g = (end.g() as f64 - start.g() as f64).mul_add(t as f64, start.g() as f64) as u8;
84        let b = (end.b() as f64 - start.b() as f64).mul_add(t as f64, start.b() as f64) as u8;
85        let a = (end.a() as f64 - start.a() as f64).mul_add(t as f64, start.a() as f64) as u8;
86        RGBA::rgba(r, g, b, a)
87    }
88}
89
90impl Interpolator for Filter {
91    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
92        match (start, end) {
93            (Filter::Blur(start), Filter::Blur(end)) => {
94                Filter::Blur(Length::interpolate(start, end, t))
95            }
96        }
97    }
98}
99
100impl Interpolator for LengthValue {
101    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
102        match (end, start) {
103            (LengthValue::Px(end_val), LengthValue::Px(start_val)) => {
104                LengthValue::Px(f32::interpolate(start_val, end_val, t))
105            }
106
107            _ => LengthValue::default(),
108        }
109    }
110}
111
112impl Interpolator for Length {
113    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
114        match (end, start) {
115            (Length::Value(end_val), Length::Value(start_val)) => {
116                Length::Value(LengthValue::interpolate(start_val, end_val, t))
117            }
118
119            _ => Length::default(),
120        }
121    }
122}
123
124impl Interpolator for LengthOrPercentage {
125    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
126        match (start, end) {
127            (LengthOrPercentage::Length(start_val), LengthOrPercentage::Length(end_val)) => {
128                LengthOrPercentage::Length(Length::interpolate(start_val, end_val, t))
129            }
130
131            (
132                LengthOrPercentage::Percentage(start_val),
133                LengthOrPercentage::Percentage(end_val),
134            ) => LengthOrPercentage::Percentage(f32::interpolate(start_val, end_val, t)),
135
136            _ => LengthOrPercentage::default(),
137        }
138    }
139}
140
141impl Interpolator for LengthPercentageOrAuto {
142    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
143        match (start, end) {
144            (
145                LengthPercentageOrAuto::LengthPercentage(start_val),
146                LengthPercentageOrAuto::LengthPercentage(end_val),
147            ) => LengthPercentageOrAuto::LengthPercentage(LengthOrPercentage::interpolate(
148                start_val, end_val, t,
149            )),
150
151            _ => end.clone(),
152        }
153    }
154}
155
156impl Interpolator for PercentageOrNumber {
157    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
158        match (start, end) {
159            (PercentageOrNumber::Number(start_val), PercentageOrNumber::Number(end_val)) => {
160                PercentageOrNumber::Number(f32::interpolate(start_val, end_val, t))
161            }
162
163            (
164                PercentageOrNumber::Percentage(start_val),
165                PercentageOrNumber::Percentage(end_val),
166            ) => PercentageOrNumber::Percentage(f32::interpolate(start_val, end_val, t)),
167
168            _ => PercentageOrNumber::default(),
169        }
170    }
171}
172
173impl Interpolator for Translate {
174    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
175        let x = LengthOrPercentage::interpolate(&start.x, &end.x, t);
176        let y = LengthOrPercentage::interpolate(&start.y, &end.y, t);
177        Translate { x, y }
178    }
179}
180
181impl Interpolator for Scale {
182    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
183        let x = PercentageOrNumber::interpolate(&start.x, &end.x, t);
184        let y = PercentageOrNumber::interpolate(&start.y, &end.y, t);
185        Scale { x, y }
186    }
187}
188
189impl Interpolator for Angle {
190    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
191        let r = start.to_radians() + (end.to_radians() - start.to_radians()) * t;
192        Angle::Rad(r)
193    }
194}
195
196impl Interpolator for Transform {
197    fn interpolate(_start: &Self, end: &Self, _t: f32) -> Self {
198        end.clone()
199    }
200}
201
202// TODO: Split this into interpolated matrices for translation, rotation, scale, and skew
203impl Interpolator for Matrix {
204    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
205        let mut transform = *start;
206
207        transform[0] = f32::interpolate(&start[0], &end[0], t);
208        transform[1] = f32::interpolate(&start[1], &end[1], t);
209        transform[2] = f32::interpolate(&start[2], &end[2], t);
210        transform[3] = f32::interpolate(&start[3], &end[3], t);
211        transform[4] = f32::interpolate(&start[4], &end[4], t);
212        transform[5] = f32::interpolate(&start[5], &end[5], t);
213
214        transform
215    }
216}
217
218impl<T: Interpolator> Interpolator for Vec<T> {
219    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
220        start
221            .iter()
222            .zip(end.iter())
223            .map(|(start, end)| T::interpolate(start, end, t))
224            .collect::<Vec<T>>()
225    }
226}
227
228impl Interpolator for ImageOrGradient {
229    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
230        match (start, end) {
231            (
232                ImageOrGradient::Gradient(gradient_start),
233                ImageOrGradient::Gradient(gradient_end),
234            ) => ImageOrGradient::Gradient(Gradient::interpolate(gradient_start, gradient_end, t)),
235            _ => end.clone(),
236        }
237    }
238}
239
240impl Interpolator for BackgroundSize {
241    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
242        match (start, end) {
243            (
244                BackgroundSize::Explicit { width: start_width, height: start_height },
245                BackgroundSize::Explicit { width: end_width, height: end_height },
246            ) => {
247                let width = LengthPercentageOrAuto::interpolate(start_width, end_width, t);
248                let height = LengthPercentageOrAuto::interpolate(start_height, end_height, t);
249                BackgroundSize::Explicit { width, height }
250            }
251
252            _ => end.clone(),
253        }
254    }
255}
256
257impl Interpolator for Gradient {
258    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
259        match (start, end) {
260            (Gradient::Linear(start_gradient), Gradient::Linear(end_gradient)) => {
261                Gradient::Linear(LinearGradient::interpolate(start_gradient, end_gradient, t))
262            }
263
264            _ => end.clone(),
265        }
266    }
267}
268
269impl Interpolator for LineDirection {
270    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
271        match (start, end) {
272            (LineDirection::Angle(start_angle), LineDirection::Angle(end_angle)) => {
273                LineDirection::Angle(Angle::interpolate(start_angle, end_angle, t))
274            }
275
276            _ => *end,
277        }
278    }
279}
280
281impl Interpolator for LinearGradient {
282    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
283        if start.stops.len() == end.stops.len() {
284            LinearGradient {
285                direction: LineDirection::interpolate(&start.direction, &end.direction, t),
286                stops: start
287                    .stops
288                    .iter()
289                    .zip(end.stops.iter())
290                    .enumerate()
291                    .map(|(index, (start_stop, end_stop))| {
292                        let num_stops = start.stops.len();
293                        let start_pos =
294                            start_stop.position.clone().unwrap_or(LengthOrPercentage::Percentage(
295                                index as f32 / (num_stops - 1) as f32 * 100.0,
296                            ));
297                        let end_pos =
298                            end_stop.position.clone().unwrap_or(LengthOrPercentage::Percentage(
299                                index as f32 / (num_stops - 1) as f32 * 100.0,
300                            ));
301                        ColorStop {
302                            color: Color::interpolate(&start_stop.color, &end_stop.color, t),
303                            position: Some(LengthOrPercentage::interpolate(
304                                &start_pos, &end_pos, t,
305                            )),
306                        }
307                    })
308                    .collect::<Vec<_>>(),
309            }
310        } else {
311            end.clone()
312        }
313    }
314}
315
316impl Interpolator for Shadow {
317    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
318        Shadow {
319            x_offset: Length::interpolate(&start.x_offset, &end.x_offset, t),
320            y_offset: Length::interpolate(&start.y_offset, &end.y_offset, t),
321            blur_radius: Option::interpolate(&start.blur_radius, &end.blur_radius, t),
322            spread_radius: Option::interpolate(&start.spread_radius, &end.spread_radius, t),
323            color: Option::interpolate(&start.color, &end.color, t),
324            inset: end.inset,
325        }
326    }
327}
328
329impl<T: Interpolator + Clone + Default> Interpolator for Option<T> {
330    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
331        match (start, end) {
332            (Some(s), Some(e)) => Some(T::interpolate(s, e, t)),
333            (None, Some(e)) => Some(T::interpolate(&T::default(), e, t)),
334            (Some(s), None) => Some(T::interpolate(s, &T::default(), t)),
335            _ => end.clone(),
336        }
337    }
338}
339
340impl Interpolator for FontSize {
341    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
342        FontSize(f32::interpolate(&start.0, &end.0, t))
343    }
344}
345
346impl<T: Interpolator> Interpolator for Rect<T> {
347    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
348        Rect(
349            T::interpolate(&start.0, &end.0, t),
350            T::interpolate(&start.1, &end.1, t),
351            T::interpolate(&start.2, &end.2, t),
352            T::interpolate(&start.3, &end.3, t),
353        )
354    }
355}
356
357impl Interpolator for ClipPath {
358    fn interpolate(start: &Self, end: &Self, t: f32) -> Self {
359        match (start, end) {
360            (ClipPath::Shape(s), ClipPath::Shape(e)) => ClipPath::Shape(Rect::interpolate(s, e, t)),
361            _ => end.clone(),
362        }
363    }
364}