mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-11-25 00:18:41 -06:00
it kinda works
This commit is contained in:
parent
dd4d48c91c
commit
7884de5560
|
@ -42,7 +42,7 @@ pub fn ui<T>(
|
|||
let mut hui = UiInstance::new();
|
||||
let mut backend = GliumUiRenderer::new(&display);
|
||||
|
||||
let result = init(&mut hui);
|
||||
let mut result = init(&mut hui);
|
||||
|
||||
event_loop.run(|event, window_target| {
|
||||
window.request_redraw();
|
||||
|
@ -60,7 +60,7 @@ pub fn ui<T>(
|
|||
hui.begin();
|
||||
|
||||
let size = UVec2::from(display.get_framebuffer_dimensions()).as_vec2();
|
||||
draw(&mut hui, size, &result);
|
||||
draw(&mut hui, size, &mut result);
|
||||
|
||||
hui.end();
|
||||
|
||||
|
|
38
hui-examples/examples/ui_test_5_input.rs
Normal file
38
hui-examples/examples/ui_test_5_input.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use std::time::Instant;
|
||||
use hui::{
|
||||
color, size,
|
||||
layout::{Alignment, Direction},
|
||||
element::{
|
||||
container::Container,
|
||||
fill_rect::FillRect,
|
||||
interactable::ElementInteractableExt,
|
||||
UiElementExt
|
||||
},
|
||||
};
|
||||
|
||||
#[path = "../boilerplate.rs"]
|
||||
#[macro_use]
|
||||
mod boilerplate;
|
||||
|
||||
ui_main!(
|
||||
"hUI: Internal input test",
|
||||
init: |_| {},
|
||||
run: |ui, size, _| {
|
||||
Container::default()
|
||||
.with_size(size!(100%))
|
||||
.with_align(Alignment::Center)
|
||||
.with_background(color::WHITE)
|
||||
.with_children(|ui| {
|
||||
FillRect::default()
|
||||
.with_size(size!(40))
|
||||
.with_corner_radius(8.)
|
||||
.with_background(color::DARK_RED)
|
||||
.into_interactable()
|
||||
.on_click(|| {
|
||||
println!("clicked");
|
||||
})
|
||||
.add_child(ui);
|
||||
})
|
||||
.add_root(ui, size);
|
||||
}
|
||||
);
|
|
@ -1,3 +1,5 @@
|
|||
// "The essentials":
|
||||
|
||||
#[cfg(feature = "builtin_container")]
|
||||
pub mod container;
|
||||
|
||||
|
@ -7,17 +9,24 @@ pub mod fill_rect;
|
|||
#[cfg(feature = "builtin_elements")]
|
||||
pub mod spacer;
|
||||
|
||||
#[cfg(feature = "builtin_elements")]
|
||||
pub mod progress_bar;
|
||||
// "The basics":
|
||||
|
||||
#[cfg(feature = "builtin_elements")]
|
||||
pub mod text;
|
||||
|
||||
#[cfg(feature = "builtin_elements")]
|
||||
pub mod image;
|
||||
|
||||
#[cfg(feature = "builtin_elements")]
|
||||
pub mod progress_bar;
|
||||
|
||||
// Wrappers:
|
||||
|
||||
#[cfg(feature = "builtin_elements")]
|
||||
pub mod transformer;
|
||||
|
||||
#[cfg(feature = "builtin_elements")]
|
||||
pub mod image;
|
||||
pub mod interactable;
|
||||
|
||||
//TODO add: Image
|
||||
//TODO add: OverlayContainer (for simply laying multiple elements on top of each other)
|
||||
|
|
|
@ -1,55 +1,79 @@
|
|||
//TODO this thing?
|
||||
//not sure if this is a good idea...
|
||||
//but having the ability to add a click event to any element would be nice, and this is a naive way to do it
|
||||
//! wrapper that allows adding click and hover events to any element
|
||||
|
||||
// use crate::element::{UiElement, MeasureContext, ProcessContext};
|
||||
// not sure if this is a good idea...
|
||||
// but having the ability to add a click event to any element would be nice, and this is a naive way to do it
|
||||
|
||||
// pub struct Interactable<T: UiElement> {
|
||||
// pub element: T,
|
||||
// pub hovered: Option<Box<dyn FnOnce()>>,
|
||||
// pub clicked: Option<Box<dyn FnOnce()>>,
|
||||
// }
|
||||
use crate::element::{UiElement, MeasureContext, ProcessContext};
|
||||
use std::cell::RefCell;
|
||||
|
||||
// impl<T: UiElement> Interactable<T> {
|
||||
// pub fn new(element: T) -> Self {
|
||||
// Self {
|
||||
// element,
|
||||
// hovered: None,
|
||||
// clicked: None,
|
||||
// }
|
||||
// }
|
||||
/// Wrapper that allows adding click and hover events to any element
|
||||
pub struct Interactable {
|
||||
/// The wrapped element that will be interactable
|
||||
pub element: Box<dyn UiElement>,
|
||||
/// Function that will be called if the element is hovered in the current frame
|
||||
///
|
||||
/// Will be consumed after the first time it's called
|
||||
pub hovered: RefCell<Option<Box<dyn FnOnce()>>>,
|
||||
/// Function that will be called if the element was clicked in the current frame
|
||||
///
|
||||
/// Will be consumed after the first time it's called
|
||||
pub clicked: RefCell<Option<Box<dyn FnOnce()>>>,
|
||||
}
|
||||
|
||||
// pub fn on_click(self, clicked: impl FnOnce() + 'static) -> Self {
|
||||
// Self {
|
||||
// clicked: Some(Box::new(clicked)),
|
||||
// ..self
|
||||
// }
|
||||
// }
|
||||
impl Interactable {
|
||||
pub fn new(element: Box<dyn UiElement>) -> Self {
|
||||
Self {
|
||||
element,
|
||||
hovered: RefCell::new(None),
|
||||
clicked: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn on_hover(self, clicked: impl FnOnce() + 'static) -> Self {
|
||||
// Self {
|
||||
// clicked: Some(Box::new(clicked)),
|
||||
// ..self
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
pub fn on_click(self, clicked: impl FnOnce() + 'static) -> Self {
|
||||
Self {
|
||||
clicked: RefCell::new(Some(Box::new(clicked))),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
// impl<T: UiElement> UiElement for Interactable<T> {
|
||||
// fn measure(&self, ctx: MeasureContext) -> crate::measure::Response {
|
||||
// self.element.measure(ctx)
|
||||
// }
|
||||
pub fn on_hover(self, clicked: impl FnOnce() + 'static) -> Self {
|
||||
Self {
|
||||
clicked: RefCell::new(Some(Box::new(clicked))),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fn process(&self, ctx: ProcessContext) {
|
||||
// self.element.process(ctx)
|
||||
// }
|
||||
// }
|
||||
impl UiElement for Interactable {
|
||||
fn name(&self) -> &'static str {
|
||||
"Interactable"
|
||||
}
|
||||
|
||||
// pub trait IntoInteractable<T: UiElement>: UiElement {
|
||||
// fn into_interactable(self) -> Interactable<T>;
|
||||
// }
|
||||
fn measure(&self, ctx: MeasureContext) -> crate::measure::Response {
|
||||
self.element.measure(ctx)
|
||||
}
|
||||
|
||||
// impl<T: UiElement> IntoInteractable<T> for T {
|
||||
// fn into_interactable(self) -> Interactable<Self> {
|
||||
// Interactable::new(self)
|
||||
// }
|
||||
// }
|
||||
fn process(&self, ctx: ProcessContext) {
|
||||
let rect = ctx.measure.rect(ctx.layout.position);
|
||||
|
||||
//XXX: should we do this AFTER normal process call of wrapped element?
|
||||
//TODO other events...
|
||||
if ctx.input.check_click(rect) {
|
||||
//TODO better error message
|
||||
let clicked = self.clicked.borrow_mut().take().expect("you fucked up");
|
||||
clicked();
|
||||
}
|
||||
|
||||
self.element.process(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ElementInteractableExt: UiElement {
|
||||
fn into_interactable(self) -> Interactable;
|
||||
}
|
||||
|
||||
impl<T: UiElement + 'static> ElementInteractableExt for T {
|
||||
fn into_interactable(self) -> Interactable {
|
||||
Interactable::new(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,7 +203,9 @@ impl UiInputState {
|
|||
button.start_position = self.mouse_pointer.current_position;
|
||||
},
|
||||
ButtonState::Released => {
|
||||
//log::trace!("Button {:?} was released", button);
|
||||
if let Some(button_meta) = self.mouse_pointer.buttons.remove(button) {
|
||||
//log::trace!("start pos was: {:?} current pos is: {:?}", button_meta.start_position, self.mouse_pointer.current_position);
|
||||
self.mouse_pointer.released_buttons.insert(*button, button_meta);
|
||||
} else {
|
||||
//huh
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! element measurement, hints and responses
|
||||
|
||||
use glam::Vec2;
|
||||
use crate::rectangle::Rect;
|
||||
|
||||
// #[non_exhaustive]
|
||||
#[derive(Default)]
|
||||
|
@ -27,3 +28,12 @@ pub struct Response {
|
|||
/// You should almost never set this, and the exact behavior may change in the future
|
||||
pub should_wrap: bool,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
pub fn rect(&self, position: Vec2) -> Rect {
|
||||
Rect {
|
||||
position,
|
||||
size: self.size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue