From 5678b0c06f4cd90b883cf67d471891d08c07b153 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Tue, 21 Nov 2023 16:14:26 +0100 Subject: [PATCH] update ui system --- kubi-ui/src/element.rs | 10 ++-- kubi-ui/src/element/container.rs | 87 +++++++++++++++++++++++++++++ kubi-ui/src/element/layout_box.rs | 29 ---------- kubi-ui/src/element/progress_bar.rs | 26 ++++----- kubi-ui/src/element/spacer.rs | 18 ++++++ kubi-ui/src/lib.rs | 5 +- kubi-ui/src/measure.rs | 2 +- 7 files changed, 125 insertions(+), 52 deletions(-) create mode 100644 kubi-ui/src/element/container.rs delete mode 100644 kubi-ui/src/element/layout_box.rs create mode 100644 kubi-ui/src/element/spacer.rs diff --git a/kubi-ui/src/element.rs b/kubi-ui/src/element.rs index 89625b5..4d8c786 100644 --- a/kubi-ui/src/element.rs +++ b/kubi-ui/src/element.rs @@ -2,12 +2,13 @@ use std::any::Any; use crate::{ LayoutInfo, draw::UiDrawCall, - measure::{IsMeasurable, Response}, + measure::Response, 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 layout_box; pub trait 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_stateless(&self) -> bool { self.state_id().is_none() } fn init_state(&self) -> Option> { None } - fn is_measurable(&self) -> IsMeasurable { IsMeasurable::No } - fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Option { None } - fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec) -> Response; + fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response; + fn draw(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec); } diff --git a/kubi-ui/src/element/container.rs b/kubi-ui/src/element/container.rs new file mode 100644 index 0000000..4f21d20 --- /dev/null +++ b/kubi-ui/src/element/container.rs @@ -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, + pub borders: ContainerBorders, + pub clip: bool, + pub elements: Vec>, +} + +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) { + if let Some(color) = self.background { + draw.push(UiDrawCall::Rectangle { + position: layout.position, + size: measure.desired_size, + color + }); + + //TODO draw borders + } + } +} diff --git a/kubi-ui/src/element/layout_box.rs b/kubi-ui/src/element/layout_box.rs deleted file mode 100644 index 9578ba3..0000000 --- a/kubi-ui/src/element/layout_box.rs +++ /dev/null @@ -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>, -} - -impl UiElement for LayoutBox { - fn is_measurable(&self) -> IsMeasurable { - IsMeasurable::Maybe - } - - fn measure(&self, state: StateRepo, layout: &LayoutInfo) -> Option { - 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>, layout: &LayoutInfo, draw: &mut Vec) -> Response { - todo!() - } -} diff --git a/kubi-ui/src/element/progress_bar.rs b/kubi-ui/src/element/progress_bar.rs index 7b1ee13..c9879f1 100644 --- a/kubi-ui/src/element/progress_bar.rs +++ b/kubi-ui/src/element/progress_bar.rs @@ -1,8 +1,8 @@ -use glam::{vec2, Vec2, Vec4}; +use glam::{vec2, Vec4}; use crate::{ UiSize, LayoutInfo, draw::UiDrawCall, - measure::{Response, IsMeasurable}, + measure::Response, state::StateRepo }; use super::UiElement; @@ -19,13 +19,11 @@ const BAR_HEIGHT: f32 = 20.0; impl UiElement for ProgressBar { fn name(&self) -> &'static str { "Progress bar" } - fn is_measurable(&self) -> IsMeasurable { IsMeasurable::Yes } - - fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Option { - Some(Response { - size: Vec2::new( + fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Response { + Response { + desired_size: vec2( 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::Pixels(p) => p, }, @@ -35,24 +33,20 @@ impl UiElement for ProgressBar { UiSize::Pixels(p) => p, } ) - }) + } } - fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec) -> Response { - let measure = self.measure(&state, layout).unwrap(); - + fn draw(&self, measure: &Response, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec) { draw.push(UiDrawCall::Rectangle { position: layout.position, - size: measure.size, + size: measure.desired_size, color: self.color_background }); draw.push(UiDrawCall::Rectangle { position: layout.position, - size: measure.size * vec2(self.value, 1.0), + size: measure.desired_size * vec2(self.value, 1.0), color: self.color_foreground }); - - measure } } diff --git a/kubi-ui/src/element/spacer.rs b/kubi-ui/src/element/spacer.rs new file mode 100644 index 0000000..38f754a --- /dev/null +++ b/kubi-ui/src/element/spacer.rs @@ -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) {} +} diff --git a/kubi-ui/src/lib.rs b/kubi-ui/src/lib.rs index bb27ad9..cc229fc 100644 --- a/kubi-ui/src/lib.rs +++ b/kubi-ui/src/lib.rs @@ -32,13 +32,15 @@ impl Default for KubiUi { } } +#[derive(Default)] pub enum UiSize { + #[default] Auto, Percentage(f32), Pixels(f32), } -#[derive(Default)] +#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum UiDirection { #[default] Vertical, @@ -46,6 +48,7 @@ pub enum UiDirection { } struct LayoutInfo { + ///Not availabe during measuring step position: Vec2, max_size: Vec2, direction: UiDirection, diff --git a/kubi-ui/src/measure.rs b/kubi-ui/src/measure.rs index 130e9a9..e5c02d8 100644 --- a/kubi-ui/src/measure.rs +++ b/kubi-ui/src/measure.rs @@ -9,5 +9,5 @@ pub enum IsMeasurable { } pub struct Response { - pub size: Vec2 + pub desired_size: Vec2 }