From 89e8d606a89f55de5da13e97f70be76787e0ca99 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Wed, 7 Jan 2026 21:19:18 +0900 Subject: [PATCH] list helpers --- wlx-overlay-s/src/backend/task.rs | 2 +- wlx-overlay-s/src/gui/panel/mod.rs | 2 + wlx-overlay-s/src/gui/panel/overlay_list.rs | 143 +++++++++++++++ wlx-overlay-s/src/gui/panel/set_list.rs | 76 ++++++++ .../src/overlays/keyboard/builder.rs | 169 ++---------------- wlx-overlay-s/src/overlays/keyboard/mod.rs | 55 ++---- 6 files changed, 257 insertions(+), 190 deletions(-) create mode 100644 wlx-overlay-s/src/gui/panel/overlay_list.rs create mode 100644 wlx-overlay-s/src/gui/panel/set_list.rs diff --git a/wlx-overlay-s/src/backend/task.rs b/wlx-overlay-s/src/backend/task.rs index e70511d..9a54d50 100644 --- a/wlx-overlay-s/src/backend/task.rs +++ b/wlx-overlay-s/src/backend/task.rs @@ -8,7 +8,7 @@ use std::{ use serde::Deserialize; use crate::{ - backend::{input, wayvr::process::KillSignal}, + backend::input, state::AppState, windowing::{OverlaySelector, window::OverlayWindowConfig}, }; diff --git a/wlx-overlay-s/src/gui/panel/mod.rs b/wlx-overlay-s/src/gui/panel/mod.rs index 56e6dd4..f7d3b74 100644 --- a/wlx-overlay-s/src/gui/panel/mod.rs +++ b/wlx-overlay-s/src/gui/panel/mod.rs @@ -36,6 +36,8 @@ use super::timer::GuiTimer; pub mod button; mod label; +pub mod overlay_list; +pub mod set_list; const DEFAULT_MAX_SIZE: f32 = 2048.0; diff --git a/wlx-overlay-s/src/gui/panel/overlay_list.rs b/wlx-overlay-s/src/gui/panel/overlay_list.rs new file mode 100644 index 0000000..7a03309 --- /dev/null +++ b/wlx-overlay-s/src/gui/panel/overlay_list.rs @@ -0,0 +1,143 @@ +use std::{collections::HashMap, rc::Rc}; + +use slotmap::{Key, SecondaryMap}; +use wgui::{ + components::button::ComponentButton, + event::{CallbackDataCommon, EventAlterables}, + layout::Layout, + parser::{Fetchable, ParseDocumentParams, ParserState}, +}; + +use crate::windowing::{OverlayID, backend::OverlayEventData, window::OverlayCategory}; + +#[derive(Default)] +/// Helper for managing a list of overlays +/// Populates `id="panels_root"` with ``, ``, `` templates +/// Populates `id="apps_root"` with `` templates (optional) +/// Uses the following parameters: `name` (All), `display` (Screen, Mirror), `icon` (App) +pub struct OverlayList { + overlay_buttons: SecondaryMap>, +} + +impl OverlayList { + pub fn on_notify( + &mut self, + layout: &mut Layout, + parser_state: &mut ParserState, + event_data: &OverlayEventData, + alterables: &mut EventAlterables, + doc_params: &ParseDocumentParams, + ) -> anyhow::Result { + let mut elements_changed = false; + match event_data { + OverlayEventData::OverlaysChanged(metas) => { + let panels_root = parser_state + .get_widget_id("panels_root") + .unwrap_or_default(); + let apps_root = parser_state.get_widget_id("apps_root").unwrap_or_default(); + + layout.remove_children(panels_root); + layout.remove_children(apps_root); + self.overlay_buttons.clear(); + + for (i, meta) in metas.iter().enumerate() { + let mut params = HashMap::new(); + + let (template, root) = match meta.category { + OverlayCategory::Screen => { + params.insert( + "display".into(), + format!( + "{}{}", + (*meta.name).chars().next().unwrap_or_default(), + (*meta.name).chars().last().unwrap_or_default() + ) + .into(), + ); + ("Screen", panels_root) + } + OverlayCategory::Mirror => { + params.insert( + "display".into(), + (*meta.name).chars().last().unwrap().to_string().into(), + ); + ("Mirror", panels_root) + } + OverlayCategory::Panel => ("Panel", panels_root), + OverlayCategory::WayVR => { + params.insert( + "icon".into(), + meta.icon + .as_ref() + .expect("WayVR overlay without Icon attribute!") + .as_ref() + .into(), + ); + ("App", apps_root) + } + OverlayCategory::Dashboard => { + let overlay_button = parser_state + .fetch_component_as::("btn_dashboard")?; + + if meta.visible { + let mut com = CallbackDataCommon { + alterables: alterables, + state: &layout.state, + }; + overlay_button.set_sticky_state(&mut com, true); + } + self.overlay_buttons.insert(meta.id, overlay_button); + continue; + } + _ => continue, + }; + + if root.is_null() { + continue; + } + + params.insert("idx".into(), i.to_string().into()); + params.insert("name".into(), meta.name.as_ref().into()); + parser_state.instantiate_template( + &doc_params, + template, + layout, + root, + params, + )?; + let overlay_button = parser_state + .fetch_component_as::(&format!("overlay_{i}"))?; + if meta.visible { + let mut com = CallbackDataCommon { + alterables: alterables, + state: &layout.state, + }; + overlay_button.set_sticky_state(&mut com, true); + } + self.overlay_buttons.insert(meta.id, overlay_button); + } + elements_changed = true; + } + OverlayEventData::VisibleOverlaysChanged(overlays) => { + let mut com = CallbackDataCommon { + alterables: alterables, + state: &layout.state, + }; + let mut overlay_buttons = self.overlay_buttons.clone(); + + for visible in overlays.as_ref() { + if let Some(btn) = overlay_buttons.remove(*visible) { + btn.set_sticky_state(&mut com, true); + } + } + + for btn in overlay_buttons.values() { + btn.set_sticky_state(&mut com, false); + } + } + _ => {} + } + + Ok(elements_changed) + } +} diff --git a/wlx-overlay-s/src/gui/panel/set_list.rs b/wlx-overlay-s/src/gui/panel/set_list.rs new file mode 100644 index 0000000..73d8951 --- /dev/null +++ b/wlx-overlay-s/src/gui/panel/set_list.rs @@ -0,0 +1,76 @@ +use std::{collections::HashMap, rc::Rc}; + +use wgui::{ + components::button::ComponentButton, + event::{CallbackDataCommon, EventAlterables}, + layout::Layout, + parser::{Fetchable, ParseDocumentParams, ParserState}, +}; + +use crate::windowing::backend::OverlayEventData; + +#[derive(Default)] +/// Populates `id="sets_root"` by instantiating the `` template. +/// Passes `idx`, `display` parameters. +pub struct SetList { + set_buttons: Vec>, + current_set: Option, +} + +impl SetList { + pub fn on_notify( + &mut self, + layout: &mut Layout, + parser_state: &mut ParserState, + event_data: &OverlayEventData, + alterables: &mut EventAlterables, + doc_params: &ParseDocumentParams, + ) -> anyhow::Result { + let mut elements_changed = false; + match event_data { + OverlayEventData::ActiveSetChanged(current_set) => { + let mut com = CallbackDataCommon { + alterables: alterables, + state: &layout.state, + }; + if let Some(old_set) = self.current_set.take() + && let Some(old_set) = self.set_buttons.get_mut(old_set) + { + old_set.set_sticky_state(&mut com, false); + } + if let Some(new_set) = current_set + && let Some(new_set) = self.set_buttons.get_mut(*new_set) + { + new_set.set_sticky_state(&mut com, true); + } + self.current_set = *current_set; + } + OverlayEventData::NumSetsChanged(num_sets) => { + let sets_root = parser_state.get_widget_id("sets_root")?; + layout.remove_children(sets_root); + self.set_buttons.clear(); + + for i in 0..*num_sets { + let mut params = HashMap::new(); + params.insert("idx".into(), i.to_string().into()); + params.insert("display".into(), (i + 1).to_string().into()); + parser_state + .instantiate_template(doc_params, "Set", layout, sets_root, params)?; + let set_button = + parser_state.fetch_component_as::(&format!("set_{i}"))?; + if self.current_set == Some(i) { + let mut com = CallbackDataCommon { + alterables: alterables, + state: &layout.state, + }; + set_button.set_sticky_state(&mut com, true); + } + self.set_buttons.push(set_button); + } + elements_changed = true; + } + _ => {} + } + Ok(elements_changed) + } +} diff --git a/wlx-overlay-s/src/overlays/keyboard/builder.rs b/wlx-overlay-s/src/overlays/keyboard/builder.rs index 3c381dd..bb83c16 100644 --- a/wlx-overlay-s/src/overlays/keyboard/builder.rs +++ b/wlx-overlay-s/src/overlays/keyboard/builder.rs @@ -8,16 +8,14 @@ use crate::{ }, state::AppState, subsystem::hid::XkbKeymap, - windowing::{backend::OverlayEventData, window::OverlayCategory}, }; use anyhow::Context; use glam::{FloatExt, Mat4, Vec2, vec2, vec3}; use wgui::{ animation::{Animation, AnimationEasing}, assets::AssetPath, - components::button::ComponentButton, drawing::{self, Color}, - event::{self, CallbackDataCommon, CallbackMetadata, EventAlterables, EventListenerKind}, + event::{self, CallbackMetadata, EventAlterables, EventListenerKind}, layout::LayoutUpdateParams, parser::{Fetchable, ParseDocumentParams}, renderer_vk::util, @@ -263,157 +261,24 @@ pub(super) fn create_keyboard_panel( panel.on_notify = Some(Box::new(move |panel, app, event_data| { let mut alterables = EventAlterables::default(); - match event_data { - OverlayEventData::ActiveSetChanged(current_set) => { - let mut com = CallbackDataCommon { - alterables: &mut alterables, - state: &panel.layout.state, - }; - if let Some(old_set) = panel.state.current_set.take() - && let Some(old_set) = panel.state.set_buttons.get_mut(old_set) - { - old_set.set_sticky_state(&mut com, false); - } - if let Some(new_set) = current_set - && let Some(new_set) = panel.state.set_buttons.get_mut(new_set) - { - new_set.set_sticky_state(&mut com, true); - } - panel.state.current_set = current_set; - } - OverlayEventData::NumSetsChanged(num_sets) => { - let sets_root = panel.parser_state.get_widget_id("sets_root")?; - panel.layout.remove_children(sets_root); - panel.state.set_buttons.clear(); + let mut elems_changed = panel.state.overlay_list.on_notify( + &mut panel.layout, + &mut panel.parser_state, + &event_data, + &mut alterables, + &doc_params, + )?; - for i in 0..num_sets { - let mut params = HashMap::new(); - params.insert("idx".into(), i.to_string().into()); - params.insert("display".into(), (i + 1).to_string().into()); - panel.parser_state.instantiate_template( - &doc_params, - "Set", - &mut panel.layout, - sets_root, - params, - )?; - let set_button = panel - .parser_state - .fetch_component_as::(&format!("set_{i}"))?; - if panel.state.current_set == Some(i) { - let mut com = CallbackDataCommon { - alterables: &mut alterables, - state: &panel.layout.state, - }; - set_button.set_sticky_state(&mut com, true); - } - panel.state.set_buttons.push(set_button); - } - panel.process_custom_elems(app); - } - OverlayEventData::OverlaysChanged(metas) => { - let panels_root = panel.parser_state.get_widget_id("panels_root")?; - let apps_root = panel.parser_state.get_widget_id("apps_root")?; - panel.layout.remove_children(panels_root); - panel.layout.remove_children(apps_root); - panel.state.overlay_buttons.clear(); + elems_changed |= panel.state.set_list.on_notify( + &mut panel.layout, + &mut panel.parser_state, + &event_data, + &mut alterables, + &doc_params, + )?; - for (i, meta) in metas.iter().enumerate() { - let mut params = HashMap::new(); - - let (template, root) = match meta.category { - OverlayCategory::Screen => { - params.insert( - "display".into(), - format!( - "{}{}", - (*meta.name).chars().next().unwrap_or_default(), - (*meta.name).chars().last().unwrap_or_default() - ) - .into(), - ); - ("Screen", panels_root) - } - OverlayCategory::Mirror => { - params.insert( - "display".into(), - (*meta.name).chars().last().unwrap().to_string().into(), - ); - ("Mirror", panels_root) - } - OverlayCategory::Panel => ("Panel", panels_root), - OverlayCategory::WayVR => { - params.insert( - "icon".into(), - meta.icon - .as_ref() - .expect("WayVR overlay without Icon attribute!") - .as_ref() - .into(), - ); - ("App", apps_root) - } - OverlayCategory::Dashboard => { - let overlay_button = panel - .parser_state - .fetch_component_as::("btn_dashboard")?; - - log::error!("Found dashboard at: {:?}", meta.id); - - if meta.visible { - let mut com = CallbackDataCommon { - alterables: &mut alterables, - state: &panel.layout.state, - }; - overlay_button.set_sticky_state(&mut com, true); - } - panel.state.overlay_buttons.insert(meta.id, overlay_button); - continue; - } - _ => continue, - }; - - params.insert("idx".into(), i.to_string().into()); - params.insert("name".into(), meta.name.as_ref().into()); - panel.parser_state.instantiate_template( - &doc_params, - template, - &mut panel.layout, - root, - params, - )?; - let overlay_button = panel - .parser_state - .fetch_component_as::(&format!("overlay_{i}"))?; - if meta.visible { - let mut com = CallbackDataCommon { - alterables: &mut alterables, - state: &panel.layout.state, - }; - overlay_button.set_sticky_state(&mut com, true); - } - panel.state.overlay_buttons.insert(meta.id, overlay_button); - } - panel.process_custom_elems(app); - } - OverlayEventData::VisibleOverlaysChanged(overlays) => { - let mut com = CallbackDataCommon { - alterables: &mut alterables, - state: &panel.layout.state, - }; - let mut overlay_buttons = panel.state.overlay_buttons.clone(); - - for visible in &*overlays { - if let Some(btn) = overlay_buttons.remove(*visible) { - btn.set_sticky_state(&mut com, true); - } - } - - for btn in overlay_buttons.values() { - btn.set_sticky_state(&mut com, false); - } - } - _ => {} + if elems_changed { + panel.process_custom_elems(app); } panel.layout.process_alterables(alterables)?; diff --git a/wlx-overlay-s/src/overlays/keyboard/mod.rs b/wlx-overlay-s/src/overlays/keyboard/mod.rs index e4dd6e9..fd5acb3 100644 --- a/wlx-overlay-s/src/overlays/keyboard/mod.rs +++ b/wlx-overlay-s/src/overlays/keyboard/mod.rs @@ -2,14 +2,13 @@ use std::{ cell::Cell, collections::HashMap, process::{Child, Command}, - rc::Rc, sync::atomic::Ordering, }; use crate::{ KEYMAP_CHANGE, backend::input::{HoverResult, PointerHit}, - gui::panel::GuiPanel, + gui::panel::{GuiPanel, overlay_list::OverlayList, set_list::SetList}, overlays::keyboard::{builder::create_keyboard_panel, layout::AltModifier}, state::AppState, subsystem::{ @@ -20,19 +19,15 @@ use crate::{ }, }, windowing::{ - OverlayID, - backend::{ - FrameMeta, OverlayBackend, OverlayEventData, OverlayMeta, RenderResources, ShouldRender, - }, + backend::{FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender}, window::{OverlayCategory, OverlayWindowConfig}, }, }; use anyhow::Context; use glam::{Affine3A, Quat, Vec3, vec3}; use regex::Regex; -use slotmap::{SecondaryMap, SlotMap, new_key_type}; +use slotmap::{SlotMap, new_key_type}; use wgui::{ - components::button::ComponentButton, drawing, event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex}, }; @@ -59,10 +54,8 @@ pub fn create_keyboard(app: &mut AppState, wayland: bool) -> anyhow::Result 0, }, processes: vec![], - set_buttons: vec![], - overlay_buttons: SecondaryMap::new(), - overlay_metas: SecondaryMap::new(), - current_set: None, + overlay_list: OverlayList::default(), + set_list: SetList::default(), }; let auto_labels = layout.auto_labels.unwrap_or(true); @@ -318,10 +311,16 @@ struct KeyboardState { modifiers: KeyModifier, alt_modifier: KeyModifier, processes: Vec, - set_buttons: Vec>, - overlay_buttons: SecondaryMap>, - overlay_metas: SecondaryMap, - current_set: Option, + overlay_list: OverlayList, + set_list: SetList, +} + +macro_rules! take_and_leave_default { + ($what:expr) => {{ + let mut x = Default::default(); + std::mem::swap(&mut x, $what); + x + }}; } impl KeyboardState { @@ -329,27 +328,9 @@ impl KeyboardState { Self { modifiers: self.modifiers, alt_modifier: self.alt_modifier, - processes: { - let mut processes = vec![]; - std::mem::swap(&mut processes, &mut self.processes); - processes - }, - set_buttons: { - let mut set_buttons = vec![]; - std::mem::swap(&mut set_buttons, &mut self.set_buttons); - set_buttons - }, - overlay_buttons: { - let mut overlay_buttons = SecondaryMap::new(); - std::mem::swap(&mut overlay_buttons, &mut self.overlay_buttons); - overlay_buttons - }, - overlay_metas: { - let mut overlay_metas = SecondaryMap::new(); - std::mem::swap(&mut overlay_metas, &mut self.overlay_metas); - overlay_metas - }, - current_set: self.current_set.take(), + processes: take_and_leave_default!(&mut self.processes), + overlay_list: take_and_leave_default!(&mut self.overlay_list), + set_list: take_and_leave_default!(&mut self.set_list), } } }