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