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 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();

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")]
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)

View file

@ -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))
}
}

View file

@ -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

View file

@ -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,
}
}
}