diff --git a/wlx-common/src/windowing.rs b/wlx-common/src/windowing.rs index c9d26c2..2c6041d 100644 --- a/wlx-common/src/windowing.rs +++ b/wlx-common/src/windowing.rs @@ -10,18 +10,12 @@ pub enum Positioning { Floating, /// Stays in place, recenters relative to anchor. Follows anchor during anchor grab. Anchored, - /// Same as anchor but paused due to interaction - AnchoredPaused, /// Stays in place, no recentering Static, /// Following HMD FollowHead { lerp: f32 }, - /// Normally follows HMD, but paused due to interaction - FollowHeadPaused { lerp: f32 }, /// Following hand FollowHand { hand: LeftRight, lerp: f32 }, - /// Normally follows hand, but paused due to interaction - FollowHandPaused { hand: LeftRight, lerp: f32 }, } impl Positioning { diff --git a/wlx-overlay-s/src/backend/input.rs b/wlx-overlay-s/src/backend/input.rs index 71304c8..6331c54 100644 --- a/wlx-overlay-s/src/backend/input.rs +++ b/wlx-overlay-s/src/backend/input.rs @@ -1,15 +1,18 @@ use std::f32::consts::PI; use std::process::{Child, Command}; +use std::sync::Arc; use std::{collections::VecDeque, time::Instant}; use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles}; use idmap_derive::IntegerId; use smallvec::{smallvec, SmallVec}; +use wlx_common::common::LeftRight; use wlx_common::windowing::{OverlayWindowState, Positioning}; use crate::backend::task::OverlayTask; use crate::overlays::anchor::ANCHOR_NAME; +use crate::overlays::watch::WATCH_NAME; use crate::state::{AppSession, AppState}; use crate::subsystem::hid::WheelDelta; use crate::subsystem::input::KeyboardFocus; @@ -232,6 +235,14 @@ impl Pointer { interaction: InteractionState::default(), } } + + pub fn hand(&self) -> Option { + match self.idx { + 0 => Some(LeftRight::Left), + 1 => Some(LeftRight::Right), + _ => None, + } + } } #[derive(Clone, Copy, Default)] @@ -278,7 +289,7 @@ struct RayHit { #[derive(Debug, Clone, Copy, Default)] pub struct GrabData { - pub offset: Vec3A, + pub offset: Affine3A, pub grabbed_id: OverlayID, pub grab_anchor: bool, } @@ -604,16 +615,13 @@ fn start_grab( let grab_anchor = !edit_mode && !app.anchor_grabbed && matches!(state.positioning, Positioning::Anchored); - let relative_grab_point = if grab_anchor { - app.anchor.translation + let relative_grab_transform = if grab_anchor { + app.anchor } else { - state.transform.translation + state.transform }; - let offset = pointer - .pose - .inverse() - .transform_point3a(relative_grab_point); + let offset = pointer.pose.inverse() * relative_grab_transform; app.anchor_grabbed = grab_anchor; @@ -623,13 +631,6 @@ fn start_grab( grab_anchor, }); - state.positioning = match state.positioning { - Positioning::FollowHand { hand, lerp } => Positioning::FollowHandPaused { hand, lerp }, - Positioning::FollowHead { lerp } => Positioning::FollowHeadPaused { lerp }, - Positioning::Anchored if !grab_anchor => Positioning::AnchoredPaused, - x => x, - }; - // Show anchor app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Name(ANCHOR_NAME.clone()), @@ -664,22 +665,27 @@ where }; let grab_anchor = grab_data.grab_anchor; - let Some(overlay_state) = overlay.config.active_state.as_mut() else { - return; - }; - if pointer.now.grab { + let Some(overlay_state) = overlay.config.active_state.as_mut() else { + // overlay got toggled off while being grabbed. those dastardly users! + // just wait for them to release the grab + return; + }; + if grab_anchor { if pointer.now.click { pointer.interaction.mode = PointerMode::Special; handle_scale(&mut app.anchor, pointer.now.scroll_y); } else if app.session.config.allow_sliding && pointer.now.scroll_y.is_finite() { // single grab push/pull - grab_data.offset.z -= pointer.now.scroll_y * 0.05; + grab_data.offset.translation.z -= pointer.now.scroll_y * 0.05; } - app.anchor.translation = pointer.pose.transform_point3a(grab_data.offset); if !pointer.now.click_modifier_right { + app.anchor.translation = + pointer.pose.transform_point3a(grab_data.offset.translation); realign(&mut app.anchor, &app.input_state.hmd); + } else { + app.anchor = pointer.pose * grab_data.offset; } } else { // single grab resize @@ -688,12 +694,16 @@ where handle_scale(&mut overlay_state.transform, pointer.now.scroll_y); } else if app.session.config.allow_sliding && pointer.now.scroll_y.is_finite() { // single grab push/pull - grab_data.offset.z -= pointer.now.scroll_y * 0.05; + grab_data.offset.translation.z -= pointer.now.scroll_y * 0.05; } - overlay_state.transform.translation = pointer.pose.transform_point3a(grab_data.offset); if !pointer.now.click_modifier_right { + overlay_state.transform.translation = + pointer.pose.transform_point3a(grab_data.offset.translation); realign(&mut overlay_state.transform, &app.input_state.hmd); + } else { + overlay_state.transform = pointer.pose * grab_data.offset; } + overlay.config.pause_movement = true; overlay.config.dirty = true; } } else { @@ -703,16 +713,29 @@ where app.anchor_grabbed = false; } else { // single grab released - overlay_state.positioning = match overlay_state.positioning { - Positioning::FollowHandPaused { hand, lerp } => { - Positioning::FollowHand { hand, lerp } + if &*overlay.config.name == WATCH_NAME { + // watch special: when dropped, follow the hand that wasn't grabbing + if let Some(overlay_state) = overlay.config.active_state.as_mut() { + overlay_state.positioning = match overlay_state.positioning { + Positioning::FollowHand { hand, lerp } => match pointer.hand() { + Some(LeftRight::Left) => Positioning::FollowHand { + hand: LeftRight::Right, + lerp, + }, + Some(LeftRight::Right) => Positioning::FollowHand { + hand: LeftRight::Left, + lerp, + }, + _ => Positioning::FollowHand { hand, lerp }, + }, + x => x, + }; } - Positioning::FollowHeadPaused { lerp } => Positioning::FollowHead { lerp }, - Positioning::AnchoredPaused => Positioning::Anchored, - x => x, - }; - - window::save_transform(overlay_state, app); + } + overlay.config.pause_movement = false; + if let Some(overlay_state) = overlay.config.active_state.as_mut() { + window::save_transform(overlay_state, app); + } } // Hide anchor diff --git a/wlx-overlay-s/src/overlays/edit/pos.rs b/wlx-overlay-s/src/overlays/edit/pos.rs index ce59fa6..893abab 100644 --- a/wlx-overlay-s/src/overlays/edit/pos.rs +++ b/wlx-overlay-s/src/overlays/edit/pos.rs @@ -131,24 +131,16 @@ fn key_to_pos(key: &str) -> Positioning { const fn pos_to_key(pos: Positioning) -> &'static str { match pos { Positioning::Static => "static", - Positioning::Anchored | Positioning::AnchoredPaused => "anchored", + Positioning::Anchored => "anchored", Positioning::Floating => "floating", - Positioning::FollowHead { .. } | Positioning::FollowHeadPaused { .. } => "hmd", + Positioning::FollowHead { .. } => "hmd", Positioning::FollowHand { hand: LeftRight::Left, .. - } - | Positioning::FollowHandPaused { - hand: LeftRight::Left, - .. } => "hand_l", Positioning::FollowHand { hand: LeftRight::Right, .. - } - | Positioning::FollowHandPaused { - hand: LeftRight::Right, - .. } => "hand_r", } } diff --git a/wlx-overlay-s/src/windowing/window.rs b/wlx-overlay-s/src/windowing/window.rs index 5c1a1fb..8155184 100644 --- a/wlx-overlay-s/src/windowing/window.rs +++ b/wlx-overlay-s/src/windowing/window.rs @@ -79,6 +79,8 @@ pub struct OverlayWindowConfig { pub dirty: bool, /// True if the window is showing the edit overlay pub editing: bool, + /// Used by grab to pause following of HMD or other devices + pub pause_movement: bool, } impl OverlayWindowConfig { @@ -98,6 +100,7 @@ impl OverlayWindowConfig { global: false, dirty: true, editing: false, + pause_movement: false, } } @@ -130,6 +133,10 @@ impl OverlayWindowConfig { } pub fn auto_movement(&mut self, app: &mut AppState) { + if self.pause_movement { + return; + } + let Some(state) = self.active_state.as_mut() else { return; }; @@ -184,13 +191,9 @@ impl OverlayWindowConfig { .unwrap_or(self.default_state.transform); let parent_transform = match state.positioning { - Positioning::Floating - | Positioning::FollowHead { .. } - | Positioning::FollowHeadPaused { .. } => app.input_state.hmd, - Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => { - app.input_state.pointers[hand as usize].pose - } - Positioning::Anchored | Positioning::AnchoredPaused => app.anchor, + Positioning::Floating | Positioning::FollowHead { .. } => app.input_state.hmd, + Positioning::FollowHand { hand, .. } => app.input_state.pointers[hand as usize].pose, + Positioning::Anchored => app.anchor, Positioning::Static => return, }; @@ -249,13 +252,9 @@ pub fn realign(transform: &mut Affine3A, hmd: &Affine3A) { pub fn save_transform(state: &mut OverlayWindowState, app: &mut AppState) -> bool { let parent_transform = match state.positioning { Positioning::Floating => snap_upright(app.input_state.hmd, Vec3A::Y), - Positioning::FollowHead { .. } | Positioning::FollowHeadPaused { .. } => { - app.input_state.hmd - } - Positioning::FollowHand { hand, .. } | Positioning::FollowHandPaused { hand, .. } => { - app.input_state.pointers[hand as usize].pose - } - Positioning::Anchored | Positioning::AnchoredPaused => snap_upright(app.anchor, Vec3A::Y), + Positioning::FollowHead { .. } => app.input_state.hmd, + Positioning::FollowHand { hand, .. } => app.input_state.pointers[hand as usize].pose, + Positioning::Anchored => snap_upright(app.anchor, Vec3A::Y), Positioning::Static => return false, };