diff --git a/Cargo.toml b/Cargo.toml index 6ac4e19..449c1c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,14 @@ +[profile.dev] +opt-level = 0 +debug = true +strip = "none" +debug-assertions = true +incremental = true + +[profile.release-with-debug] +inherits = "release" +debug = true + [workspace] members = ["wgui", "wgui/uidev-vk", "wlx-overlay-s", "wlx-capture"] resolver = "3" diff --git a/wgui/Cargo.toml b/wgui/Cargo.toml index ef76d0d..3f2aa4e 100644 --- a/wgui/Cargo.toml +++ b/wgui/Cargo.toml @@ -27,10 +27,3 @@ smallvec = "1.15.0" taffy = "0.8.1" vulkano = { workspace = true } vulkano-shaders = { workspace = true } - -[profile.dev] -opt-level = 0 -debug = true -strip = "none" -debug-assertions = true -incremental = true diff --git a/wgui/src/event.rs b/wgui/src/event.rs index 01c0aa7..b48647f 100644 --- a/wgui/src/event.rs +++ b/wgui/src/event.rs @@ -7,26 +7,44 @@ use crate::{ widget::{WidgetData, WidgetObj}, }; -// TODO: mouse index +#[derive(Debug, Clone, Copy)] +pub enum MouseButton { + Left, + Right, + Middle, +} + pub struct MouseDownEvent { pub pos: Vec2, + pub button: MouseButton, + pub device: usize, +} + +pub struct MouseLeaveEvent { + pub device: usize, } pub struct MouseMotionEvent { pub pos: Vec2, + pub device: usize, } pub struct MouseUpEvent { pub pos: Vec2, + pub button: MouseButton, + pub device: usize, } pub struct MouseWheelEvent { pub pos: Vec2, pub shift: Vec2, + pub device: usize, } pub enum Event { + InternalStateChange, MouseDown(MouseDownEvent), + MouseLeave(MouseLeaveEvent), MouseMotion(MouseMotionEvent), MouseUp(MouseUpEvent), MouseWheel(MouseWheelEvent), @@ -46,6 +64,7 @@ impl Event { Event::MouseMotion(evt) => self.test_transform_pos(transform, &evt.pos), Event::MouseUp(evt) => self.test_transform_pos(transform, &evt.pos), Event::MouseWheel(evt) => self.test_transform_pos(transform, &evt.pos), + _ => false, } } } @@ -99,10 +118,14 @@ impl<'a> WidgetCallback<'a> for CallbackData<'a> { pub type MouseEnterCallback = Box; pub type MouseLeaveCallback = Box; -pub type MouseClickCallback = Box; +pub type MousePressCallback = Box; +pub type MouseReleaseCallback = Box; +pub type InternalStateChangeCallback = Box; pub enum EventListener { MouseEnter(MouseEnterCallback), MouseLeave(MouseLeaveCallback), - MouseClick(MouseClickCallback), + MousePress(MousePressCallback), + MouseRelease(MouseReleaseCallback), + InternalStateChange(InternalStateChangeCallback), } diff --git a/wgui/src/parser/mod.rs b/wgui/src/parser/mod.rs index 04e73f6..9ec1665 100644 --- a/wgui/src/parser/mod.rs +++ b/wgui/src/parser/mod.rs @@ -57,7 +57,7 @@ impl ParserResult { } pub fn process_template( - &self, + &mut self, template_name: &str, layout: &mut Layout, widget_id: WidgetID, @@ -90,6 +90,10 @@ impl ParserResult { widget_id, )?; + ctx.ids.into_iter().for_each(|(id, key)| { + self.ids.insert(id, key); + }); + Ok(()) } } diff --git a/wgui/src/widget/mod.rs b/wgui/src/widget/mod.rs index b240bc5..4181375 100644 --- a/wgui/src/widget/mod.rs +++ b/wgui/src/widget/mod.rs @@ -17,11 +17,56 @@ pub mod text; pub mod util; pub struct WidgetData { - pub hovered: bool, - pub pressed: bool, + hovered: usize, + pressed: usize, pub scrolling: Vec2, // normalized, 0.0-1.0. Not used in case if overflow != scroll pub transform: glam::Mat4, } + +impl WidgetData { + pub fn set_device_pressed(&mut self, device: usize, pressed: bool) -> bool { + let bit = 1 << device; + let state_changed; + if pressed { + state_changed = self.pressed == 0; + self.pressed |= bit; + } else { + state_changed = self.pressed == bit; + self.pressed &= !bit; + } + state_changed + } + + pub fn set_device_hovered(&mut self, device: usize, hovered: bool) -> bool { + let bit = 1 << device; + let state_changed; + if hovered { + state_changed = self.hovered == 0; + self.hovered |= bit; + } else { + state_changed = self.hovered == bit; + self.hovered &= !bit; + } + state_changed + } + + pub fn get_pressed(&self, device: usize) -> bool { + self.pressed & (1 << device) != 0 + } + + pub fn get_hovered(&self, device: usize) -> bool { + self.hovered & (1 << device) != 0 + } + + pub fn is_pressed(&self) -> bool { + self.pressed != 0 + } + + pub fn is_hovered(&self) -> bool { + self.hovered != 0 + } +} + pub struct WidgetState { pub data: WidgetData, pub obj: Box, @@ -32,8 +77,8 @@ impl WidgetState { fn new(obj: Box) -> anyhow::Result { Ok(Self { data: WidgetData { - hovered: false, - pressed: false, + hovered: 0, + pressed: 0, scrolling: Vec2::default(), transform: glam::Mat4::IDENTITY, }, @@ -252,32 +297,40 @@ impl WidgetState { ) -> EventResult { let hovered = event.test_mouse_within_transform(params.transform_stack.get()); - let mut just_clicked = false; + let mut pressed_changed_button = None; + let mut hovered_changed = false; + match &event { - Event::MouseDown(_) => { - if self.data.hovered { - self.data.pressed = true; - } + Event::MouseDown(e) => { + pressed_changed_button = self + .data + .set_device_pressed(e.device, true) + .then_some(e.button); } - Event::MouseUp(_) => { - if self.data.pressed { - self.data.pressed = false; - just_clicked = self.data.hovered; - } + Event::MouseUp(e) => { + pressed_changed_button = self + .data + .set_device_pressed(e.device, false) + .then_some(e.button); } Event::MouseWheel(e) => { if self.process_wheel(params, e) { return EventResult::Consumed; } } + Event::MouseMotion(e) => { + hovered_changed |= self.data.set_device_hovered(e.device, hovered); + } + Event::MouseLeave(e) => { + hovered_changed |= self.data.set_device_hovered(e.device, false); + } _ => {} } - // TODO: simplify this behemoth, I gave up arguing with the compiler for listener in &self.event_listeners { match listener { EventListener::MouseEnter(callback) => { - if hovered && !self.data.hovered { + if hovered_changed && self.data.is_hovered() { let mut data = CallbackData { obj: self.obj.as_mut(), widget_data: &mut self.data, @@ -295,7 +348,7 @@ impl WidgetState { } } EventListener::MouseLeave(callback) => { - if !hovered && self.data.hovered { + if hovered_changed && !self.data.is_hovered() { let mut data = CallbackData { obj: self.obj.as_mut(), widget_data: &mut self.data, @@ -312,8 +365,8 @@ impl WidgetState { } } } - EventListener::MouseClick(callback) => { - if just_clicked { + EventListener::MousePress(callback) => { + if let Some(button) = pressed_changed_button.filter(|_| self.data.is_pressed()) { let mut data = CallbackData { obj: self.obj.as_mut(), widget_data: &mut self.data, @@ -324,19 +377,49 @@ impl WidgetState { node_id, needs_redraw: false, }; - callback(&mut data); + callback(&mut data, button); if data.needs_redraw { *params.needs_redraw = true; } } } + EventListener::MouseRelease(callback) => { + if let Some(button) = pressed_changed_button.filter(|_| !self.data.is_pressed()) { + let mut data = CallbackData { + obj: self.obj.as_mut(), + widget_data: &mut self.data, + widgets: params.widgets, + animations: params.animations, + dirty_nodes: params.dirty_nodes, + widget_id, + node_id, + needs_redraw: false, + }; + callback(&mut data, button); + if data.needs_redraw { + *params.needs_redraw = true; + } + } + } + EventListener::InternalStateChange(callback) => { + let mut data = CallbackData { + obj: self.obj.as_mut(), + widget_data: &mut self.data, + widgets: params.widgets, + animations: params.animations, + dirty_nodes: params.dirty_nodes, + widget_id, + node_id, + needs_redraw: false, + }; + callback(&mut data); + if data.needs_redraw { + *params.needs_redraw = true; + } + } } } - if self.data.hovered != hovered { - self.data.hovered = hovered; - } - EventResult::Pass } } diff --git a/wgui/uidev-vk/Cargo.toml b/wgui/uidev-vk/Cargo.toml index 2d96beb..5c941c8 100644 --- a/wgui/uidev-vk/Cargo.toml +++ b/wgui/uidev-vk/Cargo.toml @@ -13,10 +13,3 @@ wgui = { path = "../" } winit = "0.30.10" vulkano = { workspace = true } vulkano-shaders = { workspace = true } - -[profile.dev] -opt-level = 0 -debug = true -strip = "none" -debug-assertions = true -incremental = true diff --git a/wgui/uidev-vk/src/main.rs b/wgui/uidev-vk/src/main.rs index 4f7d7bd..12bd21f 100644 --- a/wgui/uidev-vk/src/main.rs +++ b/wgui/uidev-vk/src/main.rs @@ -18,7 +18,7 @@ use vulkano::{ sync::GpuFuture, }; use wgui::{ - event::{MouseDownEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent}, + event::{MouseButton, MouseDownEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent}, gfx::WGfx, renderer_vk::{self}, }; @@ -121,6 +121,7 @@ fn main() -> Result<(), Box> { .push_event(&wgui::event::Event::MouseWheel(MouseWheelEvent { shift: Vec2::new(x, y), pos: mouse / scale, + device: 0, })) .unwrap(), MouseScrollDelta::PixelDelta(pos) => testbed @@ -128,6 +129,7 @@ fn main() -> Result<(), Box> { .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, })) .unwrap(), }, @@ -141,6 +143,8 @@ fn main() -> Result<(), Box> { .layout() .push_event(&wgui::event::Event::MouseDown(MouseDownEvent { pos: mouse / scale, + button: MouseButton::Left, + device: 0, })) .unwrap(); } else { @@ -148,6 +152,8 @@ fn main() -> Result<(), Box> { .layout() .push_event(&wgui::event::Event::MouseUp(MouseUpEvent { pos: mouse / scale, + button: MouseButton::Left, + device: 0, })) .unwrap(); } @@ -162,6 +168,7 @@ fn main() -> Result<(), Box> { .layout() .push_event(&wgui::event::Event::MouseMotion(MouseMotionEvent { pos: mouse / scale, + device: 0, })) .unwrap(); } diff --git a/wgui/uidev-vk/src/testbed/testbed_generic.rs b/wgui/uidev-vk/src/testbed/testbed_generic.rs index cbf5ed2..10e0e95 100644 --- a/wgui/uidev-vk/src/testbed/testbed_generic.rs +++ b/wgui/uidev-vk/src/testbed/testbed_generic.rs @@ -58,7 +58,7 @@ impl TestbedGeneric { let wid = widget_id.clone(); layout.add_event_listener( button.body, - EventListener::MouseClick(Box::new(move |data| { + EventListener::MouseRelease(Box::new(move |data, _| { button.set_text(data, "Congratulations!"); *wid.borrow_mut() = Some(data.widget_id); })), diff --git a/wlx-overlay-s/Cargo.toml b/wlx-overlay-s/Cargo.toml index 8099f52..17a2d0f 100644 --- a/wlx-overlay-s/Cargo.toml +++ b/wlx-overlay-s/Cargo.toml @@ -1,7 +1,3 @@ -[profile.release-with-debug] -inherits = "release" -debug = true - [package] name = "wlx-overlay-s" version = "25.4.2" diff --git a/wlx-overlay-s/src/assets/gui/theme.xml b/wlx-overlay-s/src/assets/gui/theme.xml new file mode 100644 index 0000000..61ef159 --- /dev/null +++ b/wlx-overlay-s/src/assets/gui/theme.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/wlx-overlay-s/src/assets/keyboard.xml b/wlx-overlay-s/src/assets/keyboard.xml index a30d2ea..d211355 100644 --- a/wlx-overlay-s/src/assets/keyboard.xml +++ b/wlx-overlay-s/src/assets/keyboard.xml @@ -4,7 +4,7 @@