1use crate::container::{Align, Axis};
4use crate::overflow::Overflow;
5use sequoia_core::{Edges, Length, Size};
6
7#[derive(Clone, Copy, Debug, Default, PartialEq)]
9#[non_exhaustive]
10pub enum Position {
11 #[default]
13 Flow,
14 Absolute(Inset),
16}
17
18#[derive(Clone, Copy, Debug, Default, PartialEq)]
22#[non_exhaustive]
23pub struct Inset {
24 pub left: Option<f32>,
26 pub top: Option<f32>,
28 pub right: Option<f32>,
30 pub bottom: Option<f32>,
32}
33
34impl Inset {
35 pub const AUTO: Self = Self {
37 left: None,
38 top: None,
39 right: None,
40 bottom: None,
41 };
42
43 pub fn xy(left: f32, top: f32) -> Self {
45 Self {
46 left: Some(left),
47 top: Some(top),
48 right: None,
49 bottom: None,
50 }
51 }
52
53 pub const fn only(
55 left: Option<f32>,
56 top: Option<f32>,
57 right: Option<f32>,
58 bottom: Option<f32>,
59 ) -> Self {
60 Self {
61 left,
62 top,
63 right,
64 bottom,
65 }
66 }
67}
68
69#[derive(Clone, Copy, Debug, Default, PartialEq)]
71pub struct Indents {
72 pub left: Option<f32>,
74 pub top: Option<f32>,
76 pub right: Option<f32>,
78 pub bottom: Option<f32>,
80}
81
82impl Indents {
83 pub const NONE: Self = Self {
85 left: None,
86 top: None,
87 right: None,
88 bottom: None,
89 };
90
91 pub fn all(v: f32) -> Self {
93 let v = sanitize_indent(v);
94 Self {
95 left: Some(v),
96 top: Some(v),
97 right: Some(v),
98 bottom: Some(v),
99 }
100 }
101
102 pub fn xy(x: f32, y: f32) -> Self {
104 Self {
105 left: Some(sanitize_indent(x)),
106 top: Some(sanitize_indent(y)),
107 right: Some(sanitize_indent(x)),
108 bottom: Some(sanitize_indent(y)),
109 }
110 }
111
112 pub fn axes(horizontal: f32, vertical: f32) -> Self {
114 Self::xy(horizontal, vertical)
115 }
116
117 pub fn horizontal(v: f32) -> Self {
119 let v = sanitize_indent(v);
120 Self {
121 left: Some(v),
122 right: Some(v),
123 top: None,
124 bottom: None,
125 }
126 }
127
128 pub fn vertical(v: f32) -> Self {
130 let v = sanitize_indent(v);
131 Self {
132 left: None,
133 right: None,
134 top: Some(v),
135 bottom: Some(v),
136 }
137 }
138
139 pub const fn only(
141 left: Option<f32>,
142 top: Option<f32>,
143 right: Option<f32>,
144 bottom: Option<f32>,
145 ) -> Self {
146 Self {
147 left,
148 top,
149 right,
150 bottom,
151 }
152 }
153
154 pub fn is_none(self) -> bool {
156 self.left.is_none() && self.top.is_none() && self.right.is_none() && self.bottom.is_none()
157 }
158}
159
160#[derive(Clone, Copy, Debug, PartialEq)]
162pub struct LayoutStyle {
163 pub width: Length,
165 pub height: Length,
167 pub padding: Edges,
169 pub margin: Edges,
171 pub min_width: f32,
173 pub max_width: f32,
175 pub min_height: f32,
177 pub max_height: f32,
179 pub flex: f32,
181 pub flex_shrink: f32,
183 pub flex_basis: Option<Length>,
185 pub align_self: Option<Align>,
187 pub aspect_ratio: Option<f32>,
189 pub indent_top: Option<f32>,
191 pub indent_bottom: Option<f32>,
193 pub indent_left: Option<f32>,
195 pub indent_right: Option<f32>,
197 pub position: Position,
199 pub overflow: Overflow,
201 pub hit_testable: bool,
203}
204
205impl Default for LayoutStyle {
206 fn default() -> Self {
207 Self {
208 width: Length::Fit,
209 height: Length::Fit,
210 padding: Edges::ZERO,
211 margin: Edges::ZERO,
212 min_width: 0.0,
213 max_width: f32::INFINITY,
214 min_height: 0.0,
215 max_height: f32::INFINITY,
216 flex: 0.0,
217 flex_shrink: 1.0,
218 flex_basis: None,
219 align_self: None,
220 aspect_ratio: None,
221 indent_top: None,
222 indent_bottom: None,
223 indent_left: None,
224 indent_right: None,
225 position: Position::Flow,
226 overflow: Overflow::Visible,
227 hit_testable: true,
228 }
229 }
230}
231
232impl LayoutStyle {
233 pub fn width(mut self, width: Length) -> Self {
235 self.width = width;
236 self
237 }
238
239 pub fn height(mut self, height: Length) -> Self {
241 self.height = height;
242 self
243 }
244
245 pub fn fit(mut self) -> Self {
247 self.width = Length::Fit;
248 self.height = Length::Fit;
249 self
250 }
251
252 pub fn hit_testable(mut self, on: bool) -> Self {
254 self.hit_testable = on;
255 self
256 }
257
258 pub fn padding(mut self, padding: impl Into<Edges>) -> Self {
260 self.padding = padding.into();
261 self
262 }
263
264 pub fn pad(self, padding: impl Into<Edges>) -> Self {
266 self.padding(padding)
267 }
268
269 pub fn padding_xy(self, x: f32, y: f32) -> Self {
271 self.padding(Edges::xy(x, y))
272 }
273
274 pub fn padding_x(mut self, x: f32) -> Self {
276 self.padding.left = x;
277 self.padding.right = x;
278 self
279 }
280
281 pub fn padding_y(mut self, y: f32) -> Self {
283 self.padding.top = y;
284 self.padding.bottom = y;
285 self
286 }
287
288 pub fn padding_left(mut self, v: f32) -> Self {
290 self.padding.left = v;
291 self
292 }
293
294 pub fn padding_right(mut self, v: f32) -> Self {
296 self.padding.right = v;
297 self
298 }
299
300 pub fn padding_top(mut self, v: f32) -> Self {
302 self.padding.top = v;
303 self
304 }
305
306 pub fn padding_bottom(mut self, v: f32) -> Self {
308 self.padding.bottom = v;
309 self
310 }
311
312 pub fn min_width(mut self, v: f32) -> Self {
314 self.min_width = sanitize_min(v);
315 self
316 }
317
318 pub fn max_width(mut self, v: f32) -> Self {
320 self.max_width = sanitize_max(v);
321 self
322 }
323
324 pub fn min_height(mut self, v: f32) -> Self {
326 self.min_height = sanitize_min(v);
327 self
328 }
329
330 pub fn max_height(mut self, v: f32) -> Self {
332 self.max_height = sanitize_max(v);
333 self
334 }
335
336 pub fn clamp_width(self, w: f32) -> f32 {
338 clamp_axis(w, self.min_width, self.max_width)
339 }
340
341 pub fn clamp_height(self, h: f32) -> f32 {
343 clamp_axis(h, self.min_height, self.max_height)
344 }
345
346 pub fn clamp_size(self, size: sequoia_core::Size) -> sequoia_core::Size {
348 sequoia_core::Size::new(self.clamp_width(size.width), self.clamp_height(size.height))
349 }
350
351 pub fn margin(mut self, margin: impl Into<Edges>) -> Self {
353 let m = margin.into();
354 self.margin = Edges::only(
355 sanitize_edge(m.left),
356 sanitize_edge(m.top),
357 sanitize_edge(m.right),
358 sanitize_edge(m.bottom),
359 );
360 self
361 }
362
363 pub fn margin_xy(self, x: f32, y: f32) -> Self {
365 self.margin(Edges::xy(x, y))
366 }
367
368 pub fn margin_x(mut self, x: f32) -> Self {
370 let x = sanitize_edge(x);
371 self.margin.left = x;
372 self.margin.right = x;
373 self
374 }
375
376 pub fn margin_y(mut self, y: f32) -> Self {
378 let y = sanitize_edge(y);
379 self.margin.top = y;
380 self.margin.bottom = y;
381 self
382 }
383
384 pub fn margin_left(mut self, v: f32) -> Self {
386 self.margin.left = sanitize_edge(v);
387 self
388 }
389
390 pub fn margin_right(mut self, v: f32) -> Self {
392 self.margin.right = sanitize_edge(v);
393 self
394 }
395
396 pub fn margin_top(mut self, v: f32) -> Self {
398 self.margin.top = sanitize_edge(v);
399 self
400 }
401
402 pub fn margin_bottom(mut self, v: f32) -> Self {
404 self.margin.bottom = sanitize_edge(v);
405 self
406 }
407
408 pub fn flex(mut self, weight: f32) -> Self {
410 self.flex = sanitize_flex(weight);
411 self
412 }
413
414 pub fn flex_grow(mut self, weight: f32) -> Self {
416 self.flex = sanitize_flex(weight);
417 self
418 }
419
420 pub fn flex_shrink(mut self, shrink: f32) -> Self {
422 self.flex_shrink = sanitize_shrink(shrink);
423 self
424 }
425
426 pub fn flex_full(mut self, grow: f32, shrink: f32, basis: Option<Length>) -> Self {
428 self.flex = sanitize_flex(grow);
429 self.flex_shrink = sanitize_shrink(shrink);
430 self.flex_basis = basis;
431 self
432 }
433
434 pub fn flex_basis(mut self, basis: Option<Length>) -> Self {
436 self.flex_basis = basis;
437 self
438 }
439
440 pub fn no_basis(mut self) -> Self {
442 self.flex_basis = None;
443 self
444 }
445
446 pub fn expand(self) -> Self {
448 self.flex(1.0)
449 }
450
451 pub fn flex_weight(self) -> f32 {
453 sanitize_flex(self.flex)
454 }
455
456 pub fn flex_grow_weight(self) -> f32 {
458 sanitize_flex(self.flex)
459 }
460
461 pub fn flex_shrink_weight(self) -> f32 {
463 sanitize_shrink(self.flex_shrink)
464 }
465
466 pub fn align_self(mut self, align: Option<Align>) -> Self {
468 self.align_self = align;
469 self
470 }
471
472 pub fn align_self_value(mut self, align: Align) -> Self {
474 self.align_self = Some(align);
475 self
476 }
477
478 pub fn auto_align(mut self) -> Self {
480 self.align_self = None;
481 self
482 }
483
484 pub fn effective_align(self, container: Align) -> Align {
486 Align::resolve(self.align_self, container)
487 }
488
489 pub fn aspect_ratio(mut self, ratio: Option<f32>) -> Self {
491 self.aspect_ratio = sanitize_ratio(ratio);
492 self
493 }
494
495 pub fn aspect(mut self, ratio: f32) -> Self {
497 self.aspect_ratio = sanitize_ratio(Some(ratio));
498 self
499 }
500
501 pub fn no_aspect(mut self) -> Self {
503 self.aspect_ratio = None;
504 self
505 }
506
507 pub fn position(mut self, position: Position) -> Self {
509 self.position = position;
510 self
511 }
512
513 pub fn absolute(mut self) -> Self {
515 self.position = Position::Absolute(Inset::AUTO);
516 self
517 }
518
519 pub fn absolute_at(mut self, left: f32, top: f32) -> Self {
521 self.position = Position::Absolute(Inset::xy(left, top));
522 self
523 }
524
525 pub fn absolute_inset(mut self, inset: Inset) -> Self {
527 self.position = Position::Absolute(inset);
528 self
529 }
530
531 pub fn is_absolute(self) -> bool {
533 matches!(self.position, Position::Absolute(_))
534 }
535
536 pub fn absolute_inset_of(self) -> Option<Inset> {
538 match self.position {
539 Position::Absolute(inset) => Some(inset),
540 _ => None,
541 }
542 }
543
544 pub fn margin_main(self, axis: Axis) -> f32 {
546 match axis {
547 Axis::Horizontal => self.margin.left + self.margin.right,
548 Axis::Vertical => self.margin.top + self.margin.bottom,
549 }
550 }
551
552 pub fn margin_cross(self, axis: Axis) -> f32 {
554 match axis {
555 Axis::Horizontal => self.margin.top + self.margin.bottom,
556 Axis::Vertical => self.margin.left + self.margin.right,
557 }
558 }
559
560 pub fn apply_aspect(self, mut w: f32, mut h: f32, w_auto: bool, h_auto: bool) -> (f32, f32) {
562 let Some(r) = sanitize_ratio(self.aspect_ratio) else {
563 return (w, h);
564 };
565 if r <= 0.0 {
566 return (w, h);
567 }
568 match (w_auto, h_auto) {
569 (true, false) => {
570 w = (h * r).max(0.0);
571 }
572 (false, true) => {
573 h = if r != 0.0 { (w / r).max(0.0) } else { h };
574 }
575 (true, true) => {
576 if w <= 0.0 && h > 0.0 {
577 w = (h * r).max(0.0);
578 } else if h <= 0.0 && w > 0.0 {
579 h = (w / r).max(0.0);
580 }
581 }
582 (false, false) => {}
583 }
584 (w, h)
585 }
586
587 pub fn outer_size(self, inner: Size) -> Size {
589 Size::new(
590 inner.width + self.margin.horizontal_sum(),
591 inner.height + self.margin.vertical_sum(),
592 )
593 }
594
595 pub fn min_main(self, axis: Axis) -> f32 {
597 sanitize_min(match axis {
598 Axis::Horizontal => self.min_width,
599 Axis::Vertical => self.min_height,
600 })
601 }
602
603 pub fn max_main(self, axis: Axis) -> f32 {
605 sanitize_max(match axis {
606 Axis::Horizontal => self.max_width,
607 Axis::Vertical => self.max_height,
608 })
609 }
610
611 pub fn clamp_main(self, value: f32, axis: Axis) -> f32 {
613 clamp_axis(value, self.min_main(axis), self.max_main(axis))
614 }
615
616 pub fn overflow(mut self, overflow: Overflow) -> Self {
618 self.overflow = overflow;
619 self
620 }
621
622 pub fn indent_top(mut self, v: f32) -> Self {
624 self.indent_top = Some(sanitize_indent(v));
625 self
626 }
627
628 pub fn indent_bottom(mut self, v: f32) -> Self {
630 self.indent_bottom = Some(sanitize_indent(v));
631 self
632 }
633
634 pub fn indent_left(mut self, v: f32) -> Self {
636 self.indent_left = Some(sanitize_indent(v));
637 self
638 }
639
640 pub fn indent_right(mut self, v: f32) -> Self {
642 self.indent_right = Some(sanitize_indent(v));
643 self
644 }
645
646 pub fn clear_indent_top(mut self) -> Self {
648 self.indent_top = None;
649 self
650 }
651
652 pub fn clear_indent_bottom(mut self) -> Self {
654 self.indent_bottom = None;
655 self
656 }
657
658 pub fn clear_indent_left(mut self) -> Self {
660 self.indent_left = None;
661 self
662 }
663
664 pub fn clear_indent_right(mut self) -> Self {
666 self.indent_right = None;
667 self
668 }
669
670 pub fn clear_indents(mut self) -> Self {
672 self.indent_top = None;
673 self.indent_bottom = None;
674 self.indent_left = None;
675 self.indent_right = None;
676 self
677 }
678
679 pub fn indent(mut self, indents: Indents) -> Self {
681 if let Some(v) = indents.top {
682 self.indent_top = Some(sanitize_indent(v));
683 }
684 if let Some(v) = indents.bottom {
685 self.indent_bottom = Some(sanitize_indent(v));
686 }
687 if let Some(v) = indents.left {
688 self.indent_left = Some(sanitize_indent(v));
689 }
690 if let Some(v) = indents.right {
691 self.indent_right = Some(sanitize_indent(v));
692 }
693 self
694 }
695
696 pub fn indent_all(mut self, v: f32) -> Self {
698 let v = sanitize_indent(v);
699 self.indent_top = Some(v);
700 self.indent_bottom = Some(v);
701 self.indent_left = Some(v);
702 self.indent_right = Some(v);
703 self
704 }
705
706 pub fn indent_xy(mut self, x: f32, y: f32) -> Self {
708 let x = sanitize_indent(x);
709 let y = sanitize_indent(y);
710 self.indent_left = Some(x);
711 self.indent_right = Some(x);
712 self.indent_top = Some(y);
713 self.indent_bottom = Some(y);
714 self
715 }
716
717 pub fn indent_axes(self, horizontal: f32, vertical: f32) -> Self {
719 self.indent_xy(horizontal, vertical)
720 }
721
722 pub fn indent_main_start(self, axis: Axis) -> Option<f32> {
724 match axis {
725 Axis::Horizontal => self.indent_left,
726 Axis::Vertical => self.indent_top,
727 }
728 }
729
730 pub fn indent_main_end(self, axis: Axis) -> Option<f32> {
732 match axis {
733 Axis::Horizontal => self.indent_right,
734 Axis::Vertical => self.indent_bottom,
735 }
736 }
737
738 pub fn indent_cross_start(self, axis: Axis) -> Option<f32> {
740 match axis {
741 Axis::Horizontal => self.indent_top,
742 Axis::Vertical => self.indent_left,
743 }
744 }
745
746 pub fn indent_cross_end(self, axis: Axis) -> Option<f32> {
748 match axis {
749 Axis::Horizontal => self.indent_bottom,
750 Axis::Vertical => self.indent_right,
751 }
752 }
753
754 pub fn indents(self) -> Indents {
756 Indents {
757 left: self.indent_left,
758 top: self.indent_top,
759 right: self.indent_right,
760 bottom: self.indent_bottom,
761 }
762 }
763}
764
765pub fn sanitize_flex(v: f32) -> f32 {
767 if v.is_finite() && v > 0.0 { v } else { 0.0 }
768}
769
770pub fn sanitize_shrink(v: f32) -> f32 {
772 if v.is_finite() && v >= 0.0 {
773 v
774 } else if v.is_nan() {
775 1.0
776 } else {
777 0.0
778 }
779}
780
781pub fn sanitize_ratio(v: Option<f32>) -> Option<f32> {
783 match v {
784 Some(r) if r.is_finite() && r > 0.0 => Some(r),
785 _ => None,
786 }
787}
788
789fn sanitize_edge(v: f32) -> f32 {
790 if v.is_finite() { v.max(0.0) } else { 0.0 }
791}
792
793pub fn sanitize_indent(v: f32) -> f32 {
795 if v.is_finite() { v.max(0.0) } else { 0.0 }
796}
797
798fn sanitize_min(v: f32) -> f32 {
799 if !v.is_finite() || v < 0.0 { 0.0 } else { v }
800}
801
802fn sanitize_max(v: f32) -> f32 {
803 if v.is_nan() {
804 f32::INFINITY
805 } else if v.is_infinite() {
806 if v > 0.0 { f32::INFINITY } else { 0.0 }
807 } else {
808 v.max(0.0)
809 }
810}
811
812fn clamp_axis(value: f32, min: f32, max: f32) -> f32 {
813 let (min, max) = if min > max { (max, max) } else { (min, max) };
814 if value < min {
815 min
816 } else if value > max {
817 max
818 } else {
819 value
820 }
821}