Setup empty morphorm compute module
1//! A typed representation of [CSS style properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust. Used as input to layout computation.
2mod alignment;
3mod dimension;
4
5#[cfg(feature = "flexbox")]
6mod flex;
7
8pub use self::alignment::{AlignContent, AlignItems, AlignSelf, JustifyContent, JustifyItems, JustifySelf};
9pub use self::dimension::{AvailableSpace, Dimension, LengthPercentage, LengthPercentageAuto};
10
11#[cfg(feature = "flexbox")]
12pub use self::flex::{FlexDirection, FlexWrap};
13
14#[cfg(feature = "grid")]
15mod grid;
16#[cfg(feature = "grid")]
17pub(crate) use self::grid::{GenericGridPlacement, OriginZeroGridPlacement};
18#[cfg(feature = "grid")]
19pub use self::grid::{
20 GridAutoFlow, GridPlacement, GridTrackRepetition, MaxTrackSizingFunction, MinTrackSizingFunction,
21 NonRepeatedTrackSizingFunction, TrackSizingFunction,
22};
23use crate::geometry::{Point, Rect, Size};
24
25#[cfg(feature = "grid")]
26use crate::geometry::Line;
27#[cfg(feature = "serde")]
28use crate::style_helpers;
29#[cfg(feature = "grid")]
30use crate::util::sys::GridTrackVec;
31
32/// Sets the layout used for the children of this node
33///
34/// The default values depends on on which feature flags are enabled. The order of precedence is: Flex, Grid, Block, None.
35#[derive(Copy, Clone, PartialEq, Eq, Debug)]
36#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
37pub enum Display {
38 /// The children will follow the block layout algorithm
39 #[cfg(feature = "block_layout")]
40 Block,
41 /// The children will follow the flexbox layout algorithm
42 #[cfg(feature = "flexbox")]
43 Flex,
44 /// The children will follow the CSS Grid layout algorithm
45 #[cfg(feature = "grid")]
46 Grid,
47 /// The children will follow the Morphorm layout algorithm
48 #[cfg(feature = "morphorm")]
49 Morphorm,
50 /// The children will not be laid out, and will follow absolute positioning
51 None,
52}
53
54impl Display {
55 /// The default of Display.
56 #[cfg(feature = "flexbox")]
57 pub const DEFAULT: Display = Display::Flex;
58
59 /// The default of Display.
60 #[cfg(all(feature = "grid", not(feature = "flexbox")))]
61 pub const DEFAULT: Display = Display::Grid;
62
63 /// The default of Display.
64 #[cfg(all(feature = "block_layout", not(feature = "flexbox"), not(feature = "grid")))]
65 pub const DEFAULT: Display = Display::Block;
66
67 /// The default of Display.
68 #[cfg(all(not(feature = "flexbox"), not(feature = "grid"), not(feature = "block_layout")))]
69 pub const DEFAULT: Display = Display::None;
70}
71
72impl Default for Display {
73 fn default() -> Self {
74 Self::DEFAULT
75 }
76}
77
78/// The positioning strategy for this item.
79///
80/// This controls both how the origin is determined for the [`Style::position`] field,
81/// and whether or not the item will be controlled by flexbox's layout algorithm.
82///
83/// WARNING: this enum follows the behavior of [CSS's `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position),
84/// which can be unintuitive.
85///
86/// [`Position::Relative`] is the default value, in contrast to the default behavior in CSS.
87#[derive(Copy, Clone, PartialEq, Eq, Debug)]
88#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
89pub enum Position {
90 /// The offset is computed relative to the final position given by the layout algorithm.
91 /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end.
92 Relative,
93 /// The offset is computed relative to this item's closest positioned ancestor, if any.
94 /// Otherwise, it is placed relative to the origin.
95 /// No space is created for the item in the page layout, and its size will not be altered.
96 ///
97 /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object.
98 Absolute,
99}
100
101impl Default for Position {
102 fn default() -> Self {
103 Self::Relative
104 }
105}
106
107/// How children overflowing their container should affect layout
108///
109/// In CSS the primary effect of this property is to control whether contents of a parent container that overflow that container should
110/// be displayed anyway, be clipped, or trigger the container to become a scroll container. However it also has secondary effects on layout,
111/// the main ones being:
112///
113/// - The automatic minimum size Flexbox/CSS Grid items with non-`Visible` overflow is `0` rather than being content based
114/// - `Overflow::Scroll` nodes have space in the layout reserved for a scrollbar (width controlled by the `scrollbar_width` property)
115///
116/// In Taffy, we only implement the layout related secondary effects as we are not concerned with drawing/painting. The amount of space reserved for
117/// a scrollbar is controlled by the `scrollbar_width` property. If this is `0` then `Scroll` behaves identically to `Hidden`.
118///
119/// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow>
120#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
121#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
122pub enum Overflow {
123 /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of it's content.
124 #[default]
125 Visible,
126 /// The automatic minimum size of this node as a flexbox/grid item should be `0`.
127 Hidden,
128 /// The automatic minimum size of this node as a flexbox/grid item should be `0`. Additionally, space should be reserved
129 /// for a scrollbar. The amount of space reserved is controlled by the `scrollbar_width` property.
130 Scroll,
131}
132
133impl Overflow {
134 /// Returns true for overflow modes that contain their contents (`Overflow::Hidden`, `Overflow::Scroll`, `Overflow::Auto`)
135 /// or else false for overflow modes that allow their contains to spill (`Overflow::Visible`).
136 #[inline(always)]
137 pub(crate) fn is_scroll_container(self) -> bool {
138 self != Overflow::Visible
139 }
140
141 /// Returns `Some(0.0)` if the overflow mode would cause the automatic minimum size of a Flexbox or CSS Grid item
142 /// to be `0`. Else returns None.
143 #[inline(always)]
144 pub(crate) fn maybe_into_automatic_min_size(self) -> Option<f32> {
145 match self.is_scroll_container() {
146 true => Some(0.0),
147 false => None,
148 }
149 }
150}
151
152/// The flexbox layout information for a single node.
153///
154/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
155/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
156///
157/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
158/// information about the behavior on the web should transfer directly.
159///
160/// Detailed information about the exact behavior of each of these fields
161/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
162/// The distinction between margin, padding and border is explained well in
163/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
164///
165/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
166#[derive(Clone, PartialEq, Debug)]
167#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
168#[cfg_attr(feature = "serde", serde(default))]
169pub struct Style {
170 /// What layout strategy should be used?
171 pub display: Display,
172
173 // Overflow properties
174 /// How children overflowing their container should affect layout
175 pub overflow: Point<Overflow>,
176 /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
177 pub scrollbar_width: f32,
178
179 // Position properties
180 /// What should the `position` value of this struct use as a base offset?
181 pub position: Position,
182 /// How should the position of this element be tweaked relative to the layout defined?
183 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
184 pub inset: Rect<LengthPercentageAuto>,
185
186 // Size properies
187 /// Sets the initial size of the item
188 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
189 pub size: Size<Dimension>,
190 /// Controls the minimum size of the item
191 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
192 pub min_size: Size<Dimension>,
193 /// Controls the maximum size of the item
194 #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
195 pub max_size: Size<Dimension>,
196 /// Sets the preferred aspect ratio for the item
197 ///
198 /// The ratio is calculated as width divided by height.
199 pub aspect_ratio: Option<f32>,
200
201 // Spacing Properties
202 /// How large should the margin be on each side?
203 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
204 pub margin: Rect<LengthPercentageAuto>,
205 /// How large should the padding be on each side?
206 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
207 pub padding: Rect<LengthPercentage>,
208 /// How large should the border be on each side?
209 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
210 pub border: Rect<LengthPercentage>,
211
212 // Alignment properties
213 /// How this node's children aligned in the cross/block axis?
214 #[cfg(any(feature = "flexbox", feature = "grid"))]
215 pub align_items: Option<AlignItems>,
216 /// How this node should be aligned in the cross/block axis
217 /// Falls back to the parents [`AlignItems`] if not set
218 #[cfg(any(feature = "flexbox", feature = "grid"))]
219 pub align_self: Option<AlignSelf>,
220 /// How this node's children should be aligned in the inline axis
221 #[cfg(feature = "grid")]
222 pub justify_items: Option<AlignItems>,
223 /// How this node should be aligned in the inline axis
224 /// Falls back to the parents [`JustifyItems`] if not set
225 #[cfg(feature = "grid")]
226 pub justify_self: Option<AlignSelf>,
227 /// How should content contained within this item be aligned in the cross/block axis
228 #[cfg(any(feature = "flexbox", feature = "grid"))]
229 pub align_content: Option<AlignContent>,
230 /// How should contained within this item be aligned in the main/inline axis
231 #[cfg(any(feature = "flexbox", feature = "grid"))]
232 pub justify_content: Option<JustifyContent>,
233 /// How large should the gaps between items in a grid or flex container be?
234 #[cfg(any(feature = "flexbox", feature = "grid"))]
235 #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
236 pub gap: Size<LengthPercentage>,
237
238 // Flexbox properies
239 /// Which direction does the main axis flow in?
240 #[cfg(feature = "flexbox")]
241 pub flex_direction: FlexDirection,
242 /// Should elements wrap, or stay in a single line?
243 #[cfg(feature = "flexbox")]
244 pub flex_wrap: FlexWrap,
245 /// Sets the initial main axis size of the item
246 #[cfg(feature = "flexbox")]
247 pub flex_basis: Dimension,
248 /// The relative rate at which this item grows when it is expanding to fill space
249 ///
250 /// 0.0 is the default value, and this value must be positive.
251 #[cfg(feature = "flexbox")]
252 pub flex_grow: f32,
253 /// The relative rate at which this item shrinks when it is contracting to fit into space
254 ///
255 /// 1.0 is the default value, and this value must be positive.
256 #[cfg(feature = "flexbox")]
257 pub flex_shrink: f32,
258
259 // Grid container properies
260 /// Defines the track sizing functions (widths) of the grid rows
261 #[cfg(feature = "grid")]
262 pub grid_template_rows: GridTrackVec<TrackSizingFunction>,
263 /// Defines the track sizing functions (heights) of the grid columns
264 #[cfg(feature = "grid")]
265 pub grid_template_columns: GridTrackVec<TrackSizingFunction>,
266 /// Defines the size of implicitly created rows
267 #[cfg(feature = "grid")]
268 pub grid_auto_rows: GridTrackVec<NonRepeatedTrackSizingFunction>,
269 /// Defined the size of implicitly created columns
270 #[cfg(feature = "grid")]
271 pub grid_auto_columns: GridTrackVec<NonRepeatedTrackSizingFunction>,
272 /// Controls how items get placed into the grid for auto-placed items
273 #[cfg(feature = "grid")]
274 pub grid_auto_flow: GridAutoFlow,
275
276 // Grid child properties
277 /// Defines which row in the grid the item should start and end at
278 #[cfg(feature = "grid")]
279 pub grid_row: Line<GridPlacement>,
280 /// Defines which column in the grid the item should start and end at
281 #[cfg(feature = "grid")]
282 pub grid_column: Line<GridPlacement>,
283
284 // Morphorm container properties
285 /// Sets the default spacing *around* the group of all children of a morphorm container
286 #[cfg(feature = "morphorm")]
287 pub child_spacing: Rect<LengthPercentageAuto>,
288
289 // Morphorm child properties
290 /// Sets the minimum margin for child
291 #[cfg(feature = "morphorm")]
292 pub min_margin: Rect<LengthPercentage>,
293 /// Sets the maximum margin for child
294 #[cfg(feature = "morphorm")]
295 pub max_margin: Rect<LengthPercentage>,
296}
297
298impl Style {
299 /// The [`Default`] layout, in a form that can be used in const functions
300 pub const DEFAULT: Style = Style {
301 display: Display::DEFAULT,
302 overflow: Point { x: Overflow::Visible, y: Overflow::Visible },
303 scrollbar_width: 0.0,
304 position: Position::Relative,
305 inset: Rect::auto(),
306 margin: Rect::zero(),
307 padding: Rect::zero(),
308 border: Rect::zero(),
309 size: Size::auto(),
310 min_size: Size::auto(),
311 max_size: Size::auto(),
312 aspect_ratio: None,
313 #[cfg(any(feature = "flexbox", feature = "grid", feature = "morphorm"))]
314 gap: Size::zero(),
315 // Aligment
316 #[cfg(any(feature = "flexbox", feature = "grid"))]
317 align_items: None,
318 #[cfg(any(feature = "flexbox", feature = "grid"))]
319 align_self: None,
320 #[cfg(feature = "grid")]
321 justify_items: None,
322 #[cfg(feature = "grid")]
323 justify_self: None,
324 #[cfg(any(feature = "flexbox", feature = "grid"))]
325 align_content: None,
326 #[cfg(any(feature = "flexbox", feature = "grid"))]
327 justify_content: None,
328 // Flexbox
329 #[cfg(any(feature = "flexbox", feature = "morphorm"))]
330 flex_direction: FlexDirection::Row,
331 #[cfg(any(feature = "flexbox", feature = "morphorm"))]
332 flex_wrap: FlexWrap::NoWrap,
333 #[cfg(feature = "flexbox")]
334 flex_grow: 0.0,
335 #[cfg(feature = "flexbox")]
336 flex_shrink: 1.0,
337 #[cfg(feature = "flexbox")]
338 flex_basis: Dimension::Auto,
339 // Grid
340 #[cfg(feature = "grid")]
341 grid_template_rows: GridTrackVec::new(),
342 #[cfg(feature = "grid")]
343 grid_template_columns: GridTrackVec::new(),
344 #[cfg(feature = "grid")]
345 grid_auto_rows: GridTrackVec::new(),
346 #[cfg(feature = "grid")]
347 grid_auto_columns: GridTrackVec::new(),
348 #[cfg(feature = "grid")]
349 grid_auto_flow: GridAutoFlow::Row,
350 #[cfg(feature = "grid")]
351 grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
352 #[cfg(feature = "grid")]
353 grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
354
355 #[cfg(feature = "morphorm")]
356 child_spacing: Rect::zero(),
357 #[cfg(feature = "morphorm")]
358 min_margin: Rect::zero(),
359 #[cfg(feature = "morphorm")]
360 max_margin: Rect {
361 left: LengthPercentage::Length(f32::INFINITY),
362 right: LengthPercentage::Length(f32::INFINITY),
363 top: LengthPercentage::Length(f32::INFINITY),
364 bottom: LengthPercentage::Length(f32::INFINITY),
365 },
366 };
367}
368
369impl Default for Style {
370 fn default() -> Self {
371 Style::DEFAULT
372 }
373}
374
375#[cfg(test)]
376mod tests {
377 use super::Style;
378 use crate::geometry::*;
379
380 #[test]
381 fn defaults_match() {
382 #[cfg(feature = "grid")]
383 use super::GridPlacement;
384 use super::LengthPercentage;
385
386 let old_defaults = Style {
387 display: Default::default(),
388 overflow: Default::default(),
389 scrollbar_width: 0.0,
390 position: Default::default(),
391 #[cfg(feature = "flexbox")]
392 flex_direction: Default::default(),
393 #[cfg(feature = "flexbox")]
394 flex_wrap: Default::default(),
395 #[cfg(any(feature = "flexbox", feature = "grid"))]
396 align_items: Default::default(),
397 #[cfg(any(feature = "flexbox", feature = "grid"))]
398 align_self: Default::default(),
399 #[cfg(feature = "grid")]
400 justify_items: Default::default(),
401 #[cfg(feature = "grid")]
402 justify_self: Default::default(),
403 #[cfg(any(feature = "flexbox", feature = "grid"))]
404 align_content: Default::default(),
405 #[cfg(any(feature = "flexbox", feature = "grid"))]
406 justify_content: Default::default(),
407 inset: Rect::auto(),
408 margin: Rect::zero(),
409 padding: Rect::zero(),
410 border: Rect::zero(),
411 gap: Size::zero(),
412 #[cfg(feature = "flexbox")]
413 flex_grow: 0.0,
414 #[cfg(feature = "flexbox")]
415 flex_shrink: 1.0,
416 #[cfg(feature = "flexbox")]
417 flex_basis: super::Dimension::Auto,
418 size: Size::auto(),
419 min_size: Size::auto(),
420 max_size: Size::auto(),
421 aspect_ratio: Default::default(),
422
423 #[cfg(feature = "grid")]
424 grid_template_rows: Default::default(),
425 #[cfg(feature = "grid")]
426 grid_template_columns: Default::default(),
427 #[cfg(feature = "grid")]
428 grid_auto_rows: Default::default(),
429 #[cfg(feature = "grid")]
430 grid_auto_columns: Default::default(),
431 #[cfg(feature = "grid")]
432 grid_auto_flow: Default::default(),
433 #[cfg(feature = "grid")]
434 grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
435 #[cfg(feature = "grid")]
436 grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
437
438 #[cfg(feature = "morphorm")]
439 child_spacing: Rect::zero(),
440 #[cfg(feature = "morphorm")]
441 min_margin: Rect::zero(),
442 #[cfg(feature = "morphorm")]
443 max_margin: Rect {
444 left: LengthPercentage::Length(f32::INFINITY),
445 right: LengthPercentage::Length(f32::INFINITY),
446 top: LengthPercentage::Length(f32::INFINITY),
447 bottom: LengthPercentage::Length(f32::INFINITY),
448 },
449 };
450
451 assert_eq!(Style::DEFAULT, Style::default());
452 assert_eq!(Style::DEFAULT, old_defaults);
453 }
454
455 // NOTE: Please feel free the update the sizes in this test as required. This test is here to prevent unintentional size changes
456 // and to serve as accurate up-to-date documentation on the sizes.
457 #[test]
458 fn style_sizes() {
459 use super::*;
460
461 fn assert_type_size<T>(expected_size: usize) {
462 let name = ::core::any::type_name::<T>();
463 let name = name.replace("taffy::geometry::", "");
464 let name = name.replace("taffy::style::dimension::", "");
465 let name = name.replace("taffy::style::alignment::", "");
466 let name = name.replace("taffy::style::flex::", "");
467 let name = name.replace("taffy::style::grid::", "");
468
469 assert_eq!(
470 ::core::mem::size_of::<T>(),
471 expected_size,
472 "Expected {} for be {} byte(s) but it was {} byte(s)",
473 name,
474 expected_size,
475 ::core::mem::size_of::<T>(),
476 );
477 }
478
479 // Display and Position
480 assert_type_size::<Display>(1);
481 assert_type_size::<Position>(1);
482 assert_type_size::<Overflow>(1);
483
484 // Dimensions and aggregations of Dimensions
485 assert_type_size::<f32>(4);
486 assert_type_size::<LengthPercentage>(8);
487 assert_type_size::<LengthPercentageAuto>(8);
488 assert_type_size::<Dimension>(8);
489 assert_type_size::<Size<LengthPercentage>>(16);
490 assert_type_size::<Size<LengthPercentageAuto>>(16);
491 assert_type_size::<Size<Dimension>>(16);
492 assert_type_size::<Rect<LengthPercentage>>(32);
493 assert_type_size::<Rect<LengthPercentageAuto>>(32);
494 assert_type_size::<Rect<Dimension>>(32);
495
496 // Alignment
497 assert_type_size::<AlignContent>(1);
498 assert_type_size::<AlignItems>(1);
499 assert_type_size::<Option<AlignItems>>(1);
500
501 // Flexbox Container
502 assert_type_size::<FlexDirection>(1);
503 assert_type_size::<FlexWrap>(1);
504
505 // CSS Grid Container
506 assert_type_size::<GridAutoFlow>(1);
507 assert_type_size::<MinTrackSizingFunction>(8);
508 assert_type_size::<MaxTrackSizingFunction>(12);
509 assert_type_size::<NonRepeatedTrackSizingFunction>(20);
510 assert_type_size::<TrackSizingFunction>(32);
511 assert_type_size::<Vec<NonRepeatedTrackSizingFunction>>(24);
512 assert_type_size::<Vec<TrackSizingFunction>>(24);
513
514 // CSS Grid Item
515 assert_type_size::<GridPlacement>(4);
516 assert_type_size::<Line<GridPlacement>>(8);
517
518 // Overall
519 assert_type_size::<Style>(448);
520 }
521}