1use crate::util::sys::f32_max;
4use crate::{style::Dimension, util::sys::f32_min};
5use core::ops::{Add, Sub};
6
7#[cfg(feature = "flexbox")]
8use crate::style::FlexDirection;
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12pub enum AbsoluteAxis {
13 Horizontal,
15 Vertical,
17}
18
19impl AbsoluteAxis {
20 #[inline]
22 pub const fn other_axis(&self) -> Self {
23 match *self {
24 AbsoluteAxis::Horizontal => AbsoluteAxis::Vertical,
25 AbsoluteAxis::Vertical => AbsoluteAxis::Horizontal,
26 }
27 }
28}
29
30impl<T> Size<T> {
31 #[inline(always)]
32 pub fn get_abs(self, axis: AbsoluteAxis) -> T {
34 match axis {
35 AbsoluteAxis::Horizontal => self.width,
36 AbsoluteAxis::Vertical => self.height,
37 }
38 }
39}
40
41impl<T: Add> Rect<T> {
42 #[inline(always)]
43 pub fn grid_axis_sum(self, axis: AbsoluteAxis) -> <T as Add>::Output {
45 match axis {
46 AbsoluteAxis::Horizontal => self.left + self.right,
47 AbsoluteAxis::Vertical => self.top + self.bottom,
48 }
49 }
50}
51
52#[derive(Copy, Clone, Debug, PartialEq, Eq)]
55pub enum AbstractAxis {
56 Inline,
58 Block,
60}
61
62impl AbstractAxis {
63 #[inline]
65 pub fn other(&self) -> AbstractAxis {
66 match *self {
67 AbstractAxis::Inline => AbstractAxis::Block,
68 AbstractAxis::Block => AbstractAxis::Inline,
69 }
70 }
71
72 #[inline]
75 pub fn as_abs_naive(&self) -> AbsoluteAxis {
76 match self {
77 AbstractAxis::Inline => AbsoluteAxis::Horizontal,
78 AbstractAxis::Block => AbsoluteAxis::Vertical,
79 }
80 }
81}
82
83#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub(crate) struct InBothAbsAxis<T> {
87 pub horizontal: T,
89 pub vertical: T,
91}
92
93impl<T: Copy> InBothAbsAxis<T> {
94 #[cfg(feature = "grid")]
95 pub fn get(&self, axis: AbsoluteAxis) -> T {
97 match axis {
98 AbsoluteAxis::Horizontal => self.horizontal,
99 AbsoluteAxis::Vertical => self.vertical,
100 }
101 }
102}
103
104#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
106#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
107pub struct Rect<T> {
108 pub left: T,
114 pub right: T,
120 pub top: T,
123 pub bottom: T,
126}
127
128impl<U, T: Add<U>> Add<Rect<U>> for Rect<T> {
129 type Output = Rect<T::Output>;
130
131 fn add(self, rhs: Rect<U>) -> Self::Output {
132 Rect {
133 left: self.left + rhs.left,
134 right: self.right + rhs.right,
135 top: self.top + rhs.top,
136 bottom: self.bottom + rhs.bottom,
137 }
138 }
139}
140
141impl<T> Rect<T> {
142 #[cfg(feature = "flexbox")]
148 pub(crate) fn zip_size<R, F, U>(self, size: Size<U>, f: F) -> Rect<R>
149 where
150 F: Fn(T, U) -> R,
151 U: Copy,
152 {
153 Rect {
154 left: f(self.left, size.width),
155 right: f(self.right, size.width),
156 top: f(self.top, size.height),
157 bottom: f(self.bottom, size.height),
158 }
159 }
160
161 pub fn map<R, F>(self, f: F) -> Rect<R>
165 where
166 F: Fn(T) -> R,
167 {
168 Rect { left: f(self.left), right: f(self.right), top: f(self.top), bottom: f(self.bottom) }
169 }
170
171 pub fn horizontal_components(self) -> Line<T> {
173 Line { start: self.left, end: self.right }
174 }
175
176 pub fn vertical_components(self) -> Line<T> {
178 Line { start: self.top, end: self.bottom }
179 }
180}
181
182impl<T, U> Rect<T>
183where
184 T: Add<Output = U> + Copy + Clone,
185{
186 #[inline(always)]
192 pub(crate) fn horizontal_axis_sum(&self) -> U {
193 self.left + self.right
194 }
195
196 #[inline(always)]
202 pub(crate) fn vertical_axis_sum(&self) -> U {
203 self.top + self.bottom
204 }
205
206 #[inline(always)]
210 #[allow(dead_code)] pub(crate) fn sum_axes(&self) -> Size<U> {
212 Size { width: self.horizontal_axis_sum(), height: self.vertical_axis_sum() }
213 }
214
215 #[cfg(feature = "flexbox")]
222 pub(crate) fn main_axis_sum(&self, direction: FlexDirection) -> U {
223 if direction.is_row() {
224 self.horizontal_axis_sum()
225 } else {
226 self.vertical_axis_sum()
227 }
228 }
229
230 #[cfg(feature = "flexbox")]
235 pub(crate) fn cross_axis_sum(&self, direction: FlexDirection) -> U {
236 if direction.is_row() {
237 self.vertical_axis_sum()
238 } else {
239 self.horizontal_axis_sum()
240 }
241 }
242}
243
244impl<T> Rect<T>
245where
246 T: Copy + Clone,
247{
248 #[cfg(feature = "flexbox")]
250 pub(crate) fn main_start(&self, direction: FlexDirection) -> T {
251 if direction.is_row() {
252 self.left
253 } else {
254 self.top
255 }
256 }
257
258 #[cfg(feature = "flexbox")]
260 pub(crate) fn main_end(&self, direction: FlexDirection) -> T {
261 if direction.is_row() {
262 self.right
263 } else {
264 self.bottom
265 }
266 }
267
268 #[cfg(feature = "flexbox")]
270 pub(crate) fn cross_start(&self, direction: FlexDirection) -> T {
271 if direction.is_row() {
272 self.top
273 } else {
274 self.left
275 }
276 }
277
278 #[cfg(feature = "flexbox")]
280 pub(crate) fn cross_end(&self, direction: FlexDirection) -> T {
281 if direction.is_row() {
282 self.bottom
283 } else {
284 self.right
285 }
286 }
287}
288
289impl Rect<f32> {
290 pub const ZERO: Rect<f32> = Self { left: 0.0, right: 0.0, top: 0.0, bottom: 0.0 };
292
293 #[must_use]
295 pub const fn new(start: f32, end: f32, top: f32, bottom: f32) -> Self {
296 Self { left: start, right: end, top, bottom }
297 }
298}
299
300#[derive(Debug, Copy, Clone, PartialEq, Eq)]
302#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
303#[cfg_attr(feature = "serde", serde(default))]
304pub struct Line<T> {
305 pub start: T,
307 pub end: T,
309}
310
311impl<T> Line<T> {
312 pub fn map<R, F>(self, f: F) -> Line<R>
316 where
317 F: Fn(T) -> R,
318 {
319 Line { start: f(self.start), end: f(self.end) }
320 }
321}
322
323impl Line<bool> {
324 pub const TRUE: Self = Line { start: true, end: true };
326 pub const FALSE: Self = Line { start: false, end: false };
328}
329
330impl<T: Add + Copy> Line<T> {
331 pub fn sum(&self) -> <T as Add>::Output {
333 self.start + self.end
334 }
335}
336
337#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
339#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
340pub struct Size<T> {
341 pub width: T,
343 pub height: T,
345}
346
347impl<U, T: Add<U>> Add<Size<U>> for Size<T> {
349 type Output = Size<<T as Add<U>>::Output>;
350
351 fn add(self, rhs: Size<U>) -> Self::Output {
352 Size { width: self.width + rhs.width, height: self.height + rhs.height }
353 }
354}
355
356impl<U, T: Sub<U>> Sub<Size<U>> for Size<T> {
358 type Output = Size<<T as Sub<U>>::Output>;
359
360 fn sub(self, rhs: Size<U>) -> Self::Output {
361 Size { width: self.width - rhs.width, height: self.height - rhs.height }
362 }
363}
364
365#[allow(dead_code)]
368impl<T> Size<T> {
369 pub fn map<R, F>(self, f: F) -> Size<R>
373 where
374 F: Fn(T) -> R,
375 {
376 Size { width: f(self.width), height: f(self.height) }
377 }
378
379 pub fn map_width<F>(self, f: F) -> Size<T>
381 where
382 F: Fn(T) -> T,
383 {
384 Size { width: f(self.width), height: self.height }
385 }
386
387 pub fn map_height<F>(self, f: F) -> Size<T>
389 where
390 F: Fn(T) -> T,
391 {
392 Size { width: self.width, height: f(self.height) }
393 }
394
395 pub fn zip_map<Other, Ret, Func>(self, other: Size<Other>, f: Func) -> Size<Ret>
398 where
399 Func: Fn(T, Other) -> Ret,
400 {
401 Size { width: f(self.width, other.width), height: f(self.height, other.height) }
402 }
403
404 #[cfg(feature = "flexbox")]
408 pub(crate) fn set_main(&mut self, direction: FlexDirection, value: T) {
409 if direction.is_row() {
410 self.width = value
411 } else {
412 self.height = value
413 }
414 }
415
416 #[cfg(feature = "flexbox")]
420 pub(crate) fn set_cross(&mut self, direction: FlexDirection, value: T) {
421 if direction.is_row() {
422 self.height = value
423 } else {
424 self.width = value
425 }
426 }
427
428 #[cfg(feature = "flexbox")]
432 pub(crate) fn with_main(self, direction: FlexDirection, value: T) -> Self {
433 let mut new = self;
434 if direction.is_row() {
435 new.width = value
436 } else {
437 new.height = value
438 }
439 new
440 }
441
442 #[cfg(feature = "flexbox")]
446 pub(crate) fn with_cross(self, direction: FlexDirection, value: T) -> Self {
447 let mut new = self;
448 if direction.is_row() {
449 new.height = value
450 } else {
451 new.width = value
452 }
453 new
454 }
455
456 #[cfg(feature = "flexbox")]
460 pub(crate) fn map_main(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
461 let mut new = self;
462 if direction.is_row() {
463 new.width = mapper(new.width);
464 } else {
465 new.height = mapper(new.height);
466 }
467 new
468 }
469
470 #[cfg(feature = "flexbox")]
474 pub(crate) fn map_cross(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
475 let mut new = self;
476 if direction.is_row() {
477 new.height = mapper(new.height);
478 } else {
479 new.width = mapper(new.width);
480 }
481 new
482 }
483
484 #[cfg(feature = "flexbox")]
488 pub(crate) fn main(self, direction: FlexDirection) -> T {
489 if direction.is_row() {
490 self.width
491 } else {
492 self.height
493 }
494 }
495
496 #[cfg(feature = "flexbox")]
500 pub(crate) fn cross(self, direction: FlexDirection) -> T {
501 if direction.is_row() {
502 self.height
503 } else {
504 self.width
505 }
506 }
507
508 #[cfg(feature = "grid")]
511 pub(crate) fn get(self, axis: AbstractAxis) -> T {
512 match axis {
513 AbstractAxis::Inline => self.width,
514 AbstractAxis::Block => self.height,
515 }
516 }
517
518 #[cfg(feature = "grid")]
521 pub(crate) fn set(&mut self, axis: AbstractAxis, value: T) {
522 match axis {
523 AbstractAxis::Inline => self.width = value,
524 AbstractAxis::Block => self.height = value,
525 }
526 }
527}
528
529impl Size<f32> {
530 pub const ZERO: Size<f32> = Self { width: 0.0, height: 0.0 };
532
533 #[inline(always)]
535 pub fn f32_max(self, rhs: Size<f32>) -> Size<f32> {
536 Size { width: f32_max(self.width, rhs.width), height: f32_max(self.height, rhs.height) }
537 }
538
539 #[inline(always)]
541 pub fn f32_min(self, rhs: Size<f32>) -> Size<f32> {
542 Size { width: f32_min(self.width, rhs.width), height: f32_min(self.height, rhs.height) }
543 }
544
545 #[inline(always)]
547 pub fn has_non_zero_area(self) -> bool {
548 self.width > 0.0 && self.height > 0.0
549 }
550}
551
552impl Size<Option<f32>> {
553 pub const NONE: Size<Option<f32>> = Self { width: None, height: None };
555
556 #[must_use]
558 pub const fn new(width: f32, height: f32) -> Self {
559 Size { width: Some(width), height: Some(height) }
560 }
561
562 pub fn maybe_apply_aspect_ratio(self, aspect_ratio: Option<f32>) -> Size<Option<f32>> {
568 match aspect_ratio {
569 Some(ratio) => match (self.width, self.height) {
570 (Some(width), None) => Size { width: Some(width), height: Some(width / ratio) },
571 (None, Some(height)) => Size { width: Some(height * ratio), height: Some(height) },
572 _ => self,
573 },
574 None => self,
575 }
576 }
577}
578
579impl<T> Size<Option<T>> {
580 pub fn unwrap_or(self, alt: Size<T>) -> Size<T> {
582 Size { width: self.width.unwrap_or(alt.width), height: self.height.unwrap_or(alt.height) }
583 }
584
585 pub fn or(self, alt: Size<Option<T>>) -> Size<Option<T>> {
587 Size { width: self.width.or(alt.width), height: self.height.or(alt.height) }
588 }
589
590 #[inline(always)]
592 pub fn both_axis_defined(&self) -> bool {
593 self.width.is_some() && self.height.is_some()
594 }
595}
596
597impl Size<Dimension> {
598 #[must_use]
600 pub const fn from_lengths(width: f32, height: f32) -> Self {
601 Size { width: Dimension::Length(width), height: Dimension::Length(height) }
602 }
603
604 #[must_use]
606 pub const fn from_percent(width: f32, height: f32) -> Self {
607 Size { width: Dimension::Percent(width), height: Dimension::Percent(height) }
608 }
609}
610
611#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
615#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
616pub struct Point<T> {
617 pub x: T,
619 pub y: T,
621}
622
623impl Point<f32> {
624 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
626}
627
628impl Point<Option<f32>> {
629 pub const NONE: Self = Self { x: None, y: None };
631}
632
633impl<U, T: Add<U>> Add<Point<U>> for Point<T> {
635 type Output = Point<<T as Add<U>>::Output>;
636
637 fn add(self, rhs: Point<U>) -> Self::Output {
638 Point { x: self.x + rhs.x, y: self.y + rhs.y }
639 }
640}
641
642impl<T> Point<T> {
643 pub fn map<R, F>(self, f: F) -> Point<R>
647 where
648 F: Fn(T) -> R,
649 {
650 Point { x: f(self.x), y: f(self.y) }
651 }
652
653 #[cfg(feature = "grid")]
656 pub fn get(self, axis: AbstractAxis) -> T {
657 match axis {
658 AbstractAxis::Inline => self.x,
659 AbstractAxis::Block => self.y,
660 }
661 }
662
663 pub fn transpose(self) -> Point<T> {
665 Point { x: self.y, y: self.x }
666 }
667
668 #[cfg(feature = "grid")]
671 pub fn set(&mut self, axis: AbstractAxis, value: T) {
672 match axis {
673 AbstractAxis::Inline => self.x = value,
674 AbstractAxis::Block => self.y = value,
675 }
676 }
677
678 #[cfg(feature = "flexbox")]
682 pub(crate) fn main(self, direction: FlexDirection) -> T {
683 if direction.is_row() {
684 self.x
685 } else {
686 self.y
687 }
688 }
689
690 #[cfg(feature = "flexbox")]
694 pub(crate) fn cross(self, direction: FlexDirection) -> T {
695 if direction.is_row() {
696 self.y
697 } else {
698 self.x
699 }
700 }
701}
702
703impl<T> From<Point<T>> for Size<T> {
704 fn from(value: Point<T>) -> Self {
705 Size { width: value.x, height: value.y }
706 }
707}
708
709#[derive(Debug, Copy, Clone, PartialEq, Eq)]
711#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
712pub struct MinMax<Min, Max> {
713 pub min: Min,
715 pub max: Max,
717}