mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-29 02:18:40 -06:00
Compare commits
2 commits
d430996e14
...
bbc1d9f1ff
Author | SHA1 | Date | |
---|---|---|---|
griffi-gh | bbc1d9f1ff | ||
griffi-gh | 915b99c3a5 |
|
@ -26,6 +26,7 @@ document-features = "0.2"
|
||||||
derive_setters = "0.1"
|
derive_setters = "0.1"
|
||||||
derive_more = "0.99"
|
derive_more = "0.99"
|
||||||
tinyset = "0.4"
|
tinyset = "0.4"
|
||||||
|
enum_dispatch = "0.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["builtin_elements", "builtin_font", "pixel_perfect_text"]
|
default = ["builtin_elements", "builtin_font", "pixel_perfect_text"]
|
||||||
|
|
219
hui/src/frame.rs
219
hui/src/frame.rs
|
@ -1,195 +1,42 @@
|
||||||
use glam::{Vec2, vec2};
|
use crate::rect::FillColor;
|
||||||
use derive_more::{Add, AddAssign, Sub, SubAssign};
|
|
||||||
use crate::{
|
|
||||||
draw::ImageHandle,
|
|
||||||
element::fill_rect::FillRect,
|
|
||||||
layout::{Size, Size2d}
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO finish dis, slider component would be a great place to test it
|
pub mod point;
|
||||||
|
pub mod layer;
|
||||||
|
|
||||||
/// Point inside a frame
|
use layer::{FrameLayer, RectLayer};
|
||||||
|
|
||||||
|
///XXX: this is not used yet, and also kinda a mess, simplify?
|
||||||
|
///Maybe limit to a single layer? (aka `Frame` will be just one of the options)
|
||||||
|
///Because currently, this is just a duplicate of the dormal draw command system, but with a different name...
|
||||||
|
///Then, there's no need for the positioning stuff too, which is a bit overkill and is kinda code duplication too!
|
||||||
|
///aka Frame::Rectangle, Frame::NinePatch, ...
|
||||||
|
|
||||||
|
/// A frame, which can contain multiple layers
|
||||||
///
|
///
|
||||||
/// Can be absolute, relative, or a combination of both\
|
/// Use these to construct complex backgrounds
|
||||||
/// Final coordinate is calculated as `absolute + relative * parent_size`
|
#[derive(Default, Clone)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Add, AddAssign, Sub, SubAssign)]
|
|
||||||
pub struct FramePoint {
|
|
||||||
/// Absolute positioning
|
|
||||||
pub absolute: f32,
|
|
||||||
|
|
||||||
/// Relative positioning
|
|
||||||
pub relative: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<f32> for FramePoint {
|
|
||||||
fn from(value: f32) -> Self {
|
|
||||||
Self::absolute(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Size> for FramePoint {
|
|
||||||
/// Convert a `Size` into a `FramePoint`
|
|
||||||
///
|
|
||||||
/// This function behaves just as you would expect, but `Auto` is always treated as `BEGIN`
|
|
||||||
fn from(size: Size) -> Self {
|
|
||||||
match size {
|
|
||||||
Size::Auto => Self::BEGIN,
|
|
||||||
Size::Relative(value) => Self::relative(value),
|
|
||||||
Size::Absolute(value) => Self::absolute(value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FramePoint {
|
|
||||||
pub const BEGIN: Self = Self {
|
|
||||||
absolute: 0.0,
|
|
||||||
relative: 0.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const CENTER: Self = Self {
|
|
||||||
absolute: 0.5,
|
|
||||||
relative: 0.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const END: Self = Self {
|
|
||||||
absolute: 1.0,
|
|
||||||
relative: 0.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const fn absolute(value: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
absolute: value,
|
|
||||||
relative: 0.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn relative(value: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
absolute: 0.0,
|
|
||||||
relative: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn relative_absolute(relative: f32, absolute: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
absolute,
|
|
||||||
relative,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve(&self, parent_size: f32) -> f32 {
|
|
||||||
self.absolute + self.relative * parent_size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Add, AddAssign, Sub, SubAssign)]
|
|
||||||
pub struct FramePoint2d {
|
|
||||||
pub x: FramePoint,
|
|
||||||
pub y: FramePoint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(FramePoint, FramePoint)> for FramePoint2d {
|
|
||||||
fn from((x, y): (FramePoint, FramePoint)) -> Self {
|
|
||||||
Self { x, y }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Size> for FramePoint2d {
|
|
||||||
fn from(size: Size) -> Self {
|
|
||||||
Self {
|
|
||||||
x: size.into(),
|
|
||||||
y: size.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Size2d> for FramePoint2d {
|
|
||||||
fn from(size: Size2d) -> Self {
|
|
||||||
Self {
|
|
||||||
x: size.width.into(),
|
|
||||||
y: size.height.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(f32, f32)> for FramePoint2d {
|
|
||||||
fn from((x, y): (f32, f32)) -> Self {
|
|
||||||
Self {
|
|
||||||
x: FramePoint::absolute(x),
|
|
||||||
y: FramePoint::absolute(y),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec2> for FramePoint2d {
|
|
||||||
fn from(vec: Vec2) -> Self {
|
|
||||||
Self {
|
|
||||||
x: FramePoint::absolute(vec.x),
|
|
||||||
y: FramePoint::absolute(vec.y),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FramePoint2d {
|
|
||||||
pub const TOP_LEFT: Self = Self {
|
|
||||||
x: FramePoint::BEGIN,
|
|
||||||
y: FramePoint::BEGIN,
|
|
||||||
};
|
|
||||||
pub const TOP_CENTER: Self = Self {
|
|
||||||
x: FramePoint::CENTER,
|
|
||||||
y: FramePoint::BEGIN,
|
|
||||||
};
|
|
||||||
pub const TOP_RIGHT: Self = Self {
|
|
||||||
x: FramePoint::END,
|
|
||||||
y: FramePoint::BEGIN,
|
|
||||||
};
|
|
||||||
pub const CENTER_LEFT: Self = Self {
|
|
||||||
x: FramePoint::BEGIN,
|
|
||||||
y: FramePoint::CENTER,
|
|
||||||
};
|
|
||||||
pub const CENTER: Self = Self {
|
|
||||||
x: FramePoint::CENTER,
|
|
||||||
y: FramePoint::CENTER,
|
|
||||||
};
|
|
||||||
pub const CENTER_RIGHT: Self = Self {
|
|
||||||
x: FramePoint::END,
|
|
||||||
y: FramePoint::CENTER,
|
|
||||||
};
|
|
||||||
pub const BOTTOM_LEFT: Self = Self {
|
|
||||||
x: FramePoint::BEGIN,
|
|
||||||
y: FramePoint::END,
|
|
||||||
};
|
|
||||||
pub const BOTTOM_CENTER: Self = Self {
|
|
||||||
x: FramePoint::CENTER,
|
|
||||||
y: FramePoint::END,
|
|
||||||
};
|
|
||||||
pub const BOTTOM_RIGHT: Self = Self {
|
|
||||||
x: FramePoint::END,
|
|
||||||
y: FramePoint::END,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn resolve(&self, parent_size: Vec2) -> Vec2 {
|
|
||||||
let x = self.x.resolve(parent_size.x);
|
|
||||||
let y = self.y.resolve(parent_size.y);
|
|
||||||
vec2(x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum FrameLayer {
|
|
||||||
Rect {
|
|
||||||
color: FillRect,
|
|
||||||
image: Option<ImageHandle>,
|
|
||||||
top_left: FramePoint2d,
|
|
||||||
bottom_right: FramePoint2d,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
|
/// Layers of the frame
|
||||||
layers: Vec<FrameLayer>
|
layers: Vec<FrameLayer>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<FillRect>> From<T> for Frame {
|
impl<T: Into<FillColor>> From<T> for Frame {
|
||||||
fn from(value: T) -> Self {
|
fn from(color: T) -> Self {
|
||||||
todo!()
|
let mut frame = Self::default();
|
||||||
|
frame.add(RectLayer::from_color(color));
|
||||||
|
frame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
#[inline]
|
||||||
|
pub fn add(&mut self, layer: impl Into<FrameLayer>) -> &mut Self {
|
||||||
|
self.layers.push(layer.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn finish(&mut self) -> Self {
|
||||||
|
self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
90
hui/src/frame/layer.rs
Normal file
90
hui/src/frame/layer.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use glam::Vec2;
|
||||||
|
use enum_dispatch::enum_dispatch;
|
||||||
|
use crate::{
|
||||||
|
color,
|
||||||
|
draw::{ImageHandle, RoundedCorners, UiDrawCommand, UiDrawCommandList},
|
||||||
|
rect::{Corners, FillColor},
|
||||||
|
};
|
||||||
|
use super::point::FramePoint2d;
|
||||||
|
|
||||||
|
#[enum_dispatch]
|
||||||
|
pub(crate) trait FrameLayerImpl {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, parent_size: Vec2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[enum_dispatch(FrameLayerImpl)]
|
||||||
|
pub enum FrameLayer {
|
||||||
|
Rect(RectLayer),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct RectLayer {
|
||||||
|
color: FillColor,
|
||||||
|
image: Option<ImageHandle>,
|
||||||
|
top_left: FramePoint2d,
|
||||||
|
bottom_right: FramePoint2d,
|
||||||
|
corner_radius: Corners<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RectLayer {
|
||||||
|
pub fn from_color(color: impl Into<FillColor>) -> Self {
|
||||||
|
Self {
|
||||||
|
color: color.into(),
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_color_rounded(color: impl Into<FillColor>, corner_radius: impl Into<Corners<f32>>) -> Self {
|
||||||
|
Self {
|
||||||
|
color: color.into(),
|
||||||
|
corner_radius: corner_radius.into(),
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_image(image: ImageHandle) -> Self {
|
||||||
|
Self {
|
||||||
|
color: color::WHITE.into(),
|
||||||
|
image: Some(image),
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_color_image(color: impl Into<FillColor>, image: ImageHandle) -> Self {
|
||||||
|
Self {
|
||||||
|
color: color.into(),
|
||||||
|
image: Some(image),
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RectLayer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
color: FillColor::default(),
|
||||||
|
image: None,
|
||||||
|
top_left: FramePoint2d::default(),
|
||||||
|
bottom_right: FramePoint2d::default(),
|
||||||
|
corner_radius: Corners::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameLayerImpl for RectLayer {
|
||||||
|
fn draw(&self, draw: &mut UiDrawCommandList, parent_size: Vec2) {
|
||||||
|
//TODO: handle bottom_right < top_left
|
||||||
|
let top_left = self.top_left.resolve(parent_size);
|
||||||
|
let bottom_right = self.bottom_right.resolve(parent_size);
|
||||||
|
draw.add(UiDrawCommand::Rectangle {
|
||||||
|
position: top_left,
|
||||||
|
size: bottom_right - top_left,
|
||||||
|
color: self.color.corners(),
|
||||||
|
texture: self.image,
|
||||||
|
rounded_corners: (self.corner_radius.max_f32() > 0.).then_some(
|
||||||
|
RoundedCorners::from_radius(self.corner_radius)
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
198
hui/src/frame/point.rs
Normal file
198
hui/src/frame/point.rs
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
use glam::{Vec2, vec2};
|
||||||
|
use derive_more::{Add, AddAssign, Sub, SubAssign};
|
||||||
|
use crate::layout::{Size, Size2d};
|
||||||
|
|
||||||
|
/// Point inside a frame
|
||||||
|
///
|
||||||
|
/// Can be absolute, relative, or a combination of both\
|
||||||
|
/// Final coordinate is calculated as `absolute + relative * parent_size`
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Add, AddAssign, Sub, SubAssign)]
|
||||||
|
pub struct FramePoint {
|
||||||
|
/// Absolute positioning
|
||||||
|
pub absolute: f32,
|
||||||
|
|
||||||
|
/// Relative positioning
|
||||||
|
pub relative: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f32> for FramePoint {
|
||||||
|
fn from(value: f32) -> Self {
|
||||||
|
Self::absolute(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size> for FramePoint {
|
||||||
|
/// Convert a `Size` into a `FramePoint`
|
||||||
|
///
|
||||||
|
/// This function behaves just as you would expect, but `Auto` is always treated as `BEGIN`
|
||||||
|
fn from(size: Size) -> Self {
|
||||||
|
match size {
|
||||||
|
Size::Auto => Self::BEGIN,
|
||||||
|
Size::Relative(value) => Self::relative(value),
|
||||||
|
Size::Absolute(value) => Self::absolute(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FramePoint {
|
||||||
|
/// Beginning of the frame axis
|
||||||
|
pub const BEGIN: Self = Self {
|
||||||
|
absolute: 0.0,
|
||||||
|
relative: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Center of the frame axis
|
||||||
|
pub const CENTER: Self = Self {
|
||||||
|
absolute: 0.5,
|
||||||
|
relative: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// End of the frame axis
|
||||||
|
pub const END: Self = Self {
|
||||||
|
absolute: 1.0,
|
||||||
|
relative: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a new absolutely positioned `FramePoint`
|
||||||
|
pub const fn absolute(value: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
absolute: value,
|
||||||
|
relative: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new relatively positioned `FramePoint`
|
||||||
|
pub const fn relative(value: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
absolute: 0.0,
|
||||||
|
relative: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `FramePoint` with both absolute and relative positioning
|
||||||
|
pub const fn relative_absolute(relative: f32, absolute: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
absolute,
|
||||||
|
relative,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve the `FramePoint` into an absolute coordinate
|
||||||
|
pub(crate) fn resolve(&self, parent_size: f32) -> f32 {
|
||||||
|
self.absolute + self.relative * parent_size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A 2-dimensional [`FramePoint`]
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Add, AddAssign, Sub, SubAssign)]
|
||||||
|
pub struct FramePoint2d {
|
||||||
|
pub x: FramePoint,
|
||||||
|
pub y: FramePoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(FramePoint, FramePoint)> for FramePoint2d {
|
||||||
|
fn from((x, y): (FramePoint, FramePoint)) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size> for FramePoint2d {
|
||||||
|
fn from(size: Size) -> Self {
|
||||||
|
Self {
|
||||||
|
x: size.into(),
|
||||||
|
y: size.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size2d> for FramePoint2d {
|
||||||
|
fn from(size: Size2d) -> Self {
|
||||||
|
Self {
|
||||||
|
x: size.width.into(),
|
||||||
|
y: size.height.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(f32, f32)> for FramePoint2d {
|
||||||
|
fn from((x, y): (f32, f32)) -> Self {
|
||||||
|
Self {
|
||||||
|
x: FramePoint::absolute(x),
|
||||||
|
y: FramePoint::absolute(y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec2> for FramePoint2d {
|
||||||
|
fn from(vec: Vec2) -> Self {
|
||||||
|
Self {
|
||||||
|
x: FramePoint::absolute(vec.x),
|
||||||
|
y: FramePoint::absolute(vec.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FramePoint2d {
|
||||||
|
/// Top left corner of the frame
|
||||||
|
pub const TOP_LEFT: Self = Self {
|
||||||
|
x: FramePoint::BEGIN,
|
||||||
|
y: FramePoint::BEGIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Top center of the frame
|
||||||
|
pub const TOP_CENTER: Self = Self {
|
||||||
|
x: FramePoint::CENTER,
|
||||||
|
y: FramePoint::BEGIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Top right corner of the frame
|
||||||
|
pub const TOP_RIGHT: Self = Self {
|
||||||
|
x: FramePoint::END,
|
||||||
|
y: FramePoint::BEGIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Center left of the frame
|
||||||
|
pub const CENTER_LEFT: Self = Self {
|
||||||
|
x: FramePoint::BEGIN,
|
||||||
|
y: FramePoint::CENTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Center of the frame
|
||||||
|
pub const CENTER: Self = Self {
|
||||||
|
x: FramePoint::CENTER,
|
||||||
|
y: FramePoint::CENTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Center right of the frame
|
||||||
|
pub const CENTER_RIGHT: Self = Self {
|
||||||
|
x: FramePoint::END,
|
||||||
|
y: FramePoint::CENTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Bottom left corner of the frame
|
||||||
|
pub const BOTTOM_LEFT: Self = Self {
|
||||||
|
x: FramePoint::BEGIN,
|
||||||
|
y: FramePoint::END,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Bottom center of the frame
|
||||||
|
pub const BOTTOM_CENTER: Self = Self {
|
||||||
|
x: FramePoint::CENTER,
|
||||||
|
y: FramePoint::END,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Bottom right corner of the frame
|
||||||
|
pub const BOTTOM_RIGHT: Self = Self {
|
||||||
|
x: FramePoint::END,
|
||||||
|
y: FramePoint::END,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Resolve the `FramePoint2d` into an absolute coordinate within the frame's coordinate system\
|
||||||
|
///
|
||||||
|
/// (point with absolute cordinates, relative to the frame's top-left corner)
|
||||||
|
pub(crate) fn resolve(&self, parent_size: Vec2) -> Vec2 {
|
||||||
|
let x = self.x.resolve(parent_size.x);
|
||||||
|
let y = self.y.resolve(parent_size.y);
|
||||||
|
vec2(x, y)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue