zng_layout/unit/
length.rs

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