Files
hcie-rust-v3.05/handoff1-mimo.md
T

203 lines
8.4 KiB
Markdown
Raw Normal View History

# HCIE-Rust v3.05 — Session Handoff Document
**Date:** 2026-07-12
**Session ID:** ses_0a89f4c7dffeLzqNKSKFHyyaI1
---
## Summary
This session fixed critical engine bugs and completed iced GUI features for the HCIE-Rust image editor. The most significant fix was a fundamental architecture bug in the effects pipeline that caused new drawing strokes to disappear and effects to accumulate incorrectly.
---
## 1. Critical Engine Fixes (hcie-engine-api)
### 1.1 Effects Pipeline — `layer.pixels` Corruption Fix (CRITICAL)
**File:** `hcie-engine-api/src/partial_composite.rs` (line ~261)
**Root Cause:**
`apply_effects_and_sync_tiles()` wrote effects-applied pixels back to `layer.pixels`:
```rust
layer.pixels = processed; // BUG: corrupted raw drawing data
```
This caused a cascade of bugs:
1. User draws stroke → `layer.pixels` = raw + stroke
2. Effects pipeline runs → `layer.pixels` = effects(raw + stroke)
3. User draws next stroke → `layer.pixels` = effects(raw + stroke1) + stroke2
4. Effects pipeline restores from backup → `layer.pixels` = raw (stroke1+stroke2 LOST!)
5. Effects applied → `layer.pixels` = effects(raw) → **strokes vanished**
**Fix:** Removed `layer.pixels = processed`. Now `layer.pixels` always contains raw drawing data. The composite pipeline in `tiled.rs` reads from `effects_cache` when it exists (line 123), bypassing `layer.pixels` entirely for effect-bearing layers.
**Impact:** Fixes ALL of the following:
- New strokes disappearing after effects are applied
- Effects accumulating (shadow-on-shadow stacking)
- Toggle not working correctly (ON creating disabled styles)
- Slider preview showing corrupted state
### 1.2 `update_layer_style()` Missing Dirty Flags
**File:** `hcie-engine-api/src/lib.rs` (line ~1720)
**Root Cause:**
`update_layer_style()` set `effects_dirty`, `dirty`, and `composite_dirty` but did NOT set:
- `dirty_bounds` — caused full-canvas recomposite (~33MB for 4K) on every toggle
- `below_cache_dirty` — risked stale below-layer composite cache
**Fix:** Added:
```rust
let w = self.document.canvas_width;
let h = self.document.canvas_height;
self.document.dirty_bounds = Some([0, 0, w, h]);
self.below_cache_dirty = true;
```
Same fix applied to `remove_layer_style_by_index()`.
### 1.3 Stroke Drawing — `effects_dirty` During Strokes
**File:** `hcie-engine-api/src/stroke_brush.rs` (4 locations)
**Context:** `effects_dirty` is set during stroke drawing so the effects pipeline re-runs after the stroke ends. This is now safe because the effects pipeline no longer corrupts `layer.pixels` (fix 1.1).
**Functions modified:**
- `draw_brush_stroke` (line ~134)
- `draw_brush_stroke` (line ~172)
- `draw_pen_segment` (line ~203)
- `draw_stroke` (line ~266)
---
## 2. Iced GUI Fixes (hcie-iced-gui)
### 2.1 Layer Style Toggle Inversion
**File:** `hcie-iced-app/crates/hcie-iced-gui/src/app.rs` (line ~1044)
**Root Cause:**
```rust
enabled: existing.map_or(false, |s| matches!(s, LayerStyle::DropShadow { enabled, .. } if *enabled))
```
When style doesn't exist (`existing = None`), `map_or(false, ...)` returns `false`. First click ON created disabled style.
**Fix:** Changed to explicit logic:
- Style doesn't exist → `new_enabled = true` (first click enables)
- Style exists → `new_enabled = !was_enabled` (toggle)
### 2.2 Layer Style Panel — Draggable Floating Dialog
**Files:**
- `app.rs` — new state fields, messages, handlers
- `panels/layer_styles.rs` — draggable title bar, X button, offset positioning
**Implementation:**
- Added `layer_style_offset: (f32, f32)`, `layer_style_dragging: bool`, `layer_style_drag_start: Option<(f32, f32)>` state
- Added `LayerStyleDialogDragStart/Move/End` messages
- Title bar uses `mouse_area.on_press()` to start drag
- Global `iced::event::listen_with()` subscription tracks `CursorMoved` events during drag
- Delta-based position tracking: each move event adds delta to offset
- Dialog rendering uses `padding()` with offset to shift from center
- X close button (`\u{2715}`) wired to `LayerStyleCancel`
### 2.3 Layer Style Panel — Reopen Mechanism
**Files:**
- `panels/layers.rs` — "fx" button in toolbar
- `panels/menus.rs` — "Layer Styles..." in Layer menu (index 4,7)
- `app.rs` — menu action handler
**Buttons:**
- **"fx" button** in layers panel bottom toolbar → `Message::OpenLayerStyleDialog`
- **Layer menu → "Layer Styles..."** → menu action (4,7) → `Message::OpenLayerStyleDialog`
- Opening resets drag offset to (0, 0)
### 2.4 Layer Style Color Picker
**Files:**
- `app.rs``LayerStyleUpdateColor`, `ShowStyleColorPicker`, `HideStyleColorPicker` messages
- `panels/layer_styles.rs` — clickable color swatch, inline HSL picker popup
**Implementation:**
- Color swatch is clickable (opens HSL color picker popup)
- Popup has H/S/L sliders, color preview, hex display, Close button
- `LayerStyleUpdateColor` handler updates the style's color field in the engine
- HSL state tracked in `style_color_hsl: (f32, f32, f32)`
### 2.5 Color Picker Redesign
**File:** `color_picker.rs` (complete rewrite)
**Layout (matching egui version):**
1. Primary/Secondary swatch buttons + swap button (`\u{21C5}`)
2. Editable hex input field (`text_input`)
3. Tab bar: W (Color Wheel), H (HSL Sliders), G (Palette Grid)
4. Tab W: Hue ring (36 cells × 10°) + SL picker grid (12×12)
5. Tab H: HSL sliders with degree/percent readout
6. Tab G: 10×10 palette grid (algorithmically generated like egui)
7. Recent colors section
**Tab state:** `color_tab: usize` field in `HcieIcedApp`, `ColorTabChanged(usize)` message.
### 2.6 Recent Files Persistence
**Files:**
- `app.rs``load_recent_files()`, `save_recent_files()`, config helpers
- `Cargo.toml` — added `dirs = "5.0"` and `serde = { workspace = true }`
**Implementation:**
- Config stored at `~/.config/hcie-iced/recent_files.json`
- `RecentFileEntry` derives `serde::Serialize` and `serde::Deserialize`
- `add_recent_file()` persists to disk after each add
- `ClearRecentFiles` handler persists empty list
- `new()` loads from disk on startup
### 2.7 Backdrop for Modal Dialogs
**File:** `panels/layer_styles.rs`
**Fix:** Added semi-transparent backdrop (`rgba(0,0,0,0.5)`) around the dialog, matching the pattern used by all other dialogs (NewImage, BrightnessContrast, CloseConfirm).
---
## 3. Build Status
All changes compile successfully:
```
cargo build -p hcie-engine-api -p hcie-iced-gui
```
Pre-existing warnings only (dead code in `MenuDef`, unused `union_regions`, etc.).
---
## 4. Files Modified
### Engine (locked layer)
| File | Changes |
|------|---------|
| `hcie-engine-api/src/partial_composite.rs` | Removed `layer.pixels = processed` in effects pipeline |
| `hcie-engine-api/src/lib.rs` | Added `dirty_bounds`/`below_cache_dirty` to `update_layer_style` and `remove_layer_style_by_index` |
| `hcie-engine-api/src/stroke_brush.rs` | Restored `effects_dirty` in 4 drawing functions |
### Iced GUI (open layer)
| File | Changes |
|------|---------|
| `hcie-iced-app/crates/hcie-iced-gui/src/app.rs` | Toggle fix, drag state/messages/handlers, color messages, recent files, menu wiring |
| `hcie-iced-app/crates/hcie-iced-gui/src/panels/layer_styles.rs` | Complete rewrite: draggable, X button, color picker, backdrop |
| `hcie-iced-app/crates/hcie-iced-gui/src/panels/layers.rs` | Added "fx" button to toolbar |
| `hcie-iced-app/crates/hcie-iced-gui/src/color_picker.rs` | Complete rewrite: tabs, wheel, hex input, swatches |
| `hcie-iced-app/crates/hcie-iced-gui/src/dock/view.rs` | Updated `layer_styles::view()` calls with new parameters |
| `hcie-iced-app/crates/hcie-iced-gui/Cargo.toml` | Added `dirs` and `serde` dependencies |
---
## 5. Known Remaining Issues
1. **Panel positioning:** The drag uses `padding()` offset which may not perfectly center on all screen sizes. The dialog may need `top()`/`left()` absolute positioning for true floating behavior.
2. **Color picker wheel:** The "W" tab uses a grid approximation (36 hue cells + 12×12 SL grid). An actual circular wheel would require custom rendering (iced Canvas widget).
3. **Effects pipeline backup:** The `raw_pixel_backup` is never cleared when a style is removed and the layer has no more styles. This could accumulate memory for layers that had styles and then removed them all.
4. **egui version has the same toggle bug:** The `map_or(false, ...)` pattern exists in the egui version too. The engine fix (1.1) resolves the effects corruption for both GUIs, but the egui toggle inversion needs a separate fix.