1use core::{fmt::Display, ops::Deref};
2
3use alloc::{string::String, vec::Vec};
4use euclid::UnknownUnit;
5use float_pigment_css::typing::{Direction, WritingMode};
6
7use crate::LayoutTreeNode;
8pub(crate) use float_pigment_css::length_num::{length_sum, LengthNum};
9
10pub type Rect<L> = euclid::Rect<L, UnknownUnit>;
12
13pub type Size<L> = euclid::Size2D<L, UnknownUnit>;
15
16pub type OptionSize<L> = euclid::Size2D<OptionNum<L>, UnknownUnit>;
18
19pub type Vector<L> = euclid::Vector2D<L, euclid::UnknownUnit>;
21
22pub type Point<L> = euclid::Point2D<L, euclid::UnknownUnit>;
24
25pub(crate) trait PointGetter<T> {
26 fn main_axis(&self, dir: AxisDirection) -> T;
27 fn cross_axis(&self, dir: AxisDirection) -> T;
28}
29
30impl<L: LengthNum> PointGetter<L> for Point<L> {
31 fn main_axis(&self, dir: AxisDirection) -> L {
32 match dir {
33 AxisDirection::Horizontal => self.x,
34 AxisDirection::Vertical => self.y,
35 }
36 }
37 fn cross_axis(&self, dir: AxisDirection) -> L {
38 match dir {
39 AxisDirection::Horizontal => self.y,
40 AxisDirection::Vertical => self.x,
41 }
42 }
43}
44
45pub(crate) trait SizeGetter<T: Copy> {
46 fn main_size(&self, dir: AxisDirection) -> T;
47 fn cross_size(&self, dir: AxisDirection) -> T;
48}
49
50pub(crate) trait SizeSetter<T> {
51 fn set_main_size(&mut self, dir: AxisDirection, value: T);
52 fn set_cross_size(&mut self, dir: AxisDirection, value: T);
53}
54
55impl<T: Copy> SizeGetter<T> for euclid::Size2D<T, UnknownUnit> {
56 #[inline]
57 fn main_size(&self, dir: AxisDirection) -> T {
58 match dir {
59 AxisDirection::Horizontal => self.width,
60 AxisDirection::Vertical => self.height,
61 }
62 }
63
64 #[inline]
65 fn cross_size(&self, dir: AxisDirection) -> T {
66 match dir {
67 AxisDirection::Horizontal => self.height,
68 AxisDirection::Vertical => self.width,
69 }
70 }
71}
72
73impl<T> SizeSetter<T> for euclid::Size2D<T, UnknownUnit> {
74 #[inline]
75 fn set_main_size(&mut self, dir: AxisDirection, value: T) {
76 match dir {
77 AxisDirection::Horizontal => self.width = value,
78 AxisDirection::Vertical => self.height = value,
79 }
80 }
81
82 #[inline]
83 fn set_cross_size(&mut self, dir: AxisDirection, value: T) {
84 match dir {
85 AxisDirection::Horizontal => self.height = value,
86 AxisDirection::Vertical => self.width = value,
87 }
88 }
89}
90
91pub(crate) trait SizeProxy<T> {
92 fn new_with_dir(dir: AxisDirection, main_size: T, cross_size: T) -> Self;
93}
94
95impl<T> SizeProxy<T> for euclid::Size2D<T, UnknownUnit> {
96 #[inline(always)]
97 fn new_with_dir(dir: AxisDirection, main_size: T, cross_size: T) -> Self {
98 let (width, height) = match dir {
99 AxisDirection::Horizontal => (main_size, cross_size),
100 AxisDirection::Vertical => (cross_size, main_size),
101 };
102 Self::new(width, height)
103 }
104}
105
106pub(crate) trait OrZero<L: LengthNum>: Sized {
107 fn or_zero(&self) -> Size<L>;
108}
109
110impl<L: LengthNum> OrZero<L> for OptionSize<L> {
111 #[inline(always)]
112 fn or_zero(&self) -> Size<L> {
113 Size::new(self.width.or_zero(), self.height.or_zero())
114 }
115}
116
117pub(crate) trait VectorGetter<T> {
118 #[allow(unused)]
119 fn main_axis(&self, dir: AxisDirection) -> T;
120 fn cross_axis(&self, dir: AxisDirection) -> T;
121}
122
123impl<L: LengthNum> VectorGetter<L> for Vector<L> {
124 #[inline]
125 fn main_axis(&self, dir: AxisDirection) -> L {
126 match dir {
127 AxisDirection::Horizontal => self.x,
128 AxisDirection::Vertical => self.y,
129 }
130 }
131 #[inline]
132 fn cross_axis(&self, dir: AxisDirection) -> L {
133 match dir {
134 AxisDirection::Horizontal => self.y,
135 AxisDirection::Vertical => self.x,
136 }
137 }
138}
139
140pub(crate) trait VectorSetter<T> {
141 fn set_main_axis(&mut self, dir: AxisDirection, value: T);
142 fn set_cross_axis(&mut self, dir: AxisDirection, value: T);
143}
144
145impl<L: LengthNum> VectorSetter<L> for Vector<L> {
146 #[inline(always)]
147 fn set_main_axis(&mut self, dir: AxisDirection, value: L) {
148 match dir {
149 AxisDirection::Horizontal => self.x = value,
150 AxisDirection::Vertical => self.y = value,
151 }
152 }
153 #[inline(always)]
154 fn set_cross_axis(&mut self, dir: AxisDirection, value: L) {
155 match dir {
156 AxisDirection::Horizontal => self.y = value,
157 AxisDirection::Vertical => self.x = value,
158 }
159 }
160}
161
162pub(crate) trait VectorProxy<T> {
163 fn new_with_dir(dir: AxisDirection, main_axis: T, cross_axis: T) -> Self;
164}
165
166impl<L: LengthNum> VectorProxy<L> for Vector<L> {
167 fn new_with_dir(dir: AxisDirection, main_axis: L, cross_axis: L) -> Self {
168 let (x, y) = match dir {
169 AxisDirection::Horizontal => (main_axis, cross_axis),
170 AxisDirection::Vertical => (cross_axis, main_axis),
171 };
172 Self::new(x, y)
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Default)]
178pub enum DefLength<L: LengthNum, T: PartialEq + Clone = i32> {
179 #[default]
181 Undefined,
182
183 Auto,
185
186 Points(L),
188
189 Percent(f32),
191
192 Custom(T),
196}
197
198impl<L: LengthNum, T: PartialEq + Display + Clone> Display for DefLength<L, T> {
199 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200 match self {
201 Self::Undefined => write!(f, "Undefined"),
202 Self::Auto => write!(f, "Auto"),
203 Self::Points(x) => write!(f, "Points({})", L::to_f32(*x)),
204 Self::Percent(x) => write!(f, "Percent({})", *x),
205 Self::Custom(x) => write!(f, "Custom({})", *x),
206 }
207 }
208}
209
210impl<L: LengthNum, T: PartialEq + Clone> DefLength<L, T> {
211 pub(crate) fn resolve<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
212 &self,
213 parent: OptionNum<L>,
214 node: &N,
215 ) -> OptionNum<L> {
216 match self {
217 Self::Undefined => OptionNum::none(),
218 Self::Auto => OptionNum::none(),
219 Self::Points(x) => OptionNum::some(*x),
220 Self::Percent(x) => parent * *x,
221 Self::Custom(x) => {
222 OptionNum::some(node.resolve_custom_length(x, parent.unwrap_or(L::zero())))
223 }
224 }
225 }
226
227 pub(crate) fn resolve_with_auto<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
228 &self,
229 parent: OptionNum<L>,
230 node: &N,
231 ) -> OptionNum<L> {
232 match self {
233 Self::Undefined => OptionNum::some(L::zero()),
234 Self::Auto => OptionNum::none(),
235 Self::Points(x) => OptionNum::some(*x),
236 Self::Percent(x) => parent * *x,
237 Self::Custom(x) => {
238 OptionNum::some(node.resolve_custom_length(x, parent.unwrap_or(L::zero())))
239 }
240 }
241 }
242
243 pub(crate) fn resolve_num<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
244 &self,
245 parent: L,
246 node: &N,
247 ) -> OptionNum<L> {
248 match self {
249 Self::Undefined => OptionNum::none(),
250 Self::Auto => OptionNum::none(),
251 Self::Points(x) => OptionNum::some(*x),
252 Self::Percent(x) => OptionNum::some(parent.mul_f32(*x)),
253 Self::Custom(x) => OptionNum::some(node.resolve_custom_length(x, parent)),
254 }
255 }
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
260pub struct OptionNum<L>(Option<L>);
261
262impl<L: LengthNum> OptionNum<L> {
263 pub fn to_hashable(&self) -> OptionNum<L::Hashable> {
265 match self.0 {
266 None => OptionNum(None),
267 Some(x) => OptionNum(Some(x.to_hashable())),
268 }
269 }
270
271 #[inline]
273 pub fn none() -> Self {
274 Self(None)
275 }
276
277 #[inline]
279 pub fn some(v: L) -> Self {
280 Self(Some(v))
281 }
282
283 #[inline]
285 pub fn zero() -> Self {
286 Self(Some(L::zero()))
287 }
288
289 #[inline]
291 pub fn is_none(&self) -> bool {
292 self.0.is_none()
293 }
294
295 #[inline]
297 pub fn is_some(&self) -> bool {
298 self.0.is_some()
299 }
300
301 #[inline]
303 pub fn val(&self) -> Option<L> {
304 self.0
305 }
306
307 #[inline]
309 pub fn unwrap_or(self, rhs: L) -> L {
310 self.0.unwrap_or(rhs)
311 }
312
313 #[inline]
315 pub fn unwrap_or_else(self, f: impl FnOnce() -> L) -> L {
316 self.0.unwrap_or_else(f)
317 }
318
319 #[inline]
321 pub fn or(self, rhs: Self) -> Self {
322 Self(self.0.or(rhs.0))
323 }
324
325 #[inline]
327 pub fn or_zero(self) -> L {
328 self.0.unwrap_or_else(L::zero)
329 }
330
331 #[inline]
333 pub fn map(self, f: impl FnOnce(L) -> L) -> Self {
334 Self(self.0.map(f))
335 }
336}
337
338impl<L: LengthNum> From<Option<L>> for OptionNum<L> {
339 fn from(value: Option<L>) -> Self {
340 Self(value)
341 }
342}
343
344impl<L: LengthNum> core::ops::Add<L> for OptionNum<L> {
345 type Output = Self;
346
347 fn add(self, rhs: L) -> Self {
348 self.map(|x| x + rhs)
349 }
350}
351
352impl<L: LengthNum> core::ops::Sub<L> for OptionNum<L> {
353 type Output = Self;
354
355 fn sub(self, rhs: L) -> Self {
356 self.map(|x| x - rhs)
357 }
358}
359
360impl<L: LengthNum> core::ops::Mul<f32> for OptionNum<L> {
361 type Output = Self;
362
363 fn mul(self, rhs: f32) -> Self {
364 self.map(|x| x.mul_f32(rhs))
365 }
366}
367
368impl<L: LengthNum> core::ops::Mul<i32> for OptionNum<L> {
369 type Output = Self;
370
371 fn mul(self, rhs: i32) -> Self {
372 self.map(|x| x.mul_i32(rhs))
373 }
374}
375
376impl<L: LengthNum> core::ops::Add<Self> for OptionNum<L> {
377 type Output = Self;
378
379 fn add(self, rhs: Self) -> Self {
380 match rhs.val() {
381 Some(x) => self + x,
382 None => self,
383 }
384 }
385}
386
387impl<L: LengthNum> core::ops::Sub<Self> for OptionNum<L> {
388 type Output = Self;
389
390 fn sub(self, rhs: Self) -> Self {
391 match rhs.val() {
392 Some(x) => self - x,
393 None => self,
394 }
395 }
396}
397
398pub(crate) trait MinMax {
399 fn min(self, rhs: Self) -> Self;
400 fn max(self, rhs: Self) -> Self;
401}
402
403impl<L: LengthNum> MinMax for L {
404 fn min(self, rhs: Self) -> Self {
405 if self < rhs {
406 self
407 } else {
408 rhs
409 }
410 }
411
412 fn max(self, rhs: Self) -> Self {
413 if self > rhs {
414 self
415 } else {
416 rhs
417 }
418 }
419}
420
421pub(crate) trait MaybeMinMax<In, Out> {
422 fn maybe_min(self, rhs: In) -> Out;
423 fn maybe_max(self, rhs: In) -> Out;
424}
425
426impl<L: LengthNum> MaybeMinMax<OptionNum<L>, L> for L {
427 fn maybe_min(self, rhs: OptionNum<L>) -> L {
428 match rhs.val() {
429 None => self,
430 Some(x) => self.min(x),
431 }
432 }
433
434 fn maybe_max(self, rhs: OptionNum<L>) -> L {
435 match rhs.val() {
436 None => self,
437 Some(x) => self.max(x),
438 }
439 }
440}
441
442impl<L: LengthNum> MaybeMinMax<Self, Self> for OptionNum<L> {
443 fn maybe_min(self, rhs: Self) -> Self {
444 match self.val() {
445 None => OptionNum::none(),
446 Some(x) => match rhs.val() {
447 None => self,
448 Some(y) => OptionNum::some(x.min(y)),
449 },
450 }
451 }
452
453 fn maybe_max(self, rhs: Self) -> Self {
454 match self.val() {
455 None => OptionNum::none(),
456 Some(x) => match rhs.val() {
457 None => self,
458 Some(y) => OptionNum::some(x.max(y)),
459 },
460 }
461 }
462}
463
464impl<L: LengthNum> MaybeMinMax<L, Self> for OptionNum<L> {
465 fn maybe_min(self, rhs: L) -> OptionNum<L> {
466 match self.val() {
467 None => OptionNum::none(),
468 Some(x) => OptionNum::some(x.min(rhs)),
469 }
470 }
471
472 fn maybe_max(self, rhs: L) -> OptionNum<L> {
473 match self.val() {
474 None => OptionNum::none(),
475 Some(x) => OptionNum::some(x.max(rhs)),
476 }
477 }
478}
479
480impl<L: LengthNum> MaybeMinMax<OptionSize<L>, Size<L>> for Size<L> {
481 fn maybe_min(self, rhs: OptionSize<L>) -> Size<L> {
482 let width = match rhs.width.val() {
483 None => self.width,
484 Some(x) => self.width.min(x),
485 };
486 let height = match rhs.height.val() {
487 None => self.height,
488 Some(x) => self.height.min(x),
489 };
490 Size::new(width, height)
491 }
492
493 fn maybe_max(self, rhs: OptionSize<L>) -> Size<L> {
494 let width = match rhs.width.val() {
495 None => self.width,
496 Some(x) => self.width.max(x),
497 };
498 let height = match rhs.height.val() {
499 None => self.height,
500 Some(x) => self.height.max(x),
501 };
502 Size::new(width, height)
503 }
504}
505
506#[allow(missing_docs)]
508#[derive(Debug, Clone, Copy, PartialEq)]
509pub struct Edge<L: LengthNum> {
510 pub left: L,
511 pub right: L,
512 pub top: L,
513 pub bottom: L,
514}
515
516impl<L: LengthNum> Edge<L> {
517 #[inline(always)]
519 pub fn zero() -> Self {
520 Self {
521 left: L::zero(),
522 right: L::zero(),
523 top: L::zero(),
524 bottom: L::zero(),
525 }
526 }
527
528 #[inline(always)]
530 pub fn horizontal(&self) -> L {
531 self.left + self.right
532 }
533
534 #[inline(always)]
536 pub fn vertical(&self) -> L {
537 self.top + self.bottom
538 }
539
540 #[inline(always)]
541 pub(crate) fn main_axis_sum(&self, dir: AxisDirection) -> L {
542 match dir {
543 AxisDirection::Vertical => self.vertical(),
544 AxisDirection::Horizontal => self.horizontal(),
545 }
546 }
547
548 #[inline(always)]
549 pub(crate) fn cross_axis_sum(&self, dir: AxisDirection) -> L {
550 match dir {
551 AxisDirection::Vertical => self.horizontal(),
552 AxisDirection::Horizontal => self.vertical(),
553 }
554 }
555
556 #[inline(always)]
557 pub(crate) fn main_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> L {
558 match (dir, rev) {
559 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left,
560 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right,
561 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top,
562 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom,
563 }
564 }
565
566 #[allow(unused)]
567 #[inline(always)]
568 pub(crate) fn main_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> L {
569 match (dir, rev) {
570 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right,
571 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left,
572 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom,
573 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top,
574 }
575 }
576
577 #[inline(always)]
578 pub(crate) fn cross_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> L {
579 match (dir, rev) {
580 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top,
581 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom,
582 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left,
583 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right,
584 }
585 }
586
587 #[allow(unused)]
588 #[inline(always)]
589 pub(crate) fn cross_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> L {
590 match (dir, rev) {
591 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom,
592 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top,
593 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right,
594 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left,
595 }
596 }
597}
598
599impl<L: LengthNum> core::ops::Add<Edge<L>> for Edge<L> {
600 type Output = Self;
601
602 fn add(self, rhs: Edge<L>) -> Self {
603 Self {
604 left: self.left + rhs.left,
605 right: self.right + rhs.right,
606 top: self.top + rhs.top,
607 bottom: self.bottom + rhs.bottom,
608 }
609 }
610}
611
612impl<L: LengthNum> core::ops::Sub<Edge<L>> for Edge<L> {
613 type Output = Self;
614 fn sub(self, rhs: Edge<L>) -> Self {
615 Self {
616 left: self.left - rhs.left,
617 right: self.right - rhs.right,
618 top: self.top - rhs.top,
619 bottom: self.bottom - rhs.bottom,
620 }
621 }
622}
623
624#[allow(missing_docs)]
626#[derive(Debug, Clone, Copy, PartialEq)]
627pub struct EdgeOption<L: LengthNum> {
628 pub left: OptionNum<L>,
629 pub right: OptionNum<L>,
630 pub top: OptionNum<L>,
631 pub bottom: OptionNum<L>,
632}
633
634impl<L: LengthNum> EdgeOption<L> {
635 #[inline(always)]
637 pub fn or_zero(&self) -> Edge<L> {
638 Edge {
639 left: self.left.or_zero(),
640 right: self.right.or_zero(),
641 top: self.top.or_zero(),
642 bottom: self.bottom.or_zero(),
643 }
644 }
645
646 #[inline(always)]
648 pub fn horizontal(&self) -> L {
649 self.left.or_zero() + self.right.or_zero()
650 }
651
652 #[inline(always)]
654 pub fn vertical(&self) -> L {
655 self.top.or_zero() + self.bottom.or_zero()
656 }
657
658 pub(crate) fn is_left_right_either_none(&self) -> bool {
659 self.left.is_none() || self.right.is_none()
660 }
661
662 pub(crate) fn is_top_bottom_either_none(&self) -> bool {
663 self.top.is_none() || self.bottom.is_none()
664 }
665
666 #[inline(always)]
667 pub(crate) fn main_axis_sum(&self, dir: AxisDirection) -> L {
668 match dir {
669 AxisDirection::Horizontal => self.horizontal(),
670 AxisDirection::Vertical => self.vertical(),
671 }
672 }
673
674 #[inline(always)]
675 pub(crate) fn cross_axis_sum(&self, dir: AxisDirection) -> L {
676 match dir {
677 AxisDirection::Horizontal => self.vertical(),
678 AxisDirection::Vertical => self.horizontal(),
679 }
680 }
681
682 #[inline(always)]
683 pub(crate) fn main_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
684 match (dir, rev) {
685 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left,
686 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right,
687 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top,
688 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom,
689 }
690 }
691
692 #[inline(always)]
693 pub(crate) fn set_main_axis_start(
694 &mut self,
695 dir: AxisDirection,
696 rev: AxisReverse,
697 value: OptionNum<L>,
698 ) {
699 match (dir, rev) {
700 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left = value,
701 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right = value,
702 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top = value,
703 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom = value,
704 }
705 }
706
707 #[inline(always)]
708 pub(crate) fn main_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
709 match (dir, rev) {
710 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right,
711 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left,
712 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom,
713 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top,
714 }
715 }
716
717 #[inline(always)]
718 pub(crate) fn set_main_axis_end(
719 &mut self,
720 dir: AxisDirection,
721 rev: AxisReverse,
722 value: OptionNum<L>,
723 ) {
724 match (dir, rev) {
725 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right = value,
726 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left = value,
727 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom = value,
728 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top = value,
729 }
730 }
731
732 #[inline(always)]
733 pub(crate) fn cross_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
734 match (dir, rev) {
735 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top,
736 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom,
737 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left,
738 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right,
739 }
740 }
741
742 #[inline(always)]
743 pub(crate) fn set_cross_axis_start(
744 &mut self,
745 dir: AxisDirection,
746 rev: AxisReverse,
747 value: OptionNum<L>,
748 ) {
749 match (dir, rev) {
750 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top = value,
751 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom = value,
752 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left = value,
753 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right = value,
754 }
755 }
756
757 #[inline(always)]
758 pub(crate) fn cross_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
759 match (dir, rev) {
760 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom,
761 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top,
762 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right,
763 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left,
764 }
765 }
766
767 #[inline(always)]
768 pub(crate) fn set_cross_axis_end(
769 &mut self,
770 dir: AxisDirection,
771 rev: AxisReverse,
772 value: OptionNum<L>,
773 ) {
774 match (dir, rev) {
775 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom = value,
776 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top = value,
777 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right = value,
778 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left = value,
779 }
780 }
781}
782
783#[derive(Debug, Clone, Copy, PartialEq)]
784pub(crate) enum AxisDirection {
785 Horizontal,
786 Vertical,
787}
788
789#[derive(Debug, Clone, Copy, PartialEq, Hash)]
790pub(crate) enum AxisReverse {
791 NotReversed,
792 Reversed,
793}
794
795#[derive(Debug, Clone, Copy, PartialEq)]
796pub(crate) struct AxisInfo {
797 pub(crate) dir: AxisDirection,
798 pub(crate) main_dir_rev: AxisReverse,
799 pub(crate) cross_dir_rev: AxisReverse,
800}
801
802impl AxisInfo {
803 pub(crate) fn from_writing_mode(writing_mode: WritingMode) -> Self {
804 let (dir, main_dir_rev, cross_dir_rev) = match writing_mode {
805 WritingMode::HorizontalTb => (
806 AxisDirection::Vertical,
807 AxisReverse::NotReversed,
808 AxisReverse::NotReversed,
809 ),
810 WritingMode::VerticalLr => (
811 AxisDirection::Horizontal,
812 AxisReverse::NotReversed,
813 AxisReverse::NotReversed,
814 ),
815 WritingMode::VerticalRl => (
816 AxisDirection::Horizontal,
817 AxisReverse::Reversed,
818 AxisReverse::NotReversed,
819 ),
820 };
821 Self {
822 dir,
823 main_dir_rev,
824 cross_dir_rev,
825 }
826 }
827
828 pub(crate) fn from_writing_mode_and_direction(
830 writing_mode: WritingMode,
831 direction: Direction,
832 ) -> Self {
833 let rtl_reverse = if matches!(direction, Direction::RTL) {
834 AxisReverse::Reversed
835 } else {
836 AxisReverse::NotReversed
837 };
838 let (dir, main_dir_rev, cross_dir_rev) = match writing_mode {
839 WritingMode::HorizontalTb => (
841 AxisDirection::Vertical,
842 AxisReverse::NotReversed,
843 rtl_reverse,
844 ),
845 WritingMode::VerticalLr => (
847 AxisDirection::Horizontal,
848 AxisReverse::NotReversed,
849 rtl_reverse,
850 ),
851 WritingMode::VerticalRl => (
853 AxisDirection::Horizontal,
854 AxisReverse::Reversed,
855 rtl_reverse,
856 ),
857 };
858 Self {
859 dir,
860 main_dir_rev,
861 cross_dir_rev,
862 }
863 }
864}
865#[derive(Debug, Clone, Copy, PartialEq)]
866pub(crate) struct MinMaxSize<L: LengthNum> {
867 pub(crate) min_width: OptionNum<L>,
868 pub(crate) max_width: OptionNum<L>,
869 pub(crate) min_height: OptionNum<L>,
870 pub(crate) max_height: OptionNum<L>,
871}
872
873#[derive(Debug, Clone, Copy, PartialEq)]
874pub(crate) struct MinMaxLimit<L: LengthNum> {
875 pub(crate) min_width: L,
876 pub(crate) max_width: OptionNum<L>,
877 pub(crate) min_height: L,
878 pub(crate) max_height: OptionNum<L>,
879}
880
881impl<L: LengthNum> MinMaxLimit<L> {
882 pub(crate) fn normalized_size(&self, v: OptionSize<L>) -> Normalized<OptionSize<L>> {
883 Normalized(OptionSize::new(
884 v.width
885 .map(|x| x.maybe_min(self.max_width).max(self.min_width)),
886 v.height
887 .map(|x| x.maybe_min(self.max_height).max(self.min_height)),
888 ))
889 }
890
891 pub(crate) fn width(&self, x: L) -> L {
892 x.maybe_min(self.max_width).max(self.min_width)
893 }
894
895 pub(crate) fn height(&self, x: L) -> L {
896 x.maybe_min(self.max_height).max(self.min_height)
897 }
898
899 pub(crate) fn maybe(&self) -> MinMaxLimitMaybe<'_, L> {
900 MinMaxLimitMaybe(self)
901 }
902
903 #[inline(always)]
904 pub(crate) fn main_size(&self, x: L, dir: AxisDirection) -> L {
905 match dir {
906 AxisDirection::Horizontal => self.width(x),
907 AxisDirection::Vertical => self.height(x),
908 }
909 }
910
911 #[inline(always)]
912 pub(crate) fn cross_size(&self, x: L, dir: AxisDirection) -> L {
913 match dir {
914 AxisDirection::Horizontal => self.height(x),
915 AxisDirection::Vertical => self.width(x),
916 }
917 }
918
919 #[inline(always)]
920 pub(crate) fn min_main_size(&self, dir: AxisDirection) -> L {
921 match dir {
922 AxisDirection::Horizontal => self.min_width,
923 AxisDirection::Vertical => self.min_height,
924 }
925 }
926
927 #[inline(always)]
928 #[allow(unused)]
929 pub(crate) fn max_main_size(&self, dir: AxisDirection) -> OptionNum<L> {
930 match dir {
931 AxisDirection::Horizontal => self.max_width,
932 AxisDirection::Vertical => self.max_height,
933 }
934 }
935
936 #[inline(always)]
937 #[allow(unused)]
938 pub(crate) fn min_cross_size(&self, dir: AxisDirection) -> L {
939 match dir {
940 AxisDirection::Horizontal => self.min_height,
941 AxisDirection::Vertical => self.min_width,
942 }
943 }
944
945 #[inline(always)]
946 #[allow(unused)]
947 pub(crate) fn max_cross_size(&self, dir: AxisDirection) -> OptionNum<L> {
948 match dir {
949 AxisDirection::Horizontal => self.max_height,
950 AxisDirection::Vertical => self.max_width,
951 }
952 }
953
954 #[inline(always)]
955 #[allow(unused)]
956 pub(crate) fn set_min_cross_size(&mut self, x: L, dir: AxisDirection) {
957 match dir {
958 AxisDirection::Horizontal => self.min_height = x,
959 AxisDirection::Vertical => self.min_width = x,
960 }
961 }
962
963 #[inline(always)]
964 #[allow(unused)]
965 pub(crate) fn set_max_cross_size(&mut self, x: OptionNum<L>, dir: AxisDirection) {
966 match dir {
967 AxisDirection::Horizontal => self.max_height = x,
968 AxisDirection::Vertical => self.max_width = x,
969 }
970 }
971
972 #[inline(always)]
973 #[allow(unused)]
974 pub(crate) fn set_min_main_size(&mut self, x: L, dir: AxisDirection) {
975 match dir {
976 AxisDirection::Horizontal => self.min_width = x,
977 AxisDirection::Vertical => self.min_height = x,
978 }
979 }
980
981 #[inline(always)]
982 #[allow(unused)]
983 pub(crate) fn set_max_main_size(&mut self, x: OptionNum<L>, dir: AxisDirection) {
984 match dir {
985 AxisDirection::Horizontal => self.max_width = x,
986 AxisDirection::Vertical => self.max_height = x,
987 }
988 }
989}
990
991pub(crate) struct MinMaxLimitMaybe<'a, L: LengthNum>(&'a MinMaxLimit<L>);
992
993impl<'a, L: LengthNum> MinMaxLimitMaybe<'a, L> {
994 pub(crate) fn width(&self, v: OptionNum<L>) -> OptionNum<L> {
995 v.map(|x| x.maybe_min(self.0.max_width).max(self.0.min_width))
996 }
997
998 pub(crate) fn height(&self, v: OptionNum<L>) -> OptionNum<L> {
999 v.map(|x| x.maybe_min(self.0.max_height).max(self.0.min_height))
1000 }
1001
1002 #[inline(always)]
1003 #[allow(unused)]
1004 pub(crate) fn main_size(&self, dir: AxisDirection, v: OptionNum<L>) -> OptionNum<L> {
1005 match dir {
1006 AxisDirection::Horizontal => self.width(v),
1007 AxisDirection::Vertical => self.height(v),
1008 }
1009 }
1010
1011 #[inline(always)]
1012 pub(crate) fn cross_size(&self, dir: AxisDirection, v: OptionNum<L>) -> OptionNum<L> {
1013 match dir {
1014 AxisDirection::Horizontal => self.height(v),
1015 AxisDirection::Vertical => self.width(v),
1016 }
1017 }
1018}
1019
1020#[derive(Debug, Clone, Copy, PartialEq, Hash)]
1021pub(crate) struct Normalized<T>(pub(crate) T);
1022
1023impl<T> Deref for Normalized<T> {
1024 type Target = T;
1025
1026 fn deref(&self) -> &Self::Target {
1027 &self.0
1028 }
1029}
1030
1031#[inline(always)]
1032pub(crate) fn size_to_option<L: LengthNum>(size: Size<L>) -> OptionSize<L> {
1033 OptionSize::new(OptionNum::some(size.width), OptionNum::some(size.height))
1034}
1035
1036#[allow(missing_docs)]
1037#[derive(Debug, Clone, PartialEq, Default)]
1038pub enum LayoutGridTemplate<L: LengthNum, T: PartialEq + Clone = i32> {
1039 #[default]
1040 None,
1041 TrackList(Vec<LayoutTrackListItem<L, T>>),
1042}
1043
1044#[allow(missing_docs)]
1045#[derive(Debug, Clone, PartialEq)]
1046pub enum LayoutTrackListItem<L: LengthNum, T: PartialEq + Clone = i32> {
1047 LineNames(Vec<String>),
1048 TrackSize(LayoutTrackSize<L, T>),
1049}
1050
1051impl<L: LengthNum, T: PartialEq + Clone> LayoutTrackListItem<L, T> {
1052 pub fn is_intrinsic(&self) -> bool {
1055 matches!(
1056 self,
1057 LayoutTrackListItem::TrackSize(
1058 LayoutTrackSize::Length(DefLength::Auto)
1059 | LayoutTrackSize::MinContent
1060 | LayoutTrackSize::MaxContent
1061 )
1062 )
1063 }
1064}
1065
1066#[allow(missing_docs)]
1067#[derive(Debug, Clone, PartialEq)]
1068pub enum LayoutTrackSize<L: LengthNum, T: PartialEq + Clone = i32> {
1069 MinContent,
1070 MaxContent,
1071 Fr(f32),
1072 Length(DefLength<L, T>),
1073}
1074
1075#[allow(missing_docs)]
1081#[derive(Debug, Clone, PartialEq)]
1082pub struct LayoutGridAuto<L: LengthNum, T: PartialEq + Clone = i32>(pub Vec<LayoutTrackSize<L, T>>);
1083
1084impl<L: LengthNum, T: PartialEq + Clone> Default for LayoutGridAuto<L, T> {
1085 fn default() -> Self {
1086 Self(vec![LayoutTrackSize::Length(DefLength::Auto)])
1088 }
1089}
1090
1091impl<L: LengthNum, T: PartialEq + Clone> LayoutGridAuto<L, T> {
1092 pub fn get(&self, index: usize) -> LayoutTrackSize<L, T> {
1095 if self.0.is_empty() {
1096 LayoutTrackSize::Length(DefLength::Auto)
1097 } else {
1098 self.0[index % self.0.len()].clone()
1099 }
1100 }
1101
1102 pub fn len(&self) -> usize {
1104 self.0.len()
1105 }
1106
1107 pub fn is_empty(&self) -> bool {
1109 self.0.is_empty()
1110 }
1111}
1112
1113#[cfg(test)]
1114mod test {
1115
1116 use crate::{AxisDirection, Normalized, OptionSize, Size, SizeGetter, SizeSetter};
1117
1118 #[test]
1119 fn option_size_get_main_size() {
1120 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1121 let size = os.main_size(AxisDirection::Horizontal);
1122 assert_eq!(size.val(), Some(10.));
1124 let size = os.main_size(AxisDirection::Vertical);
1125 assert_eq!(size.val(), Some(20.));
1126 }
1127
1128 #[test]
1129 fn option_size_get_cross_size() {
1130 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1131 let size = os.cross_size(AxisDirection::Horizontal);
1132 assert_eq!(size.val(), Some(20.));
1133 let size = os.cross_size(AxisDirection::Vertical);
1134 assert_eq!(size.val(), Some(10.));
1135 }
1136
1137 #[test]
1138 fn normalized_option_size_get_size() {
1139 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1140 let normalized = Normalized(os);
1141 let size = normalized.main_size(AxisDirection::Horizontal);
1142 assert_eq!(size.val(), Some(10.));
1143 let size = normalized.main_size(AxisDirection::Vertical);
1144 assert_eq!(size.val(), Some(20.));
1145 }
1146
1147 #[test]
1148 fn size_get_size() {
1149 let s = Size::new(10.0_f32, 20.0_f32);
1150 let size = s.main_size(AxisDirection::Horizontal);
1151 assert_eq!(size, 10.);
1152 let size = s.main_size(AxisDirection::Vertical);
1153 assert_eq!(size, 20.);
1154 }
1155
1156 #[test]
1157 fn size_set_size() {
1158 let mut s = Size::new(10.0_f32, 20.0_f32);
1159 s.set_main_size(AxisDirection::Horizontal, 20.);
1160 assert_eq!(s.main_size(AxisDirection::Horizontal), 20.);
1161 s.set_cross_size(AxisDirection::Horizontal, 30.);
1162 assert_eq!(s.cross_size(AxisDirection::Horizontal), 30.);
1163 }
1164}