tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1077HTML 1008Markdown 12TOML 83209 Definitions

⎇ 859cc921b3adb8e3b184e6fc0cf0c40b6c5a625b src/style/mod.rs Rust · 352 lines · 13.6 KB History Who touched what raw

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