Files
hcie-rust-v3.05/.kilo/plans/1784456713003-iced-gui-visual-polish-plan.md
T
phantom 3659b886ff Refactor and enhance the Iced GUI with new features and improvements
- Improved layout and styling in filter_params.rs for better visual consistency.
- Enhanced filters.rs to ensure scrollable parameters fill the available width.
- Added a new Custom Shapes panel to display user-defined SVG shapes.
- Updated menus.rs to include a new Custom Shapes menu item and adjusted related logic.
- Modified properties.rs to support additional spray tool properties (particle size and density).
- Adjusted title_bar.rs for improved menu button dimensions and layout.
- Enhanced toolbar.rs to include spray tool options in the toolbar.
- Fixed color persistence issues in settings.rs to ensure colors are saved and loaded correctly.
- Updated plain_slider.rs to ensure sliders utilize the full width of their containers.
- Created a visual polish plan to address various UI/UX issues and improve overall usability.
2026-07-20 20:24:40 +03:00

15 KiB
Raw Blame History

ICED GUI Visual & Behavioral Polish Plan

Context

This plan addresses the visual and functional issues surfaced during recent ICED GUI testing. The focus is on the Iced build (hcie-iced-app/crates/hcie-iced-gui/). Items are grouped by theme and ordered to minimize code conflicts.


Tasks

1. Fix theme-inconsistent blue accent buttons

