Compare commits

..

4 commits

Author SHA1 Message Date
griffi-gh 63f862c2be (todo) ui demo 2023-11-23 01:48:04 +01:00
griffi-gh 4263c1ff6c container impl (wip) 2023-11-23 01:47:54 +01:00
griffi-gh b28dca8721 add rect element 2023-11-23 01:47:27 +01:00
griffi-gh 3d8803f465 spacer default 2023-11-23 01:22:33 +01:00
6 changed files with 159 additions and 18 deletions

View file

@ -11,6 +11,9 @@ glam = { version = "0.24", features = ["approx"] }
glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf", optional = true } glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf", optional = true }
log = "0.4" log = "0.4"
[dev-dependencies]
glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf" }
[features] [features]
default = ["backend_glium", "builtin_elements"] default = ["backend_glium", "builtin_elements"]
backend_glium = ["dep:glium"] backend_glium = ["dep:glium"]

3
kubi-ui/examples/test.rs Normal file
View file

@ -0,0 +1,3 @@
pub fn main() {
//TODO ui demo
}

View file

@ -6,6 +6,7 @@ use crate::{
state::StateRepo state::StateRepo
}; };
#[cfg(feature = "builtin_elements")] pub mod rect;
#[cfg(feature = "builtin_elements")] pub mod container; #[cfg(feature = "builtin_elements")] pub mod container;
#[cfg(feature = "builtin_elements")] pub mod spacer; #[cfg(feature = "builtin_elements")] pub mod spacer;
#[cfg(feature = "builtin_elements")] pub mod progress_bar; #[cfg(feature = "builtin_elements")] pub mod progress_bar;

View file

