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#[derive(Clone, serde::Serialize, serde::Deserialize)]
32#[non_exhaustive]
33pub enum Length {
34 Default,
36 Dip(Dip),
38 Px(Px),
40 Pt(f32),
42 Factor(Factor),
44 Leftover(Factor),
46 Em(Factor),
48 RootEm(Factor),
50 ViewportWidth(Factor),
52 ViewportHeight(Factor),
54 ViewportMin(Factor),
56 ViewportMax(Factor),
58
59 DipF32(f32),
64 PxF32(f32),
69
70 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; }
99 if rhs.is_zero() == Some(true) {
100 return true; }
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; } else if self.is_zero() == Some(true) {
156 *self = -mem::take(rhs);
157 return true; }
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; } else if rhs == 0.fct() {
214 *self = Self::zero();
215 return true; }
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; }
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 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 fn from(percent: FactorPercent) -> Length {
544 Length::Factor(percent.into())
545 }
546
547 fn from(norm: Factor) -> Length {
549 Length::Factor(norm)
550 }
551
552 fn from(f: f32) -> Length {
554 Length::DipF32(f)
555 }
556
557 fn from(i: i32) -> Length {
559 Length::Dip(Dip::new(i))
560 }
561
562 fn from(l: Px) -> Length {
564 Length::Px(l)
565 }
566
567 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 pub const fn zero() -> Length {
586 Length::Px(Px(0))
587 }
588
589 pub const fn fill() -> Length {
591 Length::Factor(Factor(1.0))
592 }
593
594 pub const fn half() -> Length {
596 Length::Factor(Factor(0.5))
597 }
598
599 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 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 pub fn clamp(self, min: impl Into<Length>, max: impl Into<Length>) -> Length {
677 self.max(min).min(max)
678 }
679
680 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 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 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 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 pub fn pt_to_px_f32(pt: f32, scale_factor: Factor) -> f32 {
750 pt * Self::PT_TO_DIP * scale_factor.0
751 }
752
753 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 pub fn is_default(&self) -> bool {
763 matches!(self, Length::Default)
764 }
765
766 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 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 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 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 pub fn memory_used(&self) -> ByteLength {
822 std::mem::size_of::<Length>().bytes() + self.heap_memory_used()
823 }
824
825 pub fn heap_memory_used(&self) -> ByteLength {
827 if let Length::Expr(e) = self { e.memory_used() } else { 0.bytes() }
828 }
829
830 const PT_TO_DIP: f32 = 96.0 / 72.0; }
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
912pub trait LengthUnits {
934 fn dip(self) -> Length;
938
939 fn px(self) -> Length;
943
944 fn pt(self) -> Length;
948
949 fn fct_l(self) -> Length;
956
957 fn pct_l(self) -> Length;
964
965 fn em(self) -> Length;
969
970 fn em_pct(self) -> Length;
974
975 fn rem(self) -> Length;
979
980 fn rem_pct(self) -> Length;
984
985 fn vw(self) -> Length;
989
990 fn vw_pct(self) -> Length;
994
995 fn vh(self) -> Length;
999
1000 fn vh_pct(self) -> Length;
1004
1005 fn vmin(self) -> Length;
1009
1010 fn vmin_pct(self) -> Length;
1014
1015 fn vmax(self) -> Length;
1019
1020 fn vmax_pct(self) -> Length;
1024
1025 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}