mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-12-26 21:58:20 -06:00
wip ui
This commit is contained in:
parent
6eb7a3f690
commit
ad61b7db94
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -78,6 +78,15 @@ version = "1.0.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "approx"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
|
@ -724,6 +733,7 @@ version = "0.24.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42218cb640844e3872cc3c153dc975229e080a6c4733b34709ef445610550226"
|
checksum = "42218cb640844e3872cc3c153dc975229e080a6c4733b34709ef445610550226"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"approx",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -972,6 +982,7 @@ dependencies = [
|
||||||
"image",
|
"image",
|
||||||
"kubi-logging",
|
"kubi-logging",
|
||||||
"kubi-shared",
|
"kubi-shared",
|
||||||
|
"kubi-ui",
|
||||||
"log",
|
"log",
|
||||||
"lz4_flex",
|
"lz4_flex",
|
||||||
"ndk",
|
"ndk",
|
||||||
|
@ -1043,6 +1054,16 @@ dependencies = [
|
||||||
"strum",
|
"strum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kubi-ui"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"glam",
|
||||||
|
"glium",
|
||||||
|
"hashbrown 0.14.0",
|
||||||
|
"nohash-hasher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["kubi", "kubi-server", "kubi-shared", "kubi-logging", "kubi-pool"]
|
members = ["kubi", "kubi-server", "kubi-shared", "kubi-logging", "kubi-pool", "kubi-ui"]
|
||||||
default-members = ["kubi"]
|
default-members = ["kubi"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
|
16
kubi-ui/Cargo.toml
Normal file
16
kubi-ui/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "kubi-ui"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
hashbrown = "0.14"
|
||||||
|
nohash-hasher = "0.2"
|
||||||
|
glam = { version = "0.24", features = ["approx"] }
|
||||||
|
glium = { git = "https://github.com/glium/glium", rev = "5d50e7", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["backend_glium", "builtin_elements"]
|
||||||
|
backend_glium = ["dep:glium"]
|
||||||
|
builtin_elements = []
|
2
kubi-ui/src/backend.rs
Normal file
2
kubi-ui/src/backend.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#[cfg(feature = "backend_glium")]
|
||||||
|
pub mod glium;
|
0
kubi-ui/src/backend/glium.rs
Normal file
0
kubi-ui/src/backend/glium.rs
Normal file
22
kubi-ui/src/draw.rs
Normal file
22
kubi-ui/src/draw.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use glam::{Vec2, vec2, Vec4};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum UiDrawCall {
|
||||||
|
///Filled, colored rectangle
|
||||||
|
Rectangle {
|
||||||
|
///Position in pixels
|
||||||
|
position: Vec2,
|
||||||
|
///Size in pixels
|
||||||
|
size: Vec2,
|
||||||
|
///Color (RGBA)
|
||||||
|
color: Vec4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UiDrawCalls {
|
||||||
|
pub calls: Vec<UiDrawCall>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UiDrawPlan {
|
||||||
|
|
||||||
|
}
|
21
kubi-ui/src/element.rs
Normal file
21
kubi-ui/src/element.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use std::any::Any;
|
||||||
|
use crate::{
|
||||||
|
LayoutInfo,
|
||||||
|
draw::UiDrawCall,
|
||||||
|
measure::{IsMeasurable, Response},
|
||||||
|
state::StateRepo
|
||||||
|
};
|
||||||
|
|
||||||
|
#[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" }
|
||||||
|
fn state_id(&self) -> Option<u64> { None }
|
||||||
|
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<Box<dyn Any>> { None }
|
||||||
|
fn is_measurable(&self) -> IsMeasurable { IsMeasurable::No }
|
||||||
|
fn measure(&self, state: &StateRepo, layout: &LayoutInfo) -> Option<Response> { None }
|
||||||
|
fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response;
|
||||||
|
}
|
29
kubi-ui/src/element/layout_box.rs
Normal file
29
kubi-ui/src/element/layout_box.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
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!()
|
||||||
|
}
|
||||||
|
}
|
58
kubi-ui/src/element/progress_bar.rs
Normal file
58
kubi-ui/src/element/progress_bar.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
use glam::{vec2, Vec2, Vec4};
|
||||||
|
use crate::{
|
||||||
|
UiSize, LayoutInfo,
|
||||||
|
draw::UiDrawCall,
|
||||||
|
measure::{Response, IsMeasurable},
|
||||||
|
state::StateRepo
|
||||||
|
};
|
||||||
|
use super::UiElement;
|
||||||
|
|
||||||
|
struct ProgressBar {
|
||||||
|
size: (UiSize, UiSize),
|
||||||
|
value: f32,
|
||||||
|
color_foreground: Vec4,
|
||||||
|
color_background: Vec4,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Response> {
|
||||||
|
Some(Response {
|
||||||
|
size: Vec2::new(
|
||||||
|
match self.size.0 {
|
||||||
|
UiSize::Auto => layout.max_size.x,
|
||||||
|
UiSize::Percentage(p) => layout.max_size.x * p,
|
||||||
|
UiSize::Pixels(p) => p,
|
||||||
|
},
|
||||||
|
match self.size.1 {
|
||||||
|
UiSize::Auto => BAR_HEIGHT,
|
||||||
|
UiSize::Percentage(p) => layout.max_size.y * p,
|
||||||
|
UiSize::Pixels(p) => p,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process(&self, state: &mut StateRepo, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response {
|
||||||
|
let measure = self.measure(&state, layout).unwrap();
|
||||||
|
|
||||||
|
draw.push(UiDrawCall::Rectangle {
|
||||||
|
position: layout.position,
|
||||||
|
size: measure.size,
|
||||||
|
color: self.color_background
|
||||||
|
});
|
||||||
|
|
||||||
|
draw.push(UiDrawCall::Rectangle {
|
||||||
|
position: layout.position,
|
||||||
|
size: measure.size * vec2(self.value, 1.0),
|
||||||
|
color: self.color_foreground
|
||||||
|
});
|
||||||
|
|
||||||
|
measure
|
||||||
|
}
|
||||||
|
}
|
10
kubi-ui/src/event.rs
Normal file
10
kubi-ui/src/event.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use glam::Vec2;
|
||||||
|
|
||||||
|
pub enum UiEvent {
|
||||||
|
MouseMove(Vec2),
|
||||||
|
MouseDown(Vec2),
|
||||||
|
MouseUp(Vec2),
|
||||||
|
KeyDown(u32),
|
||||||
|
KeyUp(u32),
|
||||||
|
TextInput(char),
|
||||||
|
}
|
52
kubi-ui/src/lib.rs
Normal file
52
kubi-ui/src/lib.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use glam::Vec2;
|
||||||
|
|
||||||
|
pub mod element;
|
||||||
|
pub mod event;
|
||||||
|
pub mod draw;
|
||||||
|
pub mod backend;
|
||||||
|
pub mod measure;
|
||||||
|
pub mod state;
|
||||||
|
|
||||||
|
use state::StateRepo;
|
||||||
|
|
||||||
|
pub struct KubiUi {
|
||||||
|
mouse_position: Vec2,
|
||||||
|
stateful_state: StateRepo,
|
||||||
|
event_queue: VecDeque<event::UiEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KubiUi {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
KubiUi {
|
||||||
|
mouse_position: Vec2::ZERO,
|
||||||
|
stateful_state: StateRepo::default(),
|
||||||
|
event_queue: VecDeque::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for KubiUi {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum UiSize {
|
||||||
|
Auto,
|
||||||
|
Percentage(f32),
|
||||||
|
Pixels(f32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub enum UiDirection {
|
||||||
|
#[default]
|
||||||
|
Vertical,
|
||||||
|
Horizontal,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LayoutInfo {
|
||||||
|
position: Vec2,
|
||||||
|
max_size: Vec2,
|
||||||
|
direction: UiDirection,
|
||||||
|
}
|
13
kubi-ui/src/measure.rs
Normal file
13
kubi-ui/src/measure.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use glam::Vec2;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum IsMeasurable {
|
||||||
|
#[default]
|
||||||
|
No,
|
||||||
|
Maybe,
|
||||||
|
Yes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Response {
|
||||||
|
pub size: Vec2
|
||||||
|
}
|
9
kubi-ui/src/state.rs
Normal file
9
kubi-ui/src/state.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
use nohash_hasher::BuildNoHashHasher;
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct StateRepo {
|
||||||
|
state: HashMap<u64, Box<dyn Any>, BuildNoHashHasher<u64>>,
|
||||||
|
active_ids: HashSet<u64, BuildNoHashHasher<u64>>
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ crate-type = ["lib", "cdylib"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
kubi-shared = { path = "../kubi-shared" }
|
kubi-shared = { path = "../kubi-shared" }
|
||||||
kubi-logging = { path = "../kubi-logging" }
|
kubi-logging = { path = "../kubi-logging" }
|
||||||
|
kubi-ui = { path = "../kubi-ui" }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
glium = { git = "https://github.com/glium/glium", rev = "5d50e7" }
|
glium = { git = "https://github.com/glium/glium", rev = "5d50e7" }
|
||||||
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] }
|
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] }
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
use glam::{Vec2, vec2, Vec4};
|
|
||||||
use shipyard::Unique;
|
|
||||||
|
|
||||||
pub enum UiSize {
|
|
||||||
Auto,
|
|
||||||
Percentage(f32),
|
|
||||||
Pixels(f32),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LayoutInfo {
|
|
||||||
position: Vec2,
|
|
||||||
max_preferred_size: Vec2,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Response {
|
|
||||||
size: Vec2
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait UiElement {
|
|
||||||
fn process(&self, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response;
|
|
||||||
fn measure(&self, layout: &LayoutInfo) -> Option<Response> { None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum LayoutDirection {
|
|
||||||
Horizontal,
|
|
||||||
Vertical
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LayoutBox {
|
|
||||||
pub direction: LayoutDirection,
|
|
||||||
pub gap: f32,
|
|
||||||
pub elements: Vec<Box<dyn UiElement>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ProgressBar {
|
|
||||||
size: (UiSize, UiSize),
|
|
||||||
value: f32,
|
|
||||||
color_foreground: Vec4,
|
|
||||||
color_background: Vec4,
|
|
||||||
}
|
|
||||||
|
|
||||||
const BAR_HEIGHT: f32 = 20.0;
|
|
||||||
|
|
||||||
impl UiElement for ProgressBar {
|
|
||||||
fn measure(&self, layout: &LayoutInfo) -> Option<Response> {
|
|
||||||
let width = match self.size.0 {
|
|
||||||
UiSize::Auto => layout.max_preferred_size.x,
|
|
||||||
UiSize::Percentage(p) => layout.max_preferred_size.x * p,
|
|
||||||
UiSize::Pixels(p) => p,
|
|
||||||
};
|
|
||||||
let height = match self.size.1 {
|
|
||||||
UiSize::Auto => BAR_HEIGHT,
|
|
||||||
UiSize::Percentage(p) => layout.max_preferred_size.y * p,
|
|
||||||
UiSize::Pixels(p) => p,
|
|
||||||
};
|
|
||||||
let size = Vec2::new(width, height);
|
|
||||||
Some(Response { size })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process(&self, layout: &LayoutInfo, draw: &mut Vec<UiDrawCall>) -> Response {
|
|
||||||
let measure = self.measure(layout).unwrap();
|
|
||||||
|
|
||||||
draw.push(UiDrawCall::Rectangle {
|
|
||||||
position: layout.position,
|
|
||||||
size: measure.size,
|
|
||||||
color: self.color_background
|
|
||||||
});
|
|
||||||
draw.push(UiDrawCall::Rectangle {
|
|
||||||
position: layout.position,
|
|
||||||
size: measure.size * vec2(self.value, 1.0),
|
|
||||||
color: self.color_foreground
|
|
||||||
});
|
|
||||||
|
|
||||||
measure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum UiDrawCall {
|
|
||||||
Rectangle {
|
|
||||||
///Position in pixels
|
|
||||||
position: Vec2,
|
|
||||||
///Size in pixels
|
|
||||||
size: Vec2,
|
|
||||||
///Color (RGBA)
|
|
||||||
color: Vec4,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Unique)]
|
|
||||||
struct UiDrawCalls {
|
|
||||||
pub calls: Vec<UiDrawCall>,
|
|
||||||
}
|
|
|
@ -29,8 +29,7 @@ pub(crate) mod delta_time;
|
||||||
pub(crate) mod cursor_lock;
|
pub(crate) mod cursor_lock;
|
||||||
pub(crate) mod control_flow;
|
pub(crate) mod control_flow;
|
||||||
pub(crate) mod state;
|
pub(crate) mod state;
|
||||||
pub(crate) mod gui;
|
pub(crate) mod legacy_gui;
|
||||||
pub(crate) mod gui_v2;
|
|
||||||
pub(crate) mod networking;
|
pub(crate) mod networking;
|
||||||
pub(crate) mod init;
|
pub(crate) mod init;
|
||||||
pub(crate) mod color;
|
pub(crate) mod color;
|
||||||
|
@ -77,7 +76,7 @@ use control_flow::{exit_on_esc, insert_control_flow_unique, SetControlFlow};
|
||||||
use state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state, is_connecting};
|
use state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state, is_connecting};
|
||||||
use networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit, is_singleplayer};
|
use networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit, is_singleplayer};
|
||||||
use init::initialize_from_args;
|
use init::initialize_from_args;
|
||||||
use gui::{render_gui, init_gui, update_gui};
|
use legacy_gui::{render_gui, init_gui, update_gui};
|
||||||
use loading_screen::update_loading_screen;
|
use loading_screen::update_loading_screen;
|
||||||
use connecting_screen::switch_to_loading_if_connected;
|
use connecting_screen::switch_to_loading_if_connected;
|
||||||
use fixed_timestamp::init_fixed_timestamp_storage;
|
use fixed_timestamp::init_fixed_timestamp_storage;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
world::ChunkStorage,
|
world::ChunkStorage,
|
||||||
state::{GameState, NextState, is_changing_state},
|
state::{GameState, NextState, is_changing_state},
|
||||||
transform::Transform2d,
|
transform::Transform2d,
|
||||||
gui::{
|
legacy_gui::{
|
||||||
GuiComponent,
|
GuiComponent,
|
||||||
progressbar::ProgressbarComponent
|
progressbar::ProgressbarComponent
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue