mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-22 23:28:43 -06:00
Compare commits
No commits in common. "dd4c71db3b205e2dd1ef982e75c374158f0bb8f5" and "6606119cc4729f4f4d5a4bcd544119b9f2c48efc" have entirely different histories.
dd4c71db3b
...
6606119cc4
|
@ -1,5 +1,5 @@
|
||||||
use glam::{UVec2, Vec2};
|
use glam::{UVec2, Vec2};
|
||||||
use glium::{Surface, backend::glutin::SimpleWindowBuilder};
|
use glium::{backend::glutin::SimpleWindowBuilder, Surface};
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{Event, WindowEvent},
|
event::{Event, WindowEvent},
|
||||||
event_loop::{EventLoopBuilder, ControlFlow}
|
event_loop::{EventLoopBuilder, ControlFlow}
|
||||||
|
@ -35,9 +35,9 @@ pub fn ui<T>(
|
||||||
kubi_logging::init();
|
kubi_logging::init();
|
||||||
|
|
||||||
let event_loop = EventLoopBuilder::new().build().unwrap();
|
let event_loop = EventLoopBuilder::new().build().unwrap();
|
||||||
let (window, display) = SimpleWindowBuilder::new()
|
let (window, display) = SimpleWindowBuilder::new().build(&event_loop);
|
||||||
.with_title(name)
|
|
||||||
.build(&event_loop);
|
window.set_title(name);
|
||||||
|
|
||||||
let mut hui = UiInstance::new();
|
let mut hui = UiInstance::new();
|
||||||
let mut backend = GliumUiRenderer::new(&display);
|
let mut backend = GliumUiRenderer::new(&display);
|
||||||
|
|
|
@ -15,7 +15,8 @@ use hui::{
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CounterSignal {
|
enum CounterSignal {
|
||||||
ChangeValue(u32)
|
Increment,
|
||||||
|
Decrement,
|
||||||
}
|
}
|
||||||
impl UiSignal for CounterSignal {}
|
impl UiSignal for CounterSignal {}
|
||||||
|
|
||||||
|
@ -45,11 +46,8 @@ ui_main!(
|
||||||
.with_text_size(24)
|
.with_text_size(24)
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Br.add_child(ui);
|
||||||
Slider::new(*counter as f32 / 100.)
|
Slider::new(0.5)
|
||||||
.with_size(size!(66%, 20))
|
.with_size(size!(66%, 20))
|
||||||
.on_change(|x| {
|
|
||||||
CounterSignal::ChangeValue((x * 100.).round() as u32)
|
|
||||||
})
|
|
||||||
.add_child(ui);
|
.add_child(ui);
|
||||||
Br.add_child(ui);
|
Br.add_child(ui);
|
||||||
for _ in 0..*counter {
|
for _ in 0..*counter {
|
||||||
|
@ -61,7 +59,8 @@ ui_main!(
|
||||||
.add_root(ui, size);
|
.add_root(ui, size);
|
||||||
|
|
||||||
ui.process_signals(|sig| match sig {
|
ui.process_signals(|sig| match sig {
|
||||||
CounterSignal::ChangeValue(v) => *counter = v,
|
CounterSignal::Increment => *counter += 1,
|
||||||
|
CounterSignal::Decrement => *counter -= 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,26 +1,22 @@
|
||||||
//! work in progress
|
//! work in progress
|
||||||
|
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use glam::{vec2, Vec2};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
draw::{RoundedCorners, UiDrawCommand},
|
draw::UiDrawCommand,
|
||||||
element::{MeasureContext, ProcessContext, UiElement},
|
element::{MeasureContext, ProcessContext, UiElement},
|
||||||
layout::{compute_size, Size2d},
|
layout::{compute_size, Size2d},
|
||||||
measure::Response,
|
measure::Response,
|
||||||
rectangle::Corners,
|
rectangle::Corners,
|
||||||
signal::{SignalStore, UiSignal},
|
signal::UiSignal,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// work in progress
|
/// work in progress
|
||||||
#[derive(Default, Setters)]
|
#[derive(Default, Debug, Clone, Copy, Setters)]
|
||||||
#[setters(prefix = "with_")]
|
#[setters(prefix = "with_")]
|
||||||
pub struct Slider {
|
pub struct Slider {
|
||||||
pub value: f32,
|
pub value: f32,
|
||||||
pub size: Size2d,
|
pub size: Size2d,
|
||||||
|
|
||||||
#[setters(skip)]
|
|
||||||
fire_on_shit: Option<Box<dyn Fn(&mut SignalStore, f32)>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Slider {
|
impl Slider {
|
||||||
|
@ -32,15 +28,6 @@ impl Slider {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_change<S: UiSignal + 'static, T: Fn(f32) -> S + 'static>(self, f: T) -> Self {
|
|
||||||
Self {
|
|
||||||
fire_on_shit: Some(Box::new(move |s: &mut SignalStore, x| {
|
|
||||||
s.add::<S>(f(x));
|
|
||||||
})),
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiElement for Slider {
|
impl UiElement for Slider {
|
||||||
|
@ -56,33 +43,26 @@ impl UiElement for Slider {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&self, ctx: ProcessContext) {
|
fn process(&self, ctx: ProcessContext) {
|
||||||
let bgrect_height_ratio = 0.25;
|
|
||||||
ctx.draw.add(UiDrawCommand::Rectangle {
|
ctx.draw.add(UiDrawCommand::Rectangle {
|
||||||
position: ctx.layout.position + ctx.measure.size * vec2(0., 0.5 - bgrect_height_ratio / 2.),
|
position: ctx.layout.position,
|
||||||
size: ctx.measure.size * vec2(1., bgrect_height_ratio),
|
size: ctx.measure.size,
|
||||||
color: Corners::all((1., 1., 1., 0.7).into()),
|
color: Corners::all((1., 0., 0., 1.).into()),
|
||||||
texture: None,
|
texture: None,
|
||||||
rounded_corners: None,
|
rounded_corners: None,
|
||||||
//Some(RoundedCorners::from_radius(Corners::all(bgrect_height_ratio * ctx.measure.size.y * 0.4))),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let value = self.value.clamp(0., 1.);
|
let value = self.value.clamp(0., 1.);
|
||||||
let handle_size = vec2(15., ctx.measure.size.y);
|
|
||||||
ctx.draw.add(UiDrawCommand::Rectangle {
|
ctx.draw.add(UiDrawCommand::Rectangle {
|
||||||
position: ctx.layout.position + (ctx.measure.size.x * value - handle_size.x / 2.) * Vec2::X,
|
position: ctx.layout.position,
|
||||||
size: handle_size,
|
size: (ctx.measure.size.x * value, ctx.measure.size.y).into(),
|
||||||
color: Corners::all((1., 1., 1., 1.).into()),
|
color: Corners::all((0., 1., 0., 1.).into()),
|
||||||
texture: None,
|
texture: None,
|
||||||
rounded_corners: None,
|
rounded_corners: None,
|
||||||
//Some(RoundedCorners::from_radius(Corners::all(handle_size.x / 3.))),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//handle click etc
|
//handle click etc
|
||||||
if let Some(res) = ctx.input.check_active(ctx.measure.rect(ctx.layout.position)) {
|
if let Some(res) = ctx.input.check_click(ctx.measure.rect(ctx.layout.position)) {
|
||||||
let new_value = (res.position_in_rect.x / ctx.measure.size.x).clamp(0., 1.);
|
let new_value = res.position_in_rect.x / ctx.measure.size.x;
|
||||||
if let Some(fire) = &self.fire_on_shit {
|
|
||||||
fire(ctx.signal, new_value);
|
|
||||||
}
|
|
||||||
//TODO call signal with new value
|
//TODO call signal with new value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,7 +286,15 @@ impl<'a> InputCtx<'a> {
|
||||||
rect.contains_point(self.0.mouse_pointer.current_position)
|
rect.contains_point(self.0.mouse_pointer.current_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a rect can be considered "clicked" in the current frame
|
/// Check if a rect can be considered "active" (i.e. held down)
|
||||||
|
///
|
||||||
|
/// WIP: Not implemented yet, always returns `false`
|
||||||
|
pub fn check_active(&self, _rect: Rect) -> bool {
|
||||||
|
//TODO `check_active`
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a rect can be considered "clicked"
|
||||||
///
|
///
|
||||||
/// This can be triggered by multiple input sources, such as mouse, touch, etc.\
|
/// This can be triggered by multiple input sources, such as mouse, touch, etc.\
|
||||||
/// In case of a mouse, these conditions must be met:
|
/// In case of a mouse, these conditions must be met:
|
||||||
|
@ -305,15 +313,4 @@ impl<'a> InputCtx<'a> {
|
||||||
position_in_rect: pos - rect.position,
|
position_in_rect: pos - rect.position,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: write better docs
|
|
||||||
|
|
||||||
/// Check if a rect is being actively being interacted with (e.g. dragged)
|
|
||||||
pub fn check_active(&self, rect: Rect) -> Option<ClickCheckResponse> {
|
|
||||||
self.0.mouse_pointer.buttons.get(&MouseButton::Primary).filter(|mi| {
|
|
||||||
rect.contains_point(mi.start_position)
|
|
||||||
}).map(|_| ClickCheckResponse {
|
|
||||||
position_in_rect: self.0.mouse_pointer.current_position - rect.position,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,8 +248,6 @@ impl UiInstance {
|
||||||
self.signal.add(signal);
|
self.signal.add(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: offer a non-consuming version of this function for T: Clone
|
|
||||||
|
|
||||||
/// Process all signals of a given type
|
/// Process all signals of a given type
|
||||||
///
|
///
|
||||||
/// This clears the signal queue for the given type and iterates over all signals
|
/// This clears the signal queue for the given type and iterates over all signals
|
||||||
|
|
|
@ -2,23 +2,18 @@
|
||||||
|
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
|
|
||||||
/// Represents a rectangle/AABB with specified position and size
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
/// Position of the top-left corner of the rect.
|
|
||||||
pub position: Vec2,
|
pub position: Vec2,
|
||||||
/// Size of the rect, should not be negative.
|
|
||||||
pub size: Vec2,
|
pub size: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rect {
|
impl Rect {
|
||||||
/// Check if the rect contains a point.
|
|
||||||
pub fn contains_point(&self, point: Vec2) -> bool {
|
pub fn contains_point(&self, point: Vec2) -> bool {
|
||||||
point.cmpge(self.position).all() && point.cmple(self.position + self.size).all()
|
point.cmpge(self.position).all() && point.cmple(self.position + self.size).all()
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: return intersect rect
|
//TODO: return intersect rect
|
||||||
/// Check if the rect intersects with another rect.
|
|
||||||
pub fn intersects_rect(&self, other: Rect) -> bool {
|
pub fn intersects_rect(&self, other: Rect) -> bool {
|
||||||
self.position.x < other.position.x + other.size.x
|
self.position.x < other.position.x + other.size.x
|
||||||
&& self.position.x + self.size.x > other.position.x
|
&& self.position.x + self.size.x > other.position.x
|
||||||
|
@ -26,35 +21,22 @@ impl Rect {
|
||||||
&& self.position.y + self.size.y > other.position.y
|
&& self.position.y + self.size.y > other.position.y
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get width of the rectangle.
|
|
||||||
///
|
|
||||||
/// To get both width and height, use the `size` property instead.
|
|
||||||
pub fn width(&self) -> f32 {
|
pub fn width(&self) -> f32 {
|
||||||
self.size.x
|
self.size.x
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get height of the rectangle.
|
|
||||||
///
|
|
||||||
/// To get both width and height, use the `size` property instead.
|
|
||||||
pub fn height(&self) -> f32 {
|
pub fn height(&self) -> f32 {
|
||||||
self.size.y
|
self.size.y
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get position of the top-left corner of the rectangle on the x-axis.
|
|
||||||
///
|
|
||||||
/// To get both x and y, use the `position` property instead.
|
|
||||||
pub fn x(&self) -> f32 {
|
pub fn x(&self) -> f32 {
|
||||||
self.position.x
|
self.position.x
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get position of the top-left corner of the rectangle on the y-axis.
|
|
||||||
///
|
|
||||||
/// To get both x and y, use the `position` property instead.
|
|
||||||
pub fn y(&self) -> f32 {
|
pub fn y(&self) -> f32 {
|
||||||
self.position.y
|
self.position.y
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get positions of all 4 corners of the rectangle.
|
|
||||||
pub fn corners(&self) -> Corners<Vec2> {
|
pub fn corners(&self) -> Corners<Vec2> {
|
||||||
Corners {
|
Corners {
|
||||||
top_left: self.position,
|
top_left: self.position,
|
||||||
|
|
|
@ -56,28 +56,6 @@ impl SignalStore {
|
||||||
|
|
||||||
//TODO this, simplifies handling signals
|
//TODO this, simplifies handling signals
|
||||||
|
|
||||||
// pub trait Signal {
|
|
||||||
// type Arg;
|
|
||||||
// type Output;
|
|
||||||
// fn call(&self, arg: Self::Arg) -> Self::Output;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<F: Fn() -> T, T> Signal for F {
|
|
||||||
// type Arg = ();
|
|
||||||
// type Output = T;
|
|
||||||
// fn call(&self, _: Self::Arg) -> Self::Output {
|
|
||||||
// self()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // impl<F: Fn(A) -> T, A, T> Signal for F {
|
|
||||||
// // type Arg = A;
|
|
||||||
// // type Output = T;
|
|
||||||
// // fn call(&self, a: Self::Arg) -> Self::Output {
|
|
||||||
// // self(a)
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// pub struct SignalTrigger<R: UiSignal + 'static, A = ()>(pub(crate) Box<dyn Fn(A) -> R + 'static>);
|
// pub struct SignalTrigger<R: UiSignal + 'static, A = ()>(pub(crate) Box<dyn Fn(A) -> R + 'static>);
|
||||||
|
|
||||||
// impl<R: UiSignal + 'static, A> SignalTrigger<R, A> {
|
// impl<R: UiSignal + 'static, A> SignalTrigger<R, A> {
|
||||||
|
|
Loading…
Reference in a new issue