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