Grid: resolve item percentages against grid area rather than grid container (#960)
1//! Geometric primitives useful for layout
2
3use crate::util::sys::f32_max;
4use crate::CompactLength;
5use crate::{style::Dimension, util::sys::f32_min};
6use core::ops::{Add, Sub};
7
8#[cfg(feature = "flexbox")]
9use crate::style::FlexDirection;
10
11/// The simple absolute horizontal and vertical axis
12#[derive(Copy, Clone, Debug, PartialEq, Eq)]
13pub enum AbsoluteAxis {
14 /// The horizontal axis
15 Horizontal,
16 /// The vertical axis
17 Vertical,
18}
19
20impl AbsoluteAxis {
21 /// Returns the other variant of the enum
22 #[inline]
23 pub const fn other_axis(&self) -> Self {
24 match *self {
25 AbsoluteAxis::Horizontal => AbsoluteAxis::Vertical,
26 AbsoluteAxis::Vertical => AbsoluteAxis::Horizontal,
27 }
28 }
29}
30
31impl<T> Size<T> {
32 #[inline(always)]
33 /// Get either the width or height depending on the AbsoluteAxis passed in
34 pub fn get_abs(self, axis: AbsoluteAxis) -> T {
35 match axis {
36 AbsoluteAxis::Horizontal => self.width,
37 AbsoluteAxis::Vertical => self.height,
38 }
39 }
40}
41
42impl<T: Add> Rect<T> {
43 #[inline(always)]
44 /// Get either the width or height depending on the AbsoluteAxis passed in
45 pub fn grid_axis_sum(self, axis: AbsoluteAxis) -> <T as Add>::Output {
46 match axis {
47 AbsoluteAxis::Horizontal => self.left + self.right,
48 AbsoluteAxis::Vertical => self.top + self.bottom,
49 }
50 }
51}
52
53/// The CSS abstract axis
54/// <https://www.w3.org/TR/css-writing-modes-3/#abstract-axes>
55#[derive(Copy, Clone, Debug, PartialEq, Eq)]
56pub enum AbstractAxis {
57 /// The axis in the inline dimension, i.e. the horizontal axis in horizontal writing modes and the vertical axis in vertical writing modes.
58 Inline,
59 /// The axis in the block dimension, i.e. the vertical axis in horizontal writing modes and the horizontal axis in vertical writing modes.
60 Block,
61}
62
63impl AbstractAxis {
64 /// Returns the other variant of the enum
65 #[inline]
66 pub const fn other(&self) -> AbstractAxis {
67 match *self {
68 AbstractAxis::Inline => AbstractAxis::Block,
69 AbstractAxis::Block => AbstractAxis::Inline,
70 }
71 }
72
73 /// Convert an `AbstractAxis` into an `AbsoluteAxis` naively assuming that the Inline axis is Horizontal
74 /// This is currently always true, but will change if Taffy ever implements the `writing_mode` property
75 #[inline]
76 pub const fn as_abs_naive(&self) -> AbsoluteAxis {
77 match self {
78 AbstractAxis::Inline => AbsoluteAxis::Horizontal,
79 AbstractAxis::Block => AbsoluteAxis::Vertical,
80 }
81 }
82}
83
84/// Container that holds an item in each absolute axis without specifying
85/// what kind of item it is.
86#[derive(Clone, Copy, Debug, PartialEq, Eq)]
87pub(crate) struct InBothAbsAxis<T> {
88 /// The item in the horizontal axis
89 pub horizontal: T,
90 /// The item in the vertical axis
91 pub vertical: T,
92}
93
94impl<T: Copy> InBothAbsAxis<T> {
95 #[cfg(feature = "grid")]
96 /// Get the contained item based on the AbsoluteAxis passed
97 pub const fn get(&self, axis: AbsoluteAxis) -> T {
98 match axis {
99 AbsoluteAxis::Horizontal => self.horizontal,
100 AbsoluteAxis::Vertical => self.vertical,
101 }
102 }
103}
104
105/// An axis-aligned UI rectangle
106#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
107#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
108pub struct Rect<T> {
109 /// This can represent either the x-coordinate of the starting edge,
110 /// or the amount of padding on the starting side.
111 ///
112 /// The starting edge is the left edge when working with LTR text,
113 /// and the right edge when working with RTL text.
114 pub left: T,
115 /// This can represent either the x-coordinate of the ending edge,
116 /// or the amount of padding on the ending side.
117 ///
118 /// The ending edge is the right edge when working with LTR text,
119 /// and the left edge when working with RTL text.
120 pub right: T,
121 /// This can represent either the y-coordinate of the top edge,
122 /// or the amount of padding on the top side.
123 pub top: T,
124 /// This can represent either the y-coordinate of the bottom edge,
125 /// or the amount of padding on the bottom side.
126 pub bottom: T,
127}
128
129impl<U, T: Add<U>> Add<Rect<U>> for Rect<T> {
130 type Output = Rect<T::Output>;
131
132 fn add(self, rhs: Rect<U>) -> Self::Output {
133 Rect {
134 left: self.left + rhs.left,
135 right: self.right + rhs.right,
136 top: self.top + rhs.top,
137 bottom: self.bottom + rhs.bottom,
138 }
139 }
140}
141
142impl<T> Rect<T> {
143 /// Applies the function `f` to all four sides of the rect
144 ///
145 /// When applied to the left and right sides, the width is used
146 /// as the second parameter of `f`.
147 /// When applied to the top or bottom sides, the height is used instead.
148 #[cfg(any(feature = "flexbox", feature = "block_layout"))]
149 pub(crate) fn zip_size<R, F, U>(self, size: Size<U>, f: F) -> Rect<R>
150 where
151 F: Fn(T, U) -> R,
152 U: Copy,
153 {
154 Rect {
155 left: f(self.left, size.width),
156 right: f(self.right, size.width),
157 top: f(self.top, size.height),
158 bottom: f(self.bottom, size.height),
159 }
160 }
161
162 /// Applies the function `f` to the left, right, top, and bottom properties
163 ///
164 /// This is used to transform a `Rect<T>` into a `Rect<R>`.
165 pub fn map<R, F>(self, f: F) -> Rect<R>
166 where
167 F: Fn(T) -> R,
168 {
169 Rect { left: f(self.left), right: f(self.right), top: f(self.top), bottom: f(self.bottom) }
170 }
171
172 /// Returns a `Line<T>` representing the left and right properties of the Rect
173 pub fn horizontal_components(self) -> Line<T> {
174 Line { start: self.left, end: self.right }
175 }
176
177 /// Returns a `Line<T>` containing the top and bottom properties of the Rect
178 pub fn vertical_components(self) -> Line<T> {
179 Line { start: self.top, end: self.bottom }
180 }
181}
182
183impl<T, U> Rect<T>
184where
185 T: Add<Output = U> + Copy + Clone,
186{
187 /// The sum of [`Rect.start`](Rect) and [`Rect.end`](Rect)
188 ///
189 /// This is typically used when computing total padding.
190 ///
191 /// **NOTE:** this is *not* the width of the rectangle.
192 #[inline(always)]
193 pub fn horizontal_axis_sum(&self) -> U {
194 self.left + self.right
195 }
196
197 /// The sum of [`Rect.top`](Rect) and [`Rect.bottom`](Rect)
198 ///
199 /// This is typically used when computing total padding.
200 ///
201 /// **NOTE:** this is *not* the height of the rectangle.
202 #[inline(always)]
203 pub fn vertical_axis_sum(&self) -> U {
204 self.top + self.bottom
205 }
206
207 /// Both horizontal_axis_sum and vertical_axis_sum as a `Size<T>`
208 ///
209 /// **NOTE:** this is *not* the width/height of the rectangle.
210 #[inline(always)]
211 #[allow(dead_code)] // Fixes spurious clippy warning: this function is used!
212 pub fn sum_axes(&self) -> Size<U> {
213 Size { width: self.horizontal_axis_sum(), height: self.vertical_axis_sum() }
214 }
215
216 /// The sum of the two fields of the [`Rect`] representing the main axis.
217 ///
218 /// This is typically used when computing total padding.
219 ///
220 /// If the [`FlexDirection`] is [`FlexDirection::Row`] or [`FlexDirection::RowReverse`], this is [`Rect::horizontal`].
221 /// Otherwise, this is [`Rect::vertical`].
222 #[cfg(feature = "flexbox")]
223 pub(crate) fn main_axis_sum(&self, direction: FlexDirection) -> U {
224 if direction.is_row() {
225 self.horizontal_axis_sum()
226 } else {
227 self.vertical_axis_sum()
228 }
229 }
230
231 /// The sum of the two fields of the [`Rect`] representing the cross axis.
232 ///
233 /// If the [`FlexDirection`] is [`FlexDirection::Row`] or [`FlexDirection::RowReverse`], this is [`Rect::vertical`].
234 /// Otherwise, this is [`Rect::horizontal`].
235 #[cfg(feature = "flexbox")]
236 pub(crate) fn cross_axis_sum(&self, direction: FlexDirection) -> U {
237 if direction.is_row() {
238 self.vertical_axis_sum()
239 } else {
240 self.horizontal_axis_sum()
241 }
242 }
243}
244
245impl<T> Rect<T>
246where
247 T: Copy + Clone,
248{
249 /// The `start` or `top` value of the [`Rect`], from the perspective of the main layout axis
250 #[cfg(feature = "flexbox")]
251 pub(crate) const fn main_start(&self, direction: FlexDirection) -> T {
252 if direction.is_row() {
253 self.left
254 } else {
255 self.top
256 }
257 }
258
259 /// The `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
260 #[cfg(feature = "flexbox")]
261 pub(crate) const fn main_end(&self, direction: FlexDirection) -> T {
262 if direction.is_row() {
263 self.right
264 } else {
265 self.bottom
266 }
267 }
268
269 /// The `start` or `top` value of the [`Rect`], from the perspective of the cross layout axis
270 #[cfg(feature = "flexbox")]
271 pub(crate) const fn cross_start(&self, direction: FlexDirection) -> T {
272 if direction.is_row() {
273 self.top
274 } else {
275 self.left
276 }
277 }
278
279 /// The `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
280 #[cfg(feature = "flexbox")]
281 pub(crate) const fn cross_end(&self, direction: FlexDirection) -> T {
282 if direction.is_row() {
283 self.bottom
284 } else {
285 self.right
286 }
287 }
288}
289
290impl Rect<f32> {
291 /// Creates a new Rect with `0.0` as all parameters
292 pub const ZERO: Rect<f32> = Self { left: 0.0, right: 0.0, top: 0.0, bottom: 0.0 };
293
294 /// Creates a new Rect
295 #[must_use]
296 pub const fn new(start: f32, end: f32, top: f32, bottom: f32) -> Self {
297 Self { left: start, right: end, top, bottom }
298 }
299}
300
301/// An abstract "line". Represents any type that has a start and an end
302#[derive(Debug, Copy, Clone, PartialEq, Eq)]
303#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
304#[cfg_attr(feature = "serde", serde(default))]
305pub struct Line<T> {
306 /// The start position of a line
307 pub start: T,
308 /// The end position of a line
309 pub end: T,
310}
311
312impl<T> Line<T> {
313 /// Applies the function `f` to both the width and height
314 ///
315 /// This is used to transform a `Line<T>` into a `Line<R>`.
316 pub fn map<R, F>(self, f: F) -> Line<R>
317 where
318 F: Fn(T) -> R,
319 {
320 Line { start: f(self.start), end: f(self.end) }
321 }
322}
323
324impl Line<bool> {
325 /// A `Line<bool>` with both start and end set to `true`
326 pub const TRUE: Self = Line { start: true, end: true };
327 /// A `Line<bool>` with both start and end set to `false`
328 pub const FALSE: Self = Line { start: false, end: false };
329}
330
331impl<T: Add + Copy> Line<T> {
332 /// Adds the start and end values together and returns the result
333 pub fn sum(&self) -> <T as Add>::Output {
334 self.start + self.end
335 }
336}
337
338/// The width and height of a [`Rect`]
339#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
340#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
341pub struct Size<T> {
342 /// The x extent of the rectangle
343 pub width: T,
344 /// The y extent of the rectangle
345 pub height: T,
346}
347
348// Generic Add impl for Size<T> + Size<U> where T + U has an Add impl
349impl<U, T: Add<U>> Add<Size<U>> for Size<T> {
350 type Output = Size<<T as Add<U>>::Output>;
351
352 fn add(self, rhs: Size<U>) -> Self::Output {
353 Size { width: self.width + rhs.width, height: self.height + rhs.height }
354 }
355}
356
357// Generic Sub impl for Size<T> + Size<U> where T + U has an Sub impl
358impl<U, T: Sub<U>> Sub<Size<U>> for Size<T> {
359 type Output = Size<<T as Sub<U>>::Output>;
360
361 fn sub(self, rhs: Size<U>) -> Self::Output {
362 Size { width: self.width - rhs.width, height: self.height - rhs.height }
363 }
364}
365
366// Note: we allow dead_code here as we want to provide a complete API of helpers that is symmetrical in all axes,
367// but sometimes we only currently have a use for the helper in a single axis
368#[allow(dead_code)]
369impl<T> Size<T> {
370 /// Applies the function `f` to both the width and height
371 ///
372 /// This is used to transform a `Size<T>` into a `Size<R>`.
373 pub fn map<R, F>(self, f: F) -> Size<R>
374 where
375 F: Fn(T) -> R,
376 {
377 Size { width: f(self.width), height: f(self.height) }
378 }
379
380 /// Applies the function `f` to the width
381 pub fn map_width<F>(self, f: F) -> Size<T>
382 where
383 F: Fn(T) -> T,
384 {
385 Size { width: f(self.width), height: self.height }
386 }
387
388 /// Applies the function `f` to the height
389 pub fn map_height<F>(self, f: F) -> Size<T>
390 where
391 F: Fn(T) -> T,
392 {
393 Size { width: self.width, height: f(self.height) }
394 }
395
396 /// Applies the function `f` to both the width and height
397 /// of this value and another passed value
398 pub fn zip_map<Other, Ret, Func>(self, other: Size<Other>, f: Func) -> Size<Ret>
399 where
400 Func: Fn(T, Other) -> Ret,
401 {
402 Size { width: f(self.width, other.width), height: f(self.height, other.height) }
403 }
404
405 /// Sets the extent of the main layout axis
406 ///
407 /// Whether this is the width or height depends on the `direction` provided
408 #[cfg(feature = "flexbox")]
409 pub(crate) fn set_main(&mut self, direction: FlexDirection, value: T) {
410 if direction.is_row() {
411 self.width = value
412 } else {
413 self.height = value
414 }
415 }
416
417 /// Sets the extent of the cross layout axis
418 ///
419 /// Whether this is the width or height depends on the `direction` provided
420 #[cfg(feature = "flexbox")]
421 pub(crate) fn set_cross(&mut self, direction: FlexDirection, value: T) {
422 if direction.is_row() {
423 self.height = value
424 } else {
425 self.width = value
426 }
427 }
428
429 /// Creates a new value of type Self with the main axis set to value provided
430 ///
431 /// Whether this is the width or height depends on the `direction` provided
432 #[cfg(feature = "flexbox")]
433 pub(crate) fn with_main(self, direction: FlexDirection, value: T) -> Self {
434 let mut new = self;
435 if direction.is_row() {
436 new.width = value
437 } else {
438 new.height = value
439 }
440 new
441 }
442
443 /// Creates a new value of type Self with the cross axis set to value provided
444 ///
445 /// Whether this is the width or height depends on the `direction` provided
446 #[cfg(feature = "flexbox")]
447 pub(crate) fn with_cross(self, direction: FlexDirection, value: T) -> Self {
448 let mut new = self;
449 if direction.is_row() {
450 new.height = value
451 } else {
452 new.width = value
453 }
454 new
455 }
456
457 /// Creates a new value of type Self with the main axis modified by the callback provided
458 ///
459 /// Whether this is the width or height depends on the `direction` provided
460 #[cfg(feature = "flexbox")]
461 pub(crate) fn map_main(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
462 let mut new = self;
463 if direction.is_row() {
464 new.width = mapper(new.width);
465 } else {
466 new.height = mapper(new.height);
467 }
468 new
469 }
470
471 /// Creates a new value of type Self with the cross axis modified by the callback provided
472 ///
473 /// Whether this is the width or height depends on the `direction` provided
474 #[cfg(feature = "flexbox")]
475 pub(crate) fn map_cross(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
476 let mut new = self;
477 if direction.is_row() {
478 new.height = mapper(new.height);
479 } else {
480 new.width = mapper(new.width);
481 }
482 new
483 }
484
485 /// Gets the extent of the main layout axis
486 ///
487 /// Whether this is the width or height depends on the `direction` provided
488 #[cfg(feature = "flexbox")]
489 pub(crate) fn main(self, direction: FlexDirection) -> T {
490 if direction.is_row() {
491 self.width
492 } else {
493 self.height
494 }
495 }
496
497 /// Gets the extent of the cross layout axis
498 ///
499 /// Whether this is the width or height depends on the `direction` provided
500 #[cfg(feature = "flexbox")]
501 pub(crate) fn cross(self, direction: FlexDirection) -> T {
502 if direction.is_row() {
503 self.height
504 } else {
505 self.width
506 }
507 }
508
509 /// Gets the extent of the specified layout axis
510 /// Whether this is the width or height depends on the `GridAxis` provided
511 #[cfg(feature = "grid")]
512 pub(crate) fn get(self, axis: AbstractAxis) -> T {
513 match axis {
514 AbstractAxis::Inline => self.width,
515 AbstractAxis::Block => self.height,
516 }
517 }
518
519 /// Sets the extent of the specified layout axis
520 /// Whether this is the width or height depends on the `GridAxis` provided
521 #[cfg(feature = "grid")]
522 pub(crate) fn set(&mut self, axis: AbstractAxis, value: T) {
523 match axis {
524 AbstractAxis::Inline => self.width = value,
525 AbstractAxis::Block => self.height = value,
526 }
527 }
528
529 /// Sets the extent of the specified layout axis
530 /// Whether this is the width or height depends on the `GridAxis` provided
531 #[cfg(feature = "grid")]
532 pub(crate) fn with(mut self, axis: AbstractAxis, value: T) -> Self {
533 match axis {
534 AbstractAxis::Inline => self.width = value,
535 AbstractAxis::Block => self.height = value,
536 }
537 self
538 }
539}
540
541impl Size<f32> {
542 /// A [`Size`] with zero width and height
543 pub const ZERO: Size<f32> = Self { width: 0.0, height: 0.0 };
544
545 /// Applies f32_max to each component separately
546 #[inline(always)]
547 pub fn f32_max(self, rhs: Size<f32>) -> Size<f32> {
548 Size { width: f32_max(self.width, rhs.width), height: f32_max(self.height, rhs.height) }
549 }
550
551 /// Applies f32_min to each component separately
552 #[inline(always)]
553 pub fn f32_min(self, rhs: Size<f32>) -> Size<f32> {
554 Size { width: f32_min(self.width, rhs.width), height: f32_min(self.height, rhs.height) }
555 }
556
557 /// Return true if both width and height are greater than 0 else false
558 #[inline(always)]
559 pub fn has_non_zero_area(self) -> bool {
560 self.width > 0.0 && self.height > 0.0
561 }
562}
563
564impl Size<Option<f32>> {
565 /// A [`Size`] with `None` width and height
566 pub const NONE: Size<Option<f32>> = Self { width: None, height: None };
567
568 /// A [`Size<Option<f32>>`] with `Some(width)` and `Some(height)` as parameters
569 #[must_use]
570 pub const fn new(width: f32, height: f32) -> Self {
571 Size { width: Some(width), height: Some(height) }
572 }
573
574 /// Creates a new [`Size<Option<f32>>`] with either the width or height set based on the provided `direction`
575 #[cfg(feature = "flexbox")]
576 pub const fn from_cross(direction: FlexDirection, value: Option<f32>) -> Self {
577 let mut new = Self::NONE;
578 if direction.is_row() {
579 new.height = value
580 } else {
581 new.width = value
582 }
583 new
584 }
585
586 /// Applies aspect_ratio (if one is supplied) to the Size:
587 /// - If width is `Some` but height is `None`, then height is computed from width and aspect_ratio
588 /// - If height is `Some` but width is `None`, then width is computed from height and aspect_ratio
589 ///
590 /// If aspect_ratio is `None` then this function simply returns self.
591 pub fn maybe_apply_aspect_ratio(self, aspect_ratio: Option<f32>) -> Size<Option<f32>> {
592 match aspect_ratio {
593 Some(ratio) => match (self.width, self.height) {
594 (Some(width), None) => Size { width: Some(width), height: Some(width / ratio) },
595 (None, Some(height)) => Size { width: Some(height * ratio), height: Some(height) },
596 _ => self,
597 },
598 None => self,
599 }
600 }
601}
602
603impl<T> Size<Option<T>> {
604 /// Performs Option::unwrap_or on each component separately
605 pub fn unwrap_or(self, alt: Size<T>) -> Size<T> {
606 Size { width: self.width.unwrap_or(alt.width), height: self.height.unwrap_or(alt.height) }
607 }
608
609 /// Performs Option::or on each component separately
610 pub fn or(self, alt: Size<Option<T>>) -> Size<Option<T>> {
611 Size { width: self.width.or(alt.width), height: self.height.or(alt.height) }
612 }
613
614 /// Return true if both components are Some, else false.
615 #[inline(always)]
616 pub fn both_axis_defined(&self) -> bool {
617 self.width.is_some() && self.height.is_some()
618 }
619}
620
621impl Size<Dimension> {
622 /// Generates a [`Size<Dimension>`] using length values
623 #[must_use]
624 pub const fn from_lengths(width: f32, height: f32) -> Self {
625 Size { width: Dimension(CompactLength::length(width)), height: Dimension(CompactLength::length(height)) }
626 }
627
628 /// Generates a [`Size<Dimension>`] using percentage values
629 #[must_use]
630 pub const fn from_percent(width: f32, height: f32) -> Self {
631 Size { width: Dimension(CompactLength::percent(width)), height: Dimension(CompactLength::percent(height)) }
632 }
633}
634
635/// A 2-dimensional coordinate.
636///
637/// When used in association with a [`Rect`], represents the top-left corner.
638#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
639#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
640pub struct Point<T> {
641 /// The x-coordinate
642 pub x: T,
643 /// The y-coordinate
644 pub y: T,
645}
646
647impl Point<f32> {
648 /// A [`Point`] with values (0,0), representing the origin
649 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
650}
651
652impl Point<Option<f32>> {
653 /// A [`Point`] with values (None, None)
654 pub const NONE: Self = Self { x: None, y: None };
655}
656
657// Generic Add impl for Point<T> + Point<U> where T + U has an Add impl
658impl<U, T: Add<U>> Add<Point<U>> for Point<T> {
659 type Output = Point<<T as Add<U>>::Output>;
660
661 fn add(self, rhs: Point<U>) -> Self::Output {
662 Point { x: self.x + rhs.x, y: self.y + rhs.y }
663 }
664}
665
666impl<T> Point<T> {
667 /// Applies the function `f` to both the x and y
668 ///
669 /// This is used to transform a `Point<T>` into a `Point<R>`.
670 pub fn map<R, F>(self, f: F) -> Point<R>
671 where
672 F: Fn(T) -> R,
673 {
674 Point { x: f(self.x), y: f(self.y) }
675 }
676
677 /// Gets the extent of the specified layout axis
678 /// Whether this is the width or height depends on the `GridAxis` provided
679 #[cfg(feature = "grid")]
680 pub fn get(self, axis: AbstractAxis) -> T {
681 match axis {
682 AbstractAxis::Inline => self.x,
683 AbstractAxis::Block => self.y,
684 }
685 }
686
687 /// Swap x and y components
688 pub fn transpose(self) -> Point<T> {
689 Point { x: self.y, y: self.x }
690 }
691
692 /// Sets the extent of the specified layout axis
693 /// Whether this is the width or height depends on the `GridAxis` provided
694 #[cfg(feature = "grid")]
695 pub fn set(&mut self, axis: AbstractAxis, value: T) {
696 match axis {
697 AbstractAxis::Inline => self.x = value,
698 AbstractAxis::Block => self.y = value,
699 }
700 }
701
702 /// Gets the component in the main layout axis
703 ///
704 /// Whether this is the x or y depends on the `direction` provided
705 #[cfg(feature = "flexbox")]
706 pub(crate) fn main(self, direction: FlexDirection) -> T {
707 if direction.is_row() {
708 self.x
709 } else {
710 self.y
711 }
712 }
713
714 /// Gets the component in the cross layout axis
715 ///
716 /// Whether this is the x or y depends on the `direction` provided
717 #[cfg(feature = "flexbox")]
718 pub(crate) fn cross(self, direction: FlexDirection) -> T {
719 if direction.is_row() {
720 self.y
721 } else {
722 self.x
723 }
724 }
725}
726
727impl<T> From<Point<T>> for Size<T> {
728 fn from(value: Point<T>) -> Self {
729 Size { width: value.x, height: value.y }
730 }
731}
732
733/// Generic struct which holds a "min" value and a "max" value
734#[derive(Debug, Copy, Clone, PartialEq, Eq)]
735#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
736pub struct MinMax<Min, Max> {
737 /// The value representing the minimum
738 pub min: Min,
739 /// The value representing the maximum
740 pub max: Max,
741}