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}
};
use hui::{
draw::CornerRadius, element::{
container::{Alignment, Container, Sides}, progress_bar::ProgressBar, text::Text
}, elements, UiDirection, UiInstance, UiSize
UiInstance, elements,
layout::{Alignment, UiDirection, UiSize},
rectangle::{Corners, Sides},
element::{
container::Container,
progress_bar::ProgressBar,
text::Text,
},
};
use hui_glium::GliumUiRenderer;
@ -52,7 +57,7 @@ fn main() {
align: (Alignment::Begin, Alignment::Begin),
size: (UiSize::Static(450.), UiSize::Auto),
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| {
if instant.elapsed().as_secs_f32() < 5. {
el.add(Text {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,14 +26,18 @@ nz = "0.3"
document-features = "0.2"
[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)
builtin_font = []
## Enable the built-in elements (`Container`, `ProgressBar`, etc.)\
builtin_elements = ["builtin_container"]
## Enable only the `Container` component (which is essential for laying out other components)
builtin_container = []
## Round vertex positions to nearest integer coordinates (fixes blurry text)
pixel_perfect = []
#parallel = ["dep:rayon", "fontdue/parallel"]
## Round all vertex positions to nearest integer coordinates (not recommended)
pixel_perfect = ["pixel_perfect_text"]
## Apply pixel-perfect rendering hack to text (fixes blurry text rendering)
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;
pub use corner_radius::{CornerRadius, RoundedCorners};
pub use corner_radius::RoundedCorners;
use std::borrow::Cow;
use fontdue::layout::{Layout, CoordinateSystem, TextStyle};
use glam::{Vec2, Vec4, vec2};
@ -157,7 +157,7 @@ impl UiDrawPlan {
match command {
UiDrawCommand::Rectangle { position, size, color, rounded_corners } => {
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
//Random vert in the center for no reason
@ -271,6 +271,10 @@ impl UiDrawPlan {
todo!("circle draw command not implemented yet")
},
UiDrawCommand::Text { position, size, color, text, font } => {
if text.is_empty() {
continue
}
//XXX: should we be doing this every time?
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
layout.append(
@ -314,12 +318,20 @@ impl UiDrawPlan {
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")]
swapper.current_mut().vertices.iter_mut().for_each(|v| {
v.position = v.position.floor()
v.position = v.position.round()
});
prev_command = Some(command);
}

View file

@ -1,90 +1,25 @@
use std::num::NonZeroU16;
use crate::Corners;
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct CornerRadius {
pub top_left: f32,
pub top_right: f32,
pub bottom_left: f32,
pub bottom_right: f32,
}
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 {
fn point_count(corners: Corners<f32>) -> 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
(corners.max_f32() * 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)]
pub struct RoundedCorners {
pub radius: CornerRadius,
pub radius: Corners<f32>,
pub point_count: NonZeroU16,
}
impl RoundedCorners {
pub fn from_radius(radius: CornerRadius) -> Self {
pub fn from_radius(radius: Corners<f32>) -> Self {
Self {
radius,
point_count: radius.point_count(),
point_count: point_count(radius),
}
}
}
@ -92,7 +27,7 @@ impl RoundedCorners {
impl Default for RoundedCorners {
fn default() -> Self {
Self {
radius: CornerRadius::default(),
radius: Corners::default(),
point_count: NonZeroU16::new(8).unwrap(),
}
}

View file

@ -1,53 +1,17 @@
use glam::{Vec2, vec2, Vec4};
use crate::{
draw::{CornerRadius, RoundedCorners, UiDrawCommand},
layout::{Alignment, LayoutInfo, UiDirection, UiSize},
rectangle::{Corners, Sides},
draw::{RoundedCorners, UiDrawCommand},
element::{MeasureContext, ProcessContext, UiElement},
measure::{Hints, Response},
LayoutInfo, UiDirection, UiSize
};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Alignment {
Begin,
Center,
End,
}
pub struct Border {
pub color: Vec4,
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 min_size: (UiSize, UiSize),
// pub max_size: (UiSize, UiSize),
@ -62,7 +26,7 @@ pub struct Container {
pub borders: Sides<Option<Border>>,
//pub clip: bool, //TODO clip children
pub elements: Vec<Box<dyn UiElement>>,
pub corner_radius: Option<CornerRadius>,
pub corner_radius: Option<Corners<f32>>,
}
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;
pub mod layout;
pub mod rectangle;
pub mod element;
pub mod event;
pub mod input;
@ -17,8 +19,9 @@ pub mod draw;
pub mod measure;
pub mod state;
pub mod text;
pub mod interaction;
use layout::{UiDirection, UiSize, LayoutInfo};
use rectangle::{Corners, Sides};
use element::{MeasureContext, ProcessContext, UiElement};
use event::UiEvent;
use state::StateRepo;
@ -122,35 +125,20 @@ impl Default for UiInstance {
}
}
#[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,
}
#[allow(deprecated)]
#[deprecated(since = "0.1.0-alpha.3", note = "will be removed in the next release")]
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 {
pub fn add(&mut self, element: impl UiElement + 'static) {
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>> {
let mut elements = ElementList(Vec::new());
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,
}
}
}