range sliders in settings

This commit is contained in:
galister 2026-05-13 16:38:15 +09:00
parent 20743f91eb
commit 80bfb177be
14 changed files with 102 additions and 75 deletions

View File

@ -17,6 +17,11 @@
<Slider id="${id}" width="250" height="24" min_value="${min}" max_value="${max}" step="${step}" value="${value}" tooltip="${tooltip}" />
</template>
<template name="RangeSetting">
<label text="${text}" translation="${translation}" />
<Slider id="${id}" width="250" height="24" min_value="${min}" max_value="${max}" step="${step}" value="${value}" value2="${value2}" tooltip="${tooltip}" />
</template>
<template name="SelectSetting">
<label text="${text}" translation="${translation}" tooltip="${tooltip}" />
<RadioGroup id="${id}" />

View File

@ -35,8 +35,6 @@
"SCROLL_SPEED": "Scrollgeschwindigkeit",
"LONG_PRESS_DURATION": "Dauer für lange Drückvorgänge",
"POINTER_LERP_FACTOR": "Zeigerglättung",
"XR_CLICK_SENSITIVITY": "XR-Klicksensitivität",
"XR_CLICK_SENSITIVITY_RELEASE": "XR-Loslassempfindlichkeit",
"CLICK_FREEZE_TIME_MS": "Klick-Freeze-Zeit (ms)",
"MISC": "Verschiedenes",
"XWAYLAND_BY_DEFAULT": "Standardmäßig Apps im Kompatibilitätsmodus ausführen",
@ -45,17 +43,11 @@
"SCREEN_RENDER_DOWN": "Bildschirm bei niedrigerer Auflösung rendern",
"UPRIGHT_SCREEN_FIX_HELP": "Behebt hochstehende Bildschirme auf einigen Desktops",
"DOUBLE_CURSOR_FIX_HELP": "Aktivieren Sie dies, wenn Sie 2 Cursor sehen",
"XR_CLICK_SENSITIVITY_HELP": "Analoge Trigger-Empfindlichkeit",
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Muss niedriger als Klick sein",
"CLICK_FREEZE_TIME_MS_HELP": "Hilft bei der Präzision von Doppelklicks",
"LEFT_HANDED_MOUSE_HELP": "Verwenden Sie diese Option, wenn die Maustasten vertauscht sind",
"BLOCK_GAME_INPUT_HELP": "Blockiert alle Eingaben, wenn ein Overlay angefahren wird",
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "Blockiere die Eingabe nicht, wenn die Überwachung aktiviert ist",
"USE_SKYBOX_HELP": "Zeige einen Skybox, wenn keine Szenen-App oder Passthrough vorhanden ist",
"WATCH_VIEW_ANGLE_MIN": "Blickwinkel Min (Watch)",
"WATCH_VIEW_ANGLE_MIN_HELP": "Winkel, ab dem die Watch zu verblassen beginnt",
"WATCH_VIEW_ANGLE_MAX": "Blickwinkel Max (Watch)",
"WATCH_VIEW_ANGLE_MAX_HELP": "Winkel, ab dem die Watch voll sichtbar wird",
"USE_PASSTHROUGH_HELP": "Aktiviere Passthrough, falls die XR-Laufzeitumgebung dies unterstützt",
"SCREEN_RENDER_DOWN_HELP": "Hilft bei Aliasing auf hochauflösenden Bildschirmen",
"SETS_ON_WATCH": "Sets auf der Watch",

View File

