
# Objective - Migrate changes from #3503. ## Solution - Change `Size<T>` and `UiRect<T>` to `Size` and `UiRect` using `Val`. - Implement `Sub`, `SubAssign`, `Mul`, `MulAssign`, `Div` and `DivAssign` for `Val`. - Update tests for `Size`. --- ## Changelog ### Changed - The generic `T` of `Size` and `UiRect` got removed and instead they both now always use `Val`. ## Migration Guide - The generic `T` of `Size` and `UiRect` got removed and instead they both now always use `Val`. If you used a `Size<f32>` consider replacing it with a `Vec2` which is way more powerful. Co-authored-by: KDecay <KDecayMusic@protonmail.com>
343 lines
8.9 KiB
Rust
343 lines
8.9 KiB
Rust
use crate::Val;
|
|
use bevy_math::Vec2;
|
|
use bevy_reflect::Reflect;
|
|
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
|
|
|
|
/// A type which is commonly used to define positions, margins, paddings and borders.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ## Position
|
|
///
|
|
/// A position is used to determine where to place a UI element.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{UiRect, Val};
|
|
/// # use bevy_utils::default;
|
|
/// #
|
|
/// let position = UiRect {
|
|
/// left: Val::Px(100.0),
|
|
/// top: Val::Px(50.0),
|
|
/// ..default()
|
|
/// };
|
|
/// ```
|
|
///
|
|
/// If you define opposite sides of the position, the size of the UI element will automatically be calculated
|
|
/// if not explicitly specified. This means that if you have a [`Size`] that uses [`Val::Undefined`](crate::Val::Undefined)
|
|
/// as a width and height, the size would be determined by the window size and the values specified in the position.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{UiRect, Val};
|
|
/// #
|
|
/// let position = UiRect {
|
|
/// left: Val::Px(100.0),
|
|
/// right: Val::Px(200.0),
|
|
/// top: Val::Px(300.0),
|
|
/// bottom: Val::Px(400.0),
|
|
/// };
|
|
/// ```
|
|
///
|
|
/// To determine the width of the UI element you have to take the width of the window and subtract it by the
|
|
/// left and right values of the position. To determine the height of the UI element you have to take the height
|
|
/// of the window and subtract it by the top and bottom values of the position. If we had a window with a width
|
|
/// and height of 1000px, the UI element declared above would have a width of 700px and a height of 300px.
|
|
///
|
|
/// ```
|
|
/// // Size of the window
|
|
/// let window_width = 1000.0;
|
|
/// let window_height = 1000.0;
|
|
///
|
|
/// // Values of the position
|
|
/// let left = 100.0;
|
|
/// let right = 200.0;
|
|
/// let top = 300.0;
|
|
/// let bottom = 400.0;
|
|
///
|
|
/// // Calculation to get the size of the UI element
|
|
/// let ui_element_width = window_width - left - right;
|
|
/// let ui_element_height = window_height - top - bottom;
|
|
///
|
|
/// assert_eq!(ui_element_width, 700.0);
|
|
/// assert_eq!(ui_element_height, 300.0);
|
|
/// ```
|
|
///
|
|
/// If you define a [`Size`] and also all four sides of the position, the top and left values of the position
|
|
/// are used to determine where to place the UI element. The size will not be calculated using the bottom and
|
|
/// right values of the position because the size of the UI element is already explicitly specified.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{UiRect, Size, Val, Style};
|
|
/// # use bevy_utils::default;
|
|
/// #
|
|
/// let style = Style {
|
|
/// position: UiRect { // Defining all four sides
|
|
/// left: Val::Px(100.0),
|
|
/// right: Val::Px(200.0),
|
|
/// top: Val::Px(300.0),
|
|
/// bottom: Val::Px(400.0),
|
|
/// },
|
|
/// size: Size::new(Val::Percent(100.0), Val::Percent(50.0)), // but also explicitly specifying a size
|
|
/// ..default()
|
|
/// };
|
|
/// ```
|
|
///
|
|
/// ## Margin
|
|
///
|
|
/// A margin is used to create space around UI elements, outside of any defined borders.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{UiRect, Val};
|
|
/// #
|
|
/// let margin = UiRect::all(Val::Auto); // Centers the UI element
|
|
/// ```
|
|
///
|
|
/// ## Padding
|
|
///
|
|
/// A padding is used to create space around UI elements, inside of any defined borders.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{UiRect, Val};
|
|
/// #
|
|
/// let padding = UiRect {
|
|
/// left: Val::Px(10.0),
|
|
/// right: Val::Px(20.0),
|
|
/// top: Val::Px(30.0),
|
|
/// bottom: Val::Px(40.0),
|
|
/// };
|
|
/// ```
|
|
///
|
|
/// ## Borders
|
|
///
|
|
/// A border is used to define the width of the border of a UI element.
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{UiRect, Val};
|
|
/// #
|
|
/// let border = UiRect {
|
|
/// left: Val::Px(10.0),
|
|
/// right: Val::Px(20.0),
|
|
/// top: Val::Px(30.0),
|
|
/// bottom: Val::Px(40.0),
|
|
/// };
|
|
/// ```
|
|
#[derive(Copy, Clone, PartialEq, Debug, Default, Reflect)]
|
|
#[reflect(PartialEq)]
|
|
pub struct UiRect {
|
|
/// The value corresponding to the left side of the UI rect.
|
|
pub left: Val,
|
|
/// The value corresponding to the right side of the UI rect.
|
|
pub right: Val,
|
|
/// The value corresponding to the top side of the UI rect.
|
|
pub top: Val,
|
|
/// The value corresponding to the bottom side of the UI rect.
|
|
pub bottom: Val,
|
|
}
|
|
|
|
impl UiRect {
|
|
/// Creates a new [`UiRect`] from the values specified.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{UiRect, Val};
|
|
/// #
|
|
/// let ui_rect = UiRect::new(
|
|
/// Val::Px(10.0),
|
|
/// Val::Px(20.0),
|
|
/// Val::Px(30.0),
|
|
/// Val::Px(40.0),
|
|
/// );
|
|
///
|
|
/// assert_eq!(ui_rect.left, Val::Px(10.0));
|
|
/// assert_eq!(ui_rect.right, Val::Px(20.0));
|
|
/// 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 {
|
|
UiRect {
|
|
left,
|
|
right,
|
|
top,
|
|
bottom,
|
|
}
|
|
}
|
|
|
|
/// Creates a new [`UiRect`] where all sides have the same value.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{UiRect, Val};
|
|
/// #
|
|
/// let ui_rect = UiRect::all(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.top, Val::Px(10.0));
|
|
/// assert_eq!(ui_rect.bottom, Val::Px(10.0));
|
|
/// ```
|
|
pub fn all(value: Val) -> Self {
|
|
UiRect {
|
|
left: value,
|
|
right: value,
|
|
top: value,
|
|
bottom: value,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 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)]
|
|
#[reflect(PartialEq)]
|
|
pub struct Size {
|
|
/// The width of the 2-dimensional area.
|
|
pub width: Val,
|
|
/// The height of the 2-dimensional area.
|
|
pub height: Val,
|
|
}
|
|
|
|
impl Size {
|
|
/// Creates a new [`Size`] from a width and a height.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # use bevy_ui::{Size, Val};
|
|
/// #
|
|
/// let size = Size::new(Val::Px(100.0), Val::Px(200.0));
|
|
///
|
|
/// assert_eq!(size.width, Val::Px(100.0));
|
|
/// assert_eq!(size.height, Val::Px(200.0));
|
|
/// ```
|
|
pub fn new(width: Val, height: Val) -> Self {
|
|
Size { width, height }
|
|
}
|
|
}
|
|
|
|
impl Add<Vec2> for Size {
|
|
type Output = Size;
|
|
|
|
fn add(self, rhs: Vec2) -> Self::Output {
|
|
Self {
|
|
width: self.width + rhs.x,
|
|
height: self.height + rhs.y,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AddAssign<Vec2> for Size {
|
|
fn add_assign(&mut self, rhs: Vec2) {
|
|
self.width += rhs.x;
|
|
self.height += rhs.y;
|
|
}
|
|
}
|
|
|
|
impl Sub<Vec2> for Size {
|
|
type Output = Size;
|
|
|
|
fn sub(self, rhs: Vec2) -> Self::Output {
|
|
Self {
|
|
width: self.width - rhs.x,
|
|
height: self.height - rhs.y,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SubAssign<Vec2> for Size {
|
|
fn sub_assign(&mut self, rhs: Vec2) {
|
|
self.width -= rhs.x;
|
|
self.height -= rhs.y;
|
|
}
|
|
}
|
|
|
|
impl Mul<f32> for Size {
|
|
type Output = Size;
|
|
|
|
fn mul(self, rhs: f32) -> Self::Output {
|
|
Self::Output {
|
|
width: self.width * rhs,
|
|
height: self.height * rhs,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MulAssign<f32> for Size {
|
|
fn mul_assign(&mut self, rhs: f32) {
|
|
self.width *= rhs;
|
|
self.height *= rhs;
|
|
}
|
|
}
|
|
|
|
impl Div<f32> for Size {
|
|
type Output = Size;
|
|
|
|
fn div(self, rhs: f32) -> Self::Output {
|
|
Self::Output {
|
|
width: self.width / rhs,
|
|
height: self.height / rhs,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DivAssign<f32> for Size {
|
|
fn div_assign(&mut self, rhs: f32) {
|
|
self.width /= rhs;
|
|
self.height /= rhs;
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_size_add() {
|
|
assert_eq!(
|
|
Size::new(Val::Px(10.), Val::Px(10.)) + Vec2::new(10., 10.),
|
|
Size::new(Val::Px(20.), Val::Px(20.))
|
|
);
|
|
|
|
let mut size = Size::new(Val::Px(10.), Val::Px(10.));
|
|
size += Vec2::new(10., 10.);
|
|
assert_eq!(size, Size::new(Val::Px(20.), Val::Px(20.)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_size_sub() {
|
|
assert_eq!(
|
|
Size::new(Val::Px(20.), Val::Px(20.)) - Vec2::new(10., 10.),
|
|
Size::new(Val::Px(10.), Val::Px(10.))
|
|
);
|
|
|
|
let mut size = Size::new(Val::Px(20.), Val::Px(20.));
|
|
size -= Vec2::new(10., 10.);
|
|
assert_eq!(size, Size::new(Val::Px(10.), Val::Px(10.)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_size_mul() {
|
|
assert_eq!(
|
|
Size::new(Val::Px(10.), Val::Px(10.)) * 2.,
|
|
Size::new(Val::Px(20.), Val::Px(20.))
|
|
);
|
|
|
|
let mut size = Size::new(Val::Px(10.), Val::Px(10.));
|
|
size *= 2.;
|
|
assert_eq!(size, Size::new(Val::Px(20.), Val::Px(20.)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_size_div() {
|
|
assert_eq!(
|
|
Size::new(Val::Px(20.), Val::Px(20.)) / 2.,
|
|
Size::new(Val::Px(10.), Val::Px(10.))
|
|
);
|
|
|
|
let mut size = Size::new(Val::Px(20.), Val::Px(20.));
|
|
size /= 2.;
|
|
assert_eq!(size, Size::new(Val::Px(10.), Val::Px(10.)));
|
|
}
|
|
}
|