bevy_ui/
ui_node.rs

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