diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index 47d3725041c0e..f9a8870da25e8 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -9,5 +9,4 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [dependencies] -glam = { version = "0.20.0", features = ["serde", "bytemuck"] } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } +glam = { version = "0.20.0", features = ["serde", "bytemuck"] } \ No newline at end of file diff --git a/crates/bevy_math/src/face_toward.rs b/crates/bevy_math/src/face_toward.rs deleted file mode 100644 index f873964b18afc..0000000000000 --- a/crates/bevy_math/src/face_toward.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{Mat4, Vec3}; - -/// Generates a translation / rotation matrix that faces a given target -pub trait FaceToward { - /// Generates a translation / rotation matrix that faces a given target - fn face_toward(eye: Vec3, center: Vec3, up: Vec3) -> Self; -} - -impl FaceToward for Mat4 { - fn face_toward(eye: Vec3, center: Vec3, up: Vec3) -> Self { - let forward = (eye - center).normalize(); - let right = up.cross(forward).normalize(); - let up = forward.cross(right); - Mat4::from_cols( - right.extend(0.0), - up.extend(0.0), - forward.extend(0.0), - eye.extend(1.0), - ) - } -} - -#[cfg(test)] -mod test { - #[test] - fn face_toward_mat4() { - use crate::{FaceToward, Mat4, Vec3, Vec4}; - - // Completely arbitrary arguments - let matrix = Mat4::face_toward( - Vec3::new(50.0, 60.0, 0.0), - Vec3::new(0.0, 0.0, 0.0), - Vec3::new(0.0, 1.0, 0.0), - ); - - assert_eq!(matrix.x_axis, Vec4::new(0.0, 0.0, -1.0, -0.0)); - assert_eq!(matrix.y_axis, Vec4::new(-0.7682213, 0.6401844, 0.0, 0.0)); - assert_eq!(matrix.z_axis, Vec4::new(0.6401844, 0.7682213, 0.0, 0.0)); - assert_eq!(matrix.w_axis, Vec4::new(50.0, 60.0, 0.0, 1.0)); - } -} diff --git a/crates/bevy_math/src/geometry.rs b/crates/bevy_math/src/geometry.rs deleted file mode 100644 index 0a449e5d026f9..0000000000000 --- a/crates/bevy_math/src/geometry.rs +++ /dev/null @@ -1,184 +0,0 @@ -use bevy_reflect::Reflect; -use glam::Vec2; -use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; - -/// A two dimensional "size" as defined by a width and height -#[derive(Copy, Clone, PartialEq, Debug, Reflect)] -#[reflect(PartialEq)] -pub struct Size { - pub width: T, - pub height: T, -} - -impl Size { - pub fn new(width: T, height: T) -> Self { - Size { width, height } - } -} - -impl Default for Size { - fn default() -> Self { - Self { - width: Default::default(), - height: Default::default(), - } - } -} - -/// A rect, as defined by its "side" locations -#[derive(Copy, Clone, PartialEq, Debug, Reflect)] -#[reflect(PartialEq)] -pub struct Rect { - pub left: T, - pub right: T, - pub top: T, - pub bottom: T, -} - -impl Rect { - pub fn all(value: T) -> Self - where - T: Clone, - { - Rect { - left: value.clone(), - right: value.clone(), - top: value.clone(), - bottom: value, - } - } -} - -impl Default for Rect { - fn default() -> Self { - Self { - left: Default::default(), - right: Default::default(), - top: Default::default(), - bottom: Default::default(), - } - } -} - -impl Add for Size -where - T: Add, -{ - type Output = Size; - - fn add(self, rhs: Vec2) -> Self::Output { - Self { - width: self.width + rhs.x, - height: self.height + rhs.y, - } - } -} - -impl AddAssign for Size -where - T: AddAssign, -{ - fn add_assign(&mut self, rhs: Vec2) { - self.width += rhs.x; - self.height += rhs.y; - } -} - -impl Sub for Size -where - T: Sub, -{ - type Output = Size; - - fn sub(self, rhs: Vec2) -> Self::Output { - Self { - width: self.width - rhs.x, - height: self.height - rhs.y, - } - } -} - -impl SubAssign for Size -where - T: SubAssign, -{ - fn sub_assign(&mut self, rhs: Vec2) { - self.width -= rhs.x; - self.height -= rhs.y; - } -} - -impl Mul for Size -where - T: Mul, -{ - type Output = Size; - - fn mul(self, rhs: f32) -> Self::Output { - Self::Output { - width: self.width * rhs, - height: self.height * rhs, - } - } -} - -impl MulAssign for Size -where - T: MulAssign, -{ - fn mul_assign(&mut self, rhs: f32) { - self.width *= rhs; - self.height *= rhs; - } -} - -impl Div for Size -where - T: Div, -{ - type Output = Size; - - fn div(self, rhs: f32) -> Self::Output { - Self::Output { - width: self.width / rhs, - height: self.height / rhs, - } - } -} - -impl DivAssign for Size -where - T: DivAssign, -{ - fn div_assign(&mut self, rhs: f32) { - self.width /= rhs; - self.height /= rhs; - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn size_ops() { - type SizeF = Size; - - assert_eq!( - SizeF::new(10., 10.) + Vec2::new(10., 10.), - SizeF::new(20., 20.) - ); - assert_eq!( - SizeF::new(20., 20.) - Vec2::new(10., 10.), - SizeF::new(10., 10.) - ); - assert_eq!(SizeF::new(10., 10.) * 2., SizeF::new(20., 20.)); - assert_eq!(SizeF::new(20., 20.) / 2., SizeF::new(10., 10.)); - - let mut size = SizeF::new(10., 10.); - - size += Vec2::new(10., 10.); - - assert_eq!(size, SizeF::new(20., 20.)); - } -} diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index 9a8ae797ed04b..6ff93da8905e8 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -1,14 +1,17 @@ -mod face_toward; -mod geometry; +#![warn(missing_docs)] + +//! Provides math types and functionality for the Bevy game engine. +//! +//! The commonly used types are vectors like [`Vec2`], [`Vec3`] and [`Vec4`] and +//! matrices like [`Mat3`] and [`Mat4`]. -pub use face_toward::*; -pub use geometry::*; pub use glam::*; +/// The `bevy_math` prelude. pub mod prelude { #[doc(hidden)] pub use crate::{ - BVec2, BVec3, BVec4, EulerRot, FaceToward, IVec2, IVec3, IVec4, Mat3, Mat4, Quat, Rect, - Size, UVec2, UVec3, UVec4, Vec2, Vec3, Vec4, + BVec2, BVec3, BVec4, EulerRot, IVec2, IVec3, IVec4, Mat3, Mat4, Quat, UVec2, UVec3, UVec4, + Vec2, Vec3, Vec4, }; } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 8d00086881215..466fec7e7975b 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ prelude::*, system::{lifetimeless::*, SystemParamItem}, }; -use bevy_math::{Mat4, Size}; +use bevy_math::{Mat4, Vec2}; use bevy_reflect::TypeUuid; use bevy_render::{ mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout}, @@ -329,7 +329,7 @@ impl FromWorld for MeshPipeline { texture_view, texture_format: image.texture_descriptor.format, sampler, - size: Size::new( + size: Vec2::new( image.texture_descriptor.size.width as f32, image.texture_descriptor.size.height as f32, ), diff --git a/crates/bevy_render/src/texture/image.rs b/crates/bevy_render/src/texture/image.rs index fa4afe04924ef..791f86ec1574a 100644 --- a/crates/bevy_render/src/texture/image.rs +++ b/crates/bevy_render/src/texture/image.rs @@ -14,7 +14,7 @@ use crate::{ }; use bevy_asset::HandleUntyped; use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem}; -use bevy_math::{Size, Vec2}; +use bevy_math::Vec2; use bevy_reflect::TypeUuid; use thiserror::Error; use wgpu::{ @@ -533,14 +533,14 @@ impl TextureFormatPixelInfo for TextureFormat { } /// The GPU-representation of an [`Image`]. -/// Consists of the [`Texture`], its [`TextureView`] and the corresponding [`Sampler`], and the texture's [`Size`]. +/// Consists of the [`Texture`], its [`TextureView`] and the corresponding [`Sampler`], and the textures `size` represented by a [`Vec2`]. #[derive(Debug, Clone)] pub struct GpuImage { pub texture: Texture, pub texture_view: TextureView, pub texture_format: TextureFormat, pub sampler: Sampler, - pub size: Size, + pub size: Vec2, } impl RenderAsset for Image { @@ -595,7 +595,7 @@ impl RenderAsset for Image { }; let texture_view = texture.create_view(&TextureViewDescriptor::default()); - let size = Size::new( + let size = Vec2::new( image.texture_descriptor.size.width as f32, image.texture_descriptor.size.height as f32, ); diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 2c6e31085130a..3f21460b3a83e 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -4,7 +4,7 @@ use bevy_ecs::{ prelude::*, system::{lifetimeless::*, SystemParamItem}, }; -use bevy_math::{Mat4, Size}; +use bevy_math::{Mat4, Vec2}; use bevy_reflect::TypeUuid; use bevy_render::{ mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout}, @@ -194,7 +194,7 @@ impl FromWorld for Mesh2dPipeline { texture_view, texture_format: image.texture_descriptor.format, sampler, - size: Size::new( + size: Vec2::new( image.texture_descriptor.size.width as f32, image.texture_descriptor.size.height as f32, ), diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 7e3ffe4c97038..fa3e90d00d87a 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -428,7 +428,7 @@ pub fn queue_sprites( gpu_images.get(&Handle::weak(new_batch.image_handle_id)) { current_batch = new_batch; - current_image_size = Vec2::new(gpu_image.size.width, gpu_image.size.height); + current_image_size = Vec2::new(gpu_image.size.x, gpu_image.size.y); current_batch_entity = commands.spawn_bundle((current_batch,)).id(); image_bind_groups diff --git a/crates/bevy_text/src/glyph_brush.rs b/crates/bevy_text/src/glyph_brush.rs index 6d11b07ad1053..ca7331901775d 100644 --- a/crates/bevy_text/src/glyph_brush.rs +++ b/crates/bevy_text/src/glyph_brush.rs @@ -1,6 +1,6 @@ use ab_glyph::{Font as _, FontArc, Glyph, ScaleFont as _}; use bevy_asset::{Assets, Handle}; -use bevy_math::{Size, Vec2}; +use bevy_math::Vec2; use bevy_render::texture::Image; use bevy_sprite::TextureAtlas; use glyph_brush_layout::{ @@ -29,11 +29,11 @@ impl GlyphBrush { pub fn compute_glyphs( &self, sections: &[S], - bounds: Size, + bounds: Vec2, text_alignment: TextAlignment, ) -> Result, TextError> { let geom = SectionGeometry { - bounds: (bounds.width, bounds.height), + bounds: (bounds.x, bounds.y), ..Default::default() }; let section_glyphs = Layout::default() diff --git a/crates/bevy_text/src/pipeline.rs b/crates/bevy_text/src/pipeline.rs index 5539a4e1d0c07..5b728552513ab 100644 --- a/crates/bevy_text/src/pipeline.rs +++ b/crates/bevy_text/src/pipeline.rs @@ -2,7 +2,7 @@ use std::hash::Hash; use ab_glyph::{PxScale, ScaleFont}; use bevy_asset::{Assets, Handle, HandleId}; -use bevy_math::Size; +use bevy_math::Vec2; use bevy_render::texture::Image; use bevy_sprite::TextureAtlas; use bevy_utils::HashMap; @@ -32,7 +32,7 @@ impl Default for TextPipeline { pub struct TextLayoutInfo { pub glyphs: Vec, - pub size: Size, + pub size: Vec2, } impl TextPipeline { @@ -56,7 +56,7 @@ impl TextPipeline { sections: &[TextSection], scale_factor: f64, text_alignment: TextAlignment, - bounds: Size, + bounds: Vec2, font_atlas_set_storage: &mut Assets, texture_atlases: &mut Assets, textures: &mut Assets, @@ -92,7 +92,7 @@ impl TextPipeline { id, TextLayoutInfo { glyphs: Vec::new(), - size: Size::new(0., 0.), + size: Vec2::new(0., 0.), }, ); return Ok(()); @@ -112,7 +112,7 @@ impl TextPipeline { max_y = max_y.max(glyph.position.y - scaled_font.descent()); } - let size = Size::new(max_x - min_x, max_y - min_y); + let size = Vec2::new(max_x - min_x, max_y - min_y); let glyphs = self.brush.process_glyphs( section_glyphs, diff --git a/crates/bevy_text/src/text.rs b/crates/bevy_text/src/text.rs index 2f2b37ab9a19e..0b1b22eebdd08 100644 --- a/crates/bevy_text/src/text.rs +++ b/crates/bevy_text/src/text.rs @@ -1,6 +1,6 @@ use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; -use bevy_math::Size; +use bevy_math::Vec2; use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize}; use bevy_render::color::Color; use serde::{Deserialize, Serialize}; @@ -154,5 +154,5 @@ impl Default for TextStyle { #[derive(Component, Default, Copy, Clone, Debug, Reflect)] #[reflect(Component)] pub struct Text2dSize { - pub size: Size, + pub size: Vec2, } diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 0119bffde7b6e..70f726d1ccc0b 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -5,7 +5,7 @@ use bevy_ecs::{ query::{Changed, QueryState, With}, system::{Local, Query, QuerySet, Res, ResMut}, }; -use bevy_math::{Size, Vec3}; +use bevy_math::{Vec2, Vec3}; use bevy_render::{texture::Image, view::Visibility, RenderWorld}; use bevy_sprite::{ExtractedSprite, ExtractedSprites, TextureAtlas}; use bevy_transform::prelude::{GlobalTransform, Transform}; @@ -34,7 +34,7 @@ impl Default for Text2dBundle { transform: Default::default(), global_transform: Default::default(), text_2d_size: Text2dSize { - size: Size::default(), + size: Vec2::default(), }, visibility: Default::default(), } @@ -56,7 +56,7 @@ pub fn extract_text2d_sprite( if !visibility.is_visible { continue; } - let (width, height) = (calculated_size.size.width, calculated_size.size.height); + let (width, height) = (calculated_size.size.x, calculated_size.size.y); if let Some(text_layout) = text_pipeline.get_glyphs(&entity) { let text_glyphs = &text_layout.glyphs; @@ -148,7 +148,7 @@ pub fn text2d_system( &text.sections, scale_factor, text.alignment, - Size::new(f32::MAX, f32::MAX), + Vec2::new(f32::MAX, f32::MAX), &mut *font_atlas_set_storage, &mut *texture_atlases, &mut *textures, @@ -165,10 +165,10 @@ pub fn text2d_system( let text_layout_info = text_pipeline.get_glyphs(&entity).expect( "Failed to get glyphs from the pipeline that have just been computed", ); - calculated_size.size = Size { - width: scale_value(text_layout_info.size.width, 1. / scale_factor), - height: scale_value(text_layout_info.size.height, 1. / scale_factor), - }; + calculated_size.size = Vec2::new( + scale_value(text_layout_info.size.x, 1. / scale_factor), + scale_value(text_layout_info.size.y, 1. / scale_factor), + ); } } } diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 10e6839134349..b851ed91b94bd 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -1,40 +1,43 @@ use crate::{ AlignContent, AlignItems, AlignSelf, Direction, Display, FlexDirection, FlexWrap, - JustifyContent, PositionType, Style, Val, + JustifyContent, PositionType, Size, Style, UiRect, Val, }; -use bevy_math::{Rect, Size}; -pub fn from_rect( +/// Converts a [`UiRect`] to a [`stretch::geometry::Rect`] respecting the scale factor. +pub fn uirect_to_rect( scale_factor: f64, - rect: Rect, + rect: UiRect, ) -> stretch::geometry::Rect { stretch::geometry::Rect { - start: from_val(scale_factor, rect.left), - end: from_val(scale_factor, rect.right), + start: val_to_dimension(scale_factor, rect.left), + end: val_to_dimension(scale_factor, rect.right), // NOTE: top and bottom are intentionally flipped. stretch has a flipped y-axis - top: from_val(scale_factor, rect.bottom), - bottom: from_val(scale_factor, rect.top), + top: val_to_dimension(scale_factor, rect.bottom), + bottom: val_to_dimension(scale_factor, rect.top), } } -pub fn from_f32_size(scale_factor: f64, size: Size) -> stretch::geometry::Size { +/// Converts a [`Size`] to a [`stretch::geometry::Size`] respecting the scale factor. +pub fn size_to_f32_size(scale_factor: f64, size: Size) -> stretch::geometry::Size { stretch::geometry::Size { - width: (scale_factor * size.width as f64) as f32, - height: (scale_factor * size.height as f64) as f32, + width: val_to_f32(scale_factor, size.width), + height: val_to_f32(scale_factor, size.height), } } -pub fn from_val_size( +/// Converts a [`Size`] to a [`stretch::geometry::Size`] respecting the scale factor. +pub fn size_to_dimension_size( scale_factor: f64, - size: Size, + size: Size, ) -> stretch::geometry::Size { stretch::geometry::Size { - width: from_val(scale_factor, size.width), - height: from_val(scale_factor, size.height), + width: val_to_dimension(scale_factor, size.width), + height: val_to_dimension(scale_factor, size.height), } } -pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style { +/// Converts a [`Style`] to a [`stretch::style::Style`] respecting the scale factor. +pub fn style_to_style(scale_factor: f64, value: &Style) -> stretch::style::Style { stretch::style::Style { overflow: stretch::style::Overflow::Visible, display: value.display.into(), @@ -46,16 +49,16 @@ pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style { align_self: value.align_self.into(), align_content: value.align_content.into(), justify_content: value.justify_content.into(), - position: from_rect(scale_factor, value.position), - margin: from_rect(scale_factor, value.margin), - padding: from_rect(scale_factor, value.padding), - border: from_rect(scale_factor, value.border), + position: uirect_to_rect(scale_factor, value.position), + margin: uirect_to_rect(scale_factor, value.margin), + padding: uirect_to_rect(scale_factor, value.padding), + border: uirect_to_rect(scale_factor, value.border), flex_grow: value.flex_grow, flex_shrink: value.flex_shrink, - flex_basis: from_val(scale_factor, value.flex_basis), - size: from_val_size(scale_factor, value.size), - min_size: from_val_size(scale_factor, value.min_size), - max_size: from_val_size(scale_factor, value.max_size), + flex_basis: val_to_dimension(scale_factor, value.flex_basis), + size: size_to_dimension_size(scale_factor, value.size), + min_size: size_to_dimension_size(scale_factor, value.min_size), + max_size: size_to_dimension_size(scale_factor, value.max_size), aspect_ratio: match value.aspect_ratio { Some(value) => stretch::number::Number::Defined(value), None => stretch::number::Number::Undefined, @@ -63,12 +66,22 @@ pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style { } } -pub fn from_val(scale_factor: f64, val: Val) -> stretch::style::Dimension { +/// Converts a [`Val`] to a [`stretch::style::Dimension`] while respecting the scale factor. +pub fn val_to_dimension(scale_factor: f64, val: Val) -> stretch::style::Dimension { match val { + Val::Undefined => stretch::style::Dimension::Undefined, Val::Auto => stretch::style::Dimension::Auto, - Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0), Val::Px(value) => stretch::style::Dimension::Points((scale_factor * value as f64) as f32), - Val::Undefined => stretch::style::Dimension::Undefined, + Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0), + } +} + +/// Converts a [`Val`] to an [`f32`] while respecting the scale factor. +pub fn val_to_f32(scale_factor: f64, val: Val) -> f32 { + match val { + Val::Undefined | Val::Auto => 0.0, + Val::Px(value) => (scale_factor * value as f64) as f32, + Val::Percent(value) => value / 100.0, } } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index 63ccf94a2ca13..cd282067851d4 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -59,7 +59,7 @@ impl FlexSurface { pub fn upsert_node(&mut self, entity: Entity, style: &Style, scale_factor: f64) { let mut added = false; let stretch = &mut self.stretch; - let stretch_style = convert::from_style(scale_factor, style); + let stretch_style = convert::style_to_style(scale_factor, style); let stretch_node = self.entity_to_stretch.entry(entity).or_insert_with(|| { added = true; stretch.new_node(stretch_style, Vec::new()).unwrap() @@ -80,9 +80,9 @@ impl FlexSurface { scale_factor: f64, ) { let stretch = &mut self.stretch; - let stretch_style = convert::from_style(scale_factor, style); + let stretch_style = convert::style_to_style(scale_factor, style); let measure = Box::new(move |constraints: stretch::geometry::Size| { - let mut size = convert::from_f32_size(scale_factor, calculated_size.size); + let mut size = convert::size_to_f32_size(scale_factor, calculated_size.size); match (constraints.width, constraints.height) { (Number::Undefined, Number::Undefined) => {} (Number::Defined(width), Number::Undefined) => { diff --git a/crates/bevy_ui/src/geometry.rs b/crates/bevy_ui/src/geometry.rs new file mode 100644 index 0000000000000..f344f73bbbdb8 --- /dev/null +++ b/crates/bevy_ui/src/geometry.rs @@ -0,0 +1,336 @@ +use crate::Val; +use bevy_math::Vec2; +use bevy_reflect::Reflect; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; + +/// A 2-dimensional area defined by a width and height. +/// +/// It is commonly used to define the size of a text or UI element. +/// +/// # Example +/// +/// ```rust +/// # use bevy_ui::{Size, Val}; +/// # +/// let size = Size { +/// width: Val::Px(100.0), +/// height: Val::Px(200.0), +/// }; +/// ``` +#[derive(Default, Copy, Clone, PartialEq, Debug, 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 + /// + /// ```rust + /// # 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 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 for Size { + fn add_assign(&mut self, rhs: Vec2) { + self.width += rhs.x; + self.height += rhs.y; + } +} + +impl Sub 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 for Size { + fn sub_assign(&mut self, rhs: Vec2) { + self.width -= rhs.x; + self.height -= rhs.y; + } +} + +impl Mul for Size { + type Output = Size; + + fn mul(self, rhs: f32) -> Self::Output { + Self::Output { + width: self.width * rhs, + height: self.height * rhs, + } + } +} + +impl MulAssign for Size { + fn mul_assign(&mut self, rhs: f32) { + self.width *= rhs; + self.height *= rhs; + } +} + +impl Div for Size { + type Output = Size; + + fn div(self, rhs: f32) -> Self::Output { + Self::Output { + width: self.width / rhs, + height: self.height / rhs, + } + } +} + +impl DivAssign for Size { + fn div_assign(&mut self, rhs: f32) { + self.width /= rhs; + self.height /= rhs; + } +} + +/// 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. +/// +/// In this example we are creating a UI position. It has a left value of 100px and a top value of 50px. +/// If positioned absolutely this would correspond to a UI element which is positioned 100px to the right +/// from the left side of the window and 50px down from the top side of the window. +/// +/// ```rust +/// # use bevy_ui::{UiRect, Val}; +/// # +/// let position = UiRect { +/// left: Val::Px(100.0), +/// top: Val::Px(50.0), +/// ..Default::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`] as a +/// width and height, the size would be determined by the window size and the values specified in the position. +/// +/// In this example we are creating another UI position. It has a left value of 100px, a right value of 200px, +/// a top value of 300px and a bottom value of 400px. If positioned absolutely this would correspond to a +/// UI element that is positioned 100px to the right from the left side of the window and 300px down from +/// the top side of the window. +/// +/// ```rust +/// # 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), +/// }; +/// ``` +/// +/// The size of the UI element would now be determined by the window size and the position values. +/// 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 would have a width of 700px and a height +/// of 300px. +/// +/// ```rust +/// let window_size = 1000.0; +/// let left = 100.0; +/// let right = 200.0; +/// let top = 300.0; +/// let bottom = 400.0; +/// +/// let ui_element_width = window_size - left - right; +/// let ui_element_height = window_size - top - bottom; +/// ``` +/// +/// 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. +/// +/// ## Margin +/// +/// A margin is used to create space around UI elements, outside of any defined borders. +/// +/// In this example we are creating a UI margin. It has a left value of 10px, a right value of 20px, +/// a top value of 30px and a bottom value of 40px. This would add a margin of 10px on the left, +/// 20px on the right, 30px on the top and 40px on the bottom of the UI element. +/// +/// ```rust +/// # use bevy_ui::{UiRect, Val}; +/// # +/// let margin = UiRect { +/// left: Val::Px(10.0), +/// right: Val::Px(20.0), +/// top: Val::Px(30.0), +/// bottom: Val::Px(40.0), +/// }; +/// ``` +/// +/// ## Padding +/// +/// A padding is used to create space around UI elements, inside of any defined borders. +/// +/// In this example we are creating a UI padding. It has a left value of 10px, a right value of 20px, +/// a top value of 30px and a bottom value of 40px. This would add a padding of 10px on the left, +/// 20px on the right, 30px on the top and 40px on the bottom of the UI element. +/// +/// ```rust +/// # 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. +/// +/// In this example we are creating a UI border. It has a left value of 10px, a right value of 20px, +/// a top value of 30px and a bottom value of 40px. This would create a border around a UI element +/// that has a width of 10px on the left, 20px on the right, 30px on the top and 40px on the bottom. +/// +/// ```rust +/// # 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(Default, Copy, Clone, PartialEq, Debug, Reflect)] +#[reflect(PartialEq)] +pub struct UiRect { + /// The left value of the [`UiRect`]. + pub left: Val, + /// The right value of the [`UiRect`]. + pub right: Val, + /// The top value of the [`UiRect`]. + pub top: Val, + /// The bottom value of the [`UiRect`]. + pub bottom: Val, +} + +impl UiRect { + /// Creates a new [`UiRect`] from the values specified. + /// + /// # Example + /// + /// ```rust + /// # 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 + /// + /// ```rust + /// # 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, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bevy_math::Vec2; + + #[test] + fn size_ops() { + assert_eq!( + Size::new(Val::Px(10.), Val::Px(10.)) + Vec2::new(10., 10.), + Size::new(Val::Px(20.), Val::Px(20.)) + ); + assert_eq!( + Size::new(Val::Px(20.), Val::Px(20.)) - Vec2::new(10., 10.), + Size::new(Val::Px(10.), Val::Px(10.)) + ); + assert_eq!( + Size::new(Val::Px(10.), Val::Px(10.)) * 2., + Size::new(Val::Px(20.), Val::Px(20.)) + ); + 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(10.), Val::Px(10.)); + + size += Vec2::new(10., 10.); + + assert_eq!(size, Size::new(Val::Px(20.), Val::Px(20.))); + } +} diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 2a44323966a3d..7b96781165b6f 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -4,7 +4,7 @@ //! This UI is laid out with the Flexbox paradigm (see ) except the vertical axis is inverted mod flex; mod focus; -mod margins; +mod geometry; mod render; mod ui_node; @@ -15,20 +15,19 @@ pub mod widget; use bevy_render::camera::CameraTypePlugin; pub use flex::*; pub use focus::*; -pub use margins::*; +pub use geometry::*; pub use render::*; pub use ui_node::*; #[doc(hidden)] pub mod prelude { #[doc(hidden)] - pub use crate::{entity::*, ui_node::*, widget::Button, Interaction, Margins}; + pub use crate::{entity::*, geometry::*, ui_node::*, widget::Button, Interaction}; } use bevy_app::prelude::*; use bevy_ecs::schedule::{ParallelSystemDescriptorCoercion, SystemLabel}; use bevy_input::InputSystem; -use bevy_math::{Rect, Size}; use bevy_transform::TransformSystem; use update::{ui_z_system, update_clipping_system}; @@ -67,9 +66,8 @@ impl Plugin for UiPlugin { .register_type::>() .register_type::() .register_type::() - .register_type::>() - .register_type::>() - .register_type::>() + .register_type::() + .register_type::() .register_type::