diff --git a/dash-frontend/src/lib.rs b/dash-frontend/src/lib.rs index 383e840..256e61f 100644 --- a/dash-frontend/src/lib.rs +++ b/dash-frontend/src/lib.rs @@ -5,7 +5,7 @@ use glam::Vec2; use wgui::{ assets::AssetPath, components::button::ComponentButton, - event::{CallbackDataCommon, EventAlterables, EventListenerCollection}, + event::{CallbackDataCommon, EventAlterables}, globals::WguiGlobals, i18n::Translation, layout::{LayoutParams, RcLayout, WidgetID}, @@ -14,8 +14,8 @@ use wgui::{ }; use crate::tab::{ - Tab, TabParams, TabType, apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, processes::TabProcesses, - settings::TabSettings, + apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, processes::TabProcesses, settings::TabSettings, + Tab, TabParams, TabType, }; mod assets; @@ -45,16 +45,11 @@ pub enum FrontendTask { SetTab(TabType), } -pub struct FrontendParams<'a> { - pub listeners: &'a mut EventListenerCollection<(), ()>, -} - impl Frontend { - pub fn new(params: FrontendParams) -> anyhow::Result<(RcFrontend, RcLayout)> { + pub fn new() -> anyhow::Result<(RcFrontend, RcLayout)> { let globals = WguiGlobals::new(Box::new(assets::Asset {}), wgui::globals::Defaults::default())?; let (layout, state) = wgui::parser::new_layout_from_assets( - params.listeners, &ParseDocumentParams { globals: globals.clone(), path: AssetPath::BuiltIn("gui/dashboard.xml"), @@ -85,16 +80,9 @@ impl Frontend { Ok((res, rc_layout)) } - pub fn update( - &mut self, - rc_this: &RcFrontend, - listeners: &mut EventListenerCollection<(), ()>, - width: f32, - height: f32, - timestep_alpha: f32, - ) -> anyhow::Result<()> { + pub fn update(&mut self, rc_this: &RcFrontend, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()> { while let Some(task) = self.tasks.pop_front() { - self.process_task(rc_this, task, listeners)?; + self.process_task(rc_this, task)?; } self.tick(width, height, timestep_alpha)?; @@ -143,24 +131,14 @@ impl Frontend { self.tasks.push_back(task); } - fn process_task( - &mut self, - rc_this: &RcFrontend, - task: FrontendTask, - listeners: &mut EventListenerCollection<(), ()>, - ) -> anyhow::Result<()> { + fn process_task(&mut self, rc_this: &RcFrontend, task: FrontendTask) -> anyhow::Result<()> { match task { - FrontendTask::SetTab(tab_type) => self.set_tab(tab_type, rc_this, listeners)?, + FrontendTask::SetTab(tab_type) => self.set_tab(tab_type, rc_this)?, } Ok(()) } - fn set_tab( - &mut self, - tab_type: TabType, - rc_this: &RcFrontend, - listeners: &mut EventListenerCollection<(), ()>, - ) -> anyhow::Result<()> { + fn set_tab(&mut self, tab_type: TabType, rc_this: &RcFrontend) -> anyhow::Result<()> { log::info!("Setting tab to {tab_type:?}"); let mut layout = self.layout.borrow_mut(); let widget_content = self.state.fetch_widget(&layout.state, "content")?; @@ -170,7 +148,6 @@ impl Frontend { globals: &self.globals, layout: &mut layout, parent_id: widget_content.id, - listeners, frontend: rc_this, }; diff --git a/dash-frontend/src/tab/apps.rs b/dash-frontend/src/tab/apps.rs index 67573d7..c60f59a 100644 --- a/dash-frontend/src/tab/apps.rs +++ b/dash-frontend/src/tab/apps.rs @@ -41,12 +41,7 @@ impl TabApps { extra: Default::default(), }; - let mut state = wgui::parser::parse_from_assets( - doc_params, - tab_params.layout, - tab_params.listeners, - tab_params.parent_id, - )?; + let mut state = wgui::parser::parse_from_assets(doc_params, tab_params.layout, tab_params.parent_id)?; gtk::init()?; @@ -97,14 +92,7 @@ impl AppList { template_params.insert(Rc::from("name"), Rc::from(entry.app_name.as_str())); - let data = parser_state.parse_template( - doc_params, - "AppEntry", - params.layout, - params.listeners, - list_parent.id, - template_params, - )?; + let data = parser_state.parse_template(doc_params, "AppEntry", params.layout, list_parent.id, template_params)?; let button = data.fetch_component_as::("button")?; button.on_click(Box::new(move |_common, _evt| { diff --git a/dash-frontend/src/tab/games.rs b/dash-frontend/src/tab/games.rs index 6107717..1a304c7 100644 --- a/dash-frontend/src/tab/games.rs +++ b/dash-frontend/src/tab/games.rs @@ -25,7 +25,6 @@ impl TabGames { extra: Default::default(), }, params.layout, - params.listeners, params.parent_id, )?; diff --git a/dash-frontend/src/tab/home.rs b/dash-frontend/src/tab/home.rs index 9d6c6dd..8481918 100644 --- a/dash-frontend/src/tab/home.rs +++ b/dash-frontend/src/tab/home.rs @@ -43,7 +43,6 @@ impl TabHome { extra: Default::default(), }, params.layout, - params.listeners, params.parent_id, )?; diff --git a/dash-frontend/src/tab/mod.rs b/dash-frontend/src/tab/mod.rs index a5293cd..7383450 100644 --- a/dash-frontend/src/tab/mod.rs +++ b/dash-frontend/src/tab/mod.rs @@ -2,7 +2,6 @@ use std::rc::Rc; use wgui::{ components::button::ComponentButton, - event::EventListenerCollection, globals::WguiGlobals, layout::{Layout, WidgetID}, }; @@ -31,7 +30,6 @@ pub struct TabParams<'a> { pub layout: &'a mut Layout, pub parent_id: WidgetID, pub frontend: &'a RcFrontend, - pub listeners: &'a mut EventListenerCollection<(), ()>, } pub trait Tab { diff --git a/dash-frontend/src/tab/monado.rs b/dash-frontend/src/tab/monado.rs index d59c47e..4130ac7 100644 --- a/dash-frontend/src/tab/monado.rs +++ b/dash-frontend/src/tab/monado.rs @@ -25,7 +25,6 @@ impl TabMonado { extra: Default::default(), }, params.layout, - params.listeners, params.parent_id, )?; diff --git a/dash-frontend/src/tab/processes.rs b/dash-frontend/src/tab/processes.rs index f1b6580..a19bf28 100644 --- a/dash-frontend/src/tab/processes.rs +++ b/dash-frontend/src/tab/processes.rs @@ -25,7 +25,6 @@ impl TabProcesses { extra: Default::default(), }, params.layout, - params.listeners, params.parent_id, )?; diff --git a/dash-frontend/src/tab/settings.rs b/dash-frontend/src/tab/settings.rs index f8c7184..57e29f3 100644 --- a/dash-frontend/src/tab/settings.rs +++ b/dash-frontend/src/tab/settings.rs @@ -25,7 +25,6 @@ impl TabSettings { extra: Default::default(), }, params.layout, - params.listeners, params.parent_id, )?; diff --git a/wgui/src/components/button.rs b/wgui/src/components/button.rs index 6e73324..643147e 100644 --- a/wgui/src/components/button.rs +++ b/wgui/src/components/button.rs @@ -1,19 +1,19 @@ use crate::{ animation::{Animation, AnimationEasing}, - components::{self, Component, ComponentBase, ComponentTrait, InitData, tooltip::ComponentTooltip}, + components::{tooltip::ComponentTooltip, Component, ComponentBase, ComponentTrait, InitData}, drawing::{self, Boundary, Color}, - event::{CallbackDataCommon, EventListenerCollection, EventListenerKind, ListenerHandleVec}, + event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind}, i18n::Translation, - layout::{LayoutTask, WidgetID, WidgetPair}, + layout::{WidgetID, WidgetPair}, renderer_vk::{ text::{FontWeight, TextStyle}, util::centered_matrix, }, widget::{ - ConstructEssentials, EventResult, WidgetData, label::{WidgetLabel, WidgetLabelParams}, rectangle::{WidgetRectangle, WidgetRectangleParams}, util::WLength, + ConstructEssentials, EventResult, WidgetData, }, }; use glam::{Mat4, Vec3}; @@ -141,17 +141,14 @@ fn anim_hover_create(data: Rc, state: Rc>, widget_id: Widge ) } -fn register_event_mouse_enter( +fn register_event_mouse_enter( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> EventListenerID { listeners.register( - listener_handles, - data.id_rect, EventListenerKind::MouseEnter, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { common.alterables.trigger_haptics(); common.alterables.mark_redraw(); common.alterables.animate(anim_hover_create( @@ -182,20 +179,17 @@ fn register_event_mouse_enter( state.hovered = true; Ok(EventResult::Pass) }), - ); + ) } -fn register_event_mouse_leave( +fn register_event_mouse_leave( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> EventListenerID { listeners.register( - listener_handles, - data.id_rect, EventListenerKind::MouseLeave, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { common.alterables.trigger_haptics(); common.alterables.animate(anim_hover_create( data.clone(), @@ -208,20 +202,17 @@ fn register_event_mouse_leave( state.hovered = false; Ok(EventResult::Pass) }), - ); + ) } -fn register_event_mouse_press( +fn register_event_mouse_press( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> EventListenerID { listeners.register( - listener_handles, - data.id_rect, EventListenerKind::MousePress, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { let mut state = state.borrow_mut(); let rect = event_data.obj.get_as_mut::().unwrap(); @@ -244,20 +235,17 @@ fn register_event_mouse_press( Ok(EventResult::Pass) } }), - ); + ) } -fn register_event_mouse_release( +fn register_event_mouse_release( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> EventListenerID { listeners.register( - listener_handles, - data.id_rect, EventListenerKind::MouseRelease, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { let rect = event_data.obj.get_as_mut::().unwrap(); anim_hover( rect, @@ -285,13 +273,10 @@ fn register_event_mouse_release( Ok(EventResult::Pass) } }), - ); + ) } -pub fn construct( - ess: &mut ConstructEssentials, - params: Params, -) -> anyhow::Result<(WidgetPair, Rc)> { +pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc)> { let globals = ess.layout.state.globals.clone(); let mut style = params.style; @@ -384,12 +369,17 @@ pub fn construct( tooltip: None, })); - let mut base = ComponentBase::default(); - - register_event_mouse_enter(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_leave(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_press(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_release(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); + let base = ComponentBase { + lhandles: { + let mut widget = ess.layout.state.widgets.get(id_rect).unwrap().state(); + vec![ + register_event_mouse_enter(data.clone(), state.clone(), &mut widget.event_listeners), + register_event_mouse_leave(data.clone(), state.clone(), &mut widget.event_listeners), + register_event_mouse_press(data.clone(), state.clone(), &mut widget.event_listeners), + register_event_mouse_release(data.clone(), state.clone(), &mut widget.event_listeners), + ] + }, + }; let button = Rc::new(ComponentButton { base, data, state }); diff --git a/wgui/src/components/checkbox.rs b/wgui/src/components/checkbox.rs index 89e0d0e..ae1d639 100644 --- a/wgui/src/components/checkbox.rs +++ b/wgui/src/components/checkbox.rs @@ -1,22 +1,22 @@ use std::{cell::RefCell, rc::Rc}; use taffy::{ - AlignItems, JustifyContent, prelude::{length, percent}, + AlignItems, JustifyContent, }; use crate::{ animation::{Animation, AnimationEasing}, components::{Component, ComponentBase, ComponentTrait, InitData}, drawing::Color, - event::{CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerKind, ListenerHandleVec}, + event::{CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerID, EventListenerKind}, i18n::Translation, layout::{self, LayoutState, WidgetID, WidgetPair}, renderer_vk::text::{FontWeight, TextStyle}, widget::{ - ConstructEssentials, EventResult, label::{WidgetLabel, WidgetLabelParams}, rectangle::{WidgetRectangle, WidgetRectangleParams}, util::WLength, + ConstructEssentials, EventResult, }, }; @@ -139,17 +139,10 @@ fn anim_hover_out(state: Rc>, widget_id: WidgetID) -> Animation { ) } -fn register_event_mouse_enter( - data: &Rc, - state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { +fn register_event_mouse_enter(state: Rc>, listeners: &mut EventListenerCollection) -> EventListenerID { listeners.register( - listener_handles, - data.id_container, EventListenerKind::MouseEnter, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { common.alterables.trigger_haptics(); common .alterables @@ -157,20 +150,13 @@ fn register_event_mouse_enter( state.borrow_mut().hovered = true; Ok(EventResult::Pass) }), - ); + ) } -fn register_event_mouse_leave( - data: &Rc, - state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { +fn register_event_mouse_leave(state: Rc>, listeners: &mut EventListenerCollection) -> EventListenerID { listeners.register( - listener_handles, - data.id_container, EventListenerKind::MouseLeave, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { common.alterables.trigger_haptics(); common .alterables @@ -178,20 +164,13 @@ fn register_event_mouse_leave( state.borrow_mut().hovered = false; Ok(EventResult::Pass) }), - ); + ) } -fn register_event_mouse_press( - data: &Rc, - state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { +fn register_event_mouse_press(state: Rc>, listeners: &mut EventListenerCollection) -> EventListenerID { listeners.register( - listener_handles, - data.id_container, EventListenerKind::MousePress, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { let mut state = state.borrow_mut(); let rect = event_data.obj.get_as_mut::().unwrap(); @@ -207,20 +186,17 @@ fn register_event_mouse_press( Ok(EventResult::Pass) } }), - ); + ) } -fn register_event_mouse_release( +fn register_event_mouse_release( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> EventListenerID { listeners.register( - listener_handles, - data.id_container, EventListenerKind::MouseRelease, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { let rect = event_data.obj.get_as_mut::().unwrap(); anim_hover(rect, 1.0, false); @@ -244,13 +220,10 @@ fn register_event_mouse_release( Ok(EventResult::Pass) } }), - ); + ) } -pub fn construct( - ess: &mut ConstructEssentials, - params: Params, -) -> anyhow::Result<(WidgetPair, Rc)> { +pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc)> { let mut style = params.style; // force-override style @@ -348,12 +321,17 @@ pub fn construct( on_toggle: None, })); - let mut base = ComponentBase::default(); - - register_event_mouse_enter(&data, state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_leave(&data, state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_press(&data, state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_release(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); + let base = ComponentBase { + lhandles: { + let mut widget = ess.layout.state.widgets.get(id_container).unwrap().state(); + vec![ + register_event_mouse_enter(state.clone(), &mut widget.event_listeners), + register_event_mouse_leave(state.clone(), &mut widget.event_listeners), + register_event_mouse_press(state.clone(), &mut widget.event_listeners), + register_event_mouse_release(data.clone(), state.clone(), &mut widget.event_listeners), + ] + }, + }; let checkbox = Rc::new(ComponentCheckbox { base, data, state }); diff --git a/wgui/src/components/mod.rs b/wgui/src/components/mod.rs index 3a83541..2d24642 100644 --- a/wgui/src/components/mod.rs +++ b/wgui/src/components/mod.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use crate::{ any::AnyTrait, - event::{self, CallbackDataCommon}, + event::{CallbackDataCommon, EventListenerID}, }; pub mod button; @@ -17,7 +17,7 @@ pub struct InitData<'a> { // common component data #[derive(Default)] pub struct ComponentBase { - lhandles: event::ListenerHandleVec, + lhandles: Vec, } pub trait ComponentTrait: AnyTrait { diff --git a/wgui/src/components/slider.rs b/wgui/src/components/slider.rs index 230ab1d..1e9ea5a 100644 --- a/wgui/src/components/slider.rs +++ b/wgui/src/components/slider.rs @@ -7,7 +7,7 @@ use crate::{ animation::{Animation, AnimationEasing}, components::{Component, ComponentBase, ComponentTrait, InitData}, drawing::{self}, - event::{self, CallbackDataCommon, EventListenerCollection, EventListenerKind, ListenerHandleVec}, + event::{self, CallbackDataCommon, EventListenerCollection, EventListenerKind}, i18n::Translation, layout::{WidgetID, WidgetPair}, renderer_vk::{ @@ -15,11 +15,11 @@ use crate::{ util, }, widget::{ - ConstructEssentials, EventResult, div::WidgetDiv, label::{WidgetLabel, WidgetLabelParams}, rectangle::{WidgetRectangle, WidgetRectangleParams}, util::WLength, + ConstructEssentials, EventResult, }, }; @@ -197,55 +197,46 @@ fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) { )); } -fn register_event_mouse_enter( +fn register_event_mouse_enter( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> event::EventListenerID { listeners.register( - listener_handles, - data.body, EventListenerKind::MouseEnter, - Box::new(move |common, _data, _, _| { + Box::new(move |common, _data, (), ()| { common.alterables.trigger_haptics(); state.borrow_mut().hovered = true; on_enter_anim(common, data.slider_handle_rect_id); Ok(EventResult::Pass) }), - ); + ) } -fn register_event_mouse_leave( +fn register_event_mouse_leave( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> event::EventListenerID { listeners.register( - listener_handles, - data.body, EventListenerKind::MouseLeave, - Box::new(move |common, _data, _, _| { + Box::new(move |common, _data, (), ()| { common.alterables.trigger_haptics(); state.borrow_mut().hovered = false; on_leave_anim(common, data.slider_handle_rect_id); Ok(EventResult::Pass) }), - ); + ) } -fn register_event_mouse_motion( +fn register_event_mouse_motion( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> event::EventListenerID { listeners.register( - listener_handles, - data.body, EventListenerKind::MouseMotion, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { let mut state = state.borrow_mut(); if state.dragging { @@ -255,20 +246,17 @@ fn register_event_mouse_motion( Ok(EventResult::Pass) } }), - ); + ) } -fn register_event_mouse_press( +fn register_event_mouse_press( data: Rc, state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> event::EventListenerID { listeners.register( - listener_handles, - data.body, EventListenerKind::MousePress, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, event_data, (), ()| { common.alterables.trigger_haptics(); let mut state = state.borrow_mut(); @@ -280,20 +268,16 @@ fn register_event_mouse_press( Ok(EventResult::Pass) } }), - ); + ) } -fn register_event_mouse_release( - data: &Rc, +fn register_event_mouse_release( state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { + listeners: &mut EventListenerCollection, +) -> event::EventListenerID { listeners.register( - listener_handles, - data.body, EventListenerKind::MouseRelease, - Box::new(move |common, _data, _, _| { + Box::new(move |common, _data, (), ()| { common.alterables.trigger_haptics(); let mut state = state.borrow_mut(); @@ -304,13 +288,10 @@ fn register_event_mouse_release( Ok(EventResult::Pass) } }), - ); + ) } -pub fn construct( - ess: &mut ConstructEssentials, - params: Params, -) -> anyhow::Result<(WidgetPair, Rc)> { +pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc)> { let mut style = params.style; style.position = taffy::Position::Relative; style.min_size = style.size; @@ -410,14 +391,19 @@ pub fn construct( let state = Rc::new(RefCell::new(state)); - let mut base = ComponentBase::default(); - - register_event_mouse_enter(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_leave(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_motion(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_press(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_leave(data.clone(), state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_release(&data, state.clone(), ess.listeners, &mut base.lhandles); + let base = ComponentBase { + lhandles: { + let mut widget = ess.layout.state.widgets.get(body_id).unwrap().state(); + vec![ + register_event_mouse_enter(data.clone(), state.clone(), &mut widget.event_listeners), + register_event_mouse_leave(data.clone(), state.clone(), &mut widget.event_listeners), + register_event_mouse_motion(data.clone(), state.clone(), &mut widget.event_listeners), + register_event_mouse_press(data.clone(), state.clone(), &mut widget.event_listeners), + register_event_mouse_leave(data.clone(), state.clone(), &mut widget.event_listeners), + register_event_mouse_release(state.clone(), &mut widget.event_listeners), + ] + }, + }; let slider = Rc::new(ComponentSlider { base, data, state }); diff --git a/wgui/src/components/tooltip.rs b/wgui/src/components/tooltip.rs index de70c3c..cb35606 100644 --- a/wgui/src/components/tooltip.rs +++ b/wgui/src/components/tooltip.rs @@ -4,15 +4,15 @@ use taffy::prelude::length; use crate::{ components::{Component, ComponentBase, ComponentTrait, InitData}, drawing::Color, - event::{EventListenerCollection, EventListenerKind, ListenerHandleVec}, + event::{EventListenerCollection, EventListenerKind}, i18n::Translation, layout::{LayoutTasks, WidgetID, WidgetPair}, renderer_vk::text::{FontWeight, TextStyle}, widget::{ - ConstructEssentials, EventResult, label::{WidgetLabel, WidgetLabelParams}, rectangle::{WidgetRectangle, WidgetRectangleParams}, util::WLength, + ConstructEssentials, EventResult, }, }; @@ -53,44 +53,27 @@ impl ComponentTrait for ComponentTooltip { impl ComponentTooltip {} -fn register_event_mouse_enter( - data: &Rc, - state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { +fn register_event_mouse_enter(listeners: &mut EventListenerCollection) -> crate::event::EventListenerID { listeners.register( - listener_handles, - data.id_container, EventListenerKind::MouseEnter, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, _event_data, (), ()| { common.alterables.trigger_haptics(); Ok(EventResult::Pass) }), - ); + ) } -fn register_event_mouse_leave( - data: &Rc, - state: Rc>, - listeners: &mut EventListenerCollection, - listener_handles: &mut ListenerHandleVec, -) { +fn register_event_mouse_leave(listeners: &mut EventListenerCollection) -> crate::event::EventListenerID { listeners.register( - listener_handles, - data.id_container, EventListenerKind::MouseEnter, - Box::new(move |common, event_data, _, _| { + Box::new(move |common, _event_data, (), ()| { common.alterables.trigger_haptics(); Ok(EventResult::Pass) }), - ); + ) } -pub fn construct( - ess: &mut ConstructEssentials, - params: Params, -) -> anyhow::Result<(WidgetPair, Rc)> { +pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc)> { let style = taffy::Style { align_items: Some(taffy::AlignItems::Center), justify_content: Some(taffy::JustifyContent::Center), @@ -141,10 +124,15 @@ pub fn construct( let state = Rc::new(RefCell::new(State {})); - let mut base = ComponentBase::default(); - - register_event_mouse_enter(&data, state.clone(), ess.listeners, &mut base.lhandles); - register_event_mouse_leave(&data, state.clone(), ess.listeners, &mut base.lhandles); + let base = ComponentBase { + lhandles: { + let mut widget = ess.layout.state.widgets.get(id_container).unwrap().state(); + vec![ + register_event_mouse_enter(&mut widget.event_listeners), + register_event_mouse_leave(&mut widget.event_listeners), + ] + }, + }; let tooltip = Rc::new(ComponentTooltip { base, diff --git a/wgui/src/event.rs b/wgui/src/event.rs index d432245..970f4e9 100644 --- a/wgui/src/event.rs +++ b/wgui/src/event.rs @@ -1,11 +1,11 @@ use std::{ - cell::{Ref, RefCell, RefMut}, + any::{Any, TypeId}, + cell::RefMut, collections::HashSet, - rc::Rc, }; use glam::Vec2; -use slotmap::SecondaryMap; +use slotmap::{new_key_type, DenseSlotMap}; use crate::{ animation::{self, Animation}, @@ -192,130 +192,94 @@ pub enum EventListenerKind { InternalStateChange, } -pub type EventCallback = - Box anyhow::Result>; +pub type EventCallbackInternal = Box< + dyn for<'a, 'b, 'c, 'd> Fn( + &'a mut CallbackDataCommon<'b>, + &'a mut CallbackData<'c>, + &'d mut dyn Any, + &'d mut dyn Any, + ) -> anyhow::Result, +>; -//for ref-counting -pub struct ListenerHandle { - needs_gc: Rc>, // this will be set to true on destructor +pub type EventCallback = Box< + dyn for<'a, 'b, 'c, 'd> Fn( + &'a mut CallbackDataCommon<'b>, + &'a mut CallbackData<'c>, + &'d mut U1, + &'d mut U2, + ) -> anyhow::Result, +>; + +new_key_type! { + pub struct EventListenerID; +} + +pub struct EventListener { + kind: EventListenerKind, + callback: EventCallbackInternal, + tid1: TypeId, + tid2: TypeId, +} + +impl EventListener { + pub fn call_with( + &self, + common: &mut CallbackDataCommon, + data: &mut CallbackData, + user_data: &mut (&mut U1, &mut U2), + ) -> anyhow::Result { + (self.callback)(common, data, user_data.0, user_data.1) + } } #[derive(Default)] -pub struct ListenerHandleVec(Vec>); - -impl ListenerHandleVec { - pub fn push(&mut self, handle: Rc) { - self.0.push(handle); - } +pub struct EventListenerCollection { + inner: DenseSlotMap, } -impl Drop for ListenerHandle { - fn drop(&mut self) { - *self.needs_gc.borrow_mut() = true; - } -} - -pub struct EventListener { - pub kind: EventListenerKind, - pub callback: EventCallback, - pub handle: std::rc::Weak, -} - -impl EventListener { - pub fn callback_for_kind( +impl EventListenerCollection { + /// Iterates over event handlers with a matching U type + pub fn iter_filtered( &self, kind: EventListenerKind, - ) -> Option<&impl Fn(&mut CallbackDataCommon, &mut CallbackData, &mut U1, &mut U2) -> anyhow::Result> { - if self.kind == kind { Some(&self.callback) } else { None } + ) -> impl Iterator { + let tid1 = TypeId::of::(); + let tid2 = TypeId::of::(); + self + .inner + .values() + .filter(move |p| p.tid1 == tid1 && p.tid2 == tid2 && p.kind == kind) } -} -#[derive(Default)] -pub struct EventListenerVec(Vec>); - -impl EventListenerVec { - pub fn iter(&self) -> impl Iterator> { - self.0.iter().filter(|p| p.handle.strong_count() > 0) - } -} - -pub struct EventListenerCollection { - pub map: SecondaryMap>, - needs_gc: Rc>, -} - -// derive only works if generics also implement Default -impl Default for EventListenerCollection { - fn default() -> Self { - Self { - map: SecondaryMap::default(), - needs_gc: Rc::new(RefCell::new(false)), - } - } -} - -impl EventListenerCollection { - pub fn register( + pub fn register( &mut self, - listener_handles: &mut ListenerHandleVec, - widget_id: WidgetID, kind: EventListenerKind, callback: EventCallback, - ) { - let res = self.add_single(widget_id, kind, callback); - listener_handles.push(res); - } + ) -> EventListenerID { + let tid1 = TypeId::of::(); + let tid2 = TypeId::of::(); - pub fn add_single( - &mut self, - widget_id: WidgetID, - kind: EventListenerKind, - callback: EventCallback, - ) -> Rc { - let handle = Rc::new(ListenerHandle { - needs_gc: self.needs_gc.clone(), + let callback_inner: EventCallbackInternal = Box::new(move |common, data, u1_any, u2_any| { + if let Some(u1) = u1_any.downcast_mut::() + && let Some(u2) = u2_any.downcast_mut::() + { + callback(common, data, u1, u2) + } else { + Ok(EventResult::Pass) + } }); let new_item = EventListener { kind, - callback, - handle: Rc::downgrade(&handle), + callback: callback_inner, + tid1, + tid2, }; - if let Some(vec) = self.map.get_mut(widget_id) { - vec.0.push(new_item); - } else { - self.map.insert(widget_id, EventListenerVec(vec![new_item])); - } - handle + self.inner.insert(new_item) } - // clean-up expired events - pub fn gc(&mut self) { - { - let mut needs_gc = self.needs_gc.borrow_mut(); - if !*needs_gc { - return; - } - - *needs_gc = false; - } - - let mut count = 0; - - for (_id, vec) in &mut self.map { - vec.0.retain(|listener| { - if listener.handle.strong_count() != 0 { - true - } else { - count += 1; - false - } - }); - } - - self.map.retain(|_k, v| !v.0.is_empty()); - - log::debug!("EventListenerCollection: cleaned-up {count} expired events"); + pub fn remove(&mut self, event_listener_id: EventListenerID) -> Option { + self.inner.remove(event_listener_id) } } diff --git a/wgui/src/layout.rs b/wgui/src/layout.rs index fc4f6fd..953ed9e 100644 --- a/wgui/src/layout.rs +++ b/wgui/src/layout.rs @@ -8,14 +8,14 @@ use std::{ use crate::{ animation::Animations, components::{Component, InitData}, - drawing::{self, ANSI_BOLD_CODE, ANSI_RESET_CODE, Boundary, push_scissor_stack, push_transform_stack}, - event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection}, + drawing::{self, push_scissor_stack, push_transform_stack, Boundary, ANSI_BOLD_CODE, ANSI_RESET_CODE}, + event::{self, CallbackDataCommon, EventAlterables}, globals::WguiGlobals, - widget::{self, EventParams, EventResult, WidgetObj, WidgetState, div::WidgetDiv}, + widget::{self, div::WidgetDiv, EventParams, EventResult, WidgetObj, WidgetState}, }; -use glam::{Vec2, vec2}; -use slotmap::{HopSlotMap, SecondaryMap, new_key_type}; +use glam::{vec2, Vec2}; +use slotmap::{new_key_type, HopSlotMap, SecondaryMap}; use taffy::{NodeId, TaffyTree, TraversePartialTree}; new_key_type! { @@ -113,7 +113,7 @@ pub struct LayoutState { pub struct ModifyLayoutStateData<'a> { pub layout: &'a mut Layout, // don't uncomment this, todo! - // pub listeners: &'a mut EventListenerCollection, + // pub listeners: &'a mut EventListenerCollection, } pub enum LayoutTask { @@ -310,9 +310,26 @@ impl Layout { self.components_to_init.push(component); } - fn push_event_children( + /// Convenience function to avoid repeated `WidgetID` → `WidgetState` lookups. + pub fn add_event_listener( + &self, + widget_id: WidgetID, + kind: event::EventListenerKind, + callback: event::EventCallback, + ) -> Option { + Some( + self + .state + .widgets + .get(widget_id)? + .state() + .event_listeners + .register(kind, callback), + ) + } + + fn push_event_children( &self, - listeners: &mut EventListenerCollection, parent_node_id: taffy::NodeId, event: &event::Event, alterables: &mut EventAlterables, @@ -325,7 +342,7 @@ impl Layout { let mut iter = |idx: usize| -> anyhow::Result { let child_id = self.state.tree.get_child_id(parent_node_id, idx); - let child_result = self.push_event_widget(listeners, child_id, event, alterables, user_data, false)?; + let child_result = self.push_event_widget(child_id, event, alterables, user_data, false)?; if child_result != EventResult::Pass { event_result = child_result; return Ok(true); @@ -350,9 +367,8 @@ impl Layout { Ok(event_result) } - fn push_event_widget( + fn push_event_widget( &self, - listeners: &mut EventListenerCollection, node_id: taffy::NodeId, event: &event::Event, alterables: &mut EventAlterables, @@ -392,7 +408,7 @@ impl Layout { let reverse_iter = is_root_node; // check children first - let mut evt_result = self.push_event_children(listeners, node_id, event, alterables, user_data, reverse_iter)?; + let mut evt_result = self.push_event_children(node_id, event, alterables, user_data, reverse_iter)?; if evt_result == EventResult::Pass { let mut params = EventParams { @@ -403,8 +419,7 @@ impl Layout { style, }; - let listeners_vec = listeners.map.get(widget_id); - let this_evt_result = widget.process_event(widget_id, listeners_vec, node_id, event, user_data, &mut params)?; + let this_evt_result = widget.process_event(widget_id, node_id, event, user_data, &mut params)?; if this_evt_result != EventResult::Pass { evt_result = this_evt_result; } @@ -436,25 +451,16 @@ impl Layout { } } - pub fn push_event( + pub fn push_event( &mut self, - listeners: &mut EventListenerCollection, event: &event::Event, - mut user_data: (&mut U1, &mut U2), + user1: &mut U1, + user2: &mut U2, ) -> anyhow::Result<()> { let mut alterables = EventAlterables::default(); - let _event_result = self.push_event_widget( - listeners, - self.tree_root_node, - event, - &mut alterables, - &mut user_data, - true, - )?; + let _event_result = + self.push_event_widget(self.tree_root_node, event, &mut alterables, &mut (user1, user2), true)?; self.process_alterables(alterables)?; - - listeners.gc(); - Ok(()) } diff --git a/wgui/src/parser/component_button.rs b/wgui/src/parser/component_button.rs index d424479..ebf7355 100644 --- a/wgui/src/parser/component_button.rs +++ b/wgui/src/parser/component_button.rs @@ -7,12 +7,12 @@ use crate::{ AttribPair, ParserContext, ParserFile, parse_check_f32, parse_children, process_component, style::{parse_color_opt, parse_round, parse_style, parse_text_style}, }, - widget::{ConstructEssentials, util::WLength}, + widget::util::WLength, }; -pub fn parse_component_button<'a, U1, U2>( +pub fn parse_component_button<'a>( file: &'a ParserFile, - ctx: &mut ParserContext, + ctx: &mut ParserContext, node: roxmltree::Node<'a, 'a>, parent_id: WidgetID, attribs: &[AttribPair], @@ -79,4 +79,4 @@ pub fn parse_component_button<'a, U1, U2>( parse_children(file, ctx, node, widget.id)?; Ok(widget.id) -} +} \ No newline at end of file diff --git a/wgui/src/parser/component_checkbox.rs b/wgui/src/parser/component_checkbox.rs index f77f4c3..1dcdfb1 100644 --- a/wgui/src/parser/component_checkbox.rs +++ b/wgui/src/parser/component_checkbox.rs @@ -3,11 +3,10 @@ use crate::{ i18n::Translation, layout::WidgetID, parser::{AttribPair, ParserContext, parse_check_f32, parse_check_i32, process_component, style::parse_style}, - widget::ConstructEssentials, }; -pub fn parse_component_checkbox( - ctx: &mut ParserContext, +pub fn parse_component_checkbox( + ctx: &mut ParserContext, parent_id: WidgetID, attribs: &[AttribPair], ) -> anyhow::Result { @@ -49,4 +48,4 @@ pub fn parse_component_checkbox( process_component(ctx, Component(component), widget.id, attribs); Ok(widget.id) -} +} \ No newline at end of file diff --git a/wgui/src/parser/component_slider.rs b/wgui/src/parser/component_slider.rs index 4d67d04..74615e9 100644 --- a/wgui/src/parser/component_slider.rs +++ b/wgui/src/parser/component_slider.rs @@ -5,8 +5,8 @@ use crate::{ widget::ConstructEssentials, }; -pub fn parse_component_slider( - ctx: &mut ParserContext, +pub fn parse_component_slider( + ctx: &mut ParserContext, parent_id: WidgetID, attribs: &[AttribPair], ) -> anyhow::Result { @@ -35,7 +35,6 @@ pub fn parse_component_slider( let (widget, component) = slider::construct( &mut ConstructEssentials { layout: ctx.layout, - listeners: ctx.listeners, parent: parent_id, }, slider::Params { @@ -51,4 +50,4 @@ pub fn parse_component_slider( process_component(ctx, Component(component), widget.id, attribs); Ok(widget.id) -} +} \ No newline at end of file diff --git a/wgui/src/parser/mod.rs b/wgui/src/parser/mod.rs index 867e4e8..1246fc5 100644 --- a/wgui/src/parser/mod.rs +++ b/wgui/src/parser/mod.rs @@ -11,7 +11,6 @@ use crate::{ assets::{AssetPath, AssetPathOwned, normalize_path}, components::{Component, ComponentWeak}, drawing::{self}, - event::EventListenerCollection, globals::WguiGlobals, layout::{Layout, LayoutParams, LayoutState, Widget, WidgetID, WidgetMap, WidgetPair}, parser::{ @@ -204,12 +203,11 @@ impl ParserState { /// This function is suitable in cases if you don't want to pollute main parser state with dynamic IDs /// Use `instantiate_template` instead unless you want to handle `components` results yourself. /// Make sure not to drop them if you want to have your listener handles valid - pub fn parse_template( + pub fn parse_template( &mut self, doc_params: &ParseDocumentParams, template_name: &str, layout: &mut Layout, - listeners: &mut EventListenerCollection, widget_id: WidgetID, template_parameters: HashMap, Rc>, ) -> anyhow::Result { @@ -219,7 +217,6 @@ impl ParserState { let mut ctx = ParserContext { layout, - listeners, data_global: &self.data, data_local: ParserData::default(), doc_params, @@ -236,23 +233,15 @@ impl ParserState { } /// Instantinate template by saving all the results into the main `ParserState` - pub fn instantiate_template( + pub fn instantiate_template( &mut self, doc_params: &ParseDocumentParams, template_name: &str, layout: &mut Layout, - listeners: &mut EventListenerCollection, widget_id: WidgetID, template_parameters: HashMap, Rc>, ) -> anyhow::Result<()> { - let mut data_local = self.parse_template( - doc_params, - template_name, - layout, - listeners, - widget_id, - template_parameters, - )?; + let mut data_local = self.parse_template(doc_params, template_name, layout, widget_id, template_parameters)?; self.data.take_results_from(&mut data_local); Ok(()) @@ -295,19 +284,17 @@ struct MacroAttribs { attribs: HashMap, Rc>, } -struct ParserContext<'a, U1, U2> { +struct ParserContext<'a> { doc_params: &'a ParseDocumentParams<'a>, layout: &'a mut Layout, - listeners: &'a mut EventListenerCollection, data_global: &'a ParserData, // current parser state at a given moment data_local: ParserData, // newly processed items in a given template } -impl ParserContext<'_, U1, U2> { - const fn get_construct_essentials(&mut self, parent: WidgetID) -> ConstructEssentials<'_, U1, U2> { +impl ParserContext<'_> { + const fn get_construct_essentials(&mut self, parent: WidgetID) -> ConstructEssentials<'_> { ConstructEssentials { layout: self.layout, - listeners: self.listeners, parent, } } @@ -509,11 +496,11 @@ where } } -fn parse_widget_other_internal( +fn parse_widget_other_internal( template: &Rc