From eb4094bdaf2b76e8cd379e83fbfe65fcae31cffd Mon Sep 17 00:00:00 2001 From: James O'Brien Date: Wed, 4 Jan 2023 19:58:09 +0000 Subject: [PATCH] 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 --- crates/bevy_ui/src/focus.rs | 31 +++-- crates/bevy_ui/src/geometry.rs | 32 ++++- crates/bevy_ui/src/ui_node.rs | 236 ++++++++++++++++++++++++++------- 3 files changed, 238 insertions(+), 61 deletions(-) diff --git a/crates/bevy_ui/src/focus.rs b/crates/bevy_ui/src/focus.rs index c27c6fe041159..aa5327c13ad3a 100644 --- a/crates/bevy_ui/src/focus.rs +++ b/crates/bevy_ui/src/focus.rs @@ -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, /// which fully collapses it during layout calculations. -#[derive( - Component, Copy, Clone, Default, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize, -)] +#[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)] #[reflect(Component, Serialize, Deserialize, PartialEq)] pub enum Interaction { /// The node has been clicked @@ -41,22 +39,39 @@ pub enum Interaction { /// The node has been hovered over Hovered, /// Nothing has happened - #[default] 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 -#[derive( - Component, Copy, Clone, Default, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize, -)] +#[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)] #[reflect(Component, Serialize, Deserialize, PartialEq)] pub enum FocusPolicy { /// Blocks interaction - #[default] Block, /// Lets interaction pass through 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 #[derive(Default)] pub struct State { diff --git a/crates/bevy_ui/src/geometry.rs b/crates/bevy_ui/src/geometry.rs index 52cb28ad2d0db..42eaa5651c665 100644 --- a/crates/bevy_ui/src/geometry.rs +++ b/crates/bevy_ui/src/geometry.rs @@ -119,7 +119,7 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; /// bottom: Val::Px(40.0), /// }; /// ``` -#[derive(Copy, Clone, PartialEq, Debug, Default, Reflect)] +#[derive(Copy, Clone, PartialEq, Debug, Reflect)] #[reflect(PartialEq)] pub struct UiRect { /// The value corresponding to the left side of the UI rect. @@ -133,6 +133,13 @@ pub struct 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. /// /// # Example @@ -152,7 +159,7 @@ impl UiRect { /// assert_eq!(ui_rect.top, Val::Px(30.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 { left, right, @@ -175,7 +182,7 @@ impl UiRect { /// assert_eq!(ui_rect.top, 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 { left: 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. /// /// 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)] pub struct Size { /// The width of the 2-dimensional area. @@ -326,6 +339,11 @@ pub struct Size { } impl Size { + pub const DEFAULT: Self = Self { + width: Val::DEFAULT, + height: Val::DEFAULT, + }; + /// Creates a new [`Size`] from a width and a height. /// /// # Example @@ -355,6 +373,12 @@ impl Size { }; } +impl Default for Size { + fn default() -> Self { + Self::DEFAULT + } +} + impl From<(Val, Val)> for Size { fn from(vals: (Val, Val)) -> Self { Self { diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 6b1dd0343029c..a19f7802df8a6 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -12,7 +12,7 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; use thiserror::Error; /// Describes the size of a UI node -#[derive(Component, Debug, Clone, Default, Reflect)] +#[derive(Component, Debug, Clone, Reflect)] #[reflect(Component, Default)] pub struct Node { /// 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 -#[derive(Copy, Clone, PartialEq, Debug, Default, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum Val { /// No value defined - #[default] Undefined, /// Automatically determine this value Auto, @@ -43,6 +54,16 @@ pub enum Val { Percent(f32), } +impl Val { + pub const DEFAULT: Self = Self::Undefined; +} + +impl Default for Val { + fn default() -> Self { + Self::DEFAULT + } +} + impl Mul for Val { type Output = Val; @@ -243,37 +264,41 @@ pub struct Style { pub gap: Size, } +impl Style { + pub const DEFAULT: Self = Self { + display: Display::DEFAULT, + position_type: PositionType::DEFAULT, + direction: Direction::DEFAULT, + flex_direction: FlexDirection::DEFAULT, + flex_wrap: FlexWrap::DEFAULT, + align_items: AlignItems::DEFAULT, + align_self: AlignSelf::DEFAULT, + align_content: AlignContent::DEFAULT, + justify_content: JustifyContent::DEFAULT, + position: UiRect::DEFAULT, + margin: UiRect::DEFAULT, + padding: UiRect::DEFAULT, + border: UiRect::DEFAULT, + flex_grow: 0.0, + flex_shrink: 1.0, + flex_basis: Val::Auto, + size: Size::AUTO, + min_size: Size::AUTO, + max_size: Size::AUTO, + aspect_ratio: None, + overflow: Overflow::DEFAULT, + gap: Size::UNDEFINED, + }; +} + impl Default for Style { fn default() -> Self { - Self { - display: Default::default(), - position_type: Default::default(), - direction: Default::default(), - flex_direction: Default::default(), - flex_wrap: Default::default(), - align_items: Default::default(), - align_self: Default::default(), - align_content: Default::default(), - justify_content: Default::default(), - position: Default::default(), - margin: Default::default(), - padding: Default::default(), - border: Default::default(), - flex_grow: 0.0, - flex_shrink: 1.0, - flex_basis: Val::Auto, - size: Size::AUTO, - min_size: Size::AUTO, - max_size: Size::AUTO, - aspect_ratio: Default::default(), - overflow: Default::default(), - gap: Size::UNDEFINED, - } + Self::DEFAULT } } /// 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)] pub enum AlignItems { /// Items are aligned at the start @@ -285,16 +310,24 @@ pub enum AlignItems { /// Items are aligned at the baseline Baseline, /// Items are stretched across the whole cross axis - #[default] 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 -#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum AlignSelf { /// Use the value of [`AlignItems`] - #[default] Auto, /// If the parent has [`AlignItems::Center`] only this item will be at the start FlexStart, @@ -308,10 +341,20 @@ pub enum AlignSelf { 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. /// /// 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)] pub enum AlignContent { /// 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 Center, /// Each line will stretch to fill the remaining space - #[default] Stretch, /// Each line fills the space it needs, putting the remaining space, if any /// inbetween the lines @@ -331,14 +373,23 @@ pub enum AlignContent { SpaceAround, } +impl AlignContent { + pub const DEFAULT: Self = Self::Stretch; +} + +impl Default for AlignContent { + fn default() -> Self { + Self::DEFAULT + } +} + /// Defines the text direction /// /// 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)] pub enum Direction { /// Inherit from parent node - #[default] Inherit, /// Text is written left to right LeftToRight, @@ -346,14 +397,23 @@ pub enum Direction { 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. /// /// 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)] pub enum Display { /// Use Flexbox layout model to determine the position of this [`Node`]. - #[default] Flex, /// Use no layout, don't render this node and its children. /// @@ -362,12 +422,21 @@ pub enum Display { 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 -#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum FlexDirection { /// Same way as text direction along the main axis - #[default] Row, /// Flex from top to bottom Column, @@ -377,12 +446,21 @@ pub enum FlexDirection { 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 -#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum JustifyContent { /// Pushed towards the start - #[default] FlexStart, /// Pushed towards the end FlexEnd, @@ -396,23 +474,41 @@ pub enum JustifyContent { 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 -#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Reflect, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum Overflow { /// Show overflowing items - #[default] Visible, /// Hide overflowing items 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 -#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum PositionType { /// Relative to all other nodes with the [`PositionType::Relative`] value - #[default] Relative, /// Independent of all other nodes /// @@ -420,12 +516,21 @@ pub enum PositionType { 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 -#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum FlexWrap { /// Single line, will overflow if needed - #[default] NoWrap, /// Multiple lines, if needed Wrap, @@ -433,8 +538,18 @@ pub enum FlexWrap { WrapReverse, } +impl FlexWrap { + const DEFAULT: Self = Self::NoWrap; +} + +impl Default for FlexWrap { + fn default() -> Self { + Self::DEFAULT + } +} + /// The calculated size of the node -#[derive(Component, Default, Copy, Clone, Debug, Reflect)] +#[derive(Component, Copy, Clone, Debug, Reflect)] #[reflect(Component)] pub struct CalculatedSize { /// The size of the node @@ -443,14 +558,37 @@ pub struct CalculatedSize { 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 /// /// This serves as the "fill" color. /// When combined with [`UiImage`], tints the provided texture. -#[derive(Component, Default, Copy, Clone, Debug, Reflect)] +#[derive(Component, Copy, Clone, Debug, Reflect)] #[reflect(Component, Default)] 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 for BackgroundColor { fn from(color: Color) -> Self { Self(color)