events refactor
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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::<ComponentButton>("button")?;
|
||||
button.on_click(Box::new(move |_common, _evt| {
|
||||
|
||||
@@ -25,7 +25,6 @@ impl TabGames {
|
||||
extra: Default::default(),
|
||||
},
|
||||
params.layout,
|
||||
params.listeners,
|
||||
params.parent_id,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ impl TabHome {
|
||||
extra: Default::default(),
|
||||
},
|
||||
params.layout,
|
||||
params.listeners,
|
||||
params.parent_id,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -25,7 +25,6 @@ impl TabMonado {
|
||||
extra: Default::default(),
|
||||
},
|
||||
params.layout,
|
||||
params.listeners,
|
||||
params.parent_id,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ impl TabProcesses {
|
||||
extra: Default::default(),
|
||||
},
|
||||
params.layout,
|
||||
params.listeners,
|
||||
params.parent_id,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ impl TabSettings {
|
||||
extra: Default::default(),
|
||||
},
|
||||
params.layout,
|
||||
params.listeners,
|
||||
params.parent_id,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -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<Data>, state: Rc<RefCell<State>>, widget_id: Widge
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_enter<U1, U2>(
|
||||
fn register_event_mouse_enter(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
state.hovered = true;
|
||||
Ok(EventResult::Pass)
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_leave<U1, U2>(
|
||||
fn register_event_mouse_leave(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
state.hovered = false;
|
||||
Ok(EventResult::Pass)
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_press<U1, U2>(
|
||||
fn register_event_mouse_press(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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::<WidgetRectangle>().unwrap();
|
||||
@@ -244,20 +235,17 @@ fn register_event_mouse_press<U1, U2>(
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_release<U1, U2>(
|
||||
fn register_event_mouse_release(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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::<WidgetRectangle>().unwrap();
|
||||
anim_hover(
|
||||
rect,
|
||||
@@ -285,13 +273,10 @@ fn register_event_mouse_release<U1, U2>(
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
pub fn construct<U1, U2>(
|
||||
ess: &mut ConstructEssentials<U1, U2>,
|
||||
params: Params,
|
||||
) -> anyhow::Result<(WidgetPair, Rc<ComponentButton>)> {
|
||||
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentButton>)> {
|
||||
let globals = ess.layout.state.globals.clone();
|
||||
let mut style = params.style;
|
||||
|
||||
@@ -384,12 +369,17 @@ pub fn construct<U1, U2>(
|
||||
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 });
|
||||
|
||||
|
||||
@@ -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<RefCell<State>>, widget_id: WidgetID) -> Animation {
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_enter<U1, U2>(
|
||||
data: &Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
listener_handles: &mut ListenerHandleVec,
|
||||
) {
|
||||
fn register_event_mouse_enter(state: Rc<RefCell<State>>, 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<U1, U2>(
|
||||
state.borrow_mut().hovered = true;
|
||||
Ok(EventResult::Pass)
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_leave<U1, U2>(
|
||||
data: &Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
listener_handles: &mut ListenerHandleVec,
|
||||
) {
|
||||
fn register_event_mouse_leave(state: Rc<RefCell<State>>, 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<U1, U2>(
|
||||
state.borrow_mut().hovered = false;
|
||||
Ok(EventResult::Pass)
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_press<U1, U2>(
|
||||
data: &Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
listener_handles: &mut ListenerHandleVec,
|
||||
) {
|
||||
fn register_event_mouse_press(state: Rc<RefCell<State>>, 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::<WidgetRectangle>().unwrap();
|
||||
@@ -207,20 +186,17 @@ fn register_event_mouse_press<U1, U2>(
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_release<U1, U2>(
|
||||
fn register_event_mouse_release(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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::<WidgetRectangle>().unwrap();
|
||||
anim_hover(rect, 1.0, false);
|
||||
|
||||
@@ -244,13 +220,10 @@ fn register_event_mouse_release<U1, U2>(
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
pub fn construct<U1, U2>(
|
||||
ess: &mut ConstructEssentials<U1, U2>,
|
||||
params: Params,
|
||||
) -> anyhow::Result<(WidgetPair, Rc<ComponentCheckbox>)> {
|
||||
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentCheckbox>)> {
|
||||
let mut style = params.style;
|
||||
|
||||
// force-override style
|
||||
@@ -348,12 +321,17 @@ pub fn construct<U1, U2>(
|
||||
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 });
|
||||
|
||||
|
||||
@@ -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<EventListenerID>,
|
||||
}
|
||||
|
||||
pub trait ComponentTrait: AnyTrait {
|
||||
|
||||
@@ -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<U1, U2>(
|
||||
fn register_event_mouse_enter(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
fn register_event_mouse_leave(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
fn register_event_mouse_motion(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_press<U1, U2>(
|
||||
fn register_event_mouse_press(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
fn register_event_mouse_release<U1, U2>(
|
||||
data: &Rc<Data>,
|
||||
fn register_event_mouse_release(
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
pub fn construct<U1, U2>(
|
||||
ess: &mut ConstructEssentials<U1, U2>,
|
||||
params: Params,
|
||||
) -> anyhow::Result<(WidgetPair, Rc<ComponentSlider>)> {
|
||||
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentSlider>)> {
|
||||
let mut style = params.style;
|
||||
style.position = taffy::Position::Relative;
|
||||
style.min_size = style.size;
|
||||
@@ -410,14 +391,19 @@ pub fn construct<U1, U2>(
|
||||
|
||||
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 });
|
||||
|
||||
|
||||
@@ -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<U1, U2>(
|
||||
data: &Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
data: &Rc<Data>,
|
||||
state: Rc<RefCell<State>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
ess: &mut ConstructEssentials<U1, U2>,
|
||||
params: Params,
|
||||
) -> anyhow::Result<(WidgetPair, Rc<ComponentTooltip>)> {
|
||||
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentTooltip>)> {
|
||||
let style = taffy::Style {
|
||||
align_items: Some(taffy::AlignItems::Center),
|
||||
justify_content: Some(taffy::JustifyContent::Center),
|
||||
@@ -141,10 +124,15 @@ pub fn construct<U1, U2>(
|
||||
|
||||
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,
|
||||
|
||||
@@ -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<U1, U2> =
|
||||
Box<dyn Fn(&mut CallbackDataCommon, &mut CallbackData, &mut U1, &mut U2) -> anyhow::Result<EventResult>>;
|
||||
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<EventResult>,
|
||||
>;
|
||||
|
||||
//for ref-counting
|
||||
pub struct ListenerHandle {
|
||||
needs_gc: Rc<RefCell<bool>>, // this will be set to true on destructor
|
||||
pub type EventCallback<U1, U2> = Box<
|
||||
dyn for<'a, 'b, 'c, 'd> Fn(
|
||||
&'a mut CallbackDataCommon<'b>,
|
||||
&'a mut CallbackData<'c>,
|
||||
&'d mut U1,
|
||||
&'d mut U2,
|
||||
) -> anyhow::Result<EventResult>,
|
||||
>;
|
||||
|
||||
new_key_type! {
|
||||
pub struct EventListenerID;
|
||||
}
|
||||
|
||||
pub struct EventListener {
|
||||
kind: EventListenerKind,
|
||||
callback: EventCallbackInternal,
|
||||
tid1: TypeId,
|
||||
tid2: TypeId,
|
||||
}
|
||||
|
||||
impl EventListener {
|
||||
pub fn call_with<U1: 'static, U2: 'static>(
|
||||
&self,
|
||||
common: &mut CallbackDataCommon,
|
||||
data: &mut CallbackData,
|
||||
user_data: &mut (&mut U1, &mut U2),
|
||||
) -> anyhow::Result<EventResult> {
|
||||
(self.callback)(common, data, user_data.0, user_data.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ListenerHandleVec(Vec<Rc<ListenerHandle>>);
|
||||
|
||||
impl ListenerHandleVec {
|
||||
pub fn push(&mut self, handle: Rc<ListenerHandle>) {
|
||||
self.0.push(handle);
|
||||
}
|
||||
pub struct EventListenerCollection {
|
||||
inner: DenseSlotMap<EventListenerID, EventListener>,
|
||||
}
|
||||
|
||||
impl Drop for ListenerHandle {
|
||||
fn drop(&mut self) {
|
||||
*self.needs_gc.borrow_mut() = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventListener<U1, U2> {
|
||||
pub kind: EventListenerKind,
|
||||
pub callback: EventCallback<U1, U2>,
|
||||
pub handle: std::rc::Weak<ListenerHandle>,
|
||||
}
|
||||
|
||||
impl<U1, U2> EventListener<U1, U2> {
|
||||
pub fn callback_for_kind(
|
||||
impl EventListenerCollection {
|
||||
/// Iterates over event handlers with a matching U type
|
||||
pub fn iter_filtered<U1: 'static, U2: 'static>(
|
||||
&self,
|
||||
kind: EventListenerKind,
|
||||
) -> Option<&impl Fn(&mut CallbackDataCommon, &mut CallbackData, &mut U1, &mut U2) -> anyhow::Result<EventResult>> {
|
||||
if self.kind == kind { Some(&self.callback) } else { None }
|
||||
}
|
||||
) -> impl Iterator<Item = &EventListener> {
|
||||
let tid1 = TypeId::of::<U1>();
|
||||
let tid2 = TypeId::of::<U2>();
|
||||
self
|
||||
.inner
|
||||
.values()
|
||||
.filter(move |p| p.tid1 == tid1 && p.tid2 == tid2 && p.kind == kind)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EventListenerVec<U1, U2>(Vec<EventListener<U1, U2>>);
|
||||
|
||||
impl<U1, U2> EventListenerVec<U1, U2> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = &EventListener<U1, U2>> {
|
||||
self.0.iter().filter(|p| p.handle.strong_count() > 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventListenerCollection<U1, U2> {
|
||||
pub map: SecondaryMap<WidgetID, EventListenerVec<U1, U2>>,
|
||||
needs_gc: Rc<RefCell<bool>>,
|
||||
}
|
||||
|
||||
// derive only works if generics also implement Default
|
||||
impl<U1, U2> Default for EventListenerCollection<U1, U2> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
map: SecondaryMap::default(),
|
||||
needs_gc: Rc::new(RefCell::new(false)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<U1, U2> EventListenerCollection<U1, U2> {
|
||||
pub fn register(
|
||||
pub fn register<U1: 'static, U2: 'static>(
|
||||
&mut self,
|
||||
listener_handles: &mut ListenerHandleVec,
|
||||
widget_id: WidgetID,
|
||||
kind: EventListenerKind,
|
||||
callback: EventCallback<U1, U2>,
|
||||
) {
|
||||
let res = self.add_single(widget_id, kind, callback);
|
||||
listener_handles.push(res);
|
||||
}
|
||||
) -> EventListenerID {
|
||||
let tid1 = TypeId::of::<U1>();
|
||||
let tid2 = TypeId::of::<U2>();
|
||||
|
||||
pub fn add_single(
|
||||
&mut self,
|
||||
widget_id: WidgetID,
|
||||
kind: EventListenerKind,
|
||||
callback: EventCallback<U1, U2>,
|
||||
) -> Rc<ListenerHandle> {
|
||||
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::<U1>()
|
||||
&& let Some(u2) = u2_any.downcast_mut::<U2>()
|
||||
{
|
||||
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]));
|
||||
|
||||
self.inner.insert(new_item)
|
||||
}
|
||||
|
||||
handle
|
||||
}
|
||||
|
||||
// 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<EventListener> {
|
||||
self.inner.remove(event_listener_id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<U1, U2>,
|
||||
// pub listeners: &'a mut EventListenerCollection,
|
||||
}
|
||||
|
||||
pub enum LayoutTask {
|
||||
@@ -310,9 +310,26 @@ impl Layout {
|
||||
self.components_to_init.push(component);
|
||||
}
|
||||
|
||||
fn push_event_children<U1, U2>(
|
||||
/// Convenience function to avoid repeated `WidgetID` → `WidgetState` lookups.
|
||||
pub fn add_event_listener<U1: 'static, U2: 'static>(
|
||||
&self,
|
||||
widget_id: WidgetID,
|
||||
kind: event::EventListenerKind,
|
||||
callback: event::EventCallback<U1, U2>,
|
||||
) -> Option<event::EventListenerID> {
|
||||
Some(
|
||||
self
|
||||
.state
|
||||
.widgets
|
||||
.get(widget_id)?
|
||||
.state()
|
||||
.event_listeners
|
||||
.register(kind, callback),
|
||||
)
|
||||
}
|
||||
|
||||
fn push_event_children<U1: 'static, U2: 'static>(
|
||||
&self,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
parent_node_id: taffy::NodeId,
|
||||
event: &event::Event,
|
||||
alterables: &mut EventAlterables,
|
||||
@@ -325,7 +342,7 @@ impl Layout {
|
||||
|
||||
let mut iter = |idx: usize| -> anyhow::Result<bool> {
|
||||
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<U1, U2>(
|
||||
fn push_event_widget<U1: 'static, U2: 'static>(
|
||||
&self,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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<U1, U2>(
|
||||
pub fn push_event<U1: 'static, U2: 'static>(
|
||||
&mut self,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
|
||||
@@ -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<U1, U2>(
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
pub fn parse_component_checkbox(
|
||||
ctx: &mut ParserContext,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
|
||||
@@ -5,8 +5,8 @@ use crate::{
|
||||
widget::ConstructEssentials,
|
||||
};
|
||||
|
||||
pub fn parse_component_slider<U1, U2>(
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
pub fn parse_component_slider(
|
||||
ctx: &mut ParserContext,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
@@ -35,7 +35,6 @@ pub fn parse_component_slider<U1, U2>(
|
||||
let (widget, component) = slider::construct(
|
||||
&mut ConstructEssentials {
|
||||
layout: ctx.layout,
|
||||
listeners: ctx.listeners,
|
||||
parent: parent_id,
|
||||
},
|
||||
slider::Params {
|
||||
|
||||
@@ -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<U1, U2>(
|
||||
pub fn parse_template(
|
||||
&mut self,
|
||||
doc_params: &ParseDocumentParams,
|
||||
template_name: &str,
|
||||
layout: &mut Layout,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
widget_id: WidgetID,
|
||||
template_parameters: HashMap<Rc<str>, Rc<str>>,
|
||||
) -> anyhow::Result<ParserData> {
|
||||
@@ -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<U1, U2>(
|
||||
pub fn instantiate_template(
|
||||
&mut self,
|
||||
doc_params: &ParseDocumentParams,
|
||||
template_name: &str,
|
||||
layout: &mut Layout,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
widget_id: WidgetID,
|
||||
template_parameters: HashMap<Rc<str>, Rc<str>>,
|
||||
) -> 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<str>, Rc<str>>,
|
||||
}
|
||||
|
||||
struct ParserContext<'a, U1, U2> {
|
||||
struct ParserContext<'a> {
|
||||
doc_params: &'a ParseDocumentParams<'a>,
|
||||
layout: &'a mut Layout,
|
||||
listeners: &'a mut EventListenerCollection<U1, U2>,
|
||||
data_global: &'a ParserData, // current parser state at a given moment
|
||||
data_local: ParserData, // newly processed items in a given template
|
||||
}
|
||||
|
||||
impl<U1, U2> 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<U1, U2>(
|
||||
fn parse_widget_other_internal(
|
||||
template: &Rc<Template>,
|
||||
template_parameters: HashMap<Rc<str>, Rc<str>>,
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
parent_id: WidgetID,
|
||||
) -> anyhow::Result<()> {
|
||||
let template_file = ParserFile {
|
||||
@@ -534,10 +521,10 @@ fn parse_widget_other_internal<U1, U2>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_widget_other<U1, U2>(
|
||||
fn parse_widget_other(
|
||||
xml_tag_name: &str,
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<()> {
|
||||
@@ -552,9 +539,9 @@ fn parse_widget_other<U1, U2>(
|
||||
parse_widget_other_internal(&template, template_parameters, file, ctx, parent_id)
|
||||
}
|
||||
|
||||
fn parse_tag_include<U1, U2>(
|
||||
fn parse_tag_include(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<()> {
|
||||
@@ -591,7 +578,7 @@ fn parse_tag_include<U1, U2>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_tag_var<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'a, 'a>) {
|
||||
fn parse_tag_var<'a>(ctx: &mut ParserContext, node: roxmltree::Node<'a, 'a>) {
|
||||
let mut out_key: Option<&str> = None;
|
||||
let mut out_value: Option<&str> = None;
|
||||
|
||||
@@ -646,12 +633,7 @@ pub fn replace_vars(input: &str, vars: &HashMap<Rc<str>, Rc<str>>) -> Rc<str> {
|
||||
}
|
||||
|
||||
#[allow(clippy::manual_strip)]
|
||||
fn process_attrib<'a, U1, U2>(
|
||||
file: &'a ParserFile,
|
||||
ctx: &'a ParserContext<U1, U2>,
|
||||
key: &str,
|
||||
value: &str,
|
||||
) -> AttribPair {
|
||||
fn process_attrib<'a>(file: &'a ParserFile, ctx: &'a ParserContext, key: &str, value: &str) -> AttribPair {
|
||||
if value.starts_with('~') {
|
||||
let name = &value[1..];
|
||||
|
||||
@@ -673,9 +655,9 @@ fn raw_attribs<'a>(node: &'a roxmltree::Node<'a, 'a>) -> Vec<AttribPair> {
|
||||
res
|
||||
}
|
||||
|
||||
fn process_attribs<'a, U1, U2>(
|
||||
fn process_attribs<'a>(
|
||||
file: &'a ParserFile,
|
||||
ctx: &'a ParserContext<U1, U2>,
|
||||
ctx: &'a ParserContext,
|
||||
node: &'a roxmltree::Node<'a, 'a>,
|
||||
is_tag_macro: bool,
|
||||
) -> Vec<AttribPair> {
|
||||
@@ -704,7 +686,7 @@ fn process_attribs<'a, U1, U2>(
|
||||
res
|
||||
}
|
||||
|
||||
fn parse_tag_theme<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'a, 'a>) {
|
||||
fn parse_tag_theme<'a>(ctx: &mut ParserContext, node: roxmltree::Node<'a, 'a>) {
|
||||
for child_node in node.children() {
|
||||
let child_name = child_node.tag_name().name();
|
||||
match child_name {
|
||||
@@ -719,7 +701,7 @@ fn parse_tag_theme<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, node: roxmltree:
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_tag_template<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'_, '_>) {
|
||||
fn parse_tag_template(file: &ParserFile, ctx: &mut ParserContext, node: roxmltree::Node<'_, '_>) {
|
||||
let mut template_name: Option<Rc<str>> = None;
|
||||
|
||||
let attribs = process_attribs(file, ctx, &node, false);
|
||||
@@ -749,7 +731,7 @@ fn parse_tag_template<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>
|
||||
);
|
||||
}
|
||||
|
||||
fn parse_tag_macro<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'_, '_>) {
|
||||
fn parse_tag_macro(file: &ParserFile, ctx: &mut ParserContext, node: roxmltree::Node<'_, '_>) {
|
||||
let mut macro_name: Option<Rc<str>> = None;
|
||||
|
||||
let attribs = process_attribs(file, ctx, &node, true);
|
||||
@@ -776,12 +758,7 @@ fn parse_tag_macro<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, n
|
||||
ctx.insert_macro_attrib(name, MacroAttribs { attribs: macro_attribs });
|
||||
}
|
||||
|
||||
fn process_component<U1, U2>(
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
component: Component,
|
||||
widget_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) {
|
||||
fn process_component(ctx: &mut ParserContext, component: Component, widget_id: WidgetID, attribs: &[AttribPair]) {
|
||||
let mut component_id: Option<Rc<str>> = None;
|
||||
|
||||
for pair in attribs {
|
||||
@@ -797,7 +774,7 @@ fn process_component<U1, U2>(
|
||||
ctx.insert_component(widget_id, component, component_id);
|
||||
}
|
||||
|
||||
fn parse_widget_universal<U1, U2>(ctx: &mut ParserContext<U1, U2>, widget_id: WidgetID, attribs: &[AttribPair]) {
|
||||
fn parse_widget_universal(ctx: &mut ParserContext, widget_id: WidgetID, attribs: &[AttribPair]) {
|
||||
for pair in attribs {
|
||||
#[allow(clippy::single_match)]
|
||||
match pair.attrib.as_ref() {
|
||||
@@ -810,9 +787,9 @@ fn parse_widget_universal<U1, U2>(ctx: &mut ParserContext<U1, U2>, widget_id: Wi
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_child<'a, U1, U2>(
|
||||
fn parse_child<'a>(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
parent_node: roxmltree::Node<'a, 'a>,
|
||||
child_node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
@@ -893,9 +870,9 @@ fn parse_child<'a, U1, U2>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_children<'a, U1, U2>(
|
||||
fn parse_children<'a>(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
parent_node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
) -> anyhow::Result<()> {
|
||||
@@ -906,16 +883,14 @@ fn parse_children<'a, U1, U2>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_default_context<'a, U1, U2>(
|
||||
fn create_default_context<'a>(
|
||||
doc_params: &'a ParseDocumentParams,
|
||||
layout: &'a mut Layout,
|
||||
listeners: &'a mut EventListenerCollection<U1, U2>,
|
||||
data_global: &'a ParserData,
|
||||
) -> ParserContext<'a, U1, U2> {
|
||||
) -> ParserContext<'a> {
|
||||
ParserContext {
|
||||
doc_params,
|
||||
layout,
|
||||
listeners,
|
||||
data_local: ParserData::default(),
|
||||
data_global,
|
||||
}
|
||||
@@ -1011,14 +986,13 @@ pub struct ParseDocumentParams<'a> {
|
||||
pub extra: ParseDocumentExtra, // optional field, can be Default-ed
|
||||
}
|
||||
|
||||
pub fn parse_from_assets<U1, U2>(
|
||||
pub fn parse_from_assets(
|
||||
doc_params: &ParseDocumentParams,
|
||||
layout: &mut Layout,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
parent_id: WidgetID,
|
||||
) -> anyhow::Result<ParserState> {
|
||||
let parser_data = ParserData::default();
|
||||
let mut ctx = create_default_context(doc_params, layout, listeners, &parser_data);
|
||||
let mut ctx = create_default_context(doc_params, layout, &parser_data);
|
||||
let (file, node_layout) = get_doc_from_asset_path(&ctx, doc_params.path)?;
|
||||
parse_document_root(&file, &mut ctx, parent_id, node_layout)?;
|
||||
|
||||
@@ -1033,19 +1007,18 @@ pub fn parse_from_assets<U1, U2>(
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn new_layout_from_assets<U1, U2>(
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
pub fn new_layout_from_assets(
|
||||
doc_params: &ParseDocumentParams,
|
||||
layout_params: &LayoutParams,
|
||||
) -> anyhow::Result<(Layout, ParserState)> {
|
||||
let mut layout = Layout::new(doc_params.globals.clone(), layout_params)?;
|
||||
let widget = layout.content_root_widget;
|
||||
let state = parse_from_assets(doc_params, &mut layout, listeners, widget)?;
|
||||
let state = parse_from_assets(doc_params, &mut layout, widget)?;
|
||||
Ok((layout, state))
|
||||
}
|
||||
|
||||
fn get_doc_from_asset_path<U1, U2>(
|
||||
ctx: &ParserContext<U1, U2>,
|
||||
fn get_doc_from_asset_path(
|
||||
ctx: &ParserContext,
|
||||
asset_path: AssetPath,
|
||||
) -> anyhow::Result<(ParserFile, roxmltree::NodeId)> {
|
||||
let data = ctx.layout.state.globals.get_asset(asset_path)?;
|
||||
@@ -1071,9 +1044,9 @@ fn get_doc_from_asset_path<U1, U2>(
|
||||
Ok((file, tag_layout.id()))
|
||||
}
|
||||
|
||||
fn parse_document_root<U1, U2>(
|
||||
fn parse_document_root(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
parent_id: WidgetID,
|
||||
node_layout: roxmltree::NodeId,
|
||||
) -> anyhow::Result<()> {
|
||||
|
||||
@@ -4,9 +4,9 @@ use crate::{
|
||||
widget::div::WidgetDiv,
|
||||
};
|
||||
|
||||
pub fn parse_widget_div<'a, U1, U2>(
|
||||
pub fn parse_widget_div<'a>(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
|
||||
@@ -8,9 +8,9 @@ use crate::{
|
||||
widget::label::{WidgetLabel, WidgetLabelParams},
|
||||
};
|
||||
|
||||
pub fn parse_widget_label<'a, U1, U2>(
|
||||
pub fn parse_widget_label<'a>(
|
||||
file: &'a ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
|
||||
@@ -8,9 +8,9 @@ use crate::{
|
||||
widget::rectangle::{WidgetRectangle, WidgetRectangleParams},
|
||||
};
|
||||
|
||||
pub fn parse_widget_rectangle<'a, U1, U2>(
|
||||
pub fn parse_widget_rectangle<'a>(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
|
||||
@@ -8,9 +8,9 @@ use crate::{
|
||||
|
||||
use super::{parse_color_hex, print_invalid_attrib};
|
||||
|
||||
pub fn parse_widget_sprite<'a, U1, U2>(
|
||||
pub fn parse_widget_sprite<'a>(
|
||||
file: &'a ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
ctx: &mut ParserContext,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
|
||||
@@ -7,7 +7,8 @@ use crate::{
|
||||
drawing::{self, PrimitiveExtent},
|
||||
event::{
|
||||
self, CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables, EventListenerCollection,
|
||||
EventListenerKind, EventListenerVec, MouseWheelEvent,
|
||||
EventListenerKind::{InternalStateChange, MouseEnter, MouseLeave, MouseMotion, MousePress, MouseRelease},
|
||||
MouseWheelEvent,
|
||||
},
|
||||
layout::{Layout, LayoutState, WidgetID},
|
||||
stack::{ScissorStack, TransformStack},
|
||||
@@ -75,6 +76,7 @@ impl WidgetData {
|
||||
pub struct WidgetState {
|
||||
pub data: WidgetData,
|
||||
pub obj: Box<dyn WidgetObj>,
|
||||
pub event_listeners: EventListenerCollection,
|
||||
}
|
||||
|
||||
impl WidgetState {
|
||||
@@ -95,6 +97,7 @@ impl WidgetState {
|
||||
transform: glam::Mat4::IDENTITY,
|
||||
},
|
||||
obj,
|
||||
event_listeners: EventListenerCollection::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,9 +211,8 @@ impl dyn WidgetObj {
|
||||
}
|
||||
|
||||
macro_rules! call_event {
|
||||
($self:ident, $listeners:ident, $widget_id:ident, $node_id:ident, $params:ident, $kind:ident, $user_data:expr, $metadata:expr) => {
|
||||
for listener in $listeners.iter() {
|
||||
if let Some(callback) = listener.callback_for_kind(EventListenerKind::$kind) {
|
||||
($self:ident, $widget_id:ident, $node_id:ident, $params:ident, $kind:ident, $u1:ty, $u2:ty, $user_data:expr, $metadata:expr) => {
|
||||
for listener in $self.event_listeners.iter_filtered::<$u1, $u2>($kind) {
|
||||
let mut data = CallbackData {
|
||||
obj: $self.obj.as_mut(),
|
||||
widget_data: &mut $self.data,
|
||||
@@ -223,13 +225,11 @@ macro_rules! call_event {
|
||||
state: $params.state,
|
||||
alterables: $params.alterables,
|
||||
};
|
||||
|
||||
let result = callback(&mut common, &mut data, $user_data.0, $user_data.1)?;
|
||||
let result = listener.call_with(&mut common, &mut data, $user_data)?;
|
||||
if result == EventResult::Consumed {
|
||||
return Ok(EventResult::Consumed);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -384,10 +384,9 @@ impl WidgetState {
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn process_event<'a, U1, U2>(
|
||||
pub fn process_event<'a, U1: 'static, U2: 'static>(
|
||||
&mut self,
|
||||
widget_id: WidgetID,
|
||||
listeners: Option<&EventListenerVec<U1, U2>>,
|
||||
node_id: taffy::NodeId,
|
||||
event: &Event,
|
||||
user_data: &mut (&mut U1, &mut U2),
|
||||
@@ -397,17 +396,15 @@ impl WidgetState {
|
||||
|
||||
match &event {
|
||||
Event::MouseDown(e) => {
|
||||
if hovered
|
||||
&& self.data.set_device_pressed(e.device, true)
|
||||
&& let Some(listeners) = &listeners
|
||||
{
|
||||
if hovered && self.data.set_device_pressed(e.device, true) {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MousePress,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
@@ -417,16 +414,15 @@ impl WidgetState {
|
||||
}
|
||||
}
|
||||
Event::MouseUp(e) => {
|
||||
if self.data.set_device_pressed(e.device, false)
|
||||
&& let Some(listeners) = listeners
|
||||
{
|
||||
if self.data.set_device_pressed(e.device, false) {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseRelease,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
@@ -438,40 +434,41 @@ impl WidgetState {
|
||||
Event::MouseMotion(e) => {
|
||||
let hover_state_changed = self.data.set_device_hovered(e.device, hovered);
|
||||
|
||||
if let Some(listeners) = &listeners {
|
||||
if hover_state_changed {
|
||||
if self.data.is_hovered() {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseEnter,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
);
|
||||
} else {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseLeave,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseMotion,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::MousePosition(event::MousePosition { pos: e.pos })
|
||||
);
|
||||
@@ -483,42 +480,39 @@ impl WidgetState {
|
||||
}
|
||||
}
|
||||
Event::MouseLeave(e) => {
|
||||
if self.data.set_device_hovered(e.device, false)
|
||||
&& let Some(listeners) = &listeners
|
||||
{
|
||||
if self.data.set_device_hovered(e.device, false) {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseLeave,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
);
|
||||
}
|
||||
}
|
||||
Event::InternalStateChange(e) => {
|
||||
if let Some(listeners) = &listeners {
|
||||
call_event!(
|
||||
self,
|
||||
listeners,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
InternalStateChange,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::Custom(e.metadata)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(EventResult::Pass)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConstructEssentials<'a, U1, U2> {
|
||||
pub struct ConstructEssentials<'a> {
|
||||
pub layout: &'a mut Layout,
|
||||
pub listeners: &'a mut EventListenerCollection<U1, U2>,
|
||||
pub parent: WidgetID,
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use taffy::prelude::length;
|
||||
use crate::{
|
||||
assets::AssetPath,
|
||||
components::button::ComponentButton,
|
||||
event::EventListenerCollection,
|
||||
globals::WguiGlobals,
|
||||
layout::{Layout, LayoutTask, LayoutTasks, WidgetPair},
|
||||
parser::{self, Fetchable, ParserState},
|
||||
@@ -43,7 +42,6 @@ pub struct WguiWindowParams<'a> {
|
||||
pub position: Vec2,
|
||||
pub globals: WguiGlobals,
|
||||
pub layout: &'a mut Layout,
|
||||
pub listeners: &'a mut EventListenerCollection<(), ()>,
|
||||
}
|
||||
|
||||
impl Default for WguiWindow {
|
||||
@@ -84,7 +82,6 @@ impl WguiWindow {
|
||||
extra: Default::default(),
|
||||
},
|
||||
params.layout,
|
||||
params.listeners,
|
||||
widget.id,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ use std::{
|
||||
};
|
||||
|
||||
use wgui::{
|
||||
event::{self, EventCallback, EventListenerCollection, EventListenerKind, ListenerHandleVec},
|
||||
event::{self, EventCallback, EventListenerKind},
|
||||
layout::Layout,
|
||||
parser::CustomAttribsInfoOwned,
|
||||
widget::EventResult,
|
||||
};
|
||||
@@ -17,10 +18,9 @@ use crate::backend::{task::TaskType, wayvr::WayVRAction};
|
||||
|
||||
use super::helper::read_label_from_pipe;
|
||||
|
||||
pub(super) fn setup_custom_button<S>(
|
||||
pub(super) fn setup_custom_button<S: 'static>(
|
||||
layout: &mut Layout,
|
||||
attribs: &CustomAttribsInfoOwned,
|
||||
listeners: &mut EventListenerCollection<AppState, S>,
|
||||
listener_handles: &mut ListenerHandleVec,
|
||||
_app: &AppState,
|
||||
) {
|
||||
const EVENTS: [(&str, EventListenerKind); 2] = [
|
||||
@@ -69,7 +69,7 @@ pub(super) fn setup_custom_button<S>(
|
||||
_ => return,
|
||||
};
|
||||
|
||||
listeners.register(listener_handles, attribs.widget_id, *kind, callback);
|
||||
layout.add_event_listener(attribs.widget_id, *kind, callback);
|
||||
}
|
||||
}
|
||||
struct ShellButtonMutableState {
|
||||
|
||||
@@ -12,11 +12,11 @@ use chrono_tz::Tz;
|
||||
use interprocess::os::unix::fifo_file::create_fifo;
|
||||
use wgui::{
|
||||
drawing,
|
||||
event::{self, EventCallback, EventListenerCollection, ListenerHandleVec},
|
||||
event::{self, EventCallback},
|
||||
i18n::Translation,
|
||||
layout::Layout,
|
||||
parser::{CustomAttribsInfoOwned, parse_color_hex},
|
||||
widget::{EventResult, label::WidgetLabel},
|
||||
parser::{parse_color_hex, CustomAttribsInfoOwned},
|
||||
widget::{label::WidgetLabel, EventResult},
|
||||
};
|
||||
|
||||
use crate::state::AppState;
|
||||
@@ -24,11 +24,9 @@ use crate::state::AppState;
|
||||
use super::helper::{expand_env_vars, read_label_from_pipe};
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub(super) fn setup_custom_label<S>(
|
||||
pub(super) fn setup_custom_label<S: 'static>(
|
||||
layout: &mut Layout,
|
||||
attribs: &CustomAttribsInfoOwned,
|
||||
listeners: &mut EventListenerCollection<AppState, S>,
|
||||
listener_handles: &mut ListenerHandleVec,
|
||||
app: &AppState,
|
||||
) {
|
||||
let Some(source) = attribs.get_value("_source") else {
|
||||
@@ -51,7 +49,7 @@ pub(super) fn setup_custom_label<S>(
|
||||
}),
|
||||
carry_over: RefCell::new(None),
|
||||
};
|
||||
Box::new(move |common, data, _app, _| {
|
||||
Box::new(move |common, data, _, _| {
|
||||
shell_on_tick(&state, common, data);
|
||||
Ok(EventResult::Pass)
|
||||
})
|
||||
@@ -69,7 +67,7 @@ pub(super) fn setup_custom_label<S>(
|
||||
next_try: Instant::now(),
|
||||
}),
|
||||
};
|
||||
Box::new(move |common, data, _app, _| {
|
||||
Box::new(move |common, data, _, _| {
|
||||
pipe_on_tick(&state, common, data);
|
||||
Ok(EventResult::Pass)
|
||||
})
|
||||
@@ -165,7 +163,7 @@ pub(super) fn setup_custom_label<S>(
|
||||
format: format.into(),
|
||||
};
|
||||
|
||||
Box::new(move |common, data, _app, _| {
|
||||
Box::new(move |common, data, _, _| {
|
||||
clock_on_tick(&state, common, data);
|
||||
Ok(EventResult::Pass)
|
||||
})
|
||||
@@ -180,8 +178,7 @@ pub(super) fn setup_custom_label<S>(
|
||||
}
|
||||
};
|
||||
|
||||
listeners.register(
|
||||
listener_handles,
|
||||
layout.add_event_listener(
|
||||
attribs.widget_id,
|
||||
wgui::event::EventListenerKind::InternalStateChange,
|
||||
callback,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||
|
||||
use button::setup_custom_button;
|
||||
use glam::{Affine2, Vec2, vec2};
|
||||
use glam::{vec2, Affine2, Vec2};
|
||||
use label::setup_custom_label;
|
||||
use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView};
|
||||
use wgui::{
|
||||
assets::AssetPath,
|
||||
drawing,
|
||||
event::{
|
||||
Event as WguiEvent, EventListenerCollection, InternalStateChangeEvent, ListenerHandleVec,
|
||||
MouseButtonIndex, MouseDownEvent, MouseLeaveEvent, MouseMotionEvent, MouseUpEvent,
|
||||
MouseWheelEvent,
|
||||
Event as WguiEvent, EventCallback, EventListenerID, EventListenerKind,
|
||||
InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent,
|
||||
MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
|
||||
},
|
||||
layout::{Layout, LayoutParams, WidgetID},
|
||||
parser::ParserState,
|
||||
@@ -22,7 +22,7 @@ use crate::{
|
||||
backend::input::{Haptics, PointerHit, PointerMode},
|
||||
graphics::{CommandBuffers, ExtentExt},
|
||||
state::AppState,
|
||||
windowing::backend::{FrameMeta, OverlayBackend, ShouldRender, ui_transform},
|
||||
windowing::backend::{ui_transform, FrameMeta, OverlayBackend, ShouldRender},
|
||||
};
|
||||
|
||||
use super::{timer::GuiTimer, timestep::Timestep};
|
||||
@@ -40,35 +40,29 @@ pub struct GuiPanel<S> {
|
||||
pub layout: Layout,
|
||||
pub state: S,
|
||||
pub timers: Vec<GuiTimer>,
|
||||
pub listeners: EventListenerCollection<AppState, S>,
|
||||
pub listener_handles: ListenerHandleVec,
|
||||
pub parser_state: ParserState,
|
||||
interaction_transform: Option<Affine2>,
|
||||
context: WguiContext,
|
||||
timestep: Timestep,
|
||||
}
|
||||
|
||||
pub type OnCustomIdFunc<S> = Box<
|
||||
pub type OnCustomIdFunc = Box<
|
||||
dyn Fn(
|
||||
Rc<str>,
|
||||
WidgetID,
|
||||
&wgui::parser::ParseDocumentParams,
|
||||
&mut Layout,
|
||||
&mut ParserState,
|
||||
&mut EventListenerCollection<AppState, S>,
|
||||
) -> anyhow::Result<()>,
|
||||
>;
|
||||
|
||||
impl<S> GuiPanel<S> {
|
||||
impl<S: 'static> GuiPanel<S> {
|
||||
pub fn new_from_template(
|
||||
app: &mut AppState,
|
||||
path: &str,
|
||||
state: S,
|
||||
on_custom_id: Option<OnCustomIdFunc<S>>,
|
||||
on_custom_id: Option<OnCustomIdFunc>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let mut listeners = EventListenerCollection::<AppState, S>::default();
|
||||
let mut listener_handles = ListenerHandleVec::default();
|
||||
|
||||
let custom_elems = Rc::new(RefCell::new(vec![]));
|
||||
|
||||
let doc_params = wgui::parser::ParseDocumentParams {
|
||||
@@ -85,11 +79,8 @@ impl<S> GuiPanel<S> {
|
||||
},
|
||||
};
|
||||
|
||||
let (mut layout, mut parser_state) = wgui::parser::new_layout_from_assets(
|
||||
&mut listeners,
|
||||
&doc_params,
|
||||
&LayoutParams::default(),
|
||||
)?;
|
||||
let (mut layout, mut parser_state) =
|
||||
wgui::parser::new_layout_from_assets(&doc_params, &LayoutParams::default())?;
|
||||
|
||||
if let Some(on_element_id) = on_custom_id {
|
||||
let ids = parser_state.data.ids.clone(); // FIXME: copying all ids?
|
||||
@@ -101,7 +92,6 @@ impl<S> GuiPanel<S> {
|
||||
&doc_params,
|
||||
&mut layout,
|
||||
&mut parser_state,
|
||||
&mut listeners,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@@ -113,20 +103,14 @@ impl<S> GuiPanel<S> {
|
||||
.get_as::<WidgetLabel>(elem.widget_id)
|
||||
.is_some()
|
||||
{
|
||||
setup_custom_label(
|
||||
&mut layout,
|
||||
elem,
|
||||
&mut listeners,
|
||||
&mut listener_handles,
|
||||
app,
|
||||
);
|
||||
setup_custom_label::<S>(&mut layout, elem, app);
|
||||
} else if layout
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetRectangle>(elem.widget_id)
|
||||
.is_some()
|
||||
{
|
||||
setup_custom_button(elem, &mut listeners, &mut listener_handles, app);
|
||||
setup_custom_button::<S>(&mut layout, elem, app);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,10 +123,8 @@ impl<S> GuiPanel<S> {
|
||||
context,
|
||||
timestep,
|
||||
state,
|
||||
listener_handles,
|
||||
parser_state,
|
||||
timers: vec![],
|
||||
listeners,
|
||||
interaction_transform: None,
|
||||
})
|
||||
}
|
||||
@@ -159,9 +141,7 @@ impl<S> GuiPanel<S> {
|
||||
timestep,
|
||||
state,
|
||||
parser_state: ParserState::default(),
|
||||
listener_handles: ListenerHandleVec::default(),
|
||||
timers: vec![],
|
||||
listeners: EventListenerCollection::default(),
|
||||
interaction_transform: None,
|
||||
})
|
||||
}
|
||||
@@ -171,16 +151,22 @@ impl<S> GuiPanel<S> {
|
||||
}
|
||||
|
||||
pub fn push_event(&mut self, app: &mut AppState, event: &WguiEvent) {
|
||||
if let Err(e) = self
|
||||
.layout
|
||||
.push_event(&mut self.listeners, event, (app, &mut self.state))
|
||||
{
|
||||
if let Err(e) = self.layout.push_event(event, app, &mut self.state) {
|
||||
log::error!("Failed to push event: {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_event_listener(
|
||||
&mut self,
|
||||
widget_id: WidgetID,
|
||||
kind: EventListenerKind,
|
||||
callback: EventCallback<AppState, S>,
|
||||
) -> Option<EventListenerID> {
|
||||
self.layout.add_event_listener(widget_id, kind, callback)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> OverlayBackend for GuiPanel<S> {
|
||||
impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
||||
fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> {
|
||||
if self.layout.content_size.x * self.layout.content_size.y != 0.0 {
|
||||
self.update_layout()?;
|
||||
@@ -274,13 +260,13 @@ impl<S> OverlayBackend for GuiPanel<S> {
|
||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32) {
|
||||
self.layout
|
||||
.push_event(
|
||||
&mut self.listeners,
|
||||
&WguiEvent::MouseWheel(MouseWheelEvent {
|
||||
shift: vec2(delta_x, delta_y),
|
||||
pos: hit.uv * self.layout.content_size,
|
||||
device: hit.pointer,
|
||||
}),
|
||||
(app, &mut self.state),
|
||||
app,
|
||||
&mut self.state,
|
||||
)
|
||||
.unwrap(); // want panic
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use glam::{Affine3A, Mat4, Quat, Vec2, Vec3, vec2, vec3};
|
||||
use glam::{vec2, vec3, Affine3A, Mat4, Quat, Vec2, Vec3};
|
||||
use wgui::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
assets::AssetPath,
|
||||
@@ -11,24 +11,24 @@ use wgui::{
|
||||
renderer_vk::util,
|
||||
taffy::{self, prelude::length},
|
||||
widget::{
|
||||
EventResult,
|
||||
div::WidgetDiv,
|
||||
rectangle::{WidgetRectangle, WidgetRectangleParams},
|
||||
util::WLength,
|
||||
EventResult,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gui::panel::GuiPanel,
|
||||
state::AppState,
|
||||
subsystem::hid::{ALT, CTRL, META, SHIFT, SUPER, XkbKeymap},
|
||||
subsystem::hid::{XkbKeymap, ALT, CTRL, META, SHIFT, SUPER},
|
||||
windowing::window::{OverlayWindowConfig, OverlayWindowState, Positioning},
|
||||
};
|
||||
|
||||
use super::{
|
||||
KEYBOARD_NAME, KeyButtonData, KeyState, KeyboardBackend, KeyboardState, handle_press,
|
||||
handle_release,
|
||||
handle_press, handle_release,
|
||||
layout::{self, AltModifier, KeyCapType},
|
||||
KeyButtonData, KeyState, KeyboardBackend, KeyboardState, KEYBOARD_NAME,
|
||||
};
|
||||
|
||||
const BACKGROUND_PADDING: f32 = 4.;
|
||||
@@ -81,11 +81,8 @@ pub fn create_keyboard(
|
||||
extra: Default::default(),
|
||||
};
|
||||
|
||||
let (_, mut gui_state_key) = wgui::parser::new_layout_from_assets(
|
||||
&mut panel.listeners,
|
||||
&parse_doc_params,
|
||||
&LayoutParams::default(),
|
||||
)?;
|
||||
let (_, mut gui_state_key) =
|
||||
wgui::parser::new_layout_from_assets(&parse_doc_params, &LayoutParams::default())?;
|
||||
|
||||
for row in 0..layout.key_sizes.len() {
|
||||
let (div, _) = panel.layout.add_child(
|
||||
@@ -167,7 +164,6 @@ pub fn create_keyboard(
|
||||
&parse_doc_params,
|
||||
&template_key,
|
||||
&mut panel.layout,
|
||||
&mut panel.listeners,
|
||||
div.id,
|
||||
params,
|
||||
)?;
|
||||
@@ -190,8 +186,7 @@ pub fn create_keyboard(
|
||||
})
|
||||
};
|
||||
|
||||
panel.listeners.register(
|
||||
&mut panel.listener_handles,
|
||||
panel.add_event_listener(
|
||||
widget_id,
|
||||
EventListenerKind::MouseEnter,
|
||||
Box::new({
|
||||
@@ -203,8 +198,7 @@ pub fn create_keyboard(
|
||||
}
|
||||
}),
|
||||
);
|
||||
panel.listeners.register(
|
||||
&mut panel.listener_handles,
|
||||
panel.add_event_listener(
|
||||
widget_id,
|
||||
EventListenerKind::MouseLeave,
|
||||
Box::new({
|
||||
@@ -216,8 +210,7 @@ pub fn create_keyboard(
|
||||
}
|
||||
}),
|
||||
);
|
||||
panel.listeners.register(
|
||||
&mut panel.listener_handles,
|
||||
panel.add_event_listener(
|
||||
widget_id,
|
||||
EventListenerKind::MousePress,
|
||||
Box::new({
|
||||
@@ -233,8 +226,7 @@ pub fn create_keyboard(
|
||||
}
|
||||
}),
|
||||
);
|
||||
panel.listeners.register(
|
||||
&mut panel.listener_handles,
|
||||
panel.add_event_listener(
|
||||
widget_id,
|
||||
EventListenerKind::MouseRelease,
|
||||
Box::new({
|
||||
@@ -249,8 +241,7 @@ pub fn create_keyboard(
|
||||
);
|
||||
|
||||
if let Some(modifier) = my_modifier {
|
||||
panel.listeners.register(
|
||||
&mut panel.listener_handles,
|
||||
panel.add_event_listener(
|
||||
widget_id,
|
||||
EventListenerKind::InternalStateChange,
|
||||
Box::new({
|
||||
|
||||
@@ -23,7 +23,7 @@ pub fn create_watch(app: &mut AppState, num_sets: usize) -> anyhow::Result<Overl
|
||||
"gui/watch.xml",
|
||||
state,
|
||||
Some(Box::new(
|
||||
move |id, widget, doc_params, layout, parser_state, listeners| {
|
||||
move |id, widget, doc_params, layout, parser_state| {
|
||||
if &*id != "sets" {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -32,9 +32,7 @@ pub fn create_watch(app: &mut AppState, num_sets: usize) -> anyhow::Result<Overl
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert("display".into(), (idx + 1).to_string().into());
|
||||
params.insert("handle".into(), idx.to_string().into());
|
||||
parser_state.instantiate_template(
|
||||
doc_params, "Set", layout, listeners, widget, params,
|
||||
)?;
|
||||
parser_state.instantiate_template(doc_params, "Set", layout, widget, params)?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user