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