Files
hcie-rust-v3.05/.kilo/plans/1783343158172-photopea-inline-text-tool.md
T
2026-07-09 02:59:53 +03:00

6.2 KiB

Plan: Photopea-Style Inline Text Tool

Goal

Replace the current modal/separate text dialog with a direct-on-canvas inline text editor that is dedicated to the Text tool and behaves like Photopea/Photoshop.

Design Decisions (resolved)

Topic Decision
Activation Text tool active → click on canvas opens an editable text box at the clicked point.
Box position Clicked point is the top-left corner of the text box; alignment controls internal line alignment only.
Box size Box grows/shrinks dynamically with the typed text; height expands for multi-line content.
Visual style Thin-framed editable box with caret, rendered on top of the canvas.
Live preview Every keystroke updates the underlying Text layer through the engine API (set_text_layer_text).
Accept Ctrl/Cmd+Enter or the toolbar Accept ✓ button finalizes the edit.
Cancel Escape or the toolbar Cancel ✕ button discards the draft layer (ToolTextCancelled).
Toolbar Accept/Cancel buttons are shown only in the top menu bar and only while the Text tool is active and an edit is in progress.
Tool switching guard While a text edit is active, switching to another tool is blocked until Accept or Cancel is pressed.
Re-edit existing layer Double-click a text layer, or click it while the Text tool is active, enters edit mode for that layer.
Non-text layers Clicking a non-text layer while editing cancels the draft.

Affected code boundaries

  • hcie-egui-app/crates/hcie-gui-egui/src/canvas/text_overlay.rs — inline editor widget.
  • hcie-egui-app/crates/hcie-gui-egui/src/canvas/mod.rs — hook overlay, double-click detection, Text-tool click on existing text layer.
  • hcie-egui-app/crates/hcie-gui-egui/src/app/panels.rs — add Accept/Cancel to the top menu bar when Text tool + edit active.
  • hcie-egui-app/crates/hcie-gui-egui/src/app/mod.rs — event handling, tool-change guard, Accept/Cancel events.
  • hcie-egui-app/crates/hcie-gui-egui/src/app/text_editor.rs — keep properties panel live-preview controls.

Implementation tasks

  1. Inline text box (canvas/text_overlay.rs)

    • Use egui::TextEdit::multiline bound to state.text_edit.draft_text.
    • Make the box auto-sized: remove fixed width/height and let egui measure content.
    • Add a visible frame (thin border + subtle fill) so the user sees the edit area.
    • Place top-left at (canvas_rect.min.x + edit.canvas_x * zoom, canvas_rect.min.y + edit.canvas_y * zoom).
    • On change, call doc.engine.set_text_layer_text(layer_id, text) and push RenderRequested.
    • Keyboard:
      • Enter → new line.
      • Ctrl/Cmd+Enter → push ToolTextAccepted.
      • Escape → already handled globally, pushes ToolTextCancelled.
  2. Top toolbar Accept/Cancel (app/panels.rs / app/mod.rs)

    • In show_menu_bar, after the right window-controls cluster or in a dedicated center/right slot, render two small buttons only when state.active_tool == Tool::Text && state.text_edit.active.
    • Accept: green checkmark / “Accept” label; pushes ToolTextAccepted.
    • Cancel: red cross / “Cancel” label; pushes ToolTextCancelled.
    • Keep existing layout stable when buttons are hidden.
  3. Event handling updates (app/mod.rs)

    • ToolTextStart { x, y }: already creates a draft Text layer and opens edit. Keep behavior.
    • ToolTextAccepted: finalize, clear edit state.
    • ToolTextCancelled: delete draft layer, clear edit state.
    • TextLayerSelected(id): load existing text layer into edit state.
    • ToolChanged(new_tool) / LayerSelected(id):
      • If state.text_edit.active, do not apply the change; optionally show a status message like “Finish text edit first”.
      • Only allow the change after ToolTextAccepted or ToolTextCancelled.
  4. Canvas interaction updates (canvas/mod.rs)

    • Detect double-click on the canvas.
    • If double-clicked point is over a text layer (use engine get_pixel or hit-test via layer bounds), push TextLayerSelected(layer_id).
    • If Text tool active and single-click lands on an existing text layer, also push TextLayerSelected instead of creating a new draft.
    • If Text tool active and single-click lands on empty canvas, push ToolTextStart (already implemented).
  5. Properties panel (app/text_editor.rs)

    • Keep current live-preview controls (text content, font, size, color, angle, alignment, orientation).
    • Remove Accept/Cancel from here because they now live in the top toolbar.
    • Ensure changes while editing update the draft layer and request a render.
  6. State consistency

    • When TextLayerSelected loads an existing layer, populate TextEditState from LayerData::Text.
    • When Accept is pressed, ensure the final text is written to the layer and the edit state is cleared.
    • When Cancel is pressed, delete the draft layer only if it was newly created; if editing an existing layer, Cancel should revert to the original text.
    • To support safe Cancel for existing layers, store an original_text snapshot in TextEditState when entering edit mode.

Validation plan

  • Build: cargo build -p hcie-gui-egui
  • Regression tests: cargo test -p hcie-engine-api --test visual_regression --test performance_stroke_4k -- --nocapture
  • Manual GUI checks:
    1. Select Text tool, click canvas → inline box appears and typing shows live text on canvas.
    2. Press Ctrl+Enter or toolbar Accept → edit closes, layer stays visible.
    3. Click canvas again → new draft. Press Escape or toolbar Cancel → draft disappears.
    4. While editing, press B/Brush shortcut or click another tool → nothing happens, status message appears.
    5. Create a text layer, accept it, then double-click it → edit re-opens with original text.
    6. Edit existing layer, change text, press Cancel → text reverts to original.
    7. Change font, size, color, angle, alignment, orientation in Properties panel → canvas updates live.

Open / out-of-scope

  • Warp, 3D and other non-destructive text effects remain metadata-only and will be rasterized in a follow-up phase.
  • PSD/XCF/Krita text-layer round-trip import is out of scope for this plan; the data structures are already prepared for it.