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
12pub(crate) trait Interpolator {
14 fn interpolate(start: &Self, end: &Self, t: f32) -> Self;
15}
16
17impl 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
202impl 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}