use rect om frame api

This commit is contained in:
griffi-gh 2024-04-17 16:22:51 +02:00
parent 104ac018fe
commit b30fe304d1
10 changed files with 129 additions and 66 deletions

View file

@ -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);

View file

@ -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());
}
}

View file

@ -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 =

View file

@ -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()
);
}

View file

@ -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
///

View file

@ -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<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()
@ -54,8 +54,8 @@ impl Frame for Corners<Vec4> {
}
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<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()
@ -92,8 +92,8 @@ impl Frame for Corners<Vec3> {
}
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()

View file

@ -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,
);

View file

@ -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,

View file

@ -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<dyn Frame>, pub Box<dyn Frame>);
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<T: Frame + 'static> 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))
}
}

View file

@ -88,3 +88,51 @@ impl From<Vec2> 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<Rect> 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<Rect> 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<Rect> 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]
}
}