events refactor

This commit is contained in:
galister
2025-10-12 17:30:30 +09:00
parent fbe1d5b09e
commit 90eed4558f
30 changed files with 420 additions and 616 deletions

View File

@@ -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 });

View File

@@ -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 });

View File

@@ -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 {

View File

@@ -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 });

View File

@@ -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,

View File

@@ -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]));
}
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<EventListener> {
self.inner.remove(event_listener_id)
}
}

View File

@@ -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(())
}

View File

@@ -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],
@@ -79,4 +79,4 @@ pub fn parse_component_button<'a, U1, U2>(
parse_children(file, ctx, node, widget.id)?;
Ok(widget.id)
}
}

View File

@@ -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> {
@@ -49,4 +48,4 @@ pub fn parse_component_checkbox<U1, U2>(
process_component(ctx, Component(component), widget.id, attribs);
Ok(widget.id)
}
}

View File

@@ -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 {
@@ -51,4 +50,4 @@ pub fn parse_component_slider<U1, U2>(
process_component(ctx, Component(component), widget.id, attribs);
Ok(widget.id)
}
}

View File

@@ -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<()> {
@@ -1100,4 +1073,4 @@ fn parse_document_root<U1, U2>(
}
Ok(())
}
}

View File

@@ -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],
@@ -19,4 +19,4 @@ pub fn parse_widget_div<'a, U1, U2>(
parse_children(file, ctx, node, widget.id)?;
Ok(widget.id)
}
}

View File

@@ -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],
@@ -47,4 +47,4 @@ pub fn parse_widget_label<'a, U1, U2>(
parse_children(file, ctx, node, widget.id)?;
Ok(widget.id)
}
}

View File

@@ -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],
@@ -63,4 +63,4 @@ pub fn parse_widget_rectangle<'a, U1, U2>(
parse_children(file, ctx, node, widget.id)?;
Ok(widget.id)
}
}

View File

@@ -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],
@@ -63,4 +63,4 @@ pub fn parse_widget_sprite<'a, U1, U2>(
parse_children(file, ctx, node, widget.id)?;
Ok(widget.id)
}
}

View File

@@ -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,26 +211,23 @@ 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) {
let mut data = CallbackData {
obj: $self.obj.as_mut(),
widget_data: &mut $self.data,
$widget_id,
$node_id,
metadata: $metadata,
};
($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,
$widget_id,
$node_id,
metadata: $metadata,
};
let mut common = CallbackDataCommon {
state: $params.state,
alterables: $params.alterables,
};
let result = callback(&mut common, &mut data, $user_data.0, $user_data.1)?;
if result == EventResult::Consumed {
return Ok(EventResult::Consumed);
}
let mut common = CallbackDataCommon {
state: $params.state,
alterables: $params.alterables,
};
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,
user_data,
CallbackMetadata::None
);
} else {
call_event!(
self,
listeners,
widget_id,
node_id,
params,
MouseLeave,
user_data,
CallbackMetadata::None
);
}
if hover_state_changed {
if self.data.is_hovered() {
call_event!(
self,
widget_id,
node_id,
params,
MouseEnter,
U1,
U2,
user_data,
CallbackMetadata::None
);
} else {
call_event!(
self,
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,
user_data,
CallbackMetadata::Custom(e.metadata)
);
}
call_event!(
self,
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,
}

View File

@@ -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,
)?;