list helpers

This commit is contained in:
galister
2026-01-07 21:19:18 +09:00
parent 576506233e
commit 89e8d606a8
6 changed files with 257 additions and 190 deletions

View File

@@ -8,7 +8,7 @@ use std::{
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{
backend::{input, wayvr::process::KillSignal}, backend::input,
state::AppState, state::AppState,
windowing::{OverlaySelector, window::OverlayWindowConfig}, windowing::{OverlaySelector, window::OverlayWindowConfig},
}; };

View File

@@ -36,6 +36,8 @@ use super::timer::GuiTimer;
pub mod button; pub mod button;
mod label; mod label;
pub mod overlay_list;
pub mod set_list;
const DEFAULT_MAX_SIZE: f32 = 2048.0; const DEFAULT_MAX_SIZE: f32 = 2048.0;

View File

@@ -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 `<Screen>`, `<Mirror>`, `<Panel>` templates
/// Populates `id="apps_root"` with `<App>` templates (optional)
/// Uses the following parameters: `name` (All), `display` (Screen, Mirror), `icon` (App)
pub struct OverlayList {
overlay_buttons: SecondaryMap<OverlayID, Rc<ComponentButton>>,
}
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<bool> {
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::<ComponentButton>("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::<ComponentButton>(&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)
}
}

View File

@@ -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 `<Set>` template.
/// Passes `idx`, `display` parameters.
pub struct SetList {
set_buttons: Vec<Rc<ComponentButton>>,
current_set: Option<usize>,
}
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<bool> {
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::<ComponentButton>(&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)
}
}

View File