@ -114,16 +114,12 @@
"USE_PASSTHROUGH_HELP": "Allow passthrough if the XR runtime supports it",
"USE_SKYBOX": "Enable skybox",
"USE_SKYBOX_HELP": "Show a skybox if there's no scene app or passthrough",
"WATCH_VIEW_ANGLE_MIN": "Watch view angle min",
"WATCH_VIEW_ANGLE_MIN_HELP": "Angle where the watch starts to fade away",
"WATCH_VIEW_ANGLE_MAX": "Watch view angle max",
"WATCH_VIEW_ANGLE_MAX_HELP": "Angle where the watch is fully visible",
"WATCH_VIEW_ANGLE": "Watch view angles",
"WATCH_VIEW_ANGLE_HELP": "Control how the watch fades away",
"GRID_OPACITY": "Floor grid opacity",
"GRID_OPACITY_HELP": "Opacity of the floor grid when the skybox is enabled",
"XR_CLICK_SENSITIVITY": "XR click sensitivity",
"XR_CLICK_SENSITIVITY_HELP": "Analog trigger sensitivity",
"XR_CLICK_SENSITIVITY_RELEASE": "XR release sensitivity",
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Must be lower than click",
"XR_CLICK_SENSITIVITY": "XR trigger sensitivity",
"XR_CLICK_SENSITIVITY_HELP": "Press and release values for analog triggers",
"XWAYLAND_BY_DEFAULT": "Run apps in Compatibility mode by default"
},
"APPLICATION_LAUNCHER": "Application launcher",

View File

@ -35,8 +35,6 @@
"SCROLL_SPEED": "Velocidad de desplazamiento",
"LONG_PRESS_DURATION": "Duración de la pulsación larga",
"POINTER_LERP_FACTOR": "Suavizado del puntero",
"XR_CLICK_SENSITIVITY": "Sensibilidad del clic XR",
"XR_CLICK_SENSITIVITY_RELEASE": "Sensibilidad de liberación de OpenXR",
"CLICK_FREEZE_TIME_MS": "Tiempo de congelación al hacer clic (ms)",
"MISC": "Miscelánea",
"XWAYLAND_BY_DEFAULT": "Ejecutar aplicaciones en modo de compatibilidad por defecto",
@ -45,17 +43,11 @@
"SCREEN_RENDER_DOWN": "Renderizar pantalla a menor resolución",
"UPRIGHT_SCREEN_FIX_HELP": "Corrige pantallas en posición vertical en algunos escritorios",
"DOUBLE_CURSOR_FIX_HELP": "Habilita esto si ves 2 cursores",
"XR_CLICK_SENSITIVITY_HELP": "Sensibilidad del gatillo analógico",
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Debe ser inferior a 'click'",
"CLICK_FREEZE_TIME_MS_HELP": "Ayuda con la precisión de los dobles clics",
"LEFT_HANDED_MOUSE_HELP": "Utilice esto si los botones del ratón están intercambiados",
"BLOCK_GAME_INPUT_HELP": "Bloquea toda la entrada cuando se pasa el cursor sobre un overlay",
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "No bloquear la entrada cuando el cursor está sobre la ventana",
"USE_SKYBOX_HELP": "Mostrar una skybox si no hay una aplicación de escena o passthrough",
"WATCH_VIEW_ANGLE_MIN": "Watch view angle min",
"WATCH_VIEW_ANGLE_MIN_HELP": "Angle where the watch starts to fade away",
"WATCH_VIEW_ANGLE_MAX": "Watch view angle max",
"WATCH_VIEW_ANGLE_MAX_HELP": "Angle where the watch is fully visible",
"USE_PASSTHROUGH_HELP": "Permitir passthrough si el entorno de ejecución XR lo admite",
"SCREEN_RENDER_DOWN_HELP": "Ayuda a reducir el aliasing en pantallas de alta resolución",
"SETS_ON_WATCH": "Conjuntos en el reloj",

View File

