Navigation: choose the orbit centre: view centre, origin or point under the cursor (#1377)
Preferences ▸ Navigation ▸ Orbit around now offers View centre (the default, as before), Origin and Point under the cursor. A saved orbit_cursor preference migrates to the cursor option, and the control channel still accepts the old key. Thanks to @kuraneko1 for this. Co-authored-by: kuraneko1 <98832587+kuraneko1@users.noreply.github.com>
This commit is contained in:
1 parent
4b3b48388c
commit
ad30a2350e
6 files changed
+161
-40
No files matched your search
@@ -2304,16 +2304,22 @@ pub fn show(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
if let Some((mode, delta)) = motion {
|
||||
if delta != egui::Vec2::ZERO {
|
||||
let mut params = json!({"motion":if mode == NavMode::Pan {"pan"} else {"orbit"},"delta":[delta.x,delta.y]});
|
||||
if mode == NavMode::Orbit && app.preferences.orbit_cursor {
|
||||
let pivot = match app.viewport.orbit_pivot {
|
||||
Some(pivot) => pivot,
|
||||
None => {
|
||||
let pivot = crate::prefs::pivot_under(app, &projection(app, rect), hover.unwrap_or(rect.center()) - delta);
|
||||
app.viewport.orbit_pivot = Some(pivot);
|
||||
pivot
|
||||
}
|
||||
if mode == NavMode::Orbit {
|
||||
let pivot = match app.preferences.orbit_around {
|
||||
crate::prefs::OrbitAround::ViewCentre => None,
|
||||
crate::prefs::OrbitAround::Origin => Some(Vec3::ZERO),
|
||||
crate::prefs::OrbitAround::Cursor => Some(match app.viewport.orbit_pivot {
|
||||
Some(pivot) => pivot,
|
||||
None => {
|
||||
let pivot = crate::prefs::pivot_under(app, &projection(app, rect), hover.unwrap_or(rect.center()) - delta);
|
||||
app.viewport.orbit_pivot = Some(pivot);
|
||||
pivot
|
||||
}
|
||||
}),
|
||||
};
|
||||
params["pivot"] = json!(pivot);
|
||||
if let Some(pivot) = pivot {
|
||||
params["pivot"] = json!(pivot);
|
||||
}
|
||||
}
|
||||
camera_motion(app, rect, params);
|
||||
}
|
||||
@@ -3345,7 +3351,17 @@ fn orbit_drag(app: &mut SolveApp, rect: Rect, dx: f64, dy: f64, press: Option<Po
|
||||
target.pitch = previous.target.pitch;
|
||||
}
|
||||
}
|
||||
let pivot = app.viewport.orbit_pivot.filter(|_| around_cursor).and_then(|p| {
|
||||
// The cursor and origin pivots stay still while a snap eases in; the axis gizmo has no
|
||||
// pivot (it orbits about the view centre, see `axis_view`).
|
||||
let pivot = if around_cursor {
|
||||
match app.preferences.orbit_around {
|
||||
crate::prefs::OrbitAround::Origin => Some(Vec3::ZERO),
|
||||
_ => app.viewport.orbit_pivot,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.and_then(|p| {
|
||||
app.cam = displayed;
|
||||
projection(app, rect).to_screen(p).map(|at| (p, at))
|
||||
});
|
||||
@@ -4429,7 +4445,7 @@ mod tests {
|
||||
let ctx = egui::Context::default();
|
||||
let mut app = hover_app(false);
|
||||
app.preferences.nav = "touchpad".into();
|
||||
app.preferences.orbit_cursor = true;
|
||||
app.preferences.orbit_around = crate::prefs::OrbitAround::Cursor;
|
||||
let p = pos2(350.0, 300.0);
|
||||
let alt = egui::Modifiers { alt: true, ..Default::default() };
|
||||
hover_frame(&mut app, &ctx, vec![egui::Event::PointerMoved(p)]);
|
||||
@@ -5499,10 +5515,35 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// The origin pivot holds through a Shift drag that snaps to an axis: the spring eases the
|
||||
/// view round without letting the origin slide on screen.
|
||||
#[test]
|
||||
fn snapping_keeps_the_origin_still() {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.app.preferences.orbit_around = crate::prefs::OrbitAround::Origin;
|
||||
h.app.run("solid.box", json!({"length":40,"width":40,"height":40})).unwrap();
|
||||
h.app.fit_view();
|
||||
let rect = h.app.viewport.rect.unwrap();
|
||||
let at = rect.center() + vec2(50.0, -20.0);
|
||||
orbit_drag(&mut h.app, rect, 0.0, 0.0, Some(at), true, true);
|
||||
assert_eq!(
|
||||
h.app.viewport.orbit_snap.as_ref().and_then(|s| s.pivot).map(|(p, _)| p),
|
||||
Some(Vec3::ZERO),
|
||||
"the origin is the pivot while snapping"
|
||||
);
|
||||
let before = projection(&h.app, rect).to_screen(Vec3::ZERO).unwrap();
|
||||
for _ in 0..30 {
|
||||
orbit_drag(&mut h.app, rect, 4.0, 2.0, Some(at), true, true);
|
||||
step_orbit_snap(&mut h.app, rect, 1.0 / 60.0);
|
||||
let after = projection(&h.app, rect).to_screen(Vec3::ZERO).unwrap();
|
||||
assert!(after.distance(before) < 2.0, "{before:?} -> {after:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shift_orbit_keeps_cursor_pivot_and_default_middle_pan() {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.app.preferences.orbit_cursor = true;
|
||||
h.app.preferences.orbit_around = crate::prefs::OrbitAround::Cursor;
|
||||
h.app.run("solid.box", json!({"length":40,"width":40,"height":40})).unwrap();
|
||||
h.app.fit_view();
|
||||
let rect = h.app.viewport.rect.unwrap();
|
||||
|
||||
Reference in new issue
Block a user