use std::{hash::Hash, rc::Rc}; use crate::{ layout::{IdFnTag, Ui, UiModule, Widget, WidgetId, WidgetIdFn, WidgetLike}, util::{HashMap, Id}, }; pub trait UiCtx { fn ui(&mut self) -> &mut Ui; } impl UiCtx for Ui { fn ui(&mut self) -> &mut Ui { self } } pub trait Event: Sized { type Module: EventModule; type Data: Clone; } pub trait EventFn: Fn(&mut Ctx, Data) + 'static {} impl EventFn for F {} pub trait Eventable { fn on( self, event: E, f: impl EventFn, ) -> impl WidgetIdFn + Eventable; fn id_on( self, event: E, f: impl Fn(&WidgetId, &mut Ctx, E::Data) + 'static, ) -> impl WidgetIdFn + Eventable where W: Widget; fn edit_on( self, event: E, f: impl Fn(&mut W, E::Data) + 'static, ) -> impl WidgetIdFn + Eventable where W: Widget; } impl, Tag> Eventable for W { fn on( self, event: E, f: impl EventFn, ) -> impl WidgetIdFn { move |ui| { let id = self.add(ui); ui.register_event(&id, event, f); id } } fn id_on( self, event: E, f: impl Fn(&WidgetId, &mut Ctx, E::Data) + 'static, ) -> impl WidgetIdFn where W::Widget: Widget, { self.with_id(move |ui, id| { let id2 = id.clone(); id.on(event, move |ctx, pos| f(&id2, ctx, pos)).add(ui) }) } fn edit_on( self, event: E, f: impl Fn(&mut W::Widget, E::Data) + 'static, ) -> impl WidgetIdFn where W::Widget: Widget, { self.id_on(event, move |id, ui: &mut Ui, pos| f(&mut ui[id], pos)) } } pub trait DefaultEvent: Hash + Eq + 'static { type Data: Clone; } impl Event for E { type Module = DefaultEventModule; type Data = E::Data; } pub trait EventModule: UiModule + Default { fn register(&mut self, id: Id, event: E, f: impl EventFn); fn run<'a>( &self, id: &Id, event: E, ) -> Option>; } type EventFnMap = HashMap>>>; pub struct DefaultEventModule { map: HashMap::Data>>, } impl UiModule for DefaultEventModule { fn on_remove(&mut self, id: &Id) { for map in self.map.values_mut() { map.remove(id); } } } pub trait HashableEvent: Event + Hash + Eq + 'static {} impl HashableEvent for E {} impl EventModule for DefaultEventModule { fn register(&mut self, id: Id, event: E, f: impl EventFn::Data>) { self.map .entry(event) .or_default() .entry(id) .or_default() .push(Rc::new(f)); } fn run<'a>(&self, id: &Id, event: E) -> Option> { if let Some(map) = self.map.get(&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 DefaultEventModule { pub fn run_all(&self, ctx: &mut Ctx, event: E, data: E::Data) where E::Data: Clone, { if let Some(map) = self.map.get(&event) { for fs in map.values() { for f in fs { f(ctx, data.clone()) } } } } } impl Default for DefaultEventModule { fn default() -> Self { Self { map: Default::default(), } } } impl Ui { pub fn run_event( ctx: &mut Ctx, id: &WidgetId, event: E, data: E::Data, ) { if let Some(f) = ctx .ui() .data .modules .get_mut::>() .run(&id.id, event) { f(ctx, data); } } } pub trait EventCtx: UiCtx { fn run_event(&mut self, id: &WidgetId, event: E, data: E::Data); } impl EventCtx for Ctx { fn run_event(&mut self, id: &WidgetId, event: E, data: E::Data) { Ui::run_event(self, id, event.clone(), data.clone()); } }