2fb47520b3
feat(debug-logger): add DebugSignalLogger plugin for event logging and inspection feat(plugins): introduce built-in plugins module and integrate debug logger feat(plugin-integration): create integration layer for mapping Iced Messages to CoreEvents feat(plugin-registry): establish PluginRegistry for managing plugins and event dispatching
14 KiB
14 KiB
ICED GUI — Advanced SVG Editor and UI/Color Fixes
Scope
Implement the requested ICED improvements:
- Replace the SVG coordinate-list dialog with an interactive visual node editor.
- Make filter-history behavior explicit and regression-tested.
- Widen filter sliders.
- Open Brushes when Brush is selected.
- Open Filters when a filter is selected from the menu.
- Add secondary-color selection by right-click in the color picker.
The following requests are already implemented and require verification rather than duplicate code:
- Recent colors persist in
~/.config/hcie-iced/colors.json. - Foreground/background colors persist in the same file.
- Recent color swatches already use
.on_right_press(Message::BgColorChanged(c)). - Committed filters already enter history through
Engine::apply_filter()andpush_draw_snapshot("Filter: <id>"); only live preview usesapply_filter_preview()and correctly avoids history entries.
Decisions
| Area | Decision |
|---|---|
| SVG geometry | Support polygon/line paths represented by existing SvgEditable; bezier/curve SVGs remain unsupported because the locked engine API rejects them. |
| SVG live editing | Update the visible canvas preview and engine SVG on every node drag; create one logical edit session. Cancel restores the original SVG; Save keeps the current SVG. Do not create per-mouse-move history entries. |
| SVG editor interaction | Add node drag, node hit testing, edge-midpoint node insertion, node deletion, polygon selection, numeric X/Y editing, zoom/pan, fit-to-view, grid/background, selection highlighting, keyboard Delete/Backspace, and Save/Cancel. |
| SVG rendering | Use an iced::widget::canvas::Canvas/canvas::Program, following canvas/viewport.rs event and coordinate-mapping patterns. Keep the existing modal overlay and Message-driven app state. |
| SVG engine history | Out of scope for GUI-only changes because set_vector_shape_svg() does not expose a vector-history snapshot API. Record this as a residual limitation; do not modify locked engine crates. |
| Filter history | No behavior rewrite. Add regression coverage or an auditable helper around the existing apply_filter() path to prove committed filters are undoable and previews are not committed. |
| Filter slider width | Make filter parameter sliders fill the available Filters pane width and ensure the Filters pane has a minimum width that leaves at least approximately 150px for the track. Use the existing responsive pane sizing rather than a hard-coded global width. |
| Brush auto-open | On Message::ToolSelected(Tool::Brush), reopen the Brushes pane only if it is closed. Never toggle an already-open pane closed. |
| Filter auto-open | In the central Message::FilterSelect handler, reopen the Filters pane only if it is closed. This covers menu commands and other filter entry points consistently. |
| Right-click secondary color | Add right-click handling to the HSL/color-picker canvas. Keep the main canvas right-click context menu unchanged. Recent swatch right-click behavior remains as-is. |
Current Findings
panels/svg_editor.rscurrently displays polygon buttons and a coordinate list only; it has no visual canvas, no drag state, and no numeric editing.- EGUI’s reference editor has
svg_to_screen,screen_to_svg, polygon rendering, node circles, midpoint hit testing, node dragging, add/remove controls, and a resizable canvas. SvgEditableexposesview_box,polygons,add_node,remove_node,move_node,from_svg, andto_svg.- ICED already has interactive Canvas examples in
canvas/viewport.rsand color picker programs incolor_picker.rs. set_vector_shape_svg()marks the vector layer/composite dirty and modified but does not push a vector history snapshot.Engine::apply_filter()already snapshots the pre-filter pixels with descriptionFilter: <id>;apply_filter_preview()intentionally does not.plain_slider()usesLength::Fillinternally, but filter content/pane sizing can leave its parent too narrow. The fix should make the filter slider row explicitly fill the panel and increase Filters sizing minimum if needed.Message::ToolSelectedcurrently changes the active tool but does not reopen Brushes.Message::FilterSelectcurrently selects/preview-starts a filter but does not reopen Filters.recent_colors/fg_color/bg_colorload from and save tocolors.json; recent swatches already support right-click secondary selection.
Affected Files
Advanced SVG editor
-
hcie-iced-app/crates/hcie-iced-gui/src/panels/svg_editor.rs- Replace list-only layout with a visual editor canvas.
- Extend editor state with drag state, original SVG/session state, zoom, pan, hover/selection state, and any fit/grid state needed by the canvas program.
- Add coordinate conversion using
SvgEditable.view_box, preserving aspect ratio and centering the viewBox. - Draw polygon fills/outlines, node handles, edge midpoint handles, grid/background, and selected-node styling.
- Handle primary click/drag for node selection and movement, midpoint click for insertion, and wheel/secondary gestures for zoom/pan without interfering with modal buttons.
- Keep controls for polygon selection, Add Node, Remove Node, X/Y numeric editing, Fit, Zoom +/- or reset, Save, and Cancel.
-
hcie-iced-app/crates/hcie-iced-gui/src/app.rs- Add SVG canvas messages for pointer press/move/release, zoom/pan/fit, numeric X/Y changes, and any explicit node action needed by the new Program.
- Update existing SVG editor handlers to mutate
SvgEditableand immediately callset_vector_shape_svg()for live engine preview. - Capture the original SVG when opening; restore it on Cancel.
- Keep Save/Cancel dialog lifecycle intact and ensure editor drag sessions do not create per-event history entries.
-
hcie-iced-app/crates/hcie-iced-gui/src/dock/view.rsor editor call site only if required by the new state/signature.
Filter and panel behavior
-
hcie-iced-app/crates/hcie-iced-gui/src/app.rs- In
Message::ToolSelected, call a new local helper ordock.reopen_pane(PaneType::Brushes)only when!dock.is_pane_open(PaneType::Brushes)and the selected tool isTool::Brush. - In
Message::FilterSelect, ensurePaneType::Filtersis open before starting the preview. - Preserve the existing filter preview/commit lifecycle.
- Add focused tests or testable helper coverage proving
apply_filter()creates a history entry andapply_filter_preview()does not create a committed entry, if the current test architecture permits without engine changes. - Keep existing persistence code; add tests only if needed to prove colors/recent colors survive serialization/deserialization.
- In
-
hcie-iced-app/crates/hcie-iced-gui/src/panels/filter_params.rs- Make
float_slider()andint_slider()return a control wrapped withLength::Fillat the row/container level so the track consumes the available panel width. - Avoid changing numeric behavior, labels, ranges, or parameter messages.
- Make
-
hcie-iced-app/crates/hcie-iced-gui/src/dock/sizing.rs- Increase the Filters pane minimum/preferred width enough for a roughly 150px slider after label/value columns, while preserving responsive resizing and existing other-pane policies.
Color picker
-
hcie-iced-app/crates/hcie-iced-gui/src/color_picker.rs- Extend the interactive color wheel/picker Canvas program so right-click emits
Message::BgColorChangedwhile left-click/drag continues emitting foreground changes. - Keep current color calculations and alpha behavior.
- Ensure the picker’s displayed source color remains stable and right-click does not alter foreground.
- Preserve existing recent-swatch
.on_right_press(Message::BgColorChanged(c))behavior.
- Extend the interactive color wheel/picker Canvas program so right-click emits
-
hcie-iced-app/crates/hcie-iced-gui/src/app.rs- Confirm
BgColorChangedupdates secondary color, shape synchronization, and persistence state as appropriate. - Do not change main canvas right-click context-menu behavior.
- Confirm
Ordered Implementation Tasks
1. SVG editor state and messages
- Extend
SvgEditorStatewith:original_svg: Stringfor Cancel restoration.drag_node: Option<(usize, usize)>.zoom: f32andpan: Vectoror equivalent.hovered_node/hovered_midpointand fit/grid state if needed.
- Add
Messagevariants for:- canvas pointer pressed/moved/released;
- node X/Y field changes;
- zoom/pan/fit/reset;
- retain existing polygon/node/add/remove/save/cancel messages where reusable.
- On SVG editor open, store the original SVG alongside the parsed editable state.
2. SVG coordinate and rendering model
- Implement
svg_to_screen()andscreen_to_svg()using the viewBox, canvas bounds, margin, zoom, and pan. Preserve aspect ratio so nodes are not distorted. - Implement a Canvas Program that:
- draws the viewBox background/grid;
- draws each polygon/path fill and outline;
- draws node handles with selected/hovered styles;
- draws smaller edge midpoint handles;
- uses
Cursor::position_in(bounds)for hit testing; - maps drag positions back to SVG coordinates.
- Implement hit testing for nearest node and edge midpoint with screen-space thresholds that remain usable at different zoom levels.
3. SVG live editing behavior
- On node press, select the polygon/node and begin drag.
- On node drag, call
editable.move_node(...), update the numeric fields, and immediately emit/apply the currentto_svg()to the active vector shape for live canvas preview. - On midpoint click, call
editable.add_node(...)and update selection/live preview. - On Delete/Backspace or Remove button, remove the selected node when valid and update/live-preview.
- Numeric X/Y edits update the selected node and live-preview.
- Save keeps the current SVG, clears the original/session state, closes the editor, and requests composite refresh.
- Cancel calls
set_vector_shape_svg()withoriginal_svg, refreshes the composite, clears session state, and closes without retaining edits. - Handle empty polygons, invalid selection indices, unsupported bezier SVGs, and zero-sized viewBoxes without panics.
4. Filter/panel behavior
- Add a small
ensure_pane_open(PaneType)helper if repeated logic is useful; otherwise useis_pane_open+reopen_panedirectly. - Call it for Brush selection and Filter selection as specified above.
- Widen filter slider rows and increase Filters pane minimum sizing. Verify at narrow and wide pane widths.
- Verify committed filter history by applying a filter, checking the history description, undoing, and redoing. Do not add history entries during preview slider movement.
5. Color behavior
- Add right-click output support to the color-wheel/picker Canvas Program.
- Verify left-click changes foreground, right-click changes background, recent swatch right-click changes background, and both colors/recent colors persist across restart.
Risks and Edge Cases
- SVG curve limitation:
SvgEditable::from_svg()rejects QuadTo/CubicTo. Show/retain a clear parse failure path; do not silently flatten curves. - Live SVG update cost: Updating the full SVG string on every drag is acceptable for the small vector shape payload, but avoid cloning unrelated document pixels.
- Cancel correctness: Capture the original SVG before the first live update. Cancel must restore it exactly, including after multiple node additions/removals.
- SVG history limitation: The public GUI-facing API has no vector snapshot method for
set_vector_shape_svg(). Do not modify locked engine crates in this scope; document that SVG edits are not currently represented as a dedicated undo entry. - Filter history semantics: Do not push history from slider-preview events. Only the final
FilterApply/directapply_filtercall should be undoable. - Pane reopening: Use
reopen_paneonly when closed; callingtoggle_panewould incorrectly close an already visible pane. - Color picker right-click: Keep canvas context-menu right-click untouched; limit the new behavior to color picker surfaces.
- Color persistence: Avoid resetting
recent_colors,fg_color, orbg_colorduring app initialization afterload_colors().
Validation
cargo check -p hcie-iced-gui.cargo test -p hcie-iced-guiand existing menu tests.- SVG manual flow:
- Open a supported polygon SVG.
- Select a node and drag it; verify the SVG and main canvas update during the drag.
- Insert a node through an edge midpoint and move it.
- Edit X/Y numerically.
- Delete a node and verify minimum-node safeguards.
- Cancel after several edits and verify exact original restoration.
- Reopen, edit, Save, close, and verify the updated SVG persists.
- Try a bezier SVG and verify a controlled unsupported-geometry failure.
- Filter history flow:
- Select a filter and change sliders; verify preview movement does not create multiple history records.
- Apply the filter; verify one
Filter: <id>history entry. - Undo and redo; verify pixels restore/reapply.
- Panel flow:
- Close Brushes, select Brush via sidebar/shortcut/menu, verify Brushes opens.
- Close Filters, choose a filter from the Filter menu, verify Filters opens and the selected filter is shown.
- Slider flow:
- Test Filters pane at minimum and expanded widths; verify slider track is at least approximately 150px or consumes the available panel width.
- Color flow:
- Left-click picker changes foreground only.
- Right-click picker changes background only.
- Right-click recent swatch changes background only.
- Restart app and verify foreground, background, and recent colors persist.
- Capture a focused Filters panel and SVG editor screenshot after the UI changes for visual verification.
Explicitly Unchanged / Already Satisfied
- No engine crate modifications.
- No replacement of the main canvas context menu.
- No per-mouse-move SVG history entries.
- No duplicate recent-color persistence implementation.
- No duplicate filter-history implementation; existing engine snapshot behavior is retained and verified.
- Bezier/curve SVG editing remains a separate engine/API scope.