event system!!!
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
use std::{hash::Hash, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
layout::{IdFnTag, Ui, UiModule, Widget, WidgetId, WidgetIdFn, WidgetLike},
|
||||
util::Id,
|
||||
util::{HashMap, Id},
|
||||
};
|
||||
|
||||
pub trait UiCtx {
|
||||
@@ -14,16 +16,12 @@ impl UiCtx for Ui {
|
||||
}
|
||||
|
||||
pub trait Event<Ctx>: Sized {
|
||||
type Module: UiModule + EventModule<Ctx, Self> + Default;
|
||||
type Data;
|
||||
type Module: EventModule<Self, Ctx>;
|
||||
type Data: Clone;
|
||||
}
|
||||
|
||||
pub trait EventModule<Ctx, E: Event<Ctx>> {
|
||||
fn register(&mut self, id: Id, event: E, f: impl EventFn<Ctx, E::Data>);
|
||||
}
|
||||
|
||||
pub trait EventFn<Ctx, Data>: FnMut(&mut Ctx, Data) + 'static {}
|
||||
impl<F: FnMut(&mut Ctx, Data) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {}
|
||||
pub trait EventFn<Ctx, Data>: Fn(&mut Ctx, Data) + 'static {}
|
||||
impl<F: Fn(&mut Ctx, Data) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {}
|
||||
|
||||
pub trait Eventable<W, Tag> {
|
||||
fn on<E: Event<Ctx>, Ctx>(
|
||||
@@ -35,7 +33,7 @@ pub trait Eventable<W, Tag> {
|
||||
fn id_on<E: Event<Ctx>, Ctx>(
|
||||
self,
|
||||
event: E,
|
||||
f: impl FnMut(&WidgetId<W>, &mut Ctx, E::Data) + 'static,
|
||||
f: impl Fn(&WidgetId<W>, &mut Ctx, E::Data) + 'static,
|
||||
) -> impl WidgetIdFn<W> + Eventable<W, IdFnTag>
|
||||
where
|
||||
W: Widget;
|
||||
@@ -43,7 +41,7 @@ pub trait Eventable<W, Tag> {
|
||||
fn edit_on<E: Event<Ui>>(
|
||||
self,
|
||||
event: E,
|
||||
f: impl FnMut(&mut W, E::Data) + 'static,
|
||||
f: impl Fn(&mut W, E::Data) + 'static,
|
||||
) -> impl WidgetIdFn<W> + Eventable<W, IdFnTag>
|
||||
where
|
||||
W: Widget;
|
||||
@@ -67,7 +65,7 @@ impl<W: WidgetLike<Tag>, Tag> Eventable<W::Widget, Tag> for W {
|
||||
fn id_on<E: Event<Ctx>, Ctx>(
|
||||
self,
|
||||
event: E,
|
||||
mut f: impl FnMut(&WidgetId<W::Widget>, &mut Ctx, E::Data) + 'static,
|
||||
mut f: impl Fn(&WidgetId<W::Widget>, &mut Ctx, E::Data) + 'static,
|
||||
) -> impl WidgetIdFn<W::Widget>
|
||||
where
|
||||
W::Widget: Widget,
|
||||
@@ -81,7 +79,7 @@ impl<W: WidgetLike<Tag>, Tag> Eventable<W::Widget, Tag> for W {
|
||||
fn edit_on<E: Event<Ui>>(
|
||||
self,
|
||||
event: E,
|
||||
mut f: impl FnMut(&mut W::Widget, E::Data) + 'static,
|
||||
mut f: impl Fn(&mut W::Widget, E::Data) + 'static,
|
||||
) -> impl WidgetIdFn<W::Widget>
|
||||
where
|
||||
W::Widget: Widget,
|
||||
@@ -89,3 +87,116 @@ impl<W: WidgetLike<Tag>, Tag> Eventable<W::Widget, Tag> for W {
|
||||
self.id_on(event, move |id, ui, pos| f(&mut ui[id], pos))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DefaultEvent: Hash + Eq + 'static {
|
||||
type Data: Clone;
|
||||
}
|
||||
|
||||
impl<E: DefaultEvent, Ctx: 'static> Event<Ctx> for E {
|
||||
type Module = DefaultEventModule<E, Ctx>;
|
||||
type Data = E::Data;
|
||||
}
|
||||
|
||||
pub trait EventModule<E: Event<Ctx>, Ctx>: UiModule + Default {
|
||||
fn register(&mut self, id: Id, event: E, f: impl EventFn<Ctx, E::Data>);
|
||||
fn run<'a>(
|
||||
&mut self,
|
||||
id: &Id,
|
||||
event: E,
|
||||
) -> Option<impl Fn(&mut Ctx, E::Data) + use<'a, Self, E, Ctx>>;
|
||||
}
|
||||
|
||||
type EventFnMap<Ctx, Data> = HashMap<Id, Vec<Rc<dyn EventFn<Ctx, Data>>>>;
|
||||
pub struct DefaultEventModule<E: Event<Ctx>, Ctx> {
|
||||
map: HashMap<E, EventFnMap<Ctx, <E as Event<Ctx>>::Data>>,
|
||||
}
|
||||
|
||||
impl<E: Event<Ctx> + 'static, Ctx: 'static> UiModule for DefaultEventModule<E, Ctx> {
|
||||
fn on_remove(&mut self, id: &Id) {
|
||||
for map in self.map.values_mut() {
|
||||
map.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HashableEvent<Ctx>: Event<Ctx> + Hash + Eq + 'static {}
|
||||
impl<E: Event<Ctx> + Hash + Eq + 'static, Ctx> HashableEvent<Ctx> for E {}
|
||||
|
||||
impl<E: HashableEvent<Ctx>, Ctx: 'static> EventModule<E, Ctx> for DefaultEventModule<E, Ctx> {
|
||||
fn register(&mut self, id: Id, event: E, f: impl EventFn<Ctx, <E as Event<Ctx>>::Data>) {
|
||||
self.map
|
||||
.entry(event)
|
||||
.or_default()
|
||||
.entry(id)
|
||||
.or_default()
|
||||
.push(Rc::new(f));
|
||||
}
|
||||
|
||||
fn run<'a>(
|
||||
&mut self,
|
||||
id: &Id,
|
||||
event: E,
|
||||
) -> Option<impl Fn(&mut Ctx, E::Data) + use<'a, E, Ctx>> {
|
||||
if let Some(map) = self.map.get_mut(&event)
|
||||
&& let Some(fs) = map.get(id)
|
||||
{
|
||||
let fs = fs.clone();
|
||||
Some(move |ctx: &mut Ctx, data: E::Data| {
|
||||
for f in &fs {
|
||||
f(ctx, data.clone())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: HashableEvent<Ctx>, Ctx: 'static> DefaultEventModule<E, Ctx> {
|
||||
pub fn run_all(&mut self, ctx: &mut Ctx, event: E, data: E::Data)
|
||||
where
|
||||
E::Data: Clone,
|
||||
{
|
||||
if let Some(map) = self.map.get_mut(&event) {
|
||||
for fs in map.values_mut() {
|
||||
for f in fs {
|
||||
f(ctx, data.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run<W>(&mut self, ctx: &mut Ctx, id: WidgetId<W>, event: E, data: E::Data)
|
||||
where
|
||||
E::Data: Clone,
|
||||
{
|
||||
if let Some(map) = self.map.get_mut(&event)
|
||||
&& let Some(fs) = map.get_mut(&id.id)
|
||||
{
|
||||
for f in fs {
|
||||
f(ctx, data.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Event<Ctx> + 'static, Ctx: 'static> Default for DefaultEventModule<E, Ctx> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
map: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ui {
|
||||
pub fn run_event<E: Event<Ctx>, Ctx: UiCtx, W>(
|
||||
ctx: &mut Ctx,
|
||||
id: &WidgetId<W>,
|
||||
event: E,
|
||||
data: E::Data,
|
||||
) {
|
||||
if let Some(f) = ctx.ui().modules.get_mut::<E::Module>().run(&id.id, event) {
|
||||
f(ctx, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user