Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
use crate ::UiRect ;
2021-12-14 03:58:23 +00:00
use bevy_asset ::Handle ;
use bevy_ecs ::{ prelude ::Component , reflect ::ReflectComponent } ;
2022-09-02 12:35:23 +00:00
use bevy_math ::{ Rect , Vec2 } ;
2022-05-03 19:20:13 +00:00
use bevy_reflect ::prelude ::* ;
2023-04-26 12:17:23 +00:00
use bevy_reflect ::ReflectFromReflect ;
2021-12-14 03:58:23 +00:00
use bevy_render ::{
color ::Color ,
texture ::{ Image , DEFAULT_IMAGE_HANDLE } ,
} ;
2023-03-09 14:12:54 +00:00
use bevy_transform ::prelude ::GlobalTransform ;
2020-11-28 00:39:59 +00:00
use serde ::{ Deserialize , Serialize } ;
2023-04-17 16:21:38 +00:00
use smallvec ::SmallVec ;
2022-10-24 14:33:46 +00:00
use std ::ops ::{ Div , DivAssign , Mul , MulAssign } ;
use thiserror ::Error ;
2020-01-13 00:51:21 +00:00
2022-01-07 22:20:34 +00:00
/// Describes the size of a UI node
2023-06-19 16:18:17 +00:00
#[ derive(Component, Debug, Copy, Clone, Reflect, FromReflect) ]
#[ reflect(Component, Default, FromReflect) ]
2020-01-13 00:51:21 +00:00
pub struct Node {
2023-03-04 19:24:56 +00:00
/// The size of the node as width and height in logical pixels
2023-04-17 16:21:38 +00:00
/// automatically calculated by [`super::layout::ui_layout_system`]
2022-10-17 13:27:24 +00:00
pub ( crate ) calculated_size : Vec2 ,
}
impl Node {
2023-03-04 19:24:56 +00:00
/// The calculated node size as width and height in logical pixels
2023-04-17 16:21:38 +00:00
/// automatically calculated by [`super::layout::ui_layout_system`]
2023-05-11 18:38:01 +00:00
pub const fn size ( & self ) -> Vec2 {
2022-10-17 13:27:24 +00:00
self . calculated_size
}
2023-03-09 14:12:54 +00:00
2023-05-11 18:38:01 +00:00
/// Returns the size of the node in physical pixels based on the given scale factor.
#[ inline ]
pub fn physical_size ( & self , scale_factor : f64 ) -> Vec2 {
Vec2 ::new (
( self . calculated_size . x as f64 * scale_factor ) as f32 ,
( self . calculated_size . y as f64 * scale_factor ) as f32 ,
)
}
2023-04-23 17:28:36 +00:00
/// Returns the logical pixel coordinates of the UI node, based on its [`GlobalTransform`].
2023-03-09 14:12:54 +00:00
#[ inline ]
pub fn logical_rect ( & self , transform : & GlobalTransform ) -> Rect {
Rect ::from_center_size ( transform . translation ( ) . truncate ( ) , self . size ( ) )
}
2023-04-23 17:28:36 +00:00
/// Returns the physical pixel coordinates of the UI node, based on its [`GlobalTransform`] and the scale factor.
2023-03-09 14:12:54 +00:00
#[ inline ]
2023-05-11 18:38:01 +00:00
pub fn physical_rect ( & self , transform : & GlobalTransform , scale_factor : f64 ) -> Rect {
2023-03-09 14:12:54 +00:00
let rect = self . logical_rect ( transform ) ;
Rect {
2023-05-11 18:38:01 +00:00
min : Vec2 ::new (
( rect . min . x as f64 * scale_factor ) as f32 ,
( rect . min . y as f64 * scale_factor ) as f32 ,
) ,
max : Vec2 ::new (
( rect . max . x as f64 * scale_factor ) as f32 ,
( rect . max . y as f64 * scale_factor ) as f32 ,
) ,
2023-03-09 14:12:54 +00:00
}
}
2020-01-13 00:51:21 +00:00
}
2020-07-26 19:27:09 +00:00
2023-01-04 19:58:09 +00:00
impl Node {
pub const DEFAULT : Self = Self {
calculated_size : Vec2 ::ZERO ,
} ;
}
impl Default for Node {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2023-03-20 22:51:24 +00:00
/// Represents the possible value types for layout properties.
///
/// This enum allows specifying values for various [`Style`] properties in different units,
/// such as logical pixels, percentages, or automatically determined values.
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum Val {
2023-06-19 14:00:18 +00:00
/// Automatically determine the value based on the context and other [`Style`] properties.
2020-07-26 19:27:09 +00:00
Auto ,
2023-03-20 22:51:24 +00:00
/// Set this value in logical pixels.
2020-07-26 19:27:09 +00:00
Px ( f32 ) ,
2023-03-20 22:51:24 +00:00
/// Set the value as a percentage of its parent node's length along a specific axis.
///
/// If the UI node has no parent, the percentage is calculated based on the window's length
/// along the corresponding axis.
///
/// The chosen axis depends on the `Style` field set:
/// * For `flex_basis`, the percentage is relative to the main-axis length determined by the `flex_direction`.
/// * For `gap`, `min_size`, `size`, and `max_size`:
/// - `width` is relative to the parent's width.
/// - `height` is relative to the parent's height.
/// * For `margin`, `padding`, and `border` values: the percentage is relative to the parent node's width.
/// * For positions, `left` and `right` are relative to the parent's width, while `bottom` and `top` are relative to the parent's height.
2020-07-26 19:27:09 +00:00
Percent ( f32 ) ,
2023-03-21 19:14:27 +00:00
/// Set this value in percent of the viewport width
Vw ( f32 ) ,
/// Set this value in percent of the viewport height
Vh ( f32 ) ,
/// Set this value in percent of the viewport's smaller dimension.
VMin ( f32 ) ,
/// Set this value in percent of the viewport's larger dimension.
VMax ( f32 ) ,
2020-07-26 19:27:09 +00:00
}
2023-01-04 19:58:09 +00:00
impl Val {
2023-03-13 15:17:00 +00:00
pub const DEFAULT : Self = Self ::Auto ;
2023-01-04 19:58:09 +00:00
}
impl Default for Val {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-10-24 14:33:46 +00:00
impl Mul < f32 > for Val {
2020-07-26 19:27:09 +00:00
type Output = Val ;
2020-07-28 21:24:03 +00:00
2022-10-24 14:33:46 +00:00
fn mul ( self , rhs : f32 ) -> Self ::Output {
2020-07-26 19:27:09 +00:00
match self {
Val ::Auto = > Val ::Auto ,
2022-10-24 14:33:46 +00:00
Val ::Px ( value ) = > Val ::Px ( value * rhs ) ,
Val ::Percent ( value ) = > Val ::Percent ( value * rhs ) ,
2023-03-21 19:14:27 +00:00
Val ::Vw ( value ) = > Val ::Vw ( value * rhs ) ,
Val ::Vh ( value ) = > Val ::Vh ( value * rhs ) ,
Val ::VMin ( value ) = > Val ::VMin ( value * rhs ) ,
Val ::VMax ( value ) = > Val ::VMax ( value * rhs ) ,
2020-07-26 19:27:09 +00:00
}
}
}
2022-10-24 14:33:46 +00:00
impl MulAssign < f32 > for Val {
fn mul_assign ( & mut self , rhs : f32 ) {
2020-07-26 19:27:09 +00:00
match self {
2023-03-13 15:17:00 +00:00
Val ::Auto = > { }
2023-03-21 19:14:27 +00:00
Val ::Px ( value )
| Val ::Percent ( value )
| Val ::Vw ( value )
| Val ::Vh ( value )
| Val ::VMin ( value )
| Val ::VMax ( value ) = > * value * = rhs ,
2020-07-26 19:27:09 +00:00
}
}
2020-07-28 04:04:04 +00:00
}
2022-10-24 14:33:46 +00:00
impl Div < f32 > for Val {
2022-08-01 16:27:16 +00:00
type Output = Val ;
2022-10-24 14:33:46 +00:00
fn div ( self , rhs : f32 ) -> Self ::Output {
2022-08-01 16:27:16 +00:00
match self {
Val ::Auto = > Val ::Auto ,
2022-10-24 14:33:46 +00:00
Val ::Px ( value ) = > Val ::Px ( value / rhs ) ,
Val ::Percent ( value ) = > Val ::Percent ( value / rhs ) ,
2023-03-21 19:14:27 +00:00
Val ::Vw ( value ) = > Val ::Vw ( value / rhs ) ,
Val ::Vh ( value ) = > Val ::Vh ( value / rhs ) ,
Val ::VMin ( value ) = > Val ::VMin ( value / rhs ) ,
Val ::VMax ( value ) = > Val ::VMax ( value / rhs ) ,
2022-08-01 16:27:16 +00:00
}
}
}
2022-10-24 14:33:46 +00:00
impl DivAssign < f32 > for Val {
fn div_assign ( & mut self , rhs : f32 ) {
2022-08-01 16:27:16 +00:00
match self {
2023-03-13 15:17:00 +00:00
Val ::Auto = > { }
2023-03-21 19:14:27 +00:00
Val ::Px ( value )
| Val ::Percent ( value )
| Val ::Vw ( value )
| Val ::Vh ( value )
| Val ::VMin ( value )
| Val ::VMax ( value ) = > * value / = rhs ,
2022-08-01 16:27:16 +00:00
}
}
}
2022-10-24 14:33:46 +00:00
#[ derive(Debug, Eq, PartialEq, Clone, Copy, Error) ]
pub enum ValArithmeticError {
#[ error( " the variants of the Vals don't match " ) ]
NonIdenticalVariants ,
#[ error( " the given variant of Val is not evaluateable (non-numeric) " ) ]
NonEvaluateable ,
}
2022-08-01 16:27:16 +00:00
2022-10-24 14:33:46 +00:00
impl Val {
/// Tries to add the values of two [`Val`]s.
/// Returns [`ValArithmeticError::NonIdenticalVariants`] if two [`Val`]s are of different variants.
/// When adding non-numeric [`Val`]s, it returns the value unchanged.
pub fn try_add ( & self , rhs : Val ) -> Result < Val , ValArithmeticError > {
match ( self , rhs ) {
2023-03-13 15:17:00 +00:00
( Val ::Auto , Val ::Auto ) = > Ok ( * self ) ,
2022-10-24 14:33:46 +00:00
( Val ::Px ( value ) , Val ::Px ( rhs_value ) ) = > Ok ( Val ::Px ( value + rhs_value ) ) ,
( Val ::Percent ( value ) , Val ::Percent ( rhs_value ) ) = > Ok ( Val ::Percent ( value + rhs_value ) ) ,
_ = > Err ( ValArithmeticError ::NonIdenticalVariants ) ,
2022-08-01 16:27:16 +00:00
}
}
2022-10-24 14:33:46 +00:00
/// Adds `rhs` to `self` and assigns the result to `self` (see [`Val::try_add`])
pub fn try_add_assign ( & mut self , rhs : Val ) -> Result < ( ) , ValArithmeticError > {
* self = self . try_add ( rhs ) ? ;
Ok ( ( ) )
}
/// Tries to subtract the values of two [`Val`]s.
/// Returns [`ValArithmeticError::NonIdenticalVariants`] if two [`Val`]s are of different variants.
/// When adding non-numeric [`Val`]s, it returns the value unchanged.
pub fn try_sub ( & self , rhs : Val ) -> Result < Val , ValArithmeticError > {
match ( self , rhs ) {
2023-03-13 15:17:00 +00:00
( Val ::Auto , Val ::Auto ) = > Ok ( * self ) ,
2022-10-24 14:33:46 +00:00
( Val ::Px ( value ) , Val ::Px ( rhs_value ) ) = > Ok ( Val ::Px ( value - rhs_value ) ) ,
( Val ::Percent ( value ) , Val ::Percent ( rhs_value ) ) = > Ok ( Val ::Percent ( value - rhs_value ) ) ,
_ = > Err ( ValArithmeticError ::NonIdenticalVariants ) ,
2022-08-01 16:27:16 +00:00
}
}
2022-10-24 14:33:46 +00:00
/// Subtracts `rhs` from `self` and assigns the result to `self` (see [`Val::try_sub`])
pub fn try_sub_assign ( & mut self , rhs : Val ) -> Result < ( ) , ValArithmeticError > {
* self = self . try_sub ( rhs ) ? ;
Ok ( ( ) )
}
2022-08-01 16:27:16 +00:00
2022-10-24 14:33:46 +00:00
/// A convenience function for simple evaluation of [`Val::Percent`] variant into a concrete [`Val::Px`] value.
/// Returns a [`ValArithmeticError::NonEvaluateable`] if the [`Val`] is impossible to evaluate into [`Val::Px`].
/// Otherwise it returns an [`f32`] containing the evaluated value in pixels.
///
2023-01-06 00:43:30 +00:00
/// **Note:** If a [`Val::Px`] is evaluated, it's inner value returned unchanged.
2022-10-24 14:33:46 +00:00
pub fn evaluate ( & self , size : f32 ) -> Result < f32 , ValArithmeticError > {
2022-08-01 16:27:16 +00:00
match self {
2022-10-24 14:33:46 +00:00
Val ::Percent ( value ) = > Ok ( size * value / 100.0 ) ,
Val ::Px ( value ) = > Ok ( * value ) ,
_ = > Err ( ValArithmeticError ::NonEvaluateable ) ,
2022-08-01 16:27:16 +00:00
}
}
2022-10-24 14:33:46 +00:00
/// Similar to [`Val::try_add`], but performs [`Val::evaluate`] on both values before adding.
/// Returns an [`f32`] value in pixels.
pub fn try_add_with_size ( & self , rhs : Val , size : f32 ) -> Result < f32 , ValArithmeticError > {
let lhs = self . evaluate ( size ) ? ;
let rhs = rhs . evaluate ( size ) ? ;
Ok ( lhs + rhs )
}
/// Similar to [`Val::try_add_assign`], but performs [`Val::evaluate`] on both values before adding.
/// The value gets converted to [`Val::Px`].
pub fn try_add_assign_with_size (
& mut self ,
rhs : Val ,
size : f32 ,
) -> Result < ( ) , ValArithmeticError > {
* self = Val ::Px ( self . evaluate ( size ) ? + rhs . evaluate ( size ) ? ) ;
Ok ( ( ) )
}
/// Similar to [`Val::try_sub`], but performs [`Val::evaluate`] on both values before subtracting.
/// Returns an [`f32`] value in pixels.
pub fn try_sub_with_size ( & self , rhs : Val , size : f32 ) -> Result < f32 , ValArithmeticError > {
let lhs = self . evaluate ( size ) ? ;
let rhs = rhs . evaluate ( size ) ? ;
Ok ( lhs - rhs )
}
/// Similar to [`Val::try_sub_assign`], but performs [`Val::evaluate`] on both values before adding.
/// The value gets converted to [`Val::Px`].
pub fn try_sub_assign_with_size (
& mut self ,
rhs : Val ,
size : f32 ,
) -> Result < ( ) , ValArithmeticError > {
* self = Val ::Px ( self . try_add_with_size ( rhs , size ) ? ) ;
Ok ( ( ) )
2022-08-01 16:27:16 +00:00
}
}
2023-04-17 16:21:38 +00:00
/// Describes the style of a UI container node
2022-01-07 22:20:34 +00:00
///
2023-04-17 16:21:38 +00:00
/// Node's can be laid out using either Flexbox or CSS Grid Layout.<br />
/// See below for general learning resources and for documentation on the individual style properties.
///
/// ### Flexbox
///
/// - [MDN: Basic Concepts of Grid Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout)
/// - [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 comphrehensive written explanation of the different Flexbox properties and how they work.
/// - [Flexbox Froggy](https://flexboxfroggy.com/). An interactive tutorial/game that teaches the essential parts of Flebox in a fun engaging way.
///
/// ### CSS Grid
///
/// - [MDN: Basic Concepts of Flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox)
/// - [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 comphrehensive written explanation of the different CSS Grid properties and how they work.
/// - [CSS Grid Garden](https://cssgridgarden.com/). An interactive tutorial/game that teaches the essential parts of CSS Grid in a fun engaging way.
2023-04-26 12:17:23 +00:00
#[ derive(Component, Clone, PartialEq, Debug, Reflect, FromReflect) ]
#[ reflect(Component, FromReflect, Default, PartialEq) ]
2020-07-26 19:27:09 +00:00
pub struct Style {
2023-04-17 16:21:38 +00:00
/// Which layout algorithm to use when laying out this node's contents:
/// - [`Display::Flex`]: Use the Flexbox layout algorithm
/// - [`Display::Grid`]: Use the CSS Grid layout algorithm
/// - [`Display::None`]: Hide this node and perform layout as if it does not exist.
Disable UI node `Interaction` when `ComputedVisibility` is false (#5361)
# Objective
UI nodes can be hidden by setting their `Visibility` property. Since #5310 was merged, this is now ergonomic to use, as visibility is now inherited.
However, UI nodes still receive (and store) interactions when hidden, resulting in surprising hidden state (and an inability to otherwise disable UI nodes.
## Solution
Fixes #5360.
I've updated the `ui_focus_system` to accomplish this in a minimally intrusive way, and updated the docs to match.
**NOTE:** I have not added automated tests to verify this behavior, as we do not currently have a good testing paradigm for `bevy_ui`. I'm not thrilled with that by any means, but I'm not sure fixing it is within scope.
## Paths not taken
### Separate `Disabled` component
This is a much larger and more controversial change, and not well-scoped to UI.
Furthermore, it is extremely rare that you want hidden UI elements to function: the most common cases are for things like changing tabs, collapsing elements or so on.
Splitting this behavior would be more complex, and substantially violate user expectations.
### A separate limbo world
Mentioned in the linked issue. Super cool, but all of the problems of the `Disabled` component solution with a whole new RFC-worth of complexity.
### Using change detection to reduce the amount of redundant work
Adds a lot of complexity for questionable performance gains. Likely involves a complete refactor of the entire system.
We simply don't have the tests or benchmarks here to justify this.
## Changelog
- UI nodes are now always in an `Interaction::None` state while they are hidden (via the `ComputedVisibility` component).
2022-07-20 21:26:47 +00:00
///
2023-04-17 16:21:38 +00:00
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/display>
2020-07-26 19:27:09 +00:00
pub display : Display ,
2023-04-17 16:21:38 +00:00
/// Whether a node should be laid out in-flow with, or independently of it's siblings:
/// - [`PositionType::Relative`]: Layout this node in-flow with other nodes using the usual (flexbox/grid) layout algorithm.
/// - [`PositionType::Absolute`]: Layout this node on top and independently of other nodes.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/position>
2020-07-26 19:27:09 +00:00
pub position_type : PositionType ,
2023-04-17 16:21:38 +00:00
/// Whether overflowing content should be displayed or clipped.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow>
pub overflow : Overflow ,
/// Defines the text direction. For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left).
///
/// Note: the corresponding CSS property also affects box layout order, but this isn't yet implemented in bevy.
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/direction>
pub direction : Direction ,
/// The horizontal position of the left edge of the node.
/// - For relatively positioned nodes, this is relative to the node's position as computed during regular layout.
/// - For absolutely positioned nodes, this is relative to the *parent* node's bounding box.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/left>
2023-03-13 15:17:00 +00:00
pub left : Val ,
2023-04-17 16:21:38 +00:00
/// The horizontal position of the right edge of the node.
/// - For relatively positioned nodes, this is relative to the node's position as computed during regular layout.
/// - For absolutely positioned nodes, this is relative to the *parent* node's bounding box.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/right>
2023-03-13 15:17:00 +00:00
pub right : Val ,
2023-04-17 16:21:38 +00:00
/// The vertical position of the top edge of the node.
/// - For relatively positioned nodes, this is relative to the node's position as computed during regular layout.
/// - For absolutely positioned nodes, this is relative to the *parent* node's bounding box.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/top>
2023-03-13 15:17:00 +00:00
pub top : Val ,
2023-04-17 16:21:38 +00:00
/// The vertical position of the bottom edge of the node.
/// - For relatively positioned nodes, this is relative to the node's position as computed during regular layout.
/// - For absolutely positioned nodes, this is relative to the *parent* node's bounding box.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/bottom>
2023-03-13 15:17:00 +00:00
pub bottom : Val ,
2023-04-17 16:21:38 +00:00
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
/// The ideal width of the node. `width` is used when it is within the bounds defined by `min_width` and `max_width`.
2023-04-17 16:21:38 +00:00
///
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/width>
pub width : Val ,
/// The ideal height of the node. `height` is used when it is within the bounds defined by `min_height` and `max_height`.
2023-04-17 16:21:38 +00:00
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/height>
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
pub height : Val ,
2023-04-17 16:21:38 +00:00
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
/// The minimum width of the node. `min_width` is used if it is greater than either `width` and/or `max_width`.
2023-04-17 16:21:38 +00:00
///
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/min-width>
pub min_width : Val ,
/// The minimum height of the node. `min_height` is used if it is greater than either `height` and/or `max_height`.
2023-04-17 16:21:38 +00:00
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/min-height>
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
pub min_height : Val ,
2023-04-17 16:21:38 +00:00
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
/// The maximum width of the node. `max_width` is used if it is within the bounds defined by `min_width` and `width`.
2023-04-17 16:21:38 +00:00
///
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/max-width>
pub max_width : Val ,
/// The maximum height of the node. `max_height` is used if it is within the bounds defined by `min_height` and `height`.
2023-04-17 16:21:38 +00:00
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/max-height>
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
pub max_height : Val ,
2023-04-17 16:21:38 +00:00
/// The aspect ratio of the node (defined as `width / height`)
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio>
pub aspect_ratio : Option < f32 > ,
/// For Flexbox containers:
/// - Sets default cross-axis alignment of the child items.
/// For CSS Grid containers:
/// - Controls block (vertical) axis alignment of children of this grid container within their grid areas
///
/// This value is overriden [`JustifySelf`] on the child node is set.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>
2020-07-26 19:27:09 +00:00
pub align_items : AlignItems ,
2023-04-17 16:21:38 +00:00
/// For Flexbox containers:
/// - This property has no effect. See `justify_content` for main-axis alignment of flex items.
/// For CSS Grid containers:
/// - Sets default inline (horizontal) axis alignment of child items within their grid areas
///
/// This value is overriden [`JustifySelf`] on the child node is set.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items>
pub justify_items : JustifyItems ,
/// For Flexbox items:
/// - Controls cross-axis alignment of the item.
/// For CSS Grid items:
/// - Controls block (vertical) axis alignment of a grid item within it's grid area
///
/// If set to `Auto`, alignment is inherited from the value of [`AlignItems`] set on the parent node.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-self>
2020-07-26 19:27:09 +00:00
pub align_self : AlignSelf ,
2023-04-17 16:21:38 +00:00
/// For Flexbox items:
/// - This property has no effect. See `justify_content` for main-axis alignment of flex items.
/// For CSS Grid items:
/// - Controls inline (horizontal) axis alignment of a grid item within it's grid area.
///
/// If set to `Auto`, alignment is inherited from the value of [`JustifyItems`] set on the parent node.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items>
pub justify_self : JustifySelf ,
/// For Flexbox containers:
/// - Controls alignment of lines if flex_wrap is set to [`FlexWrap::Wrap`] and there are multiple lines of items
/// For CSS Grid container:
/// - Controls alignment of grid rows
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/align-content>
2020-07-26 19:27:09 +00:00
pub align_content : AlignContent ,
2023-04-17 16:21:38 +00:00
/// For Flexbox containers:
/// - Controls alignment of items in the main axis
/// For CSS Grid containers:
/// - Controls alignment of grid columns
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content>
2020-07-26 19:27:09 +00:00
pub justify_content : JustifyContent ,
2023-04-17 16:21:38 +00:00
2023-02-25 16:38:03 +00:00
/// The amount of space around a node outside its border.
///
/// If a percentage value is used, the percentage is calculated based on the width of the parent node.
///
/// # Example
/// ```
/// # use bevy_ui::{Style, UiRect, Val};
/// let style = Style {
/// margin: UiRect {
/// left: Val::Percent(10.),
/// right: Val::Percent(10.),
/// top: Val::Percent(15.),
/// bottom: Val::Percent(15.)
/// },
/// ..Default::default()
/// };
/// ```
2023-04-17 16:21:38 +00:00
/// 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.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/margin>
2022-08-01 16:27:16 +00:00
pub margin : UiRect ,
2023-04-17 16:21:38 +00:00
2023-02-25 16:38:03 +00:00
/// The amount of space between the edges of a node and its contents.
///
/// If a percentage value is used, the percentage is calculated based on the width of the parent node.
///
/// # Example
/// ```
/// # use bevy_ui::{Style, UiRect, Val};
/// let style = Style {
/// padding: UiRect {
/// left: Val::Percent(1.),
/// right: Val::Percent(2.),
/// top: Val::Percent(3.),
/// bottom: Val::Percent(4.)
/// },
/// ..Default::default()
/// };
/// ```
/// 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.
2023-04-17 16:21:38 +00:00
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/padding>
2022-08-01 16:27:16 +00:00
pub padding : UiRect ,
2023-04-17 16:21:38 +00:00
2023-03-02 17:37:09 +00:00
/// The amount of space between the margins of a node and its padding.
///
/// If a percentage value is used, the percentage is calculated based on the width of the parent node.
///
/// 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.
///
/// Rendering for borders is not yet implemented.
2023-04-17 16:21:38 +00:00
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/border-width>
2022-08-01 16:27:16 +00:00
pub border : UiRect ,
2023-04-17 16:21:38 +00:00
/// Whether a Flexbox container should be a row or a column. This property has no effect of Grid nodes.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction>
pub flex_direction : FlexDirection ,
/// Whether a Flexbox container should wrap it's contents onto multiple line wrap if they overflow. This property has no effect of Grid nodes.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap>
pub flex_wrap : FlexWrap ,
/// Defines how much a flexbox item should grow if there's space available. Defaults to 0 (don't grow at all).
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow>
2020-07-26 19:27:09 +00:00
pub flex_grow : f32 ,
2023-04-17 16:21:38 +00:00
/// Defines how much a flexbox item should shrink if there's not enough space available. Defaults to 1.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-shrink>
2020-07-26 19:27:09 +00:00
pub flex_shrink : f32 ,
2023-04-17 16:21:38 +00:00
/// The initial length of a flexbox in the main axis, before flex growing/shrinking properties are applied.
2023-02-15 13:58:01 +00:00
///
2023-04-17 16:21:38 +00:00
/// `flex_basis` overrides `size` on the main axis if both are set, but it obeys the bounds defined by `min_size` and `max_size`.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis>
2020-07-26 19:27:09 +00:00
pub flex_basis : Val ,
2023-04-17 16:21:38 +00:00
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
/// The size of the gutters between items in a vertical flexbox layout or between rows in a grid layout
///
/// Note: Values of `Val::Auto` are not valid and are treated as zero.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap>
pub row_gap : Val ,
/// The size of the gutters between items in a horizontal flexbox layout or between column in a grid layout
2023-02-10 23:50:28 +00:00
///
2023-04-17 16:21:38 +00:00
/// Note: Values of `Val::Auto` are not valid and are treated as zero.
2023-02-10 23:50:28 +00:00
///
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/column-gap>
pub column_gap : Val ,
2023-04-17 16:21:38 +00:00
/// Controls whether automatically placed grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used.
/// Only affect Grid layouts
2023-02-10 23:50:28 +00:00
///
2023-04-17 16:21:38 +00:00
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow>
pub grid_auto_flow : GridAutoFlow ,
/// 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
/// be implicitly generated by items that are placed out of bounds. The sizes of those rows are controlled by `grid_auto_rows` property.
2022-12-21 02:15:53 +00:00
///
2023-04-17 16:21:38 +00:00
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows>
pub grid_template_rows : Vec < RepeatedGridTrack > ,
/// 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
/// be implicitly generated by items that are placed out of bounds. The sizes of those columns are controlled by `grid_auto_columns` property.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns>
pub grid_template_columns : Vec < RepeatedGridTrack > ,
/// Defines the size of implicitly created rows. Rows are created implicitly when grid items are given explicit placements that are out of bounds
/// of the rows explicitly created using `grid_template_rows`.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-rows>
pub grid_auto_rows : Vec < GridTrack > ,
/// Defines the size of implicitly created columns. Columns are created implicitly when grid items are given explicit placements that are out of bounds
/// of the columns explicitly created using `grid_template_columms`.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns>
pub grid_auto_columns : Vec < GridTrack > ,
/// The row in which a grid item starts and how many rows it spans.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row>
pub grid_row : GridPlacement ,
/// The column in which a grid item starts and how many columns it spans.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column>
pub grid_column : GridPlacement ,
2020-07-26 19:27:09 +00:00
}
2023-01-04 19:58:09 +00:00
impl Style {
pub const DEFAULT : Self = Self {
display : Display ::DEFAULT ,
position_type : PositionType ::DEFAULT ,
2023-03-13 15:17:00 +00:00
left : Val ::Auto ,
right : Val ::Auto ,
top : Val ::Auto ,
bottom : Val ::Auto ,
2023-01-04 19:58:09 +00:00
direction : Direction ::DEFAULT ,
flex_direction : FlexDirection ::DEFAULT ,
flex_wrap : FlexWrap ::DEFAULT ,
align_items : AlignItems ::DEFAULT ,
2023-04-17 16:21:38 +00:00
justify_items : JustifyItems ::DEFAULT ,
2023-01-04 19:58:09 +00:00
align_self : AlignSelf ::DEFAULT ,
2023-04-17 16:21:38 +00:00
justify_self : JustifySelf ::DEFAULT ,
2023-01-04 19:58:09 +00:00
align_content : AlignContent ::DEFAULT ,
justify_content : JustifyContent ::DEFAULT ,
margin : UiRect ::DEFAULT ,
padding : UiRect ::DEFAULT ,
border : UiRect ::DEFAULT ,
flex_grow : 0.0 ,
flex_shrink : 1.0 ,
flex_basis : Val ::Auto ,
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
width : Val ::Auto ,
height : Val ::Auto ,
min_width : Val ::Auto ,
min_height : Val ::Auto ,
max_width : Val ::Auto ,
max_height : Val ::Auto ,
2023-01-04 19:58:09 +00:00
aspect_ratio : None ,
overflow : Overflow ::DEFAULT ,
Flatten UI `Style` properties that use `Size` + remove `Size` (#8548)
# Objective
- Simplify API and make authoring styles easier
See:
https://github.com/bevyengine/bevy/issues/8540#issuecomment-1536177102
## Solution
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by `width`, `height`, `min_width`, `min_height`, `max_width`,
`max_height`, `row_gap`, and `column_gap` properties
---
## Changelog
- Flattened `Style` properties that have a `Size` value directly into
`Style`
## Migration Guide
- The `size`, `min_size`, `max_size`, and `gap` properties have been
replaced by the `width`, `height`, `min_width`, `min_height`,
`max_width`, `max_height`, `row_gap`, and `column_gap` properties. Use
the new properties instead.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-05-16 01:36:32 +00:00
row_gap : Val ::Px ( 0.0 ) ,
column_gap : Val ::Px ( 0.0 ) ,
2023-04-17 16:21:38 +00:00
grid_auto_flow : GridAutoFlow ::DEFAULT ,
grid_template_rows : Vec ::new ( ) ,
grid_template_columns : Vec ::new ( ) ,
grid_auto_rows : Vec ::new ( ) ,
grid_auto_columns : Vec ::new ( ) ,
grid_column : GridPlacement ::DEFAULT ,
grid_row : GridPlacement ::DEFAULT ,
2023-01-04 19:58:09 +00:00
} ;
}
2020-07-26 19:27:09 +00:00
impl Default for Style {
fn default ( ) -> Self {
2023-01-04 19:58:09 +00:00
Self ::DEFAULT
2020-07-26 19:27:09 +00:00
}
}
2022-01-07 22:20:34 +00:00
/// How items are aligned according to the cross axis
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum AlignItems {
2023-04-17 16:21:38 +00:00
/// The items are packed in their default position as if no alignment was applied
Default ,
2023-03-04 14:09:47 +00:00
/// Items are packed towards the start of the axis.
Start ,
/// Items are packed towards the end of the axis.
End ,
/// Items are packed towards the start of the axis, unless the flex direction is reversed;
/// then they are packed towards the end of the axis.
2020-07-26 19:27:09 +00:00
FlexStart ,
2023-03-04 14:09:47 +00:00
/// Items are packed towards the end of the axis, unless the flex direction is reversed;
2023-04-02 00:02:01 +00:00
/// then they are packed towards the start of the axis.
2020-07-26 19:27:09 +00:00
FlexEnd ,
2023-03-04 14:09:47 +00:00
/// Items are aligned at the center.
2020-07-26 19:27:09 +00:00
Center ,
2023-03-04 14:09:47 +00:00
/// Items are aligned at the baseline.
2020-07-26 19:27:09 +00:00
Baseline ,
2023-03-04 14:09:47 +00:00
/// Items are stretched across the whole cross axis.
2020-07-26 19:27:09 +00:00
Stretch ,
}
2023-01-04 19:58:09 +00:00
impl AlignItems {
2023-04-17 16:21:38 +00:00
pub const DEFAULT : Self = Self ::Default ;
2023-01-04 19:58:09 +00:00
}
impl Default for AlignItems {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2023-04-17 16:21:38 +00:00
/// How items are aligned according to the cross axis
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
pub enum JustifyItems {
/// The items are packed in their default position as if no alignment was applied
Default ,
/// Items are packed towards the start of the axis.
Start ,
/// Items are packed towards the end of the axis.
End ,
/// Items are aligned at the center.
Center ,
/// Items are aligned at the baseline.
Baseline ,
/// Items are stretched across the whole cross axis.
Stretch ,
}
impl JustifyItems {
pub const DEFAULT : Self = Self ::Default ;
}
impl Default for JustifyItems {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
Fix the `AlignSelf` documentation (#7577)
# Objective
The current `AlignSelf` doc comments:
```rust
pub enum AlignSelf {
/// Use the value of [`AlignItems`]
Auto,
/// If the parent has [`AlignItems::Center`] only this item will be at the start
FlexStart,
/// If the parent has [`AlignItems::Center`] only this item will be at the end
FlexEnd,
/// If the parent has [`AlignItems::FlexStart`] only this item will be at the center
Center,
/// If the parent has [`AlignItems::Center`] only this item will be at the baseline
Baseline,
/// If the parent has [`AlignItems::Center`] only this item will stretch along the whole cross axis
Stretch,
}
```
Actual behaviour of `AlignSelf` in Bevy main:
<img width="642" alt="align_self" src="https://user-images.githubusercontent.com/27962798/217795178-7a82638f-118d-4474-b7f9-ca27f204731d.PNG">
The white label at the top of each column is the parent node's `AlignItems` setting.
`AlignSelf` is always applied, not (as the documentation states) only when the parent has `AlignItems::Center` or `AlignItems::FlexStart` set.
```rust
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.run();
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2dBundle::default());
commands.spawn(NodeBundle {
style: Style {
justify_content: JustifyContent::SpaceAround,
align_items: AlignItems::Center,
size: Size::new(Val::Percent(100.), Val::Percent(100.)),
..Default::default()
},
background_color: BackgroundColor(Color::NAVY),
..Default::default()
}).with_children(|builder| {
for align_items in [
AlignItems::Baseline,
AlignItems::FlexStart,
AlignItems::Center,
AlignItems::FlexEnd,
AlignItems::Stretch,
] {
builder.spawn(NodeBundle {
style: Style {
align_items,
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::SpaceBetween,
size: Size::new(Val::Px(150.), Val::Px(500.)),
..Default::default()
},
background_color: BackgroundColor(Color::DARK_GRAY),
..Default::default()
}).with_children(|builder| {
builder.spawn((
TextBundle {
text: Text::from_section(
format!("AlignItems::{align_items:?}"),
TextStyle {
font: asset_server.load("fonts/FiraSans-Regular.ttf"),
font_size: 16.0,
color: Color::BLACK,
},
),
style: Style {
align_self: AlignSelf::Stretch,
..Default::default()
},
..Default::default()
},
BackgroundColor(Color::WHITE),
));
for align_self in [
AlignSelf::Auto,
AlignSelf::FlexStart,
AlignSelf::Center,
AlignSelf::FlexEnd,
AlignSelf::Baseline,
AlignSelf::Stretch,
] {
builder.spawn((
TextBundle {
text: Text::from_section(
format!("AlignSelf::{align_self:?}"),
TextStyle {
font: asset_server.load("fonts/FiraSans-Regular.ttf"),
font_size: 16.0,
color: Color::WHITE,
},
),
style: Style {
align_self,
..Default::default()
},
..Default::default()
},
BackgroundColor(Color::BLACK),
));
}
});
}
});
}
```
2023-02-09 20:00:11 +00:00
/// How this item is aligned according to the cross axis.
/// Overrides [`AlignItems`].
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum AlignSelf {
2023-03-04 14:09:47 +00:00
/// Use the parent node's [`AlignItems`] value to determine how this item should be aligned.
2020-07-26 19:27:09 +00:00
Auto ,
2023-03-04 14:09:47 +00:00
/// This item will be aligned with the start of the axis.
Start ,
/// This item will be aligned with the end of the axis.
End ,
/// This item will be aligned with the start of the axis, unless the flex direction is reversed;
/// then it will be aligned with the end of the axis.
2020-07-26 19:27:09 +00:00
FlexStart ,
2023-04-02 00:02:01 +00:00
/// This item will be aligned with the end of the axis, unless the flex direction is reversed;
/// then it will be aligned with the start of the axis.
2020-07-26 19:27:09 +00:00
FlexEnd ,
2023-03-04 14:09:47 +00:00
/// This item will be aligned at the center.
2020-07-26 19:27:09 +00:00
Center ,
2023-03-04 14:09:47 +00:00
/// This item will be aligned at the baseline.
2020-07-26 19:27:09 +00:00
Baseline ,
2023-03-04 14:09:47 +00:00
/// This item will be stretched across the whole cross axis.
2020-07-26 19:27:09 +00:00
Stretch ,
}
2023-01-04 19:58:09 +00:00
impl AlignSelf {
pub const DEFAULT : Self = Self ::Auto ;
}
impl Default for AlignSelf {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2023-04-17 16:21:38 +00:00
/// How this item is aligned according to the cross axis.
/// Overrides [`AlignItems`].
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
pub enum JustifySelf {
/// Use the parent node's [`AlignItems`] value to determine how this item should be aligned.
Auto ,
/// This item will be aligned with the start of the axis.
Start ,
/// This item will be aligned with the end of the axis.
End ,
/// This item will be aligned at the center.
Center ,
/// This item will be aligned at the baseline.
Baseline ,
/// This item will be stretched across the whole cross axis.
Stretch ,
}
impl JustifySelf {
pub const DEFAULT : Self = Self ::Auto ;
}
impl Default for JustifySelf {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-01-07 22:20:34 +00:00
/// Defines how each line is aligned within the flexbox.
///
/// It only applies if [`FlexWrap::Wrap`] is present and if there are multiple lines of items.
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum AlignContent {
2023-04-17 16:21:38 +00:00
/// The items are packed in their default position as if no alignment was applied
Default ,
2023-03-04 14:09:47 +00:00
/// Each line moves towards the start of the cross axis.
Start ,
/// Each line moves towards the end of the cross axis.
End ,
/// Each line moves towards the start of the cross axis, unless the flex direction is reversed; then the line moves towards the end of the cross axis.
2020-07-26 19:27:09 +00:00
FlexStart ,
2023-03-04 14:09:47 +00:00
/// Each line moves towards the end of the cross axis, unless the flex direction is reversed; then the line moves towards the start of the cross axis.
2020-07-26 19:27:09 +00:00
FlexEnd ,
2023-03-04 14:09:47 +00:00
/// Each line moves towards the center of the cross axis.
2020-07-26 19:27:09 +00:00
Center ,
2023-03-04 14:09:47 +00:00
/// Each line will stretch to fill the remaining space.
2020-07-26 19:27:09 +00:00
Stretch ,
2022-01-07 22:20:34 +00:00
/// Each line fills the space it needs, putting the remaining space, if any
2023-03-04 14:09:47 +00:00
/// inbetween the lines.
2020-07-26 19:27:09 +00:00
SpaceBetween ,
2023-03-04 14:09:47 +00:00
/// The gap between the first and last items is exactly THE SAME as the gap between items.
/// The gaps are distributed evenly.
SpaceEvenly ,
2022-01-07 22:20:34 +00:00
/// Each line fills the space it needs, putting the remaining space, if any
2023-03-04 14:09:47 +00:00
/// around the lines.
2020-07-26 19:27:09 +00:00
SpaceAround ,
}
2023-01-04 19:58:09 +00:00
impl AlignContent {
2023-04-17 16:21:38 +00:00
pub const DEFAULT : Self = Self ::Default ;
2023-01-04 19:58:09 +00:00
}
impl Default for AlignContent {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2023-04-17 16:21:38 +00:00
/// Defines how items are aligned according to the main axis
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
pub enum JustifyContent {
/// The items are packed in their default position as if no alignment was applied
Default ,
/// Items are packed toward the start of the axis.
Start ,
/// Items are packed toward the end of the axis.
End ,
/// Pushed towards the start, unless the flex direction is reversed; then pushed towards the end.
FlexStart ,
/// Pushed towards the end, unless the flex direction is reversed; then pushed towards the start.
FlexEnd ,
/// Centered along the main axis.
Center ,
/// Remaining space is distributed between the items.
SpaceBetween ,
/// Remaining space is distributed around the items.
SpaceAround ,
/// Like [`JustifyContent::SpaceAround`] but with even spacing between items.
SpaceEvenly ,
}
impl JustifyContent {
pub const DEFAULT : Self = Self ::Default ;
}
impl Default for JustifyContent {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-01-07 22:20:34 +00:00
/// Defines the text direction
///
/// For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left).
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum Direction {
2023-03-04 14:09:47 +00:00
/// Inherit from parent node.
2020-07-26 19:27:09 +00:00
Inherit ,
2023-03-04 14:09:47 +00:00
/// Text is written left to right.
2021-08-24 01:50:21 +00:00
LeftToRight ,
2023-03-04 14:09:47 +00:00
/// Text is written right to left.
2021-08-24 01:50:21 +00:00
RightToLeft ,
2020-07-26 19:27:09 +00:00
}
2023-01-04 19:58:09 +00:00
impl Direction {
pub const DEFAULT : Self = Self ::Inherit ;
}
impl Default for Direction {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
Disable UI node `Interaction` when `ComputedVisibility` is false (#5361)
# Objective
UI nodes can be hidden by setting their `Visibility` property. Since #5310 was merged, this is now ergonomic to use, as visibility is now inherited.
However, UI nodes still receive (and store) interactions when hidden, resulting in surprising hidden state (and an inability to otherwise disable UI nodes.
## Solution
Fixes #5360.
I've updated the `ui_focus_system` to accomplish this in a minimally intrusive way, and updated the docs to match.
**NOTE:** I have not added automated tests to verify this behavior, as we do not currently have a good testing paradigm for `bevy_ui`. I'm not thrilled with that by any means, but I'm not sure fixing it is within scope.
## Paths not taken
### Separate `Disabled` component
This is a much larger and more controversial change, and not well-scoped to UI.
Furthermore, it is extremely rare that you want hidden UI elements to function: the most common cases are for things like changing tabs, collapsing elements or so on.
Splitting this behavior would be more complex, and substantially violate user expectations.
### A separate limbo world
Mentioned in the linked issue. Super cool, but all of the problems of the `Disabled` component solution with a whole new RFC-worth of complexity.
### Using change detection to reduce the amount of redundant work
Adds a lot of complexity for questionable performance gains. Likely involves a complete refactor of the entire system.
We simply don't have the tests or benchmarks here to justify this.
## Changelog
- UI nodes are now always in an `Interaction::None` state while they are hidden (via the `ComputedVisibility` component).
2022-07-20 21:26:47 +00:00
/// Whether to use a Flexbox layout model.
///
/// Part of the [`Style`] component.
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum Display {
Disable UI node `Interaction` when `ComputedVisibility` is false (#5361)
# Objective
UI nodes can be hidden by setting their `Visibility` property. Since #5310 was merged, this is now ergonomic to use, as visibility is now inherited.
However, UI nodes still receive (and store) interactions when hidden, resulting in surprising hidden state (and an inability to otherwise disable UI nodes.
## Solution
Fixes #5360.
I've updated the `ui_focus_system` to accomplish this in a minimally intrusive way, and updated the docs to match.
**NOTE:** I have not added automated tests to verify this behavior, as we do not currently have a good testing paradigm for `bevy_ui`. I'm not thrilled with that by any means, but I'm not sure fixing it is within scope.
## Paths not taken
### Separate `Disabled` component
This is a much larger and more controversial change, and not well-scoped to UI.
Furthermore, it is extremely rare that you want hidden UI elements to function: the most common cases are for things like changing tabs, collapsing elements or so on.
Splitting this behavior would be more complex, and substantially violate user expectations.
### A separate limbo world
Mentioned in the linked issue. Super cool, but all of the problems of the `Disabled` component solution with a whole new RFC-worth of complexity.
### Using change detection to reduce the amount of redundant work
Adds a lot of complexity for questionable performance gains. Likely involves a complete refactor of the entire system.
We simply don't have the tests or benchmarks here to justify this.
## Changelog
- UI nodes are now always in an `Interaction::None` state while they are hidden (via the `ComputedVisibility` component).
2022-07-20 21:26:47 +00:00
/// Use Flexbox layout model to determine the position of this [`Node`].
2020-07-26 19:27:09 +00:00
Flex ,
2023-04-17 16:21:38 +00:00
/// Use CSS Grid layout model to determine the position of this [`Node`].
Grid ,
Disable UI node `Interaction` when `ComputedVisibility` is false (#5361)
# Objective
UI nodes can be hidden by setting their `Visibility` property. Since #5310 was merged, this is now ergonomic to use, as visibility is now inherited.
However, UI nodes still receive (and store) interactions when hidden, resulting in surprising hidden state (and an inability to otherwise disable UI nodes.
## Solution
Fixes #5360.
I've updated the `ui_focus_system` to accomplish this in a minimally intrusive way, and updated the docs to match.
**NOTE:** I have not added automated tests to verify this behavior, as we do not currently have a good testing paradigm for `bevy_ui`. I'm not thrilled with that by any means, but I'm not sure fixing it is within scope.
## Paths not taken
### Separate `Disabled` component
This is a much larger and more controversial change, and not well-scoped to UI.
Furthermore, it is extremely rare that you want hidden UI elements to function: the most common cases are for things like changing tabs, collapsing elements or so on.
Splitting this behavior would be more complex, and substantially violate user expectations.
### A separate limbo world
Mentioned in the linked issue. Super cool, but all of the problems of the `Disabled` component solution with a whole new RFC-worth of complexity.
### Using change detection to reduce the amount of redundant work
Adds a lot of complexity for questionable performance gains. Likely involves a complete refactor of the entire system.
We simply don't have the tests or benchmarks here to justify this.
## Changelog
- UI nodes are now always in an `Interaction::None` state while they are hidden (via the `ComputedVisibility` component).
2022-07-20 21:26:47 +00:00
/// Use no layout, don't render this node and its children.
///
/// If you want to hide a node and its children,
/// but keep its layout in place, set its [`Visibility`](bevy_render::view::Visibility) component instead.
2020-07-26 19:27:09 +00:00
None ,
}
2023-01-04 19:58:09 +00:00
impl Display {
pub const DEFAULT : Self = Self ::Flex ;
}
impl Default for Display {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-01-07 22:20:34 +00:00
/// Defines how flexbox items are ordered within a flexbox
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum FlexDirection {
2023-03-04 14:09:47 +00:00
/// Same way as text direction along the main axis.
2020-07-26 19:27:09 +00:00
Row ,
2023-03-04 14:09:47 +00:00
/// Flex from top to bottom.
2020-07-26 19:27:09 +00:00
Column ,
2023-03-04 14:09:47 +00:00
/// Opposite way as text direction along the main axis.
2020-07-26 19:27:09 +00:00
RowReverse ,
2023-03-04 14:09:47 +00:00
/// Flex from bottom to top.
2020-07-26 19:27:09 +00:00
ColumnReverse ,
}
2023-01-04 19:58:09 +00:00
impl FlexDirection {
pub const DEFAULT : Self = Self ::Row ;
}
impl Default for FlexDirection {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-01-07 22:20:34 +00:00
/// Whether to show or hide overflowing items
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, Serialize, Deserialize, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 22:23:52 +00:00
pub struct Overflow {
/// Whether to show or clip overflowing items on the x axis
pub x : OverflowAxis ,
/// Whether to show or clip overflowing items on the y axis
pub y : OverflowAxis ,
}
impl Overflow {
pub const DEFAULT : Self = Self {
x : OverflowAxis ::DEFAULT ,
y : OverflowAxis ::DEFAULT ,
} ;
/// Show overflowing items on both axes
pub const fn visible ( ) -> Self {
Self {
x : OverflowAxis ::Visible ,
y : OverflowAxis ::Visible ,
}
}
/// Clip overflowing items on both axes
pub const fn clip ( ) -> Self {
Self {
x : OverflowAxis ::Clip ,
y : OverflowAxis ::Clip ,
}
}
/// Clip overflowing items on the x axis
pub const fn clip_x ( ) -> Self {
Self {
x : OverflowAxis ::Clip ,
y : OverflowAxis ::Visible ,
}
}
/// Clip overflowing items on the y axis
pub const fn clip_y ( ) -> Self {
Self {
x : OverflowAxis ::Visible ,
y : OverflowAxis ::Clip ,
}
}
/// Overflow is visible on both axes
pub const fn is_visible ( & self ) -> bool {
self . x . is_visible ( ) & & self . y . is_visible ( )
}
}
impl Default for Overflow {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
/// Whether to show or hide overflowing items
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, FromReflect, Serialize, Deserialize) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 22:23:52 +00:00
pub enum OverflowAxis {
2023-03-04 14:09:47 +00:00
/// Show overflowing items.
2021-12-19 05:44:28 +00:00
Visible ,
2023-03-04 14:09:47 +00:00
/// Hide overflowing items.
2023-04-17 22:23:52 +00:00
Clip ,
2021-12-19 05:44:28 +00:00
}
2020-07-26 19:27:09 +00:00
2023-04-17 22:23:52 +00:00
impl OverflowAxis {
2023-01-04 19:58:09 +00:00
pub const DEFAULT : Self = Self ::Visible ;
2023-04-17 22:23:52 +00:00
/// Overflow is visible on this axis
pub const fn is_visible ( & self ) -> bool {
matches! ( self , Self ::Visible )
}
2023-01-04 19:58:09 +00:00
}
2023-04-17 22:23:52 +00:00
impl Default for OverflowAxis {
2023-01-04 19:58:09 +00:00
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-01-07 22:20:34 +00:00
/// The strategy used to position this node
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum PositionType {
2023-03-04 14:09:47 +00:00
/// Relative to all other nodes with the [`PositionType::Relative`] value.
2020-07-26 19:27:09 +00:00
Relative ,
2023-03-04 14:09:47 +00:00
/// Independent of all other nodes.
2022-01-07 22:20:34 +00:00
///
2023-03-04 14:09:47 +00:00
/// As usual, the `Style.position` field of this node is specified relative to its parent node.
2020-07-26 19:27:09 +00:00
Absolute ,
}
2023-01-04 19:58:09 +00:00
impl PositionType {
const DEFAULT : Self = Self ::Relative ;
}
impl Default for PositionType {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-01-07 22:20:34 +00:00
/// Defines if flexbox items appear on a single line or on multiple lines
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2020-07-26 19:27:09 +00:00
pub enum FlexWrap {
2023-03-04 14:09:47 +00:00
/// Single line, will overflow if needed.
2020-07-26 19:27:09 +00:00
NoWrap ,
2023-03-04 14:09:47 +00:00
/// Multiple lines, if needed.
2020-07-26 19:27:09 +00:00
Wrap ,
2023-03-04 14:09:47 +00:00
/// Same as [`FlexWrap::Wrap`] but new lines will appear before the previous one.
2020-07-26 19:27:09 +00:00
WrapReverse ,
}
2023-01-04 19:58:09 +00:00
impl FlexWrap {
const DEFAULT : Self = Self ::NoWrap ;
}
impl Default for FlexWrap {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2023-04-17 16:21:38 +00:00
/// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used.
///
/// The "dense" packing algorithm attempts to fill in holes earlier in the grid, if smaller items come up later. This may cause items to appear out-of-order, when doing so would fill in holes left by larger items.
///
/// Defaults to [`GridAutoFlow::Row`]
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow>
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
pub enum GridAutoFlow {
/// Items are placed by filling each row in turn, adding new rows as necessary
Row ,
/// Items are placed by filling each column in turn, adding new columns as necessary.
Column ,
/// Combines `Row` with the dense packing algorithm.
RowDense ,
/// Combines `Column` with the dense packing algorithm.
ColumnDense ,
}
impl GridAutoFlow {
const DEFAULT : Self = Self ::Row ;
}
impl Default for GridAutoFlow {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
#[ derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
2023-04-26 12:17:23 +00:00
#[ reflect_value(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
pub enum MinTrackSizingFunction {
/// Track minimum size should be a fixed pixel value
Px ( f32 ) ,
/// Track minimum size should be a percentage value
Percent ( f32 ) ,
/// Track minimum size should be content sized under a min-content constraint
MinContent ,
/// Track minimum size should be content sized under a max-content constraint
MaxContent ,
/// Track minimum size should be automatically sized
Auto ,
}
#[ derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
2023-04-26 12:17:23 +00:00
#[ reflect_value(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
pub enum MaxTrackSizingFunction {
/// Track maximum size should be a fixed pixel value
Px ( f32 ) ,
/// Track maximum size should be a percentage value
Percent ( f32 ) ,
/// Track maximum size should be content sized under a min-content constraint
MinContent ,
/// Track maximum size should be content sized under a max-content constraint
MaxContent ,
/// Track maximum size should be sized according to the fit-content formula with a fixed pixel limit
FitContentPx ( f32 ) ,
/// Track maximum size should be sized according to the fit-content formula with a percentage limit
FitContentPercent ( f32 ) ,
/// Track maximum size should be automatically sized
Auto ,
/// The dimension as a fraction of the total available grid space (`fr` units in CSS)
/// Specified value is the numerator of the fraction. Denominator is the sum of all fractions specified in that grid dimension
/// Spec: <https://www.w3.org/TR/css3-grid-layout/#fr-unit>
Fraction ( f32 ) ,
}
/// A [`GridTrack`] is a Row or Column of a CSS Grid. This struct specifies what size the track should be.
/// See below for the different "track sizing functions" you can specify.
#[ derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
2023-04-26 12:17:23 +00:00
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
pub struct GridTrack {
pub ( crate ) min_sizing_function : MinTrackSizingFunction ,
pub ( crate ) max_sizing_function : MaxTrackSizingFunction ,
}
impl GridTrack {
const DEFAULT : Self = Self {
min_sizing_function : MinTrackSizingFunction ::Auto ,
max_sizing_function : MaxTrackSizingFunction ::Auto ,
} ;
/// Create a grid track with a fixed pixel size
pub fn px < T : From < Self > > ( value : f32 ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::Px ( value ) ,
max_sizing_function : MaxTrackSizingFunction ::Px ( value ) ,
}
. into ( )
}
/// Create a grid track with a percentage size
pub fn percent < T : From < Self > > ( value : f32 ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::Percent ( value ) ,
max_sizing_function : MaxTrackSizingFunction ::Percent ( value ) ,
}
. into ( )
}
/// Create a grid track with an `fr` size.
/// Note that this will give the track a content-based minimum size.
/// Usually you are best off using `GridTrack::flex` instead which uses a zero minimum size
pub fn fr < T : From < Self > > ( value : f32 ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::Auto ,
max_sizing_function : MaxTrackSizingFunction ::Fraction ( value ) ,
}
. into ( )
}
/// Create a grid track with an `minmax(0, Nfr)` size.
pub fn flex < T : From < Self > > ( value : f32 ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::Px ( 0.0 ) ,
max_sizing_function : MaxTrackSizingFunction ::Fraction ( value ) ,
}
. into ( )
}
/// Create a grid track which is automatically sized to fit it's contents, and then
pub fn auto < T : From < Self > > ( ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::Auto ,
max_sizing_function : MaxTrackSizingFunction ::Auto ,
}
. into ( )
}
/// Create a grid track which is automatically sized to fit it's contents when sized at their "min-content" sizes
pub fn min_content < T : From < Self > > ( ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::MinContent ,
max_sizing_function : MaxTrackSizingFunction ::MinContent ,
}
. into ( )
}
/// Create a grid track which is automatically sized to fit it's contents when sized at their "max-content" sizes
pub fn max_content < T : From < Self > > ( ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::MaxContent ,
max_sizing_function : MaxTrackSizingFunction ::MaxContent ,
}
. into ( )
}
/// Create a fit-content() grid track with fixed pixel limit
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/fit-content_function>
pub fn fit_content_px < T : From < Self > > ( limit : f32 ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::Auto ,
max_sizing_function : MaxTrackSizingFunction ::FitContentPx ( limit ) ,
}
. into ( )
}
/// Create a fit-content() grid track with percentage limit
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/fit-content_function>
pub fn fit_content_percent < T : From < Self > > ( limit : f32 ) -> T {
Self {
min_sizing_function : MinTrackSizingFunction ::Auto ,
max_sizing_function : MaxTrackSizingFunction ::FitContentPercent ( limit ) ,
}
. into ( )
}
/// Create a minmax() grid track
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/minmax>
pub fn minmax < T : From < Self > > ( min : MinTrackSizingFunction , max : MaxTrackSizingFunction ) -> T {
Self {
min_sizing_function : min ,
max_sizing_function : max ,
}
. into ( )
}
}
impl Default for GridTrack {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
#[ derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
2023-04-26 12:17:23 +00:00
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
/// How many times to repeat a repeated grid track
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/repeat>
pub enum GridTrackRepetition {
/// Repeat the track fixed number of times
Count ( u16 ) ,
/// Repeat the track to fill available space
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fill>
AutoFill ,
/// Repeat the track to fill available space but collapse any tracks that do not end up with
/// an item placed in them.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fit>
AutoFit ,
}
impl From < u16 > for GridTrackRepetition {
fn from ( count : u16 ) -> Self {
Self ::Count ( count )
}
}
impl From < i32 > for GridTrackRepetition {
fn from ( count : i32 ) -> Self {
Self ::Count ( count as u16 )
}
}
impl From < usize > for GridTrackRepetition {
fn from ( count : usize ) -> Self {
Self ::Count ( count as u16 )
}
}
/// Represents a *possibly* repeated [`GridTrack`].
///
/// The repetition parameter can either be:
/// - The integer `1`, in which case the track is non-repeated.
/// - a `u16` count to repeat the track N times
/// - A `GridTrackRepetition::AutoFit` or `GridTrackRepetition::AutoFill`
///
/// Note: that in the common case you want a non-repeating track (repetition count 1), you may use the constructor methods on [`GridTrack`]
/// to create a `RepeatedGridTrack`. i.e. `GridTrack::px(10.0)` is equivalent to `RepeatedGridTrack::px(1, 10.0)`.
///
/// You may only use one auto-repetition per track list. And if your track list contains an auto repetition
/// then all track (in and outside of the repetition) must be fixed size (px or percent). Integer repetitions are just shorthand for writing out
/// N tracks longhand and are not subject to the same limitations.
#[ derive(Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
2023-04-26 12:17:23 +00:00
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
pub struct RepeatedGridTrack {
pub ( crate ) repetition : GridTrackRepetition ,
pub ( crate ) tracks : SmallVec < [ GridTrack ; 1 ] > ,
}
impl RepeatedGridTrack {
/// Create a repeating set of grid tracks with a fixed pixel size
pub fn px < T : From < Self > > ( repetition : impl Into < GridTrackRepetition > , value : f32 ) -> T {
Self {
repetition : repetition . into ( ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::px ( value ) ] ) ,
}
. into ( )
}
/// Create a repeating set of grid tracks with a percentage size
pub fn percent < T : From < Self > > ( repetition : impl Into < GridTrackRepetition > , value : f32 ) -> T {
Self {
repetition : repetition . into ( ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::percent ( value ) ] ) ,
}
. into ( )
}
/// Create a repeating set of grid tracks with automatic size
pub fn auto < T : From < Self > > ( repetition : u16 ) -> T {
Self {
repetition : GridTrackRepetition ::Count ( repetition ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::auto ( ) ] ) ,
}
. into ( )
}
/// Create a repeating set of grid tracks with an `fr` size.
/// Note that this will give the track a content-based minimum size.
/// Usually you are best off using `GridTrack::flex` instead which uses a zero minimum size
pub fn fr < T : From < Self > > ( repetition : u16 , value : f32 ) -> T {
Self {
repetition : GridTrackRepetition ::Count ( repetition ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::fr ( value ) ] ) ,
}
. into ( )
}
/// Create a repeating set of grid tracks with an `minmax(0, Nfr)` size.
pub fn flex < T : From < Self > > ( repetition : u16 , value : f32 ) -> T {
Self {
repetition : GridTrackRepetition ::Count ( repetition ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::flex ( value ) ] ) ,
}
. into ( )
}
/// Create a repeating set of grid tracks with min-content size
pub fn min_content < T : From < Self > > ( repetition : u16 ) -> T {
Self {
repetition : GridTrackRepetition ::Count ( repetition ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::min_content ( ) ] ) ,
}
. into ( )
}
/// Create a repeating set of grid tracks with max-content size
pub fn max_content < T : From < Self > > ( repetition : u16 ) -> T {
Self {
repetition : GridTrackRepetition ::Count ( repetition ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::max_content ( ) ] ) ,
}
. into ( )
}
/// Create a repeating set of fit-content() grid tracks with fixed pixel limit
pub fn fit_content_px < T : From < Self > > ( repetition : u16 , limit : f32 ) -> T {
Self {
repetition : GridTrackRepetition ::Count ( repetition ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::fit_content_px ( limit ) ] ) ,
}
. into ( )
}
/// Create a repeating set of fit-content() grid tracks with percentage limit
pub fn fit_content_percent < T : From < Self > > ( repetition : u16 , limit : f32 ) -> T {
Self {
repetition : GridTrackRepetition ::Count ( repetition ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::fit_content_percent ( limit ) ] ) ,
}
. into ( )
}
/// Create a repeating set of minmax() grid track
pub fn minmax < T : From < Self > > (
repetition : impl Into < GridTrackRepetition > ,
min : MinTrackSizingFunction ,
max : MaxTrackSizingFunction ,
) -> T {
Self {
repetition : repetition . into ( ) ,
tracks : SmallVec ::from_buf ( [ GridTrack ::minmax ( min , max ) ] ) ,
}
. into ( )
}
/// Create a repetition of a set of tracks
pub fn repeat_many < T : From < Self > > (
repetition : impl Into < GridTrackRepetition > ,
tracks : impl Into < Vec < GridTrack > > ,
) -> T {
Self {
repetition : repetition . into ( ) ,
tracks : SmallVec ::from_vec ( tracks . into ( ) ) ,
}
. into ( )
}
}
impl From < GridTrack > for RepeatedGridTrack {
fn from ( track : GridTrack ) -> Self {
Self {
repetition : GridTrackRepetition ::Count ( 1 ) ,
tracks : SmallVec ::from_buf ( [ track ] ) ,
}
}
}
impl From < GridTrack > for Vec < GridTrack > {
fn from ( track : GridTrack ) -> Self {
vec! [ GridTrack {
min_sizing_function : track . min_sizing_function ,
max_sizing_function : track . max_sizing_function ,
} ]
}
}
impl From < GridTrack > for Vec < RepeatedGridTrack > {
fn from ( track : GridTrack ) -> Self {
vec! [ RepeatedGridTrack {
repetition : GridTrackRepetition ::Count ( 1 ) ,
tracks : SmallVec ::from_buf ( [ track ] ) ,
} ]
}
}
impl From < RepeatedGridTrack > for Vec < RepeatedGridTrack > {
fn from ( track : RepeatedGridTrack ) -> Self {
vec! [ track ]
}
}
2023-04-26 12:17:23 +00:00
#[ derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect) ]
#[ reflect(FromReflect, PartialEq, Serialize, Deserialize) ]
2023-04-17 16:21:38 +00:00
/// Represents the position of a grid item in a single axis.
///
/// There are 3 fields which may be set:
/// - `start`: which grid line the item should start at
/// - `end`: which grid line the item should end at
/// - `span`: how many tracks the item should span
///
/// The default `span` is 1. If neither `start` or `end` is set then the item will be placed automatically.
///
/// Generally, at most two fields should be set. If all three fields are specifed then `span` will be ignored. If `end` specifies an earlier
/// grid line than `start` then `end` will be ignored and the item will have a span of 1.
///
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Line-based_Placement_with_CSS_Grid>
pub struct GridPlacement {
/// The grid line at which the item should start. Lines are 1-indexed. Negative indexes count backwards from the end of the grid. Zero is not a valid index.
pub ( crate ) start : Option < i16 > ,
/// How many grid tracks the item should span. Defaults to 1.
pub ( crate ) span : Option < u16 > ,
/// The grid line at which the node should end. Lines are 1-indexed. Negative indexes count backwards from the end of the grid. Zero is not a valid index.
pub ( crate ) end : Option < i16 > ,
}
impl GridPlacement {
const DEFAULT : Self = Self {
start : None ,
span : Some ( 1 ) ,
end : None ,
} ;
/// Place the grid item automatically (letting the `span` default to `1`).
pub fn auto ( ) -> Self {
Self {
start : None ,
end : None ,
span : Some ( 1 ) ,
}
}
/// Place the grid item automatically, specifying how many tracks it should `span`.
pub fn span ( span : u16 ) -> Self {
Self {
start : None ,
end : None ,
span : Some ( span ) ,
}
}
/// Place the grid item specifying the `start` grid line (letting the `span` default to `1`).
pub fn start ( start : i16 ) -> Self {
Self {
start : Some ( start ) ,
end : None ,
span : Some ( 1 ) ,
}
}
/// Place the grid item specifying the `end` grid line (letting the `span` default to `1`).
pub fn end ( end : i16 ) -> Self {
Self {
start : None ,
end : Some ( end ) ,
span : Some ( 1 ) ,
}
}
/// Place the grid item specifying the `start` grid line and how many tracks it should `span`.
pub fn start_span ( start : i16 , span : u16 ) -> Self {
Self {
start : Some ( start ) ,
end : None ,
span : Some ( span ) ,
}
}
/// Place the grid item specifying `start` and `end` grid lines (`span` will be inferred)
pub fn start_end ( start : i16 , end : i16 ) -> Self {
Self {
start : Some ( start ) ,
end : Some ( end ) ,
span : None ,
}
}
/// Place the grid item specifying the `end` grid line and how many tracks it should `span`.
pub fn end_span ( end : i16 , span : u16 ) -> Self {
Self {
start : None ,
end : Some ( end ) ,
span : Some ( span ) ,
}
}
/// Mutate the item, setting the `start` grid line
pub fn set_start ( mut self , start : i16 ) -> Self {
self . start = Some ( start ) ;
self
}
/// Mutate the item, setting the `end` grid line
pub fn set_end ( mut self , end : i16 ) -> Self {
self . end = Some ( end ) ;
self
}
/// Mutate the item, setting the number of tracks the item should `span`
pub fn set_span ( mut self , span : u16 ) -> Self {
self . span = Some ( span ) ;
self
}
}
impl Default for GridPlacement {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-09-25 00:39:17 +00:00
/// The background color of the node
///
/// This serves as the "fill" color.
/// When combined with [`UiImage`], tints the provided texture.
2023-04-26 12:17:23 +00:00
#[ derive(Component, Copy, Clone, Debug, Reflect, FromReflect) ]
#[ reflect(FromReflect, Component, Default) ]
2022-09-25 00:39:17 +00:00
pub struct BackgroundColor ( pub Color ) ;
2021-12-14 03:58:23 +00:00
2023-01-04 19:58:09 +00:00
impl BackgroundColor {
pub const DEFAULT : Self = Self ( Color ::WHITE ) ;
}
impl Default for BackgroundColor {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-09-25 00:39:17 +00:00
impl From < Color > for BackgroundColor {
2021-12-14 03:58:23 +00:00
fn from ( color : Color ) -> Self {
Self ( color )
}
}
2023-06-19 21:52:02 +00:00
/// The atlas sprite to be used in a UI Texture Atlas Node
#[ derive(Component, Clone, Debug, Reflect, FromReflect, Default) ]
#[ reflect(Component, Default) ]
pub struct UiTextureAtlasImage {
/// Texture index in the TextureAtlas
pub index : usize ,
/// Whether to flip the sprite in the X axis
pub flip_x : bool ,
/// Whether to flip the sprite in the Y axis
pub flip_y : bool ,
}
2023-06-14 22:43:38 +00:00
/// The border color of the UI node.
#[ derive(Component, Copy, Clone, Debug, Reflect, FromReflect) ]
#[ reflect(FromReflect, Component, Default) ]
pub struct BorderColor ( pub Color ) ;
impl From < Color > for BorderColor {
fn from ( color : Color ) -> Self {
Self ( color )
}
}
impl BorderColor {
pub const DEFAULT : Self = BorderColor ( Color ::WHITE ) ;
}
impl Default for BorderColor {
fn default ( ) -> Self {
Self ::DEFAULT
}
}
2022-09-25 00:39:17 +00:00
/// The 2D texture displayed for this UI node
2023-06-19 16:18:17 +00:00
#[ derive(Component, Clone, Debug, Reflect, FromReflect) ]
#[ reflect(Component, Default, FromReflect) ]
2022-11-14 21:59:17 +00:00
pub struct UiImage {
/// Handle to the texture
pub texture : Handle < Image > ,
/// Whether the image should be flipped along its x-axis
pub flip_x : bool ,
/// Whether the image should be flipped along its y-axis
pub flip_y : bool ,
}
2021-12-14 03:58:23 +00:00
impl Default for UiImage {
2022-11-14 21:59:17 +00:00
fn default ( ) -> UiImage {
UiImage {
texture : DEFAULT_IMAGE_HANDLE . typed ( ) ,
flip_x : false ,
flip_y : false ,
}
}
}
impl UiImage {
pub fn new ( texture : Handle < Image > ) -> Self {
Self {
texture ,
.. Default ::default ( )
}
2021-12-14 03:58:23 +00:00
}
2023-04-05 22:19:46 +00:00
/// flip the image along its x-axis
#[ must_use ]
pub const fn with_flip_x ( mut self ) -> Self {
self . flip_x = true ;
self
}
/// flip the image along its y-axis
#[ must_use ]
pub const fn with_flip_y ( mut self ) -> Self {
self . flip_y = true ;
self
}
2021-12-14 03:58:23 +00:00
}
impl From < Handle < Image > > for UiImage {
2022-11-14 21:59:17 +00:00
fn from ( texture : Handle < Image > ) -> Self {
Self ::new ( texture )
2021-12-14 03:58:23 +00:00
}
}
2021-12-19 05:44:28 +00:00
2022-01-07 22:20:34 +00:00
/// The calculated clip of the node
2023-04-26 12:17:23 +00:00
#[ derive(Component, Default, Copy, Clone, Debug, Reflect, FromReflect) ]
#[ reflect(FromReflect, Component) ]
2021-12-19 05:44:28 +00:00
pub struct CalculatedClip {
2022-01-07 22:20:34 +00:00
/// The rect of the clip
2022-09-02 12:35:23 +00:00
pub clip : Rect ,
2021-12-19 05:44:28 +00:00
}
2022-10-24 14:33:46 +00:00
Add z-index support with a predictable UI stack (#5877)
# Objective
Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth.
## The problem with current implementation
The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another.
At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it.
## Solution
### New ZIndex component
This adds a new optional `ZIndex` enum component for nodes which offers two mechanism:
- `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings.
- `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI.
Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`.
### New UiStack resource
This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over).
### New z_index example
This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all).
![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png)
---
## Changelog
- Added the `ZIndex` component to bevy_ui.
- Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module.
- Removed the previous Z updating system from bevy_ui, because it was replaced with the above.
- Changed bevy_ui rendering to use UiStack instead of z ordering.
- Changed bevy_ui focus/interaction system to use UiStack instead of z ordering.
- Added a new z_index example.
## ZIndex demo
Here's a demo I wrote to test these features
https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
/// Indicates that this [`Node`] entity's front-to-back ordering is not controlled solely
/// by its location in the UI hierarchy. A node with a higher z-index will appear on top
/// of other nodes with a lower z-index.
///
/// UI nodes that have the same z-index will appear according to the order in which they
/// appear in the UI hierarchy. In such a case, the last node to be added to its parent
/// will appear in front of this parent's other children.
///
/// Internally, nodes with a global z-index share the stacking context of root UI nodes
/// (nodes that have no parent). Because of this, there is no difference between using
/// [`ZIndex::Local(n)`] and [`ZIndex::Global(n)`] for root nodes.
///
/// Nodes without this component will be treated as if they had a value of [`ZIndex::Local(0)`].
2023-04-26 12:17:23 +00:00
#[ derive(Component, Copy, Clone, Debug, Reflect, FromReflect) ]
#[ reflect(Component, FromReflect) ]
Add z-index support with a predictable UI stack (#5877)
# Objective
Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth.
## The problem with current implementation
The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another.
At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it.
## Solution
### New ZIndex component
This adds a new optional `ZIndex` enum component for nodes which offers two mechanism:
- `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings.
- `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI.
Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`.
### New UiStack resource
This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over).
### New z_index example
This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all).
![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png)
---
## Changelog
- Added the `ZIndex` component to bevy_ui.
- Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module.
- Removed the previous Z updating system from bevy_ui, because it was replaced with the above.
- Changed bevy_ui rendering to use UiStack instead of z ordering.
- Changed bevy_ui focus/interaction system to use UiStack instead of z ordering.
- Added a new z_index example.
## ZIndex demo
Here's a demo I wrote to test these features
https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
pub enum ZIndex {
/// Indicates the order in which this node should be rendered relative to its siblings.
Local ( i32 ) ,
/// Indicates the order in which this node should be rendered relative to root nodes and
/// all other nodes that have a global z-index.
Global ( i32 ) ,
}
impl Default for ZIndex {
fn default ( ) -> Self {
Self ::Local ( 0 )
}
}
2022-10-24 14:33:46 +00:00
#[ cfg(test) ]
mod tests {
use crate ::ValArithmeticError ;
use super ::Val ;
#[ test ]
fn val_try_add ( ) {
let auto_sum = Val ::Auto . try_add ( Val ::Auto ) . unwrap ( ) ;
let px_sum = Val ::Px ( 20. ) . try_add ( Val ::Px ( 22. ) ) . unwrap ( ) ;
let percent_sum = Val ::Percent ( 50. ) . try_add ( Val ::Percent ( 50. ) ) . unwrap ( ) ;
assert_eq! ( auto_sum , Val ::Auto ) ;
assert_eq! ( px_sum , Val ::Px ( 42. ) ) ;
assert_eq! ( percent_sum , Val ::Percent ( 100. ) ) ;
}
#[ test ]
fn val_try_add_to_self ( ) {
let mut val = Val ::Px ( 5. ) ;
val . try_add_assign ( Val ::Px ( 3. ) ) . unwrap ( ) ;
assert_eq! ( val , Val ::Px ( 8. ) ) ;
}
#[ test ]
fn val_try_sub ( ) {
let auto_sum = Val ::Auto . try_sub ( Val ::Auto ) . unwrap ( ) ;
let px_sum = Val ::Px ( 72. ) . try_sub ( Val ::Px ( 30. ) ) . unwrap ( ) ;
let percent_sum = Val ::Percent ( 100. ) . try_sub ( Val ::Percent ( 50. ) ) . unwrap ( ) ;
assert_eq! ( auto_sum , Val ::Auto ) ;
assert_eq! ( px_sum , Val ::Px ( 42. ) ) ;
assert_eq! ( percent_sum , Val ::Percent ( 50. ) ) ;
}
#[ test ]
fn different_variant_val_try_add ( ) {
2023-03-13 15:17:00 +00:00
let different_variant_sum_1 = Val ::Px ( 50. ) . try_add ( Val ::Percent ( 50. ) ) ;
let different_variant_sum_2 = Val ::Percent ( 50. ) . try_add ( Val ::Auto ) ;
2022-10-24 14:33:46 +00:00
assert_eq! (
different_variant_sum_1 ,
Err ( ValArithmeticError ::NonIdenticalVariants )
) ;
assert_eq! (
different_variant_sum_2 ,
Err ( ValArithmeticError ::NonIdenticalVariants )
) ;
}
#[ test ]
fn different_variant_val_try_sub ( ) {
2023-03-13 15:17:00 +00:00
let different_variant_diff_1 = Val ::Px ( 50. ) . try_sub ( Val ::Percent ( 50. ) ) ;
let different_variant_diff_2 = Val ::Percent ( 50. ) . try_sub ( Val ::Auto ) ;
2022-10-24 14:33:46 +00:00
assert_eq! (
different_variant_diff_1 ,
Err ( ValArithmeticError ::NonIdenticalVariants )
) ;
assert_eq! (
different_variant_diff_2 ,
Err ( ValArithmeticError ::NonIdenticalVariants )
) ;
}
#[ test ]
fn val_evaluate ( ) {
let size = 250. ;
let result = Val ::Percent ( 80. ) . evaluate ( size ) . unwrap ( ) ;
assert_eq! ( result , size * 0.8 ) ;
}
#[ test ]
fn val_evaluate_px ( ) {
let size = 250. ;
let result = Val ::Px ( 10. ) . evaluate ( size ) . unwrap ( ) ;
assert_eq! ( result , 10. ) ;
}
#[ test ]
fn val_invalid_evaluation ( ) {
let size = 250. ;
let evaluate_auto = Val ::Auto . evaluate ( size ) ;
assert_eq! ( evaluate_auto , Err ( ValArithmeticError ::NonEvaluateable ) ) ;
}
#[ test ]
fn val_try_add_with_size ( ) {
let size = 250. ;
let px_sum = Val ::Px ( 21. ) . try_add_with_size ( Val ::Px ( 21. ) , size ) . unwrap ( ) ;
let percent_sum = Val ::Percent ( 20. )
. try_add_with_size ( Val ::Percent ( 30. ) , size )
. unwrap ( ) ;
let mixed_sum = Val ::Px ( 20. )
. try_add_with_size ( Val ::Percent ( 30. ) , size )
. unwrap ( ) ;
assert_eq! ( px_sum , 42. ) ;
assert_eq! ( percent_sum , 0.5 * size ) ;
assert_eq! ( mixed_sum , 20. + 0.3 * size ) ;
}
#[ test ]
fn val_try_sub_with_size ( ) {
let size = 250. ;
let px_sum = Val ::Px ( 60. ) . try_sub_with_size ( Val ::Px ( 18. ) , size ) . unwrap ( ) ;
let percent_sum = Val ::Percent ( 80. )
. try_sub_with_size ( Val ::Percent ( 30. ) , size )
. unwrap ( ) ;
let mixed_sum = Val ::Percent ( 50. )
. try_sub_with_size ( Val ::Px ( 30. ) , size )
. unwrap ( ) ;
assert_eq! ( px_sum , 42. ) ;
assert_eq! ( percent_sum , 0.5 * size ) ;
assert_eq! ( mixed_sum , 0.5 * size - 30. ) ;
}
#[ test ]
fn val_try_add_non_numeric_with_size ( ) {
let size = 250. ;
let percent_sum = Val ::Auto . try_add_with_size ( Val ::Auto , size ) ;
assert_eq! ( percent_sum , Err ( ValArithmeticError ::NonEvaluateable ) ) ;
}
#[ test ]
fn val_arithmetic_error_messages ( ) {
assert_eq! (
format! ( " {} " , ValArithmeticError ::NonIdenticalVariants ) ,
" the variants of the Vals don't match "
) ;
assert_eq! (
format! ( " {} " , ValArithmeticError ::NonEvaluateable ) ,
" the given variant of Val is not evaluateable (non-numeric) "
) ;
}
2023-03-13 15:17:00 +00:00
#[ test ]
fn default_val_equals_const_default_val ( ) {
assert_eq! ( Val ::default ( ) , Val ::DEFAULT ) ;
}
2022-10-24 14:33:46 +00:00
}