diff --git a/wlx-common/src/config.rs b/wlx-common/src/config.rs index 88fc248..144ece4 100644 --- a/wlx-common/src/config.rs +++ b/wlx-common/src/config.rs @@ -187,6 +187,9 @@ pub struct GeneralConfig { #[serde(default = "def_false")] pub double_cursor_fix: bool, + #[serde(default = "def_false")] + pub single_set_mode: bool, + #[serde(default = "def_astrset_empty")] pub custom_panels: AStrSet, diff --git a/wlx-overlay-s/src/assets/gui/watch-noset.xml b/wlx-overlay-s/src/assets/gui/watch-noset.xml new file mode 100644 index 0000000..722b077 --- /dev/null +++ b/wlx-overlay-s/src/assets/gui/watch-noset.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wlx-overlay-s/src/backend/input.rs b/wlx-overlay-s/src/backend/input.rs index 9b6b67c..3fb1f3d 100644 --- a/wlx-overlay-s/src/backend/input.rs +++ b/wlx-overlay-s/src/backend/input.rs @@ -1,6 +1,6 @@ use std::f32::consts::PI; use std::process::{Child, Command}; -use std::{collections::VecDeque, time::Instant}; +use std::time::Instant; use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles}; @@ -192,7 +192,6 @@ pub struct InteractionState { pub grabbed: Option, pub clicked_id: Option, pub hovered_id: Option, - pub release_actions: VecDeque>, pub next_push: Instant, pub haptics: Option, } @@ -204,7 +203,6 @@ impl Default for InteractionState { grabbed: None, clicked_id: None, hovered_id: None, - release_actions: VecDeque::new(), next_push: Instant::now(), haptics: None, } diff --git a/wlx-overlay-s/src/backend/task.rs b/wlx-overlay-s/src/backend/task.rs index f10bbaa..1a82d51 100644 --- a/wlx-overlay-s/src/backend/task.rs +++ b/wlx-overlay-s/src/backend/task.rs @@ -59,6 +59,7 @@ pub type CreateOverlayTask = dyn FnOnce(&mut AppState) -> Option, label: WidgetID, sprite: WidgetID, + condensed: bool, } #[derive(Default)] @@ -126,6 +127,25 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { Ok(EventResult::Consumed) }) } + "::SingleSetOverlayToggle" => { + let arg = args.next().unwrap_or_default(); + let Ok(idx) = arg.parse::() else { + log::error!("{command} has invalid argument: \"{arg}\""); + return; + }; + Box::new(move |_common, _data, app, state| { + let Some(overlay) = state.overlay_metas.get(idx) else { + log::error!("No overlay at index {idx}."); + return Ok(EventResult::Consumed); + }; + + app.tasks + .enqueue(TaskType::Overlay(OverlayTask::SoftToggleOverlay( + OverlaySelector::Id(overlay.id), + ))); + Ok(EventResult::Consumed) + }) + } _ => return, }; @@ -134,9 +154,16 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { } }); + let watch_xml = app + .session + .config + .single_set_mode + .then_some("gui/watch-noset.xml") + .unwrap_or("gui/watch.xml"); + let mut panel = GuiPanel::new_from_template( app, - "gui/watch.xml", + watch_xml, state, NewGuiPanelParams { on_custom_id: Some(Box::new( @@ -165,7 +192,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { .fetch_component_as::(&format!("set_{idx}"))?; state.set_buttons.push(comp); } - } else if &*id == "toolbox" { + } else if &*id == "toolbox" || &*id == "toolbox-condensed" { for idx in 0..MAX_TOOLBOX_BUTTONS { let id_str = format!("overlay_{idx}"); @@ -193,6 +220,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { .get_widget_id(&format!("overlay_{idx}_sprite")) .inspect_err(|e| log::warn!("{e:?}")) .unwrap_or_default(), + condensed: id.ends_with("-condensed"), }); } } else if id.starts_with("overlay_") && id.ends_with("_sprite") { @@ -287,11 +315,15 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { match event_data { OverlayEventData::ActiveSetChanged(current_set) => { - if let Some(old_set) = panel.state.current_set.take() { - panel.state.set_buttons[old_set].set_sticky_state(&mut com, false); + 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 { - panel.state.set_buttons[new_set].set_sticky_state(&mut com, true); + 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; } @@ -341,7 +373,11 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { panel.state.overlay_metas = metas; for (idx, btn) in panel.state.overlay_buttons.iter().enumerate() { let display = if let Some(meta) = panel.state.overlay_metas.get(idx) { - let name = sanitize_overlay_name(&meta.name); + let name = btn + .condensed + .then(|| condense_overlay_name(&meta.name)) + .unwrap_or_else(|| sanitize_overlay_name(&meta.name)); + if let Some(mut label) = panel.layout.state.widgets.get_as::(btn.label) { @@ -438,3 +474,12 @@ pub fn watch_fade(app: &mut AppState, watch: &mut OverlayWindowData) { fn sanitize_overlay_name(str: &str) -> Rc { str.replace("-wvr", "").into() } + +fn condense_overlay_name(str: &str) -> Rc { + str.replace("DP-", "D") + .replace("HDMI-A-", "H") + .replace("WVR-wvr_", "W") + .replace("WVR-wvr", "W0") + .replace("Keyboard", "") + .into() +} diff --git a/wlx-overlay-s/src/windowing/manager.rs b/wlx-overlay-s/src/windowing/manager.rs index cc0b55a..59a7f24 100644 --- a/wlx-overlay-s/src/windowing/manager.rs +++ b/wlx-overlay-s/src/windowing/manager.rs @@ -148,6 +148,31 @@ where OverlayTask::ToggleSet(set) => { self.switch_or_toggle_set(app, set); } + OverlayTask::SoftToggleOverlay(sel) => { + let Some(id) = self.id_by_selector(&sel) else { + log::warn!("Overlay not found for task: {sel:?}"); + return Ok(()); + }; + + let o = &mut self.overlays[id]; + if let Some(active_state) = o.config.active_state.take() { + log::debug!("{}: soft-toggle off", o.config.name); + self.sets[self.restore_set] + .overlays + .insert(id, active_state); + } else if let Some(state) = self.sets[self.restore_set].overlays.remove(id) { + let o = &mut self.overlays[id]; + log::debug!("{}: soft-toggle on", o.config.name); + o.config.dirty = true; + o.config.active_state = Some(state); + o.config.reset(app, false); + } else { + // no saved state + o.config.activate(app); + } + + return Ok(()); + } OverlayTask::ToggleEditMode => { self.set_edit_mode(!self.edit_mode, app)?; } @@ -428,14 +453,19 @@ impl OverlayWindowManager { } } + pub fn id_by_selector(&self, selector: &OverlaySelector) -> Option { + match selector { + OverlaySelector::Id(id) => Some(*id), + OverlaySelector::Name(name) => self.lookup(name), + } + } + pub fn mut_by_selector( &mut self, selector: &OverlaySelector, ) -> Option<&mut OverlayWindowData> { - match selector { - OverlaySelector::Id(id) => self.mut_by_id(*id), - OverlaySelector::Name(name) => self.lookup(name).and_then(|id| self.mut_by_id(id)), - } + self.id_by_selector(selector) + .and_then(|id| self.mut_by_id(id)) } fn remove_by_selector( @@ -559,7 +589,6 @@ impl OverlayWindowManager { if let Some(current_set) = self.current_set.as_ref() { let ws = &mut self.sets[*current_set]; - ws.overlays.clear(); for (id, data) in self.overlays.iter_mut().filter(|(_, d)| !d.config.global) { if let Some(state) = data.config.active_state.take() { log::debug!("{}: active_state → ws{}", data.config.name, current_set); @@ -582,6 +611,7 @@ impl OverlayWindowManager { data.config.reset(app, false); } } + ws.overlays.clear(); self.restore_set = new_set; } self.current_set = new_set;