From 3875002e1e87ad9907b44e2b417676082982e3c9 Mon Sep 17 00:00:00 2001 From: Aleksander Date: Wed, 13 May 2026 17:17:15 +0200 Subject: [PATCH] wgui: use `TemplateParams` struct --- dash-frontend/src/tab/apps.rs | 28 ++--- dash-frontend/src/tab/monado.rs | 49 ++++----- dash-frontend/src/tab/settings/macros.rs | 104 +++++++++--------- dash-frontend/src/tab/welcome.rs | 13 +-- dash-frontend/src/views/app_launcher.rs | 6 +- dash-frontend/src/views/audio_settings.rs | 26 ++--- dash-frontend/src/views/dialog_box.rs | 8 +- .../src/views/remote_skymap_downloader.rs | 14 +-- dash-frontend/src/views/skymap_list_cell.rs | 17 +-- wayvr/src/gui/panel/button.rs | 7 +- wayvr/src/gui/panel/device_list.rs | 8 +- wayvr/src/gui/panel/overlay_list.rs | 25 ++--- wayvr/src/gui/panel/set_list.rs | 10 +- wayvr/src/overlays/keyboard/builder.rs | 22 ++-- wgui/src/parser/mod.rs | 56 +++++++--- wgui/src/windowing/context_menu.rs | 16 ++- 16 files changed, 198 insertions(+), 211 deletions(-) diff --git a/dash-frontend/src/tab/apps.rs b/dash-frontend/src/tab/apps.rs index 5a21b59a..08f98aaf 100644 --- a/dash-frontend/src/tab/apps.rs +++ b/dash-frontend/src/tab/apps.rs @@ -1,16 +1,10 @@ -use std::{ - cell::RefCell, - collections::{HashMap, VecDeque}, - marker::PhantomData, - rc::Rc, -}; - +use std::{cell::RefCell, collections::VecDeque, marker::PhantomData, rc::Rc}; use wgui::{ assets::AssetPath, components::button::{ButtonClickCallback, ComponentButton}, globals::WguiGlobals, layout::{WidgetID, WidgetPair}, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, }; use wlx_common::desktop_finder::DesktopEntry; @@ -242,8 +236,8 @@ impl AppList { let category_name = get_category_name(entry); if category_name != self.prev_category_name { self.prev_category_name = String::from(category_name); - let mut params = HashMap::, Rc>::new(); - params.insert("text".into(), category_name.into()); + let mut params = TemplateParams::new(); + params.insert("text", category_name); parser_state.realize_template( doc_params, @@ -255,11 +249,11 @@ impl AppList { } { - let mut params = HashMap::new(); + let mut params = TemplateParams::new(); // entry icon - params.insert( - "src_ext".into(), + params.insert_rc( + "src_ext", entry .icon_path .as_ref() @@ -268,14 +262,14 @@ impl AppList { // entry fallback (question mark) icon params.insert( - "src".into(), + "src", if entry.icon_path.is_none() { - "dashboard/terminal.svg".into() + "dashboard/terminal.svg" } else { - "".into() + "" }, ); - params.insert("name".into(), entry.app_name.clone()); + params.insert("name", &entry.app_name); let data = parser_state.realize_template( doc_params, diff --git a/dash-frontend/src/tab/monado.rs b/dash-frontend/src/tab/monado.rs index e850bc58..f184fda1 100644 --- a/dash-frontend/src/tab/monado.rs +++ b/dash-frontend/src/tab/monado.rs @@ -13,7 +13,7 @@ use wgui::{ drawing::Color, globals::WguiGlobals, layout::{Layout, WidgetID}, - parser::{self, Fetchable, ParseDocumentParams, ParserState}, + parser::{self, Fetchable, ParseDocumentParams, ParserState, TemplateParams}, task::Tasks, }; use wlx_common::{ @@ -383,15 +383,16 @@ fn mount_sessions_list( layout.remove_children(id_parent); for (session_id, session) in sessions { - let mut params = HashMap::new(); + let mut params = TemplateParams::new(); - params.insert( - Rc::from("text"), - Rc::from(format!( + params.insert_rc( + "text", + format!( "{} (ID {})", session.resolved_name.as_ref().map_or("Unknown", |s| s.as_str()), session_id, - )), + ) + .into(), ); let data = state.realize_template( @@ -427,10 +428,10 @@ fn mount_graph( limits: (f32, f32), ) -> anyhow::Result { let globals = layout.state.globals.clone(); - let mut params = HashMap::new(); - params.insert(Rc::from("name"), Rc::from(name)); - params.insert(Rc::from("limit_min"), Rc::from(limits.0.to_string())); - params.insert(Rc::from("limit_max"), Rc::from(limits.1.to_string())); + let mut params = TemplateParams::new(); + params.insert("name", name); + params.insert_rc("limit_min", limits.0.to_string().into()); + params.insert_rc("limit_max", limits.1.to_string().into()); let data = state.realize_template( &doc_params_tab_debug_timings(&globals), @@ -652,25 +653,15 @@ impl SubtabProcessList { client: &dash_interface::MonadoClient, tasks: &Tasks, ) -> anyhow::Result<()> { - let mut par = HashMap::, Rc>::new(); - par.insert( - "checked".into(), - if client.is_primary { - Rc::from("1") - } else { - Rc::from("0") - }, - ); - par.insert( - "name".into(), - format!("{} (Client ID: {})", client.name, client.id).into(), - ); - par.insert("flag_active".into(), yesno(client.is_active).into()); - par.insert("flag_focused".into(), yesno(client.is_focused).into()); - par.insert("flag_io_active".into(), yesno(client.is_io_active).into()); - par.insert("flag_overlay".into(), yesno(client.is_overlay).into()); - par.insert("flag_primary".into(), yesno(client.is_primary).into()); - par.insert("flag_visible".into(), yesno(client.is_visible).into()); + let mut par = TemplateParams::new(); + par.insert("checked", if client.is_primary { "1" } else { "0" }); + par.insert_rc("name", format!("{} (Client ID: {})", client.name, client.id).into()); + par.insert("flag_active", yesno(client.is_active)); + par.insert("flag_focused", yesno(client.is_focused)); + par.insert("flag_io_active", yesno(client.is_io_active)); + par.insert("flag_overlay", yesno(client.is_overlay)); + par.insert("flag_primary", yesno(client.is_primary)); + par.insert("flag_visible", yesno(client.is_visible)); let globals = layout.state.globals.clone(); diff --git a/dash-frontend/src/tab/settings/macros.rs b/dash-frontend/src/tab/settings/macros.rs index 275653e3..f716773a 100644 --- a/dash-frontend/src/tab/settings/macros.rs +++ b/dash-frontend/src/tab/settings/macros.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, rc::Rc}; +use std::rc::Rc; use crate::tab::settings::{self, SettingType, Task, horiz_cell, mount_requires_restart}; use wgui::{ @@ -8,7 +8,7 @@ use wgui::{ slider::ComponentSlider, }, layout::{Layout, WidgetID}, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, task::Tasks, widget::label::WidgetLabel, windowing::context_menu, @@ -24,10 +24,10 @@ pub fn options_category( let id = mp.idx.to_string(); mp.idx += 1; - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("translation"), Rc::from(translation)); - params.insert(Rc::from("icon"), Rc::from(icon)); - params.insert(Rc::from("id"), Rc::from(id.as_ref())); + let mut params = TemplateParams::new(); + params.insert("translation", translation); + params.insert("icon", icon); + params.insert("id", &id); mp.parser_state .instantiate_template(mp.doc_params, "SettingsGroupBox", mp.layout, parent, params)?; @@ -39,20 +39,20 @@ pub fn options_checkbox(mp: &mut MacroParams, parent: WidgetID, setting: Setting let id = mp.idx.to_string(); mp.idx += 1; - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("id"), Rc::from(id.as_ref())); + let mut params = TemplateParams::new(); + params.insert("id", &id); match setting.get_translation() { - Ok(translation) => params.insert(Rc::from("translation"), translation.into()), - Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()), + Ok(translation) => params.insert("translation", translation), + Err(raw_text) => params.insert("text", raw_text), }; if let Some(tooltip) = setting.get_tooltip() { - params.insert(Rc::from("tooltip"), Rc::from(tooltip)); + params.insert("tooltip", tooltip); } let checked = if *setting.mut_bool(mp.config) { "1" } else { "0" }; - params.insert(Rc::from("checked"), Rc::from(checked)); + params.insert("checked", checked); let id_cell = horiz_cell(mp.layout, parent)?; @@ -86,23 +86,23 @@ pub fn options_slider_f32( let id = mp.idx.to_string(); mp.idx += 1; - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("id"), Rc::from(id.as_ref())); + let mut params = TemplateParams::new(); + params.insert("id", &id); match setting.get_translation() { - Ok(translation) => params.insert(Rc::from("translation"), translation.into()), - Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()), + Ok(translation) => params.insert("translation", translation), + Err(raw_text) => params.insert("text", raw_text), }; if let Some(tooltip) = setting.get_tooltip() { - params.insert(Rc::from("tooltip"), Rc::from(tooltip)); + params.insert("tooltip", tooltip); } let value = setting.mut_f32(mp.config).to_string(); - params.insert(Rc::from("value"), Rc::from(value)); - params.insert(Rc::from("min"), Rc::from(min.to_string())); - params.insert(Rc::from("max"), Rc::from(max.to_string())); - params.insert(Rc::from("step"), Rc::from(step.to_string())); + params.insert_rc("value", value.into()); + params.insert_rc("min", min.to_string().into()); + params.insert_rc("max", max.to_string().into()); + params.insert_rc("step", step.to_string().into()); let id_cell = horiz_cell(mp.layout, parent)?; @@ -136,25 +136,25 @@ pub fn options_range_f32( let id = mp.idx.to_string(); mp.idx += 1; - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("id"), Rc::from(id.as_ref())); + let mut params = TemplateParams::new(); + params.insert("id", &id); match setting.get_translation() { - Ok(translation) => params.insert(Rc::from("translation"), translation.into()), - Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()), + Ok(translation) => params.insert("translation", translation), + Err(raw_text) => params.insert("text", raw_text), }; if let Some(tooltip) = setting.get_tooltip() { - params.insert(Rc::from("tooltip"), Rc::from(tooltip)); + params.insert("tooltip", tooltip); } let value = setting.mut_f32(mp.config).to_string(); let value2 = setting2.mut_f32(mp.config).to_string(); - params.insert(Rc::from("value"), Rc::from(value)); - params.insert(Rc::from("value2"), Rc::from(value2)); - params.insert(Rc::from("min"), Rc::from(min.to_string())); - params.insert(Rc::from("max"), Rc::from(max.to_string())); - params.insert(Rc::from("step"), Rc::from(step.to_string())); + params.insert_rc("value", value.into()); + params.insert_rc("value2", value2.into()); + params.insert_rc("min", min.to_string().into()); + params.insert_rc("max", max.to_string().into()); + params.insert_rc("step", step.to_string().into()); let id_cell = horiz_cell(mp.layout, parent)?; @@ -191,25 +191,25 @@ pub fn options_slider_i32( let id = mp.idx.to_string(); mp.idx += 1; - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("id"), Rc::from(id.as_ref())); + let mut params = TemplateParams::new(); + params.insert("id", &id); match setting.get_translation() { - Ok(translation) => params.insert(Rc::from("translation"), translation.into()), - Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()), + Ok(translation) => params.insert("translation", translation), + Err(raw_text) => params.insert("text", raw_text), }; if let Some(tooltip) = setting.get_tooltip() { - params.insert(Rc::from("tooltip"), Rc::from(tooltip)); + params.insert("tooltip", tooltip); } let id_cell = horiz_cell(mp.layout, parent)?; let value = setting.mut_i32(mp.config).to_string(); - params.insert(Rc::from("value"), Rc::from(value)); - params.insert(Rc::from("min"), Rc::from(min.to_string())); - params.insert(Rc::from("max"), Rc::from(max.to_string())); - params.insert(Rc::from("step"), Rc::from(step.to_string())); + params.insert_rc("value", value.into()); + params.insert_rc("min", min.to_string().into()); + params.insert_rc("max", max.to_string().into()); + params.insert_rc("step", step.to_string().into()); mp.parser_state .instantiate_template(mp.doc_params, "SliderSetting", mp.layout, id_cell, params)?; @@ -239,16 +239,16 @@ where let id = mp.idx.to_string(); mp.idx += 1; - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("id"), Rc::from(id.as_ref())); + let mut params = TemplateParams::new(); + params.insert("id", &id); match setting.get_translation() { - Ok(translation) => params.insert(Rc::from("translation"), translation.into()), - Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()), + Ok(translation) => params.insert("translation", translation), + Err(raw_text) => params.insert("text", raw_text), }; if let Some(tooltip) = setting.get_tooltip() { - params.insert(Rc::from("tooltip"), Rc::from(tooltip)); + params.insert("tooltip", tooltip); } let id_cell = horiz_cell(mp.layout, parent)?; @@ -316,10 +316,10 @@ pub fn options_danger_button( let id = mp.idx.to_string(); mp.idx += 1; - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("id"), Rc::from(id.as_ref())); - params.insert(Rc::from("translation"), Rc::from(translation)); - params.insert(Rc::from("icon"), Rc::from(icon)); + let mut params = TemplateParams::new(); + params.insert("id", &id); + params.insert("translation", translation); + params.insert("icon", icon); mp.parser_state .instantiate_template(mp.doc_params, "DangerButton", mp.layout, parent, params)?; @@ -345,9 +345,9 @@ pub fn options_autostart_app( let id = mp.idx.to_string(); mp.idx += 1; - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("id"), Rc::from(id.as_ref())); - params.insert(Rc::from("text"), Rc::from(text)); + let mut params = TemplateParams::new(); + params.insert("id", &id); + params.insert("text", text); mp.parser_state .instantiate_template(mp.doc_params, "AutostartApp", mp.layout, parent, params)?; diff --git a/dash-frontend/src/tab/welcome.rs b/dash-frontend/src/tab/welcome.rs index 40798c2a..6be85825 100644 --- a/dash-frontend/src/tab/welcome.rs +++ b/dash-frontend/src/tab/welcome.rs @@ -1,11 +1,11 @@ -use std::{collections::HashMap, marker::PhantomData, rc::Rc}; +use std::marker::PhantomData; use wgui::{ assets::AssetPath, components::button::ComponentButton, globals::WguiGlobals, layout::{Layout, WidgetID}, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, task::Tasks, }; @@ -103,16 +103,13 @@ impl TabWelcome { let globals = layout.state.globals.clone(); for i in 0..PAGE_COUNT { - let mut vars = HashMap::, Rc>::new(); + let mut params = TemplateParams::new(); let is_selected = i == self.current_page; - vars.insert( - Rc::from("COLOR"), - Rc::from(if is_selected { "#FFFFFF" } else { "#FFFFFF11" }), - ); + params.insert("COLOR", if is_selected { "#FFFFFF" } else { "#FFFFFF11" }); self .state - .instantiate_template(&doc_params(&globals), "Pip", layout, self.id_pips, vars)? + .instantiate_template(&doc_params(&globals), "Pip", layout, self.id_pips, params)? } Ok(()) diff --git a/dash-frontend/src/views/app_launcher.rs b/dash-frontend/src/views/app_launcher.rs index af9c398b..a2642377 100644 --- a/dash-frontend/src/views/app_launcher.rs +++ b/dash-frontend/src/views/app_launcher.rs @@ -8,7 +8,7 @@ use wgui::{ globals::WguiGlobals, i18n::Translation, layout::{Layout, WidgetID}, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, task::Tasks, widget::label::WidgetLabel, }; @@ -149,8 +149,8 @@ impl View { // app icon if let Some(icon_path) = ¶ms.entry.icon_path { - let mut template_params: HashMap, Rc> = HashMap::new(); - template_params.insert("path".into(), icon_path.clone()); + let mut template_params = TemplateParams::new(); + template_params.insert("path", icon_path); state.instantiate_template( doc_params, "ApplicationIcon", diff --git a/dash-frontend/src/views/audio_settings.rs b/dash-frontend/src/views/audio_settings.rs index 9546d961..3d0f4c40 100644 --- a/dash-frontend/src/views/audio_settings.rs +++ b/dash-frontend/src/views/audio_settings.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, rc::Rc}; +use std::rc::Rc; use wgui::{ assets::AssetPath, @@ -11,7 +11,7 @@ use wgui::{ globals::WguiGlobals, i18n::Translation, layout::{Layout, WidgetID}, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, task::Tasks, widget::ConstructEssentials, }; @@ -742,9 +742,9 @@ impl View { let desc = ¶ms.card.properties.device_description; let disp_name = get_profile_display_name(¶ms.card.active_profile, params.card); - let mut par = HashMap::, Rc>::new(); - par.insert("card_name".into(), desc.as_str().into()); - par.insert("profile_name".into(), disp_name.name.as_str().into()); + let mut par = TemplateParams::new(); + par.insert("card_name", desc); + par.insert("profile_name", &disp_name.name); let data = self .state @@ -766,11 +766,11 @@ impl View { } fn mount_device_slider(&mut self, params: MountDeviceSliderParams) -> anyhow::Result<()> { - let mut par = HashMap::, Rc>::new(); + let mut par = TemplateParams::new(); if let Some(disp) = ¶ms.disp { - par.insert("device_name".into(), disp.name.as_str().into()); - par.insert("device_icon".into(), disp.icon_path.into()); + par.insert("device_name", &disp.name); + par.insert("device_icon", disp.icon_path); } else { let icon_path = if params.alt_desc.contains("WiVRn") { "dashboard/wivrn_head_symbolic.svg" @@ -778,16 +778,16 @@ impl View { "dashboard/binary.svg" }; - par.insert("device_name".into(), params.alt_desc.into()); - par.insert("device_icon".into(), icon_path.into()); + par.insert("device_name", ¶ms.alt_desc); + par.insert("device_icon", icon_path); } par.insert( - "volume_icon".into(), + "volume_icon", if params.muted { - "dashboard/volume_off.svg".into() + "dashboard/volume_off.svg" } else { - "dashboard/volume.svg".into() + "dashboard/volume.svg" }, ); diff --git a/dash-frontend/src/views/dialog_box.rs b/dash-frontend/src/views/dialog_box.rs index eba712af..0a9fb17b 100644 --- a/dash-frontend/src/views/dialog_box.rs +++ b/dash-frontend/src/views/dialog_box.rs @@ -1,5 +1,3 @@ -use std::{collections::HashMap, rc::Rc}; - use crate::{ frontend::{FrontendTask, FrontendTasks}, util::popup_manager::{MountPopupOnceParams, PopupHolder}, @@ -11,7 +9,7 @@ use wgui::{ globals::WguiGlobals, i18n::Translation, layout::{Layout, WidgetID}, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, task::Tasks, widget::label::WidgetLabel, }; @@ -91,8 +89,8 @@ impl View { } for entry in par.entries { - let mut t_par = HashMap::, Rc>::new(); - t_par.insert(Rc::from("icon"), Rc::from(entry.icon)); + let mut t_par = TemplateParams::new(); + t_par.insert("icon", entry.icon); let data = parser_state.realize_template(&doc_params(&par.globals), "DialogBoxButton", layout, id_buttons, t_par)?; diff --git a/dash-frontend/src/views/remote_skymap_downloader.rs b/dash-frontend/src/views/remote_skymap_downloader.rs index 5dbaa9cf..61edba68 100644 --- a/dash-frontend/src/views/remote_skymap_downloader.rs +++ b/dash-frontend/src/views/remote_skymap_downloader.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, rc::Rc}; +use std::rc::Rc; use crate::{ frontend::{FrontendTask, FrontendTasks}, @@ -16,7 +16,7 @@ use wgui::{ globals::WguiGlobals, i18n::Translation, layout::{Layout, WidgetID}, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, renderer_vk::text::custom_glyph::CustomGlyphData, task::Tasks, widget::{image::WidgetImage, label::WidgetLabel}, @@ -73,14 +73,14 @@ fn mount_resolution_button( tasks: &Tasks, already_downloaded: bool, ) -> anyhow::Result<()> { - let mut t = HashMap::, Rc>::new(); - t.insert(Rc::from("text"), Rc::from(res.get_display_str())); + let mut t = TemplateParams::new(); + t.insert("text", res.get_display_str()); t.insert( - Rc::from("sprite"), - Rc::from(match already_downloaded { + "sprite", + match already_downloaded { true => "dashboard/check.svg", false => "dashboard/download.svg", - }), + }, ); let data = parser_state.realize_template(doc_params, "ResolutionButton", layout, parent_id, t)?; let button = data.fetch_component_as::("button")?; diff --git a/dash-frontend/src/views/skymap_list_cell.rs b/dash-frontend/src/views/skymap_list_cell.rs index fa8375de..06ab7e18 100644 --- a/dash-frontend/src/views/skymap_list_cell.rs +++ b/dash-frontend/src/views/skymap_list_cell.rs @@ -1,5 +1,3 @@ -use std::{collections::HashMap, rc::Rc}; - use wgui::{ assets::AssetPath, components::button::{ButtonClickCallback, ComponentButton}, @@ -7,7 +5,7 @@ use wgui::{ globals::WguiGlobals, i18n::Translation, layout::{Layout, WidgetID}, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, renderer_vk::text::custom_glyph::CustomGlyphData, widget::{image::WidgetImage, label::WidgetLabel}, }; @@ -54,17 +52,10 @@ fn populate_res_pips( layout.remove_children(id_parent); let mut populate_res_pip = |res: SkymapResolution| -> anyhow::Result<()> { - let mut tpar = HashMap::, Rc>::new(); + let mut tpar = TemplateParams::new(); let downloaded = entry.is_downloaded(res).unwrap_or(false); - tpar.insert( - Rc::from("color"), - if downloaded { - Rc::from("#11aa40") - } else { - Rc::from("#444444") - }, - ); - tpar.insert(Rc::from("text"), res.get_display_str_simple().into()); + tpar.insert("color", if downloaded { "#11aa40" } else { "#444444" }); + tpar.insert("text", res.get_display_str_simple()); parser_state.realize_template(&doc_params(&globals), "ResolutionPip", layout, id_parent, tpar)?; Ok(()) diff --git a/wayvr/src/gui/panel/button.rs b/wayvr/src/gui/panel/button.rs index 01d6ce8c..81dec170 100644 --- a/wayvr/src/gui/panel/button.rs +++ b/wayvr/src/gui/panel/button.rs @@ -1,6 +1,5 @@ use std::{ cell::RefCell, - collections::HashMap, process::{Child, Command, Stdio}, rc::Rc, str::FromStr, @@ -17,7 +16,7 @@ use wgui::{ }, layout::Layout, log::LogErr, - parser::{self, AttribPair, CustomAttribsInfoOwned, Fetchable, ParserState}, + parser::{self, AttribPair, CustomAttribsInfoOwned, Fetchable, ParserState, TemplateParams}, taffy, widget::EventResult, windowing::context_menu::{Blueprint, ContextMenu, OpenParams}, @@ -219,12 +218,12 @@ pub(super) fn setup_custom_button( }; // pass attribs with key `_context_{name}` to the context_menu template - let mut template_params = HashMap::new(); + let mut template_params = TemplateParams::new(); for AttribPair { attrib, value } in &attribs.pairs { const PREFIX: &str = "_context_"; #[allow(clippy::manual_strip)] if attrib.starts_with(PREFIX) { - template_params.insert(attrib[PREFIX.len()..].into(), value.clone()); + template_params.insert_rc(attrib[PREFIX.len()..].into(), value.clone()); } } diff --git a/wayvr/src/gui/panel/device_list.rs b/wayvr/src/gui/panel/device_list.rs index c2eb073c..2a5349f8 100644 --- a/wayvr/src/gui/panel/device_list.rs +++ b/wayvr/src/gui/panel/device_list.rs @@ -1,9 +1,7 @@ -use std::collections::HashMap; - use slotmap::Key; use wgui::{ layout::Layout, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, }; use crate::{ @@ -40,7 +38,7 @@ impl DeviceList { layout.remove_children(devices_root); for (i, device) in app.input_state.devices.iter().enumerate() { - let mut params = HashMap::new(); + let mut params = TemplateParams::new(); if matches!(device.role, TrackedDeviceRole::None) { continue; @@ -48,7 +46,7 @@ impl DeviceList { let template = device.role.as_ref(); - params.insert("idx".into(), i.to_string().into()); + params.insert_rc("idx", i.to_string().into()); parser_state.instantiate_template( doc_params, template, diff --git a/wayvr/src/gui/panel/overlay_list.rs b/wayvr/src/gui/panel/overlay_list.rs index 90d9044f..329165ad 100644 --- a/wayvr/src/gui/panel/overlay_list.rs +++ b/wayvr/src/gui/panel/overlay_list.rs @@ -1,10 +1,10 @@ use crate::windowing::{OverlayID, backend::OverlayEventData, window::OverlayCategory}; use slotmap::{Key, SecondaryMap}; -use std::{collections::HashMap, rc::Rc}; +use std::rc::Rc; use wgui::{ components::button::ComponentButton, layout::Layout, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, }; #[derive(Default)] @@ -37,12 +37,12 @@ impl OverlayList { self.overlay_buttons.clear(); for (i, meta) in metas.iter().enumerate() { - let mut params = HashMap::new(); + let mut params = TemplateParams::new(); let (template, root) = match meta.category { OverlayCategory::Screen => { - params.insert( - "display".into(), + params.insert_rc( + "display", format!( "{}{}", (*meta.name).chars().next().unwrap_or_default(), @@ -53,8 +53,8 @@ impl OverlayList { ("Screen", panels_root) } OverlayCategory::Mirror => { - params.insert( - "display".into(), + params.insert_rc( + "display", (*meta.name).chars().last().unwrap().to_string().into(), ); ("Mirror", panels_root) @@ -66,17 +66,16 @@ impl OverlayList { "edit/panel.svg".into() }; - params.insert("icon".into(), icon); + params.insert_rc("icon", icon); ("Panel", panels_root) } OverlayCategory::WayVR => { params.insert( - "icon".into(), + "icon", meta.icon .as_ref() .expect("WayVR overlay without Icon attribute!") - .as_ref() - .into(), + .as_ref(), ); ("App", apps_root) } @@ -106,8 +105,8 @@ impl OverlayList { continue; } - params.insert("idx".into(), i.to_string().into()); - params.insert("name".into(), meta.name.as_ref().into()); + params.insert_rc("idx", i.to_string().into()); + params.insert("name", meta.name.as_ref()); parser_state .instantiate_template(doc_params, template, layout, root, params)?; let overlay_button = parser_state diff --git a/wayvr/src/gui/panel/set_list.rs b/wayvr/src/gui/panel/set_list.rs index 83922efd..f59f380e 100644 --- a/wayvr/src/gui/panel/set_list.rs +++ b/wayvr/src/gui/panel/set_list.rs @@ -1,9 +1,9 @@ -use std::{collections::HashMap, rc::Rc}; +use std::rc::Rc; use wgui::{ components::button::ComponentButton, layout::Layout, - parser::{Fetchable, ParseDocumentParams, ParserState}, + parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams}, }; use crate::windowing::backend::OverlayEventData; @@ -45,9 +45,9 @@ impl SetList { 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()); + let mut params = TemplateParams::new(); + params.insert_rc("idx", i.to_string().into()); + params.insert_rc("display", (i + 1).to_string().into()); parser_state .instantiate_template(doc_params, "Set", layout, sets_root, params)?; let set_button = diff --git a/wayvr/src/overlays/keyboard/builder.rs b/wayvr/src/overlays/keyboard/builder.rs index ced68625..2cde8804 100644 --- a/wayvr/src/overlays/keyboard/builder.rs +++ b/wayvr/src/overlays/keyboard/builder.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, rc::Rc, time::Duration}; +use std::{rc::Rc, time::Duration}; use crate::{ app_misc, @@ -20,7 +20,7 @@ use wgui::{ event::{self, CallbackMetadata, EventListenerKind}, layout::LayoutUpdateParams, log::LogErr, - parser::{Fetchable, ParseDocumentParams}, + parser::{Fetchable, ParseDocumentParams, TemplateParams}, renderer_vk::util, taffy::{self, prelude::length}, widget::{EventResult, div::WidgetDiv, rectangle::WidgetRectangle}, @@ -108,34 +108,34 @@ pub(super) fn create_keyboard_panel( }; // todo: make this easier to maintain somehow - let mut params: HashMap, Rc> = HashMap::new(); - params.insert(Rc::from("id"), my_id.clone()); - params.insert(Rc::from("width"), Rc::from(key_width.to_string())); - params.insert(Rc::from("height"), Rc::from(key_height.to_string())); + let mut params = TemplateParams::new(); + params.insert_rc("id", my_id.clone()); + params.insert_rc("width", key_width.to_string().into()); + params.insert_rc("height", key_height.to_string().into()); let mut label = key.label.into_iter(); label .next() - .and_then(|s| params.insert("text".into(), s.into())); + .and_then(|s| params.insert_rc("text", s.into())); match key.cap_type { KeyCapType::LetterAltGr => { label .next() - .and_then(|s| params.insert("text_altgr".into(), s.into())); + .and_then(|s| params.insert_rc("text_altgr", s.into())); } KeyCapType::Symbol => { label .next() - .and_then(|s| params.insert("text_shift".into(), s.into())); + .and_then(|s| params.insert_rc("text_shift", s.into())); } KeyCapType::SymbolAltGr => { label .next() - .and_then(|s| params.insert("text_shift".into(), s.into())); + .and_then(|s| params.insert_rc("text_shift", s.into())); label .next() - .and_then(|s| params.insert("text_altgr".into(), s.into())); + .and_then(|s| params.insert_rc("text_altgr", s.into())); } _ => {} } diff --git a/wgui/src/parser/mod.rs b/wgui/src/parser/mod.rs index 1020ba47..a9510ae0 100644 --- a/wgui/src/parser/mod.rs +++ b/wgui/src/parser/mod.rs @@ -59,10 +59,13 @@ pub struct Template { node: roxmltree::NodeId, // belongs to node_document which could be included in another file } +#[derive(Clone, Default)] +pub struct TemplateParams(HashMap, Rc>); + struct ParserFile { path: AssetPathOwned, document: Rc, - template_parameters: HashMap, Rc>, + template_parameters: TemplateParams, } /* @@ -104,6 +107,24 @@ pub trait Fetchable { fn fetch_widget_as<'a, T: 'static>(&self, state: &'a LayoutState, id: &str) -> anyhow::Result>; } +impl TemplateParams { + pub fn new() -> Self { + Self(HashMap::new()) + } + + pub const fn from_hashmap(map: HashMap, Rc>) -> Self { + Self(map) + } + + pub fn insert(&mut self, key: &str, value: &str) -> Option> { + self.0.insert(Rc::from(key), Rc::from(value)) + } + + pub fn insert_rc(&mut self, key: &str, value: Rc) -> Option> { + self.0.insert(Rc::from(key), value) + } +} + impl ParserData { pub(crate) fn take_results_from(&mut self, from: &mut Self) { let ids = std::mem::take(&mut from.ids); @@ -232,7 +253,7 @@ impl ParserState { template_name: &str, layout: &mut Layout, widget_id: WidgetID, - template_parameters: HashMap, Rc>, + template_parameters: TemplateParams, ) -> anyhow::Result { let mut parser_data = self.parse_template_only(doc_params, template_name, layout, widget_id, template_parameters)?; @@ -253,7 +274,7 @@ impl ParserState { template_name: &str, layout: &mut Layout, widget_id: WidgetID, - template_parameters: HashMap, Rc>, + template_parameters: TemplateParams, ) -> anyhow::Result { let Some(template) = self.data.templates.get(template_name) else { anyhow::bail!( @@ -292,7 +313,7 @@ impl ParserState { template_name: &str, layout: &mut Layout, widget_id: WidgetID, - template_parameters: HashMap, Rc>, + template_parameters: TemplateParams, ) -> anyhow::Result<()> { let mut data_local = self.parse_template_only(doc_params, template_name, layout, widget_id, template_parameters)?; @@ -303,7 +324,7 @@ impl ParserState { pub(crate) fn context_menu_parse_cells( &mut self, template_name: &str, - template_params: &HashMap, Rc>, + template_params: &TemplateParams, ) -> anyhow::Result> { let Some(template) = self.data.templates.get(template_name) else { anyhow::bail!("no template named \"{template_name}\" found"); @@ -647,7 +668,7 @@ fn require_tag_by_name<'a>(node: &roxmltree::Node<'a, 'a>, name: &str) -> anyhow fn parse_widget_other_internal( template: &Rc