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,
/// 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 {

View File

@ -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 {

View File

@ -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<f32> 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<Color> for BackgroundColor {
fn from(color: Color) -> Self {
Self(color)