diff --git a/uidev/src/main.rs b/uidev/src/main.rs index eb29a3a..c1c39f6 100644 --- a/uidev/src/main.rs +++ b/uidev/src/main.rs @@ -19,7 +19,10 @@ use vulkano::{ sync::GpuFuture, }; use wgui::{ - event::{MouseButton, MouseDownEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent}, + event::{ + EventListenerCollection, MouseButton, MouseDownEvent, MouseMotionEvent, MouseUpEvent, + MouseWheelEvent, + }, gfx::WGfx, renderer_vk::{self}, }; @@ -29,7 +32,7 @@ use winit::{ keyboard::{KeyCode, PhysicalKey}, }; -use crate::testbed::{testbed_dashboard::TestbedDashboard, testbed_generic::TestbedGeneric}; +use crate::testbed::testbed_generic::TestbedGeneric; mod assets; mod profiler; @@ -53,11 +56,12 @@ fn init_logging() { .init(); } -fn load_testbed() -> anyhow::Result> { +fn load_testbed( + listeners: &mut EventListenerCollection<(), ()>, +) -> anyhow::Result> { let name = std::env::var("TESTBED").unwrap_or_default(); Ok(match name.as_str() { - "dashboard" => Box::new(TestbedDashboard::new()?), - "" => Box::new(TestbedGeneric::new()?), + "" => Box::new(TestbedGeneric::new(listeners)?), _ => Box::new(TestbedAny::new(&name)?), }) } @@ -92,7 +96,9 @@ fn main() -> Result<(), Box> { let mut scale = window.scale_factor() as f32; - let mut testbed = load_testbed()?; + let mut listeners = EventListenerCollection::default(); + + let mut testbed = load_testbed(&mut listeners)?; let mut mouse = Vec2::ZERO; @@ -119,19 +125,27 @@ fn main() -> Result<(), Box> { } => match delta { MouseScrollDelta::LineDelta(x, y) => testbed .layout() - .push_event(&wgui::event::Event::MouseWheel(MouseWheelEvent { - shift: Vec2::new(x, y), - pos: mouse / scale, - device: 0, - })) + .push_event( + &listeners, + &wgui::event::Event::MouseWheel(MouseWheelEvent { + shift: Vec2::new(x, y), + pos: mouse / scale, + device: 0, + }), + (&mut (), &mut ()), + ) .unwrap(), MouseScrollDelta::PixelDelta(pos) => testbed .layout() - .push_event(&wgui::event::Event::MouseWheel(MouseWheelEvent { - shift: Vec2::new(pos.x as f32 / 5.0, pos.y as f32 / 5.0), - pos: mouse / scale, - device: 0, - })) + .push_event( + &listeners, + &wgui::event::Event::MouseWheel(MouseWheelEvent { + shift: Vec2::new(pos.x as f32 / 5.0, pos.y as f32 / 5.0), + pos: mouse / scale, + device: 0, + }), + (&mut (), &mut ()), + ) .unwrap(), }, Event::WindowEvent { @@ -142,20 +156,28 @@ fn main() -> Result<(), Box> { if matches!(state, winit::event::ElementState::Pressed) { testbed .layout() - .push_event(&wgui::event::Event::MouseDown(MouseDownEvent { - pos: mouse / scale, - button: MouseButton::Left, - device: 0, - })) + .push_event( + &listeners, + &wgui::event::Event::MouseDown(MouseDownEvent { + pos: mouse / scale, + button: MouseButton::Left, + device: 0, + }), + (&mut (), &mut ()), + ) .unwrap(); } else { testbed .layout() - .push_event(&wgui::event::Event::MouseUp(MouseUpEvent { - pos: mouse / scale, - button: MouseButton::Left, - device: 0, - })) + .push_event( + &listeners, + &wgui::event::Event::MouseUp(MouseUpEvent { + pos: mouse / scale, + button: MouseButton::Left, + device: 0, + }), + (&mut (), &mut ()), + ) .unwrap(); } } @@ -167,10 +189,14 @@ fn main() -> Result<(), Box> { mouse = vec2(position.x as _, position.y as _); testbed .layout() - .push_event(&wgui::event::Event::MouseMotion(MouseMotionEvent { - pos: mouse / scale, - device: 0, - })) + .push_event( + &listeners, + &wgui::event::Event::MouseMotion(MouseMotionEvent { + pos: mouse / scale, + device: 0, + }), + (&mut (), &mut ()), + ) .unwrap(); } Event::WindowEvent { diff --git a/uidev/src/testbed/mod.rs b/uidev/src/testbed/mod.rs index cdf6c23..588f573 100644 --- a/uidev/src/testbed/mod.rs +++ b/uidev/src/testbed/mod.rs @@ -1,10 +1,9 @@ use wgui::layout::Layout; pub mod testbed_any; -pub mod testbed_dashboard; pub mod testbed_generic; pub trait Testbed { - fn update(&mut self, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()>; - fn layout(&mut self) -> &mut Layout; + fn update(&mut self, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()>; + fn layout(&mut self) -> &mut Layout; } diff --git a/uidev/src/testbed/testbed_any.rs b/uidev/src/testbed/testbed_any.rs index 06cc77e..12d3ad2 100644 --- a/uidev/src/testbed/testbed_any.rs +++ b/uidev/src/testbed/testbed_any.rs @@ -3,26 +3,26 @@ use glam::Vec2; use wgui::layout::Layout; pub struct TestbedAny { - pub layout: Layout, + pub layout: Layout, } impl TestbedAny { - pub fn new(name: &str) -> anyhow::Result { - let path = format!("gui/{name}.xml"); - let (layout, _state) = wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), &path)?; - Ok(Self { layout }) - } + pub fn new(name: &str) -> anyhow::Result { + let path = format!("gui/{name}.xml"); + let (layout, _state) = + wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), &path)?; + Ok(Self { layout }) + } } impl Testbed for TestbedAny { - fn update(&mut self, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()> { - self - .layout - .update(Vec2::new(width, height), timestep_alpha)?; - Ok(()) - } + fn update(&mut self, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()> { + self.layout + .update(Vec2::new(width, height), timestep_alpha)?; + Ok(()) + } - fn layout(&mut self) -> &mut Layout { - &mut self.layout - } + fn layout(&mut self) -> &mut Layout { + &mut self.layout + } } diff --git a/uidev/src/testbed/testbed_dashboard.rs b/uidev/src/testbed/testbed_dashboard.rs deleted file mode 100644 index 207f4e5..0000000 --- a/uidev/src/testbed/testbed_dashboard.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::{assets, testbed::Testbed}; -use glam::Vec2; -use wgui::layout::Layout; - -pub struct TestbedDashboard { - pub layout: Layout, -} - -impl TestbedDashboard { - pub fn new() -> anyhow::Result { - const XML_PATH: &str = "gui/dashboard.xml"; - let (layout, _state) = - wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), XML_PATH)?; - Ok(Self { layout }) - } -} - -impl Testbed for TestbedDashboard { - fn update(&mut self, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()> { - self - .layout - .update(Vec2::new(width, height), timestep_alpha)?; - Ok(()) - } - - fn layout(&mut self) -> &mut Layout { - &mut self.layout - } -} diff --git a/uidev/src/testbed/testbed_generic.rs b/uidev/src/testbed/testbed_generic.rs index ce71aab..ff40436 100644 --- a/uidev/src/testbed/testbed_generic.rs +++ b/uidev/src/testbed/testbed_generic.rs @@ -2,98 +2,98 @@ use std::{cell::RefCell, rc::Rc}; use glam::{Mat4, Vec2}; use wgui::{ - drawing::{self}, - event::EventListener, - layout::{Layout, WidgetID}, - renderer_vk::text::TextStyle, + drawing::{self}, + event::{EventListenerCollection, EventListenerKind}, + layout::{Layout, WidgetID}, + renderer_vk::text::TextStyle, }; use crate::{assets, testbed::Testbed}; pub struct TestbedGeneric { - pub layout: Layout, - rot: f32, - widget_id: Rc>>, + pub layout: Layout, + rot: f32, + widget_id: Rc>>, } impl TestbedGeneric { - pub fn new() -> anyhow::Result { - const XML_PATH: &str = "gui/testbed.xml"; + pub fn new(listeners: &mut EventListenerCollection<(), ()>) -> anyhow::Result { + const XML_PATH: &str = "gui/testbed.xml"; - let (mut layout, res) = - wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), XML_PATH)?; + let (mut layout, res) = + wgui::parser::new_layout_from_assets(Box::new(assets::Asset {}), XML_PATH)?; - use wgui::components::button; - let my_div_parent = res.require_by_id("my_div_parent")?; - // create some buttons for testing - for i in 0..4 { - let n = i as f32 / 4.0; - button::construct( - &mut layout, - my_div_parent, - button::Params { - text: "I'm a button!", - color: drawing::Color::new(1.0 - n, n * n, n, 1.0), - ..Default::default() - }, - )?; - } + use wgui::components::button; + let my_div_parent = res.require_by_id("my_div_parent")?; + // create some buttons for testing + for i in 0..4 { + let n = i as f32 / 4.0; + button::construct( + &mut layout, + my_div_parent, + button::Params { + text: "I'm a button!", + color: drawing::Color::new(1.0 - n, n * n, n, 1.0), + ..Default::default() + }, + )?; + } - let button = button::construct( - &mut layout, - my_div_parent, - button::Params { - text: "Click me!!", - color: drawing::Color::new(0.2, 0.2, 0.2, 1.0), - size: Vec2::new(256.0, 64.0), - text_style: TextStyle { - size: Some(30.0), - ..Default::default() - }, - }, - )?; + let button = button::construct( + &mut layout, + my_div_parent, + button::Params { + text: "Click me!!", + color: drawing::Color::new(0.2, 0.2, 0.2, 1.0), + size: Vec2::new(256.0, 64.0), + text_style: TextStyle { + size: Some(30.0), + ..Default::default() + }, + }, + )?; - let widget_id = Rc::new(RefCell::new(None)); + let widget_id = Rc::new(RefCell::new(None)); - let wid = widget_id.clone(); - layout.add_event_listener( - button.body, - EventListener::MouseRelease(Box::new(move |data, _| { - button.set_text(data, "Congratulations!"); - *wid.borrow_mut() = Some(data.widget_id); - })), - ); + let wid = widget_id.clone(); + listeners.add( + button.body, + EventListenerKind::MouseRelease, + Box::new(move |data, (), ()| { + button.set_text(data, "Congratulations!"); + *wid.borrow_mut() = Some(data.widget_id); + }), + ); - Ok(Self { - layout, - rot: 0.0, - widget_id, - }) - } + Ok(Self { + layout, + rot: 0.0, + widget_id, + }) + } } impl Testbed for TestbedGeneric { - fn update(&mut self, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()> { - if let Some(widget_id) = *self.widget_id.borrow() { - self.rot += 0.01; + fn update(&mut self, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()> { + if let Some(widget_id) = *self.widget_id.borrow() { + self.rot += 0.01; - let a = self.layout.widget_map.get(widget_id).unwrap(); - let mut widget = a.lock().unwrap(); - widget.data.transform = Mat4::IDENTITY - * Mat4::from_rotation_y(-self.rot) - * Mat4::from_rotation_x(self.rot * 0.25) - * Mat4::from_rotation_z(-self.rot * 0.1); + let a = self.layout.widget_map.get(widget_id).unwrap(); + let mut widget = a.lock().unwrap(); + widget.data.transform = Mat4::IDENTITY + * Mat4::from_rotation_y(-self.rot) + * Mat4::from_rotation_x(self.rot * 0.25) + * Mat4::from_rotation_z(-self.rot * 0.1); - self.layout.needs_redraw = true; - } + self.layout.needs_redraw = true; + } - self - .layout - .update(Vec2::new(width, height), timestep_alpha)?; - Ok(()) - } + self.layout + .update(Vec2::new(width, height), timestep_alpha)?; + Ok(()) + } - fn layout(&mut self) -> &mut Layout { - &mut self.layout - } -} \ No newline at end of file + fn layout(&mut self) -> &mut Layout { + &mut self.layout + } +} diff --git a/wgui/src/components/button.rs b/wgui/src/components/button.rs index 9bf9be7..a6eb0ac 100644 --- a/wgui/src/components/button.rs +++ b/wgui/src/components/button.rs @@ -6,7 +6,7 @@ use taffy::{AlignItems, JustifyContent, prelude::length}; use crate::{ animation::{Animation, AnimationEasing}, drawing::{self, Color}, - event::{EventListener, WidgetCallback}, + event::WidgetCallback, layout::{Layout, WidgetID}, renderer_vk::text::{FontWeight, TextStyle}, widget::{ @@ -135,8 +135,6 @@ pub fn construct( }, )?; - let mut widget = layout.widget_map.get(rect_id).unwrap().lock().unwrap(); - let button = Arc::new(Button { body: rect_id, color: params.color, @@ -144,25 +142,9 @@ pub fn construct( text_node, }); - // Highlight background on mouse enter - { - let button = button.clone(); - widget.add_event_listener(EventListener::MouseEnter(Box::new(move |data, _| { - data - .animations - .push(anim_hover_in(button.clone(), data.widget_id)); - }))); - } + //TODO: Highlight background on mouse enter - // Bring back old color on mouse leave - { - let button = button.clone(); - widget.add_event_listener(EventListener::MouseLeave(Box::new(move |data, _| { - data - .animations - .push(anim_hover_out(button.clone(), data.widget_id)); - }))); - } + //TODO: Bring back old color on mouse leave Ok(button) -} \ No newline at end of file +} diff --git a/wgui/src/event.rs b/wgui/src/event.rs index 7f67b1c..35017a1 100644 --- a/wgui/src/event.rs +++ b/wgui/src/event.rs @@ -1,4 +1,5 @@ use glam::Vec2; +use slotmap::SecondaryMap; use crate::{ animation, @@ -105,6 +106,7 @@ pub struct CallbackData<'a> { pub dirty_nodes: &'a mut Vec, pub needs_redraw: bool, pub trigger_haptics: bool, + pub metadata: CallbackMetadata, } impl<'a> WidgetCallback<'a> for CallbackData<'a> { @@ -121,16 +123,70 @@ impl<'a> WidgetCallback<'a> for CallbackData<'a> { } } -pub type MouseEnterCallback = Box; -pub type MouseLeaveCallback = Box; -pub type MousePressCallback = Box; -pub type MouseReleaseCallback = Box; -pub type InternalStateChangeCallback = Box; - -pub enum EventListener { - MouseEnter(MouseEnterCallback), - MouseLeave(MouseLeaveCallback), - MousePress(MousePressCallback), - MouseRelease(MouseReleaseCallback), - InternalStateChange(InternalStateChangeCallback), +pub enum CallbackMetadata { + None, + MouseButton(MouseButton), + Custom(usize), +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum EventListenerKind { + MousePress, + MouseRelease, + MouseEnter, + MouseLeave, + InternalStateChange, +} + +pub type EventCallback = Box; + +pub struct EventListener { + pub kind: EventListenerKind, + pub callback: EventCallback, +} + +impl EventListener { + pub fn callback_for_kind( + &self, + kind: EventListenerKind, + ) -> Option<&impl Fn(&mut CallbackData, &mut U1, &mut U2)> { + if self.kind == kind { + Some(&self.callback) + } else { + None + } + } +} + +pub struct EventListenerCollection { + map: SecondaryMap>>, +} + +// derive only works if generics also implement Default +impl Default for EventListenerCollection { + fn default() -> Self { + Self { + map: SecondaryMap::default(), + } + } +} + +impl EventListenerCollection { + pub fn add( + &mut self, + widget_id: WidgetID, + kind: EventListenerKind, + callback: EventCallback, + ) { + let new_item = EventListener { kind, callback }; + if let Some(vec) = self.map.get_mut(widget_id) { + vec.push(new_item); + } else { + self.map.insert(widget_id, vec![new_item]); + } + } + + pub fn get(&self, widget_id: WidgetID) -> Option<&[EventListener]> { + self.map.get(widget_id).map(|v| v.as_slice()) + } } diff --git a/wgui/src/layout.rs b/wgui/src/layout.rs index 8017638..92f0114 100644 --- a/wgui/src/layout.rs +++ b/wgui/src/layout.rs @@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex}; use crate::{ animation::{self, Animations}, assets::AssetProvider, - event::{self, EventListener}, + event::{self, EventListenerCollection}, transform_stack::{Transform, TransformStack}, widget::{self, EventParams, WidgetState, div::Div}, }; @@ -89,26 +89,30 @@ impl Layout { ) } - fn push_event_children( + fn push_event_children( &self, + listeners: &EventListenerCollection, parent_node_id: taffy::NodeId, state: &mut PushEventState, event: &event::Event, dirty_nodes: &mut Vec, + user_data: &mut (&mut U1, &mut U2), ) -> anyhow::Result<()> { for child_id in self.tree.child_ids(parent_node_id) { - self.push_event_widget(state, child_id, event, dirty_nodes)?; + self.push_event_widget(listeners, state, child_id, event, dirty_nodes, user_data)?; } Ok(()) } - fn push_event_widget( + fn push_event_widget( &self, + listeners: &EventListenerCollection, state: &mut PushEventState, node_id: taffy::NodeId, event: &event::Event, dirty_nodes: &mut Vec, + user_data: &mut (&mut U1, &mut U2), ) -> anyhow::Result<()> { let l = self.tree.layout(node_id)?; let Some(widget_id) = self.tree.get_node_context(node_id).cloned() else { @@ -134,38 +138,42 @@ impl Layout { let mut iter_children = true; - match widget.process_event( - widget_id, - node_id, - event, - &mut EventParams { - transform_stack: state.transform_stack, - widgets: &self.widget_map, - tree: &self.tree, - animations: state.animations, - needs_redraw: &mut state.needs_redraw, - trigger_haptics: &mut state.trigger_haptics, + if let Some(listeners) = listeners.get(widget_id) { + match widget.process_event( + widget_id, + listeners, node_id, - style, - taffy_layout: l, - dirty_nodes, - }, - ) { - widget::EventResult::Pass => { - // go on - } - widget::EventResult::Consumed => { - iter_children = false; - } - widget::EventResult::Outside => { - iter_children = false; + event, + user_data, + &mut EventParams { + transform_stack: state.transform_stack, + widgets: &self.widget_map, + tree: &self.tree, + animations: state.animations, + needs_redraw: &mut state.needs_redraw, + trigger_haptics: &mut state.trigger_haptics, + node_id, + style, + taffy_layout: l, + dirty_nodes, + }, + ) { + widget::EventResult::Pass => { + // go on + } + widget::EventResult::Consumed => { + iter_children = false; + } + widget::EventResult::Outside => { + iter_children = false; + } } } drop(widget); // free mutex if iter_children { - self.push_event_children(node_id, state, event, dirty_nodes)?; + self.push_event_children(listeners, node_id, state, event, dirty_nodes, user_data)?; } state.transform_stack.pop(); @@ -191,7 +199,12 @@ impl Layout { } } - pub fn push_event(&mut self, event: &event::Event) -> anyhow::Result<()> { + pub fn push_event( + &mut self, + listeners: &EventListenerCollection, + event: &event::Event, + mut user_data: (&mut U1, &mut U2), + ) -> anyhow::Result<()> { let mut transform_stack = TransformStack::new(); let mut animations_to_add = Vec::::new(); let mut dirty_nodes = Vec::new(); @@ -203,7 +216,14 @@ impl Layout { trigger_haptics: false, }; - self.push_event_widget(&mut state, self.root_node, event, &mut dirty_nodes)?; + self.push_event_widget( + listeners, + &mut state, + self.root_node, + event, + &mut dirty_nodes, + &mut user_data, + )?; for node in dirty_nodes { self.tree.mark_dirty(node)?; @@ -339,13 +359,4 @@ impl Layout { Ok(()) } - - // helper function - pub fn add_event_listener(&self, widget_id: WidgetID, listener: EventListener) { - let Some(widget) = self.widget_map.get(widget_id) else { - debug_assert!(false); - return; - }; - widget.lock().unwrap().add_event_listener(listener); - } -} +} \ No newline at end of file diff --git a/wgui/src/widget/mod.rs b/wgui/src/widget/mod.rs index 4ebb555..71a8a86 100644 --- a/wgui/src/widget/mod.rs +++ b/wgui/src/widget/mod.rs @@ -5,7 +5,9 @@ use crate::{ animation, any::AnyTrait, drawing, - event::{CallbackData, Event, EventListener, MouseWheelEvent}, + event::{ + CallbackData, CallbackMetadata, Event, EventListener, EventListenerKind, MouseWheelEvent, + }, layout::{Layout, WidgetID, WidgetMap}, transform_stack::TransformStack, }; @@ -70,7 +72,6 @@ impl WidgetData { pub struct WidgetState { pub data: WidgetData, pub obj: Box, - pub event_listeners: Vec, } impl WidgetState { @@ -88,7 +89,6 @@ impl WidgetState { scrolling: Vec2::default(), transform: glam::Mat4::IDENTITY, }, - event_listeners: Vec::new(), obj, }) } @@ -182,9 +182,9 @@ impl dyn WidgetObj { } macro_rules! call_event { - ($self:ident, $widget_id:ident, $node_id:ident, $params:ident, $ev:ident, $cb_arg:expr) => { - for listener in &$self.event_listeners { - if let EventListener::$ev(callback) = listener { + ($self:ident, $listeners:ident, $widget_id:ident, $node_id:ident, $params:ident, $kind:ident, $user_data:expr, $metadata:expr) => { + for listener in $listeners { + if let Some(callback) = listener.callback_for_kind(EventListenerKind::$kind) { let mut data = CallbackData { obj: $self.obj.as_mut(), widget_data: &mut $self.data, @@ -195,8 +195,9 @@ macro_rules! call_event { $node_id, needs_redraw: false, trigger_haptics: false, + metadata: $metadata, }; - callback(&mut data, $cb_arg); + callback(&mut data, $user_data.0, $user_data.1); if data.trigger_haptics { *$params.trigger_haptics = true; } @@ -209,10 +210,6 @@ macro_rules! call_event { } impl WidgetState { - pub fn add_event_listener(&mut self, listener: EventListener) { - self.event_listeners.push(listener); - } - pub fn get_scroll_shift(&self, info: &ScrollbarInfo, l: &taffy::Layout) -> Vec2 { Vec2::new( (info.content_size.x - l.content_box_width()) * self.data.scrolling.x, @@ -322,11 +319,13 @@ impl WidgetState { true } - pub fn process_event( + pub fn process_event( &mut self, widget_id: WidgetID, + listeners: &[EventListener], node_id: taffy::NodeId, event: &Event, + user_data: &mut (&mut U1, &mut U2), params: &mut EventParams, ) -> EventResult { let hovered = event.test_mouse_within_transform(params.transform_stack.get()); @@ -334,12 +333,30 @@ impl WidgetState { match &event { Event::MouseDown(e) => { if hovered && self.data.set_device_pressed(e.device, true) { - call_event!(self, widget_id, node_id, params, MousePress, e.button); + call_event!( + self, + listeners, + widget_id, + node_id, + params, + MousePress, + user_data, + CallbackMetadata::MouseButton(e.button) + ); } } Event::MouseUp(e) => { if self.data.set_device_pressed(e.device, false) { - call_event!(self, widget_id, node_id, params, MouseRelease, e.button); + call_event!( + self, + listeners, + widget_id, + node_id, + params, + MouseRelease, + user_data, + CallbackMetadata::MouseButton(e.button) + ); } } Event::MouseWheel(e) => { @@ -350,28 +367,57 @@ impl WidgetState { Event::MouseMotion(e) => { if self.data.set_device_hovered(e.device, hovered) { if self.data.is_hovered() { - call_event!(self, widget_id, node_id, params, MouseEnter, ()); + call_event!( + self, + listeners, + widget_id, + node_id, + params, + MouseEnter, + user_data, + CallbackMetadata::None + ); } else { - call_event!(self, widget_id, node_id, params, MouseLeave, ()); + call_event!( + self, + listeners, + widget_id, + node_id, + params, + MouseLeave, + user_data, + CallbackMetadata::None + ); } } } Event::MouseLeave(e) => { if self.data.set_device_hovered(e.device, false) { - call_event!(self, widget_id, node_id, params, MouseLeave, ()); + call_event!( + self, + listeners, + widget_id, + node_id, + params, + MouseLeave, + user_data, + CallbackMetadata::None + ); } } Event::InternalStateChange(e) => { call_event!( self, + listeners, widget_id, node_id, params, InternalStateChange, - e.metadata + user_data, + CallbackMetadata::Custom(e.metadata) ); } } EventResult::Pass } -} +} \ No newline at end of file diff --git a/wgui/src/widget/text.rs b/wgui/src/widget/text.rs index cd848e6..e792393 100644 --- a/wgui/src/widget/text.rs +++ b/wgui/src/widget/text.rs @@ -50,6 +50,10 @@ impl TextLabel { } pub fn set_text(&mut self, text: &str) { + if self.params.content.as_str() == text { + return; + } + self.params.content = String::from(text); let attrs = Attrs::from(&self.params.style); let mut font_system = FONT_SYSTEM.lock().unwrap(); // safe unwrap @@ -63,6 +67,10 @@ impl TextLabel { self.params.style.align.map(|a| a.into()), ); } + + pub fn get_text(&self) -> &str { + &self.params.content + } } impl WidgetObj for TextLabel { diff --git a/wlx-overlay-s/src/assets/gui/watch.xml b/wlx-overlay-s/src/assets/gui/watch.xml index 54ce61d..8b8f48f 100644 --- a/wlx-overlay-s/src/assets/gui/watch.xml +++ b/wlx-overlay-s/src/assets/gui/watch.xml @@ -1,6 +1,4 @@ - - @@ -33,7 +31,7 @@
-