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.
This commit is contained in:
Zachary Harrold 2023-08-27 00:00:53 +10:00 committed by GitHub
parent 349dd8bd45
commit 90b3ac7f3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 161 additions and 140 deletions

View File

@ -60,10 +60,17 @@ pub struct UiRect {
impl UiRect { impl UiRect {
pub const DEFAULT: Self = Self { pub const DEFAULT: Self = Self {
left: Val::Px(0.), left: Val::ZERO,
right: Val::Px(0.), right: Val::ZERO,
top: Val::Px(0.), top: Val::ZERO,
bottom: Val::Px(0.), 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. /// 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, /// 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 /// # Example
/// ///
@ -177,8 +184,8 @@ impl UiRect {
/// ///
/// assert_eq!(ui_rect.left, Val::Px(10.0)); /// assert_eq!(ui_rect.left, Val::Px(10.0));
/// assert_eq!(ui_rect.right, 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.top, Val::ZERO);
/// assert_eq!(ui_rect.bottom, Val::Px(0.)); /// assert_eq!(ui_rect.bottom, Val::ZERO);
/// ``` /// ```
pub fn horizontal(value: Val) -> Self { pub fn horizontal(value: Val) -> Self {
UiRect { UiRect {
@ -189,7 +196,7 @@ impl UiRect {
} }
/// Creates a new [`UiRect`] where `top` and `bottom` take the given value, /// 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 /// # Example
/// ///
@ -198,8 +205,8 @@ impl UiRect {
/// # /// #
/// let ui_rect = UiRect::vertical(Val::Px(10.0)); /// let ui_rect = UiRect::vertical(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(0.)); /// assert_eq!(ui_rect.right, Val::ZERO);
/// 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));
/// ``` /// ```
@ -235,7 +242,7 @@ impl UiRect {
} }
/// Creates a new [`UiRect`] where `left` takes the given value, and /// 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 /// # Example
/// ///
@ -245,9 +252,9 @@ impl UiRect {
/// let ui_rect = UiRect::left(Val::Px(10.0)); /// let ui_rect = UiRect::left(Val::Px(10.0));
/// ///
/// assert_eq!(ui_rect.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.right, Val::ZERO);
/// assert_eq!(ui_rect.top, Val::Px(0.)); /// assert_eq!(ui_rect.top, Val::ZERO);
/// assert_eq!(ui_rect.bottom, Val::Px(0.)); /// assert_eq!(ui_rect.bottom, Val::ZERO);
/// ``` /// ```
pub fn left(value: Val) -> Self { pub fn left(value: Val) -> Self {
UiRect { UiRect {
@ -257,7 +264,7 @@ impl UiRect {
} }
/// Creates a new [`UiRect`] where `right` takes the given value, /// 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 /// # Example
/// ///
@ -266,10 +273,10 @@ impl UiRect {
/// # /// #
/// let ui_rect = UiRect::right(Val::Px(10.0)); /// 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.right, Val::Px(10.0));
/// assert_eq!(ui_rect.top, Val::Px(0.)); /// assert_eq!(ui_rect.top, Val::ZERO);
/// assert_eq!(ui_rect.bottom, Val::Px(0.)); /// assert_eq!(ui_rect.bottom, Val::ZERO);
/// ``` /// ```
pub fn right(value: Val) -> Self { pub fn right(value: Val) -> Self {
UiRect { UiRect {
@ -279,7 +286,7 @@ impl UiRect {
} }
/// Creates a new [`UiRect`] where `top` takes the given value, /// 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 /// # Example
/// ///
@ -288,10 +295,10 @@ impl UiRect {
/// # /// #
/// let ui_rect = UiRect::top(Val::Px(10.0)); /// let ui_rect = UiRect::top(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(0.)); /// assert_eq!(ui_rect.right, Val::ZERO);
/// 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(0.)); /// assert_eq!(ui_rect.bottom, Val::ZERO);
/// ``` /// ```
pub fn top(value: Val) -> Self { pub fn top(value: Val) -> Self {
UiRect { UiRect {
@ -301,7 +308,7 @@ impl UiRect {
} }
/// Creates a new [`UiRect`] where `bottom` takes the given value, /// 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 /// # Example
/// ///
@ -310,9 +317,9 @@ impl UiRect {
/// # /// #
/// let ui_rect = UiRect::bottom(Val::Px(10.0)); /// let ui_rect = UiRect::bottom(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(0.)); /// assert_eq!(ui_rect.right, Val::ZERO);
/// assert_eq!(ui_rect.top, Val::Px(0.)); /// assert_eq!(ui_rect.top, Val::ZERO);
/// assert_eq!(ui_rect.bottom, Val::Px(10.0)); /// assert_eq!(ui_rect.bottom, Val::Px(10.0));
/// ``` /// ```
pub fn bottom(value: Val) -> Self { pub fn bottom(value: Val) -> Self {
@ -338,10 +345,10 @@ mod tests {
assert_eq!( assert_eq!(
UiRect::default(), UiRect::default(),
UiRect { UiRect {
left: Val::Px(0.), left: Val::ZERO,
right: Val::Px(0.), right: Val::ZERO,
top: Val::Px(0.), top: Val::ZERO,
bottom: Val::Px(0.) bottom: Val::ZERO
} }
); );
assert_eq!(UiRect::default(), UiRect::DEFAULT); assert_eq!(UiRect::default(), UiRect::DEFAULT);

View File

@ -397,14 +397,15 @@ mod tests {
#[test] #[test]
fn test_convert_from() { fn test_convert_from() {
use sh::TaffyZero;
use taffy::style_helpers as sh; use taffy::style_helpers as sh;
let bevy_style = crate::Style { let bevy_style = crate::Style {
display: Display::Flex, display: Display::Flex,
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
left: Val::Px(0.), left: Val::ZERO,
right: Val::Percent(0.), right: Val::Percent(50.),
top: Val::Auto, top: Val::Px(12.),
bottom: Val::Auto, bottom: Val::Auto,
direction: crate::Direction::Inherit, direction: crate::Direction::Inherit,
flex_direction: FlexDirection::ColumnReverse, flex_direction: FlexDirection::ColumnReverse,
@ -416,36 +417,36 @@ mod tests {
justify_self: JustifySelf::Center, justify_self: JustifySelf::Center,
justify_content: JustifyContent::SpaceEvenly, justify_content: JustifyContent::SpaceEvenly,
margin: UiRect { margin: UiRect {
left: Val::Percent(0.), left: Val::ZERO,
right: Val::Px(0.), right: Val::Px(10.),
top: Val::Auto, top: Val::Percent(15.),
bottom: Val::Auto, bottom: Val::Auto,
}, },
padding: UiRect { padding: UiRect {
left: Val::Percent(0.), left: Val::Percent(13.),
right: Val::Px(0.), right: Val::Px(21.),
top: Val::Percent(0.), top: Val::Auto,
bottom: Val::Percent(0.), bottom: Val::ZERO,
}, },
border: UiRect { border: UiRect {
left: Val::Px(0.), left: Val::Px(14.),
right: Val::Px(0.), right: Val::ZERO,
top: Val::Auto, top: Val::Auto,
bottom: Val::Px(0.), bottom: Val::Percent(31.),
}, },
flex_grow: 1., flex_grow: 1.,
flex_shrink: 0., flex_shrink: 0.,
flex_basis: Val::Px(0.), flex_basis: Val::ZERO,
width: Val::Px(0.), width: Val::ZERO,
height: Val::Auto, height: Val::Auto,
min_width: Val::Px(0.), min_width: Val::ZERO,
min_height: Val::Percent(0.), min_height: Val::ZERO,
max_width: Val::Auto, max_width: Val::Auto,
max_height: Val::Px(0.), max_height: Val::ZERO,
aspect_ratio: None, aspect_ratio: None,
overflow: crate::Overflow::clip(), overflow: crate::Overflow::clip(),
column_gap: Val::Px(0.), column_gap: Val::ZERO,
row_gap: Val::Percent(0.), row_gap: Val::ZERO,
grid_auto_flow: GridAutoFlow::ColumnDense, grid_auto_flow: GridAutoFlow::ColumnDense,
grid_template_rows: vec![ grid_template_rows: vec![
GridTrack::px(10.0), GridTrack::px(10.0),
@ -470,22 +471,22 @@ mod tests {
let taffy_style = from_style(&viewport_values, &bevy_style); let taffy_style = from_style(&viewport_values, &bevy_style);
assert_eq!(taffy_style.display, taffy::style::Display::Flex); assert_eq!(taffy_style.display, taffy::style::Display::Flex);
assert_eq!(taffy_style.position, taffy::style::Position::Absolute); assert_eq!(taffy_style.position, taffy::style::Position::Absolute);
assert!(matches!( assert_eq!(
taffy_style.inset.left, taffy_style.inset.left,
taffy::style::LengthPercentageAuto::Points(_) taffy::style::LengthPercentageAuto::ZERO
)); );
assert!(matches!( assert_eq!(
taffy_style.inset.right, taffy_style.inset.right,
taffy::style::LengthPercentageAuto::Percent(_) taffy::style::LengthPercentageAuto::Percent(0.5)
)); );
assert!(matches!( assert_eq!(
taffy_style.inset.top, taffy_style.inset.top,
taffy::style::LengthPercentageAuto::Auto taffy::style::LengthPercentageAuto::Points(12.)
)); );
assert!(matches!( assert_eq!(
taffy_style.inset.bottom, taffy_style.inset.bottom,
taffy::style::LengthPercentageAuto::Auto taffy::style::LengthPercentageAuto::Auto
)); );
assert_eq!( assert_eq!(
taffy_style.flex_direction, taffy_style.flex_direction,
taffy::style::FlexDirection::ColumnReverse taffy::style::FlexDirection::ColumnReverse
@ -509,93 +510,63 @@ mod tests {
taffy_style.justify_self, taffy_style.justify_self,
Some(taffy::style::JustifySelf::Center) Some(taffy::style::JustifySelf::Center)
); );
assert!(matches!( assert_eq!(
taffy_style.margin.left, taffy_style.margin.left,
taffy::style::LengthPercentageAuto::Percent(_) taffy::style::LengthPercentageAuto::ZERO
)); );
assert!(matches!( assert_eq!(
taffy_style.margin.right, taffy_style.margin.right,
taffy::style::LengthPercentageAuto::Points(_) taffy::style::LengthPercentageAuto::Points(10.)
)); );
assert!(matches!( assert_eq!(
taffy_style.margin.top, taffy_style.margin.top,
taffy::style::LengthPercentageAuto::Auto taffy::style::LengthPercentageAuto::Percent(0.15)
)); );
assert!(matches!( assert_eq!(
taffy_style.margin.bottom, taffy_style.margin.bottom,
taffy::style::LengthPercentageAuto::Auto taffy::style::LengthPercentageAuto::Auto
)); );
assert!(matches!( assert_eq!(
taffy_style.padding.left, taffy_style.padding.left,
taffy::style::LengthPercentage::Percent(_) taffy::style::LengthPercentage::Percent(0.13)
)); );
assert!(matches!( assert_eq!(
taffy_style.padding.right, taffy_style.padding.right,
taffy::style::LengthPercentage::Points(_) taffy::style::LengthPercentage::Points(21.)
)); );
assert!(matches!( assert_eq!(
taffy_style.padding.top, taffy_style.padding.top,
taffy::style::LengthPercentage::Percent(_) taffy::style::LengthPercentage::ZERO
)); );
assert!(matches!( assert_eq!(
taffy_style.padding.bottom, taffy_style.padding.bottom,
taffy::style::LengthPercentage::Percent(_) taffy::style::LengthPercentage::ZERO
)); );
assert!(matches!( assert_eq!(
taffy_style.border.left, taffy_style.border.left,
taffy::style::LengthPercentage::Points(_) taffy::style::LengthPercentage::Points(14.)
)); );
assert!(matches!( assert_eq!(
taffy_style.border.right, taffy_style.border.right,
taffy::style::LengthPercentage::Points(_) taffy::style::LengthPercentage::ZERO
)); );
assert!(matches!( assert_eq!(taffy_style.border.top, taffy::style::LengthPercentage::ZERO);
taffy_style.border.top, assert_eq!(
taffy::style::LengthPercentage::Points(_)
));
assert!(matches!(
taffy_style.border.bottom, 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_grow, 1.);
assert_eq!(taffy_style.flex_shrink, 0.); assert_eq!(taffy_style.flex_shrink, 0.);
assert!(matches!( assert_eq!(taffy_style.flex_basis, taffy::style::Dimension::ZERO);
taffy_style.flex_basis, assert_eq!(taffy_style.size.width, taffy::style::Dimension::ZERO);
taffy::style::Dimension::Points(_) assert_eq!(taffy_style.size.height, taffy::style::Dimension::Auto);
)); assert_eq!(taffy_style.min_size.width, taffy::style::Dimension::ZERO);
assert!(matches!( assert_eq!(taffy_style.min_size.height, taffy::style::Dimension::ZERO);
taffy_style.size.width, assert_eq!(taffy_style.max_size.width, taffy::style::Dimension::Auto);
taffy::style::Dimension::Points(_) assert_eq!(taffy_style.max_size.height, taffy::style::Dimension::ZERO);
));
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.aspect_ratio, None); assert_eq!(taffy_style.aspect_ratio, None);
assert_eq!( assert_eq!(taffy_style.gap.width, taffy::style::LengthPercentage::ZERO);
taffy_style.gap.width, assert_eq!(taffy_style.gap.height, taffy::style::LengthPercentage::ZERO);
taffy::style::LengthPercentage::Points(0.)
);
assert_eq!(
taffy_style.gap.height,
taffy::style::LengthPercentage::Percent(0.)
);
assert_eq!( assert_eq!(
taffy_style.grid_auto_flow, taffy_style.grid_auto_flow,
taffy::style::GridAutoFlow::ColumnDense taffy::style::GridAutoFlow::ColumnDense

View File

@ -82,7 +82,7 @@ impl Default for Node {
/// ///
/// This enum allows specifying values for various [`Style`] properties in different units, /// This enum allows specifying values for various [`Style`] properties in different units,
/// such as logical pixels, percentages, or automatically determined values. /// 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)] #[reflect(PartialEq, Serialize, Deserialize)]
pub enum Val { pub enum Val {
/// Automatically determine the value based on the context and other [`Style`] properties. /// Automatically determine the value based on the context and other [`Style`] properties.
@ -112,8 +112,51 @@ pub enum Val {
VMax(f32), 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 { impl Val {
pub const DEFAULT: Self = Self::Auto; pub const DEFAULT: Self = Self::Auto;
pub const ZERO: Self = Self::Px(0.0);
} }
impl Default for Val { impl Default for Val {
@ -599,8 +642,8 @@ impl Style {
max_height: Val::Auto, max_height: Val::Auto,
aspect_ratio: None, aspect_ratio: None,
overflow: Overflow::DEFAULT, overflow: Overflow::DEFAULT,
row_gap: Val::Px(0.0), row_gap: Val::ZERO,
column_gap: Val::Px(0.0), column_gap: Val::ZERO,
grid_auto_flow: GridAutoFlow::DEFAULT, grid_auto_flow: GridAutoFlow::DEFAULT,
grid_template_rows: Vec::new(), grid_template_rows: Vec::new(),
grid_template_columns: Vec::new(), grid_template_columns: Vec::new(),

View File

@ -237,7 +237,7 @@ fn setup(
TextBundle::from_section(label, label_text_style.clone()) TextBundle::from_section(label, label_text_style.clone())
.with_style(Style { .with_style(Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(0.), bottom: Val::ZERO,
..default() ..default()
}) })
.with_no_wrap(), .with_no_wrap(),

View File

@ -98,7 +98,7 @@ fn setup(
style: Style { style: Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(130.0), top: Val::Px(130.0),
right: Val::Px(0.0), right: Val::ZERO,
..default() ..default()
}, },
transform: Transform { transform: Transform {

View File

@ -50,7 +50,7 @@ fn atlas_render_system(
image: texture_atlas.texture.clone().into(), image: texture_atlas.texture.clone().into(),
style: Style { style: Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(0.0), top: Val::ZERO,
left: Val::Px(512.0 * x_offset), left: Val::Px(512.0 * x_offset),
..default() ..default()
}, },
@ -83,7 +83,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResM
background_color: Color::NONE.into(), background_color: Color::NONE.into(),
style: Style { style: Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(0.0), bottom: Val::ZERO,
..default() ..default()
}, },
..default() ..default()