Rename Rect field start->left end->right (#257)
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 {
287 left: Default::default(),
288 right: Default::default(),
289 top: Default::default(),
290 bottom: Default::default(),
291 }
292 }
293}
294
295impl Rect<Dimension> {
296 /// Generates a [`Rect<Dimension>`] using [`Dimension::Points`] values for `start` and `top`
297 #[must_use]
298 pub const fn top_from_points(start: f32, top: f32) -> Rect<Dimension> {
299 Rect { left: Dimension::Points(start), top: Dimension::Points(top), ..Rect::AUTO }
300 }
301
302 /// Generates a [`Rect<Dimension>`] using [`Dimension::Points`] values for `end` and `bottom`
303 #[must_use]
304 pub const fn bot_from_points(end: f32, bottom: f32) -> Rect<Dimension> {
305 Rect { right: Dimension::Points(end), bottom: Dimension::Points(bottom), ..Rect::AUTO }
306 }
307
308 /// Generates a [`Rect<Dimension>`] using [`Dimension::Percent`] values for `start` and `top`
309 #[must_use]
310 pub const fn top_from_percent(start: f32, top: f32) -> Rect<Dimension> {
311 Rect { left: Dimension::Percent(start), top: Dimension::Percent(top), ..Rect::AUTO }
312 }
313
314 /// Generates a [`Rect<Dimension>`] using [`Dimension::Percent`] values for `end` and `bottom`
315 #[must_use]
316 pub const fn bot_from_percent(end: f32, bottom: f32) -> Rect<Dimension> {
317 Rect { right: Dimension::Percent(end), bottom: Dimension::Percent(bottom), ..Rect::AUTO }
318 }
319
320 /// Generates a [`Rect<Dimension>`] using [`Dimension::Undefined`] for all values
321 pub const UNDEFINED: Rect<Dimension> = Self {
322 left: Dimension::Undefined,
323 right: Dimension::Undefined,
324 top: Dimension::Undefined,
325 bottom: Dimension::Undefined,
326 };
327
328 /// Generates a [`Rect<Dimension>`] using [`Dimension::Auto`] for all values
329 pub const AUTO: Rect<Dimension> =
330 Self { left: Dimension::Auto, right: Dimension::Auto, top: Dimension::Auto, bottom: Dimension::Auto };
331
332 /// Create a new Rect with [`Dimension::Points`]
333 #[must_use]
334 pub const fn from_points(start: f32, end: f32, top: f32, bottom: f32) -> Self {
335 Rect {
336 left: Dimension::Points(start),
337 right: Dimension::Points(end),
338 top: Dimension::Points(top),
339 bottom: Dimension::Points(bottom),
340 }
341 }
342
343 /// Create a new Rect with [`Dimension::Percent`]
344 #[must_use]
345 pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self {
346 Rect {
347 left: Dimension::Percent(start),
348 right: Dimension::Percent(end),
349 top: Dimension::Percent(top),
350 bottom: Dimension::Percent(bottom),
351 }
352 }
353}
354
355impl Default for Size<Dimension> {
356 fn default() -> Self {
357 Self { width: Dimension::Auto, height: Dimension::Auto }
358 }
359}
360
361/// The flexbox layout information for a single [`Node`](crate::node::Node).
362///
363/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
364/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
365///
366/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
367/// information about the behavior on the web should transfer directly.
368///
369/// Detailed information about the exact behavior of each of these fields
370/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
371/// The distinction between margin, padding and border is explained well in
372/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
373///
374/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
375#[derive(Copy, Clone, PartialEq, Debug)]
376#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
377#[cfg_attr(feature = "serde", serde(default))]
378pub struct Style {
379 /// What layout strategy should be used?
380 pub display: Display,
381 /// What should the `position` value of this struct use as a base offset?
382 pub position_type: PositionType,
383 /// Which direction does the main axis flow in?
384 pub flex_direction: FlexDirection,
385 /// Should elements wrap, or stay in a single line?
386 pub flex_wrap: FlexWrap,
387 /// How should items be aligned relative to the cross axis?
388 pub align_items: AlignItems,
389 /// Should this item violate the cross axis alignment specified by its parent's [`AlignItems`]?
390 pub align_self: AlignSelf,
391 /// How should content contained within this item be aligned relative to the cross axis?
392 pub align_content: AlignContent,
393 /// How should items be aligned relative to the main axis?
394 pub justify_content: JustifyContent,
395 /// How should the position of this element be tweaked relative to the layout defined?
396 pub position: Rect<Dimension>,
397 /// How large should the margin be on each side?
398 pub margin: Rect<Dimension>,
399 /// How large should the padding be on each side?
400 pub padding: Rect<Dimension>,
401 /// How large should the border be on each side?
402 pub border: Rect<Dimension>,
403 // Gap
404 /// How large should the gaps between items in a grid or flex container be?
405 pub gap: Size<Dimension>,
406 /// The relative rate at which this item grows when it is expanding to fill space
407 ///
408 /// 0.0 is the default value, and this value must not be negative.
409 pub flex_grow: f32,
410 /// The relative rate at which this item shrinks when it is contracting to fit into space
411 ///
412 /// 1.0 is the default value, and this value must not be negative.
413 pub flex_shrink: f32,
414 /// Sets the initial main axis size of the item
415 pub flex_basis: Dimension,
416 /// Sets the initial size of the item
417 // TODO: why does this exist as distinct from flex_basis? How do they interact?
418 pub size: Size<Dimension>,
419 /// Controls the minimum size of the item
420 pub min_size: Size<Dimension>,
421 /// Controls the maximum size of the item
422 pub max_size: Size<Dimension>,
423 /// Sets the preferred aspect ratio for the item
424 ///
425 /// The ratio is calculated as width divided by height.
426 pub aspect_ratio: Option<f32>,
427}
428
429impl Style {
430 /// The [`Default`] layout, in a form that can be used in const functions
431 pub const DEFAULT: Style = Style {
432 display: Display::Flex,
433 position_type: PositionType::Relative,
434 flex_direction: FlexDirection::Row,
435 flex_wrap: FlexWrap::NoWrap,
436 align_items: AlignItems::Stretch,
437 align_self: AlignSelf::Auto,
438 align_content: AlignContent::Stretch,
439 justify_content: JustifyContent::FlexStart,
440 position: Rect::UNDEFINED,
441 margin: Rect::UNDEFINED,
442 padding: Rect::UNDEFINED,
443 border: Rect::UNDEFINED,
444 gap: Size::UNDEFINED,
445 flex_grow: 0.0,
446 flex_shrink: 1.0,
447 flex_basis: Dimension::Auto,
448 size: Size::AUTO,
449 min_size: Size::AUTO,
450 max_size: Size::AUTO,
451 aspect_ratio: None,
452 };
453}
454
455impl Default for Style {
456 fn default() -> Self {
457 Style::DEFAULT
458 }
459}
460
461impl Style {
462 /// If the `direction` is row-oriented, the min width. Otherwise the min height
463 pub(crate) fn min_main_size(&self, direction: FlexDirection) -> Dimension {
464 if direction.is_row() {
465 self.min_size.width
466 } else {
467 self.min_size.height
468 }
469 }
470
471 /// If the `direction` is row-oriented, the max width. Otherwise the max height
472 pub(crate) fn max_main_size(&self, direction: FlexDirection) -> Dimension {
473 if direction.is_row() {
474 self.max_size.width
475 } else {
476 self.max_size.height
477 }
478 }
479
480 /// If the `direction` is row-oriented, the margin start. Otherwise the margin top
481 pub(crate) fn main_margin_start(&self, direction: FlexDirection) -> Dimension {
482 if direction.is_row() {
483 self.margin.left
484 } else {
485 self.margin.top
486 }
487 }
488
489 /// If the `direction` is row-oriented, the margin end. Otherwise the margin bottom
490 pub(crate) fn main_margin_end(&self, direction: FlexDirection) -> Dimension {
491 if direction.is_row() {
492 self.margin.right
493 } else {
494 self.margin.bottom
495 }
496 }
497
498 /// If the `direction` is row-oriented, the height. Otherwise the width
499 pub(crate) fn cross_size(&self, direction: FlexDirection) -> Dimension {
500 if direction.is_row() {
501 self.size.height
502 } else {
503 self.size.width
504 }
505 }
506
507 /// If the `direction` is row-oriented, the min height. Otherwise the min width
508 pub(crate) fn min_cross_size(&self, direction: FlexDirection) -> Dimension {
509 if direction.is_row() {
510 self.min_size.height
511 } else {
512 self.min_size.width
513 }
514 }
515
516 /// If the `direction` is row-oriented, the max height. Otherwise the max width
517 pub(crate) fn max_cross_size(&self, direction: FlexDirection) -> Dimension {
518 if direction.is_row() {
519 self.max_size.height
520 } else {
521 self.max_size.width
522 }
523 }
524
525 /// If the `direction` is row-oriented, the margin top. Otherwise the margin start
526 pub(crate) fn cross_margin_start(&self, direction: FlexDirection) -> Dimension {
527 if direction.is_row() {
528 self.margin.top
529 } else {
530 self.margin.left
531 }
532 }
533
534 /// If the `direction` is row-oriented, the margin bottom. Otherwise the margin end
535 pub(crate) fn cross_margin_end(&self, direction: FlexDirection) -> Dimension {
536 if direction.is_row() {
537 self.margin.bottom
538 } else {
539 self.margin.right
540 }
541 }
542
543 /// Computes the final alignment of this item based on the parent's [`AlignItems`] and this item's [`AlignSelf`]
544 pub(crate) fn align_self(&self, parent: &Style) -> AlignSelf {
545 // FUTURE WARNING: This function should never return AlignSelf::Auto
546 // See #169 https://github.com/DioxusLabs/taffy/pull/169#issuecomment-1157698840
547
548 if self.align_self == AlignSelf::Auto {
549 match parent.align_items {
550 AlignItems::FlexStart => AlignSelf::FlexStart,
551 AlignItems::FlexEnd => AlignSelf::FlexEnd,
552 AlignItems::Center => AlignSelf::Center,
553 AlignItems::Baseline => AlignSelf::Baseline,
554 AlignItems::Stretch => AlignSelf::Stretch,
555 }
556 } else {
557 self.align_self
558 }
559 }
560}
561
562#[allow(clippy::bool_assert_comparison)]
563#[cfg(test)]
564mod tests {
565 use super::Style;
566 use crate::geometry::Size;
567
568 #[test]
569 fn defaults_match() {
570 let old_defaults = Style {
571 display: Default::default(),
572 position_type: Default::default(),
573 flex_direction: Default::default(),
574 flex_wrap: Default::default(),
575 align_items: Default::default(),
576 align_self: Default::default(),
577 align_content: Default::default(),
578 justify_content: Default::default(),
579 position: Default::default(),
580 margin: Default::default(),
581 padding: Default::default(),
582 border: Default::default(),
583 gap: Size::UNDEFINED,
584 flex_grow: 0.0,
585 flex_shrink: 1.0,
586 flex_basis: super::Dimension::Auto,
587 size: Default::default(),
588 min_size: Default::default(),
589 max_size: Default::default(),
590 aspect_ratio: Default::default(),
591 };
592
593 assert_eq!(Style::DEFAULT, Style::default());
594 assert_eq!(Style::DEFAULT, old_defaults);
595 }
596
597 mod test_flex_direction {
598 use crate::style::*;
599
600 #[test]
601 fn flex_direction_is_row() {
602 assert_eq!(FlexDirection::Row.is_row(), true);
603 assert_eq!(FlexDirection::RowReverse.is_row(), true);
604 assert_eq!(FlexDirection::Column.is_row(), false);
605 assert_eq!(FlexDirection::ColumnReverse.is_row(), false);
606 }
607
608 #[test]
609 fn flex_direction_is_column() {
610 assert_eq!(FlexDirection::Row.is_column(), false);
611 assert_eq!(FlexDirection::RowReverse.is_column(), false);
612 assert_eq!(FlexDirection::Column.is_column(), true);
613 assert_eq!(FlexDirection::ColumnReverse.is_column(), true);
614 }
615
616 #[test]
617 fn flex_direction_is_reverse() {
618 assert_eq!(FlexDirection::Row.is_reverse(), false);
619 assert_eq!(FlexDirection::RowReverse.is_reverse(), true);
620 assert_eq!(FlexDirection::Column.is_reverse(), false);
621 assert_eq!(FlexDirection::ColumnReverse.is_reverse(), true);
622 }
623 }
624
625 mod test_flexbox_layout {
626 use crate::style::*;
627
628 fn layout_from_align_items(align: AlignItems) -> Style {
629 Style { align_items: align, ..Default::default() }
630 }
631
632 fn layout_from_align_self(align: AlignSelf) -> Style {
633 Style { align_self: align, ..Default::default() }
634 }
635
636 #[test]
637 fn flexbox_layout_min_main_size() {
638 let layout = Style { min_size: Size::from_points(1.0, 2.0), ..Default::default() };
639 assert_eq!(layout.min_main_size(FlexDirection::Row), Dimension::Points(1.0));
640 assert_eq!(layout.min_main_size(FlexDirection::Column), Dimension::Points(2.0));
641 }
642
643 #[test]
644 fn flexbox_layout_max_main_size() {
645 let layout = Style { max_size: Size::from_points(1.0, 2.0), ..Default::default() };
646 assert_eq!(layout.max_main_size(FlexDirection::Row), Dimension::Points(1.0));
647 assert_eq!(layout.max_main_size(FlexDirection::Column), Dimension::Points(2.0));
648 }
649
650 #[test]
651 fn flexbox_layout_main_margin_start() {
652 let layout = Style { margin: Rect::top_from_points(2.0, 1.0), ..Default::default() };
653 assert_eq!(layout.main_margin_start(FlexDirection::Row), Dimension::Points(2.0));
654 assert_eq!(layout.main_margin_start(FlexDirection::Column), Dimension::Points(1.0));
655 }
656
657 #[test]
658 fn flexbox_layout_main_margin_end() {
659 let layout = Style { margin: Rect::bot_from_points(2.0, 1.0), ..Default::default() };
660 assert_eq!(layout.main_margin_end(FlexDirection::Row), Dimension::Points(2.0));
661 assert_eq!(layout.main_margin_end(FlexDirection::Column), Dimension::Points(1.0));
662 }
663
664 #[test]
665 fn flexbox_layout_cross_size() {
666 let layout = Style { size: Size::from_points(1.0, 2.0), ..Default::default() };
667 assert_eq!(layout.cross_size(FlexDirection::Row), Dimension::Points(2.0));
668 assert_eq!(layout.cross_size(FlexDirection::Column), Dimension::Points(1.0));
669 }
670
671 #[test]
672 fn flexbox_layout_min_cross_size() {
673 let layout = Style { min_size: Size::from_points(1.0, 2.0), ..Default::default() };
674 assert_eq!(layout.min_cross_size(FlexDirection::Row), Dimension::Points(2.0));
675 assert_eq!(layout.min_cross_size(FlexDirection::Column), Dimension::Points(1.0));
676 }
677
678 #[test]
679 fn flexbox_layout_max_cross_size() {
680 let layout = Style { max_size: Size::from_points(1.0, 2.0), ..Default::default() };
681 assert_eq!(layout.max_cross_size(FlexDirection::Row), Dimension::Points(2.0));
682 assert_eq!(layout.max_cross_size(FlexDirection::Column), Dimension::Points(1.0));
683 }
684
685 #[test]
686 fn flexbox_layout_cross_margin_start() {
687 let layout = Style { margin: Rect::top_from_points(2.0, 1.0), ..Default::default() };
688 assert_eq!(layout.cross_margin_start(FlexDirection::Row), Dimension::Points(1.0));
689 assert_eq!(layout.cross_margin_start(FlexDirection::Column), Dimension::Points(2.0));
690 }
691
692 #[test]
693 fn flexbox_layout_cross_margin_end() {
694 let layout = Style { margin: Rect::bot_from_points(2.0, 1.0), ..Default::default() };
695 assert_eq!(layout.cross_margin_end(FlexDirection::Row), Dimension::Points(1.0));
696 assert_eq!(layout.cross_margin_end(FlexDirection::Column), Dimension::Points(2.0));
697 }
698
699 #[test]
700 fn flexbox_layout_align_self_auto() {
701 let parent = layout_from_align_items(AlignItems::FlexStart);
702 let layout = layout_from_align_self(AlignSelf::Auto);
703 assert_eq!(layout.align_self(&parent), AlignSelf::FlexStart);
704
705 let parent = layout_from_align_items(AlignItems::FlexEnd);
706 let layout = layout_from_align_self(AlignSelf::Auto);
707 assert_eq!(layout.align_self(&parent), AlignSelf::FlexEnd);
708
709 let parent = layout_from_align_items(AlignItems::Center);
710 let layout = layout_from_align_self(AlignSelf::Auto);
711 assert_eq!(layout.align_self(&parent), AlignSelf::Center);
712
713 let parent = layout_from_align_items(AlignItems::Baseline);
714 let layout = layout_from_align_self(AlignSelf::Auto);
715 assert_eq!(layout.align_self(&parent), AlignSelf::Baseline);
716
717 let parent = layout_from_align_items(AlignItems::Stretch);
718 let layout = layout_from_align_self(AlignSelf::Auto);
719 assert_eq!(layout.align_self(&parent), AlignSelf::Stretch);
720 }
721
722 #[test]
723 fn align_self() {
724 let parent = layout_from_align_items(AlignItems::FlexEnd);
725 let layout = layout_from_align_self(AlignSelf::FlexStart);
726 assert_eq!(layout.align_self(&parent), AlignSelf::FlexStart);
727
728 let parent = layout_from_align_items(AlignItems::FlexStart);
729 let layout = layout_from_align_self(AlignSelf::FlexEnd);
730 assert_eq!(layout.align_self(&parent), AlignSelf::FlexEnd);
731
732 let parent = layout_from_align_items(AlignItems::FlexStart);
733 let layout = layout_from_align_self(AlignSelf::Center);
734 assert_eq!(layout.align_self(&parent), AlignSelf::Center);
735
736 let parent = layout_from_align_items(AlignItems::FlexStart);
737 let layout = layout_from_align_self(AlignSelf::Baseline);
738 assert_eq!(layout.align_self(&parent), AlignSelf::Baseline);
739
740 let parent = layout_from_align_items(AlignItems::FlexStart);
741 let layout = layout_from_align_self(AlignSelf::Stretch);
742 assert_eq!(layout.align_self(&parent), AlignSelf::Stretch);
743 }
744 }
745}