wgui: use `TemplateParams` struct

This commit is contained in:
Aleksander 2026-05-13 17:17:15 +02:00
parent c75f38b9c0
commit 3875002e1e
16 changed files with 198 additions and 211 deletions

View File

@ -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<str>, Rc<str>>::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,

View File

@ -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<DebugGraph> {
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<Task>,
) -> anyhow::Result<()> {
let mut par = HashMap::<Rc<str>, Rc<str>>::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();

View File

@ -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<str>, Rc<str>> = 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<str>, Rc<str>> = 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<str>, Rc<str>> = 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<str>, Rc<str>> = 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<str>, Rc<str>> = 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<str>, Rc<str>> = 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<str>, Rc<str>> = 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<str>, Rc<str>> = 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)?;

View File

@ -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<T> TabWelcome<T> {
let globals = layout.state.globals.clone();
for i in 0..PAGE_COUNT {
let mut vars = HashMap::<Rc<str>, Rc<str>>::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(())

View File

@ -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) = &params.entry.icon_path {
let mut template_params: HashMap<Rc<str>, Rc<str>> = 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",

View File

@ -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 = &params.card.properties.device_description;
let disp_name = get_profile_display_name(&params.card.active_profile, params.card);
let mut par = HashMap::<Rc<str>, Rc<str>>::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<str>, Rc<str>>::new();
let mut par = TemplateParams::new();
if let Some(disp) = &params.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", &params.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"
},
);

View File

@ -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<str>, Rc<str>>::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)?;

View File

@ -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<Task>,
already_downloaded: bool,
) -> anyhow::Result<()> {
let mut t = HashMap::<Rc<str>, Rc<str>>::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::<ComponentButton>("button")?;

View File

@ -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<str>, Rc<str>>::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(())

View File

@ -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<S: 'static>(
};
// 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());
}
}

View File

@ -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,

View File

@ -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

View File

@ -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 =

View File

@ -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<str>, Rc<str>> = 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()));
}
_ => {}
}

View File

@ -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<str>, Rc<str>>);
struct ParserFile {
path: AssetPathOwned,
document: Rc<XmlDocument>,
template_parameters: HashMap<Rc<str>, Rc<str>>,
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<RefMut<'a, T>>;
}
impl TemplateParams {
pub fn new() -> Self {
Self(HashMap::new())
}
pub const fn from_hashmap(map: HashMap<Rc<str>, Rc<str>>) -> Self {
Self(map)
}
pub fn insert(&mut self, key: &str, value: &str) -> Option<Rc<str>> {
self.0.insert(Rc::from(key), Rc::from(value))
}
pub fn insert_rc(&mut self, key: &str, value: Rc<str>) -> Option<Rc<str>> {
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<str>, Rc<str>>,
template_parameters: TemplateParams,
) -> anyhow::Result<ParserData> {
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<str>, Rc<str>>,
template_parameters: TemplateParams,
) -> anyhow::Result<ParserData> {
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<str>, Rc<str>>,
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<str>, Rc<str>>,
template_params: &TemplateParams,
) -> anyhow::Result<Vec<context_menu::Cell>> {
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<Template>,
template_parameters: HashMap<Rc<str>, Rc<str>>,
template_parameters: TemplateParams,
file: &ParserFile,
ctx: &mut ParserContext,
parent_id: WidgetID,
@ -685,10 +706,16 @@ fn parse_widget_other(
return Ok(()); // not critical
};
let template_parameters: HashMap<Rc<str>, Rc<str>> =
let template_params: HashMap<Rc<str>, Rc<str>> =
attribs.iter().map(|a| (a.attrib.clone(), a.value.clone())).collect();
parse_widget_other_internal(&template, template_parameters, file, ctx, parent_id)
parse_widget_other_internal(
&template,
TemplateParams::from_hashmap(template_params),
file,
ctx,
parent_id,
)
}
fn parse_tag_include(
@ -788,7 +815,7 @@ fn parse_tag_var<'a>(ctx: &mut ParserContext, tag_name: &str, node: roxmltree::N
ctx.insert_var(key, value);
}
pub fn replace_vars(input: &str, vars: &HashMap<Rc<str>, Rc<str>>) -> Rc<str> {
pub fn replace_vars(input: &str, vars: &TemplateParams) -> Rc<str> {
let re = regex::Regex::new(r"\$\{([^}]*)\}").unwrap();
/*if !vars.is_empty() {
@ -798,7 +825,7 @@ pub fn replace_vars(input: &str, vars: &HashMap<Rc<str>, Rc<str>>) -> Rc<str> {
let out = re.replace_all(input, |captures: &regex::Captures| {
let input_var = &captures[1];
if let Some(replacement) = vars.get(input_var) {
if let Some(replacement) = vars.0.get(input_var) {
replacement.clone()
} else {
// failed to find var, return an empty string
@ -811,12 +838,7 @@ pub fn replace_vars(input: &str, vars: &HashMap<Rc<str>, Rc<str>>) -> Rc<str> {
#[allow(clippy::manual_strip)]
#[allow(clippy::single_match_else)]
fn process_attrib(
template_parameters: &HashMap<Rc<str>, Rc<str>>,
ctx: &ParserContext,
key: &str,
value: &str,
) -> AttribPair {
fn process_attrib(template_parameters: &TemplateParams, ctx: &ParserContext, key: &str, value: &str) -> AttribPair {
if value.starts_with('~') {
let name = &value[1..];
@ -1299,7 +1321,7 @@ fn get_doc_from_asset_path(
let file = ParserFile {
path: asset_path.to_owned(),
document: document.clone(),
template_parameters: Default::default(),
template_parameters: TemplateParams::new(),
};
Ok((file, tag_layout.id()))

View File

@ -1,17 +1,15 @@
use std::{collections::HashMap, rc::Rc};
use glam::Vec2;
use crate::{
assets::AssetPath,
components::{ComponentTrait, button::ComponentButton},
globals::WguiGlobals,
i18n::Translation,
layout::Layout,
parser::{self, Fetchable, ParserState},
parser::{self, Fetchable, ParserState, TemplateParams},
task::Tasks,
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra},
};
use glam::Vec2;
use std::rc::Rc;
#[derive(Clone)]
pub struct Cell {
@ -25,7 +23,7 @@ pub enum Blueprint {
Cells(Vec<Cell>),
Template {
template_name: Rc<str>,
template_params: HashMap<Rc<str>, Rc<str>>,
template_params: TemplateParams,
},
}
@ -111,10 +109,10 @@ impl ContextMenu {
let id_buttons = inner_parser.get_widget_id("buttons")?;
for (idx, cell) in cells.iter().enumerate() {
let mut par = HashMap::new();
par.insert(Rc::from("text"), cell.title.generate(&mut globals.i18n()));
let mut par = TemplateParams::new();
par.insert_rc("text", cell.title.generate(&mut globals.i18n()));
if let Some(tooltip) = cell.tooltip.as_ref() {
par.insert(Rc::from("tooltip_str"), tooltip.generate(&mut globals.i18n()));
par.insert_rc("tooltip_str", tooltip.generate(&mut globals.i18n()));
}
let mut data_cell = inner_parser.parse_template_only(&doc_params, "Cell", layout, id_buttons, par)?;