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(&self, other: impl Into<Length>) -> Length {
601        // TODO(breaking) take `self`
602        let mut self_ = self.clone();
603        let mut other = other.into();
604        if self_.try_max(&mut other) {
605            self_
606        } else {
607            LengthExpr::Max(self_, other).to_length_checked()
608        }
609    }
610    pub(crate) fn try_max(&mut self, other: &mut Self) -> bool {
611        use Length::*;
612        let ok = match (mem::take(self), mem::take(other)) {
613            (Default, Default) => Default,
614            (Dip(a), Dip(b)) => Dip(a.max(b)),
615            (Px(a), Px(b)) => Px(a.max(b)),
616            (Pt(a), Pt(b)) => Pt(a.max(b)),
617            (Factor(a), Factor(b)) => Factor(a.max(b)),
618            (Leftover(a), Leftover(b)) => Leftover(a.max(b)),
619            (Em(a), Em(b)) => Em(a.max(b)),
620            (RootEm(a), RootEm(b)) => RootEm(a.max(b)),
621            (ViewportWidth(a), ViewportWidth(b)) => ViewportWidth(a.max(b)),
622            (ViewportHeight(a), ViewportHeight(b)) => ViewportHeight(a.max(b)),
623            (ViewportMin(a), ViewportMin(b)) => ViewportMin(a.max(b)),
624            (ViewportMax(a), ViewportMax(b)) => ViewportMax(a.max(b)),
625            (DipF32(a), DipF32(b)) => DipF32(a.max(b)),
626            (PxF32(a), PxF32(b)) => PxF32(a.max(b)),
627            (DipF32(a), Dip(b)) | (Dip(b), DipF32(a)) => DipF32(a.max(b.to_f32())),
628            (PxF32(a), Px(b)) | (Px(b), PxF32(a)) => PxF32(a.max(b.0 as f32)),
629            (a, b) => {
630                *self = a;
631                *other = b;
632                return false;
633            }
634        };
635        *self = ok;
636        true
637    }
638
639    /// Returns a length that resolves to the minimum layout length between `self` and `other`.
640    pub fn min(&self, other: impl Into<Length>) -> Length {
641        // TODO(breaking) take `self`
642        let mut self_ = self.clone();
643        let mut other = other.into();
644        if self_.try_min(&mut other) {
645            self_
646        } else {
647            LengthExpr::Min(self_, other).to_length_checked()
648        }
649    }
650    pub(crate) fn try_min(&mut self, other: &mut Self) -> bool {
651        use Length::*;
652        let ok = match (mem::take(self), mem::take(other)) {
653            (Default, Default) => Default,
654            (Dip(a), Dip(b)) => Dip(a.min(b)),
655            (Px(a), Px(b)) => Px(a.min(b)),
656            (Pt(a), Pt(b)) => Pt(a.min(b)),
657            (Factor(a), Factor(b)) => Factor(a.min(b)),
658            (Leftover(a), Leftover(b)) => Leftover(a.min(b)),
659            (Em(a), Em(b)) => Em(a.min(b)),
660            (RootEm(a), RootEm(b)) => RootEm(a.min(b)),
661            (ViewportWidth(a), ViewportWidth(b)) => ViewportWidth(a.min(b)),
662            (ViewportHeight(a), ViewportHeight(b)) => ViewportHeight(a.min(b)),
663            (ViewportMin(a), ViewportMin(b)) => ViewportMin(a.min(b)),
664            (ViewportMax(a), ViewportMax(b)) => ViewportMax(a.min(b)),
665            (DipF32(a), DipF32(b)) => DipF32(a.min(b)),
666            (PxF32(a), PxF32(b)) => PxF32(a.min(b)),
667            (DipF32(a), Dip(b)) | (Dip(b), DipF32(a)) => DipF32(a.min(b.to_f32())),
668            (PxF32(a), Px(b)) | (Px(b), PxF32(a)) => PxF32(a.min(b.0 as f32)),
669            (a, b) => {
670                *self = a;
671                *other = b;
672                return false;
673            }
674        };
675        *self = ok;
676        true
677    }
678
679    /// Returns a length that constraints the computed layout length between `min` and `max`.
680    pub fn clamp(&self, min: impl Into<Length>, max: impl Into<Length>) -> Length {
681        // TODO(breaking) take `self`
682        self.max(min).min(max)
683    }
684
685    /// Returns a length that computes the absolute layout length of `self`.
686    pub fn abs(&self) -> Length {
687        // TODO(breaking) take `self`
688        use Length::*;
689        match self {
690            Default => LengthExpr::Abs(Length::Default).to_length_checked(),
691            Dip(e) => Dip(e.abs()),
692            Px(e) => Px(e.abs()),
693            Pt(e) => Pt(e.abs()),
694            Factor(r) => Factor(r.abs()),
695            Leftover(r) => Leftover(r.abs()),
696            Em(e) => Em(e.abs()),
697            RootEm(r) => RootEm(r.abs()),
698            ViewportWidth(w) => ViewportWidth(w.abs()),
699            ViewportHeight(h) => ViewportHeight(h.abs()),
700            ViewportMin(m) => ViewportMin(m.abs()),
701            ViewportMax(m) => ViewportMax(m.abs()),
702            DipF32(e) => DipF32(e.abs()),
703            PxF32(e) => PxF32(e.abs()),
704            Expr(e) => LengthExpr::Abs(Length::Expr(e.clone())).to_length_checked(),
705        }
706    }
707
708    /// If this length is zero in any finite layout context.
709    ///
710    /// Returns `None` if the value depends on the default value or is an expression.
711    pub fn is_zero(&self) -> Option<bool> {
712        use Length::*;
713        match self {
714            Default => None,
715            Dip(l) => Some(*l == self::Dip::new(0)),
716            Px(l) => Some(*l == self::Px(0)),
717            Pt(l) => Some(about_eq(*l, 0.0, EQ_GRANULARITY)),
718            Factor(f) | Leftover(f) | Em(f) | RootEm(f) | ViewportWidth(f) | ViewportHeight(f) | ViewportMin(f) | ViewportMax(f) => {
719                Some(*f == 0.fct())
720            }
721            DipF32(l) => Some(about_eq(*l, 0.0, EQ_GRANULARITY_100)),
722            PxF32(l) => Some(about_eq(*l, 0.0, EQ_GRANULARITY_100)),
723            Expr(_) => None,
724        }
725    }
726
727    /// If this length is a negative value in any finite layout context.
728    ///
729    /// Returns `None` if the value depends on the default value or is an expression.
730    pub fn is_sign_negative(&self) -> Option<bool> {
731        use Length::*;
732        match self {
733            Default => None,
734            Dip(l) => Some(*l < self::Dip::new(0)),
735            Px(l) => Some(*l < self::Px(0)),
736            Pt(l) => Some(about_eq(*l, 0.0, EQ_GRANULARITY)),
737            Factor(f) | Leftover(f) | Em(f) | RootEm(f) | ViewportWidth(f) | ViewportHeight(f) | ViewportMin(f) | ViewportMax(f) => {
738                Some(*f < 0.fct())
739            }
740            DipF32(l) => Some(l.is_sign_negative()),
741            PxF32(l) => Some(l.is_sign_negative()),
742            Expr(_) => None,
743        }
744    }
745
746    /// Convert a `pt` unit value to [`Px`] given a `scale_factor`.
747    pub fn pt_to_px(pt: f32, scale_factor: Factor) -> Px {
748        let px = Self::pt_to_px_f32(pt, scale_factor);
749        Px(px.round() as i32)
750    }
751
752    /// Same operation as [`pt_to_px`] but without rounding to nearest pixel.
753    ///
754    /// [`pt_to_px`]: Self::pt_to_px
755    pub fn pt_to_px_f32(pt: f32, scale_factor: Factor) -> f32 {
756        pt * Self::PT_TO_DIP * scale_factor.0
757    }
758
759    /// Convert a [`Px`] unit value to a `Pt` value given a `scale_factor`.
760    pub fn px_to_pt(px: Px, scale_factor: Factor) -> f32 {
761        let dip = px.0 as f32 / scale_factor.0;
762        dip / Self::PT_TO_DIP
763    }
764
765    /// If is [`Default`].
766    ///
767    /// [`Default`]: Length::Default
768    pub fn is_default(&self) -> bool {
769        matches!(self, Length::Default)
770    }
771
772    /// If is [`Default`] or is [`Expr`] that contains defaults.
773    ///
774    /// [`Default`]: Length::Default
775    /// [`Expr`]: Length::Expr
776    pub fn has_default(&self) -> bool {
777        match self {
778            Length::Default => true,
779            Length::Expr(e) => e.has_default(),
780            _ => false,
781        }
782    }
783
784    /// Replaces `self` with `overwrite` if `self` is [`Default`] or replace all defaults in [`Expr`].
785    ///
786    /// [`Default`]: Length::Default
787    /// [`Expr`]: Length::Expr
788    pub fn replace_default(&mut self, overwrite: &Length) {
789        match self {
790            Length::Default => *self = overwrite.clone(),
791            Length::Expr(e) => e.replace_default(overwrite),
792            _ => {}
793        }
794    }
795
796    /// Convert [`PxF32`] to [`Px`] and [`DipF32`] to [`Dip`].
797    ///
798    /// [`PxF32`]: Self::PxF32
799    /// [`Px`]: Self::Px
800    /// [`DipF32`]: Self::DipF32
801    /// [`Dip`]: Self::Dip
802    pub fn round_exact(&mut self) {
803        match self {
804            Length::PxF32(l) => *self = Length::Px(Px(l.round() as i32)),
805            Length::DipF32(l) => *self = Length::Dip(Dip::new_f32(*l)),
806            Length::Expr(e) => e.round_exact(),
807            _ => {}
808        }
809    }
810
811    /// Evaluate expressions that don't need layout context to compute.
812    pub fn simplify(&mut self) {
813        if let Length::Expr(e) = self {
814            e.simplify();
815            if let LengthExpr::Unit(u) = &mut **e {
816                *self = mem::take(u);
817            }
818        }
819        if self.is_zero().unwrap_or(false) {
820            *self = Length::Px(Px(0));
821        }
822    }
823
824    /// Gets the total memory allocated by this length.
825    ///
826    /// This includes the sum of all nested [`Length::Expr`] heap memory.
827    pub fn memory_used(&self) -> ByteLength {
828        std::mem::size_of::<Length>().bytes() + self.heap_memory_used()
829    }
830
831    /// Sum total memory used in nested [`Length::Expr`] heap memory.
832    pub fn heap_memory_used(&self) -> ByteLength {
833        if let Length::Expr(e) = self { e.memory_used() } else { 0.bytes() }
834    }
835
836    /// 96.0 / 72.0
837    const PT_TO_DIP: f32 = 96.0 / 72.0; // 1.3333..;
838}
839impl super::Layout1d for Length {
840    fn layout_dft(&self, axis: LayoutAxis, default: Px) -> Px {
841        use Length::*;
842        match self {
843            Default => default,
844            Dip(l) => l.to_px(LAYOUT.scale_factor()),
845            Px(l) => *l,
846            Pt(l) => Self::pt_to_px(*l, LAYOUT.scale_factor()),
847            Factor(f) => LAYOUT.constraints_for(axis).fill() * f.0,
848            Leftover(f) => {
849                if let Some(l) = LAYOUT.leftover_for(axis) {
850                    l
851                } else {
852                    let fill = LAYOUT.constraints_for(axis).fill();
853                    (fill * f.0).clamp(self::Px(0), fill)
854                }
855            }
856            Em(f) => LAYOUT.font_size() * f.0,
857            RootEm(f) => LAYOUT.root_font_size() * f.0,
858            ViewportWidth(p) => LAYOUT.viewport().width * *p,
859            ViewportHeight(p) => LAYOUT.viewport().height * *p,
860            ViewportMin(p) => LAYOUT.viewport_min() * *p,
861            ViewportMax(p) => LAYOUT.viewport_max() * *p,
862            DipF32(l) => self::Px((l * LAYOUT.scale_factor().0).round() as i32),
863            PxF32(l) => self::Px(l.round() as i32),
864            Expr(e) => e.layout_dft(axis, default),
865        }
866    }
867
868    fn layout_f32_dft(&self, axis: LayoutAxis, default: f32) -> f32 {
869        use Length::*;
870        match self {
871            Default => default,
872            Dip(l) => l.to_f32() * LAYOUT.scale_factor().0,
873            Px(l) => l.0 as f32,
874            Pt(l) => Self::pt_to_px_f32(*l, LAYOUT.scale_factor()),
875            Factor(f) => LAYOUT.constraints_for(axis).fill().0 as f32 * f.0,
876            Leftover(f) => {
877                if let Some(l) = LAYOUT.leftover_for(axis) {
878                    l.0 as f32
879                } else {
880                    let fill = LAYOUT.constraints_for(axis).fill().0 as f32;
881                    (fill * f.0).clamp(0.0, fill)
882                }
883            }
884            Em(f) => LAYOUT.font_size().0 as f32 * f.0,
885            RootEm(f) => LAYOUT.root_font_size().0 as f32 * f.0,
886            ViewportWidth(p) => LAYOUT.viewport().width.0 as f32 * *p,
887            ViewportHeight(p) => LAYOUT.viewport().height.0 as f32 * *p,
888            ViewportMin(p) => LAYOUT.viewport_min().0 as f32 * *p,
889            ViewportMax(p) => LAYOUT.viewport_max().0 as f32 * *p,
890            DipF32(l) => *l * LAYOUT.scale_factor().0,
891            PxF32(l) => *l,
892            Expr(e) => e.layout_f32_dft(axis, default),
893        }
894    }
895
896    fn affect_mask(&self) -> LayoutMask {
897        use Length::*;
898        match self {
899            Default => LayoutMask::DEFAULT_VALUE,
900            Dip(_) => LayoutMask::SCALE_FACTOR,
901            Px(_) => LayoutMask::empty(),
902            Pt(_) => LayoutMask::SCALE_FACTOR,
903            Factor(_) => LayoutMask::CONSTRAINTS,
904            Leftover(_) => LayoutMask::LEFTOVER,
905            Em(_) => LayoutMask::FONT_SIZE,
906            RootEm(_) => LayoutMask::ROOT_FONT_SIZE,
907            ViewportWidth(_) => LayoutMask::VIEWPORT,
908            ViewportHeight(_) => LayoutMask::VIEWPORT,
909            ViewportMin(_) => LayoutMask::VIEWPORT,
910            ViewportMax(_) => LayoutMask::VIEWPORT,
911            DipF32(_) => LayoutMask::SCALE_FACTOR,
912            PxF32(_) => LayoutMask::empty(),
913            Expr(e) => e.affect_mask(),
914        }
915    }
916}
917
918/// Extension methods for initializing [`Length`] units.
919///
920/// This trait is implemented for [`f32`] and [`u32`] allowing initialization of length units using the `<number>.<unit>()` syntax.
921///
922/// # Examples
923///
924/// ```
925/// # use zng_layout::unit::*;
926/// let font_size = 1.em();
927/// let root_font_size = 1.rem();
928/// let viewport_width = 100.vw();
929/// let viewport_height = 100.vh();
930/// let viewport_min = 100.vmin(); // min(width, height)
931/// let viewport_max = 100.vmax(); // max(width, height)
932///
933/// // other length units not provided by `LengthUnits`:
934///
935/// let exact_size: Length = 500.into();
936/// let relative_size: Length = 100.pct().into(); // FactorUnits
937/// let relative_size: Length = 1.0.fct().into(); // FactorUnits
938/// ```
939pub trait LengthUnits {
940    /// Exact size in device independent pixels.
941    ///
942    /// Returns [`Length::Dip`].
943    fn dip(self) -> Length;
944
945    /// Exact size in device pixels.
946    ///
947    /// Returns [`Length::Px`].
948    fn px(self) -> Length;
949
950    /// Exact size in font units.
951    ///
952    /// Returns [`Length::Pt`].
953    fn pt(self) -> Length;
954
955    /// Factor of the fill length.
956    ///
957    /// This is the same as [`FactorUnits::fct`], but produces a [`Length`] directly. This might be needed
958    /// in places that don't automatically convert [`Factor`] to [`Length`].
959    ///
960    /// Returns [`Length::Factor`].
961    fn fct_l(self) -> Length;
962
963    /// Percentage of the fill length.
964    ///
965    /// This is the same as [`FactorUnits::pct`], but produces a [`Length`] directly. This might be needed
966    /// in places that don't automatically convert [`FactorPercent`] to [`Length`].
967    ///
968    /// Returns [`Length::Factor`].
969    fn pct_l(self) -> Length;
970
971    /// Factor of the font-size of the widget.
972    ///
973    /// Returns [`Length::Em`].
974    fn em(self) -> Length;
975
976    /// Percentage of the font-size of the widget.
977    ///
978    /// Returns [`Length::Em`].
979    fn em_pct(self) -> Length;
980
981    /// Factor of the font-size of the root widget.
982    ///
983    /// Returns [`Length::RootEm`].
984    fn rem(self) -> Length;
985
986    /// Percentage of the font-size of the root widget.
987    ///
988    /// Returns [`Length::RootEm`].
989    fn rem_pct(self) -> Length;
990
991    /// Factor of the width of the nearest viewport ancestor.
992    ///
993    /// Returns [`Length::ViewportWidth`].
994    fn vw(self) -> Length;
995
996    /// Percentage of the width of the nearest viewport ancestor.
997    ///
998    /// Returns [`Length::ViewportWidth`].
999    fn vw_pct(self) -> Length;
1000
1001    /// Factor of the height of the nearest viewport ancestor.
1002    ///
1003    /// Returns [`Length::ViewportHeight`].
1004    fn vh(self) -> Length;
1005
1006    /// Percentage of the height of the nearest viewport ancestor.
1007    ///
1008    /// Returns [`Length::ViewportHeight`].
1009    fn vh_pct(self) -> Length;
1010
1011    /// Factor of the smallest of the nearest viewport's dimensions.
1012    ///
1013    /// Returns [`Length::ViewportMin`].
1014    fn vmin(self) -> Length;
1015
1016    /// Percentage of the smallest of the nearest viewport's dimensions.
1017    ///
1018    /// Returns [`Length::ViewportMin`].
1019    fn vmin_pct(self) -> Length;
1020
1021    /// Factor of the largest of the nearest viewport's dimensions.
1022    ///
1023    /// Returns [`Length::ViewportMax`].
1024    fn vmax(self) -> Length;
1025
1026    /// Percentage of the largest of the nearest viewport's dimensions.
1027    ///
1028    /// Returns [`Length::ViewportMax`].
1029    fn vmax_pct(self) -> Length;
1030
1031    /// Factor of the leftover layout space.
1032    ///
1033    /// Note that this unit must be supported by the parent panel widget and property, otherwise it evaluates
1034    /// like a single item having all the available fill space as leftover space.
1035    ///
1036    /// Returns [`Length::Leftover`].
1037    fn lft(self) -> Length;
1038}
1039impl LengthUnits for f32 {
1040    fn dip(self) -> Length {
1041        Length::DipF32(self)
1042    }
1043
1044    fn px(self) -> Length {
1045        Length::PxF32(self)
1046    }
1047
1048    fn pt(self) -> Length {
1049        Length::Pt(self)
1050    }
1051
1052    fn fct_l(self) -> Length {
1053        Length::Factor(self.fct())
1054    }
1055
1056    fn pct_l(self) -> Length {
1057        Length::Factor(self.pct().fct())
1058    }
1059
1060    fn em(self) -> Length {
1061        Length::Em(self.into())
1062    }
1063
1064    fn rem(self) -> Length {
1065        Length::RootEm(self.into())
1066    }
1067
1068    fn vw(self) -> Length {
1069        Length::ViewportWidth(self.into())
1070    }
1071
1072    fn vh(self) -> Length {
1073        Length::ViewportHeight(self.into())
1074    }
1075
1076    fn vmin(self) -> Length {
1077        Length::ViewportMin(self.into())
1078    }
1079
1080    fn vmax(self) -> Length {
1081        Length::ViewportMax(self.into())
1082    }
1083
1084    fn em_pct(self) -> Length {
1085        Length::Em(self.pct().into())
1086    }
1087
1088    fn rem_pct(self) -> Length {
1089        Length::RootEm(self.pct().into())
1090    }
1091
1092    fn vw_pct(self) -> Length {
1093        Length::ViewportWidth(self.pct().into())
1094    }
1095
1096    fn vh_pct(self) -> Length {
1097        Length::ViewportHeight(self.pct().into())
1098    }
1099
1100    fn vmin_pct(self) -> Length {
1101        Length::ViewportMin(self.pct().into())
1102    }
1103
1104    fn vmax_pct(self) -> Length {
1105        Length::ViewportMax(self.pct().into())
1106    }
1107
1108    fn lft(self) -> Length {
1109        Length::Leftover(self.fct())
1110    }
1111}
1112impl LengthUnits for i32 {
1113    fn dip(self) -> Length {
1114        Length::Dip(Dip::new(self))
1115    }
1116
1117    fn px(self) -> Length {
1118        Length::Px(Px(self))
1119    }
1120
1121    fn pt(self) -> Length {
1122        Length::Pt(self as f32)
1123    }
1124
1125    fn fct_l(self) -> Length {
1126        Length::Factor(self.fct())
1127    }
1128
1129    fn pct_l(self) -> Length {
1130        Length::Factor(self.pct().fct())
1131    }
1132
1133    fn em(self) -> Length {
1134        Length::Em(self.fct())
1135    }
1136
1137    fn rem(self) -> Length {
1138        Length::RootEm(self.fct())
1139    }
1140
1141    fn vw(self) -> Length {
1142        Length::ViewportWidth(self.fct())
1143    }
1144
1145    fn vh(self) -> Length {
1146        Length::ViewportHeight(self.fct())
1147    }
1148
1149    fn vmin(self) -> Length {
1150        Length::ViewportMin(self.fct())
1151    }
1152
1153    fn vmax(self) -> Length {
1154        Length::ViewportMax(self.fct())
1155    }
1156
1157    fn em_pct(self) -> Length {
1158        Length::Em(self.pct().into())
1159    }
1160
1161    fn rem_pct(self) -> Length {
1162        Length::RootEm(self.pct().into())
1163    }
1164
1165    fn vw_pct(self) -> Length {
1166        Length::ViewportWidth(self.pct().into())
1167    }
1168
1169    fn vh_pct(self) -> Length {
1170        Length::ViewportHeight(self.pct().into())
1171    }
1172
1173    fn vmin_pct(self) -> Length {
1174        Length::ViewportMin(self.pct().into())
1175    }
1176
1177    fn vmax_pct(self) -> Length {
1178        Length::ViewportMax(self.pct().into())
1179    }
1180
1181    fn lft(self) -> Length {
1182        Length::Leftover(self.fct())
1183    }
1184}