Files
hcie-rust-v3.05/.kilo/plans/vs-dock-regressions-plan.md
phantom b09795ccff Implement stable serialization and restoration for dock layouts, including auto-hidden and floating panels
- Add `persistence.rs` for stable serialization of dock layouts without runtime identifiers.
- Introduce `preview.rs` for geometry handling of dock drop previews.
- Create `sizing.rs` to manage content-aware sizing policies and constraint solving for dock panels.
- Implement `welcome.rs` to provide a welcome surface when no documents are open, featuring New and Open actions.
2026-07-16 22:10:22 +03:00

12 KiB

ICED Regressions and VS-Style Dock Manager Plan

Objective

Fix the three reported interaction regressions and introduce a modern Visual Studio / DevExpress-style dock manager around the existing Iced PaneGrid. The fixed toolbox/sidebar remain outside the dock system. Tool panels can move, split, auto-hide, float inside the application viewport, and redock. Documents remain in the center document area and cannot dock to tool-panel edges.

Reference images:

  • /home/dev-user/Pictures/Screenshots/vs-like-panels.png
  • /home/dev-user/Pictures/Screenshots/vs-like-panels-minimized.png

All implementation stays in hcie-iced-app/crates/hcie-iced-gui; locked engine crates and protected shader upload/rendering mechanisms remain unchanged.

Phase 1: Regression Fixes

1. Last-document close opens the welcome/new-image state

Files:

  • src/app.rs
  • src/dock/view.rs
  • tests/feature_scorecard.rs

Changes:

  1. Replace DocumentCloseDisposition::Window with Welcome.
  2. Resolve modified state before final-document behavior so the last dirty document still receives Save / Discard / Cancel.
  3. Change close_document_tab so closing the final document creates a clean placeholder document, resets active document/vector/filter transient state, and opens ActiveDialog::NewImage instead of closing the native window.
  4. Keep the application process and fixed shell alive after Save or Discard closes the final document.
  5. Update the title/document strip to show the centered welcome/new-image state without exposing the discarded image beneath it.
  6. Add tests for clean-last-tab, dirty-last-tab Save, Discard, Cancel, multiple-tab index safety, and native window-close remaining distinct from tab close.

2. Responsive realtime vector transforms

Files:

  • src/app.rs
  • src/vector_edit.rs
  • tests/feature_scorecard.rs

Changes:

  1. Add vector_drag_last_render: Option<Instant> and a 16 ms frame-cadence helper.
  2. On every pointer move, calculate the transformed shape from the immutable drag snapshot and update the public mutable shape collection immediately. This keeps overlay bounds and handles responsive without waiting for rerasterization.
  3. At most once per frame cadence, route the current bounds and angle through set_vector_shape_bounds and set_vector_shape_angle, then call refresh_composite_if_needed. These public setters mark the vector layer dirty and rerasterize actual vector content.
  4. On release, always perform one final dirtying bounds/angle update and composite refresh before clearing the drag session.
  5. Avoid duplicate setters when the bounds/angle did not change beyond a small epsilon.
  6. Preserve Shift aspect lock, Alt center-resize, rotation math, minimum dimensions, and final modified state.
  7. Add pure tests for frame throttling and final commit, plus a source/integration assertion that direct preview mutation is paired with periodic and final dirtying setters.

3. Right-click selects secondary color

Files:

  • src/color_picker.rs
  • src/sidebar/mod.rs
  • src/app.rs

Changes:

  1. Add .on_right_press(Message::BgColorChanged(...)) to recent colors, hue cells, saturation/lightness cells, palette-grid swatches, and other selectable color cells.
  2. Preserve alpha instead of forcing 255 when selecting from HSL/wheel controls.
  3. Make the main foreground/background swatches open the shared color popup for their corresponding target; right-clicking a normal palette swatch updates only secondary color.
  4. Add visible primary and secondary selection indicators and tooltips stating left-click/right-click behavior.
  5. Add tests proving left and right actions route to distinct color state and selected-vector synchronization remains realtime.

Phase 2: Dock Manager Domain Model

