Files
hcie-rust-v3.05/docs/compose/specs/2025-07-15-iced-selection-features-design.md
phantom 1fd0c5291a feat(iced): add marching ants animation for selection
- Added marching_ants_offset to HcieIcedApp for animation state
- Added selection_bounds field to IcedDocument for persistent selection display
- Updated OverlayProgram to draw animated marching ants (black + white dashed lines)
- Added timer subscription for continuous animation when selection is active
- Updated SelectAll/Deselect handlers to properly manage selection state
- Selection now remains visible after creation with animated border
2026-07-15 04:11:48 +03:00

9.3 KiB

Iced GUI Selection Features Design

[S1] Problem

The iced GUI migration is missing critical selection-based features that exist in the egui GUI:

  1. #1350 Move/Rotate/Scale - No transform handles on selections
  2. #1351 Raster Copy/Paste - Only copies entire canvas, not selected pixels
  3. #1352 Vector Copy/Paste - No vector shape selection/copy/paste
  4. Selection menu - Missing feather, grow, shrink, border, fill operations
  5. Crop tool - Broken (Enter/double-click don't work, selection mixes between images, shows marching ants instead of proper handles)

[S2] Solution Overview

Core Architecture Changes

1. SelectionTransform State (in IcedDocument)

Add to IcedDocument:

pub struct IcedDocument {
    // ... existing fields ...
    
    /// Active selection transform (floating pixels after cut/copy-paste)
    pub selection_transform: Option<SelectionTransform>,
    /// Transform handle being dragged
    pub transform_drag_handle: TransformHandle,
    /// Internal clipboard for copy/paste operations
    pub internal_clipboard: Option<SelectionTransform>,
    /// Selection mask (alpha channel) for the current selection
    pub selection_mask: Option<Vec<u8>>,
    /// Selection bounds (x, y, width, height)
    pub selection_bounds: Option<(u32, u32, u32, u32)>,
}

2. SelectionTransform Struct

#[derive(Clone)]
pub struct SelectionTransform {
    pub pixels: Vec<u8>,
    pub width: u32,
    pub height: u32,
    pub pos: iced::Vector,
    pub size: iced::Vector,
    pub rotation: f32,  // radians
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TransformHandle {
    #[default]
    None,
    Move,
    TopLeft,
    TopRight,
    BottomRight,
    BottomLeft,
    Top,
    Bottom,
    Left,
    Right,
    Rotate,  // rotation handle (outside corner)
}

3. CropState Struct

#[derive(Clone, Default)]
pub struct CropState {
    /// Crop rectangle in canvas coordinates
    pub rect: Option<(f32, f32, f32, f32)>,
    /// Whether crop is being dragged
    pub is_dragging: bool,
    /// Drag start position
    pub drag_start: Option<(f32, f32)>,
    /// Whether to show crop overlay
    pub active: bool,
}

[S3] Feature Details

Feature #1350: Raster Move & Rotate & Scale

UI Requirements:

  • Selection shows 8 resize handles (corners + edges) + rotation handle
  • Handles are 8x8px squares at zoom=1, scaled by 1/zoom
  • Rotation handle is a small circle above the top-center handle
  • Dotted rectangle around selection when in transform mode
  • Cursor changes based on handle (resize arrows, move crosshair, rotation arc)

Implementation:

  1. Add selection_transform: Option<SelectionTransform> to IcedDocument
  2. Extend OverlayProgram to draw transform handles
  3. Add TransformHandle hit-testing in overlay update()
  4. Handle mouse drag on each handle type in app.rs
  5. Apply transform on Enter key or double-click

Messages to Add:

Message::TransformStart(usize),  // handle index
Message::TransformMove(f32, f32),
Message::TransformEnd,
Message::TransformApply,
Message::TransformCancel,
Message::TransformRotate(f32),

Feature #1351: Raster Selection Copy & Paste

UI Requirements:

  • Copy (Ctrl+C) copies only selected pixels (respecting mask)
  • Paste (Ctrl+V) creates floating layer with copied pixels
  • Cut (Ctrl+X) copies and clears selected pixels
  • Internal clipboard stores SelectionTransform
  • Paste positions at selection origin or center of viewport

Implementation:

  1. On Copy: extract pixels within selection mask, store in internal_clipboard
  2. On Paste: create SelectionTransform from clipboard, enter transform mode
  3. On Cut: copy then clear selected pixels in active layer
  4. On transform apply: composite floating pixels back to layer

Engine API Calls:

// Copy selected pixels
let pixels = engine.get_active_layer_pixels();
let mask = engine.get_selection_mask();
let selected = extract_masked_pixels(pixels, mask, canvas_w, canvas_h);

// Cut
engine.clear_selection();  // may need to add this API

// Paste
engine.add_layer("Floating");
engine.set_active_layer(new_layer_id);
engine.draw_pixels_at(floating_pixels, x, y);

Feature #1352: Vector Selection Copy & Paste

UI Requirements:

  • VectorSelect tool can click to select vector shapes
  • Selected shapes show bounding box with handles
  • Copy/Paste duplicates selected vector shapes
  • Paste positions at offset from original

Implementation:

  1. Add selected_vector_indices: Vec<usize> to state
  2. On VectorSelect click: hit-test vector shapes, select closest
  3. On Copy: store selected VectorShape data in clipboard
  4. On Paste: add duplicated shapes with offset
  5. Draw selection bounding box in overlay

Messages to Add:

Message::VectorSelectAt(f32, f32),
Message::VectorSelectToggle(usize),
Message::VectorCopy,
Message::VectorPaste,
Message::VectorCut,
Message::VectorDelete,

Selection Menu Improvements

Menu Items to Implement:

  • Select > All (Ctrl+A) - already exists
  • Select > Deselect (Ctrl+D) - already exists
  • Select > Inverse (Shift+Ctrl+I) - needs implementation
  • Select > Grow - dialog exists, needs engine call
  • Select > Shrink - needs implementation
  • Select > Feather - needs implementation
  • Select > Border - needs implementation
  • Select > Fill - needs implementation

Implementation:

  1. Add engine API methods if missing:
    • engine.invert_selection()
    • engine.shrink_selection(px)
    • engine.feather_selection(px)
    • engine.border_selection(px)
    • engine.fill_selection(color)
  2. Wire menu items to these methods
  3. Add dialog for parameter input (px value)

Crop Tool Fixes

Issues to Fix:

  1. Enter key not working → Wire keyboard event to crop confirm
  2. Double-click not working → Add double-click handler
  3. Selection mixing between images → Store crop state per-document
  4. Marching ants instead of handles → Draw proper crop handles

Implementation:

  1. Add crop_state: CropState to IcedDocument (per-document)
  2. Draw crop overlay with 8 handles + rule-of-thirds grid
  3. Handle Enter/double-click to confirm crop
  4. Handle Escape to cancel crop
  5. Apply crop via engine.crop(x, y, w, h)

Crop Overlay Drawing:

┌─────────────────────┐
│     │     │     │   │  ← rule of thirds
│─────┼─────┼─────│   │
│     │     │     │   │
│─────┼─────┼─────│   │
│     │     │     │   │
└─────────────────────┘
  □                 □    ← corner handles
       □       □         ← edge handles

[S4] Files to Modify

Primary Files

  1. hcie-iced-app/crates/hcie-iced-gui/src/app.rs - Main state and update logic
  2. hcie-iced-app/crates/hcie-iced-gui/src/canvas/mod.rs - Overlay drawing
  3. hcie-iced-app/crates/hcie-iced-gui/src/panels/menus.rs - Menu definitions
  4. hcie-iced-app/crates/hcie-iced-gui/src/panels/tool_options.rs - Tool options

New Files (if needed)

  1. hcie-iced-app/crates/hcie-iced-gui/src/selection/transform.rs - Transform logic
  2. hcie-iced-app/crates/hcie-iced-gui/src/selection/crop.rs - Crop tool logic

[S5] Implementation Order

  1. Phase 1: Core Selection State

    • Add SelectionTransform, TransformHandle, CropState structs
    • Add selection_mask, selection_bounds to IcedDocument
    • Basic selection drawing improvements
  2. Phase 2: Transform Handles

    • Draw 8 resize handles + rotation handle
    • Handle hit-testing for each handle
    • Implement drag behavior for resize/move/rotate
  3. Phase 3: Raster Copy/Paste

    • Implement extract_masked_pixels helper
    • Wire Ctrl+C/V/X to selection operations
    • Add transform mode on paste
  4. Phase 4: Vector Selection

    • Add vector shape hit-testing
    • Implement VectorSelect tool behavior
    • Wire vector copy/paste
  5. Phase 5: Selection Menu

    • Implement Inverse, Shrink, Feather, Border, Fill
    • Add parameter dialogs where needed
  6. Phase 6: Crop Tool

    • Fix Enter/double-click handling
    • Draw proper crop overlay with handles
    • Per-document crop state isolation

[S6] Testing Strategy

  1. Unit Tests:

    • SelectionTransform::from_engine() with various masks
    • TransformHandle hit-testing accuracy
    • extract_masked_pixels() correctness
  2. Integration Tests:

    • Full copy/paste workflow
    • Transform apply/cancel cycle
    • Crop confirm/cancel cycle
  3. Visual Tests:

    • Screenshot comparison for handle rendering
    • Verify cursor changes on hover
    • Check overlay alignment at different zoom levels

[S7] Performance Considerations

  • Selection mask should be cached, not recomputed per frame
  • Transform preview should use existing composite refresh throttling
  • Crop overlay is lightweight (few rectangles) - no performance concern
  • Vector hit-testing uses bounding box first, then precise test only on candidates

[S8] Edge Cases

  1. Empty selection - All operations should be no-ops or show warning
  2. Selection outside canvas - Clamp to canvas bounds
  3. Multiple documents - Each has independent selection state
  4. Undo/redo - Transform apply should create history entry
  5. Layer visibility - Selection should only affect visible layers
  6. Vector shapes on hidden layers - Should not be selectable