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