mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-25 00:08:42 -06:00
Compare commits
3 commits
0af548320b
...
2e91b3a9ee
Author | SHA1 | Date | |
---|---|---|---|
griffi-gh | 2e91b3a9ee | ||
griffi-gh | eb23bdb448 | ||
griffi-gh | bf5b05295d |
|
@ -1,5 +1,5 @@
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use glam::{Vec2, IVec2, UVec2};
|
use glam::{Vec2, IVec2, UVec2, vec4};
|
||||||
use glium::{backend::glutin::SimpleWindowBuilder, Surface};
|
use glium::{backend::glutin::SimpleWindowBuilder, Surface};
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{Event, WindowEvent},
|
event::{Event, WindowEvent},
|
||||||
|
@ -7,7 +7,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
use kubi_ui::{
|
use kubi_ui::{
|
||||||
KubiUi,
|
KubiUi,
|
||||||
backend::glium::GliumUiRenderer, element::{progress_bar::ProgressBar, container::{Container, Sides}, UiElement}, UiSize
|
backend::glium::GliumUiRenderer, element::{progress_bar::ProgressBar, container::{Container, Sides, Alignment}, UiElement, rect::Rect}, UiSize, UiDirection
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -34,18 +34,85 @@ fn main() {
|
||||||
|
|
||||||
kui.begin();
|
kui.begin();
|
||||||
|
|
||||||
|
let z = instant.elapsed().as_secs_f32().sin().powi(2);
|
||||||
|
|
||||||
kui.add(Container {
|
kui.add(Container {
|
||||||
gap: 5.,
|
gap: 5.,
|
||||||
padding: Sides::all(5.),
|
padding: Sides::all(5.),
|
||||||
|
align: (Alignment::Begin, Alignment::Center),
|
||||||
|
size: (UiSize::Percentage(1.), UiSize::Percentage(1.)),
|
||||||
elements: vec![
|
elements: vec![
|
||||||
Box::new(ProgressBar {
|
Box::new(ProgressBar {
|
||||||
value: 0.5,
|
value: 0.5,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
}, resolution);
|
||||||
|
|
||||||
|
kui.add(Container {
|
||||||
|
gap: 5.,
|
||||||
|
padding: Sides::all(5.),
|
||||||
|
align: (Alignment::End, Alignment::Center),
|
||||||
|
size: (UiSize::Percentage(1.), UiSize::Percentage(1.)),
|
||||||
|
elements: vec![
|
||||||
Box::new(ProgressBar {
|
Box::new(ProgressBar {
|
||||||
value: instant.elapsed().as_secs_f32().sin().powi(2),
|
value: z,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|
Box::new(Container {
|
||||||
|
size: (UiSize::Percentage(1.), UiSize::Auto),
|
||||||
|
align: (Alignment::Center, Alignment::End),
|
||||||
|
padding: Sides::all(5.),
|
||||||
|
gap: 10.,
|
||||||
|
elements: vec![
|
||||||
|
Box::new(Rect {
|
||||||
|
size: (UiSize::Percentage(0.5), UiSize::Pixels(30.)),
|
||||||
|
color: Some(vec4(0.75, 0., 0., 1.))
|
||||||
|
}),
|
||||||
|
Box::new(Rect {
|
||||||
|
size: (UiSize::Percentage(z / 2. + 0.5), UiSize::Pixels(30.)),
|
||||||
|
color: Some(vec4(0., 0.75, 0., 1.))
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Box::new(Rect {
|
||||||
|
size: (UiSize::Percentage(z / 2. + 0.5), UiSize::Pixels(30.)),
|
||||||
|
color: Some(vec4(0., 0.75, 0., 1.))
|
||||||
|
}),
|
||||||
|
Box::new(Container {
|
||||||
|
gap: 5.,
|
||||||
|
padding: Sides::all(5.),
|
||||||
|
background: Some(vec4(0., 0., 0., 0.5)),
|
||||||
|
direction: UiDirection::Horizontal,
|
||||||
|
elements: {
|
||||||
|
let mut x: Vec<Box<dyn UiElement>> = vec![];
|
||||||
|
for i in 0..10 {
|
||||||
|
x.push(Box::new(Rect {
|
||||||
|
size: (UiSize::Pixels(50.), UiSize::Pixels(50.)),
|
||||||
|
color: if i == 1 {
|
||||||
|
Some(vec4(0.75, 0.75, 0.75, 0.75))
|
||||||
|
} else {
|
||||||
|
Some(vec4(0.5, 0.5, 0.5, 0.75))
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
x
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Box::new(Container {
|
||||||
|
background: Some(vec4(1., 0., 0., 1.)),
|
||||||
|
padding: Sides::horizontal_vertical(30., 5.),
|
||||||
|
elements: vec![
|
||||||
|
Box::new(Rect {
|
||||||
|
size: (UiSize::Pixels(50.), UiSize::Pixels(50.)),
|
||||||
|
color: Some(vec4(1., 1., 1., 0.75))
|
||||||
|
})
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}, resolution);
|
}, resolution);
|
||||||
|
|
|
@ -4,11 +4,12 @@ use crate::{
|
||||||
UiSize,
|
UiSize,
|
||||||
LayoutInfo,
|
LayoutInfo,
|
||||||
draw::UiDrawCommand,
|
draw::UiDrawCommand,
|
||||||
measure::Response,
|
measure::{Response, Hints},
|
||||||
state::StateRepo,
|
state::StateRepo,
|
||||||
element::UiElement
|
element::UiElement
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum Alignment {
|
pub enum Alignment {
|
||||||
Begin,
|
Begin,
|
||||||
Center,
|
Center,
|
||||||
|
@ -51,8 +52,9 @@ impl<T: Clone> Sides<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 size: (UiSize, UiSize),
|
||||||
pub direction: UiDirection,
|
pub direction: UiDirection,
|
||||||
//pub reverse: bool,
|
//pub reverse: bool,
|
||||||
pub gap: f32,
|
pub gap: f32,
|
||||||
|
@ -67,13 +69,15 @@ pub struct Container {
|
||||||
impl Default for Container {
|
impl Default for Container {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
min_size: (UiSize::Auto, UiSize::Auto),
|
// min_size: (UiSize::Auto, UiSize::Auto),
|
||||||
max_size: (UiSize::Auto, UiSize::Auto),
|
// max_size: (UiSize::Auto, UiSize::Auto),
|
||||||
|
size: (UiSize::Auto, UiSize::Auto),
|
||||||
direction: UiDirection::Vertical,
|
direction: UiDirection::Vertical,
|
||||||
//reverse: false,
|
//reverse: false,
|
||||||
gap: 0.,
|
gap: 0.,
|
||||||
padding: Sides::all(0.),
|
padding: Sides::all(0.),
|
||||||
align: (Alignment::Center, Alignment::Begin),
|
///Primary/secondary axis
|
||||||
|
align: (Alignment::Begin, Alignment::Begin),
|
||||||
background: Default::default(),
|
background: Default::default(),
|
||||||
borders: Default::default(),
|
borders: Default::default(),
|
||||||
clip: Default::default(),
|
clip: Default::default(),
|
||||||
|
@ -83,7 +87,8 @@ impl Default for Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Container {
|
impl Container {
|
||||||
pub fn measure_max_size(&self, layout: &LayoutInfo) -> Vec2 {
|
pub fn measure_max_inner_size(&self, layout: &LayoutInfo) -> Vec2 {
|
||||||
|
//TODO take explicit size into account
|
||||||
layout.max_size - vec2(
|
layout.max_size - vec2(
|
||||||
self.padding.left + self.padding.right,
|
self.padding.left + self.padding.right,
|
||||||
self.padding.top + self.padding.bottom,
|
self.padding.top + self.padding.bottom,
|
||||||
|
@ -94,28 +99,55 @@ impl Container {
|
||||||
impl UiElement for Container {
|
impl UiElement for Container {
|
||||||
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response {
|
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Response {
|
||||||
let mut size = Vec2::ZERO;
|
let mut size = Vec2::ZERO;
|
||||||
|
//if matches!(self.size.0, UiSize::Auto) || matches!(self.size.1, UiSize::Auto) {
|
||||||
let mut leftover_gap = Vec2::ZERO;
|
let mut leftover_gap = Vec2::ZERO;
|
||||||
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: self.measure_max_size(layout), // - size TODO
|
max_size: self.measure_max_inner_size(layout), // - size TODO
|
||||||
direction: self.direction,
|
direction: self.direction,
|
||||||
});
|
});
|
||||||
match self.direction {
|
match self.direction {
|
||||||
UiDirection::Horizontal => {
|
UiDirection::Horizontal => {
|
||||||
size.x += measure.desired_size.x + self.gap;
|
size.x += measure.size.x + self.gap;
|
||||||
size.y = size.y.max(measure.desired_size.y);
|
size.y = size.y.max(measure.size.y);
|
||||||
leftover_gap.x = self.gap;
|
leftover_gap.x = self.gap;
|
||||||
},
|
},
|
||||||
UiDirection::Vertical => {
|
UiDirection::Vertical => {
|
||||||
size.x = size.x.max(measure.desired_size.x);
|
size.x = size.x.max(measure.size.x);
|
||||||
size.y += measure.desired_size.y + self.gap;
|
size.y += measure.size.y + self.gap;
|
||||||
leftover_gap.y = self.gap;
|
leftover_gap.y = self.gap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size -= leftover_gap;
|
size -= leftover_gap;
|
||||||
Response { desired_size: size }
|
|
||||||
|
let inner_content_size = Some(size);
|
||||||
|
|
||||||
|
size += vec2(
|
||||||
|
self.padding.left + self.padding.right,
|
||||||
|
self.padding.top + self.padding.bottom,
|
||||||
|
);
|
||||||
|
|
||||||
|
match self.size.0 {
|
||||||
|
UiSize::Auto => (),
|
||||||
|
UiSize::Percentage(percentage) => size.x = layout.max_size.x * percentage,
|
||||||
|
UiSize::Pixels(pixels) => size.x = pixels,
|
||||||
|
}
|
||||||
|
match self.size.1 {
|
||||||
|
UiSize::Auto => (),
|
||||||
|
UiSize::Percentage(percentage) => size.y = layout.max_size.y * percentage,
|
||||||
|
UiSize::Pixels(pixels) => size.y = pixels,
|
||||||
|
}
|
||||||
|
|
||||||
|
Response {
|
||||||
|
size,
|
||||||
|
hints: Hints {
|
||||||
|
inner_content_size,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
user_data: None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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>) {
|
||||||
|
@ -125,7 +157,7 @@ impl UiElement for Container {
|
||||||
if let Some(color) = self.background {
|
if let Some(color) = self.background {
|
||||||
draw.push(UiDrawCommand::Rectangle {
|
draw.push(UiDrawCommand::Rectangle {
|
||||||
position,
|
position,
|
||||||
size: measure.desired_size,
|
size: measure.size,
|
||||||
color
|
color
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -134,48 +166,61 @@ impl UiElement for Container {
|
||||||
position += vec2(self.padding.left, self.padding.top);
|
position += vec2(self.padding.left, self.padding.top);
|
||||||
|
|
||||||
//alignment
|
//alignment
|
||||||
//TODO: REQUIRES MAX MEASURE SIZES!
|
match (self.align.0, self.direction) {
|
||||||
// match self.align.0 {
|
(Alignment::Begin, _) => (),
|
||||||
// Alignment::Begin => (),
|
(Alignment::Center, UiDirection::Horizontal) => {
|
||||||
// Alignment::Center => {
|
position.x += (measure.size.x - measure.hints.inner_content_size.unwrap().x) / 2.;
|
||||||
// position.x += (layout.max_size.x - measure.desired_size.x) / 2.;
|
},
|
||||||
// },
|
(Alignment::Center, UiDirection::Vertical) => {
|
||||||
// Alignment::End => {
|
position.y += (measure.size.y - measure.hints.inner_content_size.unwrap().y) / 2.;
|
||||||
// position.x += layout.max_size.x - measure.desired_size.x;
|
},
|
||||||
// }
|
(Alignment::End, UiDirection::Horizontal) => {
|
||||||
// }
|
position.x += measure.size.x - measure.hints.inner_content_size.unwrap().x - self.padding.right - self.padding.left;
|
||||||
// match self.align.1 {
|
},
|
||||||
// Alignment::Begin => (),
|
(Alignment::End, UiDirection::Vertical) => {
|
||||||
// Alignment::Center => {
|
position.y += measure.size.y - measure.hints.inner_content_size.unwrap().y - self.padding.bottom - self.padding.top;
|
||||||
// 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 {
|
for element in &self.elements {
|
||||||
//(passing max size from layout rather than actual bounds for the sake of consistency with measure() above)
|
//(passing max size from layout rather than actual bounds for the sake of consistency with measure() above)
|
||||||
|
|
||||||
let layout = LayoutInfo {
|
let mut el_layout = LayoutInfo {
|
||||||
position,
|
position,
|
||||||
max_size: self.measure_max_size(layout),
|
max_size: self.measure_max_inner_size(layout),
|
||||||
direction: self.direction,
|
direction: self.direction,
|
||||||
};
|
};
|
||||||
|
|
||||||
//measure
|
//measure
|
||||||
let el_measure = element.measure(state, &layout);
|
let el_measure = element.measure(state, &el_layout);
|
||||||
|
|
||||||
|
//align (on sec. axis)
|
||||||
|
match (self.align.1, self.direction) {
|
||||||
|
(Alignment::Begin, _) => (),
|
||||||
|
(Alignment::Center, UiDirection::Horizontal) => {
|
||||||
|
el_layout.position.y += (measure.size.y - self.padding.bottom - self.padding.top - el_measure.size.y) / 2.;
|
||||||
|
},
|
||||||
|
(Alignment::Center, UiDirection::Vertical) => {
|
||||||
|
el_layout.position.x += (measure.size.x - self.padding.left - self.padding.right - el_measure.size.x) / 2.;
|
||||||
|
},
|
||||||
|
(Alignment::End, UiDirection::Horizontal) => {
|
||||||
|
el_layout.position.y += measure.size.y - el_measure.size.y - self.padding.bottom;
|
||||||
|
},
|
||||||
|
(Alignment::End, UiDirection::Vertical) => {
|
||||||
|
el_layout.position.x += measure.size.x - el_measure.size.x - self.padding.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//process
|
//process
|
||||||
element.process(&el_measure, state, &layout, draw);
|
element.process(&el_measure, state, &el_layout, draw);
|
||||||
|
|
||||||
//layout
|
//layout
|
||||||
match self.direction {
|
match self.direction {
|
||||||
UiDirection::Horizontal => {
|
UiDirection::Horizontal => {
|
||||||
position.x += el_measure.desired_size.x + self.gap;
|
position.x += el_measure.size.x + self.gap;
|
||||||
},
|
},
|
||||||
UiDirection::Vertical => {
|
UiDirection::Vertical => {
|
||||||
position.y += el_measure.desired_size.y + self.gap;
|
position.y += el_measure.size.y + self.gap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl UiElement for ProgressBar {
|
||||||
|
|
||||||
fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Response {
|
fn measure(&self, _: &StateRepo, layout: &LayoutInfo) -> Response {
|
||||||
Response {
|
Response {
|
||||||
desired_size: vec2(
|
size: vec2(
|
||||||
match self.size.0 {
|
match self.size.0 {
|
||||||
UiSize::Auto => layout.max_size.x.max(300.),
|
UiSize::Auto => layout.max_size.x.max(300.),
|
||||||
UiSize::Percentage(p) => layout.max_size.x * p,
|
UiSize::Percentage(p) => layout.max_size.x * p,
|
||||||
|
@ -44,7 +44,9 @@ impl UiElement for ProgressBar {
|
||||||
UiSize::Percentage(p) => layout.max_size.y * p,
|
UiSize::Percentage(p) => layout.max_size.y * p,
|
||||||
UiSize::Pixels(p) => p,
|
UiSize::Pixels(p) => p,
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
|
hints: Default::default(),
|
||||||
|
user_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,14 +55,14 @@ impl UiElement for ProgressBar {
|
||||||
if value < 1. {
|
if value < 1. {
|
||||||
draw.push(UiDrawCommand::Rectangle {
|
draw.push(UiDrawCommand::Rectangle {
|
||||||
position: layout.position,
|
position: layout.position,
|
||||||
size: measure.desired_size,
|
size: measure.size,
|
||||||
color: self.color_background
|
color: self.color_background
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if value > 0. {
|
if value > 0. {
|
||||||
draw.push(UiDrawCommand::Rectangle {
|
draw.push(UiDrawCommand::Rectangle {
|
||||||
position: layout.position,
|
position: layout.position,
|
||||||
size: measure.desired_size * vec2(value, 1.0),
|
size: measure.size * vec2(value, 1.0),
|
||||||
color: self.color_foreground
|
color: self.color_foreground
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl Default for Rect {
|
||||||
impl UiElement for Rect {
|
impl UiElement for Rect {
|
||||||
fn measure(&self, _state: &StateRepo, layout: &LayoutInfo) -> Response {
|
fn measure(&self, _state: &StateRepo, layout: &LayoutInfo) -> Response {
|
||||||
Response {
|
Response {
|
||||||
desired_size: vec2(
|
size: vec2(
|
||||||
match self.size.0 {
|
match self.size.0 {
|
||||||
UiSize::Auto => layout.max_size.x,
|
UiSize::Auto => layout.max_size.x,
|
||||||
UiSize::Percentage(percentage) => layout.max_size.x * percentage,
|
UiSize::Percentage(percentage) => layout.max_size.x * percentage,
|
||||||
|
@ -36,7 +36,9 @@ impl UiElement for Rect {
|
||||||
UiSize::Percentage(percentage) => layout.max_size.y * percentage,
|
UiSize::Percentage(percentage) => layout.max_size.y * percentage,
|
||||||
UiSize::Pixels(pixels) => pixels,
|
UiSize::Pixels(pixels) => pixels,
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
|
hints: Default::default(),
|
||||||
|
user_data: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +46,7 @@ impl UiElement for Rect {
|
||||||
if let Some(color) = self.color {
|
if let Some(color) = self.color {
|
||||||
draw.push(UiDrawCommand::Rectangle {
|
draw.push(UiDrawCommand::Rectangle {
|
||||||
position: layout.position,
|
position: layout.position,
|
||||||
size: measure.desired_size,
|
size: measure.size,
|
||||||
color,
|
color,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,12 @@ impl Default for Spacer {
|
||||||
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 {
|
||||||
desired_size: match layout.direction {
|
size: match layout.direction {
|
||||||
UiDirection::Horizontal => vec2(self.0, 0.),
|
UiDirection::Horizontal => vec2(self.0, 0.),
|
||||||
UiDirection::Vertical => vec2(0., self.0),
|
UiDirection::Vertical => vec2(0., self.0),
|
||||||
}
|
},
|
||||||
|
hints: Default::default(),
|
||||||
|
user_data: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
|
|
||||||
pub struct Response {
|
#[derive(Default)]
|
||||||
pub desired_size: Vec2
|
#[non_exhaustive]
|
||||||
|
pub struct Hints {
|
||||||
|
pub inner_content_size: Option<Vec2>,
|
||||||
|
pub inner_content_size_cache: Option<Vec<Vec2>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Response {
|
||||||
|
pub size: Vec2,
|
||||||
|
pub hints: Hints,
|
||||||
|
pub user_data: Option<Box<dyn std::any::Any>>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue