defaults for positioning, opecity, curvature

This commit is contained in:
galister 2026-08-02 01:24:12 +09:00
parent 4eeb0afb0b
commit 5ba7d1fdad
20 changed files with 126 additions and 29 deletions

View File

@ -117,6 +117,10 @@
"DOUBLE_CURSOR_FIX_HELP": "Enable this if you see 2 cursors",
"DEFAULT_OVERLAY_SCALE": "Default overlay size",
"DEFAULT_OVERLAY_SCALE_HELP": "Spawn new overlays at this scale.",
"DEFAULT_CURVATURE": "Default overlay curvature",
"DEFAULT_OPACITY": "Default overlay opacity",
"DEFAULT_POSITIONING": "Default overlay positioning",
"DEFAULT_OVERLAY_DEFAULTS_HELP": "Only applies to new overlays",
"ENABLED": "Enabled",
"FEATURES": "Features",
"FOCUS_FOLLOWS_MOUSE_MODE": "Mouse move on trigger touch",
@ -149,6 +153,12 @@
"NO_SKYMAPS_FOUND": "No skymaps found",
"OPAQUE_BACKGROUND": "Opaque background",
"OPTION": {
"ANCHORED": "Anchored",
"FLOATING": "Floating",
"STATIC": "Static",
"ANCHORED_HELP": "Moves with center marker. Recommended.",
"FLOATING_HELP": "Moves independently, recenters.\nEasy to misplace; not recommended.",
"STATIC_HELP": "Stays in place relative to world.",
"AUTO": "Automatic",
"AUTO_HELP": "ScreenCopy GPU if supported,\notherwise PipeWire GPU.",
"EYE_ONLY": "Eye laser",

View File

@ -311,6 +311,10 @@ pub(crate) enum SettingType {
CaptureMethod,
ClickFreezeTimeMs,
Clock12h,
DefaultCurvature,
DefaultOpacity,
DefaultOverlayScale,
DefaultPositioning,
DoubleCursorFix,
EnableWatch,
FocusFollowsMouseMode,
@ -330,7 +334,6 @@ pub(crate) enum SettingType {
LongPressDuration,
NotificationsEnabled,
NotificationsSoundEnabled,
DefaultOverlayScale,
OpaqueBackground,
MouseAcceleration,
PointerLerpFactor,
@ -405,6 +408,8 @@ impl SettingType {
pub fn mut_f32(self, config: &mut GeneralConfig) -> &mut f32 {
match self {
Self::DefaultCurvature => &mut config.default_curvature,
Self::DefaultOpacity => &mut config.default_opacity,
Self::DefaultOverlayScale => &mut config.default_overlay_scale,
Self::GridOpacity => &mut config.grid_opacity,
Self::LongPressDuration => &mut config.long_press_duration,
@ -439,6 +444,10 @@ impl SettingType {
Self::CaptureMethod => {
config.capture_method = wlx_common::config::CaptureMethod::from_str(value).expect("Invalid enum value!")
}
Self::DefaultPositioning => {
config.default_positioning =
wlx_common::config::DefaultPositioning::from_str(value).expect("Invalid enum value!")
}
Self::InputCaptureMethod => {
config.wvr_input_capture = wlx_common::config::InputCaptureMethod::from_str(value).expect("Invalid enum value!")
}
@ -466,6 +475,7 @@ impl SettingType {
fn get_enum_title(self, config: &mut GeneralConfig) -> Translation {
match self {
Self::CaptureMethod => Self::get_enum_title_inner(config.capture_method),
Self::DefaultPositioning => Self::get_enum_title_inner(config.default_positioning),
Self::InputCaptureMethod => Self::get_enum_title_inner(config.wvr_input_capture),
Self::InputEmulationMethod => Self::get_enum_title_inner(config.input_emulation_method),
Self::KeyboardMiddleClick => Self::get_enum_title_inner(config.keyboard_middle_click_mode),
@ -508,7 +518,10 @@ impl SettingType {
Self::CaptureMethod => Ok("APP_SETTINGS.CAPTURE_METHOD"),
Self::ClickFreezeTimeMs => Ok("APP_SETTINGS.CLICK_FREEZE_TIME_MS"),
Self::Clock12h => Ok("APP_SETTINGS.CLOCK_12H"),
Self::DefaultCurvature => Ok("APP_SETTINGS.DEFAULT_CURVATURE"),
Self::DefaultOpacity => Ok("APP_SETTINGS.DEFAULT_OPACITY"),
Self::DefaultOverlayScale => Ok("APP_SETTINGS.DEFAULT_OVERLAY_SCALE"),
Self::DefaultPositioning => Ok("APP_SETTINGS.DEFAULT_POSITIONING"),
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
Self::FocusFollowsMouseMode => Ok("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE"),
Self::GridOpacity => Ok("APP_SETTINGS.GRID_OPACITY"),
@ -565,7 +578,10 @@ impl SettingType {
Self::BlockGameInputIgnoreWatch => Some("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH_HELP"),
Self::BlockPosesOnKbdInteraction => Some("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION_HELP"),
Self::CaptureMethod => Some("APP_SETTINGS.CAPTURE_METHOD_HELP"),
Self::DefaultCurvature => Some("APP_SETTINGS.OVERLAY_DEFAULTS_HELP"),
Self::DefaultOpacity => Some("APP_SETTINGS.OVERLAY_DEFAULTS_HELP"),
Self::DefaultOverlayScale => Some("APP_SETTINGS.DEFAULT_OVERLAY_SCALE_HELP"),
Self::DefaultPositioning => Some("APP_SETTINGS.OVERLAY_DEFAULTS_HELP"),
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
Self::GridOpacity => Some("APP_SETTINGS.GRID_OPACITY_HELP"),
Self::HandsfreeAltTab => Some("APP_SETTINGS.HANDSFREE_ALT_TAB_HELP"),

View File

@ -67,7 +67,10 @@ impl State {
options_checkbox(par.mp, c, SettingType::OpaqueBackground)?;
options_checkbox(par.mp, c, SettingType::HideUsername)?;
options_checkbox(par.mp, c, SettingType::HideGrabHelp)?;
options_slider_f32(par.mp, c, SettingType::DefaultCurvature, 0.0, 0.5, 0.05)?; // min, max, step
options_slider_f32(par.mp, c, SettingType::DefaultOpacity, 0.05, 1.0, 0.05)?; // min, max, step
options_slider_f32(par.mp, c, SettingType::DefaultOverlayScale, 0.7, 1.5, 0.05)?; // min, max, step
options_dropdown::<wlx_common::config::DefaultPositioning>(par.mp, c, &SettingType::DefaultPositioning)?;
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.1, 5.0, 0.1)?;

View File

@ -49,7 +49,6 @@
"OPACITY": "Undurchsichtigkeit",
"POSITIONING": "Positionierung",
"RESIZE_PRESS_AND_DRAG": "Größe ändern (gedrückt halten & ziehen)",
"POS_STATIC": "Statisch: Bleibt an Ort und Stelle und wird niemals neu zentriert.",
"POS_ANCHORED": "Verankert: Bewegt sich zusammen mit dem Rest des Sets. Standard.",
"POS_FLOATING": "Schwebend: Bleibt an Ort und Stelle, wird beim Anzeigen neu zentriert.",
"POS_HMD": "Folge dem Headset.",
@ -153,4 +152,4 @@
"CLOSE": "Fokussierte App schließen",
"MOUSE": "Echte Mausklicks & Scrollen werden auch auf den VR-Zeiger übertragen"
}
}
}

View File

@ -62,7 +62,7 @@
"POS_HAND_L": "Follow the left hand.",
"POS_HAND_R": "Follow the right hand.",
"POS_HMD": "Follow the HMD.",
"POS_STATIC": "Static: Not part of any set, no recenter.",
"POS_STATIC": "Static: Stays in place relative to world.",
"POSITIONING": "Positioning",
"RESIZE_PRESS_AND_DRAG": "Resize (press & drag)",
"RESIZE_CORNER": "Drag to resize",

View File

@ -49,7 +49,6 @@
"OPACITY": "Opacidad",
"POSITIONING": "Posicionamiento",
"RESIZE_PRESS_AND_DRAG": "Redimensionar (presionar y arrastrar)",
"POS_STATIC": "Estático: Permanece en su lugar y nunca se recentra.",
"POS_ANCHORED": "Anclado: Se mueve junto con el resto del conjunto. Predeterminado.",
"POS_FLOATING": "Flotante: Permanece en su lugar, se recentra cuando se muestra.",
"POS_HMD": "Seguir el HMD.",
@ -153,4 +152,4 @@
"CLOSE": "Cerrar aplicación enfocada",
"MOUSE": "Los clics y el desplazamiento del ratón real también se traducen al puntero de VR"
}
}
}

View File

@ -45,7 +45,6 @@
"POS_HAND_L": "Segui la mano sinistra.",
"POS_HAND_R": "Segui la mano destra.",
"POS_HMD": "Segui l'HMD.",
"POS_STATIC": "Statico: non fa parte di alcun set, senza recentratura.",
"POSITIONING": "Posizionamento",
"RESIZE_PRESS_AND_DRAG": "Ridimensiona (premi e trascina)",
"STEREO_3D_MODE": {
@ -151,4 +150,4 @@
"CLOSE": "Chiudi l'app focalizzata",
"MOUSE": "I clic e lo scorrimento del mouse reale vengono tradotti anche nel puntatore VR"
}
}
}

View File

@ -49,7 +49,6 @@
"OPACITY": "不透明度",
"POSITIONING": "位置付け",
"RESIZE_PRESS_AND_DRAG": "サイズ変更(押してドラッグ)",
"POS_STATIC": "固定:置かれた場所に留まり、再センタリングされません。",
"POS_ANCHORED": "アンカー:セット内の他のウィンドウと共に移動します。デフォルト。",
"POS_FLOATING": "フローティング:置かれた場所に留まるが、表示される時に再センタリングされます。",
"POS_HMD": "HMD に追従する。",
@ -151,4 +150,4 @@
"CLOSE": "フォーカス中のアプリを閉じる",
"MOUSE": "実際のマウスのクリックとスクロールもVRポインターに反映されます"
}
}
}

View File

@ -50,7 +50,6 @@
"POSITIONING": "Pozycjonowanie",
"BLOCK_INPUT": "Blokuj input z gry",
"RESIZE_PRESS_AND_DRAG": "Zmień rozmiar (naciśnij i przeciągnij)",
"POS_STATIC": "Statyczne: Pozostaje w miejscu i nigdy nie jest ponownie wyśrodkowywane.",
"POS_ANCHORED": "Zakotwiczone: Porusza się razem z resztą zestawu. Domyślne.",
"POS_FLOATING": "Pływające: Pozostaje w miejscu, ponownie się wyśrodkowuje po pokazaniu.",
"POS_HMD": "Podążaj za HMD.",
@ -151,4 +150,4 @@
"CLOSE": "Zamknij aktualną aplikację",
"MOUSE": "Kliknięcia i przewijanie fizycznej myszy są również przeniesione na wskaźnik VR"
}
}
}

View File

@ -45,7 +45,6 @@
"POS_HAND_L": "跟随左手。",
"POS_HAND_R": "跟随右手。",
"POS_HMD": "跟随头显 (HMD)。",
"POS_STATIC": "静态:不属于任何集合,不重新居中。",
"POSITIONING": "定位",
"RESIZE_PRESS_AND_DRAG": "调整大小 (按住并拖拽)",
"STEREO_3D_MODE": {
@ -151,4 +150,4 @@
"CLOSE": "关闭当前焦点应用",
"MOUSE": "真实鼠标的点击和滚动也将转换为 VR 指针"
}
}
}

View File

@ -58,7 +58,7 @@ use wgui::{gfx::WGfx, log::LogErr};
use wlx_capture::frame::Transform;
use wlx_common::{
audio::{AudioSystem, SamplePlayer},
config::{GeneralConfig, InputCaptureMethod},
config::{DefaultPositioning, GeneralConfig, InputCaptureMethod},
desktop_finder::DesktopFinder,
};
use xkbcommon::xkb;
@ -402,7 +402,11 @@ impl WvrServerState {
}
_ => (
Size::new(1920, 1080).clamp(min_size, max_size),
PositionMode::Float,
match app.session.config.default_positioning {
DefaultPositioning::Anchored => PositionMode::Anchor,
DefaultPositioning::Floating => PositionMode::Float,
DefaultPositioning::Static => PositionMode::Static,
},
None,
None,
false,

View File

@ -9,9 +9,9 @@ use wayvr_ipc::packet_client::WvrProcessLaunchParams;
use wlx_common::{
astr_containers::AStrMap,
config::{
AltModifier, CaptureMethod, ChromaKeyParams, GeneralConfig, HandsfreeAltTab,
HandsfreePointer, InputCaptureMethod, InputEmulationMethod, PinnedApp, SerializedWindowSet,
SerializedWindowStates,
AltModifier, CaptureMethod, ChromaKeyParams, DefaultPositioning, GeneralConfig,
HandsfreeAltTab, HandsfreePointer, InputCaptureMethod, InputEmulationMethod, PinnedApp,
SerializedWindowSet, SerializedWindowStates,
},
config_io,
locale::Language,
@ -195,6 +195,9 @@ pub struct AutoSettings {
pub wvr_mouse_acceleration: bool,
pub wvr_mouse_speed: f32,
pub wvr_input_capture: InputCaptureMethod,
pub default_curvature: f32,
pub default_opacity: f32,
pub default_positioning: DefaultPositioning,
}
fn get_settings_path() -> PathBuf {
@ -267,6 +270,9 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
wvr_mouse_acceleration: config.wvr_mouse_acceleration,
wvr_mouse_speed: config.wvr_mouse_speed,
wvr_input_capture: config.wvr_input_capture,
default_curvature: config.default_curvature,
default_opacity: config.default_opacity,
default_positioning: config.default_positioning,
};
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic
@ -306,3 +312,11 @@ pub fn save_state(config: &GeneralConfig) -> anyhow::Result<()> {
log::info!("State was saved successfully.");
Ok(())
}
pub fn none_if_0(val: f32) -> Option<f32> {
if val.abs() < f32::EPSILON {
None
} else {
Some(val)
}
}

View File

@ -42,7 +42,7 @@ use crate::{
window::WindowHandle,
},
},
config::save_settings,
config::{none_if_0, save_settings},
ipc::ipc_server::{gen_args_vec, gen_env_vec},
state::AppState,
subsystem::hid::WheelDelta,
@ -337,7 +337,7 @@ fn tutorial_spawn_effect(app: &mut AppState) -> anyhow::Result<()> {
grabbable: true,
interactable: true,
positioning: Positioning::FollowHead { lerp: 0.01 },
curvature: Some(0.15),
curvature: none_if_0(app.session.config.default_curvature),
alpha: 0.1,
..Default::default()
});
@ -376,7 +376,7 @@ pub fn create_dash_frontend(app: &mut AppState) -> anyhow::Result<OverlayWindowC
grabbable: true,
interactable: true,
positioning: Positioning::Floating,
curvature: Some(0.15),
curvature: none_if_0(app.session.config.default_curvature),
..OverlayWindowState::default()
},
z_order: Z_ORDER_DASHBOARD,

