diff --git a/wayvr/src/assets/gui/keyboard.xml b/wayvr/src/assets/gui/keyboard.xml
index 6378a1b..be35e18 100644
--- a/wayvr/src/assets/gui/keyboard.xml
+++ b/wayvr/src/assets/gui/keyboard.xml
@@ -141,7 +141,7 @@
diff --git a/wayvr/src/gui/panel/mod.rs b/wayvr/src/gui/panel/mod.rs
index 519294b..88fe379 100644
--- a/wayvr/src/gui/panel/mod.rs
+++ b/wayvr/src/gui/panel/mod.rs
@@ -1,8 +1,9 @@
-use std::{cell::RefCell, rc::Rc};
+use std::{cell::RefCell, collections::HashMap, rc::Rc};
use anyhow::Context;
use button::setup_custom_button;
use glam::{Affine2, Vec2, vec2};
+use idmap::IdMap;
use label::setup_custom_label;
use wgui::{
assets::AssetPath,
@@ -67,6 +68,7 @@ pub struct GuiPanel {
pub on_notify: Option>,
pub initialized: bool,
pub doc_extra: Option,
+ pub extra_attribs: IdMap,
interaction_transform: Option,
context: WguiContext,
timestep: Timestep,
@@ -182,6 +184,7 @@ impl GuiPanel {
last_content_size: Vec2::ZERO,
doc_extra: Some(doc_params.extra),
custom_elems,
+ extra_attribs: Default::default(),
context_menu: Default::default(),
on_custom_attrib: params.on_custom_attrib,
on_custom_attrib_inner,
@@ -443,8 +446,8 @@ impl OverlayBackend for GuiPanel {
fn get_interaction_transform(&mut self) -> Option {
self.interaction_transform
}
- fn get_attrib(&self, _attrib: BackendAttrib) -> Option {
- None
+ fn get_attrib(&self, attrib: BackendAttrib) -> Option {
+ self.extra_attribs.get(&attrib).cloned()
}
fn set_attrib(&mut self, _app: &mut AppState, _value: BackendAttribValue) -> bool {
false
diff --git a/wayvr/src/gui/panel/overlay_list.rs b/wayvr/src/gui/panel/overlay_list.rs
index caa08ce..bf8ea98 100644
--- a/wayvr/src/gui/panel/overlay_list.rs
+++ b/wayvr/src/gui/panel/overlay_list.rs
@@ -14,7 +14,7 @@ use crate::windowing::{OverlayID, backend::OverlayEventData, window::OverlayCate
/// Helper for managing a list of overlays
/// Populates `id="panels_root"` with ``, ``, `` templates
/// Populates `id="apps_root"` with `` templates (optional)
-/// Uses the following parameters: `name` (All), `display` (Screen, Mirror), `icon` (App)
+/// Uses the following parameters: `name` (All), `display` (Screen, Mirror), `icon` (App, Panel)
pub struct OverlayList {
overlay_buttons: SecondaryMap>,
}
@@ -63,7 +63,16 @@ impl OverlayList {
);
("Mirror", panels_root)
}
- OverlayCategory::Panel => ("Panel", panels_root),
+ OverlayCategory::Panel => {
+ let icon: Rc = if let Some(icon) = meta.icon.as_ref() {
+ icon.to_string().into()
+ } else {
+ "edit/panel.svg".into()
+ };
+
+ params.insert("icon".into(), icon);
+ ("Panel", panels_root)
+ }
OverlayCategory::WayVR => {
params.insert(
"icon".into(),
diff --git a/wayvr/src/overlays/custom.rs b/wayvr/src/overlays/custom.rs
index 986fa9f..ee43ce9 100644
--- a/wayvr/src/overlays/custom.rs
+++ b/wayvr/src/overlays/custom.rs
@@ -1,7 +1,14 @@
-use std::{sync::Arc, time::Duration};
+use std::{
+ sync::{Arc, LazyLock},
+ time::Duration,
+};
use glam::{Affine3A, Quat, Vec3, vec3};
-use wlx_common::windowing::OverlayWindowState;
+use regex::Regex;
+use wlx_common::{
+ overlays::{BackendAttrib, BackendAttribValue},
+ windowing::OverlayWindowState,
+};
use crate::{
gui::{
@@ -15,7 +22,22 @@ use crate::{
},
};
-struct CustomPanelState {}
+static ENV_VAR_REGEX: LazyLock = LazyLock::new(|| {
+ Regex::new(r"\$\{([A-Z_][A-Z0-9_]*)}|\$([A-Z_][A-Z0-9_]*)").unwrap() // want panic
+});
+
+pub(super) fn expand_env_vars(template: &str) -> String {
+ ENV_VAR_REGEX
+ .replace_all(template, |caps: ®ex::Captures| {
+ let var_name = caps.get(1).or_else(|| caps.get(2)).unwrap().as_str();
+ std::env::var(var_name)
+ .inspect_err(|e| log::warn!("Unable to substitute env var {var_name}: {e:?}"))
+ .unwrap_or_default()
+ })
+ .into_owned()
+}
+
+struct CustomPanelState;
pub fn create_custom(app: &mut AppState, name: Arc) -> Option {
let params = NewGuiPanelParams {
@@ -24,10 +46,17 @@ pub fn create_custom(app: &mut AppState, name: Arc) -> Option