mirror of
https://github.com/wayvr-org/wayvr.git
synced 2026-10-28 12:02:22 +01:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b34595e489 | ||
|
|
330cf1bdeb | ||
|
|
19b7d85682 |
No files matched your search
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="defs1" />
|
||||
<path fill="currentColor" d="m 10,12 c 0,-1.104569 0.895431,-2 2,-2 1.104569,0 2,0.895431 2,2 0,1.104569 -0.895431,2 -2,2 -1.104569,0 -2,-0.895431 -2,-2" id="path1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 422 B |
@@ -6,6 +6,16 @@
|
||||
<var key="side_button_size" value="48" />
|
||||
</vars>
|
||||
|
||||
<blueprint name="context_menu_power_options">
|
||||
<context_menu>
|
||||
<cell translation="APP_SETTINGS.RESTART_WAYVR" action="restart" sprite_src_builtin="@/dashboard/refresh.svg"/>
|
||||
<cell translation="APP_SETTINGS.CLOSE_WAYVR" action="close" sprite_src_builtin="@/dashboard/close.svg"/>
|
||||
<separator/>
|
||||
<cell translation="POWER_OPTIONS.SUSPEND" action="suspend" sprite_src_builtin="@/dashboard/sleep.svg"/>
|
||||
<cell translation="POWER_OPTIONS.SHUTDOWN" action="shutdown" sprite_src_builtin="@/dashboard/power.svg"/>
|
||||
</context_menu>
|
||||
</blueprint>
|
||||
|
||||
<template name="SideButton">
|
||||
<Button
|
||||
id="${id}"
|
||||
@@ -136,6 +146,9 @@
|
||||
|
||||
<!-- Left bottom side -->
|
||||
<div margin_left="8">
|
||||
<Button id="btn_power" color="background(transparent)" border_color="background(transparent)" tooltip="POWER_OPTIONS.TITLE" tooltip_side="top">
|
||||
<sprite src_builtin="@/dashboard/power.svg" width="24" height="24" margin="8" />
|
||||
</Button>
|
||||
<Button id="btn_audio" color="background(transparent)" border_color="background(transparent)" tooltip="AUDIO.VOLUME" tooltip_side="top">
|
||||
<sprite src_builtin="@/dashboard/volume.svg" width="24" height="24" margin="8" />
|
||||
</Button>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<layout version="2">
|
||||
<template name="DialogBoxButton">
|
||||
<Button id="btn" translation="CLOSE_WINDOW" align_self="start" sprite_src_builtin="${icon}"/>
|
||||
<Button id="btn" translation="CLOSE_WINDOW" align_self="start" sprite_src_builtin="${icon}"
|
||||
text_size="16"
|
||||
padding_left="16" padding_right="16"
|
||||
padding_top="8" padding_bottom="8"/>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
|
||||
@@ -197,8 +197,6 @@
|
||||
"SAVE_PLAYSPACE_CENTER_HELP": "Nutze aktuellen Playspace für die Playspace-Reset-Belegung.",
|
||||
"RESET_PLAYSPACE_CENTER": "Playspace-Zentrum zurücksetzen",
|
||||
"RESET_PLAYSPACE_CENTER_HELP": "Vorheriges Playspace-Zentrum zurücksetzen.",
|
||||
"RESTART_SOFTWARE": "Software neu starten",
|
||||
"RESTART_SOFTWARE_HELP": "Einstellungen übernehmen, die einen Neustart erfordern",
|
||||
"ROUND_MULTIPLIER": "Abrundung der UI-Kanten",
|
||||
"SCREEN_RENDER_DOWN": "Bildschirm mit niedrigerer Auflösung rendern",
|
||||
"SCREEN_RENDER_DOWN_HELP": "Hilft gegen Treppeneffekte bei hochauflösenden Bildschirmen",
|
||||
@@ -263,7 +261,9 @@
|
||||
"TITLE": "Diagnose",
|
||||
"ENABLE_REBAR": "Aktiviere resizable bar in den BIOS-Einstellungen für optimale VR-Performance"
|
||||
},
|
||||
"TUTORIAL": "Tutorial"
|
||||
"TUTORIAL": "Tutorial",
|
||||
"RESTART_WAYVR": "WayVR neu starten",
|
||||
"CLOSE_WAYVR": "WayVR schließen"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Programmstarter",
|
||||
"APPLICATION_STARTED": "Anwendung gestartet",
|
||||
@@ -368,5 +368,13 @@
|
||||
"REMOVE_FROM_FAVOURITES": "Aus angehefteten Anwendungen entfernen",
|
||||
"EMPTY": "Leer",
|
||||
"INSTALLED": "Installiert",
|
||||
"NOT_INSTALLED": "Nicht installiert"
|
||||
"NOT_INSTALLED": "Nicht installiert",
|
||||
"POWER_OPTIONS": {
|
||||
"TITLE": "Energieoptionen",
|
||||
"SHUTDOWN": "Herunterfahren",
|
||||
"SUSPEND": "Ruhezustand",
|
||||
"SHUTDOWN_ARE_YOU_SURE": "Bist du sicher, dass du den Computer ausschalten willst?"
|
||||
},
|
||||
"YES": "Ja",
|
||||
"NO": "Nein"
|
||||
}
|
||||
@@ -208,8 +208,8 @@ APP_SETTINGS.SAVE_PLAYSPACE_CENTER,Save playspace center,"Button in Settings > S
|
||||
APP_SETTINGS.SAVE_PLAYSPACE_CENTER_HELP,Use current playspace for reset playspace binding.,"Tooltip for the Save playspace center button. ""Playspace"" was previously translated as ""${DEFINITIONS.PLAYSPACE}""."
|
||||
APP_SETTINGS.RESET_PLAYSPACE_CENTER,Reset playspace center,"Button in Settings > Space Drag tab. Clears the previously saved playspace center. ""Playspace"" was previously translated as ""${DEFINITIONS.PLAYSPACE}""."
|
||||
APP_SETTINGS.RESET_PLAYSPACE_CENTER_HELP,Clear previously set playspace center.,"Tooltip for the Reset playspace center button. ""Playspace"" was previously translated as ""${DEFINITIONS.PLAYSPACE}""."
|
||||
APP_SETTINGS.RESTART_SOFTWARE,Restart software,Button in Settings > Troubleshooting tab. Restarts the WayVR software to apply settings that require a restart.
|
||||
APP_SETTINGS.RESTART_SOFTWARE_HELP,Apply settings that require a restart,Tooltip for the Restart software button.
|
||||
APP_SETTINGS.RESTART_WAYVR,Restart WayVR,Button in Settings which restarts WayVR
|
||||
APP_SETTINGS.CLOSE_WAYVR,Close WayVR,Button in Settings which closes WayVR
|
||||
APP_SETTINGS.ROUND_MULTIPLIER,UI Edge roundness,Slider in Settings > Look & Feel tab. Controls how rounded the corners of UI elements appear (range 0.1-5.0).
|
||||
APP_SETTINGS.SCREEN_RENDER_DOWN,Render screen at lower resolution,Checkbox in Settings > Miscellaneous tab. Renders the captured desktop screen at a lower resolution to improve performance or reduce aliasing.
|
||||
APP_SETTINGS.SCREEN_RENDER_DOWN_HELP,Helps with aliasing on high-res screens,Tooltip for the lower-resolution screen render setting.
|
||||
@@ -336,6 +336,10 @@ MODIFICATION_DATE,Modification date,Column label in the remote skymap downloader
|
||||
MONADO_RUNTIME,Monado runtime,Tab label in the dashboard sidebar for the Monado runtime tab.
|
||||
LOADING,Loading...,Label in the loading spinner template used across the UI.
|
||||
POPUP_ADD_DISPLAY.RESOLUTION,Resolution,Label for the resolution field in the add display popup.
|
||||
POWER_OPTIONS.TITLE,"Power options","A button which allows the user to perform a specific power action"
|
||||
POWER_OPTIONS.SHUTDOWN,"Shut down","One of the power options: shuts down the computer"
|
||||
POWER_OPTIONS.SUSPEND,"Suspend","One of the power options: suspends the computer"
|
||||
POWER_OPTIONS.SHUTDOWN_ARE_YOU_SURE,"Are you sure you want to turn off your computer?","Question dialog box before shutting down the computer"
|
||||
PROCESS.FORCE_KILL,Force-kill,Tooltip on the kill button in the running games list.
|
||||
PROCESS.STOP,Stop,Tooltip on the stop button in the running games list.
|
||||
PROCESS_LIST,Process list,Tab name and group box title in the Monado runtime process list section.
|
||||
@@ -357,3 +361,5 @@ REMOVE_FROM_FAVOURITES,Remove from pinned apps,"Label on the unpin section in th
|
||||
EMPTY,Empty,Label shown in the pinned apps section when there are no pinned apps.
|
||||
INSTALLED,"Installed","Installation flag (installed/not installed)"
|
||||
NOT_INSTALLED,"Not installed","Installation flag (installed/not installed)"
|
||||
YES,"Yes","Just a simple 'Yes' message, button in the dialog box"
|
||||
NO,"No","Just a simple 'No' message, button in the dialog box"
|
||||
|
@@ -211,8 +211,8 @@
|
||||
"SAVE_PLAYSPACE_CENTER_HELP": "Use current playspace for reset playspace binding.",
|
||||
"RESET_PLAYSPACE_CENTER": "Reset playspace center",
|
||||
"RESET_PLAYSPACE_CENTER_HELP": "Clear previously set playspace center.",
|
||||
"RESTART_SOFTWARE": "Restart software",
|
||||
"RESTART_SOFTWARE_HELP": "Apply settings that require a restart",
|
||||
"RESTART_WAYVR": "Restart WayVR",
|
||||
"CLOSE_WAYVR": "Close WayVR",
|
||||
"ROUND_MULTIPLIER": "UI Edge roundness",
|
||||
"SCREEN_RENDER_DOWN": "Render screen at lower resolution",
|
||||
"SCREEN_RENDER_DOWN_HELP": "Helps with aliasing on high-res screens",
|
||||
@@ -346,6 +346,12 @@
|
||||
"POPUP_ADD_DISPLAY": {
|
||||
"RESOLUTION": "Resolution"
|
||||
},
|
||||
"POWER_OPTIONS": {
|
||||
"TITLE": "Power options",
|
||||
"SHUTDOWN": "Shut down",
|
||||
"SUSPEND": "Suspend",
|
||||
"SHUTDOWN_ARE_YOU_SURE": "Are you sure you want to turn off your computer?"
|
||||
},
|
||||
"PROCESS": {
|
||||
"FORCE_KILL": "Force-kill",
|
||||
"STOP": "Stop"
|
||||
@@ -368,5 +374,7 @@
|
||||
"REMOVE_FROM_FAVOURITES": "Remove from pinned apps",
|
||||
"EMPTY": "Empty",
|
||||
"INSTALLED": "Installed",
|
||||
"NOT_INSTALLED": "Not installed"
|
||||
"NOT_INSTALLED": "Not installed",
|
||||
"YES": "Yes",
|
||||
"NO": "No"
|
||||
}
|
||||
@@ -197,8 +197,6 @@
|
||||
"SAVE_PLAYSPACE_CENTER_HELP": "Usa el espacio de juego actual para el comando de reiniciar espacio de juego.",
|
||||
"RESET_PLAYSPACE_CENTER": "Reiniciar centro del espacio de juego",
|
||||
"RESET_PLAYSPACE_CENTER_HELP": "Restablece el centro del espacio de juego definido previamente.",
|
||||
"RESTART_SOFTWARE": "Reiniciar software",
|
||||
"RESTART_SOFTWARE_HELP": "Aplicar ajustes que requieren reiniciar",
|
||||
"ROUND_MULTIPLIER": "Redondeo de bordes de la UI",
|
||||
"SCREEN_RENDER_DOWN": "Renderizar pantalla a resolución menor",
|
||||
"SCREEN_RENDER_DOWN_HELP": "Ayuda con el aliasing en pantallas de alta resolución",
|
||||
@@ -263,7 +261,9 @@
|
||||
"TITLE": "Diagnósticos",
|
||||
"ENABLE_REBAR": "Activa [resizable bar] en la configuración de la BIOS para un rendimiento óptimo de VR"
|
||||
},
|
||||
"TUTORIAL": "Tutorial"
|
||||
"TUTORIAL": "Tutorial",
|
||||
"RESTART_WAYVR": "Reiniciar WayVR",
|
||||
"CLOSE_WAYVR": "Cerrar WayVR"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Lanzador de aplicaciones",
|
||||
"APPLICATION_STARTED": "Aplicación iniciada",
|
||||
@@ -368,5 +368,13 @@
|
||||
"REMOVE_FROM_FAVOURITES": "Quitar de aplicaciones fijadas",
|
||||
"EMPTY": "Vacío",
|
||||
"INSTALLED": "Instalado",
|
||||
"NOT_INSTALLED": "No instalado"
|
||||
"NOT_INSTALLED": "No instalado",
|
||||
"POWER_OPTIONS": {
|
||||
"TITLE": "Opciones de energía",
|
||||
"SHUTDOWN": "Apagar",
|
||||
"SUSPEND": "Suspender",
|
||||
"SHUTDOWN_ARE_YOU_SURE": "¿Seguro que quieres apagar el ordenador?"
|
||||
},
|
||||
"YES": "Sí",
|
||||
"NO": "No"
|
||||
}
|
||||
@@ -197,8 +197,6 @@
|
||||
"SAVE_PLAYSPACE_CENTER_HELP": "Usa il playspace corrente per il comando di reset del playspace.",
|
||||
"RESET_PLAYSPACE_CENTER": "Resetta centro playspace",
|
||||
"RESET_PLAYSPACE_CENTER_HELP": "Rimuovi il centro del playspace impostato precedentemente.",
|
||||
"RESTART_SOFTWARE": "Riavvia software",
|
||||
"RESTART_SOFTWARE_HELP": "Applica le impostazioni che richiedono il riavvio",
|
||||
"ROUND_MULTIPLIER": "Arrotondamento bordi UI",
|
||||
"SCREEN_RENDER_DOWN": "Rendering schermo a risoluzione inferiore",
|
||||
"SCREEN_RENDER_DOWN_HELP": "Riduce l'effetto aliasing sugli schermi ad alta risoluzione",
|
||||
@@ -263,7 +261,9 @@
|
||||
"TITLE": "Diagnostica",
|
||||
"ENABLE_REBAR": "Abilita Resizable BAR nelle impostazioni del BIOS per prestazioni VR ottimali"
|
||||
},
|
||||
"TUTORIAL": "Tutorial"
|
||||
"TUTORIAL": "Tutorial",
|
||||
"RESTART_WAYVR": "Riavvia WayVR",
|
||||
"CLOSE_WAYVR": "Chiudi WayVR"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Avvio applicazioni",
|
||||
"APPLICATION_STARTED": "Applicazione avviata",
|
||||
@@ -368,5 +368,13 @@
|
||||
"REMOVE_FROM_FAVOURITES": "Rimuovi dalle app fissate",
|
||||
"EMPTY": "Vuoto",
|
||||
"INSTALLED": "Installato",
|
||||
"NOT_INSTALLED": "Non installato"
|
||||
"NOT_INSTALLED": "Non installato",
|
||||
"POWER_OPTIONS": {
|
||||
"TITLE": "Opzioni di alimentazione",
|
||||
"SHUTDOWN": "Spegni",
|
||||
"SUSPEND": "Sospendi",
|
||||
"SHUTDOWN_ARE_YOU_SURE": "Sei sicuro di voler spegnere il computer?"
|
||||
},
|
||||
"YES": "Sì",
|
||||
"NO": "No"
|
||||
}
|
||||
@@ -197,8 +197,6 @@
|
||||
"SAVE_PLAYSPACE_CENTER_HELP": "現在のプレイスペースを、プレイスペースリセットのバインディングに使用する。",
|
||||
"RESET_PLAYSPACE_CENTER": "プレイスペースの中心をリセット",
|
||||
"RESET_PLAYSPACE_CENTER_HELP": "設定済みのプレイスペースの中心点をリセットする。",
|
||||
"RESTART_SOFTWARE": "ソフトウェアを再起動",
|
||||
"RESTART_SOFTWARE_HELP": "再起動が必要な設定を適用する",
|
||||
"ROUND_MULTIPLIER": "UIの角の丸み",
|
||||
"SCREEN_RENDER_DOWN": "低解像度で画面をレンダリング",
|
||||
"SCREEN_RENDER_DOWN_HELP": "高解像度ディスプレイでのジャギーを軽減する",
|
||||
@@ -263,7 +261,9 @@
|
||||
"TITLE": "診断",
|
||||
"ENABLE_REBAR": "VRパフォーマンスを最適化するため、BIOS設定でresizable BARを有効にして下さい"
|
||||
},
|
||||
"TUTORIAL": "チュートリアル"
|
||||
"TUTORIAL": "チュートリアル",
|
||||
"RESTART_WAYVR": "WayVRを再起動",
|
||||
"CLOSE_WAYVR": "WayVRを閉じる"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "アプリランチャー",
|
||||
"APPLICATION_STARTED": "アプリが起動しました",
|
||||
@@ -368,5 +368,13 @@
|
||||
"REMOVE_FROM_FAVOURITES": "固定済みアプリから外す",
|
||||
"EMPTY": "なし",
|
||||
"INSTALLED": "インストール済み",
|
||||
"NOT_INSTALLED": "未インストール"
|
||||
"NOT_INSTALLED": "未インストール",
|
||||
"POWER_OPTIONS": {
|
||||
"TITLE": "電源オプション",
|
||||
"SHUTDOWN": "シャットダウン",
|
||||
"SUSPEND": "サスペンド",
|
||||
"SHUTDOWN_ARE_YOU_SURE": "コンピューターをシャットダウンしてもよろしいですか?"
|
||||
},
|
||||
"YES": "はい",
|
||||
"NO": "いいえ"
|
||||
}
|
||||
@@ -197,8 +197,6 @@
|
||||
"SAVE_PLAYSPACE_CENTER_HELP": "Użyj aktualnej przestrzeni gry dla przypisania resetowania przestrzeni.",
|
||||
"RESET_PLAYSPACE_CENTER": "Zresetuj centrum przestrzeni gry",
|
||||
"RESET_PLAYSPACE_CENTER_HELP": "Resetuj aktualny środek przestrzeni gry.",
|
||||
"RESTART_SOFTWARE": "Uruchom ponownie program",
|
||||
"RESTART_SOFTWARE_HELP": "Zastosuj ustawienia wymagające restartu",
|
||||
"ROUND_MULTIPLIER": "Zaokrąglenie krawędzi UI",
|
||||
"SCREEN_RENDER_DOWN": "Renderuj ekran w niższej rozdzielczości",
|
||||
"SCREEN_RENDER_DOWN_HELP": "Pomaga zredukować aliasing na ekranach o wysokiej rozdzielczości",
|
||||
@@ -263,7 +261,9 @@
|
||||
"TITLE": "Diagnostyka",
|
||||
"ENABLE_REBAR": "Włącz resizable BAR w ustawieniach BIOS, aby uzyskać optymalną wydajność VR"
|
||||
},
|
||||
"TUTORIAL": "Samouczek"
|
||||
"TUTORIAL": "Samouczek",
|
||||
"RESTART_WAYVR": "Zrestartuj WayVR",
|
||||
"CLOSE_WAYVR": "Zamknij WayVR"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Launcher aplikacji",
|
||||
"APPLICATION_STARTED": "Uruchomiono aplikację",
|
||||
@@ -368,5 +368,13 @@
|
||||
"REMOVE_FROM_FAVOURITES": "Usuń z przypiętych aplikacji",
|
||||
"EMPTY": "Puste",
|
||||
"INSTALLED": "Zainstalowano",
|
||||
"NOT_INSTALLED": "Nie zainstalowano"
|
||||
"NOT_INSTALLED": "Nie zainstalowano",
|
||||
"POWER_OPTIONS": {
|
||||
"TITLE": "Opcje zasilania",
|
||||
"SHUTDOWN": "Wyłącz",
|
||||
"SUSPEND": "Uśpij",
|
||||
"SHUTDOWN_ARE_YOU_SURE": "Czy na pewno chcesz wyłączyć komputer?"
|
||||
},
|
||||
"YES": "Tak",
|
||||
"NO": "Nie"
|
||||
}
|
||||
@@ -197,8 +197,6 @@
|
||||
"SAVE_PLAYSPACE_CENTER_HELP": "将当前的活动空间设置为重置活动空间的绑定点。",
|
||||
"RESET_PLAYSPACE_CENTER": "重置活动空间中心",
|
||||
"RESET_PLAYSPACE_CENTER_HELP": "重置之前设置的活动空间中心。",
|
||||
"RESTART_SOFTWARE": "重启软件",
|
||||
"RESTART_SOFTWARE_HELP": "应用需要重启才能生效的设置",
|
||||
"ROUND_MULTIPLIER": "UI 边缘圆角",
|
||||
"SCREEN_RENDER_DOWN": "低分辨率渲染屏幕",
|
||||
"SCREEN_RENDER_DOWN_HELP": "有助于减轻高分辨率屏幕上的锯齿现象",
|
||||
@@ -263,7 +261,9 @@
|
||||
"TITLE": "诊断",
|
||||
"ENABLE_REBAR": "请在 BIOS 设置中启用 Resizable BAR 以获得最佳 VR 性能"
|
||||
},
|
||||
"TUTORIAL": "教程"
|
||||
"TUTORIAL": "教程",
|
||||
"RESTART_WAYVR": "重启 WayVR",
|
||||
"CLOSE_WAYVR": "关闭 WayVR"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "应用启动器",
|
||||
"APPLICATION_STARTED": "应用程序已启动",
|
||||
@@ -368,5 +368,13 @@
|
||||
"REMOVE_FROM_FAVOURITES": "从固定应用中移除",
|
||||
"EMPTY": "暂无",
|
||||
"INSTALLED": "已安装",
|
||||
"NOT_INSTALLED": "未安装"
|
||||
"NOT_INSTALLED": "未安装",
|
||||
"POWER_OPTIONS": {
|
||||
"TITLE": "电源选项",
|
||||
"SHUTDOWN": "关机",
|
||||
"SUSPEND": "暂停",
|
||||
"SHUTDOWN_ARE_YOU_SURE": "确定要关机吗?"
|
||||
},
|
||||
"YES": "确定",
|
||||
"NO": "否"
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::{path::PathBuf, rc::Rc};
|
||||
use std::{path::PathBuf, process::Command, rc::Rc};
|
||||
|
||||
use chrono::Timelike;
|
||||
use glam::Vec2;
|
||||
use strum::EnumCount;
|
||||
use wgui::{
|
||||
assets::{AssetPathRef, AssetProvider},
|
||||
components::button::ComponentButton,
|
||||
components::{ComponentTrait, button::ComponentButton},
|
||||
event::{CallbackDataCommon, StyleSetRequest},
|
||||
font_config::WguiFontConfig,
|
||||
globals::WguiGlobals,
|
||||
@@ -17,7 +17,10 @@ use wgui::{
|
||||
task::Tasks,
|
||||
theme::WguiTheme,
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle, sprite::WidgetSprite},
|
||||
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
|
||||
windowing::{
|
||||
context_menu::{self, ContextMenu},
|
||||
window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
|
||||
},
|
||||
};
|
||||
use wlx_common::{
|
||||
async_executor::AsyncExecutor,
|
||||
@@ -35,10 +38,11 @@ use crate::{
|
||||
settings::TabSettings, welcome::TabWelcome,
|
||||
},
|
||||
util::{
|
||||
popup_manager::{MountPopupOnceParams, PopupManager, PopupManagerParams},
|
||||
is_exec_installed,
|
||||
popup_manager::{MountPopupOnceParams, PopupHolder, PopupManager, PopupManagerParams},
|
||||
toast_manager::ToastManager,
|
||||
},
|
||||
views,
|
||||
views::{self, ViewUpdateParams},
|
||||
};
|
||||
|
||||
pub struct FrontendWidgets {
|
||||
@@ -74,9 +78,11 @@ pub struct Frontend<T> {
|
||||
toast_manager: ToastManager,
|
||||
timestep: Timestep,
|
||||
sounds_to_play: Vec<SoundType>,
|
||||
context_menu_power: ContextMenu,
|
||||
|
||||
window_audio_settings: WguiWindow,
|
||||
view_audio_settings: Option<views::audio_settings::View>,
|
||||
popup_dialog_box: PopupHolder<views::dialog_box::View>,
|
||||
}
|
||||
|
||||
pub struct FrontendUpdateParams<'a, T> {
|
||||
@@ -116,11 +122,13 @@ pub enum FrontendTask {
|
||||
MountPopupOnce(MountPopupOnceParams),
|
||||
RefreshPopupManager,
|
||||
ShowAudioSettings,
|
||||
ShowPowerSettings(WidgetID /* source widget */),
|
||||
UpdateAudioSettingsView,
|
||||
RecenterPlayspace,
|
||||
PushToast(Translation),
|
||||
PlaySound(SoundType),
|
||||
OpenURL(Rc<str>),
|
||||
RunCommand(String /* program */, Vec<String> /* args */),
|
||||
HideDashboard,
|
||||
MarkTutorialGraduated,
|
||||
}
|
||||
@@ -202,9 +210,11 @@ impl<T: 'static> Frontend<T> {
|
||||
popup_manager,
|
||||
toast_manager,
|
||||
window_audio_settings: WguiWindow::default(),
|
||||
context_menu_power: Default::default(),
|
||||
view_audio_settings: None,
|
||||
executor: params.executor,
|
||||
sounds_to_play: Vec::new(),
|
||||
popup_dialog_box: Default::default(),
|
||||
};
|
||||
|
||||
// init some things first
|
||||
@@ -275,12 +285,77 @@ impl<T: 'static> Frontend<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn action_poweroff_confirm(&mut self) {
|
||||
let tasks = self.tasks.clone();
|
||||
views::dialog_box::mount_popup(
|
||||
self.popup_dialog_box.clone(),
|
||||
self.tasks.clone(),
|
||||
views::dialog_box::Params {
|
||||
globals: self.globals.clone(),
|
||||
message: Translation::from_translation_key("POWER_OPTIONS.SHUTDOWN_ARE_YOU_SURE"),
|
||||
entries: views::dialog_box::get_entries_yes_no(),
|
||||
on_action_click: Box::new(move |action| {
|
||||
if action == "yes" {
|
||||
tasks.push(FrontendTask::RunCommand(
|
||||
String::from("loginctl"),
|
||||
vec![String::from("poweroff")],
|
||||
));
|
||||
}
|
||||
}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn process_power_action(&mut self, action: &str, data: &mut T) {
|
||||
if !is_exec_installed("loginctl") {
|
||||
// TODO: add support for other init systems?
|
||||
self.tasks.push(FrontendTask::PushToast(Translation::from_raw_text(
|
||||
"loginctl is not installed",
|
||||
)));
|
||||
return;
|
||||
}
|
||||
|
||||
match action {
|
||||
"restart" => {
|
||||
self.interface.restart(data);
|
||||
}
|
||||
"close" => {
|
||||
self.interface.close(data);
|
||||
}
|
||||
"suspend" => {
|
||||
self.tasks.push(FrontendTask::RunCommand(
|
||||
String::from("loginctl"),
|
||||
vec![String::from("suspend")],
|
||||
));
|
||||
}
|
||||
"shutdown" => {
|
||||
self.action_poweroff_confirm();
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tick(&mut self, params: FrontendUpdateParams<T>) -> anyhow::Result<FrontendUpdateResult> {
|
||||
// fixme: timer events instead of this thing
|
||||
if self.ticks.is_multiple_of(1000) {
|
||||
self.update_time(params.data)?;
|
||||
}
|
||||
|
||||
// TODO: refactor: simplify update function (no configs or T are required in most cases)
|
||||
let mut config_change_kind = None;
|
||||
self.popup_dialog_box.update(&mut ViewUpdateParams {
|
||||
layout: &mut self.layout,
|
||||
executor: &self.executor,
|
||||
general_config: self.interface.general_config(params.data),
|
||||
config_change_kind: &mut config_change_kind,
|
||||
})?;
|
||||
|
||||
if let context_menu::TickResult::Action(action) = self.context_menu_power.tick(&mut self.layout, &mut self.state)? {
|
||||
self.process_power_action(&action, params.data);
|
||||
}
|
||||
|
||||
{
|
||||
// always 30 times per second
|
||||
while self.timestep.on_tick() {
|
||||
@@ -371,12 +446,14 @@ impl<T: 'static> Frontend<T> {
|
||||
FrontendTask::MountPopupOnce(popup_params) => self.mount_popup_once(popup_params, params.data)?,
|
||||
FrontendTask::RefreshPopupManager => self.refresh_popup_manager()?,
|
||||
FrontendTask::ShowAudioSettings => self.action_show_audio_settings()?,
|
||||
FrontendTask::ShowPowerSettings(pos) => self.action_show_power_settings(pos)?,
|
||||
FrontendTask::UpdateAudioSettingsView => self.action_update_audio_settings()?,
|
||||
FrontendTask::RecenterPlayspace => self.action_recenter_playspace(params.data)?,
|
||||
FrontendTask::PushToast(content) => self.toast_manager.push(content),
|
||||
FrontendTask::PlaySound(sound_type) => self.queue_play_sound(sound_type),
|
||||
FrontendTask::HideDashboard => self.action_hide_dashboard(params.data),
|
||||
FrontendTask::OpenURL(url) => self.action_open_url(url),
|
||||
FrontendTask::RunCommand(program, args) => self.action_run_command(program, args),
|
||||
FrontendTask::MarkTutorialGraduated => self.action_tutorial_graduated(params.data),
|
||||
};
|
||||
Ok(())
|
||||
@@ -503,6 +580,11 @@ impl<T: 'static> Frontend<T> {
|
||||
FrontendTask::ShowAudioSettings,
|
||||
);
|
||||
|
||||
let btn_power = self.state.fetch_component_as::<ComponentButton>("btn_power")?;
|
||||
self
|
||||
.tasks
|
||||
.handle_button(&btn_power, FrontendTask::ShowPowerSettings(btn_power.base().get_id()));
|
||||
|
||||
// "Recenter playspace" bottom bar button
|
||||
self.tasks.handle_button(
|
||||
&self.state.fetch_component_as::<ComponentButton>("btn_recenter")?,
|
||||
@@ -512,6 +594,18 @@ impl<T: 'static> Frontend<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn action_show_power_settings(&mut self, source_id: WidgetID) -> anyhow::Result<()> {
|
||||
self.context_menu_power.open(context_menu::OpenParams {
|
||||
on_custom_attribs: None,
|
||||
position: source_id.into(),
|
||||
blueprint: context_menu::Blueprint::Template {
|
||||
template_name: "context_menu_power_options".into(),
|
||||
template_params: Default::default(),
|
||||
},
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn action_show_audio_settings(&mut self) -> anyhow::Result<()> {
|
||||
self.window_audio_settings.open(&mut WguiWindowParams {
|
||||
position: Vec2::new(64.0, 64.0),
|
||||
@@ -576,4 +670,14 @@ impl<T: 'static> Frontend<T> {
|
||||
url
|
||||
))));
|
||||
}
|
||||
|
||||
fn action_run_command(&mut self, command: String, args: Vec<String>) {
|
||||
if let Err(e) = Command::new(command).args(args).spawn() {
|
||||
self
|
||||
.tasks
|
||||
.push(FrontendTask::PushToast(Translation::from_raw_text_string(format!(
|
||||
"Failed to launch command: {e}"
|
||||
))))
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -333,7 +333,7 @@ where
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, e: ButtonClickEvent| {
|
||||
tasks.push(Task::OpenContextMenu(
|
||||
e.mouse_pos_absolute.unwrap_or_default(),
|
||||
e.mouse_pos_absolute.into(),
|
||||
EnumType::VARIANTS
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
@@ -360,12 +360,12 @@ where
|
||||
let text = &title.text;
|
||||
let translated = if title.translated { "1" } else { "0" };
|
||||
|
||||
Some(context_menu::Cell {
|
||||
Some(context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!("{setting_str};{id};{value};{text};{translated}").into()),
|
||||
title,
|
||||
tooltip,
|
||||
attribs: vec![],
|
||||
})
|
||||
..Default::default()
|
||||
}))
|
||||
})
|
||||
.collect(),
|
||||
));
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use glam::Vec2;
|
||||
use std::{marker::PhantomData, rc::Rc, str::FromStr};
|
||||
use strum::{AsRefStr, EnumProperty, EnumString};
|
||||
use wgui::{
|
||||
@@ -81,11 +80,10 @@ pub(crate) enum Task {
|
||||
ClearPipewireTokens,
|
||||
ClearSavedState,
|
||||
DeleteAllConfigs,
|
||||
OpenContextMenu(Vec2, Vec<context_menu::Cell>),
|
||||
OpenContextMenu(context_menu::Position, Vec<context_menu::Cell>),
|
||||
RemoveAutostartApp(Rc<str>),
|
||||
ResetPlayspace,
|
||||
ResetPlayspaceCenter,
|
||||
RestartSoftware,
|
||||
SavePlayspaceCenter,
|
||||
SetTab(TabNameEnum),
|
||||
SettingUpdated(SettingType),
|
||||
@@ -231,10 +229,6 @@ impl<T> Tab<T> for TabSettings<T> {
|
||||
frontend.interface.playspace_task(data, DashPlayspaceTask::Reset)?;
|
||||
return Ok(());
|
||||
}
|
||||
Task::RestartSoftware => {
|
||||
frontend.interface.restart(data);
|
||||
return Ok(());
|
||||
}
|
||||
Task::OpenContextMenu(position, cells) => {
|
||||
self.context_menu.open(context_menu::OpenParams {
|
||||
on_custom_attribs: None,
|
||||
|
||||
@@ -1,27 +1,17 @@
|
||||
use wgui::layout::WidgetID;
|
||||
|
||||
use crate::tab::settings::{
|
||||
SettingsMountParams, SettingsTab,
|
||||
macros::{MacroParams, options_category, options_diagnostics_drm_card, options_diagnostics_row},
|
||||
use crate::{
|
||||
tab::settings::{
|
||||
SettingsMountParams, SettingsTab,
|
||||
macros::{MacroParams, options_category, options_diagnostics_drm_card, options_diagnostics_row},
|
||||
},
|
||||
util::is_exec_installed,
|
||||
};
|
||||
|
||||
pub struct State {}
|
||||
|
||||
impl SettingsTab for State {}
|
||||
|
||||
// works good enough
|
||||
fn is_exec_installed(exec: &str) -> bool {
|
||||
let mut cmd = std::process::Command::new("sh");
|
||||
cmd.arg("-c");
|
||||
cmd.arg(format!("command -v {}", exec));
|
||||
|
||||
let Ok(res) = cmd.output() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
res.status.success()
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct LspciInfo {
|
||||
// slot: String,
|
||||
|
||||
@@ -328,32 +328,33 @@ fn whisper_models_dropdown(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Re
|
||||
let mut cells = WHISPER_MODELS
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, item)| context_menu::Cell {
|
||||
action_name: Some(format!(";{id};{}", item.file_name).into()),
|
||||
title: Translation::from_raw_text_string(format!(
|
||||
"{}{}",
|
||||
item.display_name,
|
||||
if downloaded_models.contains(&idx) { " ✅" } else { "" }
|
||||
)),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
.map(|(idx, item)| {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!(";{id};{}", item.file_name).into()),
|
||||
title: Translation::from_raw_text(item.display_name),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
sprite_src_builtin: if downloaded_models.contains(&idx) {
|
||||
Some("@/dashboard/check.svg".into())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
cells.insert(
|
||||
0,
|
||||
context_menu::Cell {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(format!(";{id};").into()),
|
||||
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
|
||||
parent_tasks.push(ParentTask::OpenContextMenu(
|
||||
e.mouse_pos_absolute.unwrap_or_default(),
|
||||
cells,
|
||||
));
|
||||
parent_tasks.push(ParentTask::OpenContextMenu(e.mouse_pos_absolute.into(), cells));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -36,13 +36,6 @@ impl State {
|
||||
"@/dashboard/circle.svg",
|
||||
Task::DeleteAllConfigs,
|
||||
)?;
|
||||
options_danger_button(
|
||||
par.mp,
|
||||
c,
|
||||
"APP_SETTINGS.RESTART_SOFTWARE",
|
||||
"@/dashboard/refresh.svg",
|
||||
Task::RestartSoftware,
|
||||
)?;
|
||||
Ok(State {})
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,16 @@ pub mod steam_utils;
|
||||
pub mod toast_manager;
|
||||
pub mod wgui_simple;
|
||||
pub mod whisper;
|
||||
|
||||
// works good enough
|
||||
pub fn is_exec_installed(exec: &str) -> bool {
|
||||
let mut cmd = std::process::Command::new("sh");
|
||||
cmd.arg("-c");
|
||||
cmd.arg(format!("command -v {}", exec));
|
||||
|
||||
let Ok(res) = cmd.output() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
res.status.success()
|
||||
}
|
||||
@@ -39,7 +39,7 @@ use crate::{
|
||||
enum Task {
|
||||
Save,
|
||||
Cancel,
|
||||
OpenContextMenu(glam::Vec2, Vec<context_menu::Cell>),
|
||||
OpenContextMenu(context_menu::Position, Vec<context_menu::Cell>),
|
||||
UpdateThreshold(Rc<str>, XrInputSide, usize, f32),
|
||||
AddChordMember(Rc<str>, XrInputSide),
|
||||
RemoveChordMember(Rc<str>, XrInputSide, usize),
|
||||
@@ -804,20 +804,21 @@ fn chord_hand_dropdown(
|
||||
let cells = [XrInputSide::Left, XrInputSide::Right]
|
||||
.into_iter()
|
||||
.filter(|side| profile.find_userpath(*side).is_some())
|
||||
.map(|side| context_menu::Cell {
|
||||
action_name: Some(
|
||||
format!(
|
||||
"chord_hand;{};{};{};{}",
|
||||
action,
|
||||
output_side.as_ref(),
|
||||
member_idx,
|
||||
side.as_ref()
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
title: side_translation(side),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
.map(|side| {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(
|
||||
format!(
|
||||
"chord_hand;{};{};{};{}",
|
||||
action,
|
||||
output_side.as_ref(),
|
||||
member_idx,
|
||||
side.as_ref()
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
title: side_translation(side),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -842,20 +843,21 @@ fn chord_subpath_dropdown(
|
||||
.unwrap_or_else(|| Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"));
|
||||
let cells = available
|
||||
.iter()
|
||||
.map(|subpath| context_menu::Cell {
|
||||
action_name: Some(
|
||||
format!(
|
||||
"chord_subpath;{};{};{};{}",
|
||||
action,
|
||||
output_side.as_ref(),
|
||||
member_idx,
|
||||
subpath.as_ref()
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
title: subpath.translation(),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
.map(|subpath| {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(
|
||||
format!(
|
||||
"chord_subpath;{};{};{};{}",
|
||||
action,
|
||||
output_side.as_ref(),
|
||||
member_idx,
|
||||
subpath.as_ref()
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
title: subpath.translation(),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -885,20 +887,21 @@ fn chord_component_dropdown(
|
||||
.unwrap_or_else(|| Translation::from_raw_text_rc(Default::default()));
|
||||
let cells = available
|
||||
.iter()
|
||||
.map(|component| context_menu::Cell {
|
||||
action_name: Some(
|
||||
format!(
|
||||
"chord_comp;{};{};{};{}",
|
||||
action,
|
||||
output_side.as_ref(),
|
||||
member_idx,
|
||||
component.as_ref()
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
title: component.translation(),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
.map(|component| {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(
|
||||
format!(
|
||||
"chord_comp;{};{};{};{}",
|
||||
action,
|
||||
output_side.as_ref(),
|
||||
member_idx,
|
||||
component.as_ref()
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
title: component.translation(),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -1003,23 +1006,23 @@ fn create_dropdown<B: 'static + BindingsDropdown>(
|
||||
) -> anyhow::Result<()> {
|
||||
let mut cells = available
|
||||
.iter()
|
||||
.map(|item| context_menu::Cell {
|
||||
action_name: Some(item.action_str(&action, side)),
|
||||
title: item.translation(),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
.map(|item| {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(item.action_str(&action, side)),
|
||||
title: item.translation(),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(action_str) = B::clear_str(&action, side) {
|
||||
cells.insert(
|
||||
0,
|
||||
context_menu::Cell {
|
||||
context_menu::Cell::Button(context_menu::Button {
|
||||
action_name: Some(action_str),
|
||||
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
|
||||
tooltip: None,
|
||||
attribs: vec![],
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1052,10 +1055,7 @@ fn create_dropdown_with_cells(
|
||||
let tasks = mp.tasks.clone();
|
||||
let cells = cells.clone();
|
||||
move |_common, e: ButtonClickEvent| {
|
||||
tasks.push(Task::OpenContextMenu(
|
||||
e.mouse_pos_absolute.unwrap_or_default(),
|
||||
cells.clone(),
|
||||
));
|
||||
tasks.push(Task::OpenContextMenu(e.mouse_pos_absolute.into(), cells.clone()));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -32,6 +32,21 @@ enum Task {
|
||||
ActionClicked(&'static str),
|
||||
}
|
||||
|
||||
pub fn get_entries_yes_no() -> Vec<ButtonEntry> {
|
||||
vec![
|
||||
ButtonEntry {
|
||||
content: Translation::from_translation_key("YES"),
|
||||
icon: "@/dashboard/check.svg",
|
||||
action: "yes",
|
||||
},
|
||||
ButtonEntry {
|
||||
content: Translation::from_translation_key("NO"),
|
||||
icon: "@/dashboard/cancel.svg",
|
||||
action: "no",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
pub struct View {
|
||||
tasks: Tasks<Task>,
|
||||
|
||||
@@ -52,6 +67,13 @@ fn doc_params(globals: &WguiGlobals) -> ParseDocumentParams<'_> {
|
||||
|
||||
impl ViewTrait for View {
|
||||
fn update(&mut self, _par: &mut ViewUpdateParams) -> anyhow::Result<()> {
|
||||
self.tick();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl View {
|
||||
pub fn tick(&mut self) {
|
||||
for task in self.tasks.drain() {
|
||||
match task {
|
||||
Task::ActionClicked(action) => {
|
||||
@@ -65,11 +87,8 @@ impl ViewTrait for View {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl View {
|
||||
pub fn new(
|
||||
layout: &mut Layout,
|
||||
id_parent: WidgetID,
|
||||
|
||||
@@ -33,7 +33,7 @@ use wlx_common::locale::WayVRLangProvider;
|
||||
#[derive(Clone)]
|
||||
pub enum TestbedTask {
|
||||
ShowPopup,
|
||||
ShowContextMenu(Vec2),
|
||||
ShowContextMenu(context_menu::Position),
|
||||
}
|
||||
|
||||
struct Data {
|
||||
@@ -196,7 +196,7 @@ impl TestbedGeneric {
|
||||
button_context_menu.on_click({
|
||||
let tasks = testbed.tasks.clone();
|
||||
Rc::new(move |_common, m| {
|
||||
tasks.push(TestbedTask::ShowContextMenu(m.boundary.bottom_left()));
|
||||
tasks.push(TestbedTask::ShowContextMenu(m.boundary.into()));
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
@@ -212,7 +212,9 @@ impl TestbedGeneric {
|
||||
) -> anyhow::Result<()> {
|
||||
match task {
|
||||
TestbedTask::ShowPopup => self.show_popup(params, data)?,
|
||||
TestbedTask::ShowContextMenu(position) => self.show_context_menu(params, data, *position),
|
||||
TestbedTask::ShowContextMenu(position) => {
|
||||
self.show_context_menu(params, data, position.clone())
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -251,7 +253,7 @@ impl TestbedGeneric {
|
||||
&mut self,
|
||||
_params: &mut TestbedUpdateParams,
|
||||
data: &mut Data,
|
||||
position: Vec2,
|
||||
position: context_menu::Position,
|
||||
) {
|
||||
data.context_menu.open(context_menu::OpenParams {
|
||||
on_custom_attribs: Some(Rc::new(move |custom_attribs| {
|
||||
|
||||
@@ -244,7 +244,7 @@ pub(super) fn setup_custom_button<S: 'static>(
|
||||
template_name: template_name.clone(),
|
||||
template_params: template_params.clone(),
|
||||
},
|
||||
position: data.metadata.get_mouse_pos_absolute().unwrap(), //want panic
|
||||
position: data.metadata.get_mouse_pos_absolute().unwrap().into(), // want panic
|
||||
});
|
||||
Ok(EventResult::Consumed)
|
||||
}
|
||||
|
||||
@@ -564,6 +564,10 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&mut self, _data: &mut AppState) {
|
||||
RUNNING.store(false, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn restart(&mut self, _data: &mut AppState) {
|
||||
RUNNING.store(false, Ordering::Relaxed);
|
||||
RESTART.store(true, Ordering::Relaxed);
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
<layout version="2">
|
||||
<!-- text: str -->
|
||||
<template name="Cell">
|
||||
<Button id="button" text="${text}" tooltip_str="${tooltip_str}" weight="bold" border="0" padding="4" color="background(transparent)" height="24" justify_content="start" />
|
||||
<macro name="ContextMenuCell" tooltip_str="${tooltip_str}" weight="bold" border="0" padding_left="4" padding_right="4" color="background(transparent)" justify_content="start" min_height="28"/>
|
||||
|
||||
<!--
|
||||
text
|
||||
-->
|
||||
<template name="CellButton">
|
||||
<Button id="button" text="${text}" macro="ContextMenuCell"/>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
text, sprite_src_builtin
|
||||
-->
|
||||
<template name="CellButtonSprite">
|
||||
<Button id="button" macro="ContextMenuCell" gap="8">
|
||||
<sprite src_builtin="${sprite_src_builtin}" width="24" height="24"/>
|
||||
<label text="${text}" weight="bold"/>
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template name="Separator">
|
||||
|
||||
@@ -374,11 +374,15 @@ impl ParserState {
|
||||
'children: for child in el_context_menu.children() {
|
||||
match child.tag_name().name() {
|
||||
"" => {}
|
||||
"separator" => {
|
||||
cells.push(context_menu::Cell::Separator);
|
||||
}
|
||||
"cell" => {
|
||||
let mut title: Option<Translation> = None;
|
||||
let mut tooltip: Option<Translation> = None;
|
||||
let mut action_name: Option<Rc<str>> = None;
|
||||
let mut attribs = Vec::<AttribPair>::new();
|
||||
let mut sprite_src_builtin: Option<Rc<str>> = None;
|
||||
|
||||
for attrib in child.attributes() {
|
||||
let (key, value) = (attrib.name(), attrib.value());
|
||||
@@ -389,6 +393,7 @@ impl ParserState {
|
||||
"tooltip" => tooltip = Some(Translation::from_translation_key(value)),
|
||||
"tooltip_str" => tooltip = Some(Translation::from_raw_text(value)),
|
||||
"action" => action_name = Some(value.into()),
|
||||
"sprite_src_builtin" => sprite_src_builtin = Some(value.into()),
|
||||
"skip" => {
|
||||
let resolved = replace_vars(value, template_params);
|
||||
//FIXME: this is always empty
|
||||
@@ -406,12 +411,13 @@ impl ParserState {
|
||||
}
|
||||
|
||||
let title = title.context("No text/translation provided")?;
|
||||
cells.push(context_menu::Cell {
|
||||
cells.push(context_menu::Cell::Button(context_menu::Button {
|
||||
title,
|
||||
tooltip,
|
||||
action_name,
|
||||
sprite_src_builtin,
|
||||
attribs,
|
||||
});
|
||||
}));
|
||||
}
|
||||
other => {
|
||||
anyhow::bail!("{:?}: unexpected <{other}> tag", self.xml_path.get_path().display());
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use crate::{
|
||||
assets::AssetPathRef,
|
||||
components::{ComponentTrait, button::ComponentButton},
|
||||
drawing::Boundary,
|
||||
globals::WguiGlobals,
|
||||
i18n::Translation,
|
||||
layout::Layout,
|
||||
layout::{Layout, WidgetID},
|
||||
parser::{self, Fetchable, ParserState, TemplateParams},
|
||||
task::Tasks,
|
||||
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
|
||||
@@ -11,14 +12,21 @@ use crate::{
|
||||
use glam::Vec2;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Cell {
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Button {
|
||||
pub title: Translation,
|
||||
pub tooltip: Option<Translation>,
|
||||
pub action_name: Option<Rc<str>>,
|
||||
pub sprite_src_builtin: Option<Rc<str>>,
|
||||
pub attribs: Vec<parser::AttribPair>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Cell {
|
||||
Button(Button),
|
||||
Separator,
|
||||
}
|
||||
|
||||
pub enum Blueprint {
|
||||
Cells(Vec<Cell>),
|
||||
Template {
|
||||
@@ -27,9 +35,47 @@ pub enum Blueprint {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Position {
|
||||
Unspecified,
|
||||
Absolute(Vec2),
|
||||
Widget(WidgetID),
|
||||
Boundary(Boundary),
|
||||
}
|
||||
|
||||
// absolute position
|
||||
impl From<Vec2> for Position {
|
||||
fn from(value: Vec2) -> Self {
|
||||
Self::Absolute(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<Vec2>> for Position {
|
||||
fn from(value: Option<Vec2>) -> Self {
|
||||
match value {
|
||||
Some(v) => Self::Absolute(v),
|
||||
None => Self::Unspecified,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// relative to widget center
|
||||
impl From<WidgetID> for Position {
|
||||
fn from(value: WidgetID) -> Self {
|
||||
Self::Widget(value)
|
||||
}
|
||||
}
|
||||
|
||||
// relative to absolute rectangle center
|
||||
impl From<Boundary> for Position {
|
||||
fn from(value: Boundary) -> Self {
|
||||
Self::Boundary(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OpenParams {
|
||||
pub on_custom_attribs: Option<parser::OnCustomAttribsFunc>,
|
||||
pub position: Vec2,
|
||||
pub position: Position,
|
||||
pub blueprint: Blueprint,
|
||||
}
|
||||
|
||||
@@ -89,14 +135,24 @@ impl ContextMenu {
|
||||
Blueprint::Cells(cells) => cells,
|
||||
};
|
||||
|
||||
let absolute_pos = match params.position {
|
||||
Position::Unspecified => Vec2::new(0.0, 0.0),
|
||||
Position::Absolute(pos) => pos,
|
||||
Position::Boundary(boundary) => boundary.center(),
|
||||
Position::Widget(widget_id) => {
|
||||
let widget = layout.state.widgets.fetch(widget_id)?;
|
||||
widget.state().data.cached_absolute_boundary.center()
|
||||
}
|
||||
};
|
||||
|
||||
let root_size = layout.state.get_widget_size(layout.content_root_widget);
|
||||
|
||||
let (window_pos, placement) = if params.position.y < root_size.y / 2.0 {
|
||||
(params.position, WguiWindowPlacement::TopLeft)
|
||||
let (window_pos, placement) = if absolute_pos.y < root_size.y / 2.0 {
|
||||
(absolute_pos, WguiWindowPlacement::TopLeft)
|
||||
} else {
|
||||
// invert y axis (position.y is counted from the bottom)
|
||||
(
|
||||
Vec2::new(params.position.x, root_size.y - params.position.y),
|
||||
Vec2::new(absolute_pos.x, root_size.y - absolute_pos.y),
|
||||
WguiWindowPlacement::BottomLeft,
|
||||
)
|
||||
};
|
||||
@@ -121,33 +177,62 @@ impl ContextMenu {
|
||||
|
||||
let id_buttons = inner_parser.get_widget_id("buttons")?;
|
||||
|
||||
for (idx, cell) in cells.iter().enumerate() {
|
||||
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("tooltip_str", tooltip.generate(&mut globals.i18n()));
|
||||
let mut has_sprites = false;
|
||||
|
||||
for cell in &cells {
|
||||
if let Cell::Button(button) = cell
|
||||
&& button.sprite_src_builtin.is_some()
|
||||
{
|
||||
has_sprites = true;
|
||||
}
|
||||
}
|
||||
|
||||
let mut data_cell = inner_parser.parse_template_only(&doc_params, "Cell", layout, id_buttons, par)?;
|
||||
for cell in &cells {
|
||||
match cell {
|
||||
Cell::Button(cell) => {
|
||||
let mut par = TemplateParams::new();
|
||||
par.insert_rc("text", cell.title.generate(&mut globals.i18n()));
|
||||
|
||||
let button = data_cell.fetch_component_as::<ComponentButton>("button")?;
|
||||
let button_id = button.base().get_id();
|
||||
parser_state.data.take_results_from(&mut data_cell);
|
||||
self
|
||||
.tasks
|
||||
.handle_button(&button, Task::ActionClicked(cell.action_name.clone()));
|
||||
if has_sprites {
|
||||
par.insert_rc(
|
||||
"sprite_src_builtin",
|
||||
cell
|
||||
.sprite_src_builtin
|
||||
.clone()
|
||||
.unwrap_or_else(|| Rc::from("@/dashboard/dot.svg")),
|
||||
);
|
||||
}
|
||||
if let Some(tooltip) = &cell.tooltip {
|
||||
par.insert_rc("tooltip_str", tooltip.generate(&mut globals.i18n()));
|
||||
}
|
||||
|
||||
if let Some(c) = params.on_custom_attribs.as_ref() {
|
||||
(*c)(parser::CustomAttribsInfo {
|
||||
pairs: &cell.attribs,
|
||||
parent_id: id_buttons,
|
||||
widget_id: button_id,
|
||||
widgets: &layout.state.widgets,
|
||||
});
|
||||
}
|
||||
let mut data_cell = inner_parser.parse_template_only(
|
||||
&doc_params,
|
||||
if has_sprites { "CellButtonSprite" } else { "CellButton" },
|
||||
layout,
|
||||
id_buttons,
|
||||
par,
|
||||
)?;
|
||||
|
||||
if idx < cells.len() - 1 {
|
||||
inner_parser.realize_template(&doc_params, "Separator", layout, id_buttons, Default::default())?;
|
||||
let button = data_cell.fetch_component_as::<ComponentButton>("button")?;
|
||||
let button_id = button.base().get_id();
|
||||
parser_state.data.take_results_from(&mut data_cell);
|
||||
self
|
||||
.tasks
|
||||
.handle_button(&button, Task::ActionClicked(cell.action_name.clone()));
|
||||
|
||||
if let Some(c) = params.on_custom_attribs.as_ref() {
|
||||
(*c)(parser::CustomAttribsInfo {
|
||||
pairs: &cell.attribs,
|
||||
parent_id: id_buttons,
|
||||
widget_id: button_id,
|
||||
widgets: &layout.state.widgets,
|
||||
});
|
||||
}
|
||||
}
|
||||
Cell::Separator => {
|
||||
inner_parser.realize_template(&doc_params, "Separator", layout, id_buttons, Default::default())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -97,6 +97,7 @@ pub trait DashInterface<T> {
|
||||
fn general_config<'a>(&'a mut self, data: &'a mut T) -> &'a mut GeneralConfig;
|
||||
fn config_changed(&mut self, data: &mut T, kind: ConfigChangeKind);
|
||||
fn restart(&mut self, data: &mut T);
|
||||
fn close(&mut self, data: &mut T);
|
||||
fn toggle_dashboard(&mut self, data: &mut T);
|
||||
fn get_feats(&mut self, data: &mut T) -> InterfaceFeats;
|
||||
fn hmd_stats(&mut self, data: &mut T) -> HmdStats;
|
||||
|
||||
@@ -231,6 +231,8 @@ impl DashInterface<()> for DashInterfaceEmulated {
|
||||
|
||||
fn restart(&mut self, _data: &mut ()) {}
|
||||
|
||||
fn close(&mut self, _data: &mut ()) {}
|
||||
|
||||
fn toggle_dashboard(&mut self, _data: &mut ()) {}
|
||||
|
||||
fn get_feats(&mut self, _data: &mut ()) -> dash_interface::InterfaceFeats {
|
||||
|
||||
Reference in new issue
Block a user