1//! Style types for Flexbox layout
2use super::{AlignContent, AlignItems, AlignSelf, CoreStyle, Dimension, JustifyContent, LengthPercentage, Style};
3use crate::geometry::Size;
4
5/// The set of styles required for a Flexbox container
6pub trait FlexboxContainerStyle: CoreStyle {
7 /// Which direction does the main axis flow in?
8 #[inline(always)]
9 fn flex_direction(&self) -> FlexDirection {
10 Style::DEFAULT.flex_direction
11 }
12 /// Should elements wrap, or stay in a single line?
13 #[inline(always)]
14 fn flex_wrap(&self) -> FlexWrap {
15 Style::DEFAULT.flex_wrap
16 }
17
18 /// How large should the gaps between items in a grid or flex container be?
19 #[inline(always)]
20 fn gap(&self) -> Size<LengthPercentage> {
21 Style::DEFAULT.gap
22 }
23
24 // Alignment properties
25
26 /// How should content contained within this item be aligned in the cross/block axis
27 #[inline(always)]
28 fn align_content(&self) -> Option<AlignContent> {
29 Style::DEFAULT.align_content
30 }
31 /// How this node's children aligned in the cross/block axis?
32 #[inline(always)]
33 fn align_items(&self) -> Option<AlignItems> {
34 Style::DEFAULT.align_items
35 }
36 /// How this node's children should be aligned in the inline axis
37 #[inline(always)]
38 fn justify_content(&self) -> Option<JustifyContent> {
39 Style::DEFAULT.justify_content
40 }
41}
42
43/// The set of styles required for a Flexbox item (child of a Flexbox container)
44pub trait FlexboxItemStyle: CoreStyle {
45 /// Sets the initial main axis size of the item
46 #[inline(always)]
47 fn flex_basis(&self) -> Dimension {
48 Style::DEFAULT.flex_basis
49 }
50 /// The relative rate at which this item grows when it is expanding to fill space
51 #[inline(always)]
52 fn flex_grow(&self) -> f32 {
53 Style::DEFAULT.flex_grow
54 }
55 /// The relative rate at which this item shrinks when it is contracting to fit into space
56 #[inline(always)]
57 fn flex_shrink(&self) -> f32 {
58 Style::DEFAULT.flex_shrink
59 }
60
61 /// How this node should be aligned in the cross/block axis
62 /// Falls back to the parents [`AlignItems`] if not set
63 #[inline(always)]
64 fn align_self(&self) -> Option<AlignSelf> {
65 Style::DEFAULT.align_self
66 }
67}
68
69use crate::geometry::AbsoluteAxis;
70
71/// Controls whether flex items are forced onto one line or can wrap onto multiple lines.
72///
73/// Defaults to [`FlexWrap::NoWrap`]
74///
75/// [Specification](https://www.w3.org/TR/css-flexbox-1/#flex-wrap-property)
76#[derive(Copy, Clone, PartialEq, Eq, Debug)]
77#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
78pub enum FlexWrap {
79 /// Items will not wrap and stay on a single line
80 NoWrap,
81 /// Items will wrap according to this item's [`FlexDirection`]
82 Wrap,
83 /// Items will wrap in the opposite direction to this item's [`FlexDirection`]
84 WrapReverse,
85}
86
87impl Default for FlexWrap {
88 fn default() -> Self {
89 Self::NoWrap
90 }
91}
92
93/// The direction of the flexbox layout main axis.
94///
95/// There are always two perpendicular layout axes: main (or primary) and cross (or secondary).
96/// Adding items will cause them to be positioned adjacent to each other along the main axis.
97/// By varying this value throughout your tree, you can create complex axis-aligned layouts.
98///
99/// Items are always aligned relative to the cross axis, and justified relative to the main axis.
100///
101/// The default behavior is [`FlexDirection::Row`].
102///
103/// [Specification](https://www.w3.org/TR/css-flexbox-1/#flex-direction-property)
104#[derive(Copy, Clone, PartialEq, Eq, Debug)]
105#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
106pub enum FlexDirection {
107 /// Defines +x as the main axis
108 ///
109 /// Items will be added from left to right in a row.
110 Row,
111 /// Defines +y as the main axis
112 ///
113 /// Items will be added from top to bottom in a column.
114 Column,
115 /// Defines -x as the main axis
116 ///
117 /// Items will be added from right to left in a row.
118 RowReverse,
119 /// Defines -y as the main axis
120 ///
121 /// Items will be added from bottom to top in a column.
122 ColumnReverse,
123}
124
125impl Default for FlexDirection {
126 fn default() -> Self {
127 Self::Row
128 }
129}
130
131impl FlexDirection {
132 #[inline]
133 /// Is the direction [`FlexDirection::Row`] or [`FlexDirection::RowReverse`]?
134 pub(crate) fn is_row(self) -> bool {
135 matches!(self, Self::Row | Self::RowReverse)
136 }
137
138 #[inline]
139 /// Is the direction [`FlexDirection::Column`] or [`FlexDirection::ColumnReverse`]?
140 pub(crate) fn is_column(self) -> bool {
141 matches!(self, Self::Column | Self::ColumnReverse)
142 }
143
144 #[inline]
145 /// Is the direction [`FlexDirection::RowReverse`] or [`FlexDirection::ColumnReverse`]?
146 pub(crate) fn is_reverse(self) -> bool {
147 matches!(self, Self::RowReverse | Self::ColumnReverse)
148 }
149
150 #[inline]
151 /// The `AbsoluteAxis` that corresponds to the main axis
152 pub(crate) fn main_axis(self) -> AbsoluteAxis {
153 match self {
154 Self::Row | Self::RowReverse => AbsoluteAxis::Horizontal,
155 Self::Column | Self::ColumnReverse => AbsoluteAxis::Vertical,
156 }
157 }
158
159 #[inline]
160 /// The `AbsoluteAxis` that corresponds to the cross axis
161 pub(crate) fn cross_axis(self) -> AbsoluteAxis {
162 match self {
163 Self::Row | Self::RowReverse => AbsoluteAxis::Vertical,
164 Self::Column | Self::ColumnReverse => AbsoluteAxis::Horizontal,
165 }
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 mod test_flex_direction {
172 use crate::style::*;
173
174 #[test]
175 fn flex_direction_is_row() {
176 assert!(FlexDirection::Row.is_row());
177 assert!(FlexDirection::RowReverse.is_row());
178 assert!(!FlexDirection::Column.is_row());
179 assert!(!FlexDirection::ColumnReverse.is_row());
180 }
181
182 #[test]
183 fn flex_direction_is_column() {
184 assert!(!FlexDirection::Row.is_column());
185 assert!(!FlexDirection::RowReverse.is_column());
186 assert!(FlexDirection::Column.is_column());
187 assert!(FlexDirection::ColumnReverse.is_column());
188 }
189
190 #[test]
191 fn flex_direction_is_reverse() {
192 assert!(!FlexDirection::Row.is_reverse());
193 assert!(FlexDirection::RowReverse.is_reverse());
194 assert!(!FlexDirection::Column.is_reverse());
195 assert!(FlexDirection::ColumnReverse.is_reverse());
196 }
197 }
198}