Add const to methods and const defaults to bevy_ui (#5542)

# Objective
- Fixes #5529 

## Solution
- Add assosciated constants named DEFAULT to as many types as possible
- Add const to as many methods in bevy_ui as possible

I have not applied the same treatment to the bundles in bevy_ui as it would require going into other bevy crates to implement const defaults for structs in bevy_text or relies on UiImage which calls HandleUntyped.typed() which isn't const safe.

Alternatively the defaults could relatively easily be turned into a macro to regain some of the readability and conciseness at the cost of explicitness.
Such a macro that partially implements this exists as a crate here: [const-default](https://docs.rs/const-default/latest/const_default/derive.ConstDefault.html) but does not support enums.

Let me know if there's anything I've missed or if I should push further into other crates.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
James O'Brien 2023-01-04 19:58:09 +00:00
parent 2d727afaf7
commit df3673f679
3 changed files with 238 additions and 61 deletions

View File

@ -31,9 +31,7 @@ use smallvec::SmallVec;
/// ///
/// Note that you can also control the visibility of a node using the [`Display`](crate::ui_node::Display) property, /// Note that you can also control the visibility of a node using the [`Display`](crate::ui_node::Display) property,
/// which fully collapses it during layout calculations. /// which fully collapses it during layout calculations.
#[derive( #[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)]
Component, Copy, Clone, Default, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize,
)]
#[reflect(Component, Serialize, Deserialize, PartialEq)] #[reflect(Component, Serialize, Deserialize, PartialEq)]
pub enum Interaction { pub enum Interaction {
/// The node has been clicked /// The node has been clicked
@ -41,22 +39,39 @@ pub enum Interaction {
/// The node has been hovered over /// The node has been hovered over
Hovered, Hovered,
/// Nothing has happened /// Nothing has happened
#[default]
None, None,
} }
impl Interaction {
const DEFAULT: Self = Self::None;
}
impl Default for Interaction {
fn default() -> Self {
Self::DEFAULT
}
}
/// Describes whether the node should block interactions with lower nodes /// Describes whether the node should block interactions with lower nodes
#[derive( #[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)]
Component, Copy, Clone, Default, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize,
)]
#[reflect(Component, Serialize, Deserialize, PartialEq)] #[reflect(Component, Serialize, Deserialize, PartialEq)]
pub enum FocusPolicy { pub enum FocusPolicy {
/// Blocks interaction /// Blocks interaction
#[default]
Block, Block,
/// Lets interaction pass through /// Lets interaction pass through
Pass, Pass,
} }
impl FocusPolicy {
const DEFAULT: Self = Self::Block;
}
impl Default for FocusPolicy {
fn default() -> Self {
Self::DEFAULT
}
}
/// Contains entities whose Interaction should be set to None /// Contains entities whose Interaction should be set to None
#[derive(Default)] #[derive(Default)]
pub struct State { pub struct State {

View File

@ -119,7 +119,7 @@ use std::ops::{Div, DivAssign, Mul, MulAssign};
/// bottom: Val::Px(40.0), /// bottom: Val::Px(40.0),
/// }; /// };
/// ``` /// ```
#[derive(Copy, Clone, PartialEq, Debug, Default, Reflect)] #[derive(Copy, Clone, PartialEq, Debug, Reflect)]
#[reflect(PartialEq)] #[reflect(PartialEq)]
pub struct UiRect { pub struct UiRect {
/// The value corresponding to the left side of the UI rect. /// The value corresponding to the left side of the UI rect.
@ -133,6 +133,13 @@ pub struct UiRect {
} }
impl UiRect { impl UiRect {
pub const DEFAULT: Self = Self {
left: Val::DEFAULT,
right: Val::DEFAULT,
top: Val::DEFAULT,
bottom: Val::DEFAULT,
};
/// Creates a new [`UiRect`] from the values specified. /// Creates a new [`UiRect`] from the values specified.
/// ///
/// # Example /// # Example
@ -152,7 +159,7 @@ impl UiRect {
/// assert_eq!(ui_rect.top, Val::Px(30.0)); /// assert_eq!(ui_rect.top, Val::Px(30.0));
/// assert_eq!(ui_rect.bottom, Val::Px(40.0)); /// assert_eq!(ui_rect.bottom, Val::Px(40.0));
/// ``` /// ```
pub fn new(left: Val, right: Val, top: Val, bottom: Val) -> Self { pub const fn new(left: Val, right: Val, top: Val, bottom: Val) -> Self {
UiRect { UiRect {
left, left,
right, right,
@ -175,7 +182,7 @@ impl UiRect {
/// assert_eq!(ui_rect.top, Val::Px(10.0)); /// assert_eq!(ui_rect.top, Val::Px(10.0));
/// assert_eq!(ui_rect.bottom, Val::Px(10.0)); /// assert_eq!(ui_rect.bottom, Val::Px(10.0));
/// ``` /// ```
pub fn all(value: Val) -> Self { pub const fn all(value: Val) -> Self {
UiRect { UiRect {
left: value, left: value,
right: value, right: value,
@ -313,10 +320,16 @@ impl UiRect {
} }
} }
impl Default for UiRect {
fn default() -> Self {
Self::DEFAULT
}
}
/// A 2-dimensional area defined by a width and height. /// A 2-dimensional area defined by a width and height.
/// ///
/// It is commonly used to define the size of a text or UI element. /// It is commonly used to define the size of a text or UI element.
#[derive(Copy, Clone, PartialEq, Debug, Default, Reflect)] #[derive(Copy, Clone, PartialEq, Debug, Reflect)]
#[reflect(PartialEq)] #[reflect(PartialEq)]
pub struct Size { pub struct Size {
/// The width of the 2-dimensional area. /// The width of the 2-dimensional area.
@ -326,6 +339,11 @@ pub struct Size {
} }
impl Size { impl Size {
pub const DEFAULT: Self = Self {
width: Val::DEFAULT,
height: Val::DEFAULT,
};
/// Creates a new [`Size`] from a width and a height. /// Creates a new [`Size`] from a width and a height.
/// ///
/// # Example /// # Example
@ -355,6 +373,12 @@ impl Size {
}; };
} }
impl Default for Size {
fn default() -> Self {
Self::DEFAULT
}
}
impl From<(Val, Val)> for Size { impl From<(Val, Val)> for Size {
fn from(vals: (Val, Val)) -> Self { fn from(vals: (Val, Val)) -> Self {
Self { Self {

View File

@ -12,7 +12,7 @@ use std::ops::{Div, DivAssign, Mul, MulAssign};
use thiserror::Error; use thiserror::Error;
/// Describes the size of a UI node /// Describes the size of a UI node
#[derive(Component, Debug, Clone, Default, Reflect)] #[derive(Component, Debug, Clone, Reflect)]
#[reflect(Component, Default)] #[reflect(Component, Default)]
pub struct Node { pub struct Node {
/// The size of the node as width and height in pixels /// The size of the node as width and height in pixels
@ -28,12 +28,23 @@ impl Node {
} }
} }
impl Node {
pub const DEFAULT: Self = Self {
calculated_size: Vec2::ZERO,
};
}
impl Default for Node {
fn default() -> Self {
Self::DEFAULT
}
}
/// An enum that describes possible types of value in flexbox layout options /// An enum that describes possible types of value in flexbox layout options
#[derive(Copy, Clone, PartialEq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum Val { pub enum Val {
/// No value defined /// No value defined
#[default]
Undefined, Undefined,
/// Automatically determine this value /// Automatically determine this value
Auto, Auto,
@ -43,6 +54,16 @@ pub enum Val {
Percent(f32), Percent(f32),
} }
impl Val {
pub const DEFAULT: Self = Self::Undefined;
}
impl Default for Val {
fn default() -> Self {
Self::DEFAULT
}
}
impl Mul<f32> for Val { impl Mul<f32> for Val {
type Output = Val; type Output = Val;
@ -243,37 +264,41 @@ pub struct Style {
pub gap: Size, pub gap: Size,
} }
impl Default for Style { impl Style {
fn default() -> Self { pub const DEFAULT: Self = Self {
Self { display: Display::DEFAULT,
display: Default::default(), position_type: PositionType::DEFAULT,
position_type: Default::default(), direction: Direction::DEFAULT,
direction: Default::default(), flex_direction: FlexDirection::DEFAULT,
flex_direction: Default::default(), flex_wrap: FlexWrap::DEFAULT,
flex_wrap: Default::default(), align_items: AlignItems::DEFAULT,
align_items: Default::default(), align_self: AlignSelf::DEFAULT,
align_self: Default::default(), align_content: AlignContent::DEFAULT,
align_content: Default::default(), justify_content: JustifyContent::DEFAULT,
justify_content: Default::default(), position: UiRect::DEFAULT,
position: Default::default(), margin: UiRect::DEFAULT,
margin: Default::default(), padding: UiRect::DEFAULT,
padding: Default::default(), border: UiRect::DEFAULT,
border: Default::default(),
flex_grow: 0.0, flex_grow: 0.0,
flex_shrink: 1.0, flex_shrink: 1.0,
flex_basis: Val::Auto, flex_basis: Val::Auto,
size: Size::AUTO, size: Size::AUTO,
min_size: Size::AUTO, min_size: Size::AUTO,
max_size: Size::AUTO, max_size: Size::AUTO,
aspect_ratio: Default::default(), aspect_ratio: None,
overflow: Default::default(), overflow: Overflow::DEFAULT,
gap: Size::UNDEFINED, gap: Size::UNDEFINED,
};
} }
impl Default for Style {
fn default() -> Self {
Self::DEFAULT
} }
} }
/// How items are aligned according to the cross axis /// How items are aligned according to the cross axis
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum AlignItems { pub enum AlignItems {
/// Items are aligned at the start /// Items are aligned at the start
@ -285,16 +310,24 @@ pub enum AlignItems {
/// Items are aligned at the baseline /// Items are aligned at the baseline
Baseline, Baseline,
/// Items are stretched across the whole cross axis /// Items are stretched across the whole cross axis
#[default]
Stretch, Stretch,
} }
impl AlignItems {
pub const DEFAULT: Self = Self::Stretch;
}
impl Default for AlignItems {
fn default() -> Self {
Self::DEFAULT
}
}
/// Works like [`AlignItems`] but applies only to a single item /// Works like [`AlignItems`] but applies only to a single item
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum AlignSelf { pub enum AlignSelf {
/// Use the value of [`AlignItems`] /// Use the value of [`AlignItems`]
#[default]
Auto, Auto,
/// If the parent has [`AlignItems::Center`] only this item will be at the start /// If the parent has [`AlignItems::Center`] only this item will be at the start
FlexStart, FlexStart,
@ -308,10 +341,20 @@ pub enum AlignSelf {
Stretch, Stretch,
} }
impl AlignSelf {
pub const DEFAULT: Self = Self::Auto;
}
impl Default for AlignSelf {
fn default() -> Self {
Self::DEFAULT
}
}
/// Defines how each line is aligned within the flexbox. /// 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. /// It only applies if [`FlexWrap::Wrap`] is present and if there are multiple lines of items.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum AlignContent { pub enum AlignContent {
/// Each line moves towards the start of the cross axis /// Each line moves towards the start of the cross axis
@ -321,7 +364,6 @@ pub enum AlignContent {
/// Each line moves towards the center of the cross axis /// Each line moves towards the center of the cross axis
Center, Center,
/// Each line will stretch to fill the remaining space /// Each line will stretch to fill the remaining space
#[default]
Stretch, Stretch,
/// Each line fills the space it needs, putting the remaining space, if any /// Each line fills the space it needs, putting the remaining space, if any
/// inbetween the lines /// inbetween the lines
@ -331,14 +373,23 @@ pub enum AlignContent {
SpaceAround, SpaceAround,
} }
impl AlignContent {
pub const DEFAULT: Self = Self::Stretch;
}
impl Default for AlignContent {
fn default() -> Self {
Self::DEFAULT
}
}
/// Defines the text direction /// Defines the text direction
/// ///
/// For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left). /// For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left).
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum Direction { pub enum Direction {
/// Inherit from parent node /// Inherit from parent node
#[default]
Inherit, Inherit,
/// Text is written left to right /// Text is written left to right
LeftToRight, LeftToRight,
@ -346,14 +397,23 @@ pub enum Direction {
RightToLeft, RightToLeft,
} }
impl Direction {
pub const DEFAULT: Self = Self::Inherit;
}
impl Default for Direction {
fn default() -> Self {
Self::DEFAULT
}
}
/// Whether to use a Flexbox layout model. /// Whether to use a Flexbox layout model.
/// ///
/// Part of the [`Style`] component. /// Part of the [`Style`] component.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum Display { pub enum Display {
/// Use Flexbox layout model to determine the position of this [`Node`]. /// Use Flexbox layout model to determine the position of this [`Node`].
#[default]
Flex, Flex,
/// Use no layout, don't render this node and its children. /// Use no layout, don't render this node and its children.
/// ///
@ -362,12 +422,21 @@ pub enum Display {
None, None,
} }
impl Display {
pub const DEFAULT: Self = Self::Flex;
}
impl Default for Display {
fn default() -> Self {
Self::DEFAULT
}
}
/// Defines how flexbox items are ordered within a flexbox /// Defines how flexbox items are ordered within a flexbox
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum FlexDirection { pub enum FlexDirection {
/// Same way as text direction along the main axis /// Same way as text direction along the main axis
#[default]
Row, Row,
/// Flex from top to bottom /// Flex from top to bottom
Column, Column,
@ -377,12 +446,21 @@ pub enum FlexDirection {
ColumnReverse, ColumnReverse,
} }
impl FlexDirection {
pub const DEFAULT: Self = Self::Row;
}
impl Default for FlexDirection {
fn default() -> Self {
Self::DEFAULT
}
}
/// Defines how items are aligned according to the main axis /// Defines how items are aligned according to the main axis
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum JustifyContent { pub enum JustifyContent {
/// Pushed towards the start /// Pushed towards the start
#[default]
FlexStart, FlexStart,
/// Pushed towards the end /// Pushed towards the end
FlexEnd, FlexEnd,
@ -396,23 +474,41 @@ pub enum JustifyContent {
SpaceEvenly, SpaceEvenly,
} }
impl JustifyContent {
pub const DEFAULT: Self = Self::FlexStart;
}
impl Default for JustifyContent {
fn default() -> Self {
Self::DEFAULT
}
}
/// Whether to show or hide overflowing items /// Whether to show or hide overflowing items
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Reflect, Serialize, Deserialize)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, Serialize, Deserialize)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum Overflow { pub enum Overflow {
/// Show overflowing items /// Show overflowing items
#[default]
Visible, Visible,
/// Hide overflowing items /// Hide overflowing items
Hidden, Hidden,
} }
impl Overflow {
pub const DEFAULT: Self = Self::Visible;
}
impl Default for Overflow {
fn default() -> Self {
Self::DEFAULT
}
}
/// The strategy used to position this node /// The strategy used to position this node
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum PositionType { pub enum PositionType {
/// Relative to all other nodes with the [`PositionType::Relative`] value /// Relative to all other nodes with the [`PositionType::Relative`] value
#[default]
Relative, Relative,
/// Independent of all other nodes /// Independent of all other nodes
/// ///
@ -420,12 +516,21 @@ pub enum PositionType {
Absolute, Absolute,
} }
impl PositionType {
const DEFAULT: Self = Self::Relative;
}
impl Default for PositionType {
fn default() -> Self {
Self::DEFAULT
}
}
/// Defines if flexbox items appear on a single line or on multiple lines /// Defines if flexbox items appear on a single line or on multiple lines
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum FlexWrap { pub enum FlexWrap {
/// Single line, will overflow if needed /// Single line, will overflow if needed
#[default]
NoWrap, NoWrap,
/// Multiple lines, if needed /// Multiple lines, if needed
Wrap, Wrap,
@ -433,8 +538,18 @@ pub enum FlexWrap {
WrapReverse, WrapReverse,
} }
impl FlexWrap {
const DEFAULT: Self = Self::NoWrap;
}
impl Default for FlexWrap {
fn default() -> Self {
Self::DEFAULT
}
}
/// The calculated size of the node /// The calculated size of the node
#[derive(Component, Default, Copy, Clone, Debug, Reflect)] #[derive(Component, Copy, Clone, Debug, Reflect)]
#[reflect(Component)] #[reflect(Component)]
pub struct CalculatedSize { pub struct CalculatedSize {
/// The size of the node /// The size of the node
@ -443,14 +558,37 @@ pub struct CalculatedSize {
pub preserve_aspect_ratio: bool, pub preserve_aspect_ratio: bool,
} }
impl CalculatedSize {
const DEFAULT: Self = Self {
size: Size::DEFAULT,
preserve_aspect_ratio: false,
};
}
impl Default for CalculatedSize {
fn default() -> Self {
Self::DEFAULT
}
}
/// The background color of the node /// The background color of the node
/// ///
/// This serves as the "fill" color. /// This serves as the "fill" color.
/// When combined with [`UiImage`], tints the provided texture. /// When combined with [`UiImage`], tints the provided texture.
#[derive(Component, Default, Copy, Clone, Debug, Reflect)] #[derive(Component, Copy, Clone, Debug, Reflect)]
#[reflect(Component, Default)] #[reflect(Component, Default)]
pub struct BackgroundColor(pub Color); pub struct BackgroundColor(pub Color);
impl BackgroundColor {
pub const DEFAULT: Self = Self(Color::WHITE);
}
impl Default for BackgroundColor {
fn default() -> Self {
Self::DEFAULT
}
}
impl From<Color> for BackgroundColor { impl From<Color> for BackgroundColor {
fn from(color: Color) -> Self { fn from(color: Color) -> Self {
Self(color) Self(color)