From 1d8b22d9922c345d6d2e8348132f7150c7aa5aad Mon Sep 17 00:00:00 2001 From: Aleksander Date: Sat, 4 Apr 2026 14:47:01 +0200 Subject: [PATCH 01/19] dash-frontend: "Skybox" tab --- dash-frontend/assets/gui/tab/settings.xml | 3 ++- dash-frontend/assets/lang/en.json | 1 + dash-frontend/src/tab/settings/mod.rs | 6 ++++++ dash-frontend/src/tab/settings/tab_look_and_feel.rs | 2 -- dash-frontend/src/tab/settings/tab_skybox.rs | 12 ++++++++++++ wayvr/src/backend/openxr/monado_state.rs | 6 ++++++ wayvr/src/state.rs | 5 ----- wayvr/src/subsystem/monado_metrics/metrics_fd.rs | 1 + 8 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 dash-frontend/src/tab/settings/tab_skybox.rs diff --git a/dash-frontend/assets/gui/tab/settings.xml b/dash-frontend/assets/gui/tab/settings.xml index 9ca21283..61583d75 100644 --- a/dash-frontend/assets/gui/tab/settings.xml +++ b/dash-frontend/assets/gui/tab/settings.xml @@ -48,6 +48,7 @@
+ @@ -59,4 +60,4 @@
- \ No newline at end of file + diff --git a/dash-frontend/assets/lang/en.json b/dash-frontend/assets/lang/en.json index 7d5e2e05..81fe3df7 100644 --- a/dash-frontend/assets/lang/en.json +++ b/dash-frontend/assets/lang/en.json @@ -99,6 +99,7 @@ "SCREEN_RENDER_DOWN_HELP": "Helps with aliasing on high-res screens", "SCROLL_SPEED": "Scroll speed", "SETS_ON_WATCH": "Sets on watch", + "SKYBOX": "Skybox", "SPACE_DRAG_MULTIPLIER": "Space drag multiplier", "SPACE_DRAG_UNLOCKED": "Allow space drag on all axes", "SPACE_ROTATE_UNLOCKED": "Allow space rotate on all axes", diff --git a/dash-frontend/src/tab/settings/mod.rs b/dash-frontend/src/tab/settings/mod.rs index 55eb02a9..0374fd95 100644 --- a/dash-frontend/src/tab/settings/mod.rs +++ b/dash-frontend/src/tab/settings/mod.rs @@ -33,6 +33,7 @@ mod tab_controls; mod tab_features; mod tab_look_and_feel; mod tab_misc; +mod tab_skybox; mod tab_troubleshooting; #[derive(Clone)] @@ -43,6 +44,7 @@ enum TabNameEnum { Misc, AutostartApps, Troubleshooting, + Skybox, } impl TabNameEnum { @@ -54,6 +56,7 @@ impl TabNameEnum { "misc" => Some(TabNameEnum::Misc), "autostart_apps" => Some(TabNameEnum::AutostartApps), "troubleshooting" => Some(TabNameEnum::Troubleshooting), + "skybox" => Some(TabNameEnum::Skybox), _ => None, } } @@ -533,6 +536,9 @@ impl TabSettings { TabNameEnum::Troubleshooting => { tab_troubleshooting::mount(&mut mp, root)?; } + TabNameEnum::Skybox => { + tab_skybox::mount(&mut mp, root)?; + } } Ok(()) diff --git a/dash-frontend/src/tab/settings/tab_look_and_feel.rs b/dash-frontend/src/tab/settings/tab_look_and_feel.rs index 6fe40420..ad2d1a5a 100644 --- a/dash-frontend/src/tab/settings/tab_look_and_feel.rs +++ b/dash-frontend/src/tab/settings/tab_look_and_feel.rs @@ -7,14 +7,12 @@ use wgui::layout::WidgetID; pub fn mount(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> { let c = options_category(mp, parent, "APP_SETTINGS.LOOK_AND_FEEL", "dashboard/palette.svg")?; options_dropdown::(mp, c, &SettingType::Language)?; - options_checkbox(mp, c, SettingType::OpaqueBackground)?; options_checkbox(mp, c, SettingType::HideUsername)?; options_checkbox(mp, c, SettingType::HideGrabHelp)?; options_slider_f32(mp, c, SettingType::UiAnimationSpeed, 0.5, 5.0, 0.1)?; // min, max, step options_slider_f32(mp, c, SettingType::UiGradientIntensity, 0.0, 1.0, 0.05)?; // min, max, step options_slider_f32(mp, c, SettingType::UiRoundMultiplier, 0.5, 5.0, 0.1)?; options_checkbox(mp, c, SettingType::SetsOnWatch)?; - options_checkbox(mp, c, SettingType::UseSkybox)?; options_slider_f32(mp, c, SettingType::GridOpacity, 0.0, 1.0, 0.05)?; // min, max, step options_checkbox(mp, c, SettingType::UsePassthrough)?; options_checkbox(mp, c, SettingType::Clock12h)?; diff --git a/dash-frontend/src/tab/settings/tab_skybox.rs b/dash-frontend/src/tab/settings/tab_skybox.rs new file mode 100644 index 00000000..41d05831 --- /dev/null +++ b/dash-frontend/src/tab/settings/tab_skybox.rs @@ -0,0 +1,12 @@ +use crate::tab::settings::{ + SettingType, + macros::{MacroParams, options_category, options_checkbox}, +}; +use wgui::layout::WidgetID; + +pub fn mount(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> { + let c = options_category(mp, parent, "APP_SETTINGS.SKYBOX", "dashboard/globe.svg")?; + options_checkbox(mp, c, SettingType::UseSkybox)?; + options_checkbox(mp, c, SettingType::OpaqueBackground)?; + Ok(()) +} diff --git a/wayvr/src/backend/openxr/monado_state.rs b/wayvr/src/backend/openxr/monado_state.rs index 418e5673..ff27fc00 100644 --- a/wayvr/src/backend/openxr/monado_state.rs +++ b/wayvr/src/backend/openxr/monado_state.rs @@ -19,6 +19,8 @@ impl MonadoState { Ok(res) } + #[allow(clippy::missing_const_for_fn)] + #[allow(clippy::unused_self)] pub fn update(&mut self) { #[cfg(feature = "feat-monado-metrics")] if let Some(metrics) = &mut self.metrics { @@ -30,6 +32,10 @@ impl MonadoState { } } + #[allow(clippy::missing_const_for_fn)] + #[allow(clippy::unused_self)] + #[allow(clippy::unnecessary_wraps)] + #[cfg(feature = "feat-monado-metrics")] pub fn set_metrics_enabled(&mut self, enabled: bool) -> anyhow::Result<()> { #[cfg(feature = "feat-monado-metrics")] { diff --git a/wayvr/src/state.rs b/wayvr/src/state.rs index 9e8d7da2..051427c3 100644 --- a/wayvr/src/state.rs +++ b/wayvr/src/state.rs @@ -9,7 +9,6 @@ use wgui::{ drawing, font_config::WguiFontConfig, gfx::WGfx, globals::WguiGlobals, parser::parse_color_hex, renderer_vk::context::SharedContext as WSharedContext, }; -use wlx_common::async_executor::AsyncExecutor; use wlx_common::locale::WayVRLangProvider; use wlx_common::{ audio, @@ -38,7 +37,6 @@ use crate::{ pub struct AppState { pub session: AppSession, pub tasks: TaskContainer, - pub executor: AsyncExecutor, pub gfx: Arc, pub gfx_extras: WGfxExtras, @@ -157,12 +155,9 @@ impl AppState { let lang_provider = WayVRLangProvider::from_config(&session.config); - let executor = Rc::new(smol::LocalExecutor::new()); - Ok(Self { session, tasks, - executor, gfx, gfx_extras, hid_provider, diff --git a/wayvr/src/subsystem/monado_metrics/metrics_fd.rs b/wayvr/src/subsystem/monado_metrics/metrics_fd.rs index 983a39c9..4e349ca1 100644 --- a/wayvr/src/subsystem/monado_metrics/metrics_fd.rs +++ b/wayvr/src/subsystem/monado_metrics/metrics_fd.rs @@ -8,6 +8,7 @@ use crate::subsystem::monado_metrics::proto; pub struct MonadoMetricsFd { stream_reader: UnixStream, + #[allow(dead_code)] stream_writer: UnixStream, records: VecDeque, From 7f822b6787c1b2d313f1989def092aca12dafad4 Mon Sep 17 00:00:00 2001 From: Aleksander Date: Sat, 4 Apr 2026 21:50:35 +0200 Subject: [PATCH 02/19] dash-frontend: Skymap catalog fetch --- dash-frontend/assets/dashboard/download.svg | 1 + dash-frontend/assets/gui/view/skymap_list.xml | 11 ++ dash-frontend/assets/lang/en.json | 2 + dash-frontend/src/tab/settings/mod.rs | 38 +++++- dash-frontend/src/tab/settings/tab_skybox.rs | 40 ++++-- dash-frontend/src/util/http_client.rs | 10 ++ dash-frontend/src/util/mod.rs | 1 + dash-frontend/src/util/networking/mod.rs | 4 + .../src/util/networking/skymap_catalog.rs | 42 +++++++ dash-frontend/src/views/mod.rs | 1 + dash-frontend/src/views/skymap_list.rs | 117 ++++++++++++++++++ wlx-common/src/config_io.rs | 17 +++ 12 files changed, 273 insertions(+), 11 deletions(-) create mode 100644 dash-frontend/assets/dashboard/download.svg create mode 100644 dash-frontend/assets/gui/view/skymap_list.xml create mode 100644 dash-frontend/src/util/networking/mod.rs create mode 100644 dash-frontend/src/util/networking/skymap_catalog.rs create mode 100644 dash-frontend/src/views/skymap_list.rs diff --git a/dash-frontend/assets/dashboard/download.svg b/dash-frontend/assets/dashboard/download.svg new file mode 100644 index 00000000..f446969b --- /dev/null +++ b/dash-frontend/assets/dashboard/download.svg @@ -0,0 +1 @@ + diff --git a/dash-frontend/assets/gui/view/skymap_list.xml b/dash-frontend/assets/gui/view/skymap_list.xml new file mode 100644 index 00000000..00465088 --- /dev/null +++ b/dash-frontend/assets/gui/view/skymap_list.xml @@ -0,0 +1,11 @@ + + +
+
+
+
+
+ + diff --git a/dash-frontend/assets/lang/en.json b/dash-frontend/assets/lang/en.json index 81fe3df7..122d8206 100644 --- a/dash-frontend/assets/lang/en.json +++ b/dash-frontend/assets/lang/en.json @@ -53,6 +53,7 @@ "DELETE_ALL_CONFIGS_HELP": "Remove all configuration files from conf.d", "DOUBLE_CURSOR_FIX": "Double cursor fix", "DOUBLE_CURSOR_FIX_HELP": "Enable this if you see 2 cursors", + "DOWNLOAD_SKYMAPS": "Download skymaps", "FEATURES": "Features", "FOCUS_FOLLOWS_MOUSE_MODE": "Mouse move on trigger touch", "HANDSFREE_POINTER": "Handsfree mode", @@ -72,6 +73,7 @@ "LONG_PRESS_DURATION": "Long press duration", "LOOK_AND_FEEL": "Look & Feel", "MISC": "Miscellaneous", + "NO_SKYMAPS_FOUND": "No skymaps found", "NOTIFICATIONS_ENABLED": "Enable notifications", "NOTIFICATIONS_SOUND_ENABLED": "Notification sounds", "OPAQUE_BACKGROUND": "Opaque background", diff --git a/dash-frontend/src/tab/settings/mod.rs b/dash-frontend/src/tab/settings/mod.rs index 0374fd95..1367f193 100644 --- a/dash-frontend/src/tab/settings/mod.rs +++ b/dash-frontend/src/tab/settings/mod.rs @@ -20,7 +20,9 @@ use wgui::{ }, windowing::context_menu::{self, Blueprint, ContextMenu, TickResult}, }; -use wlx_common::{config::GeneralConfig, config_io::ConfigRoot, dash_interface::RecenterMode}; +use wlx_common::{ + async_executor::AsyncExecutor, config::GeneralConfig, config_io::ConfigRoot, dash_interface::RecenterMode, +}; use crate::{ frontend::{Frontend, FrontendTask}, @@ -78,12 +80,31 @@ enum Task { SetTab(TabNameEnum), } +struct SettingsMountParams<'a> { + mp: &'a mut MacroParams<'a>, + globals: &'a WguiGlobals, + parent_id: WidgetID, +} + +struct SettingsUpdateParams<'a> { + layout: &'a mut Layout, + executor: &'a AsyncExecutor, +} + +trait SettingsTab { + fn update(&mut self, _par: SettingsUpdateParams) -> anyhow::Result<()> { + Ok(()) + } +} + pub struct TabSettings { pub state: ParserState, app_button_ids: Vec>, context_menu: ContextMenu, + current_tab: Option>, + tasks: Tasks, marker: PhantomData, } @@ -94,6 +115,13 @@ impl Tab for TabSettings { } fn update(&mut self, frontend: &mut Frontend, _time_ms: u32, data: &mut T) -> anyhow::Result<()> { + if let Some(tab) = &mut self.current_tab { + tab.update(SettingsUpdateParams { + layout: &mut frontend.layout, + executor: &frontend.executor, + })?; + } + let mut changed = false; for task in self.tasks.drain() { match task { @@ -507,6 +535,7 @@ impl TabSettings { let root = self.state.get_widget_id("settings_root")?; frontend.layout.remove_children(root); let globals = frontend.layout.state.globals.clone(); + self.current_tab = None; let mut mp = MacroParams { layout: &mut frontend.layout, @@ -537,7 +566,11 @@ impl TabSettings { tab_troubleshooting::mount(&mut mp, root)?; } TabNameEnum::Skybox => { - tab_skybox::mount(&mut mp, root)?; + self.current_tab = Some(Box::new(tab_skybox::State::mount(SettingsMountParams { + mp: &mut mp, + globals: &globals, + parent_id: root, + })?)); } } @@ -572,6 +605,7 @@ impl TabSettings { state: parser_state, marker: PhantomData, context_menu: ContextMenu::default(), + current_tab: None, }) } } diff --git a/dash-frontend/src/tab/settings/tab_skybox.rs b/dash-frontend/src/tab/settings/tab_skybox.rs index 41d05831..3738f1aa 100644 --- a/dash-frontend/src/tab/settings/tab_skybox.rs +++ b/dash-frontend/src/tab/settings/tab_skybox.rs @@ -1,12 +1,34 @@ -use crate::tab::settings::{ - SettingType, - macros::{MacroParams, options_category, options_checkbox}, +use crate::{ + tab::settings::{ + SettingType, SettingsMountParams, SettingsTab, + macros::{options_category, options_checkbox}, + }, + views::skymap_list, }; -use wgui::layout::WidgetID; -pub fn mount(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> { - let c = options_category(mp, parent, "APP_SETTINGS.SKYBOX", "dashboard/globe.svg")?; - options_checkbox(mp, c, SettingType::UseSkybox)?; - options_checkbox(mp, c, SettingType::OpaqueBackground)?; - Ok(()) +pub struct State { + skymap_list: skymap_list::View, +} + +impl SettingsTab for State { + fn update(&mut self, par: super::SettingsUpdateParams) -> anyhow::Result<()> { + self.skymap_list.update(par.layout, par.executor)?; + Ok(()) + } +} + +impl State { + pub fn mount(par: SettingsMountParams) -> anyhow::Result { + let c = options_category(par.mp, par.parent_id, "APP_SETTINGS.SKYBOX", "dashboard/globe.svg")?; + options_checkbox(par.mp, c, SettingType::UseSkybox)?; + options_checkbox(par.mp, c, SettingType::OpaqueBackground)?; + + let skymap_list = skymap_list::View::new(skymap_list::Params { + globals: par.globals.clone(), + layout: par.mp.layout, + parent_id: c, + })?; + + Ok(Self { skymap_list }) + } } diff --git a/dash-frontend/src/util/http_client.rs b/dash-frontend/src/util/http_client.rs index 875d509e..69a018f2 100644 --- a/dash-frontend/src/util/http_client.rs +++ b/dash-frontend/src/util/http_client.rs @@ -18,6 +18,16 @@ pub struct HttpClientResponse { pub data: Vec, } +impl HttpClientResponse { + pub fn as_json(self) -> anyhow::Result + where + T: for<'a> serde::Deserialize<'a>, + { + let utf8 = str::from_utf8(&self.data)?; + Ok(serde_json::from_str::(utf8)?) + } +} + pub async fn get(executor: &AsyncExecutor, url: &str) -> anyhow::Result { log::info!("fetching URL \"{}\"", url); diff --git a/dash-frontend/src/util/mod.rs b/dash-frontend/src/util/mod.rs index e5290607..1bd01c98 100644 --- a/dash-frontend/src/util/mod.rs +++ b/dash-frontend/src/util/mod.rs @@ -1,5 +1,6 @@ pub mod cached_fetcher; pub mod http_client; +pub mod networking; pub mod pactl_wrapper; pub mod popup_manager; pub mod steam_utils; diff --git a/dash-frontend/src/util/networking/mod.rs b/dash-frontend/src/util/networking/mod.rs new file mode 100644 index 00000000..5f6c078e --- /dev/null +++ b/dash-frontend/src/util/networking/mod.rs @@ -0,0 +1,4 @@ +pub mod skymap_catalog; + +// pub const WAYVR_ROOT_URL: &'static str = "https://wayvr.org"; +pub const WAYVR_SKYMAPS_ROOT: &'static str = "https://wayvr.org/skymaps"; diff --git a/dash-frontend/src/util/networking/skymap_catalog.rs b/dash-frontend/src/util/networking/skymap_catalog.rs new file mode 100644 index 00000000..498c12f9 --- /dev/null +++ b/dash-frontend/src/util/networking/skymap_catalog.rs @@ -0,0 +1,42 @@ +#![allow(dead_code)] // TODO: Remove later +use serde::Deserialize; +use wlx_common::async_executor::AsyncExecutor; + +use crate::util::{http_client, networking}; + +#[derive(Clone, Debug, Deserialize)] +pub struct SkymapCatalogEntryFiles { + pub size_16k: Option, // "my_skymap_16k.png" + pub size_8k: Option, // "my_skymap_8k.png" + pub size_4k: Option, // "my_skymap_4k.png" + pub size_2k: String, // we should have *at least* this + pub preview: String, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct SkymapCatalogEntry { + pub uuid: String, + pub created_at: String, + pub modified_at: String, + pub entry_version: u32, + pub name: String, + pub description: String, + pub author: String, + pub files: SkymapCatalogEntryFiles, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct SkymapCatalog { + pub version: u32, + pub r#type: String, + pub entries: Vec, +} + +pub async fn request_catalog(executor: &AsyncExecutor) -> anyhow::Result { + log::info!("Fetching skymap list"); + + let res = http_client::get(executor, &format!("{}/catalog.json", networking::WAYVR_SKYMAPS_ROOT)).await?; + let catalog = res.as_json::()?; + + Ok(catalog) +} diff --git a/dash-frontend/src/views/mod.rs b/dash-frontend/src/views/mod.rs index d2cd9369..2f832208 100644 --- a/dash-frontend/src/views/mod.rs +++ b/dash-frontend/src/views/mod.rs @@ -4,3 +4,4 @@ pub mod game_cover; pub mod game_launcher; pub mod game_list; pub mod running_games_list; +pub mod skymap_list; diff --git a/dash-frontend/src/views/skymap_list.rs b/dash-frontend/src/views/skymap_list.rs new file mode 100644 index 00000000..9a968f75 --- /dev/null +++ b/dash-frontend/src/views/skymap_list.rs @@ -0,0 +1,117 @@ +use wgui::{ + assets::AssetPath, + components::button::ComponentButton, + globals::WguiGlobals, + i18n::Translation, + layout::{Layout, WidgetID}, + parser::{Fetchable, ParseDocumentParams, ParserState}, + task::Tasks, +}; +use wlx_common::{async_executor::AsyncExecutor, config_io}; + +use crate::util::{networking, wgui_simple}; + +#[derive(Clone)] +enum Task { + DownloadSkymaps, + SetSkymapCatalog(Result), + Refresh, +} + +pub struct Params<'a> { + pub globals: WguiGlobals, + pub layout: &'a mut Layout, + pub parent_id: WidgetID, +} + +pub struct View { + #[allow(dead_code)] + parser_state: ParserState, + tasks: Tasks, + list_parent: WidgetID, +} + +impl View { + pub fn new(params: Params) -> anyhow::Result { + let doc_params = &ParseDocumentParams { + globals: params.globals.clone(), + path: AssetPath::BuiltIn("gui/view/skymap_list.xml"), + extra: Default::default(), + }; + + let parser_state = wgui::parser::parse_from_assets(doc_params, params.layout, params.parent_id)?; + let list_parent = parser_state.fetch_widget(¶ms.layout.state, "list_parent")?.id; + let tasks = Tasks::new(); + + tasks.push(Task::Refresh); + + tasks.handle_button( + &parser_state.fetch_component_as::("btn_download_skymaps")?, + Task::DownloadSkymaps, + ); + + tasks.handle_button( + &parser_state.fetch_component_as::("btn_refresh")?, + Task::Refresh, + ); + + Ok(Self { + parser_state, + tasks, + list_parent, + }) + } + + pub fn update(&mut self, layout: &mut Layout, executor: &AsyncExecutor) -> anyhow::Result<()> { + loop { + let tasks = self.tasks.drain(); + if tasks.is_empty() { + break; + } + for task in tasks { + match task { + Task::DownloadSkymaps => { + self.download_skymaps(executor)?; + } + Task::Refresh => { + self.refresh(layout)?; + } + Task::SetSkymapCatalog(skymap_catalog) => { + log::info!("{:?}", skymap_catalog); + } + } + } + } + + Ok(()) + } + + async fn skymap_catalog_request_wrapper(tasks: Tasks, executor: AsyncExecutor) { + let res = networking::skymap_catalog::request_catalog(&executor).await; + tasks.push(Task::SetSkymapCatalog(res.map_err(|e| format!("{}", e)))); + } + + fn download_skymaps(&mut self, executor: &AsyncExecutor) -> anyhow::Result<()> { + let fut = View::skymap_catalog_request_wrapper(self.tasks.clone(), executor.clone()); + executor.spawn(fut).detach(); + Ok(()) + } + + fn refresh(&mut self, layout: &mut Layout) -> anyhow::Result<()> { + let skymaps_uuids = config_io::get_skymaps_uuids().unwrap_or_default(); + log::info!("skymap uuids {:?}", skymaps_uuids); + + layout.remove_children(self.list_parent); + + if skymaps_uuids.is_empty() { + wgui_simple::create_label( + layout, + self.list_parent, + Translation::from_translation_key("APP_SETTINGS.NO_SKYMAPS_FOUND"), + )?; + return Ok(()); + } + + Ok(()) + } +} diff --git a/wlx-common/src/config_io.rs b/wlx-common/src/config_io.rs index 961e4b1a..7976a5de 100644 --- a/wlx-common/src/config_io.rs +++ b/wlx-common/src/config_io.rs @@ -21,6 +21,23 @@ pub fn get_config_root() -> PathBuf { CONFIG_ROOT_PATH.clone() } +pub fn get_skymaps_root() -> PathBuf { + get_config_root().join("skymaps") +} + +pub fn get_skymaps_uuids() -> anyhow::Result> { + let data = std::fs::read_to_string(get_skymaps_root().join("skymaps.txt"))?; + Ok(data.lines().filter(|line| !line.is_empty()).map(String::from).collect()) +} + +pub fn set_skymaps_uuids(uuids: &[String]) -> anyhow::Result<()> { + let skymaps_root = get_skymaps_root(); + let _ = std::fs::create_dir_all(&skymaps_root); + let data = String::from_iter(uuids.iter().map(|uuid| format!("{}\n", uuid))); + std::fs::write(skymaps_root.join("skymaps.txt"), data)?; + Ok(()) +} + impl ConfigRoot { pub fn get_conf_d_path(&self) -> PathBuf { get_config_root().join(match self { From a3460fbe7055f1ef2b3f927fee44283018c62a6c Mon Sep 17 00:00:00 2001 From: Aleksander Date: Sat, 4 Apr 2026 22:08:44 +0200 Subject: [PATCH 03/19] dash-frontend: use SettingsTab trait for each settings tab --- dash-frontend/src/tab/settings/mod.rs | 27 +++--- .../src/tab/settings/tab_autostart_apps.rs | 35 ++++--- .../src/tab/settings/tab_controls.rs | 48 ++++++---- .../src/tab/settings/tab_features.rs | 37 ++++---- .../src/tab/settings/tab_look_and_feel.rs | 42 +++++---- dash-frontend/src/tab/settings/tab_misc.rs | 27 +++--- .../src/tab/settings/tab_troubleshooting.rs | 92 ++++++++++--------- 7 files changed, 183 insertions(+), 125 deletions(-) diff --git a/dash-frontend/src/tab/settings/mod.rs b/dash-frontend/src/tab/settings/mod.rs index 1367f193..3194e11e 100644 --- a/dash-frontend/src/tab/settings/mod.rs +++ b/dash-frontend/src/tab/settings/mod.rs @@ -546,31 +546,36 @@ impl TabSettings { idx: 9001, }; + let settings_mount_params = SettingsMountParams { + mp: &mut mp, + globals: &globals, + parent_id: root, + }; + match name { TabNameEnum::LookAndFeel => { - tab_look_and_feel::mount(&mut mp, root)?; + self.current_tab = Some(Box::new(tab_look_and_feel::State::mount(settings_mount_params)?)); } TabNameEnum::Features => { - tab_features::mount(&mut mp, root)?; + self.current_tab = Some(Box::new(tab_features::State::mount(settings_mount_params)?)); } TabNameEnum::Controls => { - tab_controls::mount(&mut mp, root)?; + self.current_tab = Some(Box::new(tab_controls::State::mount(settings_mount_params)?)); } TabNameEnum::Misc => { - tab_misc::mount(&mut mp, root)?; + self.current_tab = Some(Box::new(tab_misc::State::mount(settings_mount_params)?)); } TabNameEnum::AutostartApps => { - tab_autostart_apps::mount(&mut mp, root, &mut self.app_button_ids)?; + self.current_tab = Some(Box::new(tab_autostart_apps::State::mount( + settings_mount_params, + &mut self.app_button_ids, + )?)); } TabNameEnum::Troubleshooting => { - tab_troubleshooting::mount(&mut mp, root)?; + self.current_tab = Some(Box::new(tab_troubleshooting::State::mount(settings_mount_params)?)); } TabNameEnum::Skybox => { - self.current_tab = Some(Box::new(tab_skybox::State::mount(SettingsMountParams { - mp: &mut mp, - globals: &globals, - parent_id: root, - })?)); + self.current_tab = Some(Box::new(tab_skybox::State::mount(settings_mount_params)?)); } } diff --git a/dash-frontend/src/tab/settings/tab_autostart_apps.rs b/dash-frontend/src/tab/settings/tab_autostart_apps.rs index 6483fc94..79496d4e 100644 --- a/dash-frontend/src/tab/settings/tab_autostart_apps.rs +++ b/dash-frontend/src/tab/settings/tab_autostart_apps.rs @@ -1,19 +1,32 @@ use std::rc::Rc; -use crate::tab::settings::macros::{MacroParams, options_autostart_app, options_category}; -use wgui::layout::WidgetID; +use crate::tab::settings::{ + SettingsMountParams, SettingsTab, + macros::{options_autostart_app, options_category}, +}; -pub fn mount(mp: &mut MacroParams, parent: WidgetID, app_button_ids: &mut Vec>) -> anyhow::Result<()> { - *app_button_ids = Vec::new(); +pub struct State {} - if !mp.config.autostart_apps.is_empty() { - let c = options_category(mp, parent, "APP_SETTINGS.AUTOSTART_APPS", "dashboard/apps.svg")?; +impl SettingsTab for State {} - // todo: prevent clone - let autostart_apps = mp.config.autostart_apps.clone(); - for app in autostart_apps { - options_autostart_app(mp, c, &app.name, app_button_ids)?; +impl State { + pub fn mount(par: SettingsMountParams, app_button_ids: &mut Vec>) -> anyhow::Result { + *app_button_ids = Vec::new(); + + if !par.mp.config.autostart_apps.is_empty() { + let c = options_category( + par.mp, + par.parent_id, + "APP_SETTINGS.AUTOSTART_APPS", + "dashboard/apps.svg", + )?; + + // todo: prevent clone + let autostart_apps = par.mp.config.autostart_apps.clone(); + for app in autostart_apps { + options_autostart_app(par.mp, c, &app.name, app_button_ids)?; + } } + Ok(State {}) } - Ok(()) } diff --git a/dash-frontend/src/tab/settings/tab_controls.rs b/dash-frontend/src/tab/settings/tab_controls.rs index 27b1f10b..a8ba00f3 100644 --- a/dash-frontend/src/tab/settings/tab_controls.rs +++ b/dash-frontend/src/tab/settings/tab_controls.rs @@ -1,23 +1,33 @@ use crate::tab::settings::{ - SettingType, - macros::{MacroParams, options_category, options_checkbox, options_dropdown, options_slider_f32, options_slider_i32}, + SettingType, SettingsMountParams, SettingsTab, + macros::{options_category, options_checkbox, options_dropdown, options_slider_f32, options_slider_i32}, }; -use wgui::layout::WidgetID; -pub fn mount(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> { - let c = options_category(mp, parent, "APP_SETTINGS.CONTROLS", "dashboard/controller.svg")?; - options_dropdown::(mp, c, &SettingType::KeyboardMiddleClick)?; - options_dropdown::(mp, c, &SettingType::HandsfreePointer)?; - options_checkbox(mp, c, SettingType::FocusFollowsMouseMode)?; - options_checkbox(mp, c, SettingType::LeftHandedMouse)?; - options_checkbox(mp, c, SettingType::AllowSliding)?; - options_checkbox(mp, c, SettingType::InvertScrollDirectionX)?; - options_checkbox(mp, c, SettingType::InvertScrollDirectionY)?; - options_slider_f32(mp, c, SettingType::ScrollSpeed, 0.1, 5.0, 0.1)?; - options_slider_f32(mp, c, SettingType::LongPressDuration, 0.1, 2.0, 0.1)?; - options_slider_f32(mp, c, SettingType::PointerLerpFactor, 0.1, 1.0, 0.1)?; - options_slider_f32(mp, c, SettingType::XrClickSensitivity, 0.1, 1.0, 0.1)?; - options_slider_f32(mp, c, SettingType::XrClickSensitivityRelease, 0.1, 1.0, 0.1)?; - options_slider_i32(mp, c, SettingType::ClickFreezeTimeMs, 0, 500, 50)?; - Ok(()) +pub struct State {} + +impl SettingsTab for State {} + +impl State { + pub fn mount(par: SettingsMountParams) -> anyhow::Result { + let c = options_category( + par.mp, + par.parent_id, + "APP_SETTINGS.CONTROLS", + "dashboard/controller.svg", + )?; + options_dropdown::(par.mp, c, &SettingType::KeyboardMiddleClick)?; + options_dropdown::(par.mp, c, &SettingType::HandsfreePointer)?; + options_checkbox(par.mp, c, SettingType::FocusFollowsMouseMode)?; + options_checkbox(par.mp, c, SettingType::LeftHandedMouse)?; + options_checkbox(par.mp, c, SettingType::AllowSliding)?; + options_checkbox(par.mp, c, SettingType::InvertScrollDirectionX)?; + options_checkbox(par.mp, c, SettingType::InvertScrollDirectionY)?; + options_slider_f32(par.mp, c, SettingType::ScrollSpeed, 0.1, 5.0, 0.1)?; + options_slider_f32(par.mp, c, SettingType::LongPressDuration, 0.1, 2.0, 0.1)?; + options_slider_f32(par.mp, c, SettingType::PointerLerpFactor, 0.1, 1.0, 0.1)?; + options_slider_f32(par.mp, c, SettingType::XrClickSensitivity, 0.1, 1.0, 0.1)?; + options_slider_f32(par.mp, c, SettingType::XrClickSensitivityRelease, 0.1, 1.0, 0.1)?; + options_slider_i32(par.mp, c, SettingType::ClickFreezeTimeMs, 0, 500, 50)?; + Ok(State {}) + } } diff --git a/dash-frontend/src/tab/settings/tab_features.rs b/dash-frontend/src/tab/settings/tab_features.rs index 264a40fd..a01abdc4 100644 --- a/dash-frontend/src/tab/settings/tab_features.rs +++ b/dash-frontend/src/tab/settings/tab_features.rs @@ -1,20 +1,25 @@ use crate::tab::settings::{ - SettingType, - macros::{MacroParams, options_category, options_checkbox, options_slider_f32}, + SettingType, SettingsMountParams, SettingsTab, + macros::{options_category, options_checkbox, options_slider_f32}, }; -use wgui::layout::WidgetID; -pub fn mount(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> { - let c = options_category(mp, parent, "APP_SETTINGS.FEATURES", "dashboard/options.svg")?; - options_checkbox(mp, c, SettingType::NotificationsEnabled)?; - options_checkbox(mp, c, SettingType::NotificationsSoundEnabled)?; - options_checkbox(mp, c, SettingType::KeyboardSoundEnabled)?; - options_checkbox(mp, c, SettingType::KeyboardSwipeToTypeEnabled)?; - options_checkbox(mp, c, SettingType::SpaceDragUnlocked)?; - options_checkbox(mp, c, SettingType::SpaceRotateUnlocked)?; - options_slider_f32(mp, c, SettingType::SpaceDragMultiplier, -10.0, 10.0, 0.5)?; - options_checkbox(mp, c, SettingType::BlockGameInput)?; - options_checkbox(mp, c, SettingType::BlockGameInputIgnoreWatch)?; - options_checkbox(mp, c, SettingType::BlockPosesOnKbdInteraction)?; - Ok(()) +pub struct State {} + +impl SettingsTab for State {} + +impl State { + pub fn mount(par: SettingsMountParams) -> anyhow::Result { + let c = options_category(par.mp, par.parent_id, "APP_SETTINGS.FEATURES", "dashboard/options.svg")?; + options_checkbox(par.mp, c, SettingType::NotificationsEnabled)?; + options_checkbox(par.mp, c, SettingType::NotificationsSoundEnabled)?; + options_checkbox(par.mp, c, SettingType::KeyboardSoundEnabled)?; + options_checkbox(par.mp, c, SettingType::KeyboardSwipeToTypeEnabled)?; + options_checkbox(par.mp, c, SettingType::SpaceDragUnlocked)?; + options_checkbox(par.mp, c, SettingType::SpaceRotateUnlocked)?; + options_slider_f32(par.mp, c, SettingType::SpaceDragMultiplier, -10.0, 10.0, 0.5)?; + options_checkbox(par.mp, c, SettingType::BlockGameInput)?; + options_checkbox(par.mp, c, SettingType::BlockGameInputIgnoreWatch)?; + options_checkbox(par.mp, c, SettingType::BlockPosesOnKbdInteraction)?; + Ok(State {}) + } } diff --git a/dash-frontend/src/tab/settings/tab_look_and_feel.rs b/dash-frontend/src/tab/settings/tab_look_and_feel.rs index ad2d1a5a..55927880 100644 --- a/dash-frontend/src/tab/settings/tab_look_and_feel.rs +++ b/dash-frontend/src/tab/settings/tab_look_and_feel.rs @@ -1,20 +1,30 @@ use crate::tab::settings::{ - SettingType, - macros::{MacroParams, options_category, options_checkbox, options_dropdown, options_slider_f32}, + SettingType, SettingsMountParams, SettingsTab, + macros::{options_category, options_checkbox, options_dropdown, options_slider_f32}, }; -use wgui::layout::WidgetID; -pub fn mount(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> { - let c = options_category(mp, parent, "APP_SETTINGS.LOOK_AND_FEEL", "dashboard/palette.svg")?; - options_dropdown::(mp, c, &SettingType::Language)?; - options_checkbox(mp, c, SettingType::HideUsername)?; - options_checkbox(mp, c, SettingType::HideGrabHelp)?; - options_slider_f32(mp, c, SettingType::UiAnimationSpeed, 0.5, 5.0, 0.1)?; // min, max, step - options_slider_f32(mp, c, SettingType::UiGradientIntensity, 0.0, 1.0, 0.05)?; // min, max, step - options_slider_f32(mp, c, SettingType::UiRoundMultiplier, 0.5, 5.0, 0.1)?; - options_checkbox(mp, c, SettingType::SetsOnWatch)?; - options_slider_f32(mp, c, SettingType::GridOpacity, 0.0, 1.0, 0.05)?; // min, max, step - options_checkbox(mp, c, SettingType::UsePassthrough)?; - options_checkbox(mp, c, SettingType::Clock12h)?; - Ok(()) +pub struct State {} + +impl SettingsTab for State {} + +impl State { + pub fn mount(par: SettingsMountParams) -> anyhow::Result { + let c = options_category( + par.mp, + par.parent_id, + "APP_SETTINGS.LOOK_AND_FEEL", + "dashboard/palette.svg", + )?; + options_dropdown::(par.mp, c, &SettingType::Language)?; + options_checkbox(par.mp, c, SettingType::HideUsername)?; + options_checkbox(par.mp, c, SettingType::HideGrabHelp)?; + options_slider_f32(par.mp, c, SettingType::UiAnimationSpeed, 0.5, 5.0, 0.1)?; // min, max, step + options_slider_f32(par.mp, c, SettingType::UiGradientIntensity, 0.0, 1.0, 0.05)?; // min, max, step + options_slider_f32(par.mp, c, SettingType::UiRoundMultiplier, 0.5, 5.0, 0.1)?; + options_checkbox(par.mp, c, SettingType::SetsOnWatch)?; + options_slider_f32(par.mp, c, SettingType::GridOpacity, 0.0, 1.0, 0.05)?; // min, max, step + options_checkbox(par.mp, c, SettingType::UsePassthrough)?; + options_checkbox(par.mp, c, SettingType::Clock12h)?; + Ok(State {}) + } } diff --git a/dash-frontend/src/tab/settings/tab_misc.rs b/dash-frontend/src/tab/settings/tab_misc.rs index 9fa6f429..36b3e1b9 100644 --- a/dash-frontend/src/tab/settings/tab_misc.rs +++ b/dash-frontend/src/tab/settings/tab_misc.rs @@ -1,15 +1,20 @@ use crate::tab::settings::{ - SettingType, - macros::{MacroParams, options_category, options_checkbox, options_dropdown}, + SettingType, SettingsMountParams, SettingsTab, + macros::{options_category, options_checkbox, options_dropdown}, }; -use wgui::layout::WidgetID; -pub fn mount(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> { - let c = options_category(mp, parent, "APP_SETTINGS.MISC", "dashboard/blocks.svg")?; - options_dropdown::(mp, c, &SettingType::CaptureMethod)?; - options_checkbox(mp, c, SettingType::XwaylandByDefault)?; - options_checkbox(mp, c, SettingType::UprightScreenFix)?; - options_checkbox(mp, c, SettingType::DoubleCursorFix)?; - options_checkbox(mp, c, SettingType::ScreenRenderDown)?; - Ok(()) +pub struct State {} + +impl SettingsTab for State {} + +impl State { + pub fn mount(par: SettingsMountParams) -> anyhow::Result { + let c = options_category(par.mp, par.parent_id, "APP_SETTINGS.MISC", "dashboard/blocks.svg")?; + options_dropdown::(par.mp, c, &SettingType::CaptureMethod)?; + options_checkbox(par.mp, c, SettingType::XwaylandByDefault)?; + options_checkbox(par.mp, c, SettingType::UprightScreenFix)?; + options_checkbox(par.mp, c, SettingType::DoubleCursorFix)?; + options_checkbox(par.mp, c, SettingType::ScreenRenderDown)?; + Ok(State {}) + } } diff --git a/dash-frontend/src/tab/settings/tab_troubleshooting.rs b/dash-frontend/src/tab/settings/tab_troubleshooting.rs index 9e16fd4b..83a822c3 100644 --- a/dash-frontend/src/tab/settings/tab_troubleshooting.rs +++ b/dash-frontend/src/tab/settings/tab_troubleshooting.rs @@ -1,45 +1,55 @@ use crate::tab::settings::{ - Task, - macros::{MacroParams, options_category, options_danger_button}, + SettingsMountParams, SettingsTab, Task, + macros::{options_category, options_danger_button}, }; -use wgui::layout::WidgetID; -pub fn mount(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> { - let c = options_category(mp, parent, "APP_SETTINGS.TROUBLESHOOTING", "dashboard/cpu.svg")?; - options_danger_button( - mp, - c, - "APP_SETTINGS.RESET_PLAYSPACE", - "dashboard/recenter.svg", - Task::ResetPlayspace, - )?; - options_danger_button( - mp, - c, - "APP_SETTINGS.CLEAR_PIPEWIRE_TOKENS", - "dashboard/display.svg", - Task::ClearPipewireTokens, - )?; - options_danger_button( - mp, - c, - "APP_SETTINGS.CLEAR_SAVED_STATE", - "dashboard/binary.svg", - Task::ClearSavedState, - )?; - options_danger_button( - mp, - c, - "APP_SETTINGS.DELETE_ALL_CONFIGS", - "dashboard/circle.svg", - Task::DeleteAllConfigs, - )?; - options_danger_button( - mp, - c, - "APP_SETTINGS.RESTART_SOFTWARE", - "dashboard/refresh.svg", - Task::RestartSoftware, - )?; - Ok(()) +pub struct State {} + +impl SettingsTab for State {} + +impl State { + pub fn mount(par: SettingsMountParams) -> anyhow::Result { + let c = options_category( + par.mp, + par.parent_id, + "APP_SETTINGS.TROUBLESHOOTING", + "dashboard/cpu.svg", + )?; + options_danger_button( + par.mp, + c, + "APP_SETTINGS.RESET_PLAYSPACE", + "dashboard/recenter.svg", + Task::ResetPlayspace, + )?; + options_danger_button( + par.mp, + c, + "APP_SETTINGS.CLEAR_PIPEWIRE_TOKENS", + "dashboard/display.svg", + Task::ClearPipewireTokens, + )?; + options_danger_button( + par.mp, + c, + "APP_SETTINGS.CLEAR_SAVED_STATE", + "dashboard/binary.svg", + Task::ClearSavedState, + )?; + options_danger_button( + par.mp, + c, + "APP_SETTINGS.DELETE_ALL_CONFIGS", + "dashboard/circle.svg", + Task::DeleteAllConfigs, + )?; + options_danger_button( + par.mp, + c, + "APP_SETTINGS.RESTART_SOFTWARE", + "dashboard/refresh.svg", + Task::RestartSoftware, + )?; + Ok(State {}) + } } From f2dcdcc6c398e1d64f0e611fbed2d368763edd5e Mon Sep 17 00:00:00 2001 From: Aleksander Date: Mon, 6 Apr 2026 13:22:59 +0200 Subject: [PATCH 04/19] dash-frontend: list skymaps from the server (wip), loading spinner, wgui: animation bugfix --- dash-frontend/assets/dashboard/loading.svg | 1 + dash-frontend/assets/gui/t_loading.xml | 16 ++ .../assets/gui/view/download_skymaps.xml | 7 + dash-frontend/assets/gui/view/skymap_list.xml | 2 +- .../assets/gui/view/skymap_list_cell.xml | 26 ++++ dash-frontend/assets/lang/en.json | 1 + dash-frontend/src/frontend.rs | 23 ++- dash-frontend/src/tab/apps.rs | 49 ++---- dash-frontend/src/tab/settings/mod.rs | 6 +- dash-frontend/src/tab/settings/tab_skybox.rs | 1 + .../src/util/networking/skymap_catalog.rs | 20 ++- dash-frontend/src/util/popup_manager.rs | 78 ++++++++-- dash-frontend/src/util/wgui_simple.rs | 83 ++++++++++- dash-frontend/src/views/app_launcher.rs | 33 ++++- dash-frontend/src/views/download_skymaps.rs | 140 ++++++++++++++++++ dash-frontend/src/views/game_cover.rs | 11 ++ dash-frontend/src/views/game_launcher.rs | 30 ++++ dash-frontend/src/views/game_list.rs | 47 ++---- dash-frontend/src/views/mod.rs | 2 + dash-frontend/src/views/skymap_list.rs | 55 +++++-- dash-frontend/src/views/skymap_list_cell.rs | 56 +++++++ wgui/src/animation.rs | 8 +- wgui/src/task.rs | 9 +- 23 files changed, 594 insertions(+), 110 deletions(-) create mode 100644 dash-frontend/assets/dashboard/loading.svg create mode 100644 dash-frontend/assets/gui/t_loading.xml create mode 100644 dash-frontend/assets/gui/view/download_skymaps.xml create mode 100644 dash-frontend/assets/gui/view/skymap_list_cell.xml create mode 100644 dash-frontend/src/views/download_skymaps.rs create mode 100644 dash-frontend/src/views/skymap_list_cell.rs diff --git a/dash-frontend/assets/dashboard/loading.svg b/dash-frontend/assets/dashboard/loading.svg new file mode 100644 index 00000000..1c800c12 --- /dev/null +++ b/dash-frontend/assets/dashboard/loading.svg @@ -0,0 +1 @@ + diff --git a/dash-frontend/assets/gui/t_loading.xml b/dash-frontend/assets/gui/t_loading.xml new file mode 100644 index 00000000..ca8c5786 --- /dev/null +++ b/dash-frontend/assets/gui/t_loading.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/dash-frontend/assets/gui/view/download_skymaps.xml b/dash-frontend/assets/gui/view/download_skymaps.xml new file mode 100644 index 00000000..39c2711e --- /dev/null +++ b/dash-frontend/assets/gui/view/download_skymaps.xml @@ -0,0 +1,7 @@ + + +
+ +
+
+
diff --git a/dash-frontend/assets/gui/view/skymap_list.xml b/dash-frontend/assets/gui/view/skymap_list.xml index 00465088..c273f753 100644 --- a/dash-frontend/assets/gui/view/skymap_list.xml +++ b/dash-frontend/assets/gui/view/skymap_list.xml @@ -1,7 +1,7 @@
-
+