bevy_ui/
ui_node.rs

1use crate::{FocusPolicy, UiRect, Val};
2use bevy_color::Color;
3use bevy_derive::{Deref, DerefMut};
4use bevy_ecs::{prelude::*, system::SystemParam};
5use bevy_math::{vec4, Rect, UVec2, Vec2, Vec4Swizzles};
6use bevy_reflect::prelude::*;
7use bevy_render::{
8    camera::{Camera, RenderTarget},
9    view::Visibility,
10    view::VisibilityClass,
11};
12use bevy_sprite::BorderRect;
13use bevy_transform::components::Transform;
14use bevy_utils::once;
15use bevy_window::{PrimaryWindow, WindowRef};
16use core::num::NonZero;
17use derive_more::derive::From;
18use smallvec::SmallVec;
19use thiserror::Error;
20use tracing::warn;
21
22/// Provides the computed size and layout properties of the node.
23///
24/// Fields in this struct are public but should not be modified under most circumstances.
25/// For example, in a scrollbar you may want to derive the handle's size from the proportion of
26/// scrollable content in-view. You can directly modify `ComputedNode` after layout to set the
27/// handle size without any delays.
28#[derive(Component, Debug, Copy, Clone, PartialEq, Reflect)]
29#[reflect(Component, Default, Debug, Clone)]
30pub struct ComputedNode {
31    /// The order of the node in the UI layout.
32    /// Nodes with a higher stack index are drawn on top of and receive interactions before nodes with lower stack indices.
33    ///
34    /// Automatically calculated in [`super::UiSystem::Stack`].
35    pub stack_index: u32,
36    /// The size of the node as width and height in physical pixels.
37    ///
38    /// Automatically calculated by [`super::layout::ui_layout_system`].
39    pub size: Vec2,
40    /// Size of this node's content.
41    ///
42    /// Automatically calculated by [`super::layout::ui_layout_system`].
43    pub content_size: Vec2,
44    /// The width of this node's outline.
45    /// If this value is `Auto`, negative or `0.` then no outline will be rendered.
46    /// Outline updates bypass change detection.
47    ///
48    /// Automatically calculated by [`super::layout::ui_layout_system`].
49    pub outline_width: f32,
50    /// The amount of space between the outline and the edge of the node.
51    /// Outline updates bypass change detection.
52    ///
53    /// Automatically calculated by [`super::layout::ui_layout_system`].
54    pub outline_offset: f32,
55    /// The unrounded size of the node as width and height in physical pixels.
56    ///
57    /// Automatically calculated by [`super::layout::ui_layout_system`].
58    pub unrounded_size: Vec2,
59    /// Resolved border values in physical pixels.
60    /// Border updates bypass change detection.
61    ///
62    /// Automatically calculated by [`super::layout::ui_layout_system`].
63    pub border: BorderRect,
64    /// Resolved border radius values in physical pixels.
65    /// Border radius updates bypass change detection.
66    ///
67    /// Automatically calculated by [`super::layout::ui_layout_system`].
68    pub border_radius: ResolvedBorderRadius,
69    /// Resolved padding values in physical pixels.
70    /// Padding updates bypass change detection.
71    ///
72    /// Automatically calculated by [`super::layout::ui_layout_system`].
73    pub padding: BorderRect,
74    /// Inverse scale factor for this Node.
75    /// Multiply physical coordinates by the inverse scale factor to give logical coordinates.
76    ///
77    /// Automatically calculated by [`super::layout::ui_layout_system`].
78    pub inverse_scale_factor: f32,
79}
80
81impl ComputedNode {
82    /// The calculated node size as width and height in physical pixels.
83    ///
84    /// Automatically calculated by [`super::layout::ui_layout_system`].
85    #[inline]
86    pub const fn size(&self) -> Vec2 {
87        self.size
88    }
89
90    /// The calculated node content size as width and height in physical pixels.
91    ///
92    /// Automatically calculated by [`super::layout::ui_layout_system`].
93    #[inline]
94    pub const fn content_size(&self) -> Vec2 {
95        self.content_size
96    }
97
98    /// Check if the node is empty.
99    /// A node is considered empty if it has a zero or negative extent along either of its axes.
100    #[inline]
101    pub const fn is_empty(&self) -> bool {
102        self.size.x <= 0. || self.size.y <= 0.
103    }
104
105    /// The order of the node in the UI layout.
106    /// Nodes with a higher stack index are drawn on top of and receive interactions before nodes with lower stack indices.
107    ///
108    /// Automatically calculated by [`super::layout::ui_layout_system`].
109    pub const fn stack_index(&self) -> u32 {
110        self.stack_index
111    }
112
113    /// The calculated node size as width and height in physical pixels before rounding.
114    ///
115    /// Automatically calculated by [`super::layout::ui_layout_system`].
116    #[inline]
117    pub const fn unrounded_size(&self) -> Vec2 {
118        self.unrounded_size
119    }
120
121    /// Returns the thickness of the UI node's outline in physical pixels.
122    /// If this value is negative or `0.` then no outline will be rendered.
123    ///
124    /// Automatically calculated by [`super::layout::ui_layout_system`].
125    #[inline]
126    pub const fn outline_width(&self) -> f32 {
127        self.outline_width
128    }
129
130    /// Returns the amount of space between the outline and the edge of the node in physical pixels.
131    ///
132    /// Automatically calculated by [`super::layout::ui_layout_system`].
133    #[inline]
134    pub const fn outline_offset(&self) -> f32 {
135        self.outline_offset
136    }
137
138    /// Returns the size of the node when including its outline.
139    ///
140    /// Automatically calculated by [`super::layout::ui_layout_system`].
141    #[inline]
142    pub const fn outlined_node_size(&self) -> Vec2 {
143        let offset = 2. * (self.outline_offset + self.outline_width);
144        Vec2::new(self.size.x + offset, self.size.y + offset)
145    }
146
147    /// Returns the border radius for each corner of the outline
148    /// An outline's border radius is derived from the node's border-radius
149    /// so that the outline wraps the border equally at all points.
150    ///
151    /// Automatically calculated by [`super::layout::ui_layout_system`].
152    #[inline]
153    pub const fn outline_radius(&self) -> ResolvedBorderRadius {
154        let outer_distance = self.outline_width + self.outline_offset;
155        const fn compute_radius(radius: f32, outer_distance: f32) -> f32 {
156            if radius > 0. {
157                radius + outer_distance
158            } else {
159                0.
160            }
161        }
162        ResolvedBorderRadius {
163            top_left: compute_radius(self.border_radius.top_left, outer_distance),
164            top_right: compute_radius(self.border_radius.top_right, outer_distance),
165            bottom_left: compute_radius(self.border_radius.bottom_left, outer_distance),
166            bottom_right: compute_radius(self.border_radius.bottom_right, outer_distance),
167        }
168    }
169
170    /// Returns the thickness of the node's border on each edge in physical pixels.
171    ///
172    /// Automatically calculated by [`super::layout::ui_layout_system`].
173    #[inline]
174    pub const fn border(&self) -> BorderRect {
175        self.border
176    }
177
178    /// Returns the border radius for each of the node's corners in physical pixels.
179    ///
180    /// Automatically calculated by [`super::layout::ui_layout_system`].
181    #[inline]
182    pub const fn border_radius(&self) -> ResolvedBorderRadius {
183        self.border_radius
184    }
185
186    /// Returns the inner border radius for each of the node's corners in physical pixels.
187    pub fn inner_radius(&self) -> ResolvedBorderRadius {
188        fn clamp_corner(r: f32, size: Vec2, offset: Vec2) -> f32 {
189            let s = 0.5 * size + offset;
190            let sm = s.x.min(s.y);
191            r.min(sm)
192        }
193        let b = vec4(
194            self.border.left,
195            self.border.top,
196            self.border.right,
197            self.border.bottom,
198        );
199        let s = self.size() - b.xy() - b.zw();
200        ResolvedBorderRadius {
201            top_left: clamp_corner(self.border_radius.top_left, s, b.xy()),
202            top_right: clamp_corner(self.border_radius.top_right, s, b.zy()),
203            bottom_left: clamp_corner(self.border_radius.bottom_right, s, b.zw()),
204            bottom_right: clamp_corner(self.border_radius.bottom_left, s, b.xw()),
205        }
206    }
207
208    /// Returns the thickness of the node's padding on each edge in physical pixels.
209    ///
210    /// Automatically calculated by [`super::layout::ui_layout_system`].
211    #[inline]
212    pub const fn padding(&self) -> BorderRect {
213        self.padding
214    }
215
216    /// Returns the combined inset on each edge including both padding and border thickness in physical pixels.
217    #[inline]
218    pub const fn content_inset(&self) -> BorderRect {
219        BorderRect {
220            left: self.border.left + self.padding.left,
221            right: self.border.right + self.padding.right,
222            top: self.border.top + self.padding.top,
223            bottom: self.border.bottom + self.padding.bottom,
224        }
225    }
226
227    /// Returns the inverse of the scale factor for this node.
228    /// To convert from physical coordinates to logical coordinates multiply by this value.
229    #[inline]
230    pub const fn inverse_scale_factor(&self) -> f32 {
231        self.inverse_scale_factor
232    }
233}
234
235impl ComputedNode {
236    pub const DEFAULT: Self = Self {
237        stack_index: 0,
238        size: Vec2::ZERO,
239        content_size: Vec2::ZERO,
240        outline_width: 0.,
241        outline_offset: 0.,
242        unrounded_size: Vec2::ZERO,
243        border_radius: ResolvedBorderRadius::ZERO,
244        border: BorderRect::ZERO,
245        padding: BorderRect::ZERO,
246        inverse_scale_factor: 1.,
247    };
248}
249
250impl Default for ComputedNode {
251    fn default() -> Self {
252        Self::DEFAULT
253    }
254}
255
256/// The scroll position of the node.
257///
258/// Updating the values of `ScrollPosition` will reposition the children of the node by the offset amount.
259/// `ScrollPosition` may be updated by the layout system when a layout change makes a previously valid `ScrollPosition` invalid.
260/// Changing this does nothing on a `Node` without setting at least one `OverflowAxis` to `OverflowAxis::Scroll`.
261#[derive(Component, Debug, Clone, Reflect)]
262#[reflect(Component, Default, Clone)]
263pub struct ScrollPosition {
264    /// How far across the node is scrolled, in logical pixels. (0 = not scrolled / scrolled to right)
265    pub offset_x: f32,
266    /// How far down the node is scrolled, in logical pixels. (0 = not scrolled / scrolled to top)
267    pub offset_y: f32,
268}
269
270impl ScrollPosition {
271    pub const DEFAULT: Self = Self {
272        offset_x: 0.0,
273        offset_y: 0.0,
274    };
275}
276
277impl Default for ScrollPosition {
278    fn default() -> Self {
279        Self::DEFAULT
280    }
281}
282
283impl From<&ScrollPosition> for Vec2 {
284    fn from(scroll_pos: &ScrollPosition) -> Self {
285        Vec2::new(scroll_pos.offset_x, scroll_pos.offset_y)
286    }
287}
288
289impl From<Vec2> for ScrollPosition {
290    fn from(vec: Vec2) -> Self {
291        ScrollPosition {
292            offset_x: vec.x,
293            offset_y: vec.y,
294        }
295    }
296}
297
298/// The base component for UI entities. It describes UI layout and style properties.
299///
300/// When defining new types of UI entities, require [`Node`] to make them behave like UI nodes.
301///
302/// Nodes can be laid out using either Flexbox or CSS Grid Layout.
303///
304/// See below for general learning resources and for documentation on the individual style properties.
305///
306/// ### Flexbox
307///
308/// - [MDN: Basic Concepts of Flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox)
309/// - [A Complete Guide To Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) by CSS Tricks. This is detailed guide with illustrations and comprehensive written explanation of the different Flexbox properties and how they work.
310/// - [Flexbox Froggy](https://flexboxfroggy.com/). An interactive tutorial/game that teaches the essential parts of Flexbox in a fun engaging way.
311///
312/// ### CSS Grid
313///
314/// - [MDN: Basic Concepts of Grid Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout)
315/// - [A Complete Guide To CSS Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) by CSS Tricks. This is detailed guide with illustrations and comprehensive written explanation of the different CSS Grid properties and how they work.
316/// - [CSS Grid Garden](https://cssgridgarden.com/). An interactive tutorial/game that teaches the essential parts of CSS Grid in a fun engaging way.
317///
318/// # See also
319///
320/// - [`RelativeCursorPosition`](crate::RelativeCursorPosition) to obtain the cursor position relative to this node
321/// - [`Interaction`](crate::Interaction) to obtain the interaction state of this node
322
323#[derive(Component, Clone, PartialEq, Debug, Reflect)]
324#[require(
325    ComputedNode,
326    ComputedNodeTarget,
327    BackgroundColor,
328    BorderColor,
329    BorderRadius,
330    FocusPolicy,
331    ScrollPosition,
332    Transform,
333    Visibility,
334    VisibilityClass,
335    ZIndex
336)]
337#[reflect(Component, Default, PartialEq, Debug, Clone)]
338#[cfg_attr(
339    feature = "serialize",
340    derive(serde::Serialize, serde::Deserialize),
341    reflect(Serialize, Deserialize)
342)]
343pub struct Node {
344    /// Which layout algorithm to use when laying out this node's contents:
345    ///   - [`Display::Flex`]: Use the Flexbox layout algorithm
346    ///   - [`Display::Grid`]: Use the CSS Grid layout algorithm
347    ///   - [`Display::None`]: Hide this node and perform layout as if it does not exist.
348    ///
349    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/display>
350    pub display: Display,
351
352    /// Which part of a Node's box length styles like width and height control
353    ///   - [`BoxSizing::BorderBox`]: They refer to the "border box" size (size including padding and border)
354    ///   - [`BoxSizing::ContentBox`]: They refer to the "content box" size (size excluding padding and border)
355    ///
356    /// `BoxSizing::BorderBox` is generally considered more intuitive and is the default in Bevy even though it is not on the web.
357    ///
358    /// See: <https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing>
359    pub box_sizing: BoxSizing,
360
361    /// Whether a node should be laid out in-flow with, or independently of its siblings:
362    ///  - [`PositionType::Relative`]: Layout this node in-flow with other nodes using the usual (flexbox/grid) layout algorithm.
363    ///  - [`PositionType::Absolute`]: Layout this node on top and independently of other nodes.
364    ///
365    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/position>
366    pub position_type: PositionType,
367
368    /// Whether overflowing content should be displayed or clipped.
369    ///
370    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow>
371    pub overflow: Overflow,
372
373    /// How the bounds of clipped content should be determined
374    ///
375    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-margin>
376    pub overflow_clip_margin: OverflowClipMargin,
377
378    /// The horizontal position of the left edge of the node.
379    ///  - For relatively positioned nodes, this is relative to the node's position as computed during regular layout.
380    ///  - For absolutely positioned nodes, this is relative to the *parent* node's bounding box.
381    ///
382    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/left>
383    pub left: Val,
384
385    /// The horizontal position of the right edge of the node.
386    ///  - For relatively positioned nodes, this is relative to the node's position as computed during regular layout.
387    ///  - For absolutely positioned nodes, this is relative to the *parent* node's bounding box.
388    ///
389    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/right>
390    pub right: Val,
391
392    /// The vertical position of the top edge of the node.
393    ///  - For relatively positioned nodes, this is relative to the node's position as computed during regular layout.
394    ///  - For absolutely positioned nodes, this is relative to the *parent* node's bounding box.
395    ///
396    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/top>
397    pub top: Val,
398
399    /// The vertical position of the bottom edge of the node.
400    ///  - For relatively positioned nodes, this is relative to the node's position as computed during regular layout.
401    ///  - For absolutely positioned nodes, this is relative to the *parent* node's bounding box.
402    ///
403    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/bottom>
404    pub bottom: Val,
405
406    /// The ideal width of the node. `width` is used when it is within the bounds defined by `min_width` and `max_width`.
407    ///
408    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/width>
409    pub width: Val,
410
411    /// The ideal height of the node. `height` is used when it is within the bounds defined by `min_height` and `max_height`.
412    ///
413    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/height>
414    pub height: Val,
415
416    /// The minimum width of the node. `min_width` is used if it is greater than `width` and/or `max_width`.
417    ///
418    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/min-width>
419    pub min_width: Val,
420
421    /// The minimum height of the node. `min_height` is used if it is greater than `height` and/or `max_height`.
422    ///
423    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/min-height>
424    pub min_height: Val,
425
426    /// The maximum width of the node. `max_width` is used if it is within the bounds defined by `min_width` and `width`.
427    ///
428    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/max-width>
429    pub max_width: Val,
430
431    /// The maximum height of the node. `max_height` is used if it is within the bounds defined by `min_height` and `height`.
432    ///
433    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/max-height>
434    pub max_height: Val,
435
436    /// The aspect ratio of the node (defined as `width / height`)
437    ///
438    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio>
439    pub aspect_ratio: Option<f32>,
440
441    /// Used to control how each individual item is aligned by default within the space they're given.
442    /// - For Flexbox containers, sets default cross axis alignment of the child items.
443    /// - For CSS Grid containers, controls block (vertical) axis alignment of children of this grid container within their grid areas.
444    ///
445    /// This value is overridden if [`AlignSelf`] on the child node is set.
446    ///
447    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>
448    pub align_items: AlignItems,
449
450    /// Used to control how each individual item is aligned by default within the space they're given.
451    /// - For Flexbox containers, this property has no effect. See `justify_content` for main axis alignment of flex items.
452    /// - For CSS Grid containers, sets default inline (horizontal) axis alignment of child items within their grid areas.
453    ///
454    /// This value is overridden if [`JustifySelf`] on the child node is set.
455    ///
456    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items>
457    pub justify_items: JustifyItems,
458
459    /// Used to control how the specified item is aligned within the space it's given.
460    /// - For Flexbox items, controls cross axis alignment of the item.
461    /// - For CSS Grid items, controls block (vertical) axis alignment of a grid item within its grid area.
462    ///
463    /// If set to `Auto`, alignment is inherited from the value of [`AlignItems`] set on the parent node.
464    ///
465    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-self>
466    pub align_self: AlignSelf,
467
468    /// Used to control how the specified item is aligned within the space it's given.
469    /// - For Flexbox items, this property has no effect. See `justify_content` for main axis alignment of flex items.
470    /// - For CSS Grid items, controls inline (horizontal) axis alignment of a grid item within its grid area.
471    ///
472    /// If set to `Auto`, alignment is inherited from the value of [`JustifyItems`] set on the parent node.
473    ///
474    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self>
475    pub justify_self: JustifySelf,
476
477    /// Used to control how items are distributed.
478    /// - For Flexbox containers, controls alignment of lines if `flex_wrap` is set to [`FlexWrap::Wrap`] and there are multiple lines of items.
479    /// - For CSS Grid containers, controls alignment of grid rows.
480    ///
481    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-content>
482    pub align_content: AlignContent,
483
484    /// Used to control how items are distributed.
485    /// - For Flexbox containers, controls alignment of items in the main axis.
486    /// - For CSS Grid containers, controls alignment of grid columns.
487    ///
488    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content>
489    pub justify_content: JustifyContent,
490
491    /// The amount of space around a node outside its border.
492    ///
493    /// If a percentage value is used, the percentage is calculated based on the width of the parent node.
494    ///
495    /// # Example
496    /// ```
497    /// # use bevy_ui::{Node, UiRect, Val};
498    /// let node = Node {
499    ///     margin: UiRect {
500    ///         left: Val::Percent(10.),
501    ///         right: Val::Percent(10.),
502    ///         top: Val::Percent(15.),
503    ///         bottom: Val::Percent(15.)
504    ///     },
505    ///     ..Default::default()
506    /// };
507    /// ```
508    /// A node with this style and a parent with dimensions of 100px by 300px will have calculated margins of 10px on both left and right edges, and 15px on both top and bottom edges.
509    ///
510    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/margin>
511    pub margin: UiRect,
512
513    /// The amount of space between the edges of a node and its contents.
514    ///
515    /// If a percentage value is used, the percentage is calculated based on the width of the parent node.
516    ///
517    /// # Example
518    /// ```
519    /// # use bevy_ui::{Node, UiRect, Val};
520    /// let node = Node {
521    ///     padding: UiRect {
522    ///         left: Val::Percent(1.),
523    ///         right: Val::Percent(2.),
524    ///         top: Val::Percent(3.),
525    ///         bottom: Val::Percent(4.)
526    ///     },
527    ///     ..Default::default()
528    /// };
529    /// ```
530    /// A node with this style and a parent with dimensions of 300px by 100px will have calculated padding of 3px on the left, 6px on the right, 9px on the top and 12px on the bottom.
531    ///
532    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/padding>
533    pub padding: UiRect,
534
535    /// The amount of space between the margins of a node and its padding.
536    ///
537    /// If a percentage value is used, the percentage is calculated based on the width of the parent node.
538    ///
539    /// The size of the node will be expanded if there are constraints that prevent the layout algorithm from placing the border within the existing node boundary.
540    ///
541    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/border-width>
542    pub border: UiRect,
543
544    /// Whether a Flexbox container should be a row or a column. This property has no effect on Grid nodes.
545    ///
546    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction>
547    pub flex_direction: FlexDirection,
548
549    /// Whether a Flexbox container should wrap its contents onto multiple lines if they overflow. This property has no effect on Grid nodes.
550    ///
551    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap>
552    pub flex_wrap: FlexWrap,
553
554    /// Defines how much a flexbox item should grow if there's space available. Defaults to 0 (don't grow at all).
555    ///
556    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow>
557    pub flex_grow: f32,
558
559    /// Defines how much a flexbox item should shrink if there's not enough space available. Defaults to 1.
560    ///
561    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-shrink>
562    pub flex_shrink: f32,
563
564    /// The initial length of a flexbox in the main axis, before flex growing/shrinking properties are applied.
565    ///
566    /// `flex_basis` overrides `width` (if the main axis is horizontal) or `height` (if the main axis is vertical) when both are set, but it obeys the constraints defined by `min_width`/`min_height` and `max_width`/`max_height`.
567    ///
568    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis>
569    pub flex_basis: Val,
570
571    /// The size of the gutters between items in a vertical flexbox layout or between rows in a grid layout.
572    ///
573    /// Note: Values of `Val::Auto` are not valid and are treated as zero.
574    ///
575    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap>
576    pub row_gap: Val,
577
578    /// The size of the gutters between items in a horizontal flexbox layout or between column in a grid layout.
579    ///
580    /// Note: Values of `Val::Auto` are not valid and are treated as zero.
581    ///
582    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/column-gap>
583    pub column_gap: Val,
584
585    /// Controls whether automatically placed grid items are placed row-wise or column-wise as well as whether the sparse or dense packing algorithm is used.
586    /// Only affects Grid layouts.
587    ///
588    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow>
589    pub grid_auto_flow: GridAutoFlow,
590
591    /// Defines the number of rows a grid has and the sizes of those rows. If grid items are given explicit placements then more rows may
592    /// be implicitly generated by items that are placed out of bounds. The sizes of those rows are controlled by `grid_auto_rows` property.
593    ///
594    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows>
595    pub grid_template_rows: Vec<RepeatedGridTrack>,
596
597    /// Defines the number of columns a grid has and the sizes of those columns. If grid items are given explicit placements then more columns may
598    /// be implicitly generated by items that are placed out of bounds. The sizes of those columns are controlled by `grid_auto_columns` property.
599    ///
600    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns>
601    pub grid_template_columns: Vec<RepeatedGridTrack>,
602
603    /// Defines the size of implicitly created rows. Rows are created implicitly when grid items are given explicit placements that are out of bounds
604    /// of the rows explicitly created using `grid_template_rows`.
605    ///
606    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-rows>
607    pub grid_auto_rows: Vec<GridTrack>,
608    /// Defines the size of implicitly created columns. Columns are created implicitly when grid items are given explicit placements that are out of bounds
609    /// of the columns explicitly created using `grid_template_columns`.
610    ///
611    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-columns>
612    pub grid_auto_columns: Vec<GridTrack>,
613
614    /// The row in which a grid item starts and how many rows it spans.
615    ///
616    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row>
617    pub grid_row: GridPlacement,
618
619    /// The column in which a grid item starts and how many columns it spans.
620    ///
621    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column>
622    pub grid_column: GridPlacement,
623}
624
625impl Node {
626    pub const DEFAULT: Self = Self {
627        display: Display::DEFAULT,
628        box_sizing: BoxSizing::DEFAULT,
629        position_type: PositionType::DEFAULT,
630        left: Val::Auto,
631        right: Val::Auto,
632        top: Val::Auto,
633        bottom: Val::Auto,
634        flex_direction: FlexDirection::DEFAULT,
635        flex_wrap: FlexWrap::DEFAULT,
636        align_items: AlignItems::DEFAULT,
637        justify_items: JustifyItems::DEFAULT,
638        align_self: AlignSelf::DEFAULT,
639        justify_self: JustifySelf::DEFAULT,
640        align_content: AlignContent::DEFAULT,
641        justify_content: JustifyContent::DEFAULT,
642        margin: UiRect::DEFAULT,
643        padding: UiRect::DEFAULT,
644        border: UiRect::DEFAULT,
645        flex_grow: 0.0,
646        flex_shrink: 1.0,
647        flex_basis: Val::Auto,
648        width: Val::Auto,
649        height: Val::Auto,
650        min_width: Val::Auto,
651        min_height: Val::Auto,
652        max_width: Val::Auto,
653        max_height: Val::Auto,
654        aspect_ratio: None,
655        overflow: Overflow::DEFAULT,
656        overflow_clip_margin: OverflowClipMargin::DEFAULT,
657        row_gap: Val::ZERO,
658        column_gap: Val::ZERO,
659        grid_auto_flow: GridAutoFlow::DEFAULT,
660        grid_template_rows: Vec::new(),
661        grid_template_columns: Vec::new(),
662        grid_auto_rows: Vec::new(),
663        grid_auto_columns: Vec::new(),
664        grid_column: GridPlacement::DEFAULT,
665        grid_row: GridPlacement::DEFAULT,
666    };
667}
668
669impl Default for Node {
670    fn default() -> Self {
671        Self::DEFAULT
672    }
673}
674
675/// Used to control how each individual item is aligned by default within the space they're given.
676/// - For Flexbox containers, sets default cross axis alignment of the child items.
677/// - For CSS Grid containers, controls block (vertical) axis alignment of children of this grid container within their grid areas.
678///
679/// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>
680#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
681#[reflect(Default, PartialEq, Clone)]
682#[cfg_attr(
683    feature = "serialize",
684    derive(serde::Serialize, serde::Deserialize),
685    reflect(Serialize, Deserialize)
686)]
687pub enum AlignItems {
688    /// The items are packed in their default position as if no alignment was applied.
689    Default,
690    /// The items are packed towards the start of the axis.
691    Start,
692    /// The items are packed towards the end of the axis.
693    End,
694    /// The items are packed towards the start of the axis, unless the flex direction is reversed;
695    /// then they are packed towards the end of the axis.
696    FlexStart,
697    /// The items are packed towards the end of the axis, unless the flex direction is reversed;
698    /// then they are packed towards the start of the axis.
699    FlexEnd,
700    /// The items are packed along the center of the axis.
701    Center,
702    /// The items are packed such that their baselines align.
703    Baseline,
704    /// The items are stretched to fill the space they're given.
705    Stretch,
706}
707
708impl AlignItems {
709    pub const DEFAULT: Self = Self::Default;
710}
711
712impl Default for AlignItems {
713    fn default() -> Self {
714        Self::DEFAULT
715    }
716}
717
718/// Used to control how each individual item is aligned by default within the space they're given.
719/// - For Flexbox containers, this property has no effect. See `justify_content` for main axis alignment of flex items.
720/// - For CSS Grid containers, sets default inline (horizontal) axis alignment of child items within their grid areas.
721///
722/// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items>
723#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
724#[reflect(Default, PartialEq, Clone)]
725#[cfg_attr(
726    feature = "serialize",
727    derive(serde::Serialize, serde::Deserialize),
728    reflect(Serialize, Deserialize)
729)]
730pub enum JustifyItems {
731    /// The items are packed in their default position as if no alignment was applied.
732    Default,
733    /// The items are packed towards the start of the axis.
734    Start,
735    /// The items are packed towards the end of the axis.
736    End,
737    /// The items are packed along the center of the axis
738    Center,
739    /// The items are packed such that their baselines align.
740    Baseline,
741    /// The items are stretched to fill the space they're given.
742    Stretch,
743}
744
745impl JustifyItems {
746    pub const DEFAULT: Self = Self::Default;
747}
748
749impl Default for JustifyItems {
750    fn default() -> Self {
751        Self::DEFAULT
752    }
753}
754
755/// Used to control how the specified item is aligned within the space it's given.
756/// - For Flexbox items, controls cross axis alignment of the item.
757/// - For CSS Grid items, controls block (vertical) axis alignment of a grid item within its grid area.
758///
759/// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-self>
760#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
761#[reflect(Default, PartialEq, Clone)]
762#[cfg_attr(
763    feature = "serialize",
764    derive(serde::Serialize, serde::Deserialize),
765    reflect(Serialize, Deserialize)
766)]
767pub enum AlignSelf {
768    /// Use the parent node's [`AlignItems`] value to determine how this item should be aligned.
769    Auto,
770    /// This item will be aligned with the start of the axis.
771    Start,
772    /// This item will be aligned with the end of the axis.
773    End,
774    /// This item will be aligned with the start of the axis, unless the flex direction is reversed;
775    /// then it will be aligned with the end of the axis.
776    FlexStart,
777    /// This item will be aligned with the end of the axis, unless the flex direction is reversed;
778    /// then it will be aligned with the start of the axis.
779    FlexEnd,
780    /// This item will be aligned along the center of the axis.
781    Center,
782    /// This item will be aligned at the baseline.
783    Baseline,
784    /// This item will be stretched to fill the container.
785    Stretch,
786}
787
788impl AlignSelf {
789    pub const DEFAULT: Self = Self::Auto;
790}
791
792impl Default for AlignSelf {
793    fn default() -> Self {
794        Self::DEFAULT
795    }
796}
797
798/// Used to control how the specified item is aligned within the space it's given.
799/// - For Flexbox items, this property has no effect. See `justify_content` for main axis alignment of flex items.
800/// - For CSS Grid items, controls inline (horizontal) axis alignment of a grid item within its grid area.
801///
802/// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self>
803#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
804#[reflect(Default, PartialEq, Clone)]
805#[cfg_attr(
806    feature = "serialize",
807    derive(serde::Serialize, serde::Deserialize),
808    reflect(Serialize, Deserialize)
809)]
810pub enum JustifySelf {
811    /// Use the parent node's [`JustifyItems`] value to determine how this item should be aligned.
812    Auto,
813    /// This item will be aligned with the start of the axis.
814    Start,
815    /// This item will be aligned with the end of the axis.
816    End,
817    /// This item will be aligned along the center of the axis.
818    Center,
819    /// This item will be aligned at the baseline.
820    Baseline,
821    /// This item will be stretched to fill the space it's given.
822    Stretch,
823}
824
825impl JustifySelf {
826    pub const DEFAULT: Self = Self::Auto;
827}
828
829impl Default for JustifySelf {
830    fn default() -> Self {
831        Self::DEFAULT
832    }
833}
834
835/// Used to control how items are distributed.
836/// - For Flexbox containers, controls alignment of lines if `flex_wrap` is set to [`FlexWrap::Wrap`] and there are multiple lines of items.
837/// - For CSS Grid containers, controls alignment of grid rows.
838///
839/// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-content>
840#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
841#[reflect(Default, PartialEq, Clone)]
842#[cfg_attr(
843    feature = "serialize",
844    derive(serde::Serialize, serde::Deserialize),
845    reflect(Serialize, Deserialize)
846)]
847pub enum AlignContent {
848    /// The items are packed in their default position as if no alignment was applied.
849    Default,
850    /// The items are packed towards the start of the axis.
851    Start,
852    /// The items are packed towards the end of the axis.
853    End,
854    /// The items are packed towards the start of the axis, unless the flex direction is reversed;
855    /// then the items are packed towards the end of the axis.
856    FlexStart,
857    /// The items are packed towards the end of the axis, unless the flex direction is reversed;
858    /// then the items are packed towards the start of the axis.
859    FlexEnd,
860    /// The items are packed along the center of the axis.
861    Center,
862    /// The items are stretched to fill the container along the axis.
863    Stretch,
864    /// The items are distributed such that the gap between any two items is equal.
865    SpaceBetween,
866    /// The items are distributed such that the gap between and around any two items is equal.
867    SpaceEvenly,
868    /// The items are distributed such that the gap between and around any two items is equal, with half-size gaps on either end.
869    SpaceAround,
870}
871
872impl AlignContent {
873    pub const DEFAULT: Self = Self::Default;
874}
875
876impl Default for AlignContent {
877    fn default() -> Self {
878        Self::DEFAULT
879    }
880}
881
882/// Used to control how items are distributed.
883/// - For Flexbox containers, controls alignment of items in the main axis.
884/// - For CSS Grid containers, controls alignment of grid columns.
885///
886/// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content>
887#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
888#[reflect(Default, PartialEq, Clone)]
889#[cfg_attr(
890    feature = "serialize",
891    derive(serde::Serialize, serde::Deserialize),
892    reflect(Serialize, Deserialize)
893)]
894pub enum JustifyContent {
895    /// The items are packed in their default position as if no alignment was applied.
896    Default,
897    /// The items are packed towards the start of the axis.
898    Start,
899    /// The items are packed towards the end of the axis.
900    End,
901    /// The items are packed towards the start of the axis, unless the flex direction is reversed;
902    /// then the items are packed towards the end of the axis.
903    FlexStart,
904    /// The items are packed towards the end of the axis, unless the flex direction is reversed;
905    /// then the items are packed towards the start of the axis.
906    FlexEnd,
907    /// The items are packed along the center of the axis.
908    Center,
909    /// The items are stretched to fill the container along the axis.
910    Stretch,
911    /// The items are distributed such that the gap between any two items is equal.
912    SpaceBetween,
913    /// The items are distributed such that the gap between and around any two items is equal.
914    SpaceEvenly,
915    /// The items are distributed such that the gap between and around any two items is equal, with half-size gaps on either end.
916    SpaceAround,
917}
918
919impl JustifyContent {
920    pub const DEFAULT: Self = Self::Default;
921}
922
923impl Default for JustifyContent {
924    fn default() -> Self {
925        Self::DEFAULT
926    }
927}
928
929/// Defines the layout model used by this node.
930///
931/// Part of the [`Node`] component.
932#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
933#[reflect(Default, PartialEq, Clone)]
934#[cfg_attr(
935    feature = "serialize",
936    derive(serde::Serialize, serde::Deserialize),
937    reflect(Serialize, Deserialize)
938)]
939pub enum Display {
940    /// Use Flexbox layout model to determine the position of this [`Node`]'s children.
941    Flex,
942    /// Use CSS Grid layout model to determine the position of this [`Node`]'s children.
943    Grid,
944    /// Use CSS Block layout model to determine the position of this [`Node`]'s children.
945    Block,
946    /// Use no layout, don't render this node and its children.
947    ///
948    /// If you want to hide a node and its children,
949    /// but keep its layout in place, set its [`Visibility`] component instead.
950    None,
951}
952
953impl Display {
954    pub const DEFAULT: Self = Self::Flex;
955}
956
957impl Default for Display {
958    fn default() -> Self {
959        Self::DEFAULT
960    }
961}
962
963/// Which part of a Node's box length styles like width and height control
964///
965/// See: <https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing>
966#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
967#[reflect(Default, PartialEq, Clone)]
968#[cfg_attr(
969    feature = "serialize",
970    derive(serde::Serialize, serde::Deserialize),
971    reflect(Serialize, Deserialize)
972)]
973pub enum BoxSizing {
974    /// Length styles like width and height refer to the "border box" size (size including padding and border)
975    BorderBox,
976    /// Length styles like width and height refer to the "content box" size (size excluding padding and border)
977    ContentBox,
978}
979impl BoxSizing {
980    pub const DEFAULT: Self = Self::BorderBox;
981}
982impl Default for BoxSizing {
983    fn default() -> Self {
984        Self::DEFAULT
985    }
986}
987
988/// Defines how flexbox items are ordered within a flexbox
989#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
990#[reflect(Default, PartialEq, Clone)]
991#[cfg_attr(
992    feature = "serialize",
993    derive(serde::Serialize, serde::Deserialize),
994    reflect(Serialize, Deserialize)
995)]
996pub enum FlexDirection {
997    /// Same way as text direction along the main axis.
998    Row,
999    /// Flex from top to bottom.
1000    Column,
1001    /// Opposite way as text direction along the main axis.
1002    RowReverse,
1003    /// Flex from bottom to top.
1004    ColumnReverse,
1005}
1006
1007impl FlexDirection {
1008    pub const DEFAULT: Self = Self::Row;
1009}
1010
1011impl Default for FlexDirection {
1012    fn default() -> Self {
1013        Self::DEFAULT
1014    }
1015}
1016
1017/// Whether to show or hide overflowing items
1018#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
1019#[reflect(Default, PartialEq, Clone)]
1020#[cfg_attr(
1021    feature = "serialize",
1022    derive(serde::Serialize, serde::Deserialize),
1023    reflect(Serialize, Deserialize)
1024)]
1025pub struct Overflow {
1026    /// Whether to show or clip overflowing items on the x axis
1027    pub x: OverflowAxis,
1028    /// Whether to show or clip overflowing items on the y axis
1029    pub y: OverflowAxis,
1030}
1031
1032impl Overflow {
1033    pub const DEFAULT: Self = Self {
1034        x: OverflowAxis::DEFAULT,
1035        y: OverflowAxis::DEFAULT,
1036    };
1037
1038    /// Show overflowing items on both axes
1039    pub const fn visible() -> Self {
1040        Self {
1041            x: OverflowAxis::Visible,
1042            y: OverflowAxis::Visible,
1043        }
1044    }
1045
1046    /// Clip overflowing items on both axes
1047    pub const fn clip() -> Self {
1048        Self {
1049            x: OverflowAxis::Clip,
1050            y: OverflowAxis::Clip,
1051        }
1052    }
1053
1054    /// Clip overflowing items on the x axis
1055    pub const fn clip_x() -> Self {
1056        Self {
1057            x: OverflowAxis::Clip,
1058            y: OverflowAxis::Visible,
1059        }
1060    }
1061
1062    /// Clip overflowing items on the y axis
1063    pub const fn clip_y() -> Self {
1064        Self {
1065            x: OverflowAxis::Visible,
1066            y: OverflowAxis::Clip,
1067        }
1068    }
1069
1070    /// Hide overflowing items on both axes by influencing layout and then clipping
1071    pub const fn hidden() -> Self {
1072        Self {
1073            x: OverflowAxis::Hidden,
1074            y: OverflowAxis::Hidden,
1075        }
1076    }
1077
1078    /// Hide overflowing items on the x axis by influencing layout and then clipping
1079    pub const fn hidden_x() -> Self {
1080        Self {
1081            x: OverflowAxis::Hidden,
1082            y: OverflowAxis::Visible,
1083        }
1084    }
1085
1086    /// Hide overflowing items on the y axis by influencing layout and then clipping
1087    pub const fn hidden_y() -> Self {
1088        Self {
1089            x: OverflowAxis::Visible,
1090            y: OverflowAxis::Hidden,
1091        }
1092    }
1093
1094    /// Overflow is visible on both axes
1095    pub const fn is_visible(&self) -> bool {
1096        self.x.is_visible() && self.y.is_visible()
1097    }
1098
1099    pub const fn scroll() -> Self {
1100        Self {
1101            x: OverflowAxis::Scroll,
1102            y: OverflowAxis::Scroll,
1103        }
1104    }
1105
1106    /// Scroll overflowing items on the x axis
1107    pub const fn scroll_x() -> Self {
1108        Self {
1109            x: OverflowAxis::Scroll,
1110            y: OverflowAxis::Visible,
1111        }
1112    }
1113
1114    /// Scroll overflowing items on the y axis
1115    pub const fn scroll_y() -> Self {
1116        Self {
1117            x: OverflowAxis::Visible,
1118            y: OverflowAxis::Scroll,
1119        }
1120    }
1121}
1122
1123impl Default for Overflow {
1124    fn default() -> Self {
1125        Self::DEFAULT
1126    }
1127}
1128
1129/// Whether to show or hide overflowing items
1130#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
1131#[reflect(Default, PartialEq, Clone)]
1132#[cfg_attr(
1133    feature = "serialize",
1134    derive(serde::Serialize, serde::Deserialize),
1135    reflect(Serialize, Deserialize)
1136)]
1137pub enum OverflowAxis {
1138    /// Show overflowing items.
1139    Visible,
1140    /// Hide overflowing items by clipping.
1141    Clip,
1142    /// Hide overflowing items by influencing layout and then clipping.
1143    Hidden,
1144    /// Scroll overflowing items.
1145    Scroll,
1146}
1147
1148impl OverflowAxis {
1149    pub const DEFAULT: Self = Self::Visible;
1150
1151    /// Overflow is visible on this axis
1152    pub const fn is_visible(&self) -> bool {
1153        matches!(self, Self::Visible)
1154    }
1155}
1156
1157impl Default for OverflowAxis {
1158    fn default() -> Self {
1159        Self::DEFAULT
1160    }
1161}
1162
1163/// The bounds of the visible area when a UI node is clipped.
1164#[derive(Default, Copy, Clone, PartialEq, Debug, Reflect)]
1165#[reflect(Default, PartialEq, Clone)]
1166#[cfg_attr(
1167    feature = "serialize",
1168    derive(serde::Serialize, serde::Deserialize),
1169    reflect(Serialize, Deserialize)
1170)]
1171pub struct OverflowClipMargin {
1172    /// Visible unclipped area
1173    pub visual_box: OverflowClipBox,
1174    /// Width of the margin on each edge of the visual box in logical pixels.
1175    /// The width of the margin will be zero if a negative value is set.
1176    pub margin: f32,
1177}
1178
1179impl OverflowClipMargin {
1180    pub const DEFAULT: Self = Self {
1181        visual_box: OverflowClipBox::ContentBox,
1182        margin: 0.,
1183    };
1184
1185    /// Clip any content that overflows outside the content box
1186    pub const fn content_box() -> Self {
1187        Self {
1188            visual_box: OverflowClipBox::ContentBox,
1189            ..Self::DEFAULT
1190        }
1191    }
1192
1193    /// Clip any content that overflows outside the padding box
1194    pub const fn padding_box() -> Self {
1195        Self {
1196            visual_box: OverflowClipBox::PaddingBox,
1197            ..Self::DEFAULT
1198        }
1199    }
1200
1201    /// Clip any content that overflows outside the border box
1202    pub const fn border_box() -> Self {
1203        Self {
1204            visual_box: OverflowClipBox::BorderBox,
1205            ..Self::DEFAULT
1206        }
1207    }
1208
1209    /// Add a margin on each edge of the visual box in logical pixels.
1210    /// The width of the margin will be zero if a negative value is set.
1211    pub const fn with_margin(mut self, margin: f32) -> Self {
1212        self.margin = margin;
1213        self
1214    }
1215}
1216
1217/// Used to determine the bounds of the visible area when a UI node is clipped.
1218#[derive(Default, Copy, Clone, PartialEq, Eq, Debug, Reflect)]
1219#[reflect(Default, PartialEq, Clone)]
1220#[cfg_attr(
1221    feature = "serialize",
1222    derive(serde::Serialize, serde::Deserialize),
1223    reflect(Serialize, Deserialize)
1224)]
1225pub enum OverflowClipBox {
1226    /// Clip any content that overflows outside the content box
1227    #[default]
1228    ContentBox,
1229    /// Clip any content that overflows outside the padding box
1230    PaddingBox,
1231    /// Clip any content that overflows outside the border box
1232    BorderBox,
1233}
1234
1235/// The strategy used to position this node
1236#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
1237#[reflect(Default, PartialEq, Clone)]
1238#[cfg_attr(
1239    feature = "serialize",
1240    derive(serde::Serialize, serde::Deserialize),
1241    reflect(Serialize, Deserialize)
1242)]
1243pub enum PositionType {
1244    /// Relative to all other nodes with the [`PositionType::Relative`] value.
1245    Relative,
1246    /// Independent of all other nodes, but relative to its parent node.
1247    Absolute,
1248}
1249
1250impl PositionType {
1251    pub const DEFAULT: Self = Self::Relative;
1252}
1253
1254impl Default for PositionType {
1255    fn default() -> Self {
1256        Self::DEFAULT
1257    }
1258}
1259
1260/// Defines if flexbox items appear on a single line or on multiple lines
1261#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
1262#[reflect(Default, PartialEq, Clone)]
1263#[cfg_attr(
1264    feature = "serialize",
1265    derive(serde::Serialize, serde::Deserialize),
1266    reflect(Serialize, Deserialize)
1267)]
1268pub enum FlexWrap {
1269    /// Single line, will overflow if needed.
1270    NoWrap,
1271    /// Multiple lines, if needed.
1272    Wrap,
1273    /// Same as [`FlexWrap::Wrap`] but new lines will appear before the previous one.
1274    WrapReverse,
1275}
1276
1277impl FlexWrap {
1278    pub const DEFAULT: Self = Self::NoWrap;
1279}
1280
1281impl Default for FlexWrap {
1282    fn default() -> Self {
1283        Self::DEFAULT
1284    }
1285}
1286
1287/// Controls whether grid items are placed row-wise or column-wise as well as whether the sparse or dense packing algorithm is used.
1288///
1289/// The "dense" packing algorithm attempts to fill in holes earlier in the grid, if smaller items come up later.
1290/// This may cause items to appear out-of-order when doing so would fill in holes left by larger items.
1291///
1292/// Defaults to [`GridAutoFlow::Row`].
1293///
1294/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow>
1295#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
1296#[reflect(Default, PartialEq, Clone)]
1297#[cfg_attr(
1298    feature = "serialize",
1299    derive(serde::Serialize, serde::Deserialize),
1300    reflect(Serialize, Deserialize)
1301)]
1302pub enum GridAutoFlow {
1303    /// Items are placed by filling each row in turn, adding new rows as necessary.
1304    Row,
1305    /// Items are placed by filling each column in turn, adding new columns as necessary.
1306    Column,
1307    /// Combines `Row` with the dense packing algorithm.
1308    RowDense,
1309    /// Combines `Column` with the dense packing algorithm.
1310    ColumnDense,
1311}
1312
1313impl GridAutoFlow {
1314    pub const DEFAULT: Self = Self::Row;
1315}
1316
1317impl Default for GridAutoFlow {
1318    fn default() -> Self {
1319        Self::DEFAULT
1320    }
1321}
1322
1323#[derive(Default, Copy, Clone, PartialEq, Debug, Reflect)]
1324#[reflect(Default, PartialEq, Clone)]
1325#[cfg_attr(
1326    feature = "serialize",
1327    derive(serde::Serialize, serde::Deserialize),
1328    reflect(Serialize, Deserialize)
1329)]
1330pub enum MinTrackSizingFunction {
1331    /// Track minimum size should be a fixed pixel value
1332    Px(f32),
1333    /// Track minimum size should be a percentage value
1334    Percent(f32),
1335    /// Track minimum size should be content sized under a min-content constraint
1336    MinContent,
1337    /// Track minimum size should be content sized under a max-content constraint
1338    MaxContent,
1339    /// Track minimum size should be automatically sized
1340    #[default]
1341    Auto,
1342    /// Track minimum size should be a percent of the viewport's smaller dimension.
1343    VMin(f32),
1344    /// Track minimum size should be a percent of the viewport's larger dimension.
1345    VMax(f32),
1346    /// Track minimum size should be a percent of the viewport's height dimension.
1347    Vh(f32),
1348    /// Track minimum size should be a percent of the viewport's width dimension.
1349    Vw(f32),
1350}
1351
1352#[derive(Default, Copy, Clone, PartialEq, Debug, Reflect)]
1353#[reflect(Default, PartialEq, Clone)]
1354#[cfg_attr(
1355    feature = "serialize",
1356    derive(serde::Serialize, serde::Deserialize),
1357    reflect(Serialize, Deserialize)
1358)]
1359pub enum MaxTrackSizingFunction {
1360    /// Track maximum size should be a fixed pixel value
1361    Px(f32),
1362    /// Track maximum size should be a percentage value
1363    Percent(f32),
1364    /// Track maximum size should be content sized under a min-content constraint
1365    MinContent,
1366    /// Track maximum size should be content sized under a max-content constraint
1367    MaxContent,
1368    /// Track maximum size should be sized according to the fit-content formula with a fixed pixel limit
1369    FitContentPx(f32),
1370    /// Track maximum size should be sized according to the fit-content formula with a percentage limit
1371    FitContentPercent(f32),
1372    /// Track maximum size should be automatically sized
1373    #[default]
1374    Auto,
1375    /// The dimension as a fraction of the total available grid space (`fr` units in CSS)
1376    /// Specified value is the numerator of the fraction. Denominator is the sum of all fractions specified in that grid dimension.
1377    ///
1378    /// Spec: <https://www.w3.org/TR/css3-grid-layout/#fr-unit>
1379    Fraction(f32),
1380    /// Track maximum size should be a percent of the viewport's smaller dimension.
1381    VMin(f32),
1382    /// Track maximum size should be a percent of the viewport's smaller dimension.
1383    VMax(f32),
1384    /// Track maximum size should be a percent of the viewport's height dimension.
1385    Vh(f32),
1386    /// Track maximum size should be a percent of the viewport's width dimension.
1387    Vw(f32),
1388}
1389
1390/// A [`GridTrack`] is a Row or Column of a CSS Grid. This struct specifies what size the track should be.
1391/// See below for the different "track sizing functions" you can specify.
1392#[derive(Copy, Clone, PartialEq, Debug, Reflect)]
1393#[reflect(Default, PartialEq, Clone)]
1394#[cfg_attr(
1395    feature = "serialize",
1396    derive(serde::Serialize, serde::Deserialize),
1397    reflect(Serialize, Deserialize)
1398)]
1399pub struct GridTrack {
1400    pub(crate) min_sizing_function: MinTrackSizingFunction,
1401    pub(crate) max_sizing_function: MaxTrackSizingFunction,
1402}
1403
1404impl GridTrack {
1405    pub const DEFAULT: Self = Self {
1406        min_sizing_function: MinTrackSizingFunction::Auto,
1407        max_sizing_function: MaxTrackSizingFunction::Auto,
1408    };
1409
1410    /// Create a grid track with a fixed pixel size
1411    pub fn px<T: From<Self>>(value: f32) -> T {
1412        Self {
1413            min_sizing_function: MinTrackSizingFunction::Px(value),
1414            max_sizing_function: MaxTrackSizingFunction::Px(value),
1415        }
1416        .into()
1417    }
1418
1419    /// Create a grid track with a percentage size
1420    pub fn percent<T: From<Self>>(value: f32) -> T {
1421        Self {
1422            min_sizing_function: MinTrackSizingFunction::Percent(value),
1423            max_sizing_function: MaxTrackSizingFunction::Percent(value),
1424        }
1425        .into()
1426    }
1427
1428    /// Create a grid track with an `fr` size.
1429    /// Note that this will give the track a content-based minimum size.
1430    /// Usually you are best off using `GridTrack::flex` instead which uses a zero minimum size.
1431    pub fn fr<T: From<Self>>(value: f32) -> T {
1432        Self {
1433            min_sizing_function: MinTrackSizingFunction::Auto,
1434            max_sizing_function: MaxTrackSizingFunction::Fraction(value),
1435        }
1436        .into()
1437    }
1438
1439    /// Create a grid track with a `minmax(0, Nfr)` size.
1440    pub fn flex<T: From<Self>>(value: f32) -> T {
1441        Self {
1442            min_sizing_function: MinTrackSizingFunction::Px(0.0),
1443            max_sizing_function: MaxTrackSizingFunction::Fraction(value),
1444        }
1445        .into()
1446    }
1447
1448    /// Create a grid track which is automatically sized to fit its contents.
1449    pub fn auto<T: From<Self>>() -> T {
1450        Self {
1451            min_sizing_function: MinTrackSizingFunction::Auto,
1452            max_sizing_function: MaxTrackSizingFunction::Auto,
1453        }
1454        .into()
1455    }
1456
1457    /// Create a grid track which is automatically sized to fit its contents when sized at their "min-content" sizes
1458    pub fn min_content<T: From<Self>>() -> T {
1459        Self {
1460            min_sizing_function: MinTrackSizingFunction::MinContent,
1461            max_sizing_function: MaxTrackSizingFunction::MinContent,
1462        }
1463        .into()
1464    }
1465
1466    /// Create a grid track which is automatically sized to fit its contents when sized at their "max-content" sizes
1467    pub fn max_content<T: From<Self>>() -> T {
1468        Self {
1469            min_sizing_function: MinTrackSizingFunction::MaxContent,
1470            max_sizing_function: MaxTrackSizingFunction::MaxContent,
1471        }
1472        .into()
1473    }
1474
1475    /// Create a `fit-content()` grid track with fixed pixel limit.
1476    ///
1477    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/fit-content_function>
1478    pub fn fit_content_px<T: From<Self>>(limit: f32) -> T {
1479        Self {
1480            min_sizing_function: MinTrackSizingFunction::Auto,
1481            max_sizing_function: MaxTrackSizingFunction::FitContentPx(limit),
1482        }
1483        .into()
1484    }
1485
1486    /// Create a `fit-content()` grid track with percentage limit.
1487    ///
1488    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/fit-content_function>
1489    pub fn fit_content_percent<T: From<Self>>(limit: f32) -> T {
1490        Self {
1491            min_sizing_function: MinTrackSizingFunction::Auto,
1492            max_sizing_function: MaxTrackSizingFunction::FitContentPercent(limit),
1493        }
1494        .into()
1495    }
1496
1497    /// Create a `minmax()` grid track.
1498    ///
1499    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/minmax>
1500    pub fn minmax<T: From<Self>>(min: MinTrackSizingFunction, max: MaxTrackSizingFunction) -> T {
1501        Self {
1502            min_sizing_function: min,
1503            max_sizing_function: max,
1504        }
1505        .into()
1506    }
1507
1508    /// Create a grid track with a percentage of the viewport's smaller dimension
1509    pub fn vmin<T: From<Self>>(value: f32) -> T {
1510        Self {
1511            min_sizing_function: MinTrackSizingFunction::VMin(value),
1512            max_sizing_function: MaxTrackSizingFunction::VMin(value),
1513        }
1514        .into()
1515    }
1516
1517    /// Create a grid track with a percentage of the viewport's larger dimension
1518    pub fn vmax<T: From<Self>>(value: f32) -> T {
1519        Self {
1520            min_sizing_function: MinTrackSizingFunction::VMax(value),
1521            max_sizing_function: MaxTrackSizingFunction::VMax(value),
1522        }
1523        .into()
1524    }
1525
1526    /// Create a grid track with a percentage of the viewport's height dimension
1527    pub fn vh<T: From<Self>>(value: f32) -> T {
1528        Self {
1529            min_sizing_function: MinTrackSizingFunction::Vh(value),
1530            max_sizing_function: MaxTrackSizingFunction::Vh(value),
1531        }
1532        .into()
1533    }
1534
1535    /// Create a grid track with a percentage of the viewport's width dimension
1536    pub fn vw<T: From<Self>>(value: f32) -> T {
1537        Self {
1538            min_sizing_function: MinTrackSizingFunction::Vw(value),
1539            max_sizing_function: MaxTrackSizingFunction::Vw(value),
1540        }
1541        .into()
1542    }
1543}
1544
1545impl Default for GridTrack {
1546    fn default() -> Self {
1547        Self::DEFAULT
1548    }
1549}
1550
1551#[derive(Copy, Clone, PartialEq, Debug, Reflect, From)]
1552#[reflect(Default, PartialEq, Clone)]
1553#[cfg_attr(
1554    feature = "serialize",
1555    derive(serde::Serialize, serde::Deserialize),
1556    reflect(Serialize, Deserialize)
1557)]
1558/// How many times to repeat a repeated grid track
1559///
1560/// <https://developer.mozilla.org/en-US/docs/Web/CSS/repeat>
1561pub enum GridTrackRepetition {
1562    /// Repeat the track fixed number of times
1563    Count(u16),
1564    /// Repeat the track to fill available space
1565    ///
1566    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fill>
1567    AutoFill,
1568    /// Repeat the track to fill available space but collapse any tracks that do not end up with
1569    /// an item placed in them.
1570    ///
1571    /// <https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fit>
1572    AutoFit,
1573}
1574
1575impl Default for GridTrackRepetition {
1576    fn default() -> Self {
1577        Self::Count(1)
1578    }
1579}
1580
1581impl From<i32> for GridTrackRepetition {
1582    fn from(count: i32) -> Self {
1583        Self::Count(count as u16)
1584    }
1585}
1586
1587impl From<usize> for GridTrackRepetition {
1588    fn from(count: usize) -> Self {
1589        Self::Count(count as u16)
1590    }
1591}
1592
1593/// Represents a *possibly* repeated [`GridTrack`].
1594///
1595/// The repetition parameter can either be:
1596///   - The integer `1`, in which case the track is non-repeated.
1597///   - a `u16` count to repeat the track N times.
1598///   - A `GridTrackRepetition::AutoFit` or `GridTrackRepetition::AutoFill`.
1599///
1600/// Note: that in the common case you want a non-repeating track (repetition count 1), you may use the constructor methods on [`GridTrack`]
1601/// to create a `RepeatedGridTrack`. i.e. `GridTrack::px(10.0)` is equivalent to `RepeatedGridTrack::px(1, 10.0)`.
1602///
1603/// You may only use one auto-repetition per track list. And if your track list contains an auto repetition
1604/// then all tracks (in and outside of the repetition) must be fixed size (px or percent). Integer repetitions are just shorthand for writing out
1605/// N tracks longhand and are not subject to the same limitations.
1606#[derive(Clone, PartialEq, Debug, Reflect)]
1607#[reflect(Default, PartialEq, Clone)]
1608#[cfg_attr(
1609    feature = "serialize",
1610    derive(serde::Serialize, serde::Deserialize),
1611    reflect(Serialize, Deserialize)
1612)]
1613pub struct RepeatedGridTrack {
1614    pub(crate) repetition: GridTrackRepetition,
1615    pub(crate) tracks: SmallVec<[GridTrack; 1]>,
1616}
1617
1618impl RepeatedGridTrack {
1619    /// Create a repeating set of grid tracks with a fixed pixel size
1620    pub fn px<T: From<Self>>(repetition: impl Into<GridTrackRepetition>, value: f32) -> T {
1621        Self {
1622            repetition: repetition.into(),
1623            tracks: SmallVec::from_buf([GridTrack::px(value)]),
1624        }
1625        .into()
1626    }
1627
1628    /// Create a repeating set of grid tracks with a percentage size
1629    pub fn percent<T: From<Self>>(repetition: impl Into<GridTrackRepetition>, value: f32) -> T {
1630        Self {
1631            repetition: repetition.into(),
1632            tracks: SmallVec::from_buf([GridTrack::percent(value)]),
1633        }
1634        .into()
1635    }
1636
1637    /// Create a repeating set of grid tracks with automatic size
1638    pub fn auto<T: From<Self>>(repetition: u16) -> T {
1639        Self {
1640            repetition: GridTrackRepetition::Count(repetition),
1641            tracks: SmallVec::from_buf([GridTrack::auto()]),
1642        }
1643        .into()
1644    }
1645
1646    /// Create a repeating set of grid tracks with an `fr` size.
1647    /// Note that this will give the track a content-based minimum size.
1648    /// Usually you are best off using `GridTrack::flex` instead which uses a zero minimum size.
1649    pub fn fr<T: From<Self>>(repetition: u16, value: f32) -> T {
1650        Self {
1651            repetition: GridTrackRepetition::Count(repetition),
1652            tracks: SmallVec::from_buf([GridTrack::fr(value)]),
1653        }
1654        .into()
1655    }
1656
1657    /// Create a repeating set of grid tracks with a `minmax(0, Nfr)` size.
1658    pub fn flex<T: From<Self>>(repetition: u16, value: f32) -> T {
1659        Self {
1660            repetition: GridTrackRepetition::Count(repetition),
1661            tracks: SmallVec::from_buf([GridTrack::flex(value)]),
1662        }
1663        .into()
1664    }
1665
1666    /// Create a repeating set of grid tracks with min-content size
1667    pub fn min_content<T: From<Self>>(repetition: u16) -> T {
1668        Self {
1669            repetition: GridTrackRepetition::Count(repetition),
1670            tracks: SmallVec::from_buf([GridTrack::min_content()]),
1671        }
1672        .into()
1673    }
1674
1675    /// Create a repeating set of grid tracks with max-content size
1676    pub fn max_content<T: From<Self>>(repetition: u16) -> T {
1677        Self {
1678            repetition: GridTrackRepetition::Count(repetition),
1679            tracks: SmallVec::from_buf([GridTrack::max_content()]),
1680        }
1681        .into()
1682    }
1683
1684    /// Create a repeating set of `fit-content()` grid tracks with fixed pixel limit
1685    pub fn fit_content_px<T: From<Self>>(repetition: u16, limit: f32) -> T {
1686        Self {
1687            repetition: GridTrackRepetition::Count(repetition),
1688            tracks: SmallVec::from_buf([GridTrack::fit_content_px(limit)]),
1689        }
1690        .into()
1691    }
1692
1693    /// Create a repeating set of `fit-content()` grid tracks with percentage limit
1694    pub fn fit_content_percent<T: From<Self>>(repetition: u16, limit: f32) -> T {
1695        Self {
1696            repetition: GridTrackRepetition::Count(repetition),
1697            tracks: SmallVec::from_buf([GridTrack::fit_content_percent(limit)]),
1698        }
1699        .into()
1700    }
1701
1702    /// Create a repeating set of `minmax()` grid track
1703    pub fn minmax<T: From<Self>>(
1704        repetition: impl Into<GridTrackRepetition>,
1705        min: MinTrackSizingFunction,
1706        max: MaxTrackSizingFunction,
1707    ) -> T {
1708        Self {
1709            repetition: repetition.into(),
1710            tracks: SmallVec::from_buf([GridTrack::minmax(min, max)]),
1711        }
1712        .into()
1713    }
1714
1715    /// Create a repeating set of grid tracks with the percentage size of the viewport's smaller dimension
1716    pub fn vmin<T: From<Self>>(repetition: impl Into<GridTrackRepetition>, value: f32) -> T {
1717        Self {
1718            repetition: repetition.into(),
1719            tracks: SmallVec::from_buf([GridTrack::vmin(value)]),
1720        }
1721        .into()
1722    }
1723
1724    /// Create a repeating set of grid tracks with the percentage size of the viewport's larger dimension
1725    pub fn vmax<T: From<Self>>(repetition: impl Into<GridTrackRepetition>, value: f32) -> T {
1726        Self {
1727            repetition: repetition.into(),
1728            tracks: SmallVec::from_buf([GridTrack::vmax(value)]),
1729        }
1730        .into()
1731    }
1732
1733    /// Create a repeating set of grid tracks with the percentage size of the viewport's height dimension
1734    pub fn vh<T: From<Self>>(repetition: impl Into<GridTrackRepetition>, value: f32) -> T {
1735        Self {
1736            repetition: repetition.into(),
1737            tracks: SmallVec::from_buf([GridTrack::vh(value)]),
1738        }
1739        .into()
1740    }
1741
1742    /// Create a repeating set of grid tracks with the percentage size of the viewport's width dimension
1743    pub fn vw<T: From<Self>>(repetition: impl Into<GridTrackRepetition>, value: f32) -> T {
1744        Self {
1745            repetition: repetition.into(),
1746            tracks: SmallVec::from_buf([GridTrack::vw(value)]),
1747        }
1748        .into()
1749    }
1750
1751    /// Create a repetition of a set of tracks
1752    pub fn repeat_many<T: From<Self>>(
1753        repetition: impl Into<GridTrackRepetition>,
1754        tracks: impl Into<Vec<GridTrack>>,
1755    ) -> T {
1756        Self {
1757            repetition: repetition.into(),
1758            tracks: SmallVec::from_vec(tracks.into()),
1759        }
1760        .into()
1761    }
1762}
1763
1764impl Default for RepeatedGridTrack {
1765    fn default() -> Self {
1766        Self {
1767            repetition: Default::default(),
1768            tracks: SmallVec::from_buf([GridTrack::default()]),
1769        }
1770    }
1771}
1772
1773impl From<GridTrack> for RepeatedGridTrack {
1774    fn from(track: GridTrack) -> Self {
1775        Self {
1776            repetition: GridTrackRepetition::Count(1),
1777            tracks: SmallVec::from_buf([track]),
1778        }
1779    }
1780}
1781
1782impl From<GridTrack> for Vec<GridTrack> {
1783    fn from(track: GridTrack) -> Self {
1784        vec![track]
1785    }
1786}
1787
1788impl From<GridTrack> for Vec<RepeatedGridTrack> {
1789    fn from(track: GridTrack) -> Self {
1790        vec![RepeatedGridTrack {
1791            repetition: GridTrackRepetition::Count(1),
1792            tracks: SmallVec::from_buf([track]),
1793        }]
1794    }
1795}
1796
1797impl From<RepeatedGridTrack> for Vec<RepeatedGridTrack> {
1798    fn from(track: RepeatedGridTrack) -> Self {
1799        vec![track]
1800    }
1801}
1802
1803#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
1804#[reflect(Default, PartialEq, Clone)]
1805#[cfg_attr(
1806    feature = "serialize",
1807    derive(serde::Serialize, serde::Deserialize),
1808    reflect(Serialize, Deserialize)
1809)]
1810/// Represents the position of a grid item in a single axis.
1811///
1812/// There are 3 fields which may be set:
1813///   - `start`: which grid line the item should start at
1814///   - `end`: which grid line the item should end at
1815///   - `span`: how many tracks the item should span
1816///
1817/// The default `span` is 1. If neither `start` or `end` is set then the item will be placed automatically.
1818///
1819/// Generally, at most two fields should be set. If all three fields are specified then `span` will be ignored. If `end` specifies an earlier
1820/// grid line than `start` then `end` will be ignored and the item will have a span of 1.
1821///
1822/// <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Line-based_Placement_with_CSS_Grid>
1823pub struct GridPlacement {
1824    /// The grid line at which the item should start.
1825    /// Lines are 1-indexed.
1826    /// Negative indexes count backwards from the end of the grid.
1827    /// Zero is not a valid index.
1828    pub(crate) start: Option<NonZero<i16>>,
1829    /// How many grid tracks the item should span.
1830    /// Defaults to 1.
1831    pub(crate) span: Option<NonZero<u16>>,
1832    /// The grid line at which the item should end.
1833    /// Lines are 1-indexed.
1834    /// Negative indexes count backwards from the end of the grid.
1835    /// Zero is not a valid index.
1836    pub(crate) end: Option<NonZero<i16>>,
1837}
1838
1839impl GridPlacement {
1840    pub const DEFAULT: Self = Self {
1841        start: None,
1842        span: NonZero::<u16>::new(1),
1843        end: None,
1844    };
1845
1846    /// Place the grid item automatically (letting the `span` default to `1`).
1847    pub fn auto() -> Self {
1848        Self::DEFAULT
1849    }
1850
1851    /// Place the grid item automatically, specifying how many tracks it should `span`.
1852    ///
1853    /// # Panics
1854    ///
1855    /// Panics if `span` is `0`.
1856    pub fn span(span: u16) -> Self {
1857        Self {
1858            start: None,
1859            end: None,
1860            span: try_into_grid_span(span).expect("Invalid span value of 0."),
1861        }
1862    }
1863
1864    /// Place the grid item specifying the `start` grid line (letting the `span` default to `1`).
1865    ///
1866    /// # Panics
1867    ///
1868    /// Panics if `start` is `0`.
1869    pub fn start(start: i16) -> Self {
1870        Self {
1871            start: try_into_grid_index(start).expect("Invalid start value of 0."),
1872            ..Self::DEFAULT
1873        }
1874    }
1875
1876    /// Place the grid item specifying the `end` grid line (letting the `span` default to `1`).
1877    ///
1878    /// # Panics
1879    ///
1880    /// Panics if `end` is `0`.
1881    pub fn end(end: i16) -> Self {
1882        Self {
1883            end: try_into_grid_index(end).expect("Invalid end value of 0."),
1884            ..Self::DEFAULT
1885        }
1886    }
1887
1888    /// Place the grid item specifying the `start` grid line and how many tracks it should `span`.
1889    ///
1890    /// # Panics
1891    ///
1892    /// Panics if `start` or `span` is `0`.
1893    pub fn start_span(start: i16, span: u16) -> Self {
1894        Self {
1895            start: try_into_grid_index(start).expect("Invalid start value of 0."),
1896            end: None,
1897            span: try_into_grid_span(span).expect("Invalid span value of 0."),
1898        }
1899    }
1900
1901    /// Place the grid item specifying `start` and `end` grid lines (`span` will be inferred)
1902    ///
1903    /// # Panics
1904    ///
1905    /// Panics if `start` or `end` is `0`.
1906    pub fn start_end(start: i16, end: i16) -> Self {
1907        Self {
1908            start: try_into_grid_index(start).expect("Invalid start value of 0."),
1909            end: try_into_grid_index(end).expect("Invalid end value of 0."),
1910            span: None,
1911        }
1912    }
1913
1914    /// Place the grid item specifying the `end` grid line and how many tracks it should `span`.
1915    ///
1916    /// # Panics
1917    ///
1918    /// Panics if `end` or `span` is `0`.
1919    pub fn end_span(end: i16, span: u16) -> Self {
1920        Self {
1921            start: None,
1922            end: try_into_grid_index(end).expect("Invalid end value of 0."),
1923            span: try_into_grid_span(span).expect("Invalid span value of 0."),
1924        }
1925    }
1926
1927    /// Mutate the item, setting the `start` grid line
1928    ///
1929    /// # Panics
1930    ///
1931    /// Panics if `start` is `0`.
1932    pub fn set_start(mut self, start: i16) -> Self {
1933        self.start = try_into_grid_index(start).expect("Invalid start value of 0.");
1934        self
1935    }
1936
1937    /// Mutate the item, setting the `end` grid line
1938    ///
1939    /// # Panics
1940    ///
1941    /// Panics if `end` is `0`.
1942    pub fn set_end(mut self, end: i16) -> Self {
1943        self.end = try_into_grid_index(end).expect("Invalid end value of 0.");
1944        self
1945    }
1946
1947    /// Mutate the item, setting the number of tracks the item should `span`
1948    ///
1949    /// # Panics
1950    ///
1951    /// Panics if `span` is `0`.
1952    pub fn set_span(mut self, span: u16) -> Self {
1953        self.span = try_into_grid_span(span).expect("Invalid span value of 0.");
1954        self
1955    }
1956
1957    /// Returns the grid line at which the item should start, or `None` if not set.
1958    pub fn get_start(self) -> Option<i16> {
1959        self.start.map(NonZero::<i16>::get)
1960    }
1961
1962    /// Returns the grid line at which the item should end, or `None` if not set.
1963    pub fn get_end(self) -> Option<i16> {
1964        self.end.map(NonZero::<i16>::get)
1965    }
1966
1967    /// Returns span for this grid item, or `None` if not set.
1968    pub fn get_span(self) -> Option<u16> {
1969        self.span.map(NonZero::<u16>::get)
1970    }
1971}
1972
1973impl Default for GridPlacement {
1974    fn default() -> Self {
1975        Self::DEFAULT
1976    }
1977}
1978
1979/// Convert an `i16` to `NonZero<i16>`, fails on `0` and returns the `InvalidZeroIndex` error.
1980fn try_into_grid_index(index: i16) -> Result<Option<NonZero<i16>>, GridPlacementError> {
1981    Ok(Some(
1982        NonZero::<i16>::new(index).ok_or(GridPlacementError::InvalidZeroIndex)?,
1983    ))
1984}
1985
1986/// Convert a `u16` to `NonZero<u16>`, fails on `0` and returns the `InvalidZeroSpan` error.
1987fn try_into_grid_span(span: u16) -> Result<Option<NonZero<u16>>, GridPlacementError> {
1988    Ok(Some(
1989        NonZero::<u16>::new(span).ok_or(GridPlacementError::InvalidZeroSpan)?,
1990    ))
1991}
1992
1993/// Errors that occur when setting constraints for a `GridPlacement`
1994#[derive(Debug, Eq, PartialEq, Clone, Copy, Error)]
1995pub enum GridPlacementError {
1996    #[error("Zero is not a valid grid position")]
1997    InvalidZeroIndex,
1998    #[error("Spans cannot be zero length")]
1999    InvalidZeroSpan,
2000}
2001
2002/// The background color of the node
2003///
2004/// This serves as the "fill" color.
2005#[derive(Component, Copy, Clone, Debug, PartialEq, Reflect)]
2006#[reflect(Component, Default, Debug, PartialEq, Clone)]
2007#[cfg_attr(
2008    feature = "serialize",
2009    derive(serde::Serialize, serde::Deserialize),
2010    reflect(Serialize, Deserialize)
2011)]
2012pub struct BackgroundColor(pub Color);
2013
2014impl BackgroundColor {
2015    /// Background color is transparent by default.
2016    pub const DEFAULT: Self = Self(Color::NONE);
2017}
2018
2019impl Default for BackgroundColor {
2020    fn default() -> Self {
2021        Self::DEFAULT
2022    }
2023}
2024
2025impl<T: Into<Color>> From<T> for BackgroundColor {
2026    fn from(color: T) -> Self {
2027        Self(color.into())
2028    }
2029}
2030
2031/// The border color of the UI node.
2032#[derive(Component, Copy, Clone, Debug, PartialEq, Reflect)]
2033#[reflect(Component, Default, Debug, PartialEq, Clone)]
2034#[cfg_attr(
2035    feature = "serialize",
2036    derive(serde::Serialize, serde::Deserialize),
2037    reflect(Serialize, Deserialize)
2038)]
2039pub struct BorderColor(pub Color);
2040
2041impl<T: Into<Color>> From<T> for BorderColor {
2042    fn from(color: T) -> Self {
2043        Self(color.into())
2044    }
2045}
2046
2047impl BorderColor {
2048    /// Border color is transparent by default.
2049    pub const DEFAULT: Self = BorderColor(Color::NONE);
2050}
2051
2052impl Default for BorderColor {
2053    fn default() -> Self {
2054        Self::DEFAULT
2055    }
2056}
2057
2058#[derive(Component, Copy, Clone, Default, Debug, PartialEq, Reflect)]
2059#[reflect(Component, Default, Debug, PartialEq, Clone)]
2060#[cfg_attr(
2061    feature = "serialize",
2062    derive(serde::Serialize, serde::Deserialize),
2063    reflect(Serialize, Deserialize)
2064)]
2065/// The [`Outline`] component adds an outline outside the edge of a UI node.
2066/// Outlines do not take up space in the layout.
2067///
2068/// To add an [`Outline`] to a ui node you can spawn a `(Node, Outline)` tuple bundle:
2069/// ```
2070/// # use bevy_ecs::prelude::*;
2071/// # use bevy_ui::prelude::*;
2072/// # use bevy_color::palettes::basic::{RED, BLUE};
2073/// fn setup_ui(mut commands: Commands) {
2074///     commands.spawn((
2075///         Node {
2076///             width: Val::Px(100.),
2077///             height: Val::Px(100.),
2078///             ..Default::default()
2079///         },
2080///         BackgroundColor(BLUE.into()),
2081///         Outline::new(Val::Px(10.), Val::ZERO, RED.into())
2082///     ));
2083/// }
2084/// ```
2085///
2086/// [`Outline`] components can also be added later to existing UI nodes:
2087/// ```
2088/// # use bevy_ecs::prelude::*;
2089/// # use bevy_ui::prelude::*;
2090/// # use bevy_color::Color;
2091/// fn outline_hovered_button_system(
2092///     mut commands: Commands,
2093///     mut node_query: Query<(Entity, &Interaction, Option<&mut Outline>), Changed<Interaction>>,
2094/// ) {
2095///     for (entity, interaction, mut maybe_outline) in node_query.iter_mut() {
2096///         let outline_color =
2097///             if matches!(*interaction, Interaction::Hovered) {
2098///                 Color::WHITE
2099///             } else {
2100///                 Color::NONE
2101///             };
2102///         if let Some(mut outline) = maybe_outline {
2103///             outline.color = outline_color;
2104///         } else {
2105///             commands.entity(entity).insert(Outline::new(Val::Px(10.), Val::ZERO, outline_color));
2106///         }
2107///     }
2108/// }
2109/// ```
2110/// Inserting and removing an [`Outline`] component repeatedly will result in table moves, so it is generally preferable to
2111/// set `Outline::color` to [`Color::NONE`] to hide an outline.
2112pub struct Outline {
2113    /// The width of the outline.
2114    ///
2115    /// Percentage `Val` values are resolved based on the width of the outlined [`Node`].
2116    pub width: Val,
2117    /// The amount of space between a node's outline the edge of the node.
2118    ///
2119    /// Percentage `Val` values are resolved based on the width of the outlined [`Node`].
2120    pub offset: Val,
2121    /// The color of the outline.
2122    ///
2123    /// If you are frequently toggling outlines for a UI node on and off it is recommended to set [`Color::NONE`] to hide the outline.
2124    /// This avoids the table moves that would occur from the repeated insertion and removal of the `Outline` component.
2125    pub color: Color,
2126}
2127
2128impl Outline {
2129    /// Create a new outline
2130    pub const fn new(width: Val, offset: Val, color: Color) -> Self {
2131        Self {
2132            width,
2133            offset,
2134            color,
2135        }
2136    }
2137}
2138
2139/// The calculated clip of the node
2140#[derive(Component, Default, Copy, Clone, Debug, Reflect)]
2141#[reflect(Component, Default, Debug, Clone)]
2142pub struct CalculatedClip {
2143    /// The rect of the clip
2144    pub clip: Rect,
2145}
2146
2147/// Indicates that this [`Node`] entity's front-to-back ordering is not controlled solely
2148/// by its location in the UI hierarchy. A node with a higher z-index will appear on top
2149/// of sibling nodes with a lower z-index.
2150///
2151/// UI nodes that have the same z-index will appear according to the order in which they
2152/// appear in the UI hierarchy. In such a case, the last node to be added to its parent
2153/// will appear in front of its siblings.
2154///
2155/// Nodes without this component will be treated as if they had a value of [`ZIndex(0)`].
2156///
2157/// Use [`GlobalZIndex`] if you need to order separate UI hierarchies or nodes that are
2158/// not siblings in a given UI hierarchy.
2159#[derive(Component, Copy, Clone, Debug, Default, PartialEq, Eq, Reflect)]
2160#[reflect(Component, Default, Debug, PartialEq, Clone)]
2161pub struct ZIndex(pub i32);
2162
2163/// `GlobalZIndex` allows a [`Node`] entity anywhere in the UI hierarchy to escape the implicit draw ordering of the UI's layout tree and
2164/// be rendered above or below other UI nodes.
2165/// Nodes with a `GlobalZIndex` of greater than 0 will be drawn on top of nodes without a `GlobalZIndex` or nodes with a lower `GlobalZIndex`.
2166/// Nodes with a `GlobalZIndex` of less than 0 will be drawn below nodes without a `GlobalZIndex` or nodes with a greater `GlobalZIndex`.
2167///
2168/// If two Nodes have the same `GlobalZIndex`, the node with the greater [`ZIndex`] will be drawn on top.
2169#[derive(Component, Copy, Clone, Debug, Default, PartialEq, Eq, Reflect)]
2170#[reflect(Component, Default, Debug, PartialEq, Clone)]
2171pub struct GlobalZIndex(pub i32);
2172
2173/// Used to add rounded corners to a UI node. You can set a UI node to have uniformly
2174/// rounded corners or specify different radii for each corner. If a given radius exceeds half
2175/// the length of the smallest dimension between the node's height or width, the radius will
2176/// calculated as half the smallest dimension.
2177///
2178/// Elliptical nodes are not supported yet. Percentage values are based on the node's smallest
2179/// dimension, either width or height.
2180///
2181/// # Example
2182/// ```rust
2183/// # use bevy_ecs::prelude::*;
2184/// # use bevy_ui::prelude::*;
2185/// # use bevy_color::palettes::basic::{BLUE};
2186/// fn setup_ui(mut commands: Commands) {
2187///     commands.spawn((
2188///         Node {
2189///             width: Val::Px(100.),
2190///             height: Val::Px(100.),
2191///             border: UiRect::all(Val::Px(2.)),
2192///             ..Default::default()
2193///         },
2194///         BackgroundColor(BLUE.into()),
2195///         BorderRadius::new(
2196///             // top left
2197///             Val::Px(10.),
2198///             // top right
2199///             Val::Px(20.),
2200///             // bottom right
2201///             Val::Px(30.),
2202///             // bottom left
2203///             Val::Px(40.),
2204///         ),
2205///     ));
2206/// }
2207/// ```
2208///
2209/// <https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius>
2210#[derive(Component, Copy, Clone, Debug, PartialEq, Reflect)]
2211#[reflect(Component, PartialEq, Default, Debug, Clone)]
2212#[cfg_attr(
2213    feature = "serialize",
2214    derive(serde::Serialize, serde::Deserialize),
2215    reflect(Serialize, Deserialize)
2216)]
2217pub struct BorderRadius {
2218    pub top_left: Val,
2219    pub top_right: Val,
2220    pub bottom_left: Val,
2221    pub bottom_right: Val,
2222}
2223
2224impl Default for BorderRadius {
2225    fn default() -> Self {
2226        Self::DEFAULT
2227    }
2228}
2229
2230impl BorderRadius {
2231    pub const DEFAULT: Self = Self::ZERO;
2232
2233    /// Zero curvature. All the corners will be right-angled.
2234    pub const ZERO: Self = Self::all(Val::Px(0.));
2235
2236    /// Maximum curvature. The UI Node will take a capsule shape or circular if width and height are equal.
2237    pub const MAX: Self = Self::all(Val::Px(f32::MAX));
2238
2239    #[inline]
2240    /// Set all four corners to the same curvature.
2241    pub const fn all(radius: Val) -> Self {
2242        Self {
2243            top_left: radius,
2244            top_right: radius,
2245            bottom_left: radius,
2246            bottom_right: radius,
2247        }
2248    }
2249
2250    #[inline]
2251    pub const fn new(top_left: Val, top_right: Val, bottom_right: Val, bottom_left: Val) -> Self {
2252        Self {
2253            top_left,
2254            top_right,
2255            bottom_right,
2256            bottom_left,
2257        }
2258    }
2259
2260    #[inline]
2261    /// Sets the radii to logical pixel values.
2262    pub const fn px(top_left: f32, top_right: f32, bottom_right: f32, bottom_left: f32) -> Self {
2263        Self {
2264            top_left: Val::Px(top_left),
2265            top_right: Val::Px(top_right),
2266            bottom_right: Val::Px(bottom_right),
2267            bottom_left: Val::Px(bottom_left),
2268        }
2269    }
2270
2271    #[inline]
2272    /// Sets the radii to percentage values.
2273    pub const fn percent(
2274        top_left: f32,
2275        top_right: f32,
2276        bottom_right: f32,
2277        bottom_left: f32,
2278    ) -> Self {
2279        Self {
2280            top_left: Val::Percent(top_left),
2281            top_right: Val::Percent(top_right),
2282            bottom_right: Val::Percent(bottom_right),
2283            bottom_left: Val::Percent(bottom_left),
2284        }
2285    }
2286
2287    #[inline]
2288    /// Sets the radius for the top left corner.
2289    /// Remaining corners will be right-angled.
2290    pub const fn top_left(radius: Val) -> Self {
2291        Self {
2292            top_left: radius,
2293            ..Self::DEFAULT
2294        }
2295    }
2296
2297    #[inline]
2298    /// Sets the radius for the top right corner.
2299    /// Remaining corners will be right-angled.
2300    pub const fn top_right(radius: Val) -> Self {
2301        Self {
2302            top_right: radius,
2303            ..Self::DEFAULT
2304        }
2305    }
2306
2307    #[inline]
2308    /// Sets the radius for the bottom right corner.
2309    /// Remaining corners will be right-angled.
2310    pub const fn bottom_right(radius: Val) -> Self {
2311        Self {
2312            bottom_right: radius,
2313            ..Self::DEFAULT
2314        }
2315    }
2316
2317    #[inline]
2318    /// Sets the radius for the bottom left corner.
2319    /// Remaining corners will be right-angled.
2320    pub const fn bottom_left(radius: Val) -> Self {
2321        Self {
2322            bottom_left: radius,
2323            ..Self::DEFAULT
2324        }
2325    }
2326
2327    #[inline]
2328    /// Sets the radii for the top left and bottom left corners.
2329    /// Remaining corners will be right-angled.
2330    pub const fn left(radius: Val) -> Self {
2331        Self {
2332            top_left: radius,
2333            bottom_left: radius,
2334            ..Self::DEFAULT
2335        }
2336    }
2337
2338    #[inline]
2339    /// Sets the radii for the top right and bottom right corners.
2340    /// Remaining corners will be right-angled.
2341    pub const fn right(radius: Val) -> Self {
2342        Self {
2343            top_right: radius,
2344            bottom_right: radius,
2345            ..Self::DEFAULT
2346        }
2347    }
2348
2349    #[inline]
2350    /// Sets the radii for the top left and top right corners.
2351    /// Remaining corners will be right-angled.
2352    pub const fn top(radius: Val) -> Self {
2353        Self {
2354            top_left: radius,
2355            top_right: radius,
2356            ..Self::DEFAULT
2357        }
2358    }
2359
2360    #[inline]
2361    /// Sets the radii for the bottom left and bottom right corners.
2362    /// Remaining corners will be right-angled.
2363    pub const fn bottom(radius: Val) -> Self {
2364        Self {
2365            bottom_left: radius,
2366            bottom_right: radius,
2367            ..Self::DEFAULT
2368        }
2369    }
2370
2371    /// Returns the [`BorderRadius`] with its `top_left` field set to the given value.
2372    #[inline]
2373    pub const fn with_top_left(mut self, radius: Val) -> Self {
2374        self.top_left = radius;
2375        self
2376    }
2377
2378    /// Returns the [`BorderRadius`] with its `top_right` field set to the given value.
2379    #[inline]
2380    pub const fn with_top_right(mut self, radius: Val) -> Self {
2381        self.top_right = radius;
2382        self
2383    }
2384
2385    /// Returns the [`BorderRadius`] with its `bottom_right` field set to the given value.
2386    #[inline]
2387    pub const fn with_bottom_right(mut self, radius: Val) -> Self {
2388        self.bottom_right = radius;
2389        self
2390    }
2391
2392    /// Returns the [`BorderRadius`] with its `bottom_left` field set to the given value.
2393    #[inline]
2394    pub const fn with_bottom_left(mut self, radius: Val) -> Self {
2395        self.bottom_left = radius;
2396        self
2397    }
2398
2399    /// Returns the [`BorderRadius`] with its `top_left` and `bottom_left` fields set to the given value.
2400    #[inline]
2401    pub const fn with_left(mut self, radius: Val) -> Self {
2402        self.top_left = radius;
2403        self.bottom_left = radius;
2404        self
2405    }
2406
2407    /// Returns the [`BorderRadius`] with its `top_right` and `bottom_right` fields set to the given value.
2408    #[inline]
2409    pub const fn with_right(mut self, radius: Val) -> Self {
2410        self.top_right = radius;
2411        self.bottom_right = radius;
2412        self
2413    }
2414
2415    /// Returns the [`BorderRadius`] with its `top_left` and `top_right` fields set to the given value.
2416    #[inline]
2417    pub const fn with_top(mut self, radius: Val) -> Self {
2418        self.top_left = radius;
2419        self.top_right = radius;
2420        self
2421    }
2422
2423    /// Returns the [`BorderRadius`] with its `bottom_left` and `bottom_right` fields set to the given value.
2424    #[inline]
2425    pub const fn with_bottom(mut self, radius: Val) -> Self {
2426        self.bottom_left = radius;
2427        self.bottom_right = radius;
2428        self
2429    }
2430
2431    /// Resolve the border radius for a single corner from the given context values.
2432    /// Returns the radius of the corner in physical pixels.
2433    pub fn resolve_single_corner(
2434        radius: Val,
2435        node_size: Vec2,
2436        viewport_size: Vec2,
2437        scale_factor: f32,
2438    ) -> f32 {
2439        match radius {
2440            Val::Auto => 0.,
2441            Val::Px(px) => px * scale_factor,
2442            Val::Percent(percent) => node_size.min_element() * percent / 100.,
2443            Val::Vw(percent) => viewport_size.x * percent / 100.,
2444            Val::Vh(percent) => viewport_size.y * percent / 100.,
2445            Val::VMin(percent) => viewport_size.min_element() * percent / 100.,
2446            Val::VMax(percent) => viewport_size.max_element() * percent / 100.,
2447        }
2448        .clamp(0., 0.5 * node_size.min_element())
2449    }
2450
2451    /// Resolve the border radii for the corners from the given context values.
2452    /// Returns the radii of the each corner in physical pixels.
2453    pub fn resolve(
2454        &self,
2455        node_size: Vec2,
2456        viewport_size: Vec2,
2457        scale_factor: f32,
2458    ) -> ResolvedBorderRadius {
2459        ResolvedBorderRadius {
2460            top_left: Self::resolve_single_corner(
2461                self.top_left,
2462                node_size,
2463                viewport_size,
2464                scale_factor,
2465            ),
2466            top_right: Self::resolve_single_corner(
2467                self.top_right,
2468                node_size,
2469                viewport_size,
2470                scale_factor,
2471            ),
2472            bottom_left: Self::resolve_single_corner(
2473                self.bottom_left,
2474                node_size,
2475                viewport_size,
2476                scale_factor,
2477            ),
2478            bottom_right: Self::resolve_single_corner(
2479                self.bottom_right,
2480                node_size,
2481                viewport_size,
2482                scale_factor,
2483            ),
2484        }
2485    }
2486}
2487
2488/// Represents the resolved border radius values for a UI node.
2489///
2490/// The values are in physical pixels.
2491#[derive(Copy, Clone, Debug, Default, PartialEq, Reflect)]
2492#[reflect(Clone, PartialEq, Default)]
2493pub struct ResolvedBorderRadius {
2494    pub top_left: f32,
2495    pub top_right: f32,
2496    pub bottom_left: f32,
2497    pub bottom_right: f32,
2498}
2499
2500impl ResolvedBorderRadius {
2501    pub const ZERO: Self = Self {
2502        top_left: 0.,
2503        top_right: 0.,
2504        bottom_left: 0.,
2505        bottom_right: 0.,
2506    };
2507}
2508
2509#[derive(Component, Clone, Debug, Default, PartialEq, Reflect, Deref, DerefMut)]
2510#[reflect(Component, PartialEq, Default, Clone)]
2511#[cfg_attr(
2512    feature = "serialize",
2513    derive(serde::Serialize, serde::Deserialize),
2514    reflect(Serialize, Deserialize)
2515)]
2516/// List of shadows to draw for a [`Node`].
2517///
2518/// Draw order is determined implicitly from the vector of [`ShadowStyle`]s, back-to-front.
2519pub struct BoxShadow(pub Vec<ShadowStyle>);
2520
2521impl BoxShadow {
2522    /// A single drop shadow
2523    pub fn new(
2524        color: Color,
2525        x_offset: Val,
2526        y_offset: Val,
2527        spread_radius: Val,
2528        blur_radius: Val,
2529    ) -> Self {
2530        Self(vec![ShadowStyle {
2531            color,
2532            x_offset,
2533            y_offset,
2534            spread_radius,
2535            blur_radius,
2536        }])
2537    }
2538}
2539
2540impl From<ShadowStyle> for BoxShadow {
2541    fn from(value: ShadowStyle) -> Self {
2542        Self(vec![value])
2543    }
2544}
2545
2546#[derive(Copy, Clone, Debug, PartialEq, Reflect)]
2547#[reflect(PartialEq, Default, Clone)]
2548#[cfg_attr(
2549    feature = "serialize",
2550    derive(serde::Serialize, serde::Deserialize),
2551    reflect(Serialize, Deserialize)
2552)]
2553pub struct ShadowStyle {
2554    /// The shadow's color
2555    pub color: Color,
2556    /// Horizontal offset
2557    pub x_offset: Val,
2558    /// Vertical offset
2559    pub y_offset: Val,
2560    /// How much the shadow should spread outward.
2561    ///
2562    /// Negative values will make the shadow shrink inwards.
2563    /// Percentage values are based on the width of the UI node.
2564    pub spread_radius: Val,
2565    /// Blurriness of the shadow
2566    pub blur_radius: Val,
2567}
2568
2569impl Default for ShadowStyle {
2570    fn default() -> Self {
2571        Self {
2572            color: Color::BLACK,
2573            x_offset: Val::Percent(20.),
2574            y_offset: Val::Percent(20.),
2575            spread_radius: Val::ZERO,
2576            blur_radius: Val::Percent(10.),
2577        }
2578    }
2579}
2580
2581#[derive(Component, Copy, Clone, Debug, PartialEq, Reflect)]
2582#[reflect(Component, Debug, PartialEq, Default, Clone)]
2583#[cfg_attr(
2584    feature = "serialize",
2585    derive(serde::Serialize, serde::Deserialize),
2586    reflect(Serialize, Deserialize)
2587)]
2588/// This component can be added to any UI node to modify its layout behavior.
2589pub struct LayoutConfig {
2590    /// If set to true the coordinates for this node and its descendents will be rounded to the nearest physical pixel.
2591    /// This can help prevent visual artifacts like blurry images or semi-transparent edges that can occur with sub-pixel positioning.
2592    ///
2593    /// Defaults to true.
2594    pub use_rounding: bool,
2595}
2596
2597impl Default for LayoutConfig {
2598    fn default() -> Self {
2599        Self { use_rounding: true }
2600    }
2601}
2602
2603#[cfg(test)]
2604mod tests {
2605    use crate::GridPlacement;
2606
2607    #[test]
2608    fn invalid_grid_placement_values() {
2609        assert!(std::panic::catch_unwind(|| GridPlacement::span(0)).is_err());
2610        assert!(std::panic::catch_unwind(|| GridPlacement::start(0)).is_err());
2611        assert!(std::panic::catch_unwind(|| GridPlacement::end(0)).is_err());
2612        assert!(std::panic::catch_unwind(|| GridPlacement::start_end(0, 1)).is_err());
2613        assert!(std::panic::catch_unwind(|| GridPlacement::start_end(-1, 0)).is_err());
2614        assert!(std::panic::catch_unwind(|| GridPlacement::start_span(1, 0)).is_err());
2615        assert!(std::panic::catch_unwind(|| GridPlacement::start_span(0, 1)).is_err());
2616        assert!(std::panic::catch_unwind(|| GridPlacement::end_span(0, 1)).is_err());
2617        assert!(std::panic::catch_unwind(|| GridPlacement::end_span(1, 0)).is_err());
2618        assert!(std::panic::catch_unwind(|| GridPlacement::default().set_start(0)).is_err());
2619        assert!(std::panic::catch_unwind(|| GridPlacement::default().set_end(0)).is_err());
2620        assert!(std::panic::catch_unwind(|| GridPlacement::default().set_span(0)).is_err());
2621    }
2622
2623    #[test]
2624    fn grid_placement_accessors() {
2625        assert_eq!(GridPlacement::start(5).get_start(), Some(5));
2626        assert_eq!(GridPlacement::end(-4).get_end(), Some(-4));
2627        assert_eq!(GridPlacement::span(2).get_span(), Some(2));
2628        assert_eq!(GridPlacement::start_end(11, 21).get_span(), None);
2629        assert_eq!(GridPlacement::start_span(3, 5).get_end(), None);
2630        assert_eq!(GridPlacement::end_span(-4, 12).get_start(), None);
2631    }
2632}
2633
2634/// Indicates that this root [`Node`] entity should be rendered to a specific camera.
2635///
2636/// UI then will be laid out respecting the camera's viewport and scale factor, and
2637/// rendered to this camera's [`bevy_render::camera::RenderTarget`].
2638///
2639/// Setting this component on a non-root node will have no effect. It will be overridden
2640/// by the root node's component.
2641///
2642/// Root node's without an explicit [`UiTargetCamera`] will be rendered to the default UI camera,
2643/// which is either a single camera with the [`IsDefaultUiCamera`] marker component or the highest
2644/// order camera targeting the primary window.
2645#[derive(Component, Clone, Debug, Reflect, Eq, PartialEq)]
2646#[reflect(Component, Debug, PartialEq, Clone)]
2647pub struct UiTargetCamera(pub Entity);
2648
2649impl UiTargetCamera {
2650    pub fn entity(&self) -> Entity {
2651        self.0
2652    }
2653}
2654
2655/// Marker used to identify default cameras, they will have priority over the [`PrimaryWindow`] camera.
2656///
2657/// This is useful if the [`PrimaryWindow`] has two cameras, one of them used
2658/// just for debug purposes and the user wants a way to choose the default [`Camera`]
2659/// without having to add a [`UiTargetCamera`] to the root node.
2660///
2661/// Another use is when the user wants the Ui to be in another window by default,
2662/// all that is needed is to place this component on the camera
2663///
2664/// ```
2665/// # use bevy_ui::prelude::*;
2666/// # use bevy_ecs::prelude::Commands;
2667/// # use bevy_render::camera::{Camera, RenderTarget};
2668/// # use bevy_core_pipeline::prelude::Camera2d;
2669/// # use bevy_window::{Window, WindowRef};
2670///
2671/// fn spawn_camera(mut commands: Commands) {
2672///     let another_window = commands.spawn(Window {
2673///         title: String::from("Another window"),
2674///         ..Default::default()
2675///     }).id();
2676///     commands.spawn((
2677///         Camera2d,
2678///         Camera {
2679///             target: RenderTarget::Window(WindowRef::Entity(another_window)),
2680///             ..Default::default()
2681///         },
2682///         // We add the Marker here so all Ui will spawn in
2683///         // another window if no UiTargetCamera is specified
2684///         IsDefaultUiCamera
2685///     ));
2686/// }
2687/// ```
2688#[derive(Component, Default)]
2689pub struct IsDefaultUiCamera;
2690
2691#[derive(SystemParam)]
2692pub struct DefaultUiCamera<'w, 's> {
2693    cameras: Query<'w, 's, (Entity, &'static Camera)>,
2694    default_cameras: Query<'w, 's, Entity, (With<Camera>, With<IsDefaultUiCamera>)>,
2695    primary_window: Query<'w, 's, Entity, With<PrimaryWindow>>,
2696}
2697
2698impl<'w, 's> DefaultUiCamera<'w, 's> {
2699    pub fn get(&self) -> Option<Entity> {
2700        self.default_cameras.single().ok().or_else(|| {
2701            // If there isn't a single camera and the query isn't empty, there is two or more cameras queried.
2702            if !self.default_cameras.is_empty() {
2703                once!(warn!("Two or more Entities with IsDefaultUiCamera found when only one Camera with this marker is allowed."));
2704            }
2705            self.cameras
2706                .iter()
2707                .filter(|(_, c)| match c.target {
2708                    RenderTarget::Window(WindowRef::Primary) => true,
2709                    RenderTarget::Window(WindowRef::Entity(w)) => {
2710                        self.primary_window.get(w).is_ok()
2711                    }
2712                    _ => false,
2713                })
2714                .max_by_key(|(e, c)| (c.order, *e))
2715                .map(|(e, _)| e)
2716        })
2717    }
2718}
2719
2720/// Marker for controlling whether Ui is rendered with or without anti-aliasing
2721/// in a camera. By default, Ui is always anti-aliased.
2722///
2723/// **Note:** This does not affect text anti-aliasing. For that, use the `font_smoothing` property of the [`TextFont`](bevy_text::TextFont) component.
2724///
2725/// ```
2726/// use bevy_core_pipeline::prelude::*;
2727/// use bevy_ecs::prelude::*;
2728/// use bevy_ui::prelude::*;
2729///
2730/// fn spawn_camera(mut commands: Commands) {
2731///     commands.spawn((
2732///         Camera2d,
2733///         // This will cause all Ui in this camera to be rendered without
2734///         // anti-aliasing
2735///         UiAntiAlias::Off,
2736///     ));
2737/// }
2738/// ```
2739#[derive(Component, Clone, Copy, Default, Debug, Reflect, Eq, PartialEq)]
2740#[reflect(Component, Default, PartialEq, Clone)]
2741pub enum UiAntiAlias {
2742    /// UI will render with anti-aliasing
2743    #[default]
2744    On,
2745    /// UI will render without anti-aliasing
2746    Off,
2747}
2748
2749/// Number of shadow samples.
2750/// A larger value will result in higher quality shadows.
2751/// Default is 4, values higher than ~10 offer diminishing returns.
2752///
2753/// ```
2754/// use bevy_core_pipeline::prelude::*;
2755/// use bevy_ecs::prelude::*;
2756/// use bevy_ui::prelude::*;
2757///
2758/// fn spawn_camera(mut commands: Commands) {
2759///     commands.spawn((
2760///         Camera2d,
2761///         BoxShadowSamples(6),
2762///     ));
2763/// }
2764/// ```
2765#[derive(Component, Clone, Copy, Debug, Reflect, Eq, PartialEq)]
2766#[reflect(Component, Default, PartialEq, Clone)]
2767pub struct BoxShadowSamples(pub u32);
2768
2769impl Default for BoxShadowSamples {
2770    fn default() -> Self {
2771        Self(4)
2772    }
2773}
2774
2775/// Derived information about the camera target for this UI node.
2776#[derive(Component, Clone, Copy, Debug, Reflect, PartialEq)]
2777#[reflect(Component, Default, PartialEq, Clone)]
2778pub struct ComputedNodeTarget {
2779    pub(crate) camera: Entity,
2780    pub(crate) scale_factor: f32,
2781    pub(crate) physical_size: UVec2,
2782}
2783
2784impl Default for ComputedNodeTarget {
2785    fn default() -> Self {
2786        Self {
2787            camera: Entity::PLACEHOLDER,
2788            scale_factor: 1.,
2789            physical_size: UVec2::ZERO,
2790        }
2791    }
2792}
2793
2794impl ComputedNodeTarget {
2795    pub fn camera(&self) -> Option<Entity> {
2796        Some(self.camera).filter(|&entity| entity != Entity::PLACEHOLDER)
2797    }
2798
2799    pub const fn scale_factor(&self) -> f32 {
2800        self.scale_factor
2801    }
2802
2803    pub const fn physical_size(&self) -> UVec2 {
2804        self.physical_size
2805    }
2806
2807    pub fn logical_size(&self) -> Vec2 {
2808        self.physical_size.as_vec2() / self.scale_factor
2809    }
2810}
2811
2812/// Adds a shadow behind text
2813#[derive(Component, Copy, Clone, Debug, Reflect)]
2814#[reflect(Component, Default, Debug, Clone)]
2815pub struct TextShadow {
2816    /// Shadow displacement in logical pixels
2817    /// With a value of zero the shadow will be hidden directly behind the text
2818    pub offset: Vec2,
2819    /// Color of the shadow
2820    pub color: Color,
2821}
2822
2823impl Default for TextShadow {
2824    fn default() -> Self {
2825        Self {
2826            offset: Vec2::splat(4.),
2827            color: Color::linear_rgba(0., 0., 0., 0.75),
2828        }
2829    }
2830}