diff --git a/hui/src/element/builtin/container.rs b/hui/src/element/builtin/container.rs index 289225d..0c70905 100644 --- a/hui/src/element/builtin/container.rs +++ b/hui/src/element/builtin/container.rs @@ -375,7 +375,7 @@ impl UiElement for Container { // }); // } - self.background_frame.draw(ctx.draw, ctx.layout.position, ctx.measure.size); + self.background_frame.draw(ctx.draw, (ctx.layout.position, ctx.measure.size).into()); //padding position += vec2(self.padding.left, self.padding.top); diff --git a/hui/src/element/builtin/frame_view.rs b/hui/src/element/builtin/frame_view.rs index 39f3067..d6b1e1f 100644 --- a/hui/src/element/builtin/frame_view.rs +++ b/hui/src/element/builtin/frame_view.rs @@ -63,6 +63,6 @@ impl UiElement for FrameView { } fn process(&self, ctx: ProcessContext) { - self.frame.draw(ctx.draw, ctx.layout.position, ctx.measure.size); + self.frame.draw(ctx.draw, (ctx.layout.position, ctx.measure.size).into()); } } diff --git a/hui/src/element/builtin/progress_bar.rs b/hui/src/element/builtin/progress_bar.rs index c7246be..a432956 100644 --- a/hui/src/element/builtin/progress_bar.rs +++ b/hui/src/element/builtin/progress_bar.rs @@ -75,10 +75,10 @@ impl UiElement for ProgressBar { //FIXME: these optimizations may not be valid if value < 1. || !self.foreground.covers_opaque() { - self.background.draw(ctx.draw, ctx.layout.position, ctx.measure.size); + self.background.draw(ctx.draw, (ctx.layout.position, ctx.measure.size).into()); } if value > 0. { - self.foreground.draw(ctx.draw, ctx.layout.position, ctx.measure.size * vec2(value, 1.)); + self.foreground.draw(ctx.draw, (ctx.layout.position, ctx.measure.size * vec2(value, 1.)).into()); } // let rounded_corners = diff --git a/hui/src/element/builtin/slider.rs b/hui/src/element/builtin/slider.rs index 7affebc..ea9e31a 100644 --- a/hui/src/element/builtin/slider.rs +++ b/hui/src/element/builtin/slider.rs @@ -156,8 +156,10 @@ impl UiElement for Slider { if !(self.track_active.covers_opaque() && self.handle.covers_opaque() && (self.handle_size.1 >= self.track_height) && self.value >= 1.) { self.track.draw( ctx.draw, - ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height / 2.), - ctx.measure.size * vec2(1., self.track_height), + ( + ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height / 2.), + ctx.measure.size * vec2(1., self.track_height), + ).into() ); } @@ -168,8 +170,10 @@ impl UiElement for Slider { if !(self.handle.covers_opaque() && (self.handle_size.1 >= self.track_height) && self.value <= 0.) { self.track_active.draw( ctx.draw, - ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height / 2.), - (ctx.measure.size - handle_size * Vec2::X) * vec2(self.value, self.track_height) + handle_size * Vec2::X / 2., + ( + ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - self.track_height / 2.), + (ctx.measure.size - handle_size * Vec2::X) * vec2(self.value, self.track_height) + handle_size * Vec2::X / 2., + ).into() ); } @@ -187,10 +191,12 @@ impl UiElement for Slider { if (self.handle_size.0 > 0. && self.handle_size.1 > 0.) { self.handle.draw( ctx.draw, - ctx.layout.position + - ((ctx.measure.size.x - handle_size.x) * self.value) * Vec2::X + - ctx.measure.size.y * ((1. - self.handle_size.1) * 0.5) * Vec2::Y, - handle_size, + ( + ctx.layout.position + + ((ctx.measure.size.x - handle_size.x) * self.value) * Vec2::X + + ctx.measure.size.y * ((1. - self.handle_size.1) * 0.5) * Vec2::Y, + handle_size, + ).into() ); } diff --git a/hui/src/frame.rs b/hui/src/frame.rs index d33b943..64e3237 100644 --- a/hui/src/frame.rs +++ b/hui/src/frame.rs @@ -1,7 +1,6 @@ //! modular procedural background system -use glam::Vec2; -use crate::draw::UiDrawCommandList; +use crate::{draw::UiDrawCommandList, rect::Rect}; pub mod point; mod rect; @@ -13,8 +12,8 @@ pub use rect::RectFrame; /// Trait for a drawable frame pub trait Frame { - /// Draw the frame at the given position and size - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2); + /// Draw the frame at the given rect's position and size + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect); /// Check if the frame is guaranteed to be fully opaque and fully cover the parent frame regardless of it's size /// diff --git a/hui/src/frame/impls.rs b/hui/src/frame/impls.rs index 96d24a4..c3152db 100644 --- a/hui/src/frame/impls.rs +++ b/hui/src/frame/impls.rs @@ -3,14 +3,14 @@ use super::Frame; use crate::{ color, draw::{ImageHandle, UiDrawCommand, UiDrawCommandList}, - rect::{Corners, FillColor}, + rect::{Rect, Corners, FillColor}, }; impl Frame for ImageHandle { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { draw.add(UiDrawCommand::Rectangle { - position, - size: parent_size, + position: rect.position, + size: rect.size, color: color::WHITE.into(), texture: Some(*self), texture_uv: None, @@ -24,10 +24,10 @@ impl Frame for ImageHandle { } impl Frame for FillColor { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { draw.add(UiDrawCommand::Rectangle { - position, - size: parent_size, + position: rect.position, + size: rect.size, color: self.corners(), texture: None, texture_uv: None, @@ -45,8 +45,8 @@ impl Frame for FillColor { // Corners (RGBA): impl Frame for Corners { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -54,8 +54,8 @@ impl Frame for Corners { } impl Frame for (Vec4, Vec4, Vec4, Vec4) { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -63,8 +63,8 @@ impl Frame for (Vec4, Vec4, Vec4, Vec4) { } impl Frame for ((f32, f32, f32, f32), (f32, f32, f32, f32), (f32, f32, f32, f32), (f32, f32, f32, f32)) { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -72,8 +72,8 @@ impl Frame for ((f32, f32, f32, f32), (f32, f32, f32, f32), (f32, f32, f32, f32) } impl Frame for [[f32; 4]; 4] { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -83,8 +83,8 @@ impl Frame for [[f32; 4]; 4] { // Corners (RGB): impl Frame for Corners { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -92,8 +92,8 @@ impl Frame for Corners { } impl Frame for (Vec3, Vec3, Vec3, Vec3) { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -101,8 +101,8 @@ impl Frame for (Vec3, Vec3, Vec3, Vec3) { } impl Frame for ((f32, f32, f32), (f32, f32, f32), (f32, f32, f32), (f32, f32, f32)) { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -110,8 +110,8 @@ impl Frame for ((f32, f32, f32), (f32, f32, f32), (f32, f32, f32), (f32, f32, f3 } impl Frame for [[f32; 3]; 4] { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -121,8 +121,8 @@ impl Frame for [[f32; 3]; 4] { // RGBA: impl Frame for Vec4 { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -130,8 +130,8 @@ impl Frame for Vec4 { } impl Frame for (f32, f32, f32, f32) { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -139,8 +139,8 @@ impl Frame for (f32, f32, f32, f32) { } impl Frame for [f32; 4] { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -150,8 +150,8 @@ impl Frame for [f32; 4] { // RGB: impl Frame for Vec3 { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -159,8 +159,8 @@ impl Frame for Vec3 { } impl Frame for (f32, f32, f32) { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() @@ -168,8 +168,8 @@ impl Frame for (f32, f32, f32) { } impl Frame for [f32; 3] { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - FillColor::from(*self).draw(draw, position, parent_size) + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + FillColor::from(*self).draw(draw, rect) } fn covers_opaque(&self) -> bool { FillColor::from(*self).is_opaque() diff --git a/hui/src/frame/nine_patch.rs b/hui/src/frame/nine_patch.rs index 2b686a1..09a58c1 100644 --- a/hui/src/frame/nine_patch.rs +++ b/hui/src/frame/nine_patch.rs @@ -4,7 +4,11 @@ //! This is useful for creating scalable UI elements like buttons, windows, etc. use glam::{vec2, UVec2, Vec2}; -use crate::{color, draw::{ImageHandle, UiDrawCommand}, rect::{Corners, FillColor, Rect}}; +use crate::{ + color, + draw::{ImageHandle, UiDrawCommand, UiDrawCommandList}, + rect::{Rect, Corners, FillColor} +}; use super::Frame; /// Represents a 9-patch image asset @@ -49,10 +53,10 @@ impl Default for NinePatchFrame { } impl Frame for NinePatchFrame { - fn draw(&self, draw: &mut crate::draw::UiDrawCommandList, position: glam::Vec2, parent_size: glam::Vec2) { + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { // without this, shїt gets messed up when the position is not a whole number //XXX: should we round the size as well? - let position = position.round(); + let position = rect.position.round(); let img_sz = UVec2::from(self.asset.size).as_vec2(); @@ -79,13 +83,13 @@ impl Frame for NinePatchFrame { let size_h = ( corners_image_px.top_left.x, - parent_size.x - corners_image_px.top_left.x - (img_sz.x - corners_image_px.top_right.x), + rect.size.x - corners_image_px.top_left.x - (img_sz.x - corners_image_px.top_right.x), img_sz.x - corners_image_px.top_right.x, ); let size_v = ( corners_image_px.top_left.y, - parent_size.y - corners_image_px.top_left.y - (img_sz.y - corners_image_px.bottom_left.y), + rect.size.y - corners_image_px.top_left.y - (img_sz.y - corners_image_px.bottom_left.y), img_sz.y - corners_image_px.bottom_left.y, ); diff --git a/hui/src/frame/rect.rs b/hui/src/frame/rect.rs index 05db4ee..1170360 100644 --- a/hui/src/frame/rect.rs +++ b/hui/src/frame/rect.rs @@ -2,7 +2,7 @@ use glam::Vec2; use crate::{ color, draw::{ImageHandle, RoundedCorners, UiDrawCommand, UiDrawCommandList}, - rect::{Corners, FillColor}, + rect::{Rect, Corners, FillColor}, }; use super::{Frame, point::FramePoint2d}; @@ -115,12 +115,12 @@ impl Default for RectFrame { } impl Frame for RectFrame { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { //TODO: handle bottom_right < top_left - let top_left = self.top_left.resolve(parent_size); - let bottom_right = self.bottom_right.resolve(parent_size); + let top_left = self.top_left.resolve(rect.size); + let bottom_right = self.bottom_right.resolve(rect.size); draw.add(UiDrawCommand::Rectangle { - position: position + top_left, + position: rect.position + top_left, size: bottom_right - top_left, color: self.color.corners(), texture: self.image, diff --git a/hui/src/frame/stack.rs b/hui/src/frame/stack.rs index 5e21dee..e25d495 100644 --- a/hui/src/frame/stack.rs +++ b/hui/src/frame/stack.rs @@ -1,16 +1,15 @@ //! allows stacking two frames on top of each other -use glam::Vec2; -use crate::draw::UiDrawCommandList; +use crate::{draw::UiDrawCommandList, rect::Rect}; use super::Frame; /// A frame that draws two frames on top of each other pub struct FrameStack(pub Box, pub Box); impl Frame for FrameStack { - fn draw(&self, draw: &mut UiDrawCommandList, position: Vec2, parent_size: Vec2) { - self.0.draw(draw, position, parent_size); - self.1.draw(draw, position, parent_size); + fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) { + self.0.draw(draw, rect); + self.1.draw(draw, rect); } fn covers_opaque(&self) -> bool { @@ -22,10 +21,17 @@ impl Frame for FrameStack { pub trait FrameStackExt: Frame { /// Stack another frame on top of this one fn stack(self, other: impl Frame + 'static) -> FrameStack; + + /// Stack another frame below this one + fn stack_bottom(self, other: impl Frame + 'static) -> FrameStack; } impl FrameStackExt for T { fn stack(self, other: impl Frame + 'static) -> FrameStack { FrameStack(Box::new(self), Box::new(other)) } + + fn stack_bottom(self, other: impl Frame + 'static) -> FrameStack { + FrameStack(Box::new(other), Box::new(self)) + } } diff --git a/hui/src/rect/rect.rs b/hui/src/rect/rect.rs index 2d07a04..988ae3f 100644 --- a/hui/src/rect/rect.rs +++ b/hui/src/rect/rect.rs @@ -88,3 +88,51 @@ impl From for Rect { Self::from_size(size) } } + +impl From<(Vec2, Vec2)> for Rect { + /// Create a new `Rect` from a tuple of two `Vec2`s, where the first `Vec2` is the position and the second `Vec2` is the size. + fn from((position, size): (Vec2, Vec2)) -> Self { + Self { position, size } + } +} + +impl From<(f32, f32, f32, f32)> for Rect { + /// Create a new `Rect` from a tuple of 4 `f32`s, where the first two `f32`s are the x and y positions of the top-left corner and the last two `f32`s are the width and height of the rect respectively. + fn from((x, y, width, height): (f32, f32, f32, f32)) -> Self { + Self { + position: Vec2::new(x, y), + size: Vec2::new(width, height), + } + } +} + +impl From<[f32; 4]> for Rect { + /// Create a new `Rect` from an array of 4 `f32`s, where the first two `f32`s are the x and y positions of the top-left corner and the last two `f32`s are the width and height of the rect respectively. + fn from([x, y, width, height]: [f32; 4]) -> Self { + Self { + position: Vec2::new(x, y), + size: Vec2::new(width, height), + } + } +} + +impl From for (Vec2, Vec2) { + /// Convert a `Rect` into a tuple of two `Vec2`s, where the first `Vec2` is the position and the second `Vec2` is the size. + fn from(rect: Rect) -> Self { + (rect.position, rect.size) + } +} + +impl From for (f32, f32, f32, f32) { + /// Convert a `Rect` into a tuple of 4 `f32`s, where the first two `f32`s are the x and y positions of the top-left corner and the last two `f32`s are the width and height of the rect respectively. + fn from(rect: Rect) -> Self { + (rect.position.x, rect.position.y, rect.size.x, rect.size.y) + } +} + +impl From for [f32; 4] { + /// Convert a `Rect` into an array of 4 `f32`s, where the first two `f32`s are the x and y positions of the top-left corner and the last two `f32`s are the width and height of the rect respectively. + fn from(rect: Rect) -> Self { + [rect.position.x, rect.position.y, rect.size.x, rect.size.y] + } +}