@ -97,14 +97,6 @@
"USE_PASSTHROUGH_HELP": "Consenti il passthrough se supportato dal runtime XR",
"USE_SKYBOX": "Abilita skybox",
"USE_SKYBOX_HELP": "Mostra uno skybox se non c'è un'app di scena o passthrough",
"WATCH_VIEW_ANGLE_MIN": "Watch view angle min",
"WATCH_VIEW_ANGLE_MIN_HELP": "Angle where the watch starts to fade away",
"WATCH_VIEW_ANGLE_MAX": "Watch view angle max",
"WATCH_VIEW_ANGLE_MAX_HELP": "Angle where the watch is fully visible",
"XR_CLICK_SENSITIVITY": "Sensibilità del click XR",
"XR_CLICK_SENSITIVITY_HELP": "Sensibilità del trigger analogico",
"XR_CLICK_SENSITIVITY_RELEASE": "Sensibilità di rilascio XR",
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Deve essere inferiore al clic",
"XWAYLAND_BY_DEFAULT": "Esegui le app in modalità Compatibilità per impostazione predefinita",
"AUTOSTART_APPS": "App da avviare all'avvio",
"HANDSFREE_POINTER": "Modalità a mani libere",

View File

@ -35,8 +35,6 @@
"SCROLL_SPEED": "スクロール速度",
"LONG_PRESS_DURATION": "長押し時間",
"POINTER_LERP_FACTOR": "ポインターのスムージング",
"XR_CLICK_SENSITIVITY": "XRクリック感度",
"XR_CLICK_SENSITIVITY_RELEASE": "XRリリース感度",
"CLICK_FREEZE_TIME_MS": "クリックで一時停止時間 (ms)",
"MISC": "その他",
"XWAYLAND_BY_DEFAULT": "アプリ実行のデフォルトは互換モード",
@ -45,17 +43,11 @@
"SCREEN_RENDER_DOWN": "画面の解像度を縮小",
"UPRIGHT_SCREEN_FIX_HELP": "一部のデスクトップで縦向きの画面を修正",
"DOUBLE_CURSOR_FIX_HELP": "2つのカーソルが表示される場合は、これを有効にします",
"XR_CLICK_SENSITIVITY_HELP": "アナログトリガの感度",
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "クリックより低くする必要があります",
"CLICK_FREEZE_TIME_MS_HELP": "ダブルクリックの精度向上に役立ちます",
"LEFT_HANDED_MOUSE_HELP": "マウスボタンが入れ替わっている場合に有効にします",
"BLOCK_GAME_INPUT_HELP": "オーバーレイ上にマウスカーソルがあるときに入力をブロックします",
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "ウォッチがホバーされているときは入力をブロックしない",
"USE_SKYBOX_HELP": "シーンアプリまたはパススルーがない場合にスカイボックスを表示します",
"WATCH_VIEW_ANGLE_MIN": "Watch view angle min",
"WATCH_VIEW_ANGLE_MIN_HELP": "Angle where the watch starts to fade away",
"WATCH_VIEW_ANGLE_MAX": "Watch view angle max",
"WATCH_VIEW_ANGLE_MAX_HELP": "Angle where the watch is fully visible",
"USE_PASSTHROUGH_HELP": "XRランタイムがサポートしていれば、パススルーを有効にします",
"SCREEN_RENDER_DOWN_HELP": "高解像度スクリーンでのエイリアシングを軽減します",
"SETS_ON_WATCH": "ウォッチのセット",

View File

