refactor(viewport): migrate model-space tiling to iced pane_grid

Replace the custom model_tiles tiling with iced 0.14 pane_grid as the layout
source of truth, while paper-space floating viewports are left untouched (they
overlap/free-place, which pane_grid cannot model).

Each Model pane is its own shader widget rendering its camera into the pane
bounds; the renderer Primitive carries a base_slot so several shader widgets
share the type-keyed MultiPipeline storage on disjoint slots. A second pane_grid
of transparent mouse_areas (plus on_resize) layers above the crosshair overlay
to receive input — the overlay's Hidden cursor interaction otherwise levitates
the cursor and starves any layer beneath it. The active pane follows the cursor
(hover-activate), and grid / crosshair / UCS icon render per pane while the
ViewCube and render-mode picker stay on the active pane only.

Split / close / VPORTS presets and the VPort table round-trip now drive
pane_grid (guillotine reconstruction on load). Adds drag-to-swap via a controls
bar handle with a ghost-card preview, visible pane dividers from the pane_grid
split regions, a default model background of RGB(33,40,48), and removes all the
superseded custom-tile code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-27 11:50:11 +03:00
commit 495b13ec4f
18 changed files with 1004 additions and 733 deletions

View file

@ -26,18 +26,7 @@ pub use style_ops::StyleKind;
use document::DocumentTab;
use crate::modules::ModuleEvent;
use crate::scene::{CubeRegion, TileEdgeOrient};
/// In-flight drag of a Model-tile inner divider. `last_applied` is the
/// most recent normalized coordinate handed to `move_model_tile_edge` —
/// the next `ViewportMove` uses it as the `old_coord` argument so the
/// drag follows the same edge across frames even after sub-pixel
/// adjustments from the clamp inside `move_model_tile_edge`.
#[derive(Clone, Debug)]
pub struct TileDrag {
pub orient: TileEdgeOrient,
pub last_applied: f32,
}
use crate::scene::CubeRegion;
/// Which UCS-icon grip is being dragged. `Origin` slides the UCS origin within
/// its own plane; `XAxis`/`YAxis` rotate the UCS so that axis points at the
@ -265,10 +254,6 @@ pub(super) struct OpenCADStudio {
/// `true` after a bare `VPORTS` in model space — the next command-line
/// entry is treated as the tiled-config option (SIngle/2H/2V/4).
awaiting_vports: bool,
/// Active drag of a Model-tile divider. Set on press over an inner
/// edge, updated on move, cleared on release (which also runs the
/// collapse pass).
tile_drag: Option<TileDrag>,
/// Cursor is hovering over the UCS icon body — drives the hover highlight.
ucs_icon_hover: bool,
/// UCS icon is selected (clicked): its grips are shown and draggable.
@ -276,6 +261,9 @@ pub(super) struct OpenCADStudio {
/// Active direct-drag of a UCS icon grip (origin slide or axis rotate).
/// Set on press over a grip, updated on move, committed on release.
ucs_grip_drag: Option<UcsGripKind>,
/// Pane-move drag in progress: the source pane's tile index, armed by the
/// controls-bar drag handle. On release over another pane the two swap.
pane_move_from: Option<usize>,
/// `true` once the user has reshaped the dynamic-input field set via
/// the `,` separator during the current command iteration. Tells
/// `sync_dyn_fields` to preserve the user's chosen shape instead of
@ -1143,6 +1131,26 @@ pub enum Message {
ViewportMiddleRelease,
ViewportScroll(mouse::ScrollDelta),
ViewportExit,
// ── Per-pane Model viewport (pane_grid) ───────────────────────────────
/// A pane_grid divider was dragged — resize the split.
PaneResized(iced::widget::pane_grid::ResizeEvent),
/// A pane body was clicked — focus that pane.
PaneClicked(iced::widget::pane_grid::Pane),
/// A pane was drag-and-dropped onto another — swap them.
PaneDragged(iced::widget::pane_grid::DragEvent),
/// Per-pane mouse events. `usize` = the pane's tile index; the `Point` is
/// pane-local (offset to canvas coords + focus in the handler).
PaneMove(usize, Point),
PanePress(usize),
PaneRelease(usize),
PaneRightPress(usize),
PaneRightRelease(usize),
PaneMiddlePress(usize),
PaneMiddleRelease(usize),
PaneScroll(usize, mouse::ScrollDelta),
/// Drag-handle pressed on the active pane's controls bar: arm a pane move —
/// the next pane released over is swapped with the active pane.
PaneMoveStart,
ViewCubeSnap(CubeRegion),
/// World-frame view snap from a compass cardinal (N/E/S/W), bypassing the
/// UCS so the compass stays world-aligned.
@ -1806,10 +1814,10 @@ impl OpenCADStudio {
default_bg_color: None,
default_paper_bg_color: None,
awaiting_vports: false,
tile_drag: None,
ucs_icon_hover: false,
ucs_icon_selected: false,
ucs_grip_drag: None,
pane_move_from: None,
dyn_user_reshaped: false,
grip_hover: None,
grip_popup: None,