it kinda works

This commit is contained in:
griffi-gh 2024-03-11 20:48:39 +01:00
parent dd4d48c91c
commit 7884de5560
6 changed files with 134 additions and 51 deletions

View file

@ -42,7 +42,7 @@ pub fn ui<T>(
let mut hui = UiInstance::new(); let mut hui = UiInstance::new();
let mut backend = GliumUiRenderer::new(&display); let mut backend = GliumUiRenderer::new(&display);
let result = init(&mut hui); let mut result = init(&mut hui);
event_loop.run(|event, window_target| { event_loop.run(|event, window_target| {
window.request_redraw(); window.request_redraw();
@ -60,7 +60,7 @@ pub fn ui<T>(
hui.begin(); hui.begin();
let size = UVec2::from(display.get_framebuffer_dimensions()).as_vec2(); let size = UVec2::from(display.get_framebuffer_dimensions()).as_vec2();
draw(&mut hui, size, &result); draw(&mut hui, size, &mut result);
hui.end(); hui.end();

View 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);
}
);

View file

@ -1,3 +1,5 @@
// "The essentials":
#[cfg(feature = "builtin_container")] #[cfg(feature = "builtin_container")]
pub mod container; pub mod container;
@ -7,17 +9,24 @@ pub mod fill_rect;
#[cfg(feature = "builtin_elements")] #[cfg(feature = "builtin_elements")]
pub mod spacer; pub mod spacer;
#[cfg(feature = "builtin_elements")] // "The basics":
pub mod progress_bar;
#[cfg(feature = "builtin_elements")] #[cfg(feature = "builtin_elements")]
pub mod text; pub mod text;
#[cfg(feature = "builtin_elements")]
pub mod image;
#[cfg(feature = "builtin_elements")]
pub mod progress_bar;
// Wrappers:
#[cfg(feature = "builtin_elements")] #[cfg(feature = "builtin_elements")]
pub mod transformer; pub mod transformer;
#[cfg(feature = "builtin_elements")] #[cfg(feature = "builtin_elements")]
pub mod image; pub mod interactable;
//TODO add: Image //TODO add: Image
//TODO add: OverlayContainer (for simply laying multiple elements on top of each other) //TODO add: OverlayContainer (for simply laying multiple elements on top of each other)

View file

@ -1,55 +1,79 @@
//TODO this thing? //! wrapper that allows adding click and hover events to any element
//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
// 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> { use crate::element::{UiElement, MeasureContext, ProcessContext};
// pub element: T, use std::cell::RefCell;
// pub hovered: Option<Box<dyn FnOnce()>>,
// pub clicked: Option<Box<dyn FnOnce()>>,
// }
// impl<T: UiElement> Interactable<T> { /// Wrapper that allows adding click and hover events to any element
// pub fn new(element: T) -> Self { pub struct Interactable {
// Self { /// The wrapped element that will be interactable
// element, pub element: Box<dyn UiElement>,
// hovered: None, /// Function that will be called if the element is hovered in the current frame
// clicked: None, ///
// } /// 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 { impl Interactable {
// Self { pub fn new(element: Box<dyn UiElement>) -> Self {
// clicked: Some(Box::new(clicked)), Self {
// ..self element,
// } hovered: RefCell::new(None),
// } clicked: RefCell::new(None),
}
}
// pub fn on_hover(self, clicked: impl FnOnce() + 'static) -> Self { pub fn on_click(self, clicked: impl FnOnce() + 'static) -> Self {
// Self { Self {
// clicked: Some(Box::new(clicked)), clicked: RefCell::new(Some(Box::new(clicked))),
// ..self ..self
// } }
// } }
// }
// impl<T: UiElement> UiElement for Interactable<T> { pub fn on_hover(self, clicked: impl FnOnce() + 'static) -> Self {
// fn measure(&self, ctx: MeasureContext) -> crate::measure::Response { Self {
// self.element.measure(ctx) clicked: RefCell::new(Some(Box::new(clicked))),
// } ..self
}
}
}
// fn process(&self, ctx: ProcessContext) { impl UiElement for Interactable {
// self.element.process(ctx) fn name(&self) -> &'static str {
// } "Interactable"
// } }
// pub trait IntoInteractable<T: UiElement>: UiElement { fn measure(&self, ctx: MeasureContext) -> crate::measure::Response {
// fn into_interactable(self) -> Interactable<T>; self.element.measure(ctx)
// } }
// impl<T: UiElement> IntoInteractable<T> for T { fn process(&self, ctx: ProcessContext) {
// fn into_interactable(self) -> Interactable<Self> { let rect = ctx.measure.rect(ctx.layout.position);
// Interactable::new(self)
// } //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))
}
}

View file

@ -203,7 +203,9 @@ impl UiInputState {
button.start_position = self.mouse_pointer.current_position; button.start_position = self.mouse_pointer.current_position;
}, },
ButtonState::Released => { ButtonState::Released => {
//log::trace!("Button {:?} was released", button);
if let Some(button_meta) = self.mouse_pointer.buttons.remove(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); self.mouse_pointer.released_buttons.insert(*button, button_meta);
} else { } else {
//huh //huh

View file

@ -1,6 +1,7 @@
//! element measurement, hints and responses //! element measurement, hints and responses
use glam::Vec2; use glam::Vec2;
use crate::rectangle::Rect;
// #[non_exhaustive] // #[non_exhaustive]
#[derive(Default)] #[derive(Default)]
@ -27,3 +28,12 @@ pub struct Response {
/// You should almost never set this, and the exact behavior may change in the future /// You should almost never set this, and the exact behavior may change in the future
pub should_wrap: bool, pub should_wrap: bool,
} }
impl Response {
pub fn rect(&self, position: Vec2) -> Rect {
Rect {
position,
size: self.size,
}
}
}