@ -30,8 +30,6 @@
"SCROLL_SPEED": "Prędkość przewijania",
"LONG_PRESS_DURATION": "Czas długiego przytrzymania",
"POINTER_LERP_FACTOR": "Wygładzanie wskaźnika",
"XR_CLICK_SENSITIVITY": "Czułość kliknięć XR",
"XR_CLICK_SENSITIVITY_RELEASE": "Czułość zwalniania XR",
"CLICK_FREEZE_TIME_MS": "Czas zamrożenia po kliknięciu (ms)",
"XWAYLAND_BY_DEFAULT": "Uruchamiaj aplikacje domyślnie w trybie kompatybilności",
"UPRIGHT_SCREEN_FIX": "Naprawa pozycji ekranu",
@ -39,17 +37,11 @@
"SCREEN_RENDER_DOWN": "Renderuj ekran w niższej rozdzielczości",
"UPRIGHT_SCREEN_FIX_HELP": "Naprawia pionowe ekrany na niektórych komputerach",
"DOUBLE_CURSOR_FIX_HELP": "Włącz to, jeśli widzisz 2 kursory",
"XR_CLICK_SENSITIVITY_HELP": "Czułość analogowego spustu",
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Musi być niższa niż kliknięcie",
"CLICK_FREEZE_TIME_MS_HELP": "Pomaga w precyzji podwójnego kliknięcia",
"LEFT_HANDED_MOUSE_HELP": "Użyj tego, jeśli przyciski myszy są zamienione",
"BLOCK_GAME_INPUT_HELP": "Blokuje wszystkie dane wejściowe, gdy kursor najedzie na nakładkę",
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "Nie blokuj inputu, gdy wskaźnik jest najedzony",
"USE_SKYBOX_HELP": "Wyświetlaj niebo, jeśli nie ma aplikacji sceny lub passthrough",
"WATCH_VIEW_ANGLE_MIN": "Kąt widzenia zegarka min",
"WATCH_VIEW_ANGLE_MIN_HELP": "Kąt, przy którym zegarek zaczyna zanikać",
"WATCH_VIEW_ANGLE_MAX": "Kąt widzenia zegarka max",
"WATCH_VIEW_ANGLE_MAX_HELP": "Kąt, przy którym zegarek staje się w pełni widoczny",
"USE_PASSTHROUGH_HELP": "Pozwól na passthrough, jeśli runtime XR to obsługuje",
"SCREEN_RENDER_DOWN_HELP": "Pomaga redukować aliasing na ekranach o wysokiej rozdzielczości",
"SETS_ON_WATCH": "Lista zestawów na zegarku",

View File

@ -97,14 +97,6 @@
"USE_PASSTHROUGH_HELP": "如果 XR 运行时支持,则允许穿透",
"USE_SKYBOX": "启用天空盒",
"USE_SKYBOX_HELP": "如果没有场景应用或穿透,则显示天空盒",
"WATCH_VIEW_ANGLE_MIN": "手表视角角度最小值",
"WATCH_VIEW_ANGLE_MIN_HELP": "手表开始淡出的角度",
"WATCH_VIEW_ANGLE_MAX": "手表视角角度最大值",
"WATCH_VIEW_ANGLE_MAX_HELP": "手表完全可见的角度",
"XR_CLICK_SENSITIVITY": "XR 点击灵敏度",
"XR_CLICK_SENSITIVITY_HELP": "模拟扳机灵敏度",
"XR_CLICK_SENSITIVITY_RELEASE": "XR 释放灵敏度",
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "必须低于点击灵敏度",
"XWAYLAND_BY_DEFAULT": "默认以兼容模式运行应用",
"AUTOSTART_APPS": "开机启动应用",
"HANDSFREE_POINTER": "免提模式",

View File

