1use std::{any::Any, borrow::Cow, path::PathBuf, time::Duration};
4
5use zng_app_context::app_local;
6use zng_time::{DInstant, Deadline};
7use zng_txt::Txt;
8use zng_unit::{
9 AngleDegree, AngleGradian, AngleRadian, AngleTurn, ByteLength, CornerRadius2D, Dip, Factor, FactorPercent, FactorUnits, Orientation2D,
10 Px, Rgba, euclid,
11};
12
13use crate::{
14 animation::{TRANSITIONABLE_APP, Transitionable, easing::EasingStep, is_slerp_enabled},
15 impl_from_and_into_var,
16};
17
18impl Transitionable for f64 {
19 fn lerp(self, to: &Self, step: EasingStep) -> Self {
20 self + (*to - self) * step.0 as f64
21 }
22}
23impl Transitionable for f32 {
24 fn lerp(self, to: &Self, step: EasingStep) -> Self {
25 self + (*to - self) * step.0
26 }
27}
28macro_rules! impl_transitionable {
29 ($FT:ident => $($T:ty,)+) => {$(
30 impl Transitionable for $T {
31 fn lerp(self, to: &Self, step: EasingStep) -> Self {
32 $FT::lerp(self as $FT, &((*to) as $FT), step).round() as _
33 }
34 }
35 )+}
36}
37#[rustfmt::skip] impl_transitionable! {
39 f32 => i8, u8, i16, u16, i32, u32,
40}
41#[rustfmt::skip]
42impl_transitionable! {
43 f64 => u64, i64, u128, i128, isize, usize,
44}
45impl Transitionable for Px {
46 fn lerp(self, to: &Self, step: EasingStep) -> Self {
47 Px(self.0.lerp(&to.0, step))
48 }
49}
50impl Transitionable for Dip {
51 fn lerp(self, to: &Self, step: EasingStep) -> Self {
52 Dip::new_f32(self.to_f32().lerp(&to.to_f32(), step))
53 }
54}
55impl<T, U> Transitionable for euclid::Point2D<T, U>
56where
57 T: Transitionable,
58 U: Send + Sync + Any,
59{
60 fn lerp(self, to: &Self, step: EasingStep) -> Self {
61 euclid::point2(self.x.lerp(&to.x, step), self.y.lerp(&to.y, step))
62 }
63}
64impl<T, U> Transitionable for euclid::Box2D<T, U>
65where
66 T: Transitionable,
67 U: Send + Sync + Any,
68{
69 fn lerp(self, to: &Self, step: EasingStep) -> Self {
70 euclid::Box2D::new(self.min.lerp(&to.min, step), self.max.lerp(&to.max, step))
71 }
72}
73impl<T, U> Transitionable for euclid::Point3D<T, U>
74where
75 T: Transitionable,
76 U: Send + Sync + Any,
77{
78 fn lerp(self, to: &Self, step: EasingStep) -> Self {
79 euclid::point3(self.x.lerp(&to.x, step), self.y.lerp(&to.y, step), self.z.lerp(&to.z, step))
80 }
81}
82impl<T, U> Transitionable for euclid::Box3D<T, U>
83where
84 T: Transitionable,
85 U: Send + Sync + Any,
86{
87 fn lerp(self, to: &Self, step: EasingStep) -> Self {
88 euclid::Box3D::new(self.min.lerp(&to.min, step), self.max.lerp(&to.max, step))
89 }
90}
91impl<T, U> Transitionable for euclid::Length<T, U>
92where
93 T: Transitionable,
94 U: Send + Sync + Any,
95{
96 fn lerp(self, to: &Self, step: EasingStep) -> Self {
97 euclid::Length::new(self.get().lerp(&to.clone().get(), step))
98 }
99}
100impl<T, U> Transitionable for euclid::Size2D<T, U>
101where
102 T: Transitionable,
103 U: Send + Sync + Any,
104{
105 fn lerp(self, to: &Self, step: EasingStep) -> Self {
106 euclid::size2(self.width.lerp(&to.width, step), self.height.lerp(&to.height, step))
107 }
108}
109impl<T, U> Transitionable for euclid::Size3D<T, U>
110where
111 T: Transitionable,
112 U: Send + Sync + Any,
113{
114 fn lerp(self, to: &Self, step: EasingStep) -> Self {
115 euclid::size3(
116 self.width.lerp(&to.width, step),
117 self.height.lerp(&to.height, step),
118 self.depth.lerp(&to.depth, step),
119 )
120 }
121}
122impl<T, U> Transitionable for euclid::Rect<T, U>
123where
124 T: Transitionable,
125 U: Send + Sync + Any,
126{
127 fn lerp(self, to: &Self, step: EasingStep) -> Self {
128 euclid::Rect::new(self.origin.lerp(&to.origin, step), self.size.lerp(&to.size, step))
129 }
130}
131impl<T, U> Transitionable for euclid::Vector2D<T, U>
132where
133 T: Transitionable,
134 U: Send + Sync + Any,
135{
136 fn lerp(self, to: &Self, step: EasingStep) -> Self {
137 euclid::vec2(self.x.lerp(&to.x, step), self.y.lerp(&to.y, step))
138 }
139}
140impl<T, U> Transitionable for euclid::Vector3D<T, U>
141where
142 T: Transitionable,
143 U: Send + Sync + Any,
144{
145 fn lerp(self, to: &Self, step: EasingStep) -> Self {
146 euclid::vec3(self.x.lerp(&to.x, step), self.y.lerp(&to.y, step), self.z.lerp(&to.z, step))
147 }
148}
149impl Transitionable for Factor {
150 fn lerp(self, to: &Self, step: EasingStep) -> Self {
151 Factor(self.0.lerp(&to.0, step))
152 }
153}
154impl Transitionable for FactorPercent {
155 fn lerp(self, to: &Self, step: EasingStep) -> Self {
156 FactorPercent(self.0.lerp(&to.0, step))
157 }
158}
159impl<T, U> Transitionable for euclid::SideOffsets2D<T, U>
160where
161 T: Transitionable,
162 U: Send + Sync + Any,
163{
164 fn lerp(self, to: &Self, step: EasingStep) -> Self {
165 euclid::SideOffsets2D::new(
166 self.top.lerp(&to.top, step),
167 self.right.lerp(&to.right, step),
168 self.bottom.lerp(&to.bottom, step),
169 self.left.lerp(&to.left, step),
170 )
171 }
172}
173impl Transitionable for bool {
174 fn lerp(self, to: &Self, step: EasingStep) -> Self {
175 if step >= 1.fct() { *to } else { self }
176 }
177}
178impl<T, U> Transitionable for CornerRadius2D<T, U>
179where
180 T: Transitionable,
181 U: Send + Sync + Any,
182{
183 fn lerp(self, to: &Self, step: EasingStep) -> Self {
184 Self {
185 top_left: self.top_left.lerp(&to.top_left, step),
186 top_right: self.top_right.lerp(&to.top_right, step),
187 bottom_right: self.bottom_right.lerp(&to.bottom_right, step),
188 bottom_left: self.bottom_left.lerp(&to.bottom_left, step),
189 }
190 }
191}
192
193impl Transitionable for ByteLength {
194 fn lerp(self, to: &Self, step: EasingStep) -> Self {
195 Self(self.0.lerp(&to.0, step))
196 }
197}
198
199impl_from_and_into_var! {
200 fn from(s: &'static str) -> Txt;
201 fn from(s: String) -> Txt;
202 fn from(s: Cow<'static, str>) -> Txt;
203 fn from(c: char) -> Txt;
204 fn from(t: Txt) -> PathBuf;
205 fn from(t: Txt) -> String;
206 fn from(t: Txt) -> Cow<'static, str>;
207
208 fn from(f: f32) -> Factor;
209 fn from(one_or_zero: bool) -> Factor;
210 fn from(f: FactorPercent) -> Factor;
211 fn from(f: Factor) -> FactorPercent;
212
213 fn from(d: DInstant) -> Deadline;
214 fn from(d: Duration) -> Deadline;
215
216 fn from(b: usize) -> ByteLength;
217
218 fn from(rad: AngleRadian) -> AngleTurn;
219 fn from(grad: AngleGradian) -> AngleTurn;
220 fn from(deg: AngleDegree) -> AngleTurn;
221
222 fn from(grad: AngleGradian) -> AngleRadian;
223 fn from(deg: AngleDegree) -> AngleRadian;
224 fn from(turn: AngleTurn) -> AngleRadian;
225
226 fn from(rad: AngleRadian) -> AngleGradian;
227 fn from(deg: AngleDegree) -> AngleGradian;
228 fn from(turn: AngleTurn) -> AngleGradian;
229
230 fn from(rad: AngleRadian) -> AngleDegree;
231 fn from(grad: AngleGradian) -> AngleDegree;
232 fn from(turn: AngleTurn) -> AngleDegree;
233}
234
235macro_rules! impl_into_var_option {
236 (
237 $($T:ty),* $(,)?
238 ) => {
239 impl_from_and_into_var! { $(
240 fn from(some: $T) -> Option<$T>;
241 )* }
242 }
243}
244impl_into_var_option! {
245 i8,
246 i16,
247 i32,
248 i64,
249 i128,
250 isize,
251 u8,
252 u16,
253 u32,
254 u64,
255 u128,
256 usize,
257 f32,
258 f64,
259 char,
260 bool,
261 Orientation2D,
262}
263
264impl Transitionable for AngleRadian {
265 fn lerp(self, to: &Self, step: EasingStep) -> Self {
266 match is_slerp_enabled() {
267 false => self.lerp(*to, step),
268 true => self.slerp(*to, step),
269 }
270 }
271}
272impl Transitionable for AngleGradian {
273 fn lerp(self, to: &Self, step: EasingStep) -> Self {
274 match is_slerp_enabled() {
275 false => self.lerp(*to, step),
276 true => self.slerp(*to, step),
277 }
278 }
279}
280impl Transitionable for AngleDegree {
281 fn lerp(self, to: &Self, step: EasingStep) -> Self {
282 match is_slerp_enabled() {
283 false => self.lerp(*to, step),
284 true => self.slerp(*to, step),
285 }
286 }
287}
288impl Transitionable for AngleTurn {
289 fn lerp(self, to: &Self, step: EasingStep) -> Self {
290 match is_slerp_enabled() {
291 false => self.lerp(*to, step),
292 true => self.slerp(*to, step),
293 }
294 }
295}
296impl Transitionable for Rgba {
297 fn lerp(self, to: &Self, step: EasingStep) -> Self {
298 let lerp = *RGBA_LERP.read();
299 lerp(self, *to, step)
300 }
301}
302
303app_local! {
304 static RGBA_LERP: fn(Rgba, Rgba, EasingStep) -> Rgba = const { lerp_rgba_linear };
306}
307fn lerp_rgba_linear(mut from: Rgba, to: Rgba, factor: Factor) -> Rgba {
308 from.red = from.red.lerp(&to.red, factor);
309 from.green = from.green.lerp(&to.green, factor);
310 from.blue = from.blue.lerp(&to.blue, factor);
311 from.alpha = from.alpha.lerp(&to.alpha, factor);
312 from
313}
314
315impl TRANSITIONABLE_APP {
316 pub fn init_rgba_lerp(&self, lerp: fn(Rgba, Rgba, EasingStep) -> Rgba) {
320 *RGBA_LERP.write() = lerp;
321 }
322}