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)]
76pub struct Indents {
77 pub left: Option<Length>,
79 pub top: Option<Length>,
81 pub right: Option<Length>,
83 pub bottom: Option<Length>,
85}
86
87impl Indents {
88 pub const NONE: Self = Self {
90 left: None,
91 top: None,
92 right: None,
93 bottom: None,
94 };
95
96 pub fn all(v: f32) -> Self {
98 let v = Length::Px(sanitize_indent(v));
99 Self {
100 left: Some(v),
101 top: Some(v),
102 right: Some(v),
103 bottom: Some(v),
104 }
105 }
106
107 pub fn xy(x: f32, y: f32) -> Self {
109 Self {
110 left: Some(Length::Px(sanitize_indent(x))),
111 top: Some(Length::Px(sanitize_indent(y))),
112 right: Some(Length::Px(sanitize_indent(x))),
113 bottom: Some(Length::Px(sanitize_indent(y))),
114 }
115 }
116
117 pub fn axes(horizontal: f32, vertical: f32) -> Self {
119 Self::xy(horizontal, vertical)
120 }
121
122 pub fn horizontal(v: f32) -> Self {
124 let v = Length::Px(sanitize_indent(v));
125 Self {
126 left: Some(v),
127 right: Some(v),
128 top: None,
129 bottom: None,
130 }
131 }
132
133 pub fn vertical(v: f32) -> Self {
135 let v = Length::Px(sanitize_indent(v));
136 Self {
137 left: None,
138 right: None,
139 top: Some(v),
140 bottom: Some(v),
141 }
142 }
143
144 pub const fn only(
146 left: Option<Length>,
147 top: Option<Length>,
148 right: Option<Length>,
149 bottom: Option<Length>,
150 ) -> Self {
151 Self {
152 left,
153 top,
154 right,
155 bottom,
156 }
157 }
158
159 pub fn is_none(self) -> bool {
161 self.left.is_none() && self.top.is_none() && self.right.is_none() && self.bottom.is_none()
162 }
163}
164
165#[derive(Clone, Copy, Debug, PartialEq)]
167pub struct LayoutStyle {
168 pub width: Length,
170 pub height: Length,
172 pub padding: Edges,
174 pub margin: Edges,
176 pub min_width: f32,
178 pub max_width: f32,
180 pub min_height: f32,
182 pub max_height: f32,
184 pub flex: f32,
186 pub flex_shrink: f32,
188 pub flex_basis: Option<Length>,
190 pub align_self: Option<Align>,
192 pub aspect_ratio: Option<f32>,
194 pub indent_top: Option<Length>,
196 pub indent_bottom: Option<Length>,
198 pub indent_left: Option<Length>,
200 pub indent_right: Option<Length>,
202 pub position: Position,
204 pub overflow: Overflow,
206 pub hit_testable: bool,
208}
209
210impl Default for LayoutStyle {
211 fn default() -> Self {
212 Self {
213 width: Length::Fit,
214 height: Length::Fit,
215 padding: Edges::ZERO,
216 margin: Edges::ZERO,
217 min_width: 0.0,
218 max_width: f32::INFINITY,
219 min_height: 0.0,
220 max_height: f32::INFINITY,
221 flex: 0.0,
222 flex_shrink: 1.0,
223 flex_basis: None,
224 align_self: None,
225 aspect_ratio: None,
226 indent_top: None,
227 indent_bottom: None,
228 indent_left: None,
229 indent_right: None,
230 position: Position::Flow,
231 overflow: Overflow::Visible,
232 hit_testable: true,
233 }
234 }
235}
236
237impl LayoutStyle {
238 pub fn width(mut self, width: Length) -> Self {
240 self.width = width;
241 self
242 }
243
244 pub fn height(mut self, height: Length) -> Self {
246 self.height = height;
247 self
248 }
249
250 pub fn fit(mut self) -> Self {
252 self.width = Length::Fit;
253 self.height = Length::Fit;
254 self
255 }
256
257 pub fn hit_testable(mut self, on: bool) -> Self {
259 self.hit_testable = on;
260 self
261 }
262
263 pub fn padding(mut self, padding: impl Into<Edges>) -> Self {
265 self.padding = padding.into();
266 self
267 }
268
269 pub fn pad(self, padding: impl Into<Edges>) -> Self {
271 self.padding(padding)
272 }
273
274 pub fn padding_xy(self, x: f32, y: f32) -> Self {
276 self.padding(Edges::xy(x, y))
277 }
278
279 pub fn padding_x(mut self, x: f32) -> Self {
281 self.padding.left = x;
282 self.padding.right = x;
283 self
284 }
285
286 pub fn padding_y(mut self, y: f32) -> Self {
288 self.padding.top = y;
289 self.padding.bottom = y;
290 self
291 }
292
293 pub fn padding_left(mut self, v: f32) -> Self {
295 self.padding.left = v;
296 self
297 }
298
299 pub fn padding_right(mut self, v: f32) -> Self {
301 self.padding.right = v;
302 self
303 }
304
305 pub fn padding_top(mut self, v: f32) -> Self {
307 self.padding.top = v;
308 self
309 }
310
311 pub fn padding_bottom(mut self, v: f32) -> Self {
313 self.padding.bottom = v;
314 self
315 }
316
317 pub fn min_width(mut self, v: f32) -> Self {
319 self.min_width = sanitize_min(v);
320 self
321 }
322
323 pub fn max_width(mut self, v: f32) -> Self {
325 self.max_width = sanitize_max(v);
326 self
327 }
328
329 pub fn min_height(mut self, v: f32) -> Self {
331 self.min_height = sanitize_min(v);
332 self
333 }
334
335 pub fn max_height(mut self, v: f32) -> Self {
337 self.max_height = sanitize_max(v);
338 self
339 }
340
341 pub fn clamp_width(self, w: f32) -> f32 {
343 clamp_axis(w, self.min_width, self.max_width)
344 }
345
346 pub fn clamp_height(self, h: f32) -> f32 {
348 clamp_axis(h, self.min_height, self.max_height)
349 }
350
351 pub fn clamp_size(self, size: sequoia_core::Size) -> sequoia_core::Size {
353 sequoia_core::Size::new(self.clamp_width(size.width), self.clamp_height(size.height))
354 }
355
356 pub fn margin(mut self, margin: impl Into<Edges>) -> Self {
358 let m = margin.into();
359 self.margin = Edges::only(
360 sanitize_edge(m.left),
361 sanitize_edge(m.top),
362 sanitize_edge(m.right),
363 sanitize_edge(m.bottom),
364 );
365 self
366 }
367
368 pub fn margin_xy(self, x: f32, y: f32) -> Self {
370 self.margin(Edges::xy(x, y))
371 }
372
373 pub fn margin_x(mut self, x: f32) -> Self {
375 let x = sanitize_edge(x);
376 self.margin.left = x;
377 self.margin.right = x;
378 self
379 }
380
381 pub fn margin_y(mut self, y: f32) -> Self {
383 let y = sanitize_edge(y);
384 self.margin.top = y;
385 self.margin.bottom = y;
386 self
387 }
388
389 pub fn margin_left(mut self, v: f32) -> Self {
391 self.margin.left = sanitize_edge(v);
392 self
393 }
394
395 pub fn margin_right(mut self, v: f32) -> Self {
397 self.margin.right = sanitize_edge(v);
398 self
399 }
400
401 pub fn margin_top(mut self, v: f32) -> Self {
403 self.margin.top = sanitize_edge(v);
404 self
405 }
406
407 pub fn margin_bottom(mut self, v: f32) -> Self {
409 self.margin.bottom = sanitize_edge(v);
410 self
411 }
412
413 pub fn flex(mut self, weight: f32) -> Self {
415 self.flex = sanitize_flex(weight);
416 self
417 }
418
419 pub fn flex_grow(mut self, weight: f32) -> Self {
421 self.flex = sanitize_flex(weight);
422 self
423 }
424
425 pub fn flex_shrink(mut self, shrink: f32) -> Self {
427 self.flex_shrink = sanitize_shrink(shrink);
428 self
429 }
430
431 pub fn flex_full(mut self, grow: f32, shrink: f32, basis: Option<Length>) -> Self {
433 self.flex = sanitize_flex(grow);
434 self.flex_shrink = sanitize_shrink(shrink);
435 self.flex_basis = basis;
436 self
437 }
438
439 pub fn flex_basis(mut self, basis: Option<Length>) -> Self {
441 self.flex_basis = basis;
442 self
443 }
444
445 pub fn no_basis(mut self) -> Self {
447 self.flex_basis = None;
448 self
449 }
450
451 pub fn expand(self) -> Self {
453 self.flex(1.0)
454 }
455
456 pub fn flex_weight(self) -> f32 {
458 sanitize_flex(self.flex)
459 }
460
461 pub fn flex_grow_weight(self) -> f32 {
463 sanitize_flex(self.flex)
464 }
465
466 pub fn flex_shrink_weight(self) -> f32 {
468 sanitize_shrink(self.flex_shrink)
469 }
470
471 pub fn align_self(mut self, align: Option<Align>) -> Self {
473 self.align_self = align;
474 self
475 }
476
477 pub fn align_self_value(mut self, align: Align) -> Self {
479 self.align_self = Some(align);
480 self
481 }
482
483 pub fn auto_align(mut self) -> Self {
485 self.align_self = None;
486 self
487 }
488
489 pub fn effective_align(self, container: Align) -> Align {
491 Align::resolve(self.align_self, container)
492 }
493
494 pub fn aspect_ratio(mut self, ratio: Option<f32>) -> Self {
496 self.aspect_ratio = sanitize_ratio(ratio);
497 self
498 }
499
500 pub fn aspect(mut self, ratio: f32) -> Self {
502 self.aspect_ratio = sanitize_ratio(Some(ratio));
503 self
504 }
505
506 pub fn no_aspect(mut self) -> Self {
508 self.aspect_ratio = None;
509 self
510 }
511
512 pub fn position(mut self, position: Position) -> Self {
514 self.position = position;
515 self
516 }
517
518 pub fn absolute(mut self) -> Self {
520 self.position = Position::Absolute(Inset::AUTO);
521 self
522 }
523
524 pub fn absolute_at(mut self, left: f32, top: f32) -> Self {
526 self.position = Position::Absolute(Inset::xy(left, top));
527 self
528 }
529
530 pub fn absolute_inset(mut self, inset: Inset) -> Self {
532 self.position = Position::Absolute(inset);
533 self
534 }
535
536 pub fn is_absolute(self) -> bool {
538 matches!(self.position, Position::Absolute(_))
539 }
540
541 pub fn absolute_inset_of(self) -> Option<Inset> {
543 match self.position {
544 Position::Absolute(inset) => Some(inset),
545 _ => None,
546 }
547 }
548
549 pub fn margin_main(self, axis: Axis) -> f32 {
551 match axis {
552 Axis::Horizontal => self.margin.left + self.margin.right,
553 Axis::Vertical => self.margin.top + self.margin.bottom,
554 }
555 }
556
557 pub fn margin_cross(self, axis: Axis) -> f32 {
559 match axis {
560 Axis::Horizontal => self.margin.top + self.margin.bottom,
561 Axis::Vertical => self.margin.left + self.margin.right,
562 }
563 }
564
565 pub fn apply_aspect(self, mut w: f32, mut h: f32, w_auto: bool, h_auto: bool) -> (f32, f32) {
567 let Some(r) = sanitize_ratio(self.aspect_ratio) else {
568 return (w, h);
569 };
570 if r <= 0.0 {
571 return (w, h);
572 }
573 match (w_auto, h_auto) {
574 (true, false) => {
575 w = (h * r).max(0.0);
576 }
577 (false, true) => {
578 h = if r != 0.0 { (w / r).max(0.0) } else { h };
579 }
580 (true, true) => {
581 if w <= 0.0 && h > 0.0 {
582 w = (h * r).max(0.0);
583 } else if h <= 0.0 && w > 0.0 {
584 h = (w / r).max(0.0);
585 }
586 }
587 (false, false) => {}
588 }
589 (w, h)
590 }
591
592 pub fn outer_size(self, inner: Size) -> Size {
594 Size::new(
595 inner.width + self.margin.horizontal_sum(),
596 inner.height + self.margin.vertical_sum(),
597 )
598 }
599
600 pub fn min_main(self, axis: Axis) -> f32 {
602 sanitize_min(match axis {
603 Axis::Horizontal => self.min_width,
604 Axis::Vertical => self.min_height,
605 })
606 }
607
608 pub fn max_main(self, axis: Axis) -> f32 {
610 sanitize_max(match axis {
611 Axis::Horizontal => self.max_width,
612 Axis::Vertical => self.max_height,
613 })
614 }
615
616 pub fn clamp_main(self, value: f32, axis: Axis) -> f32 {
618 clamp_axis(value, self.min_main(axis), self.max_main(axis))
619 }
620
621 pub fn overflow(mut self, overflow: Overflow) -> Self {
623 self.overflow = overflow;
624 self
625 }
626
627 pub fn indent_top(mut self, v: impl Into<Length>) -> Self {
629 self.indent_top = Some(sanitize_indent_length(v.into()));
630 self
631 }
632
633 pub fn indent_bottom(mut self, v: impl Into<Length>) -> Self {
635 self.indent_bottom = Some(sanitize_indent_length(v.into()));
636 self
637 }
638
639 pub fn indent_left(mut self, v: impl Into<Length>) -> Self {
641 self.indent_left = Some(sanitize_indent_length(v.into()));
642 self
643 }
644
645 pub fn indent_right(mut self, v: impl Into<Length>) -> Self {
647 self.indent_right = Some(sanitize_indent_length(v.into()));
648 self
649 }
650
651 pub fn clear_indent_top(mut self) -> Self {
653 self.indent_top = None;
654 self
655 }
656
657 pub fn clear_indent_bottom(mut self) -> Self {
659 self.indent_bottom = None;
660 self
661 }
662
663 pub fn clear_indent_left(mut self) -> Self {
665 self.indent_left = None;
666 self
667 }
668
669 pub fn clear_indent_right(mut self) -> Self {
671 self.indent_right = None;
672 self
673 }
674
675 pub fn clear_indents(mut self) -> Self {
677 self.indent_top = None;
678 self.indent_bottom = None;
679 self.indent_left = None;
680 self.indent_right = None;
681 self
682 }
683
684 pub fn indent(mut self, indents: Indents) -> Self {
686 if let Some(v) = indents.top {
687 self.indent_top = Some(sanitize_indent_length(v));
688 }
689 if let Some(v) = indents.bottom {
690 self.indent_bottom = Some(sanitize_indent_length(v));
691 }
692 if let Some(v) = indents.left {
693 self.indent_left = Some(sanitize_indent_length(v));
694 }
695 if let Some(v) = indents.right {
696 self.indent_right = Some(sanitize_indent_length(v));
697 }
698 self
699 }
700
701 pub fn indent_all(mut self, v: f32) -> Self {
703 let v = Length::Px(sanitize_indent(v));
704 self.indent_top = Some(v);
705 self.indent_bottom = Some(v);
706 self.indent_left = Some(v);
707 self.indent_right = Some(v);
708 self
709 }
710
711 pub fn indent_xy(mut self, x: f32, y: f32) -> Self {
713 let x = Length::Px(sanitize_indent(x));
714 let y = Length::Px(sanitize_indent(y));
715 self.indent_left = Some(x);
716 self.indent_right = Some(x);
717 self.indent_top = Some(y);
718 self.indent_bottom = Some(y);
719 self
720 }
721
722 pub fn indent_axes(self, horizontal: f32, vertical: f32) -> Self {
724 self.indent_xy(horizontal, vertical)
725 }
726
727 pub fn indent_main_start(self, axis: Axis) -> Option<Length> {
729 match axis {
730 Axis::Horizontal => self.indent_left,
731 Axis::Vertical => self.indent_top,
732 }
733 }
734
735 pub fn indent_main_end(self, axis: Axis) -> Option<Length> {
737 match axis {
738 Axis::Horizontal => self.indent_right,
739 Axis::Vertical => self.indent_bottom,
740 }
741 }
742
743 pub fn indent_cross_start(self, axis: Axis) -> Option<Length> {
745 match axis {
746 Axis::Horizontal => self.indent_top,
747 Axis::Vertical => self.indent_left,
748 }
749 }
750
751 pub fn indent_cross_end(self, axis: Axis) -> Option<Length> {
753 match axis {
754 Axis::Horizontal => self.indent_bottom,
755 Axis::Vertical => self.indent_right,
756 }
757 }
758
759 pub fn indents(self) -> Indents {
761 Indents {
762 left: self.indent_left,
763 top: self.indent_top,
764 right: self.indent_right,
765 bottom: self.indent_bottom,
766 }
767 }
768}
769
770pub fn sanitize_flex(v: f32) -> f32 {
772 if v.is_finite() && v > 0.0 { v } else { 0.0 }
773}
774
775pub fn sanitize_shrink(v: f32) -> f32 {
777 if v.is_finite() && v >= 0.0 {
778 v
779 } else if v.is_nan() {
780 1.0
781 } else {
782 0.0
783 }
784}
785
786pub fn sanitize_ratio(v: Option<f32>) -> Option<f32> {
788 match v {
789 Some(r) if r.is_finite() && r > 0.0 => Some(r),
790 _ => None,
791 }
792}
793
794fn sanitize_edge(v: f32) -> f32 {
795 if v.is_finite() { v.max(0.0) } else { 0.0 }
796}
797
798pub fn sanitize_indent(v: f32) -> f32 {
800 if v.is_finite() { v.max(0.0) } else { 0.0 }
801}
802
803pub fn sanitize_indent_length(v: Length) -> Length {
805 match v {
806 Length::Px(v) => Length::Px(sanitize_indent(v)),
807 Length::Percent(v) => Length::Percent(sanitize_indent(v)),
808 Length::Fill(v) => Length::Fill(sanitize_flex(v)),
809 Length::Fit => Length::Px(0.0),
810 }
811}
812
813fn sanitize_min(v: f32) -> f32 {
814 if !v.is_finite() || v < 0.0 { 0.0 } else { v }
815}
816
817fn sanitize_max(v: f32) -> f32 {
818 if v.is_nan() {
819 f32::INFINITY
820 } else if v.is_infinite() {
821 if v > 0.0 { f32::INFINITY } else { 0.0 }
822 } else {
823 v.max(0.0)
824 }
825}
826
827fn clamp_axis(value: f32, min: f32, max: f32) -> f32 {
828 let (min, max) = if min > max { (max, max) } else { (min, max) };
829 if value < min {
830 min
831 } else if value > max {
832 max
833 } else {
834 value
835 }
836}