refactor stuff

This commit is contained in:
griffi-gh 2024-02-20 17:30:26 +01:00
parent afcaf5fbef
commit f657c2df5f
14 changed files with 239 additions and 166 deletions

View file

@ -6,9 +6,14 @@ use winit::{
event_loop::{EventLoopBuilder, ControlFlow} event_loop::{EventLoopBuilder, ControlFlow}
}; };
use hui::{ use hui::{
draw::CornerRadius, element::{ UiInstance, elements,
container::{Alignment, Container, Sides}, progress_bar::ProgressBar, text::Text layout::{Alignment, UiDirection, UiSize},
}, elements, UiDirection, UiInstance, UiSize rectangle::{Corners, Sides},
element::{
container::Container,
progress_bar::ProgressBar,
text::Text,
},
}; };
use hui_glium::GliumUiRenderer; use hui_glium::GliumUiRenderer;
@ -52,7 +57,7 @@ fn main() {
align: (Alignment::Begin, Alignment::Begin), align: (Alignment::Begin, Alignment::Begin),
size: (UiSize::Static(450.), UiSize::Auto), size: (UiSize::Static(450.), UiSize::Auto),
background: Some(vec4(0.2, 0.2, 0.5, 1.)), background: Some(vec4(0.2, 0.2, 0.5, 1.)),
corner_radius: Some(CornerRadius::all(8.)), corner_radius: Some(Corners::all(8.)),
elements: elements(|el| { elements: elements(|el| {
if instant.elapsed().as_secs_f32() < 5. { if instant.elapsed().as_secs_f32() < 5. {
el.add(Text { el.add(Text {

View file

@ -5,10 +5,13 @@ use winit::{
event_loop::{EventLoopBuilder, ControlFlow} event_loop::{EventLoopBuilder, ControlFlow}
}; };
use hui::{ use hui::{
draw::CornerRadius, element::{ UiInstance,
container::{Alignment, Container, Sides}, layout::{Alignment, UiSize, UiDirection},
rectangle::{Corners, Sides},
element::{
container::Container,
text::Text text::Text
}, UiDirection, UiInstance, UiSize },
}; };
use hui_glium::GliumUiRenderer; use hui_glium::GliumUiRenderer;
@ -41,7 +44,7 @@ fn main() {
align: (Alignment::Center, Alignment::Center), align: (Alignment::Center, Alignment::Center),
size: (UiSize::Fraction(0.5), UiSize::Fraction(0.5)), size: (UiSize::Fraction(0.5), UiSize::Fraction(0.5)),
background: Some(vec4(1., 0., 0., 1.)), background: Some(vec4(1., 0., 0., 1.)),
corner_radius: Some(CornerRadius { corner_radius: Some(Corners {
top_left: 10., top_left: 10.,
top_right: 20., top_right: 20.,
bottom_left: 50., bottom_left: 50.,
@ -54,7 +57,7 @@ fn main() {
align: (Alignment::Center, Alignment::Center), align: (Alignment::Center, Alignment::Center),
size: (UiSize::Auto, UiSize::Auto), size: (UiSize::Auto, UiSize::Auto),
background: Some(vec4(0.1, 0.1, 0.1, 0.5)), background: Some(vec4(0.1, 0.1, 0.1, 0.5)),
corner_radius: Some(CornerRadius::all(8.)), corner_radius: Some(Corners::all(8.)),
elements: vec![ elements: vec![
Box::new(Text { Box::new(Text {
text: "Corners".into(), text: "Corners".into(),

View file

@ -7,12 +7,13 @@ use winit::{
}; };
use hui::{ use hui::{
UiInstance, UiInstance,
layout::UiSize,
rectangle::Sides,
element::{ element::{
UiElement, container::Container,
progress_bar::ProgressBar, progress_bar::ProgressBar,
container::{Container, Sides} UiElement
}, },
UiSize
}; };
use hui_glium::GliumUiRenderer; use hui_glium::GliumUiRenderer;

View file

@ -6,11 +6,13 @@ use winit::{
event_loop::{EventLoopBuilder, ControlFlow} event_loop::{EventLoopBuilder, ControlFlow}
}; };
use hui::{ use hui::{
UiInstance, UiSize, UiDirection, UiInstance,
layout::{Alignment, UiSize, UiDirection},
rectangle::{Sides, Corners},
element::{ element::{
UiElement, UiElement,
progress_bar::ProgressBar, progress_bar::ProgressBar,
container::{Container, Sides, Alignment}, container::Container,
rect::Rect rect::Rect
}, },
}; };
@ -116,6 +118,12 @@ fn main() {
left: 30., left: 30.,
right: 40., right: 40.,
}, },
corner_radius: Some(Corners {
top_left: 0.,
top_right: 30.,
bottom_left: 0.,
bottom_right: 0.,
}),
elements: vec![ elements: vec![
Box::new(Rect { Box::new(Rect {
size: (UiSize::Static(50.), UiSize::Static(50.)), size: (UiSize::Static(50.), UiSize::Static(50.)),

View file

@ -5,9 +5,11 @@ use winit::{
event_loop::{EventLoopBuilder, ControlFlow} event_loop::{EventLoopBuilder, ControlFlow}
}; };
use hui::{ use hui::{
UiInstance, UiSize, UiInstance,
rectangle::Sides,
layout::{UiSize, Alignment},
element::{ element::{
container::{Alignment, Container, Sides}, container::Container,
text::Text, text::Text,
} }
}; };

View file

@ -6,13 +6,12 @@ use winit::{
event_loop::{EventLoopBuilder, ControlFlow} event_loop::{EventLoopBuilder, ControlFlow}
}; };
use hui::{ use hui::{
UiInstance, UiInstance, elements,
layout::UiSize,
element::{ element::{
container::Container, container::Container,
text::Text, rect::Rect, spacer::Spacer text::Text, rect::Rect, spacer::Spacer
}, },
UiSize,
elements,
}; };
use hui_glium::GliumUiRenderer; use hui_glium::GliumUiRenderer;

View file

@ -26,14 +26,18 @@ nz = "0.3"
document-features = "0.2" document-features = "0.2"
[features] [features]
default = ["builtin_elements", "builtin_font", "pixel_perfect"] default = ["builtin_elements", "builtin_font", "pixel_perfect_text"]
## Enable the built-in font (ProggyTiny, adds 35kb to the executable) ## Enable the built-in font (ProggyTiny, adds 35kb to the executable)
builtin_font = [] builtin_font = []
## Enable the built-in elements (`Container`, `ProgressBar`, etc.)\ ## Enable the built-in elements (`Container`, `ProgressBar`, etc.)\
builtin_elements = ["builtin_container"] builtin_elements = ["builtin_container"]
## Enable only the `Container` component (which is essential for laying out other components) ## Enable only the `Container` component (which is essential for laying out other components)
builtin_container = [] builtin_container = []
## Round vertex positions to nearest integer coordinates (fixes blurry text) ## Round all vertex positions to nearest integer coordinates (not recommended)
pixel_perfect = [] pixel_perfect = ["pixel_perfect_text"]
## Apply pixel-perfect rendering hack to text (fixes blurry text rendering)
#parallel = ["dep:rayon", "fontdue/parallel"] pixel_perfect_text = []
#! Make sure to disable the `pixel_perfect` feature if you are rendering UI in 3D space\
#! or using DPI (or any other form of) scaling while passing the virtual resolution to the ui
# ## Enable multi-threading support (currently only affects some 3rd-party libraries)
# parallel = ["fontdue/parallel"]

View file

@ -2,7 +2,7 @@ use crate::{IfModified, text::{TextRenderer, FontHandle}};
mod corner_radius; mod corner_radius;
pub use corner_radius::{CornerRadius, RoundedCorners}; pub use corner_radius::RoundedCorners;
use std::borrow::Cow; use std::borrow::Cow;
use fontdue::layout::{Layout, CoordinateSystem, TextStyle}; use fontdue::layout::{Layout, CoordinateSystem, TextStyle};
use glam::{Vec2, Vec4, vec2}; use glam::{Vec2, Vec4, vec2};
@ -157,7 +157,7 @@ impl UiDrawPlan {
match command { match command {
UiDrawCommand::Rectangle { position, size, color, rounded_corners } => { UiDrawCommand::Rectangle { position, size, color, rounded_corners } => {
let vidx = swapper.current().vertices.len() as u32; let vidx = swapper.current().vertices.len() as u32;
if let Some(corner) = rounded_corners.filter(|x| x.radius.max() > 0.0) { if let Some(corner) = rounded_corners.filter(|x| x.radius.max_f32() > 0.0) {
//this code is stupid as fuck //this code is stupid as fuck
//Random vert in the center for no reason //Random vert in the center for no reason
@ -271,6 +271,10 @@ impl UiDrawPlan {
todo!("circle draw command not implemented yet") todo!("circle draw command not implemented yet")
}, },
UiDrawCommand::Text { position, size, color, text, font } => { UiDrawCommand::Text { position, size, color, text, font } => {
if text.is_empty() {
continue
}
//XXX: should we be doing this every time? //XXX: should we be doing this every time?
let mut layout = Layout::new(CoordinateSystem::PositiveYDown); let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
layout.append( layout.append(
@ -314,12 +318,20 @@ impl UiDrawPlan {
uv: vec2(p0x, p1y), uv: vec2(p0x, p1y),
}, },
]); ]);
#[cfg(all(
feature = "pixel_perfect_text",
not(feature = "pixel_perfect")
))] {
for vtx in &mut swapper.current_mut().vertices[(vidx as usize)..] {
vtx.position = vtx.position.round()
}
}
} }
} }
} }
#[cfg(feature = "pixel_perfect")] #[cfg(feature = "pixel_perfect")]
swapper.current_mut().vertices.iter_mut().for_each(|v| { swapper.current_mut().vertices.iter_mut().for_each(|v| {
v.position = v.position.floor() v.position = v.position.round()
}); });
prev_command = Some(command); prev_command = Some(command);
} }

View file

@ -1,90 +1,25 @@
use std::num::NonZeroU16; use std::num::NonZeroU16;
use crate::Corners;
#[derive(Clone, Copy, Debug, PartialEq, Default)] fn point_count(corners: Corners<f32>) -> NonZeroU16 {
pub struct CornerRadius { //Increase for higher quality
pub top_left: f32, const VTX_PER_CORER_RADIUS_PIXEL: f32 = 0.5;
pub top_right: f32, NonZeroU16::new(
pub bottom_left: f32, (corners.max_f32() * VTX_PER_CORER_RADIUS_PIXEL).round() as u16 + 2
pub bottom_right: f32, ).unwrap()
}
impl CornerRadius {
pub const fn all(radius: f32) -> Self {
Self {
top_left: radius,
top_right: radius,
bottom_left: radius,
bottom_right: radius,
}
}
pub const fn none() -> Self {
Self::all(0.0)
}
pub const fn top_bottom(top: f32, bottom: f32) -> Self {
Self {
top_left: top,
top_right: top,
bottom_left: bottom,
bottom_right: bottom,
}
}
pub const fn left_right(left: f32, right: f32) -> Self {
Self {
top_left: left,
top_right: right,
bottom_left: left,
bottom_right: right,
}
}
//XXX: should these be public? (don't see any reason to NOT expose them)
pub fn max(&self) -> f32 {
self.top_left
.max(self.top_right)
.max(self.bottom_left)
.max(self.bottom_right)
}
pub fn point_count(&self) -> NonZeroU16 {
//Increase for higher quality
const VTX_PER_CORER_RADIUS_PIXEL: f32 = 0.5;
NonZeroU16::new(
(self.max() * VTX_PER_CORER_RADIUS_PIXEL).round() as u16 + 2
).unwrap()
}
}
impl From<f32> for CornerRadius {
fn from(radius: f32) -> Self {
Self::all(radius)
}
}
impl From<(f32, f32, f32, f32)> for CornerRadius {
fn from((top_left, top_right, bottom_left, bottom_right): (f32, f32, f32, f32)) -> Self {
Self {
top_left,
top_right,
bottom_left,
bottom_right,
}
}
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct RoundedCorners { pub struct RoundedCorners {
pub radius: CornerRadius, pub radius: Corners<f32>,
pub point_count: NonZeroU16, pub point_count: NonZeroU16,
} }
impl RoundedCorners { impl RoundedCorners {
pub fn from_radius(radius: CornerRadius) -> Self { pub fn from_radius(radius: Corners<f32>) -> Self {
Self { Self {
radius, radius,
point_count: radius.point_count(), point_count: point_count(radius),
} }
} }
} }
@ -92,7 +27,7 @@ impl RoundedCorners {
impl Default for RoundedCorners { impl Default for RoundedCorners {
fn default() -> Self { fn default() -> Self {
Self { Self {
radius: CornerRadius::default(), radius: Corners::default(),
point_count: NonZeroU16::new(8).unwrap(), point_count: NonZeroU16::new(8).unwrap(),
} }
} }

View file

@ -1,53 +1,17 @@
use glam::{Vec2, vec2, Vec4}; use glam::{Vec2, vec2, Vec4};
use crate::{ use crate::{
draw::{CornerRadius, RoundedCorners, UiDrawCommand}, layout::{Alignment, LayoutInfo, UiDirection, UiSize},
rectangle::{Corners, Sides},
draw::{RoundedCorners, UiDrawCommand},
element::{MeasureContext, ProcessContext, UiElement}, element::{MeasureContext, ProcessContext, UiElement},
measure::{Hints, Response}, measure::{Hints, Response},
LayoutInfo, UiDirection, UiSize
}; };
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Alignment {
Begin,
Center,
End,
}
pub struct Border { pub struct Border {
pub color: Vec4, pub color: Vec4,
pub width: f32, pub width: f32,
} }
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
pub struct Sides<T> {
pub top: T,
pub bottom: T,
pub left: T,
pub right: T,
}
impl<T: Clone> Sides<T> {
#[inline]
pub fn all(value: T) -> Self {
Self {
top: value.clone(),
bottom: value.clone(),
left: value.clone(),
right: value,
}
}
#[inline]
pub fn horizontal_vertical(horizontal: T, vertical: T) -> Self {
Self {
top: vertical.clone(),
bottom: vertical,
left: horizontal.clone(),
right: horizontal,
}
}
}
pub struct Container { pub struct Container {
// pub min_size: (UiSize, UiSize), // pub min_size: (UiSize, UiSize),
// pub max_size: (UiSize, UiSize), // pub max_size: (UiSize, UiSize),
@ -62,7 +26,7 @@ pub struct Container {
pub borders: Sides<Option<Border>>, pub borders: Sides<Option<Border>>,
//pub clip: bool, //TODO clip children //pub clip: bool, //TODO clip children
pub elements: Vec<Box<dyn UiElement>>, pub elements: Vec<Box<dyn UiElement>>,
pub corner_radius: Option<CornerRadius>, pub corner_radius: Option<Corners<f32>>,
} }
impl Default for Container { impl Default for Container {

33
hui/src/layout.rs Normal file
View file

@ -0,0 +1,33 @@
//! Layout related types and functions
use glam::Vec2;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, PartialOrd, Ord)]
pub enum Alignment {
#[default]
Begin = 0,
Center = 1,
End = 2,
}
#[derive(Default, Debug, Clone, Copy)]
pub enum UiSize {
#[default]
Auto,
Fraction(f32),
Static(f32),
}
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum UiDirection {
#[default]
Vertical,
Horizontal,
}
pub struct LayoutInfo {
///Not availabe during measuring step
pub position: Vec2,
pub max_size: Vec2,
pub direction: UiDirection,
}

View file

@ -10,6 +10,8 @@
use std::collections::VecDeque; use std::collections::VecDeque;
pub mod layout;
pub mod rectangle;
pub mod element; pub mod element;
pub mod event; pub mod event;
pub mod input; pub mod input;
@ -17,8 +19,9 @@ pub mod draw;
pub mod measure; pub mod measure;
pub mod state; pub mod state;
pub mod text; pub mod text;
pub mod interaction;
use layout::{UiDirection, UiSize, LayoutInfo};
use rectangle::{Corners, Sides};
use element::{MeasureContext, ProcessContext, UiElement}; use element::{MeasureContext, ProcessContext, UiElement};
use event::UiEvent; use event::UiEvent;
use state::StateRepo; use state::StateRepo;
@ -122,35 +125,20 @@ impl Default for UiInstance {
} }
} }
#[derive(Default, Debug, Clone, Copy)] #[allow(deprecated)]
pub enum UiSize { #[deprecated(since = "0.1.0-alpha.3", note = "will be removed in the next release")]
#[default]
Auto,
Fraction(f32),
Static(f32),
}
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum UiDirection {
#[default]
Vertical,
Horizontal,
}
pub struct LayoutInfo {
///Not availabe during measuring step
pub position: Vec2,
pub max_size: Vec2,
pub direction: UiDirection,
}
pub struct ElementList(Vec<Box<dyn UiElement>>); pub struct ElementList(Vec<Box<dyn UiElement>>);
#[allow(deprecated)]
#[deprecated(since = "0.1.0-alpha.3", note = "will be removed in the next release")]
impl ElementList { impl ElementList {
pub fn add(&mut self, element: impl UiElement + 'static) { pub fn add(&mut self, element: impl UiElement + 'static) {
self.0.push(Box::new(element)); self.0.push(Box::new(element));
} }
} }
#[allow(deprecated)]
#[deprecated(since = "0.1.0-alpha.3", note = "will be removed in the next release")]
pub fn elements(f: impl FnOnce(&mut ElementList)) -> Vec<Box<dyn UiElement>> { pub fn elements(f: impl FnOnce(&mut ElementList)) -> Vec<Box<dyn UiElement>> {
let mut elements = ElementList(Vec::new()); let mut elements = ElementList(Vec::new());
f(&mut elements); f(&mut elements);

119
hui/src/rectangle.rs Normal file
View file

@ -0,0 +1,119 @@
//! This module contains the definitions of the `Sides` and `Corners` structs,
//! which represent the sides and corners of a rectangular shape.
/// Represents 4 sides of a rectangular shape.
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
pub struct Sides<T> {
pub top: T,
pub bottom: T,
pub left: T,
pub right: T,
}
impl<T: Clone> Sides<T> {
#[inline]
pub fn all(value: T) -> Self {
Self {
top: value.clone(),
bottom: value.clone(),
left: value.clone(),
right: value,
}
}
#[inline]
pub fn horizontal_vertical(horizontal: T, vertical: T) -> Self {
Self {
top: vertical.clone(),
bottom: vertical,
left: horizontal.clone(),
right: horizontal,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct Corners<T> {
pub top_left: T,
pub top_right: T,
pub bottom_left: T,
pub bottom_right: T,
}
impl<T: Clone> Corners<T> {
#[inline]
pub fn all(value: T) -> Self {
Self {
top_left: value.clone(),
top_right: value.clone(),
bottom_left: value.clone(),
bottom_right: value,
}
}
#[inline]
pub fn top_bottom(top: T, bottom: T) -> Self {
Self {
top_left: top.clone(),
top_right: top,
bottom_left: bottom.clone(),
bottom_right: bottom,
}
}
#[inline]
pub fn left_right(left: T, right: T) -> Self {
Self {
top_left: left.clone(),
top_right: right.clone(),
bottom_left: left,
bottom_right: right,
}
}
}
impl <T: Ord + Clone> Corners<T> {
pub fn max(&self) -> T {
self.top_left.clone()
.max(self.top_right.clone())
.max(self.bottom_left.clone())
.max(self.bottom_right.clone())
.clone()
}
}
/// Represents 4 corners of a rectangular shape.
impl Corners<f32> {
pub fn max_f32(&self) -> f32 {
self.top_left
.max(self.top_right)
.max(self.bottom_left)
.max(self.bottom_right)
}
}
impl Corners<f64> {
pub fn max_f64(&self) -> f64 {
self.top_left
.max(self.top_right)
.max(self.bottom_left)
.max(self.bottom_right)
}
}
impl<T: Clone> From<T> for Corners<T> {
fn from(value: T) -> Self {
Self::all(value)
}
}
impl<T> From<(T, T, T, T)> for Corners<T> {
fn from((top_left, top_right, bottom_left, bottom_right): (T, T, T, T)) -> Self {
Self {
top_left,
top_right,
bottom_left,
bottom_right,
}
}
}