ifcviewer: preset-driven nav mouse bindings + a "Web" preset (desktop + web)

Make orbit/pan/select mouse bindings pure data owned by ViewportCore so both
hosts and every preset share one source of truth, and add a "Web" preset. This
rounds out the matrix: the desktop gains a web-style scheme and the web inherits
all presets, with no per-platform hardcoding.

- Core: NavBindings { orbit, pan, select button + modifier } + setNavPreset
  ("blender" default | "rhino" | "revit" | "web") + navBindings(). Select is
  preset-driven too (was hardcoded LMB) so "web" moves it to RMB. web = orbit
  LMB, pan MMB, select RMB (LMB drag orbits with no click/drag ambiguity; RMB
  click-selects / drag-marquees). NavMod uses "Plain" not "None" (X11 #defines
  None to 0L).
- Desktop ViewportWindow: applyNavPreset sources the core table (mapped to Qt);
  marquee-arm / single-pick dispatch keys off select_button_. Default stays
  blender → no behaviour change.
- Desktop config: AppSettings::NavPreset gains Web + navPresetName(); the
  Settings dialog lists it. This also FIXES a pre-existing gap — the preset combo
  was persisted but never applied (only WGPU_NAV_PRESET env worked). MainWindow
  now applies the persisted preset at startup (env override still wins) and live
  on navPresetChanged, so all four presets actually work from the dialog.
- Web main_web: classifyPress routes the pressed button through navBindings()
  (orbit/pan/select), defaulting to the "web" preset; context menu already
  suppressed so RMB is free.

Tests: setNavPreset table (Catch2, 123 total); web smoke select tests use RMB.
BonsaiViewer builds; 9/9 web smoke.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-07-03 08:37:27 +10:00
parent cf05bbd1bb
commit f1d97ac5aa
11 changed files with 430 additions and 256 deletions
+14 -6
View File
@@ -239,12 +239,15 @@ public:
private:
// Re-aim the orbit camera so the bounding sphere of [mn, mx] fits.
void frameAabb(const float mn[3], const float mx[3], float padding);
// Resolve nav_preset_ env var to orbit/pan bindings.
void applyNavPreset(const char* name);
// chunkScreenAreaPx moved to ViewportCore (#84-h).
public:
// Apply a nav mouse preset by name ("blender"|"rhino"|"revit"|"web").
// Sources the shared binding table from ViewportCore; called from init
// (env / persisted setting) and live from the Settings dialog.
void applyNavPreset(const char* name);
// Queue a one-shot framebuffer capture: the next rendered frame is
// copied back to host memory and saved to `path` as PNG. If
@@ -800,10 +803,15 @@ private:
// so the click-vs-drag distinction at mouseReleaseEvent's pick path keeps
// working. Set at init from WGPU_NAV_PRESET=blender|rhino|revit (default
// blender, matching GL's AppSettings::NavPreset::Blender default).
Qt::MouseButton orbit_button_ = Qt::MiddleButton;
Qt::KeyboardModifiers orbit_mods_ = Qt::NoModifier;
Qt::MouseButton pan_button_ = Qt::MiddleButton;
Qt::KeyboardModifiers pan_mods_ = Qt::ShiftModifier;
// Mirror of ViewportCore's preset bindings, mapped to Qt types by
// applyNavPreset (the core owns the preset table; these are the Qt-side
// cache the mouse handlers compare against).
Qt::MouseButton orbit_button_ = Qt::MiddleButton;
Qt::KeyboardModifiers orbit_mods_ = Qt::NoModifier;
Qt::MouseButton pan_button_ = Qt::MiddleButton;
Qt::KeyboardModifiers pan_mods_ = Qt::ShiftModifier;
Qt::MouseButton select_button_ = Qt::LeftButton;
Qt::KeyboardModifiers select_mods_ = Qt::NoModifier;
// Set by mousePressEvent based on which binding matched; consumed by
// mouseMoveEvent so mid-drag modifier changes don't switch axes.
enum class NavDrag : uint8_t { Inactive, Orbit, Pan };