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

8.4 KiB
Raw Permalink Blame 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:

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:

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:

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.rsLayerStyleUpdateColor, 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.rsload_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.