Problem: Dialogs like New Image show preset buttons as solid blue (#3355cc), which clashes with the dark theme and looks unnatural.

Files:

  • hcie-iced-app/crates/hcie-iced-gui/src/dialogs/new_image.rs
  • hcie-iced-app/crates/hcie-iced-gui/src/dialogs/mod.rs (primary/secondary helpers)

Changes:

  • Add a preset_btn helper in dialogs/mod.rs that uses theme colors (bg_hover/accent border/text) rather than the default blue.
  • Use it for all preset rows.
  • Ensure primary button (Create) remains theme-accent but with hover/pressed states.

2. Fix color-picker persistence / session recall

Problem: The user reports that foreground/background colors are identical on startup and recent colors are not added/persisted.

Observed code:

  • load_colors() is called in app.rs:1719 and applied.
  • add_recent_color() exists and is called by FgColorChanged/SwapColors.
  • save_colors() is called when colors_dirty is true.

Likely issues:

  • load_colors returns PersistedColors with #[serde(default)], but if any field is absent it becomes Default, which is None/empty. This is fine.
  • Root cause candidates:
    • Message::ResetColors exists, but there may be no UI button mapped to it in the color picker panel.
    • The saved colors file may not be written because colors_dirty is only set on FgColorChanged/BgColorChanged/SwapColors/ResetColors. Some popup color changes may not route through those messages.
    • When the app starts, fg_color and bg_color are initialized to the same default ([0,0,0,255]) before load_colors() runs, and then load_colors overrides them. This should be correct, but verify.

Changes:

  • Ensure PopupColorChanged routed to Foreground/Background actually triggers add_recent_color and sets colors_dirty. It does via FgColorChanged/BgColorChanged.
  • Add a Reset button in the color picker panel (color_picker.rs) that emits Message::ResetColors.
  • Verify load_colors() correctly falls back when file is missing; add debug log if parsing fails.
  • Ensure save_colors() stores alpha and recent list (already does).
  • Remove or explain why fg_color/bg_color default to the same value in IcedDocument / HcieIcedApp::new before loading.

3. Right-click to pick secondary color in color palette panel

Problem: Right-click on palette/recent colors should set the background color.

Observed code:

  • color_picker.rs already has .on_right_press(Message::BgColorChanged(...)) on palette grid cells and recent colors.
  • However, the wheel canvas only handles right-click inside ColorWheel::update and sends Message::BgColorChanged(color).

Changes:

  • Verify right-click events are not swallowed by the panel/container.
  • If Iced does not deliver right-clicks on mouse_area children reliably, wrap the whole color picker content in a mouse_area with on_right_press to set background color from current foreground? No — user expects picking the swatch under cursor.
  • Prefer: keep per-swatch right-click handlers and add a test or visual verification.
  • If still broken, investigate whether mouse_area in Iced 0.13 requires an explicit background hit; add a transparent container around each swatch.

4. Enforce color palette panel minimum height so content stays visible

Problem: Color Palette panel can be collapsed too short; its contents become hidden.

File: hcie-iced-app/crates/hcie-iced-gui/src/dock/sizing.rs

Change:

  • Raise PaneType::ColorPicker minimum height from 300.0 to 420.0.
  • Consider also raising min width from 180.0 to 200.0.
  • Ensure the color picker view uses scrollable(content) so overflow remains usable.

5. Filters panel: parameter sliders should fill ~80% of panel width

Problem: Filter parameter sliders are too narrow and leave large unused space.

File: hcie-iced-app/crates/hcie-iced-gui/src/panels/filter_params.rs

Changes:

  • Audit all float_slider / int_slider calls and ensure the underlying plain_slider width is Length::Fill inside a container with width(Length::Fill).
  • In filters.rs, wrap the parameter section in a container with width(Length::Fill) and ensure scrollable(params_panel) does not clamp width.
  • Add width(Length::Fill) to the column! returned by filter_params::view if not already present.

6. Filter operations should integrate with history / undo

Problem: Filter Apply is not undoable via the History panel.

File: hcie-iced-app/crates/hcie-iced-gui/src/app.rs

Change:

  • Before engine.apply_filter(...) in Message::FilterApply, call engine.push_active_layer_snapshot(...) (or the appropriate engine history API) with a description like "Apply <filter_name>".
  • After apply, refresh history cache (refresh_history) so the new entry appears in the History panel.
  • Ensure undo (Message::HistoryJump) and redo paths still work after the snapshot is pushed.

7. Brush button should reveal Brushes panel if closed

Problem: User says brush button does not open the Brushes panel.

Observed code: Message::ToolSelected(Tool::Brush) already calls self.dock.reopen_pane(PaneType::Brushes) at app.rs:2289.

Possible issue: reopen_pane may silently fail when the pane is auto-hidden or floating; or the brush tool can also be selected via slot click without this path.

Changes:

  • Verify ToolSlotClicked/SubtoolsToggle also triggers reopen_pane(PaneType::Brushes) when the resulting tool is Tool::Brush.
  • Add a helper ensure_brushes_panel() and call it wherever the active tool becomes Tool::Brush.
  • Test with panel closed, auto-hidden, and in a different tab group.

8. Selecting a filter from the Filters menu should reveal the Filters panel

Problem: Filter menu selection should open/raise the Filters panel.

Observed code: Message::FilterSelect(filter) already calls self.dock.reopen_pane(PaneType::Filters) at app.rs:4628.

Possible issue: Same as above — reopen_pane may not handle auto-hide/floating states.

Changes:

  • Audit DockState::reopen_pane to ensure it restores auto-hidden panels, focuses existing floating panels, and brings the pane to front if stacked.
  • If reopen_pane is already correct, add visual verification; otherwise fix it.

9. Menu bar vertical padding (+2 px already planned, verify in final screenshot)

File: hcie-iced-app/crates/hcie-iced-gui/src/panels/title_bar.rs

Already changed: MENU_BAR_HEIGHT 28→30 and menu button widths increased.

Remaining: Confirm no clipping occurs with the new widths; adjust further if "Image" still truncates.


10. Prevent zero-size document creation (wgpu crash)

Problem: The New Image dialog allows width or height to be set to 0. Creating a 0×N document causes the renderer to request a texture with zero height (resize_texture 800×600 → 4096×0), which triggers a wgpu validation error and panic.

Files:

  • hcie-iced-app/crates/hcie-iced-gui/src/dialogs/new_image.rs
  • hcie-iced-app/crates/hcie-iced-gui/src/app.rs (DialogNewImageCreate handler)

Changes:

  • Clamp the width/height sliders to a minimum of 1 in new_image.rs.
  • In DialogNewImageCreate, validate dialog_new_width >= 1 && dialog_new_height >= 1 before creating the engine; if invalid, keep the dialog open and log a warning (or show inline validation text).
  • Optionally disable the Create button when either dimension is zero.
  • Remove or ignore the Custom preset with width: 0, height: 0 since it is not a valid document size.

11. Expose spray particle size / density in the UI

Problem: Spray tool radius/density settings are present in tool_settings.rs but not visible in the merged toolbar or Properties panel.

Observed code:

  • tool_settings.rs:132-179 already has spray_settings() with Particle Size and Density sliders.
  • properties.rs:134 groups Tool::Spray with brush properties, which only shows Size/Opacity/Hardness.
  • toolbar.rs:95 also groups Spray with Brush and only shows Size/Hardness.

Changes:

  • In properties.rs, when active_tool == Tool::Spray, call a new spray_properties(...) helper that includes Size, Particle Size, Density, Opacity, and Hardness.
  • In toolbar.rs, add a Spray-specific branch that shows Size, Particle Size, and Density (or move the existing spray controls from the Tool Settings panel into the merged toolbar if that is the intended UX).
  • Ensure the values are read from settings.tool_settings.spray_particle_size / spray_density and emit the existing Message::SprayParticleSizeChanged / SprayDensityChanged messages.

12. Add a custom-shape slot / panel so user SVGs under ~/.local/share/hcie/shapes/ are usable

Problem: The user copied extra SVG files into /home/dev-user/.local/share/hcie/shapes/, but they did not appear in the UI and could not be used.

Observed code:

  • Engine::new() initializes shape_catalog from dirs::data_local_dir()/hcie/shapes (matches ~/.local/share/hcie/shapes) in hcie-engine-api/src/lib.rs:558-562.
  • ShapeCatalog::refresh() in hcie-engine-api/src/shape_catalog.rs scans *.svg files there and assigns them indices.
  • Tool::CustomShape(idx) exists and is handled in app.rs:5945-5966, using a snapshot of shape_catalog.all() during VectorDrawEnd.
  • sidebar/mod.rs TOOL_SLOTS does not contain a slot for Tool::CustomShape. The vector-shapes slot only lists built-in VectorArrow, VectorStar, etc.
  • There is no panel or popup listing the catalog entries for selection.

Root cause: The ICED sidebar has no entry point for Tool::CustomShape, so even though the engine loads custom SVGs from ~/.local/share/hcie/shapes/, the user cannot select or draw them.

Decision: New dock panel with real SVG previews via iced::widget::svg::Handle::from_memory.

Changes:

  • Add PaneType::CustomShapes to dock/state.rs with label "Custom Shapes".
  • Create hcie-iced-app/crates/hcie-iced-gui/src/panels/custom_shapes.rs.
    • Accept shapes: &[ShapeEntry] and selected_index: Option<usize>.
    • Render each entry as a small card (e.g. 56×56 preview + label below).
    • Use iced::widget::Svg::new(Handle::from_memory(entry.svg.into_bytes())) for the preview, sized to fit the card.
    • On click, emit Message::ToolSelected(Tool::CustomShape(index)).
    • Highlight the selected card with colors.accent border.
  • Wire the new panel in dock/view.rs.
  • Add the panel to settings.rs default visible_panels / panel_order so it appears in the initial dock layout.
  • Add a "Refresh" button in the panel that emits Message::RefreshCustomShapes; handler calls engine.shape_catalog.refresh() and updates app.cached_custom_shapes.
  • Store a cached Vec<(String, String)> of custom shapes in HcieIcedApp so the panel can be rebuilt cheaply; refresh it whenever the panel is shown or when Refresh is pressed.
  • Ensure Tool::CustomShape(idx) out-of-range cases return None in VectorDrawEnd (already mostly true; add explicit guard).
  • Verify that copied SVGs are valid — ShapeCatalog silently skips unreadable / non-SVG files.

12b. Custom Shape drawing not triggering on canvas

Problem: Selecting a custom shape in the Custom Shapes panel does not actually draw it on the canvas when dragging.

Root cause: The shared vector-shape drag flow is gated by is_vector_shape_tool() and an explicit match arm in the CanvasPointerPressed handler. Both locations enumerate the built-in Tool::Vector* variants but omit Tool::CustomShape(_), so the custom-shape tool never enters VectorDrawStart/VectorDrawMove/VectorDrawEnd and therefore never reaches the existing VectorDrawEnd handler that already knows how to build a VectorShape::SvgShape from the catalog.

Files:

  • hcie-iced-app/crates/hcie-iced-gui/src/app.rs
  • hcie-iced-app/crates/hcie-iced-gui/src/sidebar/mod.rs (icon support already present; no change)

Changes:

  1. In app.rs helper is_vector_shape_tool() (around line 1287), add Tool::CustomShape(_) to the matches! pattern.
  2. In app.rs CanvasPointerPressed handler (around line 2824), add Tool::CustomShape(_) to the arm that starts Message::VectorDrawStart.
  3. Keep VectorDrawEnd unchanged; it already snapshots shape_catalog.all() (line 5528-5539) and builds a VectorShape::SvgShape for Tool::CustomShape(idx) with correct bounds.

Edge cases to consider:

  • Out-of-range Tool::CustomShape(idx) already returns None from VectorDrawEnd and produces no shape.
  • If the active layer is a locked vector layer, the shape-flow first switches to a safe non-vector layer before drawing, just like built-in vector shapes.

Validation:

  1. Build: cargo check -p hcie-iced-gui and cargo test -p hcie-iced-gui.
  2. Run the Iced GUI.
  3. Window → Custom Shapes → select a shape.
  4. Drag on the canvas → a new vector layer containing the custom SVG shape appears.
  5. Undo reverts the inserted shape (history snapshot is pushed by engine.add_vector_shape).

Validation Plan

  1. cargo check -p hcie-iced-gui
  2. cargo test -p hcie-iced-gui
  3. Manual launch and visual checks:
    • New Image dialog presets look theme-aware (not bright blue).
    • Set width or height to 0 → Create button disabled; preset ignores 0-size values.
    • Create documents with valid sizes → no wgpu panic.
    • Spray tool selected → Particle Size / Density sliders visible in Tool Settings panel.
    • Pick colors, close app, reopen — colors and recent list restored.
    • Right-click a palette swatch sets background color.
    • Color Palette panel cannot be resized below content height.
    • Select Brush tool → Brushes panel appears.
    • Filter menu → Filters panel appears and parameter sliders are wide.
    • Apply a filter → History panel gains an "Apply …" entry; Undo reverts it.
    • Custom SVG files in ~/.local/share/hcie/shapes/ appear in the new Custom Shapes panel and can be drawn.

Open Questions

  • Is there a reference image or exact hex for the desired preset button style? (Current theme tokens: bg_hover, accent, text_primary.)
  • Should the New Image dialog enforce a single minimum (e.g. 1×1) or a practical minimum (e.g. 8×8) to avoid 1-pixel-high canvases?
  • Should custom shapes be rendered as small SVG previews in the panel, or is a text label list acceptable as a first pass? (Recommended: text list first, SVG preview later.)