gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 88Markdown 11TOML 91926 Definitions

⎇ 01babab32d8138f3c3fa05095fb6c65fca0d3967 src/style/mod.rs Rust · 284 lines · 11.0 KB History Who touched what raw

Make CSS Grid feature a default feature (#297) 01babab32 · Nico Burns ·

1//! A representation of [CSS layout properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust, used for flexbox layout
2mod alignment;
3mod dimension;
4mod flex;
5
6pub use self::alignment::{AlignContent, AlignItems, AlignSelf, JustifyContent, JustifyItems, JustifySelf};
7pub use self::dimension::{AvailableSpace, Dimension, LengthPercentage, LengthPercentageAuto};
8pub use self::flex::{FlexDirection, FlexWrap};
9
10#[cfg(feature = "grid")]
11mod grid;
12#[cfg(feature = "grid")]
13pub use self::grid::{
14    GridAutoFlow, GridPlacement, GridTrackRepetition, MaxTrackSizingFunction, MinTrackSizingFunction,
15    NonRepeatedTrackSizingFunction, TrackSizingFunction,
16};
17use crate::geometry::{Rect, Size};
18
19#[cfg(feature = "grid")]
20use crate::geometry::Line;
21#[cfg(feature = "grid")]
22use crate::sys::GridTrackVec;
23
24/// Sets the layout used for the children of this node
25///
26/// [`Display::Flex`] is the default value.
27#[derive(Copy, Clone, PartialEq, Eq, Debug)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29pub enum Display {
30    /// The children will follow the flexbox layout algorithm
31    Flex,
32    /// The children will follow the CSS Grid layout algorithm
33    #[cfg(feature = "grid")]
34    Grid,
35    /// The children will not be laid out, and will follow absolute positioning
36    None,
37}
38
39impl Default for Display {
40    fn default() -> Self {
41        Self::Flex
42    }
43}
44
45/// The positioning strategy for this item.
46///
47/// This controls both how the origin is determined for the [`Style::position`] field,
48/// and whether or not the item will be controlled by flexbox's layout algorithm.
49///
50/// WARNING: this enum follows the behavior of [CSS's `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position),
51/// which can be unintuitive.
52///
53/// [`PositionType::Relative`] is the default value, in contrast to the default behavior in CSS.
54#[derive(Copy, Clone, PartialEq, Eq, Debug)]
55#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56pub enum PositionType {
57    /// The offset is computed relative to the final position given by the layout algorithm.
58    /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end.
59    Relative,
60    /// The offset is computed relative to this item's closest positioned ancestor, if any.
61    /// Otherwise, it is placed relative to the origin.
62    /// No space is created for the item in the page layout, and its size will not be altered.
63    ///
64    /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object.
65    Absolute,
66}
67
68impl Default for PositionType {
69    fn default() -> Self {
70        Self::Relative
71    }
72}
73
74/// The flexbox layout information for a single [`Node`](crate::node::Node).
75///
76/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
77/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
78///
79/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
80/// information about the behavior on the web should transfer directly.
81///
82/// Detailed information about the exact behavior of each of these fields
83/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
84/// The distinction between margin, padding and border is explained well in
85/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
86///
87/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
88#[derive(Clone, PartialEq, Debug)]
89#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
90#[cfg_attr(feature = "serde", serde(default))]
91pub struct Style {
92    /// What layout strategy should be used?
93    pub display: Display,
94
95    // Position properties
96    /// What should the `position` value of this struct use as a base offset?
97    pub position_type: PositionType,
98    /// How should the position of this element be tweaked relative to the layout defined?
99    pub position: Rect<LengthPercentageAuto>,
100
101    // Size properies
102    /// Sets the initial size of the item
103    pub size: Size<Dimension>,
104    /// Controls the minimum size of the item
105    pub min_size: Size<Dimension>,
106    /// Controls the maximum size of the item
107    pub max_size: Size<Dimension>,
108    /// Sets the preferred aspect ratio for the item
109    ///
110    /// The ratio is calculated as width divided by height.
111    pub aspect_ratio: Option<f32>,
112
113    // Spacing Properties
114    /// How large should the margin be on each side?
115    pub margin: Rect<LengthPercentageAuto>,
116    /// How large should the padding be on each side?
117    pub padding: Rect<LengthPercentage>,
118    /// How large should the border be on each side?
119    pub border: Rect<LengthPercentage>,
120
121    // Alignment properties
122    /// How this node's children aligned in the cross/block axis?
123    pub align_items: Option<AlignItems>,
124    /// How this node should be aligned in the cross/block axis
125    /// Falls back to the parents [`AlignItems`] if not set
126    pub align_self: Option<AlignSelf>,
127    /// How this node's children should be aligned in the inline axis
128    #[cfg(feature = "grid")]
129    pub justify_items: Option<AlignItems>,
130    /// How this node should be aligned in the inline axis
131    /// Falls back to the parents [`JustifyItems`] if not set
132    pub justify_self: Option<AlignSelf>,
133    /// How should content contained within this item be aligned in the cross/block axis
134    pub align_content: Option<AlignContent>,
135    /// How should contained within this item be aligned in the main/inline axis
136    pub justify_content: Option<JustifyContent>,
137    /// How large should the gaps between items in a grid or flex container be?
138    pub gap: Size<LengthPercentage>,
139
140    // Flexbox properies
141    /// Which direction does the main axis flow in?
142    pub flex_direction: FlexDirection,
143    /// Should elements wrap, or stay in a single line?
144    pub flex_wrap: FlexWrap,
145    /// Sets the initial main axis size of the item
146    pub flex_basis: Dimension,
147    /// The relative rate at which this item grows when it is expanding to fill space
148    ///
149    /// 0.0 is the default value, and this value must be positive.
150    pub flex_grow: f32,
151    /// The relative rate at which this item shrinks when it is contracting to fit into space
152    ///
153    /// 1.0 is the default value, and this value must be positive.
154    pub flex_shrink: f32,
155
156    // Grid container properies
157    /// Defines the track sizing functions (widths) of the grid rows
158    #[cfg(feature = "grid")]
159    pub grid_template_rows: GridTrackVec<TrackSizingFunction>,
160    /// Defines the track sizing functions (heights) of the grid columns
161    #[cfg(feature = "grid")]
162    pub grid_template_columns: GridTrackVec<TrackSizingFunction>,
163    /// Defines the size of implicitly created rows
164    #[cfg(feature = "grid")]
165    pub grid_auto_rows: GridTrackVec<NonRepeatedTrackSizingFunction>,
166    /// Defined the size of implicitly created columns
167    #[cfg(feature = "grid")]
168    pub grid_auto_columns: GridTrackVec<NonRepeatedTrackSizingFunction>,
169    /// Controls how items get placed into the grid for auto-placed items
170    #[cfg(feature = "grid")]
171    pub grid_auto_flow: GridAutoFlow,
172
173    // Grid child properties
174    /// Defines which row in the grid the item should start and end at
175    #[cfg(feature = "grid")]
176    pub grid_row: Line<GridPlacement>,
177    /// Defines which column in the grid the item should start and end at
178    #[cfg(feature = "grid")]
179    pub grid_column: Line<GridPlacement>,
180}
181
182impl Style {
183    /// The [`Default`] layout, in a form that can be used in const functions
184    pub const DEFAULT: Style = Style {
185        display: Display::Flex,
186        position_type: PositionType::Relative,
187        flex_direction: FlexDirection::Row,
188        flex_wrap: FlexWrap::NoWrap,
189        align_items: None,
190        align_self: None,
191        #[cfg(feature = "grid")]
192        justify_items: None,
193        justify_self: None,
194        align_content: None,
195        justify_content: None,
196        position: Rect::auto(),
197        margin: Rect::zero(),
198        padding: Rect::zero(),
199        border: Rect::zero(),
200        gap: Size::zero(),
201        flex_grow: 0.0,
202        flex_shrink: 1.0,
203        flex_basis: Dimension::Auto,
204        size: Size::auto(),
205        min_size: Size::auto(),
206        max_size: Size::auto(),
207        aspect_ratio: None,
208        #[cfg(feature = "grid")]
209        grid_template_rows: GridTrackVec::new(),
210        #[cfg(feature = "grid")]
211        grid_template_columns: GridTrackVec::new(),
212        #[cfg(feature = "grid")]
213        grid_auto_rows: GridTrackVec::new(),
214        #[cfg(feature = "grid")]
215        grid_auto_columns: GridTrackVec::new(),
216        #[cfg(feature = "grid")]
217        grid_auto_flow: GridAutoFlow::Row,
218        #[cfg(feature = "grid")]
219        grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
220        #[cfg(feature = "grid")]
221        grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
222    };
223}
224
225impl Default for Style {
226    fn default() -> Self {
227        Style::DEFAULT
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::Style;
234    use crate::geometry::*;
235
236    #[test]
237    fn defaults_match() {
238        #[cfg(feature = "grid")]
239        use super::GridPlacement;
240
241        let old_defaults = Style {
242            display: Default::default(),
243            position_type: Default::default(),
244            flex_direction: Default::default(),
245            flex_wrap: Default::default(),
246            align_items: Default::default(),
247            align_self: Default::default(),
248            #[cfg(feature = "grid")]
249            justify_items: Default::default(),
250            justify_self: Default::default(),
251            align_content: Default::default(),
252            justify_content: Default::default(),
253            position: Rect::auto(),
254            margin: Rect::zero(),
255            padding: Rect::zero(),
256            border: Rect::zero(),
257            gap: Size::zero(),
258            flex_grow: 0.0,
259            flex_shrink: 1.0,
260            flex_basis: super::Dimension::Auto,
261            size: Size::auto(),
262            min_size: Size::auto(),
263            max_size: Size::auto(),
264            aspect_ratio: Default::default(),
265            #[cfg(feature = "grid")]
266            grid_template_rows: Default::default(),
267            #[cfg(feature = "grid")]
268            grid_template_columns: Default::default(),
269            #[cfg(feature = "grid")]
270            grid_auto_rows: Default::default(),
271            #[cfg(feature = "grid")]
272            grid_auto_columns: Default::default(),
273            #[cfg(feature = "grid")]
274            grid_auto_flow: Default::default(),
275            #[cfg(feature = "grid")]
276            grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
277            #[cfg(feature = "grid")]
278            grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
279        };
280
281        assert_eq!(Style::DEFAULT, Style::default());
282        assert_eq!(Style::DEFAULT, old_defaults);
283    }
284}