Continuous orbit (navigation bar): the view turns about the vertical until the next click or key

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-08 14:14:29 +00:00
1 parent 1970b8c680
commit 8fa566af33
2 files changed
+34 -1

No files matched your search

+8
View File
@@ -421,6 +421,14 @@ pub fn paint(p: &Painter, r: Rect, name: &str, ink: Color32, fill: Color32, acce
pen.arrow((17.0, 17.5), (19.6, 14.5), a);
pen.dot(12.0, 12.0, ink);
}
"spin" => {
// A turntable: an ellipse with an arrow running round it, a post in the middle.
let pts: Vec<Pos2> = (0..=28).map(|i| 0.2 + i as f32 / 28.0 * 5.6).map(|t| pen.at(12.0 + 9.0 * t.cos(), 16.0 + 3.5 * t.sin())).collect();
p.add(Shape::line(pts, Stroke::new(pen.w, ink)));
pen.arrow((17.0, 19.0), (20.5, 17.0), a);
pen.line(&[(12.0, 15.5), (12.0, 4.0)], ink);
pen.poly(&[(9.0, 9.0), (15.0, 9.0), (15.0, 4.0), (9.0, 4.0)], Color32::TRANSPARENT, ink);
}
"pan" => {
for (dx, dy) in [(0.0, -1.0), (0.0, 1.0), (-1.0, 0.0), (1.0, 0.0)] {
pen.arrow((12.0 + 3.0 * dx, 12.0 + 3.0 * dy), (12.0 + 9.0 * dx, 12.0 + 9.0 * dy), ink);
+26 -1
View File
@@ -47,6 +47,8 @@ pub struct ViewportState {
pub hover_bodies: Vec<String>,
/// The model point an orbit turns around (Preferences: orbit around the cursor).
pub orbit_pivot: Option<Vec3>,
/// Continuous orbit: the view turns about the vertical until the next click or key.
pub spin: bool,
pub build_ms: f64,
/// The right-click menu, open at this screen position.
pub context_menu: Option<Pos2>,
@@ -1221,6 +1223,23 @@ pub fn show(app: &mut SolveApp, ui: &mut egui::Ui) {
if !dragging {
app.viewport.orbit_pivot = None;
}
if app.viewport.spin {
// A click on the navigation bar (its own button) is not a stop.
let bar = Rect::from_center_size(pos2(rect.center().x, rect.bottom() - 22.0), vec2(320.0, 30.0));
let (pressed, key, dt) = ui.input(|i| {
(
i.pointer.any_pressed() && inside && !i.pointer.press_origin().is_some_and(|p| bar.contains(p)),
i.events.iter().any(|e| matches!(e, egui::Event::Key { pressed: true, .. })),
i.stable_dt,
)
});
if pressed || key || dragging {
app.viewport.spin = false;
} else {
app.cam.orbit(f64::from(dt.min(0.1)) * 30.0, 0.0);
ui.ctx().request_repaint();
}
}
if !app.cam.is_valid() {
app.cam = Camera::default();
app.fit_view();
@@ -1897,8 +1916,9 @@ pub fn look_at_selection(app: &mut SolveApp) {
fn nav_bar(app: &mut SolveApp, ui: &mut egui::Ui, rect: Rect) {
let t = Tokens::get();
let items: [(&str, &str); 9] = [
let items: [(&str, &str); 10] = [
("orbit", "Orbit (drag; or Shift+middle / right drag)"),
("spin", "Continuous orbit (stops at the next click or key)"),
("pan", "Pan (drag; or middle drag)"),
("zoom", "Zoom (drag; or wheel)"),
("fit", "Fit (F6)"),
@@ -1921,6 +1941,7 @@ fn nav_bar(app: &mut SolveApp, ui: &mut egui::Ui, rect: Rect) {
"zoom" => app.viewport.nav == Some(NavMode::Zoom),
"perspective" => app.ui.perspective,
"settings" => app.ui.show_grid,
"spin" => app.viewport.spin,
_ => false,
};
if active || resp.hovered() {
@@ -1934,6 +1955,10 @@ fn nav_bar(app: &mut SolveApp, ui: &mut egui::Ui, rect: Rect) {
"pan" => app.viewport.nav = toggle(NavMode::Pan, app.viewport.nav),
"zoom" => app.viewport.nav = toggle(NavMode::Zoom, app.viewport.nav),
"fit" => app.animate_view("fit"),
"spin" => {
app.cancel_view_animation();
app.viewport.spin = !app.viewport.spin;
}
"home" => app.animate_view("home"),
"lookat" => look_at_selection(app),
"style" => app.ui.visual_style = (app.ui.visual_style + 1) % 4,