@ -1,6 +1,6 @@
use std::{collections::HashMap, rc::Rc};
use crate::tab::settings::{self, SettingType, Task, horiz_cell, mount_requires_restart};
use crate::tab::settings::{self, horiz_cell, mount_requires_restart, SettingType, Task};
use wgui::{
components::{
button::{ButtonClickEvent, ComponentButton},
@ -124,6 +124,62 @@ pub fn options_slider_f32(
Ok(())
}
pub fn options_range_f32(
mp: &mut MacroParams,
parent: WidgetID,
setting: SettingType,
setting2: SettingType,
min: f32,
max: f32,
step: f32,
) -> anyhow::Result<()> {
let id = mp.idx.to_string();
mp.idx += 1;
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
match setting.get_translation() {
Ok(translation) => params.insert(Rc::from("translation"), translation.into()),
Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()),
};
if let Some(tooltip) = setting.get_tooltip() {
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
}
let value = setting.mut_f32(mp.config).to_string();
let value2 = setting2.mut_f32(mp.config).to_string();
params.insert(Rc::from("value"), Rc::from(value));
params.insert(Rc::from("value2"), Rc::from(value2));
params.insert(Rc::from("min"), Rc::from(min.to_string()));
params.insert(Rc::from("max"), Rc::from(max.to_string()));
params.insert(Rc::from("step"), Rc::from(step.to_string()));
let id_cell = horiz_cell(mp.layout, parent)?;
mp.parser_state
.instantiate_template(mp.doc_params, "RangeSetting", 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)?;
slider.on_value_changed(Box::new({
let tasks = mp.tasks.clone();
move |_common, e| {
if matches!(e.index, wgui::components::slider::ValueIndex::Primary) {
tasks.push(Task::UpdateFloat(setting, e.value));
} else {
tasks.push(Task::UpdateFloat(setting2, e.value));
}
}
}));
Ok(())
}
pub fn options_slider_i32(
mp: &mut MacroParams,
parent: WidgetID,

View File

@ -444,10 +444,10 @@ impl SettingType {
Self::UprightScreenFix => Ok("APP_SETTINGS.UPRIGHT_SCREEN_FIX"),
Self::UsePassthrough => Ok("APP_SETTINGS.USE_PASSTHROUGH"),
Self::UseSkybox => Ok("APP_SETTINGS.USE_SKYBOX"),
Self::WatchViewAngleMax => Ok("APP_SETTINGS.WATCH_VIEW_ANGLE_MAX"),
Self::WatchViewAngleMin => Ok("APP_SETTINGS.WATCH_VIEW_ANGLE_MIN"),
Self::WatchViewAngleMax => Ok("APP_SETTINGS.WATCH_VIEW_ANGLE"),
Self::WatchViewAngleMin => Ok("APP_SETTINGS.WATCH_VIEW_ANGLE"),
Self::XrClickSensitivity => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY"),
Self::XrClickSensitivityRelease => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE"),
Self::XrClickSensitivityRelease => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY"),
Self::XwaylandByDefault => Ok("APP_SETTINGS.XWAYLAND_BY_DEFAULT"),
}
}
@ -469,9 +469,9 @@ impl SettingType {
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"),
Self::WatchViewAngleMin => Some("APP_SETTINGS.WATCH_VIEW_ANGLE_MIN_HELP"),
Self::WatchViewAngleMax => Some("APP_SETTINGS.WATCH_VIEW_ANGLE_MAX_HELP"),
Self::XrClickSensitivityRelease => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_HELP"),
Self::WatchViewAngleMin => Some("APP_SETTINGS.WATCH_VIEW_ANGLE_HELP"),
Self::WatchViewAngleMax => Some("APP_SETTINGS.WATCH_VIEW_ANGLE_HELP"),
_ => None,
}
}

View File

@ -1,6 +1,8 @@
use crate::tab::settings::{
macros::{
options_category, options_checkbox, options_dropdown, options_range_f32, options_slider_f32, options_slider_i32,
},
SettingType, SettingsMountParams, SettingsTab,
macros::{options_category, options_checkbox, options_dropdown, options_slider_f32, options_slider_i32},
};
pub struct State {}
@ -25,8 +27,16 @@ impl State {
options_slider_f32(par.mp, c, SettingType::ScrollSpeed, 0.1, 5.0, 0.1)?;
options_slider_f32(par.mp, c, SettingType::LongPressDuration, 0.1, 2.0, 0.1)?;
options_slider_f32(par.mp, c, SettingType::PointerLerpFactor, 0.1, 1.0, 0.1)?;
options_slider_f32(par.mp, c, SettingType::XrClickSensitivity, 0.1, 1.0, 0.1)?;
options_slider_f32(par.mp, c, SettingType::XrClickSensitivityRelease, 0.1, 1.0, 0.1)?;
options_range_f32(
par.mp,
c,
SettingType::XrClickSensitivityRelease,
SettingType::XrClickSensitivity,
0.1,
0.9,
0.1,
)?;
options_slider_i32(par.mp, c, SettingType::ClickFreezeTimeMs, 0, 500, 50)?;
Ok(State {})
}

