zng_var/
impls.rs

1//! zng-var depends on zng-[units, txt] so we need to implement these traits here.
2
3use 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] // for zng fmt
38impl_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    /// Implementation of `<Rgba as Transitionable>::lerp`.
305    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    /// Replace the [`Rgba`] lerp implementation.
317    ///
318    /// [`Rgba`]: zng_unit::Rgba
319    pub fn init_rgba_lerp(&self, lerp: fn(Rgba, Rgba, EasingStep) -> Rgba) {
320        *RGBA_LERP.write() = lerp;
321    }
322}