• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Style types for Flexbox layout
2 use super::{AlignContent, AlignItems, AlignSelf, CoreStyle, Dimension, JustifyContent, LengthPercentage, Style};
3 use crate::geometry::Size;
4 
5 /// The set of styles required for a Flexbox container
6 pub trait FlexboxContainerStyle: CoreStyle {
7     /// Which direction does the main axis flow in?
8     #[inline(always)]
flex_direction(&self) -> FlexDirection9     fn flex_direction(&self) -> FlexDirection {
10         Style::DEFAULT.flex_direction
11     }
12     /// Should elements wrap, or stay in a single line?
13     #[inline(always)]
flex_wrap(&self) -> FlexWrap14     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)]
gap(&self) -> Size<LengthPercentage>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)]
align_content(&self) -> Option<AlignContent>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)]
align_items(&self) -> Option<AlignItems>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)]
justify_content(&self) -> Option<JustifyContent>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)
44 pub trait FlexboxItemStyle: CoreStyle {
45     /// Sets the initial main axis size of the item
46     #[inline(always)]
flex_basis(&self) -> Dimension47     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)]
flex_grow(&self) -> f3252     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)]
flex_shrink(&self) -> f3257     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)]
align_self(&self) -> Option<AlignSelf>64     fn align_self(&self) -> Option<AlignSelf> {
65         Style::DEFAULT.align_self
66     }
67 }
68 
69 use 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))]
78 pub 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 
87 impl Default for FlexWrap {
default() -> Self88     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))]
106 pub 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 
125 impl Default for FlexDirection {
default() -> Self126     fn default() -> Self {
127         Self::Row
128     }
129 }
130 
131 impl FlexDirection {
132     #[inline]
133     /// Is the direction [`FlexDirection::Row`] or [`FlexDirection::RowReverse`]?
is_row(self) -> bool134     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`]?
is_column(self) -> bool140     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`]?
is_reverse(self) -> bool146     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
main_axis(self) -> AbsoluteAxis152     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
cross_axis(self) -> AbsoluteAxis161     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)]
170 mod tests {
171     mod test_flex_direction {
172         use crate::style::*;
173 
174         #[test]
flex_direction_is_row()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]
flex_direction_is_column()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]
flex_direction_is_reverse()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 }
199