View File

@ -1,6 +1,6 @@
use crate::tab::settings::{
macros::{options_category, options_checkbox, options_range_f32, options_slider_f32},
SettingType, SettingsMountParams, SettingsTab,
macros::{options_category, options_checkbox, options_slider_f32},
};
pub struct State {}
@ -19,8 +19,15 @@ impl State {
options_checkbox(par.mp, c, SettingType::BlockGameInput)?;
options_checkbox(par.mp, c, SettingType::BlockGameInputIgnoreWatch)?;
options_checkbox(par.mp, c, SettingType::BlockPosesOnKbdInteraction)?;
options_slider_f32(par.mp, c, SettingType::WatchViewAngleMin, 0.0, 1.0, 0.01)?;
options_slider_f32(par.mp, c, SettingType::WatchViewAngleMax, 0.0, 1.0, 0.01)?;
options_range_f32(
par.mp,
c,
SettingType::WatchViewAngleMin,
SettingType::WatchViewAngleMax,
0.1,
1.0,
0.1,
)?;
Ok(State {})
}
}

View File

@ -1,6 +1,6 @@
use crate::tab::settings::{
SettingType, SettingsMountParams, SettingsTab,
macros::{options_category, options_checkbox, options_dropdown, options_slider_f32},
SettingType, SettingsMountParams, SettingsTab,
};
pub struct State {}
@ -21,7 +21,7 @@ impl State {
options_checkbox(par.mp, c, SettingType::HideGrabHelp)?;
options_slider_f32(par.mp, c, SettingType::UiAnimationSpeed, 0.5, 5.0, 0.1)?; // min, max, step
options_slider_f32(par.mp, c, SettingType::UiGradientIntensity, 0.0, 1.0, 0.05)?; // min, max, step
options_slider_f32(par.mp, c, SettingType::UiRoundMultiplier, 0.5, 5.0, 0.1)?;
options_slider_f32(par.mp, c, SettingType::UiRoundMultiplier, 0.1, 5.0, 0.1)?;
options_checkbox(par.mp, c, SettingType::SetsOnWatch)?;
options_checkbox(par.mp, c, SettingType::Clock12h)?;
Ok(State {})

View File

@ -1,4 +1,4 @@
use std::{cell::RefCell, rc::Rc};
use std::{cell::RefCell, f32, rc::Rc};
use glam::{Mat4, Vec2, Vec3};
use taffy::prelude::{length, percent};
@ -51,7 +51,7 @@ impl Value {
// get the step index from min
let mut k = ((clamped - limits.min_value) / limits.step).round();
let k_max = (span / limits.step).floor();
let k_max = (span / limits.step).round();
if k < 0.0 {
k = 0.0;
}
@ -278,6 +278,7 @@ impl State {
fn set_value(&mut self, common: &mut CallbackDataCommon, data: &Data, index: ValueIndex, new_value: f32) {
let val1 = self.value1.get();
let val2 = self.value2.as_ref().map(|v| v.get()).unwrap_or(f32::MAX);
let Some(value) = (match index {
ValueIndex::Primary => Some(&mut self.value1),
@ -297,9 +298,9 @@ impl State {
let before = value.get();
if index == ValueIndex::Secondary {
value.set(&self.limits, new_value.max(val1));
value.set(&self.limits, new_value.max(val1 + self.limits.step));
} else {
value.set(&self.limits, new_value);
value.set(&self.limits, new_value.min(val2 - self.limits.step));
}
let has_changed = value.get() != before;