Add files:

  • src/dock/manager.rs
  • src/dock/persistence.rs

Update files:

  • src/dock/mod.rs
  • src/dock/state.rs
  • src/settings.rs

Roles and restrictions

Define:

  • DockRole::Document: the canvas/document host only.
  • DockRole::Tool: Layers, History, Brushes, Filters, Color Palette, Properties, Script, AI, Geometry, details, and settings.
  • DockRole::Fixed: toolbox and fixed sidebar regions, which never enter PaneGrid.
  • DockEdge: Left, Right, Top, Bottom.
  • DockPlacement: Docked, AutoHidden(edge), Floating(rect), Closed.
  • DockDropZone: OuterEdge, PaneEdge, Center.
  • DockDragState: source pane/type, pointer, candidate target, accepted preview rectangle.

Policy:

  1. Tool panels may drop on outer edges or another pane's edge.
  2. Tool panels may not drop on a pane center; center targets are rejected and never previewed.
  3. Documents remain in the center document host. Document-tab dragging may reorder center tabs but may not create side splits, float, or auto-hide.
  4. Canvas/document host is unique, cannot close, auto-hide, float, or start a PaneGrid drag.
  5. Toolbox and fixed sidebar remain outside dock calculations and cannot be dragged.
  6. Every accepted mutation must preserve exactly one Canvas pane and one instance per tool-panel type.

Persistence

Create serializable stable DTOs independent of runtime Pane IDs:

  • DockLayoutNode::{Split { axis, ratio, first, second }, Panel(PaneType)}
  • PersistedFloatingPanel { panel, rect }
  • PersistedDockLayout { tree, auto_hidden, floating, focused }

Store it under PanelLayout with #[serde(default)] compatibility. Restore ratios with safe clamping, ignore unknown/duplicate panels, and inject Canvas if missing. Persist after accepted drop, resize end, auto-hide, float, close, and restore operations.

Phase 3: Accepted-Target Preview Layer

Add file:

  • src/dock/preview.rs

Update files:

  • src/app.rs
  • src/dock/view.rs

Changes:

  1. Track global pointer position while DragEvent::Picked is active.
  2. Derive actual logical pane rectangles from pane_grid.layout().pane_regions(...), accounting for title bar, toolbar, status bar, fixed toolbox width, rail widths, and scale-independent logical coordinates.
  3. Convert pointer position to a policy-approved target and preview rectangle.
  4. Make PaneGrid's built-in hovered-region fill transparent while the custom preview is active, preventing invalid center previews.
  5. Render a modern drop compass near the hovered panel plus outer-edge targets. Use accent-blue icons, translucent accepted-region fill, a crisp 2px border, and a disabled visual for prohibited center targets.
  6. On DragEvent::Dropped, ignore Iced's raw target unless it equals the current approved target. Apply only through DockManager::drop_panel.
  7. Cancel cleanly when dropped outside accepted zones; retain the original layout.
  8. Add policy and geometry tests for every source/target/edge combination and narrow-window clamping.

Phase 4: Modern Panel Chrome

Update files:

  • src/dock/view.rs
  • src/panels/styles.rs
  • src/theme.rs

Changes:

  1. Replace Photoshop-style headers with modern compact desktop headers: 28-30px height, panel icon, 12-13px title, focus accent, subtle separator, and clear hover/pressed states.
  2. Add title controls with SVG/tooltips: auto-hide pin, float/restore, maximize, close.
  3. Make the entire non-control header area the drag handle; controls must not begin a drag.
  4. Use 1px split lines with larger invisible resize hit areas and accent hover feedback.
  5. Use consistent panel minimum sizes and clamp split ratios so narrow panels do not collapse into vertical text.
  6. Keep document chrome visually distinct: center tab well, active-document accent, modified marker, close button, and no panel pin/float controls.

Phase 5: Auto-Hide Rails

Add file:

  • src/dock/auto_hide.rs

Update files:

  • src/app.rs
  • src/dock/state.rs
  • src/dock/view.rs

