zng_layout/unit/
length.rs

1use super::{
2    ByteLength, ByteUnits, Dip, DipToPx, EQ_EPSILON, EQ_EPSILON_100, Factor, FactorPercent, FactorUnits, LayoutAxis, Px, about_eq,
3};
4use std::{fmt, mem, ops};
5
6use zng_var::{
7    animation::{Transitionable, easing::EasingStep},
8    impl_from_and_into_var,
9};
10
11use crate::context::{LAYOUT, LayoutMask};
12
13/// 1D length units.
14///
15/// See [`LengthUnits`] for more details.
16///
17/// # Equality
18///
19/// Two lengths are equal if they are of the same variant and if:
20///
21/// * `Dip` and `px` lengths uses [`Dip`] and [`Px`] equality.
22/// * `Relative`, `Em`, `RootEm` lengths use the [`Factor`] equality.
23/// * Viewport lengths uses [`about_eq`] with `0.00001` epsilon.
24#[derive(Clone, serde::Serialize, serde::Deserialize)]
25pub enum Length {
26    /// The default (initial) value.
27    Default,
28    /// The exact length in device independent units.
29    Dip(Dip),
30    /// The exact length in device pixel units.
31    Px(Px),
32    /// The exact length in font points.
33    Pt(f32),
34    /// Relative to the fill length.
35    Factor(Factor),
36    /// Relative to the leftover fill length.
37    Leftover(Factor),
38    /// Relative to the font-size of the widget.
39    Em(Factor),
40    /// Relative to the font-size of the root widget.
41    RootEm(Factor),
42    /// Relative to the width of the nearest viewport ancestor.
43    ViewportWidth(Factor),
44    /// Relative to the height of the nearest viewport ancestor.
45    ViewportHeight(Factor),
46    /// Relative to the smallest of the nearest viewport ancestor's dimensions.
47    ViewportMin(Factor),
48    /// Relative to the smallest of the nearest viewport ancestor's dimensions.
49    ViewportMax(Factor),
50
51    /// The exact length in device independent units, defined using a `f32` value.
52    ///
53    /// This value will be rounded to the nearest pixel after layout,
54    /// but it will be used as is in the evaluation of length expressions.
55    DipF32(f32),
56    /// The exact length in device pixel units, defined using a `f32` value.
57    ///
58    /// This value will be rounded to the nearest pixel after layout,
59    /// but it will be used as is in the evaluation of length expressions.
60    PxF32(f32),
61
62    /// Expression.
63    Expr(Box<LengthExpr>),
64}
65impl<L: Into<Length>> ops::Add<L> for Length {
66    type Output = Length;
67
68    fn add(self, rhs: L) -> Self::Output {
69        use Length::*;
70
71        let rhs = rhs.into();
72
73        if self.is_zero() == Some(true) {
74            return rhs; // 0 + rhs
75        } else if rhs.is_zero() == Some(true) {
76            return self; // self + 0
77        }
78
79        match (self, rhs) {
80            (Dip(a), Dip(b)) => Dip(a + b),
81            (Px(a), Px(b)) => Px(a + b),
82            (Pt(a), Pt(b)) => Pt(a + b),
83            (Factor(a), Factor(b)) => Factor(a + b),
84            (Leftover(a), Leftover(b)) => Leftover(a + b),
85            (Em(a), Em(b)) => Em(a + b),
86            (RootEm(a), RootEm(b)) => RootEm(a + b),
87            (ViewportWidth(a), ViewportWidth(b)) => ViewportWidth(a + b),
88            (ViewportHeight(a), ViewportHeight(b)) => ViewportHeight(a + b),
89            (ViewportMin(a), ViewportMin(b)) => ViewportMin(a + b),
90            (ViewportMax(a), ViewportMax(b)) => ViewportMax(a + b),
91            (PxF32(a), PxF32(b)) => PxF32(a + b),
92            (DipF32(a), DipF32(b)) => DipF32(a + b),
93            (Px(a), PxF32(b)) | (PxF32(b), Px(a)) => PxF32(a.0 as f32 + b),
94            (Dip(a), DipF32(b)) | (DipF32(b), Dip(a)) => DipF32(a.to_f32() + b),
95            (a, b) => LengthExpr::Add(a, b).to_length_checked(),
96        }
97    }
98}
99impl<L: Into<Length>> ops::AddAssign<L> for Length {
100    fn add_assign(&mut self, rhs: L) {
101        let lhs = mem::take(self);
102        *self = lhs + rhs.into();
103    }
104}
105impl<L: Into<Length>> ops::Sub<L> for Length {
106    type Output = Length;
107
108    fn sub(self, rhs: L) -> Self::Output {
109        use Length::*;
110
111        let rhs = rhs.into();
112
113        if rhs.is_zero() == Some(true) {
114            return self; // self - 0
115        } else if self.is_zero() == Some(true) {
116            return -rhs; // 0 - rhs
117        }
118
119        match (self, rhs) {
120            (Dip(a), Dip(b)) => Dip(a - b),
121            (Px(a), Px(b)) => Px(a - b),
122            (Pt(a), Pt(b)) => Pt(a - b),
123            (Factor(a), Factor(b)) => Factor(a - b),
124            (Leftover(a), Leftover(b)) => Leftover(a - b),
125            (Em(a), Em(b)) => Em(a - b),
126            (RootEm(a), RootEm(b)) => RootEm(a - b),
127            (ViewportWidth(a), ViewportWidth(b)) => ViewportWidth(a - b),
128            (ViewportHeight(a), ViewportHeight(b)) => ViewportHeight(a - b),
129            (ViewportMin(a), ViewportMin(b)) => ViewportMin(a - b),
130            (ViewportMax(a), ViewportMax(b)) => ViewportMax(a - b),
131            (PxF32(a), PxF32(b)) => PxF32(a - b),
132            (DipF32(a), DipF32(b)) => DipF32(a - b),
133            (Px(a), PxF32(b)) => PxF32(a.0 as f32 - b),
134            (PxF32(a), Px(b)) => PxF32(a - b.0 as f32),
135            (Dip(a), DipF32(b)) => DipF32(a.to_f32() - b),
136            (DipF32(a), Dip(b)) => DipF32(a - b.to_f32()),
137            (a, b) => LengthExpr::Sub(a, b).to_length_checked(),
138        }
139    }
140}
141impl<L: Into<Length>> ops::SubAssign<L> for Length {
142    fn sub_assign(&mut self, rhs: L) {
143        let lhs = mem::take(self);
144        *self = lhs - rhs.into();
145    }
146}
147impl<F: Into<Factor>> ops::Mul<F> for Length {
148    type Output = Length;
149
150    fn mul(self, rhs: F) -> Self::Output {
151        use Length::*;
152        let rhs = rhs.into();
153
154        if self.is_zero() == Some(true) || rhs == 1.fct() {
155            return self; // 0 * fct || len * 1.0
156        } else if rhs == 0.fct() {
157            return Self::zero(); // len * 0.0
158        }
159
160        match self {
161            Dip(e) => DipF32(e.to_f32() * rhs.0),
162            Px(e) => PxF32(e.0 as f32 * rhs.0),
163            Pt(e) => Pt(e * rhs.0),
164            Factor(r) => Factor(r * rhs),
165            Leftover(r) => Leftover(r * rhs),
166            Em(e) => Em(e * rhs),
167            RootEm(e) => RootEm(e * rhs),
168            ViewportWidth(w) => ViewportWidth(w * rhs),
169            ViewportHeight(h) => ViewportHeight(h * rhs),
170            ViewportMin(m) => ViewportMin(m * rhs),
171            ViewportMax(m) => ViewportMax(m * rhs),
172            DipF32(e) => DipF32(e * rhs.0),
173            PxF32(e) => PxF32(e * rhs.0),
174            e => LengthExpr::Mul(e, rhs).to_length_checked(),
175        }
176    }
177}
178impl<F: Into<Factor>> ops::MulAssign<F> for Length {
179    fn mul_assign(&mut self, rhs: F) {
180        let lhs = mem::take(self);
181        *self = lhs * rhs.into();
182    }
183}
184impl<F: Into<Factor>> ops::Div<F> for Length {
185    type Output = Length;
186
187    fn div(self, rhs: F) -> Self::Output {
188        use Length::*;
189
190        let rhs = rhs.into();
191
192        if self.is_zero() == Some(true) && rhs != 0.fct() {
193            return self; // 0 / fct
194        }
195
196        match self {
197            Dip(e) => DipF32(e.to_f32() / rhs.0),
198            Px(e) => PxF32(e.0 as f32 / rhs.0),
199            Pt(e) => Pt(e / rhs.0),
200            Factor(r) => Factor(r / rhs),
201            Leftover(r) => Leftover(r / rhs),
202            Em(e) => Em(e / rhs),
203            RootEm(e) => RootEm(e / rhs),
204            ViewportWidth(w) => ViewportWidth(w / rhs),
205            ViewportHeight(h) => ViewportHeight(h / rhs),
206            ViewportMin(m) => ViewportMin(m / rhs),
207            ViewportMax(m) => ViewportMax(m / rhs),
208            DipF32(e) => DipF32(e / rhs.0),
209            PxF32(e) => PxF32(e / rhs.0),
210            e => LengthExpr::Mul(e, rhs).to_length_checked(),
211        }
212    }
213}
214impl<F: Into<Factor>> ops::DivAssign<F> for Length {
215    fn div_assign(&mut self, rhs: F) {
216        let lhs = mem::take(self);
217        *self = lhs / rhs.into();
218    }
219}
220impl Transitionable for Length {
221    fn lerp(self, to: &Self, step: EasingStep) -> Self {
222        use Length::*;
223
224        if step == 0.fct() {
225            return self;
226        }
227        if step == 1.fct() {
228            return to.clone();
229        }
230
231        match (self, to) {
232            (Dip(a), Dip(b)) => Dip(a.lerp(b, step)),
233            (Px(a), Px(b)) => Px(a.lerp(b, step)),
234            (Pt(a), Pt(b)) => Pt(a.lerp(b, step)),
235            (Factor(a), Factor(b)) => Factor(a.lerp(b, step)),
236            (Leftover(a), Leftover(b)) => Leftover(a.lerp(b, step)),
237            (Em(a), Em(b)) => Em(a.lerp(b, step)),
238            (RootEm(a), RootEm(b)) => RootEm(a.lerp(b, step)),
239            (ViewportWidth(a), ViewportWidth(b)) => ViewportWidth(a.lerp(b, step)),
240            (ViewportHeight(a), ViewportHeight(b)) => ViewportHeight(a.lerp(b, step)),
241            (ViewportMin(a), ViewportMin(b)) => ViewportMin(a.lerp(b, step)),
242            (ViewportMax(a), ViewportMax(b)) => ViewportMax(a.lerp(b, step)),
243            (PxF32(a), PxF32(b)) => PxF32(a.lerp(b, step)),
244            (DipF32(a), DipF32(b)) => DipF32(a.lerp(b, step)),
245            (Px(a), PxF32(b)) => PxF32((a.0 as f32).lerp(b, step)),
246            (PxF32(a), Px(b)) => PxF32(a.lerp(&(b.0 as f32), step)),
247            (Dip(a), DipF32(b)) => DipF32(a.to_f32().lerp(b, step)),
248            (DipF32(a), Dip(b)) => DipF32(a.lerp(&b.to_f32(), step)),
249            (a, b) => LengthExpr::Lerp(a, b.clone(), step).to_length_checked(),
250        }
251    }
252}
253impl ops::Neg for Length {
254    type Output = Self;
255
256    fn neg(self) -> Self::Output {
257        match self {
258            Length::Default => LengthExpr::Neg(Length::Default).to_length_checked(),
259            Length::Dip(e) => Length::Dip(-e),
260            Length::Px(e) => Length::Px(-e),
261            Length::Pt(e) => Length::Pt(-e),
262            Length::Factor(e) => Length::Factor(-e),
263            Length::Leftover(e) => Length::Leftover(-e),
264            Length::Em(e) => Length::Em(-e),
265            Length::RootEm(e) => Length::RootEm(-e),
266            Length::ViewportWidth(e) => Length::ViewportWidth(-e),
267            Length::ViewportHeight(e) => Length::ViewportHeight(-e),
268            Length::ViewportMin(e) => Length::ViewportMin(-e),
269            Length::ViewportMax(e) => Length::ViewportMax(-e),
270            Length::DipF32(e) => Length::DipF32(-e),
271            Length::PxF32(e) => Length::PxF32(-e),
272            Length::Expr(e) => LengthExpr::Neg(Length::Expr(e)).to_length_checked(),
273        }
274    }
275}
276impl Default for Length {
277    /// `Length::Default`
278    fn default() -> Self {
279        Length::Default
280    }
281}
282impl PartialEq for Length {
283    fn eq(&self, other: &Self) -> bool {
284        use Length::*;
285        match (self, other) {
286            (Default, Default) => true,
287
288            (Dip(a), Dip(b)) => a == b,
289            (Px(a), Px(b)) => a == b,
290            (Pt(a), Pt(b)) => about_eq(*a, *b, EQ_EPSILON_100),
291
292            (DipF32(a), DipF32(b)) | (PxF32(a), PxF32(b)) => about_eq(*a, *b, EQ_EPSILON_100),
293
294            (Factor(a), Factor(b)) | (Em(a), Em(b)) | (RootEm(a), RootEm(b)) | (Leftover(a), Leftover(b)) => a == b,
295
296            (ViewportWidth(a), ViewportWidth(b))
297            | (ViewportHeight(a), ViewportHeight(b))
298            | (ViewportMin(a), ViewportMin(b))
299            | (ViewportMax(a), ViewportMax(b)) => about_eq(a.0, b.0, EQ_EPSILON),
300
301            (Expr(a), Expr(b)) => a == b,
302
303            (Dip(a), DipF32(b)) | (DipF32(b), Dip(a)) => about_eq(a.to_f32(), *b, EQ_EPSILON_100),
304            (Px(a), PxF32(b)) | (PxF32(b), Px(a)) => about_eq(a.0 as f32, *b, EQ_EPSILON_100),
305
306            _ => false,
307        }
308    }
309}
310impl fmt::Debug for Length {
311    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312        use Length::*;
313        if f.alternate() {
314            match self {
315                Default => write!(f, "Length::Default"),
316                Dip(e) => f.debug_tuple("Length::Dip").field(e).finish(),
317                Px(e) => f.debug_tuple("Length::Px").field(e).finish(),
318                Pt(e) => f.debug_tuple("Length::Pt").field(e).finish(),
319                Factor(e) => f.debug_tuple("Length::Factor").field(e).finish(),
320                Leftover(e) => f.debug_tuple("Length::Leftover").field(e).finish(),
321                Em(e) => f.debug_tuple("Length::Em").field(e).finish(),
322                RootEm(e) => f.debug_tuple("Length::RootEm").field(e).finish(),
323                ViewportWidth(e) => f.debug_tuple("Length::ViewportWidth").field(e).finish(),
324                ViewportHeight(e) => f.debug_tuple("Length::ViewportHeight").field(e).finish(),
325                ViewportMin(e) => f.debug_tuple("Length::ViewportMin").field(e).finish(),
326                ViewportMax(e) => f.debug_tuple("Length::ViewportMax").field(e).finish(),
327                DipF32(e) => f.debug_tuple("Length::DipF32").field(e).finish(),
328                PxF32(e) => f.debug_tuple("Length::PxF32").field(e).finish(),
329                Expr(e) => f.debug_tuple("Length::Expr").field(e).finish(),
330            }
331        } else {
332            match self {
333                Default => write!(f, "Default"),
334                Dip(e) => write!(f, "{}.dip()", e.to_f32()),
335                Px(e) => write!(f, "{}.px()", e.0),
336                Pt(e) => write!(f, "{e}.pt()"),
337                Factor(e) => write!(f, "{}.pct()", e.0 * 100.0),
338                Leftover(e) => write!(f, "{}.lft()", e.0),
339                Em(e) => write!(f, "{}.em()", e.0),
340                RootEm(e) => write!(f, "{}.rem()", e.0),
341                ViewportWidth(e) => write!(f, "{e}.vw()"),
342                ViewportHeight(e) => write!(f, "{e}.vh()"),
343                ViewportMin(e) => write!(f, "{e}.vmin()"),
344                ViewportMax(e) => write!(f, "{e}.vmax()"),
345                DipF32(e) => write!(f, "{e}.dip()"),
346                PxF32(e) => write!(f, "{e}.px()"),
347                Expr(e) => write!(f, "{e}"),
348            }
349        }
350    }
351}
352impl fmt::Display for Length {
353    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354        use Length::*;
355        match self {
356            Default => write!(f, "Default"),
357            Dip(l) => write!(f, "{l}"),
358            Px(l) => write!(f, "{l}"),
359            Pt(l) => write!(f, "{l}pt"),
360            Factor(n) => write!(f, "{:.*}%", f.precision().unwrap_or(0), n.0 * 100.0),
361            Leftover(l) => write!(f, "{l}lft"),
362            Em(e) => write!(f, "{e}em"),
363            RootEm(re) => write!(f, "{re}rem"),
364            ViewportWidth(vw) => write!(f, "{vw}vw"),
365            ViewportHeight(vh) => write!(f, "{vh}vh"),
366            ViewportMin(vmin) => write!(f, "{vmin}vmin"),
367            ViewportMax(vmax) => write!(f, "{vmax}vmax"),
368            DipF32(l) => write!(f, "{l}dip"),
369            PxF32(l) => write!(f, "{l}px"),
370            Expr(e) => write!(f, "{e}"),
371        }
372    }
373}
374impl_from_and_into_var! {
375    /// Conversion to [`Length::Factor`]
376    fn from(percent: FactorPercent) -> Length {
377        Length::Factor(percent.into())
378    }
379
380    /// Conversion to [`Length::Factor`]
381    fn from(norm: Factor) -> Length {
382        Length::Factor(norm)
383    }
384
385    /// Conversion to [`Length::DipF32`]
386    fn from(f: f32) -> Length {
387        Length::DipF32(f)
388    }
389
390    /// Conversion to [`Length::Dip`]
391    fn from(i: i32) -> Length {
392        Length::Dip(Dip::new(i))
393    }
394
395    /// Conversion to [`Length::Px`]
396    fn from(l: Px) -> Length {
397        Length::Px(l)
398    }
399
400    /// Conversion to [`Length::Dip`]
401    fn from(l: Dip) -> Length {
402        Length::Dip(l)
403    }
404}
405impl Length {
406    /// Length of exact zero.
407    pub const fn zero() -> Length {
408        Length::Px(Px(0))
409    }
410
411    /// Length that fills the available space.
412    pub const fn fill() -> Length {
413        Length::Factor(Factor(1.0))
414    }
415
416    /// Length that fills 50% of the available space.
417    pub const fn half() -> Length {
418        Length::Factor(Factor(0.5))
419    }
420
421    /// Returns a length that resolves to the maximum layout length between `self` and `other`.
422    pub fn max(&self, other: impl Into<Length>) -> Length {
423        use Length::*;
424        match (self.clone(), other.into()) {
425            (Default, Default) => Default,
426            (Dip(a), Dip(b)) => Dip(a.max(b)),
427            (Px(a), Px(b)) => Px(a.max(b)),
428            (Pt(a), Pt(b)) => Pt(a.max(b)),
429            (Factor(a), Factor(b)) => Factor(a.max(b)),
430            (Leftover(a), Leftover(b)) => Leftover(a.max(b)),
431            (Em(a), Em(b)) => Em(a.max(b)),
432            (RootEm(a), RootEm(b)) => RootEm(a.max(b)),
433            (ViewportWidth(a), ViewportWidth(b)) => ViewportWidth(a.max(b)),
434            (ViewportHeight(a), ViewportHeight(b)) => ViewportHeight(a.max(b)),
435            (ViewportMin(a), ViewportMin(b)) => ViewportMin(a.max(b)),
436            (ViewportMax(a), ViewportMax(b)) => ViewportMax(a.max(b)),
437            (DipF32(a), DipF32(b)) => DipF32(a.max(b)),
438            (PxF32(a), PxF32(b)) => PxF32(a.max(b)),
439            (DipF32(a), Dip(b)) | (Dip(b), DipF32(a)) => DipF32(a.max(b.to_f32())),
440            (PxF32(a), Px(b)) | (Px(b), PxF32(a)) => PxF32(a.max(b.0 as f32)),
441            (a, b) => LengthExpr::Max(a, b).to_length_checked(),
442        }
443    }
444
445    /// Returns a length that resolves to the minimum layout length between `self` and `other`.
446    pub fn min(&self, other: impl Into<Length>) -> Length {
447        use Length::*;
448        match (self.clone(), other.into()) {
449            (Default, Default) => Default,
450            (Dip(a), Dip(b)) => Dip(a.min(b)),
451            (Px(a), Px(b)) => Px(a.min(b)),
452            (Pt(a), Pt(b)) => Pt(a.min(b)),
453            (Factor(a), Factor(b)) => Factor(a.min(b)),
454            (Leftover(a), Leftover(b)) => Leftover(a.min(b)),
455            (Em(a), Em(b)) => Em(a.min(b)),
456            (RootEm(a), RootEm(b)) => RootEm(a.min(b)),
457            (ViewportWidth(a), ViewportWidth(b)) => ViewportWidth(a.min(b)),
458            (ViewportHeight(a), ViewportHeight(b)) => ViewportHeight(a.min(b)),
459            (ViewportMin(a), ViewportMin(b)) => ViewportMin(a.min(b)),
460            (ViewportMax(a), ViewportMax(b)) => ViewportMax(a.min(b)),
461            (DipF32(a), DipF32(b)) => DipF32(a.min(b)),
462            (PxF32(a), PxF32(b)) => PxF32(a.min(b)),
463            (DipF32(a), Dip(b)) | (Dip(b), DipF32(a)) => DipF32(a.min(b.to_f32())),
464            (PxF32(a), Px(b)) | (Px(b), PxF32(a)) => PxF32(a.min(b.0 as f32)),
465            (a, b) => LengthExpr::Min(a, b).to_length_checked(),
466        }
467    }
468
469    /// Returns a length that constraints the computed layout length between `min` and `max`.
470    pub fn clamp(&self, min: impl Into<Length>, max: impl Into<Length>) -> Length {
471        self.max(min).min(max)
472    }
473
474    /// Returns a length that computes the absolute layout length of `self`.
475    pub fn abs(&self) -> Length {
476        use Length::*;
477        match self {
478            Default => LengthExpr::Abs(Length::Default).to_length_checked(),
479            Dip(e) => Dip(e.abs()),
480            Px(e) => Px(e.abs()),
481            Pt(e) => Pt(e.abs()),
482            Factor(r) => Factor(r.abs()),
483            Leftover(r) => Leftover(r.abs()),
484            Em(e) => Em(e.abs()),
485            RootEm(r) => RootEm(r.abs()),
486            ViewportWidth(w) => ViewportWidth(w.abs()),
487            ViewportHeight(h) => ViewportHeight(h.abs()),
488            ViewportMin(m) => ViewportMin(m.abs()),
489            ViewportMax(m) => ViewportMax(m.abs()),
490            DipF32(e) => DipF32(e.abs()),
491            PxF32(e) => PxF32(e.abs()),
492            Expr(e) => LengthExpr::Abs(Length::Expr(e.clone())).to_length_checked(),
493        }
494    }
495
496    /// If this length is zero in any finite layout context.
497    ///
498    /// Returns `None` if the value depends on the default value.
499    ///
500    /// [`Expr`]: Length::Expr
501    pub fn is_zero(&self) -> Option<bool> {
502        use Length::*;
503        match self {
504            Default => None,
505            Dip(l) => Some(*l == self::Dip::new(0)),
506            Px(l) => Some(*l == self::Px(0)),
507            Pt(l) => Some(l.abs() < EQ_EPSILON),
508            Factor(f) => Some(f.0.abs() < EQ_EPSILON),
509            Leftover(f) => Some(f.0.abs() < EQ_EPSILON),
510            Em(f) => Some(f.0.abs() < EQ_EPSILON),
511            RootEm(f) => Some(f.0.abs() < EQ_EPSILON),
512            ViewportWidth(p) => Some(p.0.abs() < EQ_EPSILON),
513            ViewportHeight(p) => Some(p.0.abs() < EQ_EPSILON),
514            ViewportMin(p) => Some(p.0.abs() < EQ_EPSILON),
515            ViewportMax(p) => Some(p.0.abs() < EQ_EPSILON),
516            DipF32(l) => Some(about_eq(*l, 0.0, EQ_EPSILON_100)),
517            PxF32(l) => Some(about_eq(*l, 0.0, EQ_EPSILON_100)),
518            Expr(_) => None,
519        }
520    }
521
522    /// Convert a `pt` unit value to [`Px`] given a `scale_factor`.
523    pub fn pt_to_px(pt: f32, scale_factor: Factor) -> Px {
524        let px = Self::pt_to_px_f32(pt, scale_factor);
525        Px(px.round() as i32)
526    }
527
528    /// Same operation as [`pt_to_px`] but without rounding to nearest pixel.
529    ///
530    /// [`pt_to_px`]: Self::pt_to_px
531    pub fn pt_to_px_f32(pt: f32, scale_factor: Factor) -> f32 {
532        pt * Self::PT_TO_DIP * scale_factor.0
533    }
534
535    /// Convert a [`Px`] unit value to a `Pt` value given a `scale_factor`.
536    pub fn px_to_pt(px: Px, scale_factor: Factor) -> f32 {
537        let dip = px.0 as f32 / scale_factor.0;
538        dip / Self::PT_TO_DIP
539    }
540
541    /// If is [`Length::Default`].
542    pub fn is_default(&self) -> bool {
543        matches!(self, Length::Default)
544    }
545
546    /// Replaces `self` with `overwrite` if `self` is [`Default`].
547    ///
548    /// [`Default`]: Length::Default
549    pub fn replace_default(&mut self, overwrite: &Length) {
550        if self.is_default() {
551            *self = overwrite.clone();
552        }
553    }
554
555    /// Convert [`PxF32`] to [`Px`] and [`DipF32`] to [`Dip`].
556    ///
557    /// [`PxF32`]: Self::PxF32
558    /// [`Px`]: Self::Px
559    /// [`DipF32`]: Self::DipF32
560    /// [`Dip`]: Self::Dip
561    pub fn round_exact(&mut self) {
562        match self {
563            Length::PxF32(l) => *self = Length::Px(Px(l.round() as i32)),
564            Length::DipF32(l) => *self = Length::Dip(Dip::new_f32(*l)),
565            _ => {}
566        }
567    }
568
569    /// Gets the total memory allocated by this length.
570    ///
571    /// This includes the sum of all nested [`Length::Expr`] heap memory.
572    pub fn memory_used(&self) -> ByteLength {
573        std::mem::size_of::<Length>().bytes() + self.heap_memory_used()
574    }
575
576    /// Sum total memory used in nested [`Length::Expr`] heap memory.
577    pub fn heap_memory_used(&self) -> ByteLength {
578        if let Length::Expr(e) = self { e.memory_used() } else { 0.bytes() }
579    }
580
581    /// 96.0 / 72.0
582    const PT_TO_DIP: f32 = 96.0 / 72.0; // 1.3333..;
583}
584impl super::Layout1d for Length {
585    fn layout_dft(&self, axis: LayoutAxis, default: Px) -> Px {
586        use Length::*;
587        match self {
588            Default => default,
589            Dip(l) => l.to_px(LAYOUT.scale_factor()),
590            Px(l) => *l,
591            Pt(l) => Self::pt_to_px(*l, LAYOUT.scale_factor()),
592            Factor(f) => LAYOUT.constraints_for(axis).fill() * f.0,
593            Leftover(f) => {
594                if let Some(l) = LAYOUT.leftover_for(axis) {
595                    l
596                } else {
597                    let fill = LAYOUT.constraints_for(axis).fill();
598                    (fill * f.0).clamp(self::Px(0), fill)
599                }
600            }
601            Em(f) => LAYOUT.font_size() * f.0,
602            RootEm(f) => LAYOUT.root_font_size() * f.0,
603            ViewportWidth(p) => LAYOUT.viewport().width * *p,
604            ViewportHeight(p) => LAYOUT.viewport().height * *p,
605            ViewportMin(p) => LAYOUT.viewport_min() * *p,
606            ViewportMax(p) => LAYOUT.viewport_max() * *p,
607            DipF32(l) => self::Px((l * LAYOUT.scale_factor().0).round() as i32),
608            PxF32(l) => self::Px(l.round() as i32),
609            Expr(e) => e.layout_dft(axis, default),
610        }
611    }
612
613    fn layout_f32_dft(&self, axis: LayoutAxis, default: f32) -> f32 {
614        use Length::*;
615        match self {
616            Default => default,
617            Dip(l) => l.to_f32() * LAYOUT.scale_factor().0,
618            Px(l) => l.0 as f32,
619            Pt(l) => Self::pt_to_px_f32(*l, LAYOUT.scale_factor()),
620            Factor(f) => LAYOUT.constraints_for(axis).fill().0 as f32 * f.0,
621            Leftover(f) => {
622                if let Some(l) = LAYOUT.leftover_for(axis) {
623                    l.0 as f32
624                } else {
625                    let fill = LAYOUT.constraints_for(axis).fill().0 as f32;
626                    (fill * f.0).clamp(0.0, fill)
627                }
628            }
629            Em(f) => LAYOUT.font_size().0 as f32 * f.0,
630            RootEm(f) => LAYOUT.root_font_size().0 as f32 * f.0,
631            ViewportWidth(p) => LAYOUT.viewport().width.0 as f32 * *p,
632            ViewportHeight(p) => LAYOUT.viewport().height.0 as f32 * *p,
633            ViewportMin(p) => LAYOUT.viewport_min().0 as f32 * *p,
634            ViewportMax(p) => LAYOUT.viewport_max().0 as f32 * *p,
635            DipF32(l) => *l * LAYOUT.scale_factor().0,
636            PxF32(l) => *l,
637            Expr(e) => e.layout_f32_dft(axis, default),
638        }
639    }
640
641    fn affect_mask(&self) -> LayoutMask {
642        use Length::*;
643        match self {
644            Default => LayoutMask::DEFAULT_VALUE,
645            Dip(_) => LayoutMask::SCALE_FACTOR,
646            Px(_) => LayoutMask::empty(),
647            Pt(_) => LayoutMask::SCALE_FACTOR,
648            Factor(_) => LayoutMask::CONSTRAINTS,
649            Leftover(_) => LayoutMask::LEFTOVER,
650            Em(_) => LayoutMask::FONT_SIZE,
651            RootEm(_) => LayoutMask::ROOT_FONT_SIZE,
652            ViewportWidth(_) => LayoutMask::VIEWPORT,
653            ViewportHeight(_) => LayoutMask::VIEWPORT,
654            ViewportMin(_) => LayoutMask::VIEWPORT,
655            ViewportMax(_) => LayoutMask::VIEWPORT,
656            DipF32(_) => LayoutMask::SCALE_FACTOR,
657            PxF32(_) => LayoutMask::empty(),
658            Expr(e) => e.affect_mask(),
659        }
660    }
661}
662
663/// Represents an unresolved [`Length`] expression.
664#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize)]
665pub enum LengthExpr {
666    /// Sums the both layout length.
667    Add(Length, Length),
668    /// Subtracts the first layout length from the second.
669    Sub(Length, Length),
670    /// Multiplies the layout length by the factor.
671    Mul(Length, Factor),
672    /// Divide the layout length by the factor.
673    Div(Length, Factor),
674    /// Maximum layout length.
675    Max(Length, Length),
676    /// Minimum layout length.
677    Min(Length, Length),
678    /// Computes the absolute layout length.
679    Abs(Length),
680    /// Negate the layout length.
681    Neg(Length),
682    /// Linear interpolate between lengths by factor.
683    Lerp(Length, Length, Factor),
684}
685impl LengthExpr {
686    /// Gets the total memory allocated by this length expression.
687    ///
688    /// This includes the sum of all nested [`Length::Expr`] heap memory.
689    pub fn memory_used(&self) -> ByteLength {
690        use LengthExpr::*;
691        std::mem::size_of::<LengthExpr>().bytes()
692            + match self {
693                Add(a, b) => a.heap_memory_used() + b.heap_memory_used(),
694                Sub(a, b) => a.heap_memory_used() + b.heap_memory_used(),
695                Mul(a, _) => a.heap_memory_used(),
696                Div(a, _) => a.heap_memory_used(),
697                Max(a, b) => a.heap_memory_used() + b.heap_memory_used(),
698                Min(a, b) => a.heap_memory_used() + b.heap_memory_used(),
699                Abs(a) => a.heap_memory_used(),
700                Neg(a) => a.heap_memory_used(),
701                Lerp(a, b, _) => a.heap_memory_used() + b.heap_memory_used(),
702            }
703    }
704
705    /// Convert to [`Length::Expr`], logs warning for memory use above 1kB, logs error for use > 20kB and collapses to [`Length::zero`].
706    ///
707    /// Every length expression created using the [`std::ops`] uses this method to check the constructed expression. Some operations
708    /// like iterator fold can cause an *expression explosion* where two lengths of different units that cannot
709    /// be evaluated immediately start an expression that subsequently is wrapped in a new expression for each operation done on it.
710    pub fn to_length_checked(self) -> Length {
711        let bytes = self.memory_used();
712        if bytes > 20.kibibytes() {
713            tracing::error!(target: "to_length_checked", "length alloc > 20kB, replaced with zero");
714            return Length::zero();
715        }
716        Length::Expr(Box::new(self))
717    }
718}
719impl super::Layout1d for LengthExpr {
720    fn layout_dft(&self, axis: LayoutAxis, default: Px) -> Px {
721        let l = self.layout_f32_dft(axis, default.0 as f32);
722        Px(l.round() as i32)
723    }
724
725    fn layout_f32_dft(&self, axis: LayoutAxis, default: f32) -> f32 {
726        use LengthExpr::*;
727        match self {
728            Add(a, b) => a.layout_f32_dft(axis, default) + b.layout_f32_dft(axis, default),
729            Sub(a, b) => a.layout_f32_dft(axis, default) - b.layout_f32_dft(axis, default),
730            Mul(l, s) => l.layout_f32_dft(axis, default) * s.0,
731            Div(l, s) => l.layout_f32_dft(axis, default) / s.0,
732            Max(a, b) => {
733                let a = a.layout_f32_dft(axis, default);
734                let b = b.layout_f32_dft(axis, default);
735                a.max(b)
736            }
737            Min(a, b) => {
738                let a = a.layout_f32_dft(axis, default);
739                let b = b.layout_f32_dft(axis, default);
740                a.min(b)
741            }
742            Abs(e) => e.layout_f32_dft(axis, default).abs(),
743            Neg(e) => -e.layout_f32_dft(axis, default),
744            Lerp(a, b, f) => a.layout_f32_dft(axis, default).lerp(&b.layout_f32_dft(axis, default), *f),
745        }
746    }
747
748    fn affect_mask(&self) -> LayoutMask {
749        use LengthExpr::*;
750        match self {
751            Add(a, b) => a.affect_mask() | b.affect_mask(),
752            Sub(a, b) => a.affect_mask() | b.affect_mask(),
753            Mul(a, _) => a.affect_mask(),
754            Div(a, _) => a.affect_mask(),
755            Max(a, b) => a.affect_mask() | b.affect_mask(),
756            Min(a, b) => a.affect_mask() | b.affect_mask(),
757            Abs(a) => a.affect_mask(),
758            Neg(a) => a.affect_mask(),
759            Lerp(a, b, _) => a.affect_mask() | b.affect_mask(),
760        }
761    }
762}
763impl fmt::Debug for LengthExpr {
764    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
765        use LengthExpr::*;
766        if f.alternate() {
767            match self {
768                Add(a, b) => f.debug_tuple("LengthExpr::Add").field(a).field(b).finish(),
769                Sub(a, b) => f.debug_tuple("LengthExpr::Sub").field(a).field(b).finish(),
770                Mul(l, s) => f.debug_tuple("LengthExpr::Mul").field(l).field(s).finish(),
771                Div(l, s) => f.debug_tuple("LengthExpr::Div").field(l).field(s).finish(),
772                Max(a, b) => f.debug_tuple("LengthExpr::Max").field(a).field(b).finish(),
773                Min(a, b) => f.debug_tuple("LengthExpr::Min").field(a).field(b).finish(),
774                Abs(e) => f.debug_tuple("LengthExpr::Abs").field(e).finish(),
775                Neg(e) => f.debug_tuple("LengthExpr::Neg").field(e).finish(),
776                Lerp(a, b, n) => f.debug_tuple("LengthExpr::Lerp").field(a).field(b).field(n).finish(),
777            }
778        } else {
779            match self {
780                Add(a, b) => write!(f, "({a:?} + {b:?})"),
781                Sub(a, b) => write!(f, "({a:?} - {b:?})"),
782                Mul(l, s) => write!(f, "({l:?} * {:?}.pct())", s.0 * 100.0),
783                Div(l, s) => write!(f, "({l:?} / {:?}.pct())", s.0 * 100.0),
784                Max(a, b) => write!(f, "max({a:?}, {b:?})"),
785                Min(a, b) => write!(f, "min({a:?}, {b:?})"),
786                Abs(e) => write!(f, "abs({e:?})"),
787                Neg(e) => write!(f, "-({e:?})"),
788                Lerp(a, b, n) => write!(f, "lerp({a:?}, {b:?}, {n:?})"),
789            }
790        }
791    }
792}
793impl fmt::Display for LengthExpr {
794    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
795        use LengthExpr::*;
796        match self {
797            Add(a, b) => write!(f, "({a} + {b})"),
798            Sub(a, b) => write!(f, "({a} - {b})"),
799            Mul(l, s) => write!(f, "({l} * {}%)", s.0 * 100.0),
800            Div(l, s) => write!(f, "({l} / {}%)", s.0 * 100.0),
801            Max(a, b) => write!(f, "max({a}, {b})"),
802            Min(a, b) => write!(f, "min({a}, {b})"),
803            Abs(e) => write!(f, "abs({e})"),
804            Neg(e) => write!(f, "-({e})"),
805            Lerp(a, b, n) => write!(f, "lerp({a}, {b}, {n})"),
806        }
807    }
808}
809
810/// Extension methods for initializing [`Length`] units.
811///
812/// This trait is implemented for [`f32`] and [`u32`] allowing initialization of length units using the `<number>.<unit>()` syntax.
813///
814/// # Examples
815///
816/// ```
817/// # use zng_layout::unit::*;
818/// let font_size = 1.em();
819/// let root_font_size = 1.rem();
820/// let viewport_width = 100.vw();
821/// let viewport_height = 100.vh();
822/// let viewport_min = 100.vmin();// min(width, height)
823/// let viewport_max = 100.vmax();// max(width, height)
824///
825/// // other length units not provided by `LengthUnits`:
826///
827/// let exact_size: Length = 500.into();
828/// let relative_size: Length = 100.pct().into();// FactorUnits
829/// let relative_size: Length = 1.0.fct().into();// FactorUnits
830/// ```
831pub trait LengthUnits {
832    /// Exact size in device independent pixels.
833    ///
834    /// Returns [`Length::Dip`].
835    fn dip(self) -> Length;
836
837    /// Exact size in device pixels.
838    ///
839    /// Returns [`Length::Px`].
840    fn px(self) -> Length;
841
842    /// Exact size in font units.
843    ///
844    /// Returns [`Length::Pt`].
845    fn pt(self) -> Length;
846
847    /// Factor of the fill length.
848    ///
849    /// This is the same as [`FactorUnits::fct`], but produces a [`Length`] directly. This might be needed
850    /// in places that don't automatically convert [`Factor`] to [`Length`].
851    ///
852    /// Returns [`Length::Factor`].
853    fn fct_l(self) -> Length;
854
855    /// Percentage of the fill length.
856    ///
857    /// This is the same as [`FactorUnits::pct`], but produces a [`Length`] directly. This might be needed
858    /// in places that don't automatically convert [`FactorPercent`] to [`Length`].
859    ///
860    /// Returns [`Length::Factor`].
861    fn pct_l(self) -> Length;
862
863    /// Factor of the font-size of the widget.
864    ///
865    /// Returns [`Length::Em`].
866    fn em(self) -> Length;
867
868    /// Percentage of the font-size of the widget.
869    ///
870    /// Returns [`Length::Em`].
871    fn em_pct(self) -> Length;
872
873    /// Factor of the font-size of the root widget.
874    ///
875    /// Returns [`Length::RootEm`].
876    fn rem(self) -> Length;
877
878    /// Percentage of the font-size of the root widget.
879    ///
880    /// Returns [`Length::RootEm`].
881    fn rem_pct(self) -> Length;
882
883    /// Factor of the width of the nearest viewport ancestor.
884    ///
885    /// Returns [`Length::ViewportWidth`].
886    fn vw(self) -> Length;
887
888    /// Percentage of the width of the nearest viewport ancestor.
889    ///
890    /// Returns [`Length::ViewportWidth`].
891    fn vw_pct(self) -> Length;
892
893    /// Factor of the height of the nearest viewport ancestor.
894    ///
895    /// Returns [`Length::ViewportHeight`].
896    fn vh(self) -> Length;
897
898    /// Percentage of the height of the nearest viewport ancestor.
899    ///
900    /// Returns [`Length::ViewportHeight`].
901    fn vh_pct(self) -> Length;
902
903    /// Factor of the smallest of the nearest viewport's dimensions.
904    ///
905    /// Returns [`Length::ViewportMin`].
906    fn vmin(self) -> Length;
907
908    /// Percentage of the smallest of the nearest viewport's dimensions.
909    ///
910    /// Returns [`Length::ViewportMin`].
911    fn vmin_pct(self) -> Length;
912
913    /// Factor of the largest of the nearest viewport's dimensions.
914    ///
915    /// Returns [`Length::ViewportMax`].
916    fn vmax(self) -> Length;
917
918    /// Percentage of the largest of the nearest viewport's dimensions.
919    ///
920    /// Returns [`Length::ViewportMax`].
921    fn vmax_pct(self) -> Length;
922
923    /// Factor of the leftover layout space.
924    ///
925    /// Note that this unit must be supported by the parent panel widget and property, otherwise it evaluates
926    /// like a single item having all the available fill space as leftover space.
927    ///
928    /// Returns [`Length::Leftover`].
929    fn lft(self) -> Length;
930}
931impl LengthUnits for f32 {
932    fn dip(self) -> Length {
933        Length::DipF32(self)
934    }
935
936    fn px(self) -> Length {
937        Length::PxF32(self)
938    }
939
940    fn pt(self) -> Length {
941        Length::Pt(self)
942    }
943
944    fn fct_l(self) -> Length {
945        Length::Factor(self.fct())
946    }
947
948    fn pct_l(self) -> Length {
949        Length::Factor(self.pct().fct())
950    }
951
952    fn em(self) -> Length {
953        Length::Em(self.into())
954    }
955
956    fn rem(self) -> Length {
957        Length::RootEm(self.into())
958    }
959
960    fn vw(self) -> Length {
961        Length::ViewportWidth(self.into())
962    }
963
964    fn vh(self) -> Length {
965        Length::ViewportHeight(self.into())
966    }
967
968    fn vmin(self) -> Length {
969        Length::ViewportMin(self.into())
970    }
971
972    fn vmax(self) -> Length {
973        Length::ViewportMax(self.into())
974    }
975
976    fn em_pct(self) -> Length {
977        Length::Em(self.pct().into())
978    }
979
980    fn rem_pct(self) -> Length {
981        Length::RootEm(self.pct().into())
982    }
983
984    fn vw_pct(self) -> Length {
985        Length::ViewportWidth(self.pct().into())
986    }
987
988    fn vh_pct(self) -> Length {
989        Length::ViewportHeight(self.pct().into())
990    }
991
992    fn vmin_pct(self) -> Length {
993        Length::ViewportMin(self.pct().into())
994    }
995
996    fn vmax_pct(self) -> Length {
997        Length::ViewportMax(self.pct().into())
998    }
999
1000    fn lft(self) -> Length {
1001        Length::Leftover(self.fct())
1002    }
1003}
1004impl LengthUnits for i32 {
1005    fn dip(self) -> Length {
1006        Length::Dip(Dip::new(self))
1007    }
1008
1009    fn px(self) -> Length {
1010        Length::Px(Px(self))
1011    }
1012
1013    fn pt(self) -> Length {
1014        Length::Pt(self as f32)
1015    }
1016
1017    fn fct_l(self) -> Length {
1018        Length::Factor(self.fct())
1019    }
1020
1021    fn pct_l(self) -> Length {
1022        Length::Factor(self.pct().fct())
1023    }
1024
1025    fn em(self) -> Length {
1026        Length::Em(self.fct())
1027    }
1028
1029    fn rem(self) -> Length {
1030        Length::RootEm(self.fct())
1031    }
1032
1033    fn vw(self) -> Length {
1034        Length::ViewportWidth(self.fct())
1035    }
1036
1037    fn vh(self) -> Length {
1038        Length::ViewportHeight(self.fct())
1039    }
1040
1041    fn vmin(self) -> Length {
1042        Length::ViewportMin(self.fct())
1043    }
1044
1045    fn vmax(self) -> Length {
1046        Length::ViewportMax(self.fct())
1047    }
1048
1049    fn em_pct(self) -> Length {
1050        Length::Em(self.pct().into())
1051    }
1052
1053    fn rem_pct(self) -> Length {
1054        Length::RootEm(self.pct().into())
1055    }
1056
1057    fn vw_pct(self) -> Length {
1058        Length::ViewportWidth(self.pct().into())
1059    }
1060
1061    fn vh_pct(self) -> Length {
1062        Length::ViewportHeight(self.pct().into())
1063    }
1064
1065    fn vmin_pct(self) -> Length {
1066        Length::ViewportMin(self.pct().into())
1067    }
1068
1069    fn vmax_pct(self) -> Length {
1070        Length::ViewportMax(self.pct().into())
1071    }
1072
1073    fn lft(self) -> Length {
1074        Length::Leftover(self.fct())
1075    }
1076}