Files
wayvr/wlx-overlay-s/src/gui/panel/overlay_list.rs
2026-01-08 01:06:54 +09:00

153 lines
6.1 KiB
Rust

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 | OverlayCategory::Keyboard => {
let key = if matches!(meta.category, OverlayCategory::Dashboard) {
"btn_dashboard"
} else {
"btn_keyboard"
};
let Ok(overlay_button) =
parser_state.fetch_component_as::<ComponentButton>(key)
else {
continue;
};
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)
}
}