update interactable

This commit is contained in:
griffi-gh 2024-03-12 01:06:03 +01:00
parent 01b30c5979
commit bd0364bde9
2 changed files with 34 additions and 39 deletions

View file

@ -41,10 +41,7 @@ ui_main!(
Text::new("-") Text::new("-")
.add_child(ui); .add_child(ui);
}) })
.into_interactable() .on_click(CounterSignal::Increment)
.on_click(|| {
println!("clicked");
})
.add_child(ui); .add_child(ui);
Text::new(counter.to_string()) Text::new(counter.to_string())
.with_color(color::BLACK) .with_color(color::BLACK)
@ -58,10 +55,7 @@ ui_main!(
Text::new("+") Text::new("+")
.add_child(ui); .add_child(ui);
}) })
.into_interactable() .on_click(CounterSignal::Decrement)
.on_click(|| {
println!("clicked");
})
.add_child(ui); .add_child(ui);
}) })
.add_root(ui, size); .add_root(ui, size);

View file

@ -5,51 +5,43 @@
use crate::{ use crate::{
element::{MeasureContext, ProcessContext, UiElement}, element::{MeasureContext, ProcessContext, UiElement},
signal::{DummySignal, UiSignal}, signal::UiSignal,
}; };
use std::cell::RefCell; use std::cell::RefCell;
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum InteractableEvent {
#[default]
Click,
Hover,
}
/// Wrapper that allows adding click and hover events to any element /// Wrapper that allows adding click and hover events to any element
pub struct Interactable<H: UiSignal + 'static = DummySignal, C: UiSignal + 'static = DummySignal> { pub struct Interactable<C: UiSignal + 'static> {
/// The wrapped element that will be interactable /// The wrapped element that will be interactable
pub element: Box<dyn UiElement>, pub element: Box<dyn UiElement>,
/// Signal that will be called if the element is hovered in the current frame /// Event to listen for
/// pub event: InteractableEvent,
/// Will be consumed after the first time it's called
pub hovered: RefCell<Option<H>>,
/// Signal that will be called if the element was clicked in the current frame /// Signal that will be called if the element was clicked in the current frame
/// ///
/// Will be consumed after the first time it's called /// Will be consumed after the first time it's called
pub clicked: RefCell<Option<C>>, pub signal: RefCell<Option<C>>,
} }
impl<H: UiSignal, C: UiSignal> Interactable<H, C> { impl<C: UiSignal + 'static> Interactable<C> {
pub fn new(element: Box<dyn UiElement>) -> Self { pub fn new(element: Box<dyn UiElement>, event: InteractableEvent, signal: C) -> Self {
Self { Self {
element, element,
hovered: RefCell::new(None), event: InteractableEvent::Click,
clicked: RefCell::new(None), signal: RefCell::new(Some(signal)),
}
}
pub fn on_hover(self, hover: H) -> Self {
Self {
hovered: RefCell::new(Some(hover)),
..self
}
}
pub fn on_click(self, clicked: C) -> Self {
Self {
clicked: RefCell::new(Some(clicked)),
..self
} }
} }
} }
impl UiElement for Interactable { impl<C: UiSignal + 'static> UiElement for Interactable<C> {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"Interactable" "Interactable"
} }
@ -62,9 +54,8 @@ impl UiElement for Interactable {
let rect = ctx.measure.rect(ctx.layout.position); let rect = ctx.measure.rect(ctx.layout.position);
//XXX: should we do this AFTER normal process call of wrapped element? //XXX: should we do this AFTER normal process call of wrapped element?
//TODO other events...
if ctx.input.check_click(rect) { if ctx.input.check_click(rect) {
if let Some(sig) = self.clicked.take() { if let Some(sig) = self.signal.take() {
//ctx.signal.push(sig); //ctx.signal.push(sig);
} }
} }
@ -74,11 +65,21 @@ impl UiElement for Interactable {
} }
pub trait ElementInteractableExt: UiElement { pub trait ElementInteractableExt: UiElement {
fn into_interactable(self) -> Interactable; fn into_interactable<C: UiSignal + 'static>(self, event: InteractableEvent, signal: C) -> Interactable<C>;
fn on_click<C: UiSignal + 'static>(self, signal: C) -> Interactable<C>;
fn on_hover<C: UiSignal + 'static>(self, signal: C) -> Interactable<C>;
} }
impl<T: UiElement + 'static> ElementInteractableExt for T { impl<T: UiElement + 'static> ElementInteractableExt for T {
fn into_interactable(self) -> Interactable { fn into_interactable<C: UiSignal + 'static>(self, event: InteractableEvent, signal: C) -> Interactable<C> {
Interactable::new(Box::new(self)) Interactable::new(Box::new(self), event, signal)
}
fn on_click<C: UiSignal + 'static>(self, signal: C) -> Interactable<C> {
self.into_interactable(InteractableEvent::Click, signal)
}
fn on_hover<C: UiSignal + 'static>(self, signal: C) -> Interactable<C> {
self.into_interactable(InteractableEvent::Hover, signal)
} }
} }