tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1077HTML 1008Markdown 12TOML 83209 Definitions

⎇ 52ae96646aca7b811a12109ca699fb14bf5b50b4 src/style/mod.rs Rust · 362 lines · 14.2 KB History Who touched what raw

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