From 7e0e892bcceda65ccf16fcb66dca47b18985d0f6 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Thu, 23 Apr 2026 03:25:15 +0300 Subject: [PATCH] chore: remove VIEWPORT_WIDGET_PLAN.md as refactoring steps are complete --- VIEWPORT_WIDGET_PLAN.md | 150 ---------------------------------------- 1 file changed, 150 deletions(-) delete mode 100644 VIEWPORT_WIDGET_PLAN.md diff --git a/VIEWPORT_WIDGET_PLAN.md b/VIEWPORT_WIDGET_PLAN.md deleted file mode 100644 index 2bb5c11d8..000000000 --- a/VIEWPORT_WIDGET_PLAN.md +++ /dev/null @@ -1,150 +0,0 @@ - - -# Unified ViewportPane Widget Plan - -## Current State (as of implementation start) - -- `src/scene/render.rs`: `Scene` implements `shader::Program` → single full-screen GPU widget -- `src/app/view.rs:106`: `shader(&tab.scene).width(Fill).height(Fill)` — same widget for both model and paper space, only render content differs -- `src/entities/viewport.rs`: `Viewport` entity is a pure DXF data struct with no shader or widget of its own - -## Target Architecture - -``` -Model tab → ViewportPane (mode: Model) — Fill × Fill -Paper tab → paper_canvas_view() - ├── ViewportPane (mode: PaperSheet) — Fill × Fill (paper entities + camera) - ├── ViewportPane (mode: Paper, VP1) — vp.width × vp.height px - └── ViewportPane (mode: Paper, VP2) — vp.width × vp.height px -``` - ---- - -## ✅ Step 1 — `ViewportPane` Struct - -**File:** `src/scene/viewport_pane.rs` - -```rust -pub enum ViewportPaneMode { - Model, - PaperSheet, // paper-space entities, paper camera, no viewport projection - Paper { handle: Handle }, // model content through a specific viewport's camera -} -pub struct ViewportPane<'a> { pub scene: &'a Scene, pub mode: ViewportPaneMode } -``` - -Implements `shader::Program`. `Scene`'s own `shader::Program` impl has been **removed** — all rendering now goes through `ViewportPane`. - -Scene helper methods added to `render.rs`: -- `build_primitive()` — model/full paper space render (was `draw()`) -- `build_paper_sheet_primitive()` — paper entities only, no viewport projection -- `build_viewport_primitive(vp_handle)` — model content through viewport camera -- `update_viewcube_state()` / `viewcube_mouse_interaction()` - -Scene helper methods added to `mod.rs`: -- `paper_sheet_wires()` — paper-space entity wires without viewport content -- `camera_for_viewport(handle)` — build Camera from Viewport entity data -- `model_wires_for_viewport(handle)` — model wires filtered by viewport layer freeze - ---- - -## ✅ Step 2 — Per-Viewport Camera - -Implemented via `camera_for_viewport()` in `src/scene/mod.rs`. Derives a `Camera` from the Viewport entity's `view_direction`, `view_target`, and `view_height` each frame — no separate HashMap needed since `pan_active_viewport()` / `zoom_active_viewport()` already write back to the entity. - ---- - -## ✅ Step 3 — Paper-Space Coordinates → Pixel Conversion - -```rust -pub fn viewport_screen_rect(&self, vp_handle: Handle, canvas_px: (f32, f32)) -> Option -``` - -Added to `src/scene/mod.rs`. Uses `paper_limits()` as the paper extent and `scene.selection.borrow().vp_size` as the live canvas size. - ---- - -## ✅ Step 4 — `paper_canvas_view` Function - -Added to `src/app/view.rs`. Builds a `stack![]` with: -1. `shader(ViewportPane::paper_sheet(scene))` — full-size paper background -2. One `shader(ViewportPane::paper(scene, handle))` per viewport, positioned via Space offsets -3. `viewport_3d` in `view()` is now `paper_canvas_view(tab)` when `is_paper` - ---- - -## ✅ Step 5 — Mouse Routing per Viewport - -The full MSPACE routing chain is already wired and verified: - -- **Double-click** inside a paper viewport → `Message::EnterViewport(handle)` → `scene.active_viewport = Some(handle)` (`update.rs:1704`, `2540`) -- **Escape** → `Message::ExitViewport` → `scene.active_viewport = None` (`update.rs:658`) -- **Middle-drag** in MSPACE → `pan_active_viewport()` via `update.rs:1079–1080` -- **Scroll** in MSPACE → `zoom_active_viewport()` via `update.rs:1784–1792` - -`camera_for_viewport()` reads `view_target` / `view_height` fresh from the entity every frame, so the `ViewportPane::Paper` widget automatically reflects pan/zoom changes without any extra wiring. - ---- - -## ✅ Step 6 — Per-Viewport Layer Freeze Verification - -`model_wires_for_viewport()` (`mod.rs:2208`) uses the same handle-based filtering as the older `entity_content_wires()` (`mod.rs:697`): - -1. Reads `vp.frozen_layers: Vec` from the viewport entity -2. Looks up each entity's layer by name → gets its `Handle` -3. Skips entities whose layer handle is in the frozen set - -Both sets of handles come from the same `CadDocument`, so they match correctly. Global layer visibility (`l.flags.off || l.flags.frozen`) is also applied before the per-viewport check. - ---- - -## Implementation Order - -1. ✅ `ViewportPane` + render helpers — model tab behavior unchanged -2. ✅ Per-viewport camera — derived from entity each frame -3. ✅ `viewport_screen_rect()` — paper → pixel coordinate mapping -4. ✅ `paper_canvas_view()` — stack of PaperSheet + Paper widgets -5. ✅ Mouse routing verification for MSPACE in paper space -6. ✅ Per-viewport layer freeze verification - ---- - -## Notes - -- `CameraState` (viewcube hover) is per `ViewportPane` instance — Iced manages this automatically via `shader::Program::State`. -- Paper-space entities (title blocks, frames) are rendered by `ViewportPane::PaperSheet` using the same paper-space camera as before. -- The ViewCube is hidden in `ViewportPane::Paper` mode (only shown in Model and PaperSheet). -- `selection_overlay` and grip markers use paper-space screen coordinates — this is correct for PSPACE. For MSPACE, grips of model entities are projected through the paper camera, which may need adjustment in a future step. -- Known limitation: `viewport_screen_rect()` uses the last-rendered canvas size (`scene.selection.borrow().vp_size`), so viewport positions are correct from the second frame onward.