1use crate::{
3 AbsoluteLength, Background, Bounds, Corners, DefiniteLength, DevicePixels, Edges, Fill, Length,
4 Percentage, Pixels, Point, Radians, Relative, Rems, RingColor, Size, colors::Colors,
5};
6use palette::{
7 Hsla, IntoColor, Oklab, Oklaba,
8 rgb::{Rgb, Rgba},
9};
10use std::{
11 fmt::Debug,
12 ops::{Add, Mul, Sub},
13};
14
15pub trait Lerp<Output = Self>
39where
40 Self: Sized,
41{
42 fn lerp(&self, to: &Self, delta: f32) -> Output;
44}
45
46impl Lerp<f32> for bool {
47 fn lerp(&self, to: &Self, delta: f32) -> f32 {
48 lerp(*self as u8 as f32, *to as u8 as f32, delta)
49 }
50}
51
52macro_rules! float_lerps {
53 ( $( $ty:ty ),+ ) => {
54 $(
55 impl Lerp for $ty {
56 fn lerp(&self, to: &Self, delta: f32) -> Self {
57 lerp(*self, *to, delta as $ty)
58 }
59 }
60 )+
61 };
62}
63
64float_lerps!(f32, f64);
65
66macro_rules! int_lerps {
67 ( $( $ty:ident as $ty_into:ident ),+ ) => {
68 $(
69 impl Lerp for $ty {
70 fn lerp(&self, to: &Self, delta: f32) -> Self {
71 lerp(*self as $ty_into, *to as $ty_into, delta as $ty_into) as $ty
72 }
73 }
74 )+
75 };
76}
77
78int_lerps!(
79 usize as f32,
80 u8 as f32,
81 u16 as f32,
82 u32 as f32,
83 u64 as f64,
84 u128 as f64,
85 isize as f32,
86 i8 as f32,
87 i16 as f32,
88 i32 as f32,
89 i64 as f64,
90 i128 as f64
91);
92
93macro_rules! struct_lerps {
94 ( $( $ty:ident $( < $gen:ident > )? { $( $n:ident ),+ } ),+ $(,)? ) => {
95 $(
96 impl$(<$gen: Lerp + Clone + Debug + Default + PartialEq>)? Lerp for $ty$(<$gen>)? {
97 fn lerp(&self, to: &Self, delta: f32) -> Self {
98 $ty$(::<$gen>)? {
99 $(
100 $n: self.$n.lerp(&to.$n, delta)
101 ),+
102 }
103 }
104 }
105 )+
106 };
107}
108
109struct_lerps!(
110 Point<T> { x, y },
111 Size<T> { width, height },
112 Edges<T> { top, right, bottom, left },
113 Corners<T> { top_left, top_right, bottom_right, bottom_left },
114 Bounds<T> { origin, size },
115 Rgba { color, alpha },
116 Colors { text, selected_text, background, disabled, selected, border, separator, container }
117);
118
119macro_rules! tuple_struct_lerps {
120 ( $( $ty:ident ( $n:ty ) ),+ ) => {
121 $(
122 impl Lerp for $ty {
123 fn lerp(&self, to: &Self, delta: f32) -> Self {
124 $ty(self.0.lerp(&to.0, delta))
125 }
126 }
127 )+
128 };
129}
130
131tuple_struct_lerps!(
132 Radians(f32),
133 Percentage(f32),
134 DevicePixels(i32),
135 Relative(f32),
136 Rems(f32),
137 Pixels(f32)
138);
139
140macro_rules! new_constructor_lerps {
141 ( $( $ty:ident $( < $gen:ident > )? ::new ( $( $n:ident ),+ ) ),+ $(,)? ) => {
142 $(
143 impl$(<$gen: Lerp + Clone + Debug + Default + PartialEq>)? Lerp for $ty$(<$gen>)? {
144 fn lerp(&self, to: &Self, delta: f32) -> Self {
145 $ty$(::<$gen>)?::new(
146 $(
147 self.$n.lerp(&to.$n, delta)
148 ),+
149 )
150 }
151 }
152 )+
153 };
154}
155
156new_constructor_lerps!(
157 Rgb::new(red, green, blue),
158 Oklab::new(l, a, b),
159 Oklaba::new(l, a, b, alpha)
160);
161
162impl Lerp for Hsla {
163 fn lerp(&self, to: &Self, delta: f32) -> Self {
164 if delta <= 0.0 {
165 return *self;
166 }
167 if delta >= 1.0 {
168 return *to;
169 }
170
171 let from: Rgba = (*self).into_color();
172 let to: Rgba = (*to).into_color();
173 from.lerp(&to, delta).into_color()
174 }
175}
176
177impl Lerp for RingColor {
178 fn lerp(&self, to: &Self, delta: f32) -> Self {
179 match (*self, *to) {
180 (Self::Color(from), Self::Color(to)) => Self::Color(from.lerp(&to, delta)),
181 (_, to) if delta >= 1.0 => to,
182 (from, _) => from,
183 }
184 }
185}
186
187impl Lerp for AbsoluteLength {
188 fn lerp(&self, to: &Self, delta: f32) -> Self {
189 match (*self, *to) {
190 (Self::Pixels(from), Self::Pixels(to)) => Self::Pixels(from.lerp(&to, delta)),
191 (Self::Rems(from), Self::Rems(to)) => Self::Rems(from.lerp(&to, delta)),
192 (from, Self::Pixels(to)) if from.is_zero() => {
193 Self::Pixels(Pixels::default().lerp(&to, delta))
194 }
195 (from, Self::Rems(to)) if from.is_zero() => {
196 Self::Rems(Rems::default().lerp(&to, delta))
197 }
198 (Self::Pixels(from), to) if to.is_zero() => {
199 Self::Pixels(from.lerp(&Pixels::default(), delta))
200 }
201 (Self::Rems(from), to) if to.is_zero() => {
202 Self::Rems(from.lerp(&Rems::default(), delta))
203 }
204 _ if delta >= 1.0 => *to,
205 _ => *self,
206 }
207 }
208}
209
210impl Lerp for DefiniteLength {
211 fn lerp(&self, to: &Self, delta: f32) -> Self {
212 match (*self, *to) {
213 (Self::Absolute(from), Self::Absolute(to)) => Self::Absolute(from.lerp(&to, delta)),
214 (Self::Relative(from), Self::Relative(to)) => Self::Relative(from.lerp(&to, delta)),
215 _ if delta >= 1.0 => *to,
216 _ => *self,
217 }
218 }
219}
220
221impl Lerp for Length {
222 fn lerp(&self, to: &Self, delta: f32) -> Self {
223 match (*self, *to) {
224 (Self::Definite(from), Self::Definite(to)) => Self::Definite(from.lerp(&to, delta)),
225 _ if delta >= 1.0 => *to,
226 _ => *self,
227 }
228 }
229}
230
231impl Lerp for Background {
232 fn lerp(&self, to: &Self, delta: f32) -> Self {
233 if delta <= 0.0 {
234 return *self;
235 }
236 if delta >= 1.0 {
237 return *to;
238 }
239
240 match (self.as_solid(), to.as_solid()) {
241 (Some(from), Some(to_color)) => {
242 Background::from(from.lerp(&to_color, delta)).color_space(to.interpolation_space())
243 }
244 _ => *self,
245 }
246 }
247}
248
249impl Lerp for Fill {
250 fn lerp(&self, to: &Self, delta: f32) -> Self {
251 match (self, to) {
252 (Self::Color(from), Self::Color(to)) => Self::Color(from.lerp(to, delta)),
253 }
254 }
255}
256
257fn lerp<T>(from: T, to: T, alpha: T) -> T
258where
259 T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
260{
261 from + (to - from) * alpha
262}