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