Changes:

  1. Pin control removes a tool pane from PaneGrid and adds a vertical/horizontal tab to the selected edge rail.
  2. Rails are fixed around the dock area, inside the application shell but outside PaneGrid. They do not displace the fixed toolbox.
  3. Rail tabs use panel icon plus rotated/vertical title where supported; prefer readable icon-first compact tabs over character-by-character wrapping.
  4. Clicking or hovering a rail tab opens a temporary opaque panel overlay from that edge with shadow and border, matching the reference minimized screenshot.
  5. Clicking outside, pressing Escape, or activating another panel closes the temporary overlay without changing its auto-hide placement.
  6. Pinning the temporary panel restores it to its last dock target and ratio.
  7. Auto-hide rail and overlay bounds remain responsive to window resize.

Phase 6: Floating Panels Within the Application Viewport

Add file:

  • src/dock/floating.rs

Changes:

  1. Float control removes a tool pane from PaneGrid and renders it as a high-z-order card over the dock workspace.
  2. Floating card headers support pointer dragging with a deadband, viewport clamping, focus/z-order, close, pin/redock, and resize handles.
  3. While dragging a floating panel over the dock, show the same accepted drop compass and preview. Releasing on an accepted target redocks it; otherwise preserve floating position.
  4. Floating panels cannot cover the application title/menu bar permanently; clamp enough header area onscreen for recovery.
  5. Documents and fixed toolbox/sidebar cannot float.
  6. Persist floating rectangles in logical pixels and clamp them when restored on a smaller monitor.

Phase 7: Panel Content Reuse and Document Center Behavior

Refactor src/dock/view.rs:

  1. Extract panel_body(PaneType, &HcieIcedApp) -> Element so docked, auto-hidden, and floating containers render exactly the same panel implementation.
  2. Keep Canvas rendering exclusively in the unique center PaneGrid pane to preserve shader texture lifetime and partial uploads.
  3. Add center-only document-tab drag/reorder state. A dragged document previews only within the document tab strip/center host and cannot generate side target previews.
  4. Empty/final-close center host shows the welcome/new-image state while retaining the shell, dock panels, toolbox, and menu.
  5. Ensure auto-hide/floating overlays do not consume canvas wheel/drawing events outside their visible rectangles.

Phase 8: Validation

Automated tests

Run:

cargo check -p hcie-iced-gui --all-targets
cargo test -p hcie-iced-gui
cargo test -p hcie-engine-api --test visual_regression
cargo test -p hcie-engine-api --test performance_stroke_4k -- --nocapture
git diff --check

Required new tests:

  • Last clean/dirty document close never exits the app.
  • Native window close still exits after confirmation.
  • Vector preview updates every event, raster refresh is frame-throttled, and release forces final commit.
  • Right-click routes palette color to secondary only.
  • Dock policy matrix rejects tool-center and every document-edge/floating/auto-hide action.
  • Canvas uniqueness survives all drops, close, float, auto-hide, restore, and malformed persisted layouts.
  • Split ratios and floating rectangles clamp under small windows.
  • Persisted layouts round-trip without runtime Pane IDs.

Visual/interaction evidence

Capture and inspect:

  • Default 1280x800 layout.
  • 1024x600 compact layout.
  • Tool panel dragged over all five target zones, showing only accepted edge previews.
  • Outer-edge split preview and resulting layout.
  • Auto-hidden right rail and expanded temporary panel matching the references.
  • Floating Layers and Properties panels, then redocked.
  • Document drag showing center-only behavior.
  • Final document closed to welcome/new-image state.
  • Vector before, during, and after move/rotate with responsive content.
  • Palette left-click foreground and right-click secondary indicators.

Store screenshots under target/screenshots/dock-manager/ and include before/after paths in the completion report.

Non-Negotiable Protections

  • Do not modify locked engine crates.
  • Do not change persistent WGPU texture ownership, partial dirty uploads, viewport boundary mapping, nearest-neighbor sampling, or the RefCell dirty-bounds accumulator.
  • Do not move toolbox/sidebar into PaneGrid.
  • Do not permit more than one Canvas pane.
  • Do not render tool panels into document center drops or documents into tool-panel splits.
  • Do not accept a drop that was not shown as an approved preview.