Language selector and "requires restart" info
This commit is contained in:
@@ -10,7 +10,6 @@
|
|||||||
"APP_SETTINGS": {
|
"APP_SETTINGS": {
|
||||||
"HIDE_USERNAME": "Benutzernamen ausblenden",
|
"HIDE_USERNAME": "Benutzernamen ausblenden",
|
||||||
"OPAQUE_BACKGROUND": "Undurchsichtiger Hintergrund",
|
"OPAQUE_BACKGROUND": "Undurchsichtiger Hintergrund",
|
||||||
"WLX": {},
|
|
||||||
"LOOK_AND_FEEL": "Aussehen und Verhalten",
|
"LOOK_AND_FEEL": "Aussehen und Verhalten",
|
||||||
"HIDE_GRAB_HELP": "Greif-Hilfe ausblenden",
|
"HIDE_GRAB_HELP": "Greif-Hilfe ausblenden",
|
||||||
"ANIMATION_SPEED": "UI-Animationsgeschwindigkeit",
|
"ANIMATION_SPEED": "UI-Animationsgeschwindigkeit",
|
||||||
@@ -89,7 +88,9 @@
|
|||||||
"RESET_PLAYSPACE": "Spielbereich zurücksetzen",
|
"RESET_PLAYSPACE": "Spielbereich zurücksetzen",
|
||||||
"RESET_PLAYSPACE_HELP": "Den Abstand des Spielbereichs zurücksetzen.",
|
"RESET_PLAYSPACE_HELP": "Den Abstand des Spielbereichs zurücksetzen.",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Posen beim Interagieren mit der Tastatur blockieren",
|
"BLOCK_POSES_ON_KBD_INTERACTION": "Posen beim Interagieren mit der Tastatur blockieren",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Verhindert, dass das Spiel Posen empfängt, wenn die Tastatur angefahren wird und „Spieleingabe blockieren“ aktiviert ist"
|
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Verhindert, dass das Spiel Posen empfängt, wenn die Tastatur angefahren wird und „Spieleingabe blockieren“ aktiviert ist",
|
||||||
|
"LANGUAGE": "Sprache",
|
||||||
|
"REQUIRES_RESTART": "Erfordert Neustart"
|
||||||
},
|
},
|
||||||
"HELLO": "Hallo!",
|
"HELLO": "Hallo!",
|
||||||
"AUDIO": {
|
"AUDIO": {
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
"KEYBOARD_MIDDLE_CLICK": "Keyboard middle click",
|
"KEYBOARD_MIDDLE_CLICK": "Keyboard middle click",
|
||||||
"KEYBOARD_MIDDLE_CLICK_HELP": "Modifier to use when typing\nwith purple laser",
|
"KEYBOARD_MIDDLE_CLICK_HELP": "Modifier to use when typing\nwith purple laser",
|
||||||
"KEYBOARD_SOUND_ENABLED": "Keyboard sounds",
|
"KEYBOARD_SOUND_ENABLED": "Keyboard sounds",
|
||||||
|
"LANGUAGE": "Language",
|
||||||
"LEFT_HANDED_MOUSE": "Left-handed mouse",
|
"LEFT_HANDED_MOUSE": "Left-handed mouse",
|
||||||
"LEFT_HANDED_MOUSE_HELP": "Use this if mouse buttons are swapped",
|
"LEFT_HANDED_MOUSE_HELP": "Use this if mouse buttons are swapped",
|
||||||
"LONG_PRESS_DURATION": "Long press duration",
|
"LONG_PRESS_DURATION": "Long press duration",
|
||||||
@@ -74,10 +75,10 @@
|
|||||||
"OPTION": {
|
"OPTION": {
|
||||||
"AUTO": "Automatic",
|
"AUTO": "Automatic",
|
||||||
"AUTO_HELP": "ScreenCopy GPU if supported,\notherwise PipeWire GPU.",
|
"AUTO_HELP": "ScreenCopy GPU if supported,\notherwise PipeWire GPU.",
|
||||||
"EYE_PINCH": "Eye + pinch",
|
|
||||||
"HMD_PINCH": "HMD + pinch",
|
|
||||||
"EYE_ONLY": "Eye only",
|
"EYE_ONLY": "Eye only",
|
||||||
|
"EYE_PINCH": "Eye + pinch",
|
||||||
"HMD_ONLY": "HMD only",
|
"HMD_ONLY": "HMD only",
|
||||||
|
"HMD_PINCH": "HMD + pinch",
|
||||||
"NONE": "None",
|
"NONE": "None",
|
||||||
"PIPEWIRE_HELP": "Fast GPU capture,\nstandard on all desktops.",
|
"PIPEWIRE_HELP": "Fast GPU capture,\nstandard on all desktops.",
|
||||||
"PW_FALLBACK_HELP": "Slow method with high CPU usage.\nTry in case PipeWire GPU doesn't work",
|
"PW_FALLBACK_HELP": "Slow method with high CPU usage.\nTry in case PipeWire GPU doesn't work",
|
||||||
@@ -85,6 +86,7 @@
|
|||||||
"SCREENCOPY_HELP": "Slow, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway"
|
"SCREENCOPY_HELP": "Slow, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway"
|
||||||
},
|
},
|
||||||
"POINTER_LERP_FACTOR": "Pointer smoothing",
|
"POINTER_LERP_FACTOR": "Pointer smoothing",
|
||||||
|
"REQUIRES_RESTART": "Requires restart",
|
||||||
"RESET_PLAYSPACE": "Reset playspace",
|
"RESET_PLAYSPACE": "Reset playspace",
|
||||||
"RESET_PLAYSPACE_HELP": "Clear the stage space offset.",
|
"RESET_PLAYSPACE_HELP": "Clear the stage space offset.",
|
||||||
"RESTART_SOFTWARE": "Restart software",
|
"RESTART_SOFTWARE": "Restart software",
|
||||||
@@ -148,8 +150,8 @@
|
|||||||
"RESOLUTION": "Resolution"
|
"RESOLUTION": "Resolution"
|
||||||
},
|
},
|
||||||
"PROCESS": {
|
"PROCESS": {
|
||||||
"STOP": "Stop",
|
"FORCE_KILL": "Force-kill",
|
||||||
"FORCE_KILL": "Force-kill"
|
"STOP": "Stop"
|
||||||
},
|
},
|
||||||
"PROCESS_LIST": "Process list",
|
"PROCESS_LIST": "Process list",
|
||||||
"REFRESH": "Refresh",
|
"REFRESH": "Refresh",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"APP_SETTINGS": {
|
"APP_SETTINGS": {
|
||||||
"HIDE_USERNAME": "Ocultar nombre de usuario",
|
"HIDE_USERNAME": "Ocultar nombre de usuario",
|
||||||
"OPAQUE_BACKGROUND": "Fondo opaco",
|
"OPAQUE_BACKGROUND": "Fondo opaco",
|
||||||
"WLX": {},
|
|
||||||
"LOOK_AND_FEEL": "Apariencia y estilo",
|
"LOOK_AND_FEEL": "Apariencia y estilo",
|
||||||
"HIDE_GRAB_HELP": "Ocultar ayuda para agarrar",
|
"HIDE_GRAB_HELP": "Ocultar ayuda para agarrar",
|
||||||
"ANIMATION_SPEED": "Velocidad de animación de la IU",
|
"ANIMATION_SPEED": "Velocidad de animación de la IU",
|
||||||
@@ -89,7 +88,9 @@
|
|||||||
"RESET_PLAYSPACE": "Restablecer espacio de juego",
|
"RESET_PLAYSPACE": "Restablecer espacio de juego",
|
||||||
"RESET_PLAYSPACE_HELP": "Borrar el desplazamiento del espacio de juego.",
|
"RESET_PLAYSPACE_HELP": "Borrar el desplazamiento del espacio de juego.",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Bloquear poses al interactuar con el teclado",
|
"BLOCK_POSES_ON_KBD_INTERACTION": "Bloquear poses al interactuar con el teclado",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Bloquea que el juego reciba poses cuando el teclado está sobre él y 'Bloquear entrada del juego' está habilitado"
|
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Bloquea que el juego reciba poses cuando el teclado está sobre él y 'Bloquear entrada del juego' está habilitado",
|
||||||
|
"LANGUAGE": "Idioma",
|
||||||
|
"REQUIRES_RESTART": "Requiere reinicio"
|
||||||
},
|
},
|
||||||
"HELLO": "¡Hola!",
|
"HELLO": "¡Hola!",
|
||||||
"AUDIO": {
|
"AUDIO": {
|
||||||
|
|||||||
@@ -109,7 +109,9 @@
|
|||||||
"RESET_PLAYSPACE": "Ripristina playspace",
|
"RESET_PLAYSPACE": "Ripristina playspace",
|
||||||
"RESET_PLAYSPACE_HELP": "Cancella l'offset dello spazio di gioco.",
|
"RESET_PLAYSPACE_HELP": "Cancella l'offset dello spazio di gioco.",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Blocca le pose durante l'interazione con la tastiera",
|
"BLOCK_POSES_ON_KBD_INTERACTION": "Blocca le pose durante l'interazione con la tastiera",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Impedisce al gioco di ricevere pose quando la tastiera è evidenziata e 'Blocca input di gioco' è abilitato"
|
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Impedisce al gioco di ricevere pose quando la tastiera è evidenziata e 'Blocca input di gioco' è abilitato",
|
||||||
|
"LANGUAGE": "Lingua",
|
||||||
|
"REQUIRES_RESTART": "Richiede riavvio"
|
||||||
},
|
},
|
||||||
"APPLICATION_LAUNCHER": "Lanciatore applicazioni",
|
"APPLICATION_LAUNCHER": "Lanciatore applicazioni",
|
||||||
"APPLICATION_STARTED": "Applicazione avviata",
|
"APPLICATION_STARTED": "Applicazione avviata",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"APP_SETTINGS": {
|
"APP_SETTINGS": {
|
||||||
"HIDE_USERNAME": "ユーザー名を非表示",
|
"HIDE_USERNAME": "ユーザー名を非表示",
|
||||||
"OPAQUE_BACKGROUND": "不透明な背景",
|
"OPAQUE_BACKGROUND": "不透明な背景",
|
||||||
"WLX": {},
|
|
||||||
"LOOK_AND_FEEL": "外観",
|
"LOOK_AND_FEEL": "外観",
|
||||||
"HIDE_GRAB_HELP": "グリップ動作中にのヘルプを非表示",
|
"HIDE_GRAB_HELP": "グリップ動作中にのヘルプを非表示",
|
||||||
"ANIMATION_SPEED": "UIアニメーション速度",
|
"ANIMATION_SPEED": "UIアニメーション速度",
|
||||||
@@ -89,7 +88,9 @@
|
|||||||
"RESET_PLAYSPACE": "プレイエリアをリセット",
|
"RESET_PLAYSPACE": "プレイエリアをリセット",
|
||||||
"RESET_PLAYSPACE_HELP": "プレイエリアのオフセットをクリアします。",
|
"RESET_PLAYSPACE_HELP": "プレイエリアのオフセットをクリアします。",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION": "キーボード操作時のポーズをブロック",
|
"BLOCK_POSES_ON_KBD_INTERACTION": "キーボード操作時のポーズをブロック",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "キーボードがホバーされ、「ゲーム入力をブロック」が有効になっている場合、ゲームがポーズを受信することをブロックします"
|
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "キーボードがホバーされ、「ゲーム入力をブロック」が有効になっている場合、ゲームがポーズを受信することをブロックします",
|
||||||
|
"LANGUAGE": "言語",
|
||||||
|
"REQUIRES_RESTART": "再起動が必要です"
|
||||||
},
|
},
|
||||||
"HELLO": "こんにちは!",
|
"HELLO": "こんにちは!",
|
||||||
"AUDIO": {
|
"AUDIO": {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
"APP_SETTINGS": {
|
"APP_SETTINGS": {
|
||||||
"HIDE_USERNAME": "Ukryj nazwę użytkownika",
|
"HIDE_USERNAME": "Ukryj nazwę użytkownika",
|
||||||
"OPAQUE_BACKGROUND": "Nieprzezroczyste tło",
|
"OPAQUE_BACKGROUND": "Nieprzezroczyste tło",
|
||||||
"WLX": {},
|
|
||||||
"LOOK_AND_FEEL": "Wygląd i działanie",
|
"LOOK_AND_FEEL": "Wygląd i działanie",
|
||||||
"HIDE_GRAB_HELP": "Ukryj pomoc dotyczącą chwytania",
|
"HIDE_GRAB_HELP": "Ukryj pomoc dotyczącą chwytania",
|
||||||
"ANIMATION_SPEED": "Prędkość animacji UI",
|
"ANIMATION_SPEED": "Prędkość animacji UI",
|
||||||
@@ -34,7 +33,6 @@
|
|||||||
"XR_CLICK_SENSITIVITY": "Czułość kliknięć XR",
|
"XR_CLICK_SENSITIVITY": "Czułość kliknięć XR",
|
||||||
"XR_CLICK_SENSITIVITY_RELEASE": "Czułość zwalniania XR",
|
"XR_CLICK_SENSITIVITY_RELEASE": "Czułość zwalniania XR",
|
||||||
"CLICK_FREEZE_TIME_MS": "Czas zamrożenia po kliknięciu (ms)",
|
"CLICK_FREEZE_TIME_MS": "Czas zamrożenia po kliknięciu (ms)",
|
||||||
"MISC": "Różne",
|
|
||||||
"XWAYLAND_BY_DEFAULT": "Uruchamiaj aplikacje domyślnie w trybie kompatybilności",
|
"XWAYLAND_BY_DEFAULT": "Uruchamiaj aplikacje domyślnie w trybie kompatybilności",
|
||||||
"UPRIGHT_SCREEN_FIX": "Naprawa pozycji ekranu",
|
"UPRIGHT_SCREEN_FIX": "Naprawa pozycji ekranu",
|
||||||
"DOUBLE_CURSOR_FIX": "Naprawa podwójnego kursora",
|
"DOUBLE_CURSOR_FIX": "Naprawa podwójnego kursora",
|
||||||
@@ -55,7 +53,7 @@
|
|||||||
"CLEAR_SAVED_STATE": "Wyczyść zapisany stan",
|
"CLEAR_SAVED_STATE": "Wyczyść zapisany stan",
|
||||||
"CLEAR_PIPEWIRE_TOKENS": "Wyczyść tokeny PipeWire",
|
"CLEAR_PIPEWIRE_TOKENS": "Wyczyść tokeny PipeWire",
|
||||||
"DELETE_ALL_CONFIGS": "Wyczyść konfigurację",
|
"DELETE_ALL_CONFIGS": "Wyczyść konfigurację",
|
||||||
"RESTART_SOFTWARE": "Uruchom ponownie oprogramowanie",
|
"RESTART_SOFTWARE": "Restartuj WayVR",
|
||||||
"CLEAR_SAVED_STATE_HELP": "Zresetuj zestawy i pozycje nakładek",
|
"CLEAR_SAVED_STATE_HELP": "Zresetuj zestawy i pozycje nakładek",
|
||||||
"CLEAR_PIPEWIRE_TOKENS_HELP": "Zapytaj o wybór ekranu przy następnym uruchomieniu",
|
"CLEAR_PIPEWIRE_TOKENS_HELP": "Zapytaj o wybór ekranu przy następnym uruchomieniu",
|
||||||
"DELETE_ALL_CONFIGS_HELP": "Usuń wszystkie pliki konfiguracyjne z katalogu conf.d",
|
"DELETE_ALL_CONFIGS_HELP": "Usuń wszystkie pliki konfiguracyjne z katalogu conf.d",
|
||||||
@@ -72,19 +70,22 @@
|
|||||||
"SCREENCOPY_GPU_HELP": "Szybkie działanie, brak wyskakujących okien z informacją o udostępnianiu ekranu.\nDziała na: Hyprland, Niri, River, Sway",
|
"SCREENCOPY_GPU_HELP": "Szybkie działanie, brak wyskakujących okien z informacją o udostępnianiu ekranu.\nDziała na: Hyprland, Niri, River, Sway",
|
||||||
"SCREENCOPY_HELP": "Wolne, bez wyskakujących okienek udostępniania ekranu.\nDziała na: Hyprland, Niri, River, Sway",
|
"SCREENCOPY_HELP": "Wolne, bez wyskakujących okienek udostępniania ekranu.\nDziała na: Hyprland, Niri, River, Sway",
|
||||||
"NONE": "Brak",
|
"NONE": "Brak",
|
||||||
"HMD_PINCH": "HMD + szczyknięcie",
|
"HMD_PINCH": "HMD + ściśnięcie placami",
|
||||||
"EYE_PINCH": "Ściśnięcie palcami + oko",
|
"EYE_PINCH": "Ściśnięcie palcami + oko",
|
||||||
"EYE_ONLY": "Tylko oko",
|
"EYE_ONLY": "Tylko oko",
|
||||||
"HMD_ONLY": "Tylko HMD"
|
"HMD_ONLY": "Tylko HMD"
|
||||||
},
|
},
|
||||||
"AUTOSTART_APPS": "Aplikacje do uruchomienia przy starcie",
|
"AUTOSTART_APPS": "Aplikacje auto-start",
|
||||||
"HANDSFREE_POINTER": "Tryb bez użycia rąk",
|
"HANDSFREE_POINTER": "Tryb bez użycia rąk",
|
||||||
"HANDSFREE_POINTER_HELP": "Wejście do użycia, gdy kontrolery ruchu\nsą niedostępne. Lewy szczyptak to chwyt,\nprawy to kliknięcie.",
|
"HANDSFREE_POINTER_HELP": "Wejście do użycia, gdy kontrolery ruchu\nsą niedostępne. Lewy szczyptak to chwyt,\nprawy to kliknięcie.",
|
||||||
"UI_GRADIENT_INTENSITY": "Intensywność gradientu UI",
|
"UI_GRADIENT_INTENSITY": "Intensywność gradientu UI",
|
||||||
"RESET_PLAYSPACE": "Zresetuj przestrzeń gry",
|
"RESET_PLAYSPACE": "Zresetuj przestrzeń gry",
|
||||||
"RESET_PLAYSPACE_HELP": "Wyczyść przesunięcie przestrzeni gry.",
|
"RESET_PLAYSPACE_HELP": "Wyczyść przesunięcie przestrzeni gry.",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Blokuj pozy podczas interakcji z klawiaturą",
|
"BLOCK_POSES_ON_KBD_INTERACTION": "Blokuj pozy podczas interakcji z klawiaturą",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Blokuje odbieranie póz przez grę, gdy kursor myszy znajduje się nad klawiaturą i włączona jest opcja 'Blokuj dane wejściowe z gry'"
|
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Blokuje odbieranie póz przez grę, gdy kursor myszy znajduje się nad klawiaturą i włączona jest opcja 'Blokuj dane wejściowe z gry'",
|
||||||
|
"LANGUAGE": "Język",
|
||||||
|
"REQUIRES_RESTART": "Wymaga restartu",
|
||||||
|
"MISC": "Różne"
|
||||||
},
|
},
|
||||||
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
|
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
|
||||||
"APPLICATIONS": "Aplikacje",
|
"APPLICATIONS": "Aplikacje",
|
||||||
|
|||||||
@@ -109,7 +109,9 @@
|
|||||||
"RESET_PLAYSPACE": "重置游戏空间",
|
"RESET_PLAYSPACE": "重置游戏空间",
|
||||||
"RESET_PLAYSPACE_HELP": "清除舞台空间偏移。",
|
"RESET_PLAYSPACE_HELP": "清除舞台空间偏移。",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION": "与键盘交互时阻止姿势",
|
"BLOCK_POSES_ON_KBD_INTERACTION": "与键盘交互时阻止姿势",
|
||||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "当键盘悬停且启用“阻止游戏输入”时,阻止游戏接收姿势"
|
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "当键盘悬停且启用“阻止游戏输入”时,阻止游戏接收姿势",
|
||||||
|
"LANGUAGE": "语言",
|
||||||
|
"REQUIRES_RESTART": "需要重启"
|
||||||
},
|
},
|
||||||
"APPLICATION_LAUNCHER": "应用启动器",
|
"APPLICATION_LAUNCHER": "应用启动器",
|
||||||
"APPLICATION_STARTED": "应用已启动",
|
"APPLICATION_STARTED": "应用已启动",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use wgui::{
|
|||||||
use wlx_common::{
|
use wlx_common::{
|
||||||
audio,
|
audio,
|
||||||
dash_interface::{BoxDashInterface, RecenterMode},
|
dash_interface::{BoxDashInterface, RecenterMode},
|
||||||
|
locale::WayVRLangProvider,
|
||||||
timestep::{self, Timestep},
|
timestep::{self, Timestep},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,8 +82,9 @@ pub struct FrontendUpdateResult {
|
|||||||
pub sounds_to_play: Vec<SoundType>,
|
pub sounds_to_play: Vec<SoundType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InitParams<T> {
|
pub struct InitParams<'a, T> {
|
||||||
pub interface: BoxDashInterface<T>,
|
pub interface: BoxDashInterface<T>,
|
||||||
|
pub lang_provider: &'a WayVRLangProvider,
|
||||||
pub has_monado: bool,
|
pub has_monado: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +120,7 @@ impl<T: 'static> Frontend<T> {
|
|||||||
|
|
||||||
let globals = WguiGlobals::new(
|
let globals = WguiGlobals::new(
|
||||||
assets,
|
assets,
|
||||||
|
params.lang_provider,
|
||||||
wgui::globals::Defaults::default(),
|
wgui::globals::Defaults::default(),
|
||||||
&WguiFontConfig {
|
&WguiFontConfig {
|
||||||
binaries: vec![&font_binary_regular, &font_binary_bold, &font_binary_light],
|
binaries: vec![&font_binary_regular, &font_binary_bold, &font_binary_light],
|
||||||
|
|||||||
@@ -10,14 +10,20 @@ use wgui::{
|
|||||||
slider::ComponentSlider,
|
slider::ComponentSlider,
|
||||||
tabs::ComponentTabs,
|
tabs::ComponentTabs,
|
||||||
},
|
},
|
||||||
|
drawing,
|
||||||
event::{CallbackDataCommon, EventAlterables},
|
event::{CallbackDataCommon, EventAlterables},
|
||||||
globals::WguiGlobals,
|
globals::WguiGlobals,
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::{Layout, WidgetID},
|
layout::{Layout, WidgetID},
|
||||||
log::LogErr,
|
log::LogErr,
|
||||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||||
|
renderer_vk::text::{FontWeight, TextStyle},
|
||||||
|
taffy::{self, prelude::length},
|
||||||
task::Tasks,
|
task::Tasks,
|
||||||
widget::label::WidgetLabel,
|
widget::{
|
||||||
|
div::WidgetDiv,
|
||||||
|
label::{WidgetLabel, WidgetLabelParams},
|
||||||
|
},
|
||||||
windowing::context_menu::{self, Blueprint, ContextMenu, TickResult},
|
windowing::context_menu::{self, Blueprint, ContextMenu, TickResult},
|
||||||
};
|
};
|
||||||
use wlx_common::{config::GeneralConfig, config_io::ConfigRoot, dash_interface::RecenterMode};
|
use wlx_common::{config::GeneralConfig, config_io::ConfigRoot, dash_interface::RecenterMode};
|
||||||
@@ -202,46 +208,48 @@ impl<T> Tab<T> for TabSettings<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sorted alphabetically
|
||||||
#[allow(clippy::enum_variant_names)]
|
#[allow(clippy::enum_variant_names)]
|
||||||
#[derive(Clone, Copy, AsRefStr, EnumString)]
|
#[derive(Clone, Copy, AsRefStr, EnumString)]
|
||||||
enum SettingType {
|
enum SettingType {
|
||||||
UiAnimationSpeed,
|
|
||||||
UiGradientIntensity,
|
|
||||||
UiRoundMultiplier,
|
|
||||||
InvertScrollDirectionX,
|
|
||||||
InvertScrollDirectionY,
|
|
||||||
ScrollSpeed,
|
|
||||||
LongPressDuration,
|
|
||||||
NotificationsEnabled,
|
|
||||||
NotificationsSoundEnabled,
|
|
||||||
KeyboardSoundEnabled,
|
|
||||||
UprightScreenFix,
|
|
||||||
DoubleCursorFix,
|
|
||||||
SetsOnWatch,
|
|
||||||
HideGrabHelp,
|
|
||||||
XrClickSensitivity,
|
|
||||||
XrClickSensitivityRelease,
|
|
||||||
AllowSliding,
|
AllowSliding,
|
||||||
ClickFreezeTimeMs,
|
|
||||||
FocusFollowsMouseMode,
|
|
||||||
LeftHandedMouse,
|
|
||||||
BlockGameInput,
|
BlockGameInput,
|
||||||
BlockGameInputIgnoreWatch,
|
BlockGameInputIgnoreWatch,
|
||||||
BlockPosesOnKbdInteraction,
|
BlockPosesOnKbdInteraction,
|
||||||
SpaceDragMultiplier,
|
CaptureMethod,
|
||||||
UseSkybox,
|
ClickFreezeTimeMs,
|
||||||
UsePassthrough,
|
Clock12h,
|
||||||
ScreenRenderDown,
|
DoubleCursorFix,
|
||||||
|
FocusFollowsMouseMode,
|
||||||
|
HandsfreePointer,
|
||||||
|
HideGrabHelp,
|
||||||
|
HideUsername,
|
||||||
|
InvertScrollDirectionX,
|
||||||
|
InvertScrollDirectionY,
|
||||||
|
KeyboardMiddleClick,
|
||||||
|
KeyboardSoundEnabled,
|
||||||
|
Language,
|
||||||
|
LeftHandedMouse,
|
||||||
|
LongPressDuration,
|
||||||
|
NotificationsEnabled,
|
||||||
|
NotificationsSoundEnabled,
|
||||||
|
OpaqueBackground,
|
||||||
PointerLerpFactor,
|
PointerLerpFactor,
|
||||||
|
ScreenRenderDown,
|
||||||
|
ScrollSpeed,
|
||||||
|
SetsOnWatch,
|
||||||
|
SpaceDragMultiplier,
|
||||||
SpaceDragUnlocked,
|
SpaceDragUnlocked,
|
||||||
SpaceRotateUnlocked,
|
SpaceRotateUnlocked,
|
||||||
Clock12h,
|
UiAnimationSpeed,
|
||||||
HideUsername,
|
UiGradientIntensity,
|
||||||
OpaqueBackground,
|
UiRoundMultiplier,
|
||||||
|
UprightScreenFix,
|
||||||
|
UsePassthrough,
|
||||||
|
UseSkybox,
|
||||||
|
XrClickSensitivity,
|
||||||
|
XrClickSensitivityRelease,
|
||||||
XwaylandByDefault,
|
XwaylandByDefault,
|
||||||
CaptureMethod,
|
|
||||||
KeyboardMiddleClick,
|
|
||||||
HandsfreePointer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SettingType {
|
impl SettingType {
|
||||||
@@ -309,6 +317,9 @@ impl SettingType {
|
|||||||
Self::HandsfreePointer => {
|
Self::HandsfreePointer => {
|
||||||
config.handsfree_pointer = wlx_common::config::HandsfreePointer::from_str(value).expect("Invalid enum value!")
|
config.handsfree_pointer = wlx_common::config::HandsfreePointer::from_str(value).expect("Invalid enum value!")
|
||||||
}
|
}
|
||||||
|
Self::Language => {
|
||||||
|
config.language = Some(wlx_common::locale::Language::from_str(value).expect("Invalid enum value!"))
|
||||||
|
}
|
||||||
_ => panic!("Requested enum for non-enum SettingType"),
|
_ => panic!("Requested enum for non-enum SettingType"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,6 +329,10 @@ impl SettingType {
|
|||||||
Self::CaptureMethod => Self::get_enum_title_inner(config.capture_method),
|
Self::CaptureMethod => Self::get_enum_title_inner(config.capture_method),
|
||||||
Self::KeyboardMiddleClick => Self::get_enum_title_inner(config.keyboard_middle_click_mode),
|
Self::KeyboardMiddleClick => Self::get_enum_title_inner(config.keyboard_middle_click_mode),
|
||||||
Self::HandsfreePointer => Self::get_enum_title_inner(config.handsfree_pointer),
|
Self::HandsfreePointer => Self::get_enum_title_inner(config.handsfree_pointer),
|
||||||
|
Self::Language => match &config.language {
|
||||||
|
Some(lang) => Self::get_enum_title_inner(*lang),
|
||||||
|
None => Translation::from_translation_key("APP_SETTINGS.OPTION.AUTO"),
|
||||||
|
},
|
||||||
_ => panic!("Requested enum for non-enum SettingType"),
|
_ => panic!("Requested enum for non-enum SettingType"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -341,70 +356,71 @@ impl SettingType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ok is translation, Err is raw text
|
/// Ok is translation, Err is raw text
|
||||||
|
/// `match` sorted alphabetically
|
||||||
fn get_translation(self) -> Result<&'static str, &'static str> {
|
fn get_translation(self) -> Result<&'static str, &'static str> {
|
||||||
match self {
|
match self {
|
||||||
Self::UiAnimationSpeed => Ok("APP_SETTINGS.ANIMATION_SPEED"),
|
|
||||||
Self::UiGradientIntensity => Ok("APP_SETTINGS.UI_GRADIENT_INTENSITY"),
|
|
||||||
Self::UiRoundMultiplier => Ok("APP_SETTINGS.ROUND_MULTIPLIER"),
|
|
||||||
Self::InvertScrollDirectionX => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_X"),
|
|
||||||
Self::InvertScrollDirectionY => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_Y"),
|
|
||||||
Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"),
|
|
||||||
Self::LongPressDuration => Ok("APP_SETTINGS.LONG_PRESS_DURATION"),
|
|
||||||
Self::NotificationsEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_ENABLED"),
|
|
||||||
Self::NotificationsSoundEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_SOUND_ENABLED"),
|
|
||||||
Self::KeyboardSoundEnabled => Ok("APP_SETTINGS.KEYBOARD_SOUND_ENABLED"),
|
|
||||||
Self::UprightScreenFix => Ok("APP_SETTINGS.UPRIGHT_SCREEN_FIX"),
|
|
||||||
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
|
|
||||||
Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"),
|
|
||||||
Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"),
|
|
||||||
Self::XrClickSensitivity => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY"),
|
|
||||||
Self::XrClickSensitivityRelease => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE"),
|
|
||||||
Self::AllowSliding => Ok("APP_SETTINGS.ALLOW_SLIDING"),
|
Self::AllowSliding => Ok("APP_SETTINGS.ALLOW_SLIDING"),
|
||||||
Self::ClickFreezeTimeMs => Ok("APP_SETTINGS.CLICK_FREEZE_TIME_MS"),
|
|
||||||
Self::FocusFollowsMouseMode => Ok("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE"),
|
|
||||||
Self::LeftHandedMouse => Ok("APP_SETTINGS.LEFT_HANDED_MOUSE"),
|
|
||||||
Self::BlockGameInput => Ok("APP_SETTINGS.BLOCK_GAME_INPUT"),
|
Self::BlockGameInput => Ok("APP_SETTINGS.BLOCK_GAME_INPUT"),
|
||||||
Self::BlockGameInputIgnoreWatch => Ok("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH"),
|
Self::BlockGameInputIgnoreWatch => Ok("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH"),
|
||||||
Self::BlockPosesOnKbdInteraction => Ok("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION"),
|
Self::BlockPosesOnKbdInteraction => Ok("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION"),
|
||||||
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
|
Self::CaptureMethod => Ok("APP_SETTINGS.CAPTURE_METHOD"),
|
||||||
Self::UseSkybox => Ok("APP_SETTINGS.USE_SKYBOX"),
|
Self::ClickFreezeTimeMs => Ok("APP_SETTINGS.CLICK_FREEZE_TIME_MS"),
|
||||||
Self::UsePassthrough => Ok("APP_SETTINGS.USE_PASSTHROUGH"),
|
Self::Clock12h => Ok("APP_SETTINGS.CLOCK_12H"),
|
||||||
Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"),
|
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
|
||||||
|
Self::FocusFollowsMouseMode => Ok("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE"),
|
||||||
|
Self::HandsfreePointer => Ok("APP_SETTINGS.HANDSFREE_POINTER"),
|
||||||
|
Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"),
|
||||||
|
Self::HideUsername => Ok("APP_SETTINGS.HIDE_USERNAME"),
|
||||||
|
Self::InvertScrollDirectionX => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_X"),
|
||||||
|
Self::InvertScrollDirectionY => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_Y"),
|
||||||
|
Self::KeyboardMiddleClick => Ok("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK"),
|
||||||
|
Self::KeyboardSoundEnabled => Ok("APP_SETTINGS.KEYBOARD_SOUND_ENABLED"),
|
||||||
|
Self::Language => Ok("APP_SETTINGS.LANGUAGE"),
|
||||||
|
Self::LeftHandedMouse => Ok("APP_SETTINGS.LEFT_HANDED_MOUSE"),
|
||||||
|
Self::LongPressDuration => Ok("APP_SETTINGS.LONG_PRESS_DURATION"),
|
||||||
|
Self::NotificationsEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_ENABLED"),
|
||||||
|
Self::NotificationsSoundEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_SOUND_ENABLED"),
|
||||||
|
Self::OpaqueBackground => Ok("APP_SETTINGS.OPAQUE_BACKGROUND"),
|
||||||
Self::PointerLerpFactor => Ok("APP_SETTINGS.POINTER_LERP_FACTOR"),
|
Self::PointerLerpFactor => Ok("APP_SETTINGS.POINTER_LERP_FACTOR"),
|
||||||
|
Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"),
|
||||||
|
Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"),
|
||||||
|
Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"),
|
||||||
|
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
|
||||||
Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"),
|
Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"),
|
||||||
Self::SpaceRotateUnlocked => Ok("APP_SETTINGS.SPACE_ROTATE_UNLOCKED"),
|
Self::SpaceRotateUnlocked => Ok("APP_SETTINGS.SPACE_ROTATE_UNLOCKED"),
|
||||||
Self::Clock12h => Ok("APP_SETTINGS.CLOCK_12H"),
|
Self::UiAnimationSpeed => Ok("APP_SETTINGS.ANIMATION_SPEED"),
|
||||||
Self::HideUsername => Ok("APP_SETTINGS.HIDE_USERNAME"),
|
Self::UiGradientIntensity => Ok("APP_SETTINGS.UI_GRADIENT_INTENSITY"),
|
||||||
Self::OpaqueBackground => Ok("APP_SETTINGS.OPAQUE_BACKGROUND"),
|
Self::UiRoundMultiplier => Ok("APP_SETTINGS.ROUND_MULTIPLIER"),
|
||||||
|
Self::UprightScreenFix => Ok("APP_SETTINGS.UPRIGHT_SCREEN_FIX"),
|
||||||
|
Self::UsePassthrough => Ok("APP_SETTINGS.USE_PASSTHROUGH"),
|
||||||
|
Self::UseSkybox => Ok("APP_SETTINGS.USE_SKYBOX"),
|
||||||
|
Self::XrClickSensitivity => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY"),
|
||||||
|
Self::XrClickSensitivityRelease => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE"),
|
||||||
Self::XwaylandByDefault => Ok("APP_SETTINGS.XWAYLAND_BY_DEFAULT"),
|
Self::XwaylandByDefault => Ok("APP_SETTINGS.XWAYLAND_BY_DEFAULT"),
|
||||||
Self::CaptureMethod => Ok("APP_SETTINGS.CAPTURE_METHOD"),
|
|
||||||
Self::KeyboardMiddleClick => Ok("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK"),
|
|
||||||
Self::HandsfreePointer => Ok("APP_SETTINGS.HANDSFREE_POINTER"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `match` sorted alphabetically
|
||||||
fn get_tooltip(self) -> Option<&'static str> {
|
fn get_tooltip(self) -> Option<&'static str> {
|
||||||
match self {
|
match self {
|
||||||
Self::UprightScreenFix => Some("APP_SETTINGS.UPRIGHT_SCREEN_FIX_HELP"),
|
|
||||||
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
|
|
||||||
Self::XrClickSensitivity => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_HELP"),
|
|
||||||
Self::XrClickSensitivityRelease => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE_HELP"),
|
|
||||||
Self::FocusFollowsMouseMode => Some("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE_HELP"),
|
|
||||||
Self::LeftHandedMouse => Some("APP_SETTINGS.LEFT_HANDED_MOUSE_HELP"),
|
|
||||||
Self::BlockGameInput => Some("APP_SETTINGS.BLOCK_GAME_INPUT_HELP"),
|
Self::BlockGameInput => Some("APP_SETTINGS.BLOCK_GAME_INPUT_HELP"),
|
||||||
Self::BlockGameInputIgnoreWatch => Some("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH_HELP"),
|
Self::BlockGameInputIgnoreWatch => Some("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH_HELP"),
|
||||||
Self::BlockPosesOnKbdInteraction => Some("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION_HELP"),
|
Self::BlockPosesOnKbdInteraction => Some("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION_HELP"),
|
||||||
Self::UseSkybox => Some("APP_SETTINGS.USE_SKYBOX_HELP"),
|
|
||||||
Self::UsePassthrough => Some("APP_SETTINGS.USE_PASSTHROUGH_HELP"),
|
|
||||||
Self::ScreenRenderDown => Some("APP_SETTINGS.SCREEN_RENDER_DOWN_HELP"),
|
|
||||||
Self::CaptureMethod => Some("APP_SETTINGS.CAPTURE_METHOD_HELP"),
|
Self::CaptureMethod => Some("APP_SETTINGS.CAPTURE_METHOD_HELP"),
|
||||||
Self::KeyboardMiddleClick => Some("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK_HELP"),
|
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
|
||||||
Self::HandsfreePointer => Some("APP_SETTINGS.HANDSFREE_POINTER_HELP"),
|
Self::HandsfreePointer => Some("APP_SETTINGS.HANDSFREE_POINTER_HELP"),
|
||||||
|
Self::KeyboardMiddleClick => Some("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK_HELP"),
|
||||||
|
Self::LeftHandedMouse => Some("APP_SETTINGS.LEFT_HANDED_MOUSE_HELP"),
|
||||||
|
Self::ScreenRenderDown => Some("APP_SETTINGS.SCREEN_RENDER_DOWN_HELP"),
|
||||||
|
Self::UprightScreenFix => Some("APP_SETTINGS.UPRIGHT_SCREEN_FIX_HELP"),
|
||||||
|
Self::UsePassthrough => Some("APP_SETTINGS.USE_PASSTHROUGH_HELP"),
|
||||||
|
Self::UseSkybox => Some("APP_SETTINGS.USE_SKYBOX_HELP"),
|
||||||
|
Self::XrClickSensitivity => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_HELP"),
|
||||||
|
Self::XrClickSensitivityRelease => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE_HELP"),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: incorporate this
|
|
||||||
fn requires_restart(self) -> bool {
|
fn requires_restart(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::UiAnimationSpeed
|
Self::UiAnimationSpeed
|
||||||
@@ -412,6 +428,7 @@ impl SettingType {
|
|||||||
| Self::UprightScreenFix
|
| Self::UprightScreenFix
|
||||||
| Self::DoubleCursorFix
|
| Self::DoubleCursorFix
|
||||||
| Self::ScreenRenderDown
|
| Self::ScreenRenderDown
|
||||||
|
| Self::Language
|
||||||
| Self::CaptureMethod => true,
|
| Self::CaptureMethod => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@@ -426,6 +443,42 @@ impl SettingType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// creates a simple div with horizontal, centered flow
|
||||||
|
fn horiz_cell(layout: &mut Layout, parent: WidgetID) -> anyhow::Result<WidgetID> {
|
||||||
|
let (pair, _) = layout.add_child(
|
||||||
|
parent,
|
||||||
|
WidgetDiv::create(),
|
||||||
|
taffy::Style {
|
||||||
|
flex_direction: taffy::FlexDirection::Row,
|
||||||
|
align_items: Some(taffy::AlignItems::Center),
|
||||||
|
gap: length(8.0),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(pair.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mount_requires_restart(layout: &mut Layout, parent: WidgetID) -> anyhow::Result<()> {
|
||||||
|
let content = Translation::from_translation_key("APP_SETTINGS.REQUIRES_RESTART");
|
||||||
|
let label = WidgetLabel::create(
|
||||||
|
&mut layout.state.globals.get(),
|
||||||
|
WidgetLabelParams {
|
||||||
|
content,
|
||||||
|
style: TextStyle {
|
||||||
|
wrap: false,
|
||||||
|
color: Some(drawing::Color::new(1.0, 0.5, 0.5, 1.0)),
|
||||||
|
weight: Some(FontWeight::Bold),
|
||||||
|
size: Some(10.0),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
layout.add_child(parent, label, Default::default())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! category {
|
macro_rules! category {
|
||||||
($pe:expr, $root:expr, $translation:expr, $icon:expr) => {{
|
($pe:expr, $root:expr, $translation:expr, $icon:expr) => {{
|
||||||
let id = $pe.idx.to_string();
|
let id = $pe.idx.to_string();
|
||||||
@@ -464,9 +517,15 @@ macro_rules! checkbox {
|
|||||||
let checked = if *$setting.mut_bool($mp.config) { "1" } else { "0" };
|
let checked = if *$setting.mut_bool($mp.config) { "1" } else { "0" };
|
||||||
params.insert(Rc::from("checked"), Rc::from(checked));
|
params.insert(Rc::from("checked"), Rc::from(checked));
|
||||||
|
|
||||||
|
let id_cell = horiz_cell($mp.layout, $root)?;
|
||||||
|
|
||||||
$mp
|
$mp
|
||||||
.parser_state
|
.parser_state
|
||||||
.instantiate_template($mp.doc_params, "CheckBoxSetting", $mp.layout, $root, params)?;
|
.instantiate_template($mp.doc_params, "CheckBoxSetting", $mp.layout, id_cell, params)?;
|
||||||
|
|
||||||
|
if $setting.requires_restart() {
|
||||||
|
mount_requires_restart($mp.layout, id_cell)?;
|
||||||
|
}
|
||||||
|
|
||||||
let checkbox = $mp.parser_state.fetch_component_as::<ComponentCheckbox>(&id)?;
|
let checkbox = $mp.parser_state.fetch_component_as::<ComponentCheckbox>(&id)?;
|
||||||
checkbox.on_toggle(Box::new({
|
checkbox.on_toggle(Box::new({
|
||||||
@@ -502,9 +561,15 @@ macro_rules! slider_f32 {
|
|||||||
params.insert(Rc::from("max"), Rc::from($max.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::from("step"), Rc::from($step.to_string()));
|
||||||
|
|
||||||
|
let id_cell = horiz_cell($mp.layout, $root)?;
|
||||||
|
|
||||||
$mp
|
$mp
|
||||||
.parser_state
|
.parser_state
|
||||||
.instantiate_template($mp.doc_params, "SliderSetting", $mp.layout, $root, params)?;
|
.instantiate_template($mp.doc_params, "SliderSetting", $mp.layout, id_cell, params)?;
|
||||||
|
|
||||||
|
if $setting.requires_restart() {
|
||||||
|
mount_requires_restart($mp.layout, id_cell)?;
|
||||||
|
}
|
||||||
|
|
||||||
let slider = $mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
let slider = $mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||||
slider.on_value_changed(Box::new({
|
slider.on_value_changed(Box::new({
|
||||||
@@ -534,6 +599,8 @@ macro_rules! slider_i32 {
|
|||||||
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let id_cell = horiz_cell($mp.layout, $root)?;
|
||||||
|
|
||||||
let value = $setting.mut_i32($mp.config).to_string();
|
let value = $setting.mut_i32($mp.config).to_string();
|
||||||
params.insert(Rc::from("value"), Rc::from(value));
|
params.insert(Rc::from("value"), Rc::from(value));
|
||||||
params.insert(Rc::from("min"), Rc::from($min.to_string()));
|
params.insert(Rc::from("min"), Rc::from($min.to_string()));
|
||||||
@@ -542,7 +609,11 @@ macro_rules! slider_i32 {
|
|||||||
|
|
||||||
$mp
|
$mp
|
||||||
.parser_state
|
.parser_state
|
||||||
.instantiate_template($mp.doc_params, "SliderSetting", $mp.layout, $root, params)?;
|
.instantiate_template($mp.doc_params, "SliderSetting", $mp.layout, id_cell, params)?;
|
||||||
|
|
||||||
|
if $setting.requires_restart() {
|
||||||
|
mount_requires_restart($mp.layout, id_cell)?;
|
||||||
|
}
|
||||||
|
|
||||||
let slider = $mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
let slider = $mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||||
slider.on_value_changed(Box::new({
|
slider.on_value_changed(Box::new({
|
||||||
@@ -556,7 +627,7 @@ macro_rules! slider_i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! dropdown {
|
macro_rules! dropdown {
|
||||||
($mp:expr, $root:expr, $setting:expr, $options:expr) => {
|
($mp:expr /* `MacroParams` struct */, $root:expr, $setting:expr, $options:expr) => {
|
||||||
let id = $mp.idx.to_string();
|
let id = $mp.idx.to_string();
|
||||||
$mp.idx += 1;
|
$mp.idx += 1;
|
||||||
|
|
||||||
@@ -572,9 +643,15 @@ macro_rules! dropdown {
|
|||||||
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let id_cell = horiz_cell($mp.layout, $root)?;
|
||||||
|
|
||||||
$mp
|
$mp
|
||||||
.parser_state
|
.parser_state
|
||||||
.instantiate_template($mp.doc_params, "DropdownButton", $mp.layout, $root, params)?;
|
.instantiate_template($mp.doc_params, "DropdownButton", $mp.layout, id_cell, params)?;
|
||||||
|
|
||||||
|
if $setting.requires_restart() {
|
||||||
|
mount_requires_restart($mp.layout, id_cell)?;
|
||||||
|
}
|
||||||
|
|
||||||
let setting_str = $setting.as_ref();
|
let setting_str = $setting.as_ref();
|
||||||
let title = $setting.get_enum_title($mp.config);
|
let title = $setting.get_enum_title($mp.config);
|
||||||
@@ -709,6 +786,7 @@ impl<T> TabSettings<T> {
|
|||||||
match name {
|
match name {
|
||||||
TabNameEnum::LookAndFeel => {
|
TabNameEnum::LookAndFeel => {
|
||||||
let c = category!(mp, root, "APP_SETTINGS.LOOK_AND_FEEL", "dashboard/palette.svg")?;
|
let c = category!(mp, root, "APP_SETTINGS.LOOK_AND_FEEL", "dashboard/palette.svg")?;
|
||||||
|
dropdown!(mp, c, SettingType::Language, wlx_common::locale::Language::VARIANTS);
|
||||||
checkbox!(mp, c, SettingType::OpaqueBackground);
|
checkbox!(mp, c, SettingType::OpaqueBackground);
|
||||||
checkbox!(mp, c, SettingType::HideUsername);
|
checkbox!(mp, c, SettingType::HideUsername);
|
||||||
checkbox!(mp, c, SettingType::HideGrabHelp);
|
checkbox!(mp, c, SettingType::HideGrabHelp);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use wgui::{
|
|||||||
layout::{Layout, LayoutParams, LayoutUpdateParams},
|
layout::{Layout, LayoutParams, LayoutUpdateParams},
|
||||||
parser::{ParseDocumentParams, ParserState},
|
parser::{ParseDocumentParams, ParserState},
|
||||||
};
|
};
|
||||||
|
use wlx_common::locale::WayVRLangProvider;
|
||||||
|
|
||||||
pub struct TestbedAny {
|
pub struct TestbedAny {
|
||||||
pub layout: Layout,
|
pub layout: Layout,
|
||||||
@@ -28,8 +29,11 @@ impl TestbedAny {
|
|||||||
AssetPath::BuiltIn(&format!("gui/{name}.xml"))
|
AssetPath::BuiltIn(&format!("gui/{name}.xml"))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let lang_provider = WayVRLangProvider::default();
|
||||||
|
|
||||||
let globals = WguiGlobals::new(
|
let globals = WguiGlobals::new(
|
||||||
assets,
|
assets,
|
||||||
|
&lang_provider,
|
||||||
wgui::globals::Defaults::default(),
|
wgui::globals::Defaults::default(),
|
||||||
&WguiFontConfig::default(),
|
&WguiFontConfig::default(),
|
||||||
PathBuf::new(), // cwd
|
PathBuf::new(), // cwd
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::testbed::{Testbed, TestbedUpdateParams};
|
use crate::testbed::{Testbed, TestbedUpdateParams};
|
||||||
use dash_frontend::frontend::{self, FrontendUpdateParams};
|
use dash_frontend::frontend::{self, FrontendUpdateParams};
|
||||||
use wgui::layout::Layout;
|
use wgui::layout::Layout;
|
||||||
use wlx_common::dash_interface_emulated::DashInterfaceEmulated;
|
use wlx_common::{dash_interface_emulated::DashInterfaceEmulated, locale::WayVRLangProvider};
|
||||||
|
|
||||||
pub struct TestbedDashboard {
|
pub struct TestbedDashboard {
|
||||||
frontend: frontend::Frontend<()>,
|
frontend: frontend::Frontend<()>,
|
||||||
@@ -10,11 +10,13 @@ pub struct TestbedDashboard {
|
|||||||
impl TestbedDashboard {
|
impl TestbedDashboard {
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
let interface = DashInterfaceEmulated::new();
|
let interface = DashInterfaceEmulated::new();
|
||||||
|
let lang_provider = WayVRLangProvider::default();
|
||||||
|
|
||||||
let frontend = frontend::Frontend::new(
|
let frontend = frontend::Frontend::new(
|
||||||
frontend::InitParams {
|
frontend::InitParams {
|
||||||
interface: Box::new(interface),
|
interface: Box::new(interface),
|
||||||
has_monado: true,
|
has_monado: true,
|
||||||
|
lang_provider: &lang_provider,
|
||||||
},
|
},
|
||||||
&mut (),
|
&mut (),
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ use wgui::{
|
|||||||
window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra},
|
window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use wlx_common::locale::WayVRLangProvider;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum TestbedTask {
|
pub enum TestbedTask {
|
||||||
@@ -85,8 +86,11 @@ impl TestbedGeneric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(assets: Box<assets::Asset>) -> anyhow::Result<Self> {
|
pub fn new(assets: Box<assets::Asset>) -> anyhow::Result<Self> {
|
||||||
|
let lang_provider = WayVRLangProvider::default();
|
||||||
|
|
||||||
let globals = WguiGlobals::new(
|
let globals = WguiGlobals::new(
|
||||||
assets,
|
assets,
|
||||||
|
&lang_provider,
|
||||||
wgui::globals::Defaults::default(),
|
wgui::globals::Defaults::default(),
|
||||||
&WguiFontConfig::default(),
|
&WguiFontConfig::default(),
|
||||||
PathBuf::new(), // cwd
|
PathBuf::new(), // cwd
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use wlx_common::{
|
|||||||
SerializedWindowStates,
|
SerializedWindowStates,
|
||||||
},
|
},
|
||||||
config_io,
|
config_io,
|
||||||
|
locale::Language,
|
||||||
overlays::BackendAttribValue,
|
overlays::BackendAttribValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -143,6 +144,7 @@ pub struct AutoSettings {
|
|||||||
pub keyboard_middle_click_mode: AltModifier,
|
pub keyboard_middle_click_mode: AltModifier,
|
||||||
pub autostart_apps: Vec<WvrProcessLaunchParams>,
|
pub autostart_apps: Vec<WvrProcessLaunchParams>,
|
||||||
pub handsfree_pointer: HandsfreePointer,
|
pub handsfree_pointer: HandsfreePointer,
|
||||||
|
pub language: Option<Language>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_settings_path() -> PathBuf {
|
fn get_settings_path() -> PathBuf {
|
||||||
@@ -192,6 +194,7 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
|||||||
keyboard_middle_click_mode: config.keyboard_middle_click_mode,
|
keyboard_middle_click_mode: config.keyboard_middle_click_mode,
|
||||||
autostart_apps: config.autostart_apps.clone(),
|
autostart_apps: config.autostart_apps.clone(),
|
||||||
handsfree_pointer: config.handsfree_pointer,
|
handsfree_pointer: config.handsfree_pointer,
|
||||||
|
language: config.language,
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic
|
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use wgui::{
|
|||||||
};
|
};
|
||||||
use wlx_common::{
|
use wlx_common::{
|
||||||
dash_interface::{self, DashInterface, RecenterMode},
|
dash_interface::{self, DashInterface, RecenterMode},
|
||||||
|
locale::WayVRLangProvider,
|
||||||
overlays::{BackendAttrib, BackendAttribValue},
|
overlays::{BackendAttrib, BackendAttribValue},
|
||||||
};
|
};
|
||||||
use wlx_common::{
|
use wlx_common::{
|
||||||
@@ -79,6 +80,7 @@ impl DashFrontend {
|
|||||||
let frontend = frontend::Frontend::new(
|
let frontend = frontend::Frontend::new(
|
||||||
frontend::InitParams {
|
frontend::InitParams {
|
||||||
interface: Box::new(interface),
|
interface: Box::new(interface),
|
||||||
|
lang_provider: &WayVRLangProvider::from_config(&app.session.config),
|
||||||
has_monado: matches!(app.xr_backend, XrBackend::OpenXR),
|
has_monado: matches!(app.xr_backend, XrBackend::OpenXR),
|
||||||
},
|
},
|
||||||
app,
|
app,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use wgui::{
|
|||||||
drawing, font_config::WguiFontConfig, gfx::WGfx, globals::WguiGlobals, parser::parse_color_hex,
|
drawing, font_config::WguiFontConfig, gfx::WGfx, globals::WguiGlobals, parser::parse_color_hex,
|
||||||
renderer_vk::context::SharedContext as WSharedContext,
|
renderer_vk::context::SharedContext as WSharedContext,
|
||||||
};
|
};
|
||||||
|
use wlx_common::locale::WayVRLangProvider;
|
||||||
use wlx_common::{
|
use wlx_common::{
|
||||||
audio,
|
audio,
|
||||||
config::GeneralConfig,
|
config::GeneralConfig,
|
||||||
@@ -138,6 +139,8 @@ impl AppState {
|
|||||||
let mut desktop_finder = DesktopFinder::new();
|
let mut desktop_finder = DesktopFinder::new();
|
||||||
desktop_finder.refresh();
|
desktop_finder.refresh();
|
||||||
|
|
||||||
|
let lang_provider = WayVRLangProvider::from_config(&session.config);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
session,
|
session,
|
||||||
tasks,
|
tasks,
|
||||||
@@ -153,6 +156,7 @@ impl AppState {
|
|||||||
anchor_grabbed: false,
|
anchor_grabbed: false,
|
||||||
wgui_globals: WguiGlobals::new(
|
wgui_globals: WguiGlobals::new(
|
||||||
assets,
|
assets,
|
||||||
|
&lang_provider,
|
||||||
defaults,
|
defaults,
|
||||||
&WguiFontConfig::default(),
|
&WguiFontConfig::default(),
|
||||||
get_config_file_path(&theme),
|
get_config_file_path(&theme),
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ use std::ffi::OsStr;
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::{Component, Path, PathBuf};
|
use std::path::{Component, Path, PathBuf};
|
||||||
|
|
||||||
|
use crate::i18n::LangsList;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum AssetPath<'a> {
|
pub enum AssetPath<'a> {
|
||||||
WguiInternal(&'a str), // tied to internal wgui AssetProvider. Used internally
|
WguiInternal(&'a str), // tied to internal wgui AssetProvider. Used internally
|
||||||
@@ -83,6 +85,11 @@ impl Default for AssetPathOwned {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait LangProvider {
|
||||||
|
fn langs_list(&self) -> &dyn LangsList;
|
||||||
|
fn forced_lang(&self) -> Option<&str>;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait AssetProvider {
|
pub trait AssetProvider {
|
||||||
fn load_from_path(&mut self, path: &str) -> anyhow::Result<Vec<u8>>;
|
fn load_from_path(&mut self, path: &str) -> anyhow::Result<Vec<u8>>;
|
||||||
fn load_from_path_gzip(&mut self, path: &str) -> anyhow::Result<Vec<u8>> {
|
fn load_from_path_gzip(&mut self, path: &str) -> anyhow::Result<Vec<u8>> {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use anyhow::Context;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::{AssetPath, AssetProvider},
|
assets::{AssetPath, AssetProvider, LangProvider},
|
||||||
assets_internal, drawing,
|
assets_internal, drawing,
|
||||||
font_config::{WguiFontConfig, WguiFontSystem},
|
font_config::{WguiFontConfig, WguiFontSystem},
|
||||||
i18n::I18n,
|
i18n::I18n,
|
||||||
@@ -66,11 +66,12 @@ pub struct WguiGlobals(Rc<RefCell<Globals>>);
|
|||||||
impl WguiGlobals {
|
impl WguiGlobals {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
mut assets_builtin: Box<dyn AssetProvider>,
|
mut assets_builtin: Box<dyn AssetProvider>,
|
||||||
|
lang_provider: &dyn LangProvider,
|
||||||
defaults: Defaults,
|
defaults: Defaults,
|
||||||
font_config: &WguiFontConfig,
|
font_config: &WguiFontConfig,
|
||||||
asset_folder: PathBuf,
|
asset_folder: PathBuf,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let i18n_builtin = I18n::new(&mut assets_builtin)?;
|
let i18n_builtin = I18n::new(assets_builtin.as_mut(), lang_provider)?;
|
||||||
let assets_internal = Box::new(assets_internal::AssetInternal {});
|
let assets_internal = Box::new(assets_internal::AssetInternal {});
|
||||||
|
|
||||||
Ok(Self(Rc::new(RefCell::new(Globals {
|
Ok(Self(Rc::new(RefCell::new(Globals {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::{fmt::Display, rc::Rc, str};
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
use crate::assets::AssetProvider;
|
use crate::assets::{AssetProvider, LangProvider};
|
||||||
|
|
||||||
// a string which optionally has translation key in it
|
// a string which optionally has translation key in it
|
||||||
// it will hopefully support dynamic language changing soon
|
// it will hopefully support dynamic language changing soon
|
||||||
@@ -63,50 +63,76 @@ pub struct Locale {
|
|||||||
matched: String,
|
matched: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait LangsList {
|
||||||
|
fn all_locale(&self) -> &'static [&'static str]; // "en", "de", "es" (...)
|
||||||
|
fn default_lang(&self) -> &'static str; // "en"
|
||||||
|
}
|
||||||
|
|
||||||
impl Locale {
|
impl Locale {
|
||||||
pub fn all_locale() -> &'static [&'static str] {
|
fn match_locale<'o>(
|
||||||
&["de", "en", "es", "ja", "it", "pl", "zh_CN"]
|
default_lang: &'static str,
|
||||||
}
|
lang: &str,
|
||||||
pub fn default_lang() -> &'static str {
|
region: Option<&str>,
|
||||||
"en"
|
all_locales: &[&'o str],
|
||||||
}
|
) -> &'o str {
|
||||||
fn match_locale<'o>(lang: &str, region: Option<&str>, all_locales: &[&'o str]) -> &'o str {
|
|
||||||
if let Some(region) = region {
|
if let Some(region) = region {
|
||||||
let locale_str = format!("{lang}_{region}");
|
let locale_str = format!("{lang}_{region}");
|
||||||
if let Some(locale) = all_locales.iter().find(|&&l| l == locale_str) {
|
if let Some(locale) = all_locales.iter().find(|&&l| l == locale_str) {
|
||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
log::warn!("Unsupported locale \"{locale_str}\", trying \"{lang}\".");
|
log::warn!("Unsupported locale \"{locale_str}\", trying \"{lang}\".");
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Some(locale) = all_locales.iter().find(|&&l| l == lang) {
|
if let Some(locale) = all_locales.iter().find(|&&l| l == lang) {
|
||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefix = format!("{lang}_");
|
let prefix = format!("{lang}_");
|
||||||
if let Some(locale) = all_locales.iter().find(|&&l| l.starts_with(&prefix)) {
|
if let Some(locale) = all_locales.iter().find(|&&l| l.starts_with(&prefix)) {
|
||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
let locale = Self::default_lang();
|
log::warn!("Unsupported language \"{lang}\", defaulting to \"{default_lang}\".");
|
||||||
log::warn!("Unsupported language \"{lang}\", defaulting to \"{locale}\".");
|
default_lang
|
||||||
locale
|
|
||||||
}
|
}
|
||||||
pub fn new(lang: String, region: Option<String>) -> Self {
|
|
||||||
let matched = Self::match_locale(&lang, region.as_deref(), Self::all_locale()).to_string();
|
pub fn new(langs_list: &dyn LangsList, lang: String, region: Option<String>) -> Self {
|
||||||
|
let matched = Self::match_locale(
|
||||||
|
langs_list.default_lang(),
|
||||||
|
&lang,
|
||||||
|
region.as_deref(),
|
||||||
|
langs_list.all_locale(),
|
||||||
|
)
|
||||||
|
.to_string();
|
||||||
Self { lang, region, matched }
|
Self { lang, region, matched }
|
||||||
}
|
}
|
||||||
pub fn parse_str(locale: &str) -> Self {
|
|
||||||
let base = locale.split(|c| c == '.' || c == '@').next().unwrap_or(locale);
|
pub fn parse_str(langs_list: &dyn LangsList, locale: &str) -> Self {
|
||||||
let parts: Vec<&str> = base.split(|c| c == '_' || c == '-').collect();
|
let base = locale.split(['.', '@']).next().unwrap_or(locale);
|
||||||
|
let parts: Vec<&str> = base.split(['_', '-']).collect();
|
||||||
// Ensures the format is lang_REGION
|
// Ensures the format is lang_REGION
|
||||||
match parts.as_slice() {
|
match parts.as_slice() {
|
||||||
[lang, region, ..] => Self::new(lang.to_lowercase(), Some(region.to_uppercase())),
|
[lang, region, ..] => Self::new(langs_list, lang.to_lowercase(), Some(region.to_uppercase())),
|
||||||
[lang] if !lang.is_empty() => Self::new(lang.to_lowercase(), None),
|
[lang] if !lang.is_empty() => Self::new(langs_list, lang.to_lowercase(), None),
|
||||||
_ => Self::new("en".to_string(), None),
|
_ => Self::new(langs_list, langs_list.default_lang().to_string(), None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_env() -> Self {
|
|
||||||
|
pub fn from_env(lang_provider: &dyn LangProvider) -> Self {
|
||||||
|
let default_lang = lang_provider.langs_list().default_lang();
|
||||||
|
|
||||||
|
// check if forced language is set
|
||||||
|
if let Some(forced_lang) = lang_provider.forced_lang() {
|
||||||
|
let matched =
|
||||||
|
Self::match_locale(default_lang, forced_lang, None, lang_provider.langs_list().all_locale()).to_string();
|
||||||
|
return Self {
|
||||||
|
lang: forced_lang.to_string(),
|
||||||
|
region: None,
|
||||||
|
matched,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback to environment variables
|
||||||
use std::env;
|
use std::env;
|
||||||
let vars = ["LC_ALL", "LC_MESSAGES", "LANG"];
|
let vars = ["LC_ALL", "LC_MESSAGES", "LANG"];
|
||||||
let full_locale = vars
|
let full_locale = vars
|
||||||
@@ -114,13 +140,10 @@ impl Locale {
|
|||||||
.find_map(|&v| env::var(v).ok())
|
.find_map(|&v| env::var(v).ok())
|
||||||
.filter(|v| !v.is_empty() && v != "C" && v != "POSIX")
|
.filter(|v| !v.is_empty() && v != "C" && v != "POSIX")
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
log::warn!(
|
log::warn!("LC_ALL/LC_MESSAGES/LANG is not set, defaulting to \"{default_lang}\"");
|
||||||
"LC_ALL/LC_MESSAGES/LANG is not set, defaulting to \"{}\"",
|
default_lang.to_string()
|
||||||
Self::default_lang()
|
|
||||||
);
|
|
||||||
Self::default_lang().to_string()
|
|
||||||
});
|
});
|
||||||
Self::parse_str(&full_locale)
|
Self::parse_str(lang_provider.langs_list(), &full_locale)
|
||||||
}
|
}
|
||||||
pub fn get_matched(&self) -> &str {
|
pub fn get_matched(&self) -> &str {
|
||||||
&self.matched
|
&self.matched
|
||||||
@@ -155,13 +178,13 @@ fn find_translation<'a>(translation: &str, mut val: &'a serde_json::Value) -> Op
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl I18n {
|
impl I18n {
|
||||||
pub fn new(provider: &mut Box<dyn AssetProvider>) -> anyhow::Result<Self> {
|
pub fn new(asset_provider: &mut dyn AssetProvider, lang_provider: &dyn LangProvider) -> anyhow::Result<Self> {
|
||||||
let locale = Locale::from_env();
|
let locale = Locale::from_env(lang_provider);
|
||||||
log::info!("Guessed system language: {locale}");
|
log::info!("Guessed system language: {locale}");
|
||||||
|
|
||||||
let data_english = provider.load_from_path("lang/en.json")?;
|
let data_english = asset_provider.load_from_path("lang/en.json")?;
|
||||||
let path = format!("lang/{}.json", locale.get_matched());
|
let path = format!("lang/{}.json", locale.get_matched());
|
||||||
let data_translated = provider
|
let data_translated = asset_provider
|
||||||
.load_from_path(&path)
|
.load_from_path(&path)
|
||||||
.with_context(|| path.clone())
|
.with_context(|| path.clone())
|
||||||
.context("Could not load translation file")?;
|
.context("Could not load translation file")?;
|
||||||
@@ -189,7 +212,7 @@ impl I18n {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_locale(&self) -> &Locale {
|
pub const fn get_locale(&self) -> &Locale {
|
||||||
&self.locale
|
&self.locale
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +225,7 @@ impl I18n {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(translated_fallback) = find_translation(translation_key, &self.json_root_fallback) {
|
if let Some(translated_fallback) = find_translation(translation_key, &self.json_root_fallback) {
|
||||||
log::warn!("missing translation for key \"{translation_key}\", using \"en\" instead");
|
log::warn!("missing translation for key \"{translation_key}\", using fallback instead");
|
||||||
return Rc::from(format_translated(translated_fallback, sections));
|
return Rc::from(format_translated(translated_fallback, sections));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ use strum::{AsRefStr, EnumProperty, EnumString, VariantArray};
|
|||||||
use wayvr_ipc::packet_client::WvrProcessLaunchParams;
|
use wayvr_ipc::packet_client::WvrProcessLaunchParams;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
astr_containers::{AStrMap, AStrSet},
|
astr_containers::{AStrMap, AStrSet}, locale::{self}, overlays::{BackendAttribValue, ToastDisplayMethod, ToastTopic}, windowing::OverlayWindowState
|
||||||
overlays::{BackendAttribValue, ToastDisplayMethod, ToastTopic},
|
|
||||||
windowing::OverlayWindowState,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type PwTokenMap = AStrMap<String>;
|
pub type PwTokenMap = AStrMap<String>;
|
||||||
@@ -140,6 +138,8 @@ const fn def_max_height() -> u16 {
|
|||||||
1440
|
1440
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct GeneralConfig {
|
pub struct GeneralConfig {
|
||||||
#[serde(default = "def_theme_path")]
|
#[serde(default = "def_theme_path")]
|
||||||
@@ -151,6 +151,8 @@ pub struct GeneralConfig {
|
|||||||
pub color_faded: Option<String>,
|
pub color_faded: Option<String>,
|
||||||
pub color_background: Option<String>,
|
pub color_background: Option<String>,
|
||||||
|
|
||||||
|
pub language: Option<locale::Language>, // auto-detected at runtime if unset
|
||||||
|
|
||||||
#[serde(default = "def_one")]
|
#[serde(default = "def_one")]
|
||||||
#[serde(alias = "ui_animation_speed", alias = "animation_speed" /* old name */)]
|
#[serde(alias = "ui_animation_speed", alias = "animation_speed" /* old name */)]
|
||||||
pub ui_animation_speed: f32,
|
pub ui_animation_speed: f32,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ pub mod dash_interface;
|
|||||||
pub mod dash_interface_emulated;
|
pub mod dash_interface_emulated;
|
||||||
pub mod desktop_finder;
|
pub mod desktop_finder;
|
||||||
mod handle;
|
mod handle;
|
||||||
|
pub mod locale;
|
||||||
pub mod overlays;
|
pub mod overlays;
|
||||||
pub mod timestep;
|
pub mod timestep;
|
||||||
pub mod windowing;
|
pub mod windowing;
|
||||||
|
|||||||
88
wlx-common/src/locale.rs
Normal file
88
wlx-common/src/locale.rs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use strum::{AsRefStr, EnumProperty, EnumString, VariantArray};
|
||||||
|
|
||||||
|
use crate::config::GeneralConfig;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)]
|
||||||
|
pub enum Language {
|
||||||
|
#[strum(props(Text = "English"))]
|
||||||
|
English,
|
||||||
|
#[strum(props(Text = "Polski"))]
|
||||||
|
Polish,
|
||||||
|
#[strum(props(Text = "日本語"))]
|
||||||
|
Japanese,
|
||||||
|
#[strum(props(Text = "German"))]
|
||||||
|
German,
|
||||||
|
#[strum(props(Text = "Italiano"))]
|
||||||
|
Italian,
|
||||||
|
#[strum(props(Text = "简体中文"))]
|
||||||
|
ChineseSimplified,
|
||||||
|
#[strum(props(Text = "Español"))]
|
||||||
|
Spanish,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Language {
|
||||||
|
pub const fn code(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Language::English => "en",
|
||||||
|
Language::Polish => "pl",
|
||||||
|
Language::Japanese => "ja",
|
||||||
|
Language::German => "de",
|
||||||
|
Language::Italian => "it",
|
||||||
|
Language::ChineseSimplified => "zh_CN",
|
||||||
|
Language::Spanish => "es",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn get_default() -> Self {
|
||||||
|
Self::English
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn all_codes() -> &'static [&'static str] {
|
||||||
|
&["en", "pl", "ja", "de", "it", "zh_CN", "es"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WayVRLangsList {}
|
||||||
|
|
||||||
|
impl wgui::i18n::LangsList for WayVRLangsList {
|
||||||
|
fn all_locale(&self) -> &'static [&'static str] {
|
||||||
|
Language::all_codes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_lang(&self) -> &'static str {
|
||||||
|
Language::get_default().code()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
const G_LANGS_LIST: WayVRLangsList = WayVRLangsList {};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct WayVRLangProvider {
|
||||||
|
forced_lang: Option<Rc<str>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl wgui::assets::LangProvider for WayVRLangProvider {
|
||||||
|
fn langs_list(&self) -> &dyn wgui::i18n::LangsList {
|
||||||
|
&G_LANGS_LIST
|
||||||
|
}
|
||||||
|
|
||||||
|
fn forced_lang(&self) -> Option<&str> {
|
||||||
|
self.forced_lang.as_ref().map(|lang| lang.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WayVRLangProvider {
|
||||||
|
pub fn from_config(config: &GeneralConfig) -> Self {
|
||||||
|
if let Some(lang) = &config.language {
|
||||||
|
return Self {
|
||||||
|
forced_lang: Some(lang.code().into()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user