gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5364Rust 86Markdown 12TOML 91841 Sutichaykuna

⎇ 9e53f03adea2b770d68954e404d2fa407dfc7d40 src/style.rs Rust · 740 siq'ikuna · 27.8 KB Ñawpa willay Pi imata llamkarqan ch'uya

Implement "gap" property for flexbox algorithm (#248) 9e53f03ad · Nico Burns ·

1//! A representation of [CSS layout properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust, used for flexbox layout
2
3use crate::geometry::{Rect, Size};
4
5/// How [`Nodes`](crate::node::Node) are aligned relative to the cross axis
6///
7/// The default behavior is [`AlignItems::Stretch`].
8///
9/// [Specification](https://www.w3.org/TR/css-flexbox-1/#align-items-property)
10#[derive(Copy, Clone, PartialEq, Eq, Debug)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub enum AlignItems {
13    /// Items are packed toward the start of the cross axis
14    FlexStart,
15    /// Items are packed toward the end of the cross axis
16    FlexEnd,
17    /// Items are packed along the center of the cross axis
18    Center,
19    /// Items are aligned such as their baselines align
20    Baseline,
21    /// Stretch to fill the container
22    Stretch,
23}
24
25impl Default for AlignItems {
26    fn default() -> Self {
27        Self::Stretch
28    }
29}
30
31/// Overrides the inherited [`AlignItems`] behavior for this node.
32///
33/// The behavior of any child nodes will be controlled by this node's [`AlignItems`] value.
34///
35/// The default behavior is [`AlignSelf::Auto`].
36///
37/// [Specification](https://www.w3.org/TR/css-flexbox-1/#align-items-property)
38#[derive(Copy, Clone, PartialEq, Eq, Debug)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40pub enum AlignSelf {
41    /// Inherits the [`AlignItems`] behavior of the parent
42    Auto,
43    /// Items are packed toward the start of the cross axis
44    FlexStart,
45    /// Items are packed toward the end of the cross axis
46    FlexEnd,
47    /// Items are packed along the center of the cross axis
48    Center,
49    /// Items are aligned such as their baselines align
50    Baseline,
51    /// Distribute items evenly, but stretch them to fill the container
52    Stretch,
53}
54
55impl Default for AlignSelf {
56    fn default() -> Self {
57        Self::Auto
58    }
59}
60
61/// Sets the distribution of space between and around content items along the cross-axis
62///
63/// The default value is [`AlignContent::Stretch`].
64///
65/// [Specification](https://www.w3.org/TR/css-flexbox-1/#align-content-property)
66#[derive(Copy, Clone, PartialEq, Eq, Debug)]
67#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
68pub enum AlignContent {
69    /// Items are packed toward the start of the axis
70    FlexStart,
71    /// Items are packed toward the end of the axis
72    FlexEnd,
73    /// Items are centered around the middle of the axis
74    Center,
75    /// Items are stretched to fill the container
76    Stretch,
77    /// The first and last items are aligned flush with the edges of the container (no gap)
78    /// The gap between items is distributed evenly.
79    SpaceBetween,
80    /// The gap between the first and last items is exactly THE SAME as the gap between items.
81    /// The gaps are distributed evenly
82    SpaceEvenly,
83    /// The gap between the first and last items is exactly HALF the gap between items.
84    /// The gaps are distributed evenly in proportion to these ratios.
85    SpaceAround,
86}
87
88impl Default for AlignContent {
89    fn default() -> Self {
90        Self::Stretch
91    }
92}
93
94/// Sets the layout used for the children of this node
95///
96/// [`Display::Flex`] is the default value.
97#[derive(Copy, Clone, PartialEq, Eq, Debug)]
98#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
99pub enum Display {
100    /// The children will follow the flexbox layout algorithm
101    Flex,
102    /// The children will not be laid out, and will follow absolute positioning
103    None,
104}
105
106impl Default for Display {
107    fn default() -> Self {
108        Self::Flex
109    }
110}
111
112/// The direction of the flexbox layout main axis.
113///
114/// There are always two perpendicular layout axes: main (or primary) and cross (or secondary).
115/// Adding items will cause them to be positioned adjacent to each other along the main axis.
116/// By varying this value throughout your tree, you can create complex axis-aligned layouts.
117///
118/// Items are always aligned relative to the cross axis, and justified relative to the main axis.
119///
120/// The default behavior is [`FlexDirection::Row`].
121///
122/// [Specification](https://www.w3.org/TR/css-flexbox-1/#flex-direction-property)
123#[derive(Copy, Clone, PartialEq, Eq, Debug)]
124#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
125pub enum FlexDirection {
126    /// Defines +x as the main axis
127    ///
128    /// Items will be added from left to right in a row.
129    Row,
130    /// Defines +y as the main axis
131    ///
132    /// Items will be added from top to bottom in a column.
133    Column,
134    /// Defines -x as the main axis
135    ///
136    /// Items will be added from right to left in a row.
137    RowReverse,
138    /// Defines -y as the main axis
139    ///
140    /// Items will be added from bottom to top in a column.
141    ColumnReverse,
142}
143
144impl Default for FlexDirection {
145    fn default() -> Self {
146        Self::Row
147    }
148}
149
150impl FlexDirection {
151    #[inline]
152    /// Is the direction [`FlexDirection::Row`] or [`FlexDirection::RowReverse`]?
153    pub(crate) fn is_row(self) -> bool {
154        matches!(self, Self::Row | Self::RowReverse)
155    }
156
157    #[inline]
158    /// Is the direction [`FlexDirection::Column`] or [`FlexDirection::ColumnReverse`]?
159    pub(crate) fn is_column(self) -> bool {
160        matches!(self, Self::Column | Self::ColumnReverse)
161    }
162
163    #[inline]
164    /// Is the direction [`FlexDirection::RowReverse`] or [`FlexDirection::ColumnReverse`]?
165    pub(crate) fn is_reverse(self) -> bool {
166        matches!(self, Self::RowReverse | Self::ColumnReverse)
167    }
168}
169
170/// Sets the distribution of space between and around content items along the main-axis
171///
172/// The default value is [`JustifyContent::FlexStart`].
173///
174/// [Specification](https://www.w3.org/TR/css-flexbox-1/#justify-content-property)
175#[derive(Copy, Clone, PartialEq, Eq, Debug)]
176#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
177pub enum JustifyContent {
178    /// Items are packed toward the start of the main axis
179    FlexStart,
180    /// Items are packed toward the end of the main axis
181    FlexEnd,
182    /// Items are packed along the center of the main axis
183    Center,
184    /// The first and last items are aligned flush with the edges of the container (no gap)
185    /// The gaps between items are distributed evenly.
186    SpaceBetween,
187    /// The gap between the first and last items is exactly THE SAME as the gap between items.
188    /// The gaps are distributed evenly
189    SpaceEvenly,
190    /// The gap between the first and last items is exactly HALF the gap between items.
191    /// The gaps are distributed evenly in proportion to these ratios.
192    SpaceAround,
193}
194
195impl Default for JustifyContent {
196    fn default() -> Self {
197        Self::FlexStart
198    }
199}
200
201/// The positioning strategy for this item.
202///
203/// This controls both how the origin is determined for the [`Style::position`] field,
204/// and whether or not the item will be controlled by flexbox's layout algorithm.
205///
206/// WARNING: this enum follows the behavior of [CSS's `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position),
207/// which can be unintuitive.
208///
209/// [`PositionType::Relative`] is the default value, in contrast to the default behavior in CSS.
210#[derive(Copy, Clone, PartialEq, Eq, Debug)]
211#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
212pub enum PositionType {
213    /// The offset is computed relative to the final position given by the layout algorithm.
214    /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end.
215    Relative,
216    /// The offset is computed relative to this item's closest positioned ancestor, if any.
217    /// Otherwise, it is placed relative to the origin.
218    /// No space is created for the item in the page layout, and its size will not be altered.
219    ///
220    /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object.
221    Absolute,
222}
223
224impl Default for PositionType {
225    fn default() -> Self {
226        Self::Relative
227    }
228}
229
230/// Controls whether flex items are forced onto one line or can wrap onto multiple lines.
231///
232/// Defaults to [`FlexWrap::NoWrap`]
233///
234/// [Specification](https://www.w3.org/TR/css-flexbox-1/#flex-wrap-property)
235#[derive(Copy, Clone, PartialEq, Eq, Debug)]
236#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
237pub enum FlexWrap {
238    /// Items will not wrap and stay on a single line
239    NoWrap,
240    /// Items will wrap according to this item's [`FlexDirection`]
241    Wrap,
242    /// Items will wrap in the opposite direction to this item's [`FlexDirection`]
243    WrapReverse,
244}
245
246impl Default for FlexWrap {
247    fn default() -> Self {
248        Self::NoWrap
249    }
250}
251
252/// A unit of linear measurement
253///
254/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`].
255/// The default value is [`Dimension::Undefined`].
256#[derive(Copy, Clone, PartialEq, Debug)]
257#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
258pub enum Dimension {
259    /// The dimension is not given
260    Undefined,
261    /// The dimension should be automatically computed
262    Auto,
263    /// The dimension is stored in [points](https://en.wikipedia.org/wiki/Point_(typography))
264    ///
265    /// Each point is about 0.353 mm in size.
266    Points(f32),
267    /// The dimension is stored in percentage relative to the parent item.
268    Percent(f32),
269}
270
271impl Default for Dimension {
272    fn default() -> Self {
273        Self::Undefined
274    }
275}
276
277impl Dimension {
278    /// Is this value defined?
279    pub(crate) fn is_defined(self) -> bool {
280        matches!(self, Dimension::Points(_) | Dimension::Percent(_))
281    }
282}
283
284impl Default for Rect<Dimension> {
285    fn default() -> Self {
286        Self { start: Default::default(), end: Default::default(), top: Default::default(), bottom: Default::default() }
287    }
288}
289
290impl Rect<Dimension> {
291    /// Generates a [`Rect<Dimension>`] using [`Dimension::Points`] values for `start` and `top`
292    #[must_use]
293    pub const fn top_from_points(start: f32, top: f32) -> Rect<Dimension> {
294        Rect { start: Dimension::Points(start), top: Dimension::Points(top), ..Rect::AUTO }
295    }
296
297    /// Generates a [`Rect<Dimension>`] using [`Dimension::Points`] values for `end` and `bottom`
298    #[must_use]
299    pub const fn bot_from_points(end: f32, bottom: f32) -> Rect<Dimension> {
300        Rect { end: Dimension::Points(end), bottom: Dimension::Points(bottom), ..Rect::AUTO }
301    }
302
303    /// Generates a [`Rect<Dimension>`] using [`Dimension::Percent`] values for `start` and `top`
304    #[must_use]
305    pub const fn top_from_percent(start: f32, top: f32) -> Rect<Dimension> {
306        Rect { start: Dimension::Percent(start), top: Dimension::Percent(top), ..Rect::AUTO }
307    }
308
309    /// Generates a [`Rect<Dimension>`] using [`Dimension::Percent`] values for `end` and `bottom`
310    #[must_use]
311    pub const fn bot_from_percent(end: f32, bottom: f32) -> Rect<Dimension> {
312        Rect { end: Dimension::Percent(end), bottom: Dimension::Percent(bottom), ..Rect::AUTO }
313    }
314
315    /// Generates a [`Rect<Dimension>`] using [`Dimension::Undefined`] for all values
316    pub const UNDEFINED: Rect<Dimension> = Self {
317        start: Dimension::Undefined,
318        end: Dimension::Undefined,
319        top: Dimension::Undefined,
320        bottom: Dimension::Undefined,
321    };
322
323    /// Generates a [`Rect<Dimension>`] using [`Dimension::Auto`] for all values
324    pub const AUTO: Rect<Dimension> =
325        Self { start: Dimension::Auto, end: Dimension::Auto, top: Dimension::Auto, bottom: Dimension::Auto };
326
327    /// Create a new Rect with [`Dimension::Points`]
328    #[must_use]
329    pub const fn from_points(start: f32, end: f32, top: f32, bottom: f32) -> Self {
330        Rect {
331            start: Dimension::Points(start),
332            end: Dimension::Points(end),
333            top: Dimension::Points(top),
334            bottom: Dimension::Points(bottom),
335        }
336    }
337
338    /// Create a new Rect with [`Dimension::Percent`]
339    #[must_use]
340    pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self {
341        Rect {
342            start: Dimension::Percent(start),
343            end: Dimension::Percent(end),
344            top: Dimension::Percent(top),
345            bottom: Dimension::Percent(bottom),
346        }
347    }
348}
349
350impl Default for Size<Dimension> {
351    fn default() -> Self {
352        Self { width: Dimension::Auto, height: Dimension::Auto }
353    }
354}
355
356/// The flexbox layout information for a single [`Node`](crate::node::Node).
357///
358/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
359/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
360///
361/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
362/// information about the behavior on the web should transfer directly.
363///
364/// Detailed information about the exact behavior of each of these fields
365/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
366/// The distinction between margin, padding and border is explained well in
367/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
368///
369/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
370#[derive(Copy, Clone, PartialEq, Debug)]
371#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
372#[cfg_attr(feature = "serde", serde(default))]
373pub struct FlexboxLayout {
374    /// What layout strategy should be used?
375    pub display: Display,
376    /// What should the `position` value of this struct use as a base offset?
377    pub position_type: PositionType,
378    /// Which direction does the main axis flow in?
379    pub flex_direction: FlexDirection,
380    /// Should elements wrap, or stay in a single line?
381    pub flex_wrap: FlexWrap,
382    /// How should items be aligned relative to the cross axis?
383    pub align_items: AlignItems,
384    /// Should this item violate the cross axis alignment specified by its parent's [`AlignItems`]?
385    pub align_self: AlignSelf,
386    /// How should content contained within this item be aligned relative to the cross axis?
387    pub align_content: AlignContent,
388    /// How should items be aligned relative to the main axis?
389    pub justify_content: JustifyContent,
390    /// How should the position of this element be tweaked relative to the layout defined?
391    pub position: Rect<Dimension>,
392    /// How large should the margin be on each side?
393    pub margin: Rect<Dimension>,
394    /// How large should the padding be on each side?
395    pub padding: Rect<Dimension>,
396    /// How large should the border be on each side?
397    pub border: Rect<Dimension>,
398    // Gap
399    /// How large should the gaps between items in a grid or flex container be?
400    pub gap: Size<Dimension>,
401    /// The relative rate at which this item grows when it is expanding to fill space
402    ///
403    /// 0.0 is the default value, and this value must not be negative.
404    pub flex_grow: f32,
405    /// The relative rate at which this item shrinks when it is contracting to fit into space
406    ///
407    /// 1.0 is the default value, and this value must not be negative.
408    pub flex_shrink: f32,
409    /// Sets the initial main axis size of the item
410    pub flex_basis: Dimension,
411    /// Sets the initial size of the item
412    // TODO: why does this exist as distinct from flex_basis? How do they interact?
413    pub size: Size<Dimension>,
414    /// Controls the minimum size of the item
415    pub min_size: Size<Dimension>,
416    /// Controls the maximum size of the item
417    pub max_size: Size<Dimension>,
418    /// Sets the preferred aspect ratio for the item
419    ///
420    /// The ratio is calculated as width divided by height.
421    pub aspect_ratio: Option<f32>,
422}
423
424impl FlexboxLayout {
425    /// The [`Default`] layout, in a form that can be used in const functions
426    pub const DEFAULT: FlexboxLayout = FlexboxLayout {
427        display: Display::Flex,
428        position_type: PositionType::Relative,
429        flex_direction: FlexDirection::Row,
430        flex_wrap: FlexWrap::NoWrap,
431        align_items: AlignItems::Stretch,
432        align_self: AlignSelf::Auto,
433        align_content: AlignContent::Stretch,
434        justify_content: JustifyContent::FlexStart,
435        position: Rect::UNDEFINED,
436        margin: Rect::UNDEFINED,
437        padding: Rect::UNDEFINED,
438        border: Rect::UNDEFINED,
439        gap: Size::UNDEFINED,
440        flex_grow: 0.0,
441        flex_shrink: 1.0,
442        flex_basis: Dimension::Auto,
443        size: Size::AUTO,
444        min_size: Size::AUTO,
445        max_size: Size::AUTO,
446        aspect_ratio: None,
447    };
448}
449
450impl Default for FlexboxLayout {
451    fn default() -> Self {
452        FlexboxLayout::DEFAULT
453    }
454}
455
456impl FlexboxLayout {
457    /// If the `direction` is row-oriented, the min width. Otherwise the min height
458    pub(crate) fn min_main_size(&self, direction: FlexDirection) -> Dimension {
459        if direction.is_row() {
460            self.min_size.width
461        } else {
462            self.min_size.height
463        }
464    }
465
466    /// If the `direction` is row-oriented, the max width. Otherwise the max height
467    pub(crate) fn max_main_size(&self, direction: FlexDirection) -> Dimension {
468        if direction.is_row() {
469            self.max_size.width
470        } else {
471            self.max_size.height
472        }
473    }
474
475    /// If the `direction` is row-oriented, the margin start. Otherwise the margin top
476    pub(crate) fn main_margin_start(&self, direction: FlexDirection) -> Dimension {
477        if direction.is_row() {
478            self.margin.start
479        } else {
480            self.margin.top
481        }
482    }
483
484    /// If the `direction` is row-oriented, the margin end. Otherwise the margin bottom
485    pub(crate) fn main_margin_end(&self, direction: FlexDirection) -> Dimension {
486        if direction.is_row() {
487            self.margin.end
488        } else {
489            self.margin.bottom
490        }
491    }
492
493    /// If the `direction` is row-oriented, the height. Otherwise the width
494    pub(crate) fn cross_size(&self, direction: FlexDirection) -> Dimension {
495        if direction.is_row() {
496            self.size.height
497        } else {
498            self.size.width
499        }
500    }
501
502    /// If the `direction` is row-oriented, the min height. Otherwise the min width
503    pub(crate) fn min_cross_size(&self, direction: FlexDirection) -> Dimension {
504        if direction.is_row() {
505            self.min_size.height
506        } else {
507            self.min_size.width
508        }
509    }
510
511    /// If the `direction` is row-oriented, the max height. Otherwise the max width
512    pub(crate) fn max_cross_size(&self, direction: FlexDirection) -> Dimension {
513        if direction.is_row() {
514            self.max_size.height
515        } else {
516            self.max_size.width
517        }
518    }
519
520    /// If the `direction` is row-oriented, the margin top. Otherwise the margin start
521    pub(crate) fn cross_margin_start(&self, direction: FlexDirection) -> Dimension {
522        if direction.is_row() {
523            self.margin.top
524        } else {
525            self.margin.start
526        }
527    }
528
529    /// If the `direction` is row-oriented, the margin bottom. Otherwise the margin end
530    pub(crate) fn cross_margin_end(&self, direction: FlexDirection) -> Dimension {
531        if direction.is_row() {
532            self.margin.bottom
533        } else {
534            self.margin.end
535        }
536    }
537
538    /// Computes the final alignment of this item based on the parent's [`AlignItems`] and this item's [`AlignSelf`]
539    pub(crate) fn align_self(&self, parent: &FlexboxLayout) -> AlignSelf {
540        // FUTURE WARNING: This function should never return AlignSelf::Auto
541        // See #169 https://github.com/DioxusLabs/taffy/pull/169#issuecomment-1157698840
542
543        if self.align_self == AlignSelf::Auto {
544            match parent.align_items {
545                AlignItems::FlexStart => AlignSelf::FlexStart,
546                AlignItems::FlexEnd => AlignSelf::FlexEnd,
547                AlignItems::Center => AlignSelf::Center,
548                AlignItems::Baseline => AlignSelf::Baseline,
549                AlignItems::Stretch => AlignSelf::Stretch,
550            }
551        } else {
552            self.align_self
553        }
554    }
555}
556
557#[allow(clippy::bool_assert_comparison)]
558#[cfg(test)]
559mod tests {
560    use super::FlexboxLayout;
561    use crate::geometry::Size;
562
563    #[test]
564    fn defaults_match() {
565        let old_defaults = FlexboxLayout {
566            display: Default::default(),
567            position_type: Default::default(),
568            flex_direction: Default::default(),
569            flex_wrap: Default::default(),
570            align_items: Default::default(),
571            align_self: Default::default(),
572            align_content: Default::default(),
573            justify_content: Default::default(),
574            position: Default::default(),
575            margin: Default::default(),
576            padding: Default::default(),
577            border: Default::default(),
578            gap: Size::UNDEFINED,
579            flex_grow: 0.0,
580            flex_shrink: 1.0,
581            flex_basis: super::Dimension::Auto,
582            size: Default::default(),
583            min_size: Default::default(),
584            max_size: Default::default(),
585            aspect_ratio: Default::default(),
586        };
587
588        assert_eq!(FlexboxLayout::DEFAULT, FlexboxLayout::default());
589        assert_eq!(FlexboxLayout::DEFAULT, old_defaults);
590    }
591
592    mod test_flex_direction {
593        use crate::style::*;
594
595        #[test]
596        fn flex_direction_is_row() {
597            assert_eq!(FlexDirection::Row.is_row(), true);
598            assert_eq!(FlexDirection::RowReverse.is_row(), true);
599            assert_eq!(FlexDirection::Column.is_row(), false);
600            assert_eq!(FlexDirection::ColumnReverse.is_row(), false);
601        }
602
603        #[test]
604        fn flex_direction_is_column() {
605            assert_eq!(FlexDirection::Row.is_column(), false);
606            assert_eq!(FlexDirection::RowReverse.is_column(), false);
607            assert_eq!(FlexDirection::Column.is_column(), true);
608            assert_eq!(FlexDirection::ColumnReverse.is_column(), true);
609        }
610
611        #[test]
612        fn flex_direction_is_reverse() {
613            assert_eq!(FlexDirection::Row.is_reverse(), false);
614            assert_eq!(FlexDirection::RowReverse.is_reverse(), true);
615            assert_eq!(FlexDirection::Column.is_reverse(), false);
616            assert_eq!(FlexDirection::ColumnReverse.is_reverse(), true);
617        }
618    }
619
620    mod test_flexbox_layout {
621        use crate::style::*;
622
623        fn layout_from_align_items(align: AlignItems) -> FlexboxLayout {
624            FlexboxLayout { align_items: align, ..Default::default() }
625        }
626
627        fn layout_from_align_self(align: AlignSelf) -> FlexboxLayout {
628            FlexboxLayout { align_self: align, ..Default::default() }
629        }
630
631        #[test]
632        fn flexbox_layout_min_main_size() {
633            let layout = FlexboxLayout { min_size: Size::from_points(1.0, 2.0), ..Default::default() };
634            assert_eq!(layout.min_main_size(FlexDirection::Row), Dimension::Points(1.0));
635            assert_eq!(layout.min_main_size(FlexDirection::Column), Dimension::Points(2.0));
636        }
637
638        #[test]
639        fn flexbox_layout_max_main_size() {
640            let layout = FlexboxLayout { max_size: Size::from_points(1.0, 2.0), ..Default::default() };
641            assert_eq!(layout.max_main_size(FlexDirection::Row), Dimension::Points(1.0));
642            assert_eq!(layout.max_main_size(FlexDirection::Column), Dimension::Points(2.0));
643        }
644
645        #[test]
646        fn flexbox_layout_main_margin_start() {
647            let layout = FlexboxLayout { margin: Rect::top_from_points(2.0, 1.0), ..Default::default() };
648            assert_eq!(layout.main_margin_start(FlexDirection::Row), Dimension::Points(2.0));
649            assert_eq!(layout.main_margin_start(FlexDirection::Column), Dimension::Points(1.0));
650        }
651
652        #[test]
653        fn flexbox_layout_main_margin_end() {
654            let layout = FlexboxLayout { margin: Rect::bot_from_points(2.0, 1.0), ..Default::default() };
655            assert_eq!(layout.main_margin_end(FlexDirection::Row), Dimension::Points(2.0));
656            assert_eq!(layout.main_margin_end(FlexDirection::Column), Dimension::Points(1.0));
657        }
658
659        #[test]
660        fn flexbox_layout_cross_size() {
661            let layout = FlexboxLayout { size: Size::from_points(1.0, 2.0), ..Default::default() };
662            assert_eq!(layout.cross_size(FlexDirection::Row), Dimension::Points(2.0));
663            assert_eq!(layout.cross_size(FlexDirection::Column), Dimension::Points(1.0));
664        }
665
666        #[test]
667        fn flexbox_layout_min_cross_size() {
668            let layout = FlexboxLayout { min_size: Size::from_points(1.0, 2.0), ..Default::default() };
669            assert_eq!(layout.min_cross_size(FlexDirection::Row), Dimension::Points(2.0));
670            assert_eq!(layout.min_cross_size(FlexDirection::Column), Dimension::Points(1.0));
671        }
672
673        #[test]
674        fn flexbox_layout_max_cross_size() {
675            let layout = FlexboxLayout { max_size: Size::from_points(1.0, 2.0), ..Default::default() };
676            assert_eq!(layout.max_cross_size(FlexDirection::Row), Dimension::Points(2.0));
677            assert_eq!(layout.max_cross_size(FlexDirection::Column), Dimension::Points(1.0));
678        }
679
680        #[test]
681        fn flexbox_layout_cross_margin_start() {
682            let layout = FlexboxLayout { margin: Rect::top_from_points(2.0, 1.0), ..Default::default() };
683            assert_eq!(layout.cross_margin_start(FlexDirection::Row), Dimension::Points(1.0));
684            assert_eq!(layout.cross_margin_start(FlexDirection::Column), Dimension::Points(2.0));
685        }
686
687        #[test]
688        fn flexbox_layout_cross_margin_end() {
689            let layout = FlexboxLayout { margin: Rect::bot_from_points(2.0, 1.0), ..Default::default() };
690            assert_eq!(layout.cross_margin_end(FlexDirection::Row), Dimension::Points(1.0));
691            assert_eq!(layout.cross_margin_end(FlexDirection::Column), Dimension::Points(2.0));
692        }
693
694        #[test]
695        fn flexbox_layout_align_self_auto() {
696            let parent = layout_from_align_items(AlignItems::FlexStart);
697            let layout = layout_from_align_self(AlignSelf::Auto);
698            assert_eq!(layout.align_self(&parent), AlignSelf::FlexStart);
699
700            let parent = layout_from_align_items(AlignItems::FlexEnd);
701            let layout = layout_from_align_self(AlignSelf::Auto);
702            assert_eq!(layout.align_self(&parent), AlignSelf::FlexEnd);
703
704            let parent = layout_from_align_items(AlignItems::Center);
705            let layout = layout_from_align_self(AlignSelf::Auto);
706            assert_eq!(layout.align_self(&parent), AlignSelf::Center);
707
708            let parent = layout_from_align_items(AlignItems::Baseline);
709            let layout = layout_from_align_self(AlignSelf::Auto);
710            assert_eq!(layout.align_self(&parent), AlignSelf::Baseline);
711
712            let parent = layout_from_align_items(AlignItems::Stretch);
713            let layout = layout_from_align_self(AlignSelf::Auto);
714            assert_eq!(layout.align_self(&parent), AlignSelf::Stretch);
715        }
716
717        #[test]
718        fn align_self() {
719            let parent = layout_from_align_items(AlignItems::FlexEnd);
720            let layout = layout_from_align_self(AlignSelf::FlexStart);
721            assert_eq!(layout.align_self(&parent), AlignSelf::FlexStart);
722
723            let parent = layout_from_align_items(AlignItems::FlexStart);
724            let layout = layout_from_align_self(AlignSelf::FlexEnd);
725            assert_eq!(layout.align_self(&parent), AlignSelf::FlexEnd);
726
727            let parent = layout_from_align_items(AlignItems::FlexStart);
728            let layout = layout_from_align_self(AlignSelf::Center);
729            assert_eq!(layout.align_self(&parent), AlignSelf::Center);
730
731            let parent = layout_from_align_items(AlignItems::FlexStart);
732            let layout = layout_from_align_self(AlignSelf::Baseline);
733            assert_eq!(layout.align_self(&parent), AlignSelf::Baseline);
734
735            let parent = layout_from_align_items(AlignItems::FlexStart);
736            let layout = layout_from_align_self(AlignSelf::Stretch);
737            assert_eq!(layout.align_self(&parent), AlignSelf::Stretch);
738        }
739    }
740}