@ -1,30 +1,58 @@
use glam::{Vec2, Vec4}; use glam::{Vec2, vec2, Vec4};
use crate::{UiDirection, LayoutInfo, draw::UiDrawCommand, measure::Response, state::StateRepo, UiSize}; use crate::{UiDirection, LayoutInfo, draw::UiDrawCommand, measure::Response, state::StateRepo, UiSize};
use super::UiElement; use super::UiElement;
#[derive(Default, Clone, Copy, Debug)] pub enum Alignment {
pub struct ContainerBorders {
pub top: Option<(Vec4, f32)>,
pub bottom: Option<(Vec4, f32)>,
pub left: Option<(Vec4, f32)>,
pub right: Option<(Vec4, f32)>,
}
pub enum ContainerAlign {
Begin, Begin,
Center, Center,
End, 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 struct Container {
pub min_size: (UiSize, UiSize), pub min_size: (UiSize, UiSize),
pub max_size: (UiSize, UiSize), pub max_size: (UiSize, UiSize),
pub direction: UiDirection, pub direction: UiDirection,
//pub reverse: bool,
pub gap: f32, pub gap: f32,
pub padding: f32, pub padding: Sides<f32>,
pub align: (ContainerAlign, ContainerAlign), pub align: (Alignment, Alignment),
pub background: Option<Vec4>, pub background: Option<Vec4>,
pub borders: ContainerBorders, pub borders: Sides<Option<Border>>,
pub clip: bool, pub clip: bool,
pub elements: Vec<Box<dyn UiElement>>, pub elements: Vec<Box<dyn UiElement>>,
} }
@ -35,9 +63,10 @@ impl Default for Container {
min_size: (UiSize::Auto, UiSize::Auto), min_size: (UiSize::Auto, UiSize::Auto),
max_size: (UiSize::Auto, UiSize::Auto), max_size: (UiSize::Auto, UiSize::Auto),
direction: UiDirection::Vertical, direction: UiDirection::Vertical,
//reverse: false,
gap: 0., gap: 0.,
padding: 0., padding: Sides::all(0.),
align: (ContainerAlign::Center, ContainerAlign::Begin), align: (Alignment::Center, Alignment::Begin),
background: Default::default(), background: Default::default(),
borders: Default::default(), borders: Default::default(),
clip: Default::default(), clip: Default::default(),
@ -53,7 +82,7 @@ impl UiElement for Container {
for element in &self.elements { for element in &self.elements {
let measure = element.measure(state, &LayoutInfo { let measure = element.measure(state, &LayoutInfo {
position: layout.position + size, position: layout.position + size,
max_size: layout.max_size - size, max_size: layout.max_size, // - size, //TODO
direction: self.direction, direction: self.direction,
}); });
match self.direction { match self.direction {
@ -74,14 +103,67 @@ impl UiElement for Container {
} }
fn process(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCommand>) { fn process(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCommand>) {
let mut position = layout.position;
//background
if let Some(color) = self.background { if let Some(color) = self.background {
draw.push(UiDrawCommand::Rectangle { draw.push(UiDrawCommand::Rectangle {
position: layout.position, position,
size: measure.desired_size, size: measure.desired_size,
color color
}); });
}
//TODO draw borders //padding
position += vec2(self.padding.left, self.padding.top);
//alignment
//TODO: REQUIRES MAX MEASURE SIZES!
// match self.align.0 {
// Alignment::Begin => (),
// Alignment::Center => {
// position.x += (layout.max_size.x - measure.desired_size.x) / 2.;
// },
// Alignment::End => {
// position.x += layout.max_size.x - measure.desired_size.x;
// }
// }
// match self.align.1 {
// Alignment::Begin => (),
// Alignment::Center => {
// position.y += (layout.max_size.y - measure.desired_size.y) / 2.;
// },
// Alignment::End => {
// position.y += layout.max_size.y - measure.desired_size.y;
// }
// }
for element in &self.elements {
//(passing max size from layout rather than actual bounds for the sake of consistency with measure() above)
//measure
let el_measure = element.measure(state, &LayoutInfo {
position,
max_size: layout.max_size,
direction: self.direction,
});
//process
element.process(&el_measure, state, &LayoutInfo {
position,
max_size: layout.max_size,
direction: self.direction,
}, draw);
//layout
match self.direction {
UiDirection::Horizontal => {
position.x += el_measure.desired_size.x + self.gap;
},
UiDirection::Vertical => {
position.y += el_measure.desired_size.y + self.gap;
}
}
} }
} }
} }

View file

@ -0,0 +1,46 @@
use glam::{vec2, Vec4};
use crate::{state::StateRepo, LayoutInfo, measure::Response, draw::UiDrawCommand, UiSize};
use super::UiElement;
pub struct Rect {
pub size: (UiSize, UiSize),
pub color: Option<Vec4>,
}
impl Default for Rect {
fn default() -> Self {
Self {
size: (UiSize::Pixels(10.), UiSize::Pixels(10.)),
color: Some(Vec4::new(0., 0., 0., 0.5)),
}
}
}
impl UiElement for Rect {
fn measure(&self, _state: &StateRepo, layout: &LayoutInfo) -> Response {
Response {
desired_size: vec2(
match self.size.0 {
UiSize::Auto => layout.max_size.x,
UiSize::Percentage(percentage) => layout.max_size.x * percentage,
UiSize::Pixels(pixels) => pixels,
},
match self.size.1 {
UiSize::Auto => layout.max_size.y,
UiSize::Percentage(percentage) => layout.max_size.y * percentage,
UiSize::Pixels(pixels) => pixels,
},
)
}
}
fn process(&self, measure: &Response, _state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCommand>) {
if let Some(color) = self.color {
draw.push(UiDrawCommand::Rectangle {
position: layout.position,
size: measure.desired_size,
color,
});
}
}
}

View file

@ -4,6 +4,12 @@ use super::UiElement;
pub struct Spacer(f32); pub struct Spacer(f32);
impl Default for Spacer {
fn default() -> Self {
Self(5.)
}
}
impl UiElement for Spacer { impl UiElement for Spacer {
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response { fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response {
Response { Response {