@@ -8,16 +8,14 @@ use crate::{
}, },
state::AppState, state::AppState,
subsystem::hid::XkbKeymap, subsystem::hid::XkbKeymap,
windowing::{backend::OverlayEventData, window::OverlayCategory},
}; };
use anyhow::Context; use anyhow::Context;
use glam::{FloatExt, Mat4, Vec2, vec2, vec3}; use glam::{FloatExt, Mat4, Vec2, vec2, vec3};
use wgui::{ use wgui::{
animation::{Animation, AnimationEasing}, animation::{Animation, AnimationEasing},
assets::AssetPath, assets::AssetPath,
components::button::ComponentButton,
drawing::{self, Color}, drawing::{self, Color},
event::{self, CallbackDataCommon, CallbackMetadata, EventAlterables, EventListenerKind}, event::{self, CallbackMetadata, EventAlterables, EventListenerKind},
layout::LayoutUpdateParams, layout::LayoutUpdateParams,
parser::{Fetchable, ParseDocumentParams}, parser::{Fetchable, ParseDocumentParams},
renderer_vk::util, renderer_vk::util,
@@ -263,158 +261,25 @@ pub(super) fn create_keyboard_panel(
panel.on_notify = Some(Box::new(move |panel, app, event_data| { panel.on_notify = Some(Box::new(move |panel, app, event_data| {
let mut alterables = EventAlterables::default(); let mut alterables = EventAlterables::default();
match event_data { let mut elems_changed = panel.state.overlay_list.on_notify(
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();
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, &mut panel.layout,
sets_root, &mut panel.parser_state,
params, &event_data,
)?; &mut alterables,
let set_button = panel
.parser_state
.fetch_component_as::<ComponentButton>(&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();
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::<ComponentButton>("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, &doc_params,
template,
&mut panel.layout,
root,
params,
)?; )?;
let overlay_button = panel
.parser_state elems_changed |= panel.state.set_list.on_notify(
.fetch_component_as::<ComponentButton>(&format!("overlay_{i}"))?; &mut panel.layout,
if meta.visible { &mut panel.parser_state,
let mut com = CallbackDataCommon { &event_data,
alterables: &mut alterables, &mut alterables,
state: &panel.layout.state, &doc_params,
}; )?;
overlay_button.set_sticky_state(&mut com, true);
} if elems_changed {
panel.state.overlay_buttons.insert(meta.id, overlay_button);
}
panel.process_custom_elems(app); 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);
}
}
_ => {}
}
panel.layout.process_alterables(alterables)?; panel.layout.process_alterables(alterables)?;
Ok(()) Ok(())

View File

@@ -2,14 +2,13 @@ use std::{
cell::Cell, cell::Cell,
collections::HashMap, collections::HashMap,
process::{Child, Command}, process::{Child, Command},
rc::Rc,
sync::atomic::Ordering, sync::atomic::Ordering,
}; };
use crate::{ use crate::{
KEYMAP_CHANGE, KEYMAP_CHANGE,
backend::input::{HoverResult, PointerHit}, backend::input::{HoverResult, PointerHit},
gui::panel::GuiPanel, gui::panel::{GuiPanel, overlay_list::OverlayList, set_list::SetList},
overlays::keyboard::{builder::create_keyboard_panel, layout::AltModifier}, overlays::keyboard::{builder::create_keyboard_panel, layout::AltModifier},
state::AppState, state::AppState,
subsystem::{ subsystem::{
@@ -20,19 +19,15 @@ use crate::{
}, },
}, },
windowing::{ windowing::{
OverlayID, backend::{FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender},
backend::{
FrameMeta, OverlayBackend, OverlayEventData, OverlayMeta, RenderResources, ShouldRender,
},
window::{OverlayCategory, OverlayWindowConfig}, window::{OverlayCategory, OverlayWindowConfig},
}, },
}; };
use anyhow::Context; use anyhow::Context;
use glam::{Affine3A, Quat, Vec3, vec3}; use glam::{Affine3A, Quat, Vec3, vec3};
use regex::Regex; use regex::Regex;
use slotmap::{SecondaryMap, SlotMap, new_key_type}; use slotmap::{SlotMap, new_key_type};
use wgui::{ use wgui::{
components::button::ComponentButton,
drawing, drawing,
event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex}, event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex},
}; };
@@ -59,10 +54,8 @@ pub fn create_keyboard(app: &mut AppState, wayland: bool) -> anyhow::Result<Over
_ => 0, _ => 0,
}, },
processes: vec![], processes: vec![],
set_buttons: vec![], overlay_list: OverlayList::default(),
overlay_buttons: SecondaryMap::new(), set_list: SetList::default(),
overlay_metas: SecondaryMap::new(),
current_set: None,
}; };
let auto_labels = layout.auto_labels.unwrap_or(true); let auto_labels = layout.auto_labels.unwrap_or(true);
@@ -318,10 +311,16 @@ struct KeyboardState {
modifiers: KeyModifier, modifiers: KeyModifier,
alt_modifier: KeyModifier, alt_modifier: KeyModifier,
processes: Vec<Child>, processes: Vec<Child>,
set_buttons: Vec<Rc<ComponentButton>>, overlay_list: OverlayList,
overlay_buttons: SecondaryMap<OverlayID, Rc<ComponentButton>>, set_list: SetList,
overlay_metas: SecondaryMap<OverlayID, OverlayMeta>, }
current_set: Option<usize>,
macro_rules! take_and_leave_default {
($what:expr) => {{
let mut x = Default::default();
std::mem::swap(&mut x, $what);
x
}};
} }
impl KeyboardState { impl KeyboardState {
@@ -329,27 +328,9 @@ impl KeyboardState {
Self { Self {
modifiers: self.modifiers, modifiers: self.modifiers,
alt_modifier: self.alt_modifier, alt_modifier: self.alt_modifier,
processes: { processes: take_and_leave_default!(&mut self.processes),
let mut processes = vec![]; overlay_list: take_and_leave_default!(&mut self.overlay_list),
std::mem::swap(&mut processes, &mut self.processes); set_list: take_and_leave_default!(&mut self.set_list),
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(),
} }
} }
} }