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