From 90b3ac7f3aca3a8cf9fd42055c32188286cb613a Mon Sep 17 00:00:00 2001 From: Zachary Harrold Date: Sun, 27 Aug 2023 00:00:53 +1000 Subject: [PATCH] Added `Val::ZERO` Constant (#9566) # Objective - Fixes #9533 ## Solution * Added `Val::ZERO` as a constant which is defined as `Val::Px(0.)`. * Added manual `PartialEq` implementation for `Val` which allows any zero value to equal any other zero value. E.g., `Val::Px(0.) == Val::Percent(0.)` etc. This is technically a breaking change, as `Val::Px(0.) == Val::Percent(0.)` now equals `true` instead of `false` (as an example) * Replaced instances of `Val::Px(0.)`, `Val::Percent(0.)`, etc. with `Val::ZERO` * Fixed `bevy_ui::layout::convert::tests::test_convert_from` test to account for Taffy not equating `Points(0.)` and `Percent(0.)`. These tests now use `assert_eq!(...)` instead of `assert!(matches!(...))` which gives easier to diagnose error messages. --- crates/bevy_ui/src/geometry.rs | 67 +++++----- crates/bevy_ui/src/layout/convert.rs | 177 +++++++++++---------------- crates/bevy_ui/src/ui_node.rs | 49 +++++++- examples/3d/blend_modes.rs | 2 +- examples/3d/pbr.rs | 2 +- examples/ui/font_atlas_debug.rs | 4 +- 6 files changed, 161 insertions(+), 140 deletions(-) diff --git a/crates/bevy_ui/src/geometry.rs b/crates/bevy_ui/src/geometry.rs index aca0c10b016a1..8f940ac0ff2da 100644 --- a/crates/bevy_ui/src/geometry.rs +++ b/crates/bevy_ui/src/geometry.rs @@ -60,10 +60,17 @@ pub struct UiRect { impl UiRect { pub const DEFAULT: Self = Self { - left: Val::Px(0.), - right: Val::Px(0.), - top: Val::Px(0.), - bottom: Val::Px(0.), + left: Val::ZERO, + right: Val::ZERO, + top: Val::ZERO, + bottom: Val::ZERO, + }; + + pub const ZERO: Self = Self { + left: Val::ZERO, + right: Val::ZERO, + top: Val::ZERO, + bottom: Val::ZERO, }; /// Creates a new [`UiRect`] from the values specified. @@ -166,7 +173,7 @@ impl UiRect { } /// Creates a new [`UiRect`] where `left` and `right` take the given value, - /// and `top` and `bottom` set to zero `Val::Px(0.)`. + /// and `top` and `bottom` set to zero `Val::ZERO`. /// /// # Example /// @@ -177,8 +184,8 @@ impl UiRect { /// /// assert_eq!(ui_rect.left, Val::Px(10.0)); /// assert_eq!(ui_rect.right, Val::Px(10.0)); - /// assert_eq!(ui_rect.top, Val::Px(0.)); - /// assert_eq!(ui_rect.bottom, Val::Px(0.)); + /// assert_eq!(ui_rect.top, Val::ZERO); + /// assert_eq!(ui_rect.bottom, Val::ZERO); /// ``` pub fn horizontal(value: Val) -> Self { UiRect { @@ -189,7 +196,7 @@ impl UiRect { } /// Creates a new [`UiRect`] where `top` and `bottom` take the given value, - /// and `left` and `right` are set to `Val::Px(0.)`. + /// and `left` and `right` are set to `Val::ZERO`. /// /// # Example /// @@ -198,8 +205,8 @@ impl UiRect { /// # /// let ui_rect = UiRect::vertical(Val::Px(10.0)); /// - /// assert_eq!(ui_rect.left, Val::Px(0.)); - /// assert_eq!(ui_rect.right, Val::Px(0.)); + /// assert_eq!(ui_rect.left, Val::ZERO); + /// assert_eq!(ui_rect.right, Val::ZERO); /// assert_eq!(ui_rect.top, Val::Px(10.0)); /// assert_eq!(ui_rect.bottom, Val::Px(10.0)); /// ``` @@ -235,7 +242,7 @@ impl UiRect { } /// Creates a new [`UiRect`] where `left` takes the given value, and - /// the other fields are set to `Val::Px(0.)`. + /// the other fields are set to `Val::ZERO`. /// /// # Example /// @@ -245,9 +252,9 @@ impl UiRect { /// let ui_rect = UiRect::left(Val::Px(10.0)); /// /// assert_eq!(ui_rect.left, Val::Px(10.0)); - /// assert_eq!(ui_rect.right, Val::Px(0.)); - /// assert_eq!(ui_rect.top, Val::Px(0.)); - /// assert_eq!(ui_rect.bottom, Val::Px(0.)); + /// assert_eq!(ui_rect.right, Val::ZERO); + /// assert_eq!(ui_rect.top, Val::ZERO); + /// assert_eq!(ui_rect.bottom, Val::ZERO); /// ``` pub fn left(value: Val) -> Self { UiRect { @@ -257,7 +264,7 @@ impl UiRect { } /// Creates a new [`UiRect`] where `right` takes the given value, - /// and the other fields are set to `Val::Px(0.)`. + /// and the other fields are set to `Val::ZERO`. /// /// # Example /// @@ -266,10 +273,10 @@ impl UiRect { /// # /// let ui_rect = UiRect::right(Val::Px(10.0)); /// - /// assert_eq!(ui_rect.left, Val::Px(0.)); + /// assert_eq!(ui_rect.left, Val::ZERO); /// assert_eq!(ui_rect.right, Val::Px(10.0)); - /// assert_eq!(ui_rect.top, Val::Px(0.)); - /// assert_eq!(ui_rect.bottom, Val::Px(0.)); + /// assert_eq!(ui_rect.top, Val::ZERO); + /// assert_eq!(ui_rect.bottom, Val::ZERO); /// ``` pub fn right(value: Val) -> Self { UiRect { @@ -279,7 +286,7 @@ impl UiRect { } /// Creates a new [`UiRect`] where `top` takes the given value, - /// and the other fields are set to `Val::Px(0.)`. + /// and the other fields are set to `Val::ZERO`. /// /// # Example /// @@ -288,10 +295,10 @@ impl UiRect { /// # /// let ui_rect = UiRect::top(Val::Px(10.0)); /// - /// assert_eq!(ui_rect.left, Val::Px(0.)); - /// assert_eq!(ui_rect.right, Val::Px(0.)); + /// assert_eq!(ui_rect.left, Val::ZERO); + /// assert_eq!(ui_rect.right, Val::ZERO); /// assert_eq!(ui_rect.top, Val::Px(10.0)); - /// assert_eq!(ui_rect.bottom, Val::Px(0.)); + /// assert_eq!(ui_rect.bottom, Val::ZERO); /// ``` pub fn top(value: Val) -> Self { UiRect { @@ -301,7 +308,7 @@ impl UiRect { } /// Creates a new [`UiRect`] where `bottom` takes the given value, - /// and the other fields are set to `Val::Px(0.)`. + /// and the other fields are set to `Val::ZERO`. /// /// # Example /// @@ -310,9 +317,9 @@ impl UiRect { /// # /// let ui_rect = UiRect::bottom(Val::Px(10.0)); /// - /// assert_eq!(ui_rect.left, Val::Px(0.)); - /// assert_eq!(ui_rect.right, Val::Px(0.)); - /// assert_eq!(ui_rect.top, Val::Px(0.)); + /// assert_eq!(ui_rect.left, Val::ZERO); + /// assert_eq!(ui_rect.right, Val::ZERO); + /// assert_eq!(ui_rect.top, Val::ZERO); /// assert_eq!(ui_rect.bottom, Val::Px(10.0)); /// ``` pub fn bottom(value: Val) -> Self { @@ -338,10 +345,10 @@ mod tests { assert_eq!( UiRect::default(), UiRect { - left: Val::Px(0.), - right: Val::Px(0.), - top: Val::Px(0.), - bottom: Val::Px(0.) + left: Val::ZERO, + right: Val::ZERO, + top: Val::ZERO, + bottom: Val::ZERO } ); assert_eq!(UiRect::default(), UiRect::DEFAULT); diff --git a/crates/bevy_ui/src/layout/convert.rs b/crates/bevy_ui/src/layout/convert.rs index d3fe37679849d..1f5237a85da49 100644 --- a/crates/bevy_ui/src/layout/convert.rs +++ b/crates/bevy_ui/src/layout/convert.rs @@ -397,14 +397,15 @@ mod tests { #[test] fn test_convert_from() { + use sh::TaffyZero; use taffy::style_helpers as sh; let bevy_style = crate::Style { display: Display::Flex, position_type: PositionType::Absolute, - left: Val::Px(0.), - right: Val::Percent(0.), - top: Val::Auto, + left: Val::ZERO, + right: Val::Percent(50.), + top: Val::Px(12.), bottom: Val::Auto, direction: crate::Direction::Inherit, flex_direction: FlexDirection::ColumnReverse, @@ -416,36 +417,36 @@ mod tests { justify_self: JustifySelf::Center, justify_content: JustifyContent::SpaceEvenly, margin: UiRect { - left: Val::Percent(0.), - right: Val::Px(0.), - top: Val::Auto, + left: Val::ZERO, + right: Val::Px(10.), + top: Val::Percent(15.), bottom: Val::Auto, }, padding: UiRect { - left: Val::Percent(0.), - right: Val::Px(0.), - top: Val::Percent(0.), - bottom: Val::Percent(0.), + left: Val::Percent(13.), + right: Val::Px(21.), + top: Val::Auto, + bottom: Val::ZERO, }, border: UiRect { - left: Val::Px(0.), - right: Val::Px(0.), + left: Val::Px(14.), + right: Val::ZERO, top: Val::Auto, - bottom: Val::Px(0.), + bottom: Val::Percent(31.), }, flex_grow: 1., flex_shrink: 0., - flex_basis: Val::Px(0.), - width: Val::Px(0.), + flex_basis: Val::ZERO, + width: Val::ZERO, height: Val::Auto, - min_width: Val::Px(0.), - min_height: Val::Percent(0.), + min_width: Val::ZERO, + min_height: Val::ZERO, max_width: Val::Auto, - max_height: Val::Px(0.), + max_height: Val::ZERO, aspect_ratio: None, overflow: crate::Overflow::clip(), - column_gap: Val::Px(0.), - row_gap: Val::Percent(0.), + column_gap: Val::ZERO, + row_gap: Val::ZERO, grid_auto_flow: GridAutoFlow::ColumnDense, grid_template_rows: vec![ GridTrack::px(10.0), @@ -470,22 +471,22 @@ mod tests { let taffy_style = from_style(&viewport_values, &bevy_style); assert_eq!(taffy_style.display, taffy::style::Display::Flex); assert_eq!(taffy_style.position, taffy::style::Position::Absolute); - assert!(matches!( + assert_eq!( taffy_style.inset.left, - taffy::style::LengthPercentageAuto::Points(_) - )); - assert!(matches!( + taffy::style::LengthPercentageAuto::ZERO + ); + assert_eq!( taffy_style.inset.right, - taffy::style::LengthPercentageAuto::Percent(_) - )); - assert!(matches!( + taffy::style::LengthPercentageAuto::Percent(0.5) + ); + assert_eq!( taffy_style.inset.top, - taffy::style::LengthPercentageAuto::Auto - )); - assert!(matches!( + taffy::style::LengthPercentageAuto::Points(12.) + ); + assert_eq!( taffy_style.inset.bottom, taffy::style::LengthPercentageAuto::Auto - )); + ); assert_eq!( taffy_style.flex_direction, taffy::style::FlexDirection::ColumnReverse @@ -509,93 +510,63 @@ mod tests { taffy_style.justify_self, Some(taffy::style::JustifySelf::Center) ); - assert!(matches!( + assert_eq!( taffy_style.margin.left, - taffy::style::LengthPercentageAuto::Percent(_) - )); - assert!(matches!( + taffy::style::LengthPercentageAuto::ZERO + ); + assert_eq!( taffy_style.margin.right, - taffy::style::LengthPercentageAuto::Points(_) - )); - assert!(matches!( + taffy::style::LengthPercentageAuto::Points(10.) + ); + assert_eq!( taffy_style.margin.top, - taffy::style::LengthPercentageAuto::Auto - )); - assert!(matches!( + taffy::style::LengthPercentageAuto::Percent(0.15) + ); + assert_eq!( taffy_style.margin.bottom, taffy::style::LengthPercentageAuto::Auto - )); - assert!(matches!( + ); + assert_eq!( taffy_style.padding.left, - taffy::style::LengthPercentage::Percent(_) - )); - assert!(matches!( + taffy::style::LengthPercentage::Percent(0.13) + ); + assert_eq!( taffy_style.padding.right, - taffy::style::LengthPercentage::Points(_) - )); - assert!(matches!( + taffy::style::LengthPercentage::Points(21.) + ); + assert_eq!( taffy_style.padding.top, - taffy::style::LengthPercentage::Percent(_) - )); - assert!(matches!( + taffy::style::LengthPercentage::ZERO + ); + assert_eq!( taffy_style.padding.bottom, - taffy::style::LengthPercentage::Percent(_) - )); - assert!(matches!( + taffy::style::LengthPercentage::ZERO + ); + assert_eq!( taffy_style.border.left, - taffy::style::LengthPercentage::Points(_) - )); - assert!(matches!( + taffy::style::LengthPercentage::Points(14.) + ); + assert_eq!( taffy_style.border.right, - taffy::style::LengthPercentage::Points(_) - )); - assert!(matches!( - taffy_style.border.top, - taffy::style::LengthPercentage::Points(_) - )); - assert!(matches!( + taffy::style::LengthPercentage::ZERO + ); + assert_eq!(taffy_style.border.top, taffy::style::LengthPercentage::ZERO); + assert_eq!( taffy_style.border.bottom, - taffy::style::LengthPercentage::Points(_) - )); + taffy::style::LengthPercentage::Percent(0.31) + ); assert_eq!(taffy_style.flex_grow, 1.); assert_eq!(taffy_style.flex_shrink, 0.); - assert!(matches!( - taffy_style.flex_basis, - taffy::style::Dimension::Points(_) - )); - assert!(matches!( - taffy_style.size.width, - taffy::style::Dimension::Points(_) - )); - assert!(matches!( - taffy_style.size.height, - taffy::style::Dimension::Auto - )); - assert!(matches!( - taffy_style.min_size.width, - taffy::style::Dimension::Points(_) - )); - assert!(matches!( - taffy_style.min_size.height, - taffy::style::Dimension::Percent(_) - )); - assert!(matches!( - taffy_style.max_size.width, - taffy::style::Dimension::Auto - )); - assert!(matches!( - taffy_style.max_size.height, - taffy::style::Dimension::Points(_) - )); + assert_eq!(taffy_style.flex_basis, taffy::style::Dimension::ZERO); + assert_eq!(taffy_style.size.width, taffy::style::Dimension::ZERO); + assert_eq!(taffy_style.size.height, taffy::style::Dimension::Auto); + assert_eq!(taffy_style.min_size.width, taffy::style::Dimension::ZERO); + assert_eq!(taffy_style.min_size.height, taffy::style::Dimension::ZERO); + assert_eq!(taffy_style.max_size.width, taffy::style::Dimension::Auto); + assert_eq!(taffy_style.max_size.height, taffy::style::Dimension::ZERO); assert_eq!(taffy_style.aspect_ratio, None); - assert_eq!( - taffy_style.gap.width, - taffy::style::LengthPercentage::Points(0.) - ); - assert_eq!( - taffy_style.gap.height, - taffy::style::LengthPercentage::Percent(0.) - ); + assert_eq!(taffy_style.gap.width, taffy::style::LengthPercentage::ZERO); + assert_eq!(taffy_style.gap.height, taffy::style::LengthPercentage::ZERO); assert_eq!( taffy_style.grid_auto_flow, taffy::style::GridAutoFlow::ColumnDense diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index ebeb421814b5c..435a14b1c01f8 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -82,7 +82,7 @@ impl Default for Node { /// /// This enum allows specifying values for various [`Style`] properties in different units, /// such as logical pixels, percentages, or automatically determined values. -#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum Val { /// Automatically determine the value based on the context and other [`Style`] properties. @@ -112,8 +112,51 @@ pub enum Val { VMax(f32), } +impl PartialEq for Val { + fn eq(&self, other: &Self) -> bool { + let same_unit = matches!( + (self, other), + (Self::Auto, Self::Auto) + | (Self::Px(_), Self::Px(_)) + | (Self::Percent(_), Self::Percent(_)) + | (Self::Vw(_), Self::Vw(_)) + | (Self::Vh(_), Self::Vh(_)) + | (Self::VMin(_), Self::VMin(_)) + | (Self::VMax(_), Self::VMax(_)) + ); + + let left = match self { + Self::Auto => None, + Self::Px(v) + | Self::Percent(v) + | Self::Vw(v) + | Self::Vh(v) + | Self::VMin(v) + | Self::VMax(v) => Some(v), + }; + + let right = match other { + Self::Auto => None, + Self::Px(v) + | Self::Percent(v) + | Self::Vw(v) + | Self::Vh(v) + | Self::VMin(v) + | Self::VMax(v) => Some(v), + }; + + match (same_unit, left, right) { + (true, a, b) => a == b, + // All zero-value variants are considered equal. + (false, Some(&a), Some(&b)) => a == 0. && b == 0., + _ => false, + } + } +} + impl Val { pub const DEFAULT: Self = Self::Auto; + pub const ZERO: Self = Self::Px(0.0); } impl Default for Val { @@ -599,8 +642,8 @@ impl Style { max_height: Val::Auto, aspect_ratio: None, overflow: Overflow::DEFAULT, - row_gap: Val::Px(0.0), - column_gap: Val::Px(0.0), + row_gap: Val::ZERO, + column_gap: Val::ZERO, grid_auto_flow: GridAutoFlow::DEFAULT, grid_template_rows: Vec::new(), grid_template_columns: Vec::new(), diff --git a/examples/3d/blend_modes.rs b/examples/3d/blend_modes.rs index 6a171b34131da..1b6b43059d061 100644 --- a/examples/3d/blend_modes.rs +++ b/examples/3d/blend_modes.rs @@ -237,7 +237,7 @@ fn setup( TextBundle::from_section(label, label_text_style.clone()) .with_style(Style { position_type: PositionType::Absolute, - bottom: Val::Px(0.), + bottom: Val::ZERO, ..default() }) .with_no_wrap(), diff --git a/examples/3d/pbr.rs b/examples/3d/pbr.rs index 2bbc62a5edc51..b35e4bd8e4682 100644 --- a/examples/3d/pbr.rs +++ b/examples/3d/pbr.rs @@ -98,7 +98,7 @@ fn setup( style: Style { position_type: PositionType::Absolute, top: Val::Px(130.0), - right: Val::Px(0.0), + right: Val::ZERO, ..default() }, transform: Transform { diff --git a/examples/ui/font_atlas_debug.rs b/examples/ui/font_atlas_debug.rs index 54f1fe42f975d..4f8baf23ac118 100644 --- a/examples/ui/font_atlas_debug.rs +++ b/examples/ui/font_atlas_debug.rs @@ -50,7 +50,7 @@ fn atlas_render_system( image: texture_atlas.texture.clone().into(), style: Style { position_type: PositionType::Absolute, - top: Val::Px(0.0), + top: Val::ZERO, left: Val::Px(512.0 * x_offset), ..default() }, @@ -83,7 +83,7 @@ fn setup(mut commands: Commands, asset_server: Res, mut state: ResM background_color: Color::NONE.into(), style: Style { position_type: PositionType::Absolute, - bottom: Val::Px(0.0), + bottom: Val::ZERO, ..default() }, ..default()