View File

@ -11,6 +11,7 @@ use crate::{
input::{HoverResult, PointerHit},
task::{GlobalChange, OverlayTask, TaskType},
},
config::none_if_0,
gui::panel::{GuiPanel, overlay_list::OverlayList, set_list::SetList},
overlays::keyboard::builder::create_keyboard_panel,
state::AppState,
@ -109,7 +110,8 @@ pub fn create_keyboard(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig
grabbable: true,
positioning: Positioning::Anchored,
interactable: true,
curvature: Some(0.15),
curvature: none_if_0(app.session.config.default_curvature),
alpha: app.session.config.default_opacity,
transform: Affine3A::from_scale_rotation_translation(
Vec3::ONE * width,
Quat::from_rotation_x(-10f32.to_radians()),

View File

@ -12,6 +12,7 @@ use wlx_common::{
use crate::{
backend::input::{HoverResult, PointerHit},
config::none_if_0,
overlays::screen::{
backend::CaptureType,
capture::{WlxCaptureIn, WlxCaptureOut},
@ -120,9 +121,11 @@ pub fn new_mirror(name: Arc<str>, app: &mut AppState) -> anyhow::Result<OverlayW
category: OverlayCategory::Mirror,
show_on_spawn: true,
default_state: OverlayWindowState {
positioning: app.session.config.default_positioning.into(),
curvature: none_if_0(app.session.config.default_curvature),
alpha: app.session.config.default_opacity,
interactable: true,
grabbable: true,
curvature: Some(0.15),
transform: Affine3A::from_scale_rotation_translation(
Vec3::ONE * app.session.config.default_overlay_scale,
Quat::IDENTITY,

View File

@ -5,6 +5,7 @@ use wlx_capture::frame::Transform;
use wlx_common::windowing::{OverlayWindowState, Positioning};
use crate::{
config::none_if_0,
state::{AppSession, AppState, ScreenMeta},
subsystem::input::InputFocus,
windowing::{
@ -47,9 +48,10 @@ fn create_screen_from_backend(
category: OverlayCategory::Screen,
default_state: OverlayWindowState {
grabbable: true,
positioning: Positioning::Anchored,
positioning: session.config.default_positioning.into(),
curvature: none_if_0(session.config.default_curvature),
alpha: session.config.default_opacity,
interactable: true,
curvature: Some(0.15),
transform: Affine3A::from_scale_rotation_translation(
Vec3::ONE * 1.5 * session.config.default_overlay_scale,
Quat::from_rotation_z(angle),

View File

@ -49,6 +49,7 @@ use crate::{
window::WindowHandle,
},
},
config::none_if_0,
graphics::{ExtentExt, Vert2Uv, upload_quad_vertices},
gui::panel::{
GuiPanel, NewGuiPanelParams, OnCustomAttribFunc,
@ -111,7 +112,8 @@ pub fn create_wl_window_overlay(
PositionMode::Anchor => Positioning::Anchored,
PositionMode::Static => Positioning::Static,
},
curvature: Some(0.15 * curve_scale),
alpha: app.session.config.default_opacity,
curvature: none_if_0(app.session.config.default_curvature).map(|x| x * curve_scale),
transform: Affine3A::from_scale_rotation_translation(
Vec3::ONE * app.session.config.default_overlay_scale * scale,
Quat::IDENTITY,

View File

@ -17,6 +17,7 @@ use wlx_common::{
use crate::{
backend::task::{OverlayTask, TaskType, ToggleMode},
config::none_if_0,
gui::{
panel::{
GuiPanel, NewGuiPanelParams, OnCustomAttribFunc,
@ -326,7 +327,8 @@ pub fn create_whisper(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig>
interactable: true,
grabbable: true,
transform,
positioning: Positioning::Anchored,
positioning: app.session.config.default_positioning.into(),
alpha: app.session.config.default_opacity,
..OverlayWindowState::default()
},
category: OverlayCategory::BuiltInPanel,

View File

@ -92,6 +92,28 @@ pub enum InputCaptureMethod {
None,
}
#[derive(Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)]
pub enum DefaultPositioning {
#[default]
#[strum(props(
Translation = "APP_SETTINGS.OPTION.ANCHORED",
Tooltip = "APP_SETTINGS.OPTION.ANCHORED_HELP"
))]
Anchored,
#[strum(props(
Translation = "APP_SETTINGS.OPTION.FLOATING",
Tooltip = "APP_SETTINGS.OPTION.FLOATING_HELP",
))]
Floating,
#[strum(props(
Translation = "APP_SETTINGS.OPTION.STATIC",
Tooltip = "APP_SETTINGS.OPTION.STATIC_HELP"
))]
Static,
}
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, AsRefStr, EnumString, EnumProperty, VariantArray)]
pub enum AltModifier {
#[default]
@ -270,6 +292,10 @@ const fn def_point3() -> f32 {
0.3
}
const fn def_point15() -> f32 {
0.15
}
const fn def_osc_port() -> u16 {
9000
}
@ -530,4 +556,13 @@ pub struct GeneralConfig {
#[serde(default)]
pub wvr_input_capture: InputCaptureMethod,
#[serde(default)]
pub default_positioning: DefaultPositioning,
#[serde(default = "def_one")]
pub default_opacity: f32,
#[serde(default = "def_point15")]
pub default_curvature: f32,
}

View File

@ -1,7 +1,7 @@
use glam::Affine3A;
use serde::{Deserialize, Serialize};
use crate::common::LeftRight;
use crate::{common::LeftRight, config::DefaultPositioning};
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
pub enum Positioning {
@ -25,6 +25,16 @@ pub enum Positioning {
},
}
impl From<DefaultPositioning> for Positioning {
fn from(value: DefaultPositioning) -> Self {
match value {
DefaultPositioning::Anchored => Self::Anchored,
DefaultPositioning::Floating => Self::Floating,
DefaultPositioning::Static => Self::Static,
}
}
}
impl Positioning {
pub const fn get_lerp(self) -> Option<f32> {
match self {