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