mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-09 17:18:41 -06:00
update ui system
This commit is contained in:
parent
927337c86d
commit
5678b0c06f
|
@ -2,12 +2,13 @@ use std::any::Any;
|
||||||
use crate::{
|
use crate::{
|
||||||
LayoutInfo,
|
LayoutInfo,
|
||||||
draw::UiDrawCall,
|
draw::UiDrawCall,
|
||||||
measure::{IsMeasurable, Response},
|
measure::Response,
|
||||||
state::StateRepo
|
state::StateRepo
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "builtin_elements")] pub mod container;
|
||||||
|
#[cfg(feature = "builtin_elements")] pub mod spacer;
|
||||||
#[cfg(feature = "builtin_elements")] pub mod progress_bar;
|
#[cfg(feature = "builtin_elements")] pub mod progress_bar;
|
||||||
#[cfg(feature = "builtin_elements")] pub mod layout_box;
|
|
||||||
|
|
||||||
pub trait UiElement {
|
pub trait UiElement {
|
||||||
fn name(&self) -> &'static str { "UiElement" }
|
fn name(&self) -> &'static str { "UiElement" }
|
||||||
|
@ -15,7 +16,6 @@ pub trait UiElement {
|
||||||
fn is_stateful(&self) -> bool { self.state_id().is_some() }
|
fn is_stateful(&self) -> bool { self.state_id().is_some() }
|
||||||
fn is_stateless(&self) -> bool { self.state_id().is_none() }
|
fn is_stateless(&self) -> bool { self.state_id().is_none() }
|
||||||
fn init_state(&self) -> Option<Box<dyn Any>> { None }
|
fn init_state(&self) -> Option<Box<dyn Any>> { None }
|
||||||
fn is_measurable(&self) -> IsMeasurable { IsMeasurable::No }
|
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response;
|
||||||
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Option<Response> { None }
|
fn draw(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>);
|
||||||
fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response;
|
|
||||||
}
|
}
|
||||||
|
|
87
kubi-ui/src/element/container.rs
Normal file
87
kubi-ui/src/element/container.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
use glam::{Vec2, Vec4};
|
||||||
|
use crate::{UiDirection, LayoutInfo, draw::UiDrawCall, measure::{IsMeasurable, Response}, state::StateRepo, UiSize};
|
||||||
|
use super::UiElement;
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy, Debug)]
|
||||||
|
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,
|
||||||
|
Center,
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Container {
|
||||||
|
pub min_size: (UiSize, UiSize),
|
||||||
|
pub max_size: (UiSize, UiSize),
|
||||||
|
pub direction: UiDirection,
|
||||||
|
pub gap: f32,
|
||||||
|
pub padding: f32,
|
||||||
|
pub align: (ContainerAlign, ContainerAlign),
|
||||||
|
pub background: Option<Vec4>,
|
||||||
|
pub borders: ContainerBorders,
|
||||||
|
pub clip: bool,
|
||||||
|
pub elements: Vec<Box<dyn UiElement>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Container {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
min_size: (UiSize::Auto, UiSize::Auto),
|
||||||
|
max_size: (UiSize::Auto, UiSize::Auto),
|
||||||
|
direction: UiDirection::Vertical,
|
||||||
|
gap: 0.,
|
||||||
|
padding: 0.,
|
||||||
|
align: (ContainerAlign::Center, ContainerAlign::Begin),
|
||||||
|
background: Default::default(),
|
||||||
|
borders: Default::default(),
|
||||||
|
clip: Default::default(),
|
||||||
|
elements: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UiElement for Container {
|
||||||
|
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response {
|
||||||
|
let mut size = Vec2::ZERO;
|
||||||
|
let mut leftover_gap = Vec2::ZERO;
|
||||||
|
for element in &self.elements {
|
||||||
|
let measure = element.measure(state, &LayoutInfo {
|
||||||
|
position: layout.position + size,
|
||||||
|
max_size: layout.max_size - size,
|
||||||
|
direction: self.direction,
|
||||||
|
});
|
||||||
|
match self.direction {
|
||||||
|
UiDirection::Horizontal => {
|
||||||
|
size.x += measure.desired_size.x + self.gap;
|
||||||
|
size.y = size.y.max(measure.desired_size.y);
|
||||||
|
leftover_gap.x = self.gap;
|
||||||
|
},
|
||||||
|
UiDirection::Vertical => {
|
||||||
|
size.x = size.x.max(measure.desired_size.x);
|
||||||
|
size.y += measure.desired_size.y + self.gap;
|
||||||
|
leftover_gap.y = self.gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size -= leftover_gap;
|
||||||
|
Response { desired_size: size }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) {
|
||||||
|
if let Some(color) = self.background {
|
||||||
|
draw.push(UiDrawCall::Rectangle {
|
||||||
|
position: layout.position,
|
||||||
|
size: measure.desired_size,
|
||||||
|
color
|
||||||
|
});
|
||||||
|
|
||||||
|
//TODO draw borders
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
use std::any::Any;
|
|
||||||
use crate::{UiDirection, LayoutInfo, draw::UiDrawCall, measure::{IsMeasurable, Response}, state::StateRepo};
|
|
||||||
use super::UiElement;
|
|
||||||
|
|
||||||
pub struct LayoutBox {
|
|
||||||
pub direction: UiDirection,
|
|
||||||
pub gap: f32,
|
|
||||||
pub elements: Vec<Box<dyn UiElement>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UiElement for LayoutBox {
|
|
||||||
fn is_measurable(&self) -> IsMeasurable {
|
|
||||||
IsMeasurable::Maybe
|
|
||||||
}
|
|
||||||
|
|
||||||
fn measure(&self, state: StateRepo, layout: &LayoutInfo) -> Option<Response> {
|
|
||||||
for element in &self.elements {
|
|
||||||
if element.is_measurable() == IsMeasurable::No {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
element.measure(None, layout);
|
|
||||||
}
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process(&self, _state: Option<&mut Box<dyn Any>>, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
use glam::{vec2, Vec2, Vec4};
|
use glam::{vec2, Vec4};
|
||||||
use crate::{
|
use crate::{
|
||||||
UiSize, LayoutInfo,
|
UiSize, LayoutInfo,
|
||||||
draw::UiDrawCall,
|
draw::UiDrawCall,
|
||||||
measure::{Response, IsMeasurable},
|
measure::Response,
|
||||||
state::StateRepo
|
state::StateRepo
|
||||||
};
|
};
|
||||||
use super::UiElement;
|
use super::UiElement;
|
||||||
|
@ -19,13 +19,11 @@ const BAR_HEIGHT: f32 = 20.0;
|
||||||
impl UiElement for ProgressBar {
|
impl UiElement for ProgressBar {
|
||||||
fn name(&self) -> &'static str { "Progress bar" }
|
fn name(&self) -> &'static str { "Progress bar" }
|
||||||
|
|
||||||
fn is_measurable(&self) -> IsMeasurable { IsMeasurable::Yes }
|
fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Response {
|
||||||
|
Response {
|
||||||
fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Option<Response> {
|
desired_size: vec2(
|
||||||
Some(Response {
|
|
||||||
size: Vec2::new(
|
|
||||||
match self.size.0 {
|
match self.size.0 {
|
||||||
UiSize::Auto => layout.max_size.x,
|
UiSize::Auto => layout.max_size.x.max(300.),
|
||||||
UiSize::Percentage(p) => layout.max_size.x * p,
|
UiSize::Percentage(p) => layout.max_size.x * p,
|
||||||
UiSize::Pixels(p) => p,
|
UiSize::Pixels(p) => p,
|
||||||
},
|
},
|
||||||
|
@ -35,24 +33,20 @@ impl UiElement for ProgressBar {
|
||||||
UiSize::Pixels(p) => p,
|
UiSize::Pixels(p) => p,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response {
|
fn draw(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) {
|
||||||
let measure = self.measure(&state, layout).unwrap();
|
|
||||||
|
|
||||||
draw.push(UiDrawCall::Rectangle {
|
draw.push(UiDrawCall::Rectangle {
|
||||||
position: layout.position,
|
position: layout.position,
|
||||||
size: measure.size,
|
size: measure.desired_size,
|
||||||
color: self.color_background
|
color: self.color_background
|
||||||
});
|
});
|
||||||
|
|
||||||
draw.push(UiDrawCall::Rectangle {
|
draw.push(UiDrawCall::Rectangle {
|
||||||
position: layout.position,
|
position: layout.position,
|
||||||
size: measure.size * vec2(self.value, 1.0),
|
size: measure.desired_size * vec2(self.value, 1.0),
|
||||||
color: self.color_foreground
|
color: self.color_foreground
|
||||||
});
|
});
|
||||||
|
|
||||||
measure
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
kubi-ui/src/element/spacer.rs
Normal file
18
kubi-ui/src/element/spacer.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use glam::vec2;
|
||||||
|
use crate::{state::StateRepo, LayoutInfo, measure::Response, draw::UiDrawCall, UiDirection};
|
||||||
|
use super::UiElement;
|
||||||
|
|
||||||
|
pub struct Spacer(f32);
|
||||||
|
|
||||||
|
impl UiElement for Spacer {
|
||||||
|
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response {
|
||||||
|
Response {
|
||||||
|
desired_size: match layout.direction {
|
||||||
|
UiDirection::Horizontal => vec2(self.0, 0.),
|
||||||
|
UiDirection::Vertical => vec2(0., self.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, _measure: &Response, _state: &mut StateRepo, _layout: &LayoutInfo, _draw: &mut Vec<UiDrawCall>) {}
|
||||||
|
}
|
|
@ -32,13 +32,15 @@ impl Default for KubiUi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub enum UiSize {
|
pub enum UiSize {
|
||||||
|
#[default]
|
||||||
Auto,
|
Auto,
|
||||||
Percentage(f32),
|
Percentage(f32),
|
||||||
Pixels(f32),
|
Pixels(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum UiDirection {
|
pub enum UiDirection {
|
||||||
#[default]
|
#[default]
|
||||||
Vertical,
|
Vertical,
|
||||||
|
@ -46,6 +48,7 @@ pub enum UiDirection {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LayoutInfo {
|
struct LayoutInfo {
|
||||||
|
///Not availabe during measuring step
|
||||||
position: Vec2,
|
position: Vec2,
|
||||||
max_size: Vec2,
|
max_size: Vec2,
|
||||||
direction: UiDirection,
|
direction: UiDirection,
|
||||||
|
|
|
@ -9,5 +9,5 @@ pub enum IsMeasurable {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
pub size: Vec2
|
pub desired_size: Vec2
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue