Skip to content

feat(recolor): collapsible, drag-reorderable pane sections - #97

Draft
grymmjack wants to merge 3 commits into
mainfrom
claude/collapsible-palette-sections-g2dgxp
Draft

feat(recolor): collapsible, drag-reorderable pane sections#97
grymmjack wants to merge 3 commits into
mainfrom
claude/collapsible-palette-sections-g2dgxp

Conversation

@grymmjack

Copy link
Copy Markdown
Owner

What

The Recolor pane below the preview is now eight uniform, collapsible, drag-reorderable sections, and the arrangement persists.

Section Contents New?
Palette · N colors the swatch grid now collapsible
Cleaning Extract pixels from JPEG · Remove JPEG artifacts · Undither new section
Resize upscaler + downsample factors was collapsible
Adjustments the reorderable op stack was collapsible
Pixelate mosaic block size was collapsible
Color balance per-channel R/G/B offset was collapsible
Post FX scanlines / glow / vignette / phosphor was collapsible
Recolor Original · Reduce · palette chooser · dither · textmode export now collapsible
  • ⊞ All / ⊟ All in the pane header collapses or expands everything. Right-click it to restore the default section order. ⟲ Reset all still clears settings, never the layout.
  • Drag a section's grip to reorder; the insertion line targets whole sections (header + body), mirroring the Adjustments row drag.
  • Headers carry an activity marker so a collapsed section still says whether it's doing something — Resize * · 320×200, Cleaning * · 2 on, Recolor * · ANSI32.
  • The whole header row is the toggle, not just the words, with a hover highlight.
  • Preview + the Export/Save row stay outside the sections, directly under the thumbnail, so 💾 Save recolored / Export .GPL… / Export textmode remain reachable on a small screen whatever is collapsed.

How

  • New RecolorSection enum + the free fn recolor_section (drag grip + CollapsingState header + indented body). ui_recolor's tail is now a for loop over self.recolor_order with a match dispatching to one ui_sec_* method per section.
  • The open state is ours, not egui's — a [bool; COUNT] indexed by discriminant. It has to be: persist_egui_memory() returns false, so egui's collapsing state dies at exit, and "collapse all" has to be forceable. Note that forcing CollapsingHeader::open means the header's own clicked() stops toggling, which is why the title is a click-sensed target that calls state.toggle itself.
  • Persistence: recolor_sections (a Vec<u8> of discriminants) + recolor_open (a Vec<bool>), restored by the pure recolor_order_from / recolor_open_from. Variants are appended, never reordered or removed: an unknown id is dropped and a section missing from a saved order is appended, so a config written before a section existed gains it at the end rather than losing it.
  • Mechanically this splits ui_recolor's ~2300-line body into per-section methods; the bodies are moved verbatim (hence the large diff — it's mostly code motion + re-indentation).

Testing

  • cargo test — 505 passed, 0 failed (3 new: section id stability, order round-trip/repair, open-state defaults filling a short record).
  • cargo clippy clean; cargo fmt applied to src/app.rs only.
  • Added shoot_recolor_sections behind the existing gui-screenshots feature, rendering the pane collapsed / expanded / reordered headlessly (lavapipe). Verified visually: all eight sections collapse to one row each, Cleaning groups the three checkboxes, reordering renders in the new order, and the header row still fits Bypass at dock width.

Notes

  • The stale cargo test counts in CLAUDE.md (391 / 266) were already wrong before this change; left alone rather than folded into this diff.

Generated by Claude Code

The Recolor pane was one long scroll: a 473-swatch palette grid, three
loose JPEG/undither checkboxes, and the palette chooser all had to be
scrolled past to reach anything. Only Resize/Adjustments/Pixelate/Balance/
Post FX were collapsible, and their state died at exit.

The pane below the preview is now eight uniform sections — Palette,
Cleaning, Resize, Adjustments, Pixelate, Color balance, Post FX, Recolor —
each with a drag grip, a collapsing header carrying an activity marker
(`Resize *  · 320×200`), and an indented body. The whole header row is the
toggle, not just the words.

- New `Cleaning` section groups the three source-repair steps that were
  previously loose checkboxes: Extract pixels from JPEG, Remove JPEG
  artifacts, Undither.
- Palette (the swatch grid) and Recolor (Reduce / palette chooser / dither /
  textmode export) become collapsible for the first time.
- `⊞ All` / `⊟ All` in the pane header collapses or expands everything;
  right-click restores the default section order. `⟲ Reset all` still
  clears settings only, never the layout.
- Drag a grip to reorder; the insertion line targets whole sections
  (header + body), mirroring the Adjustments row drag.
- Order and per-section open state persist (`recolor_sections` /
  `recolor_open`). The open state is ours rather than egui's because
  `persist_egui_memory()` is false and "collapse all" has to be forceable.
  Restore is via the pure `recolor_order_from` / `recolor_open_from`:
  unknown ids are dropped and a section missing from a saved order is
  appended, so a config written before a section existed gains it instead
  of losing it.

Preview and the Export/Save row stay outside the sections, directly under
the thumbnail, so Save is reachable on a small screen whatever is
collapsed.

Mechanically this splits `ui_recolor`'s 2300-line body into one `ui_sec_*`
method per section plus a `match` in the section loop; the bodies are moved
verbatim. Three unit tests cover the layout round-trip, and a
`gui-screenshots`-gated `shoot_recolor_sections` renders the pane
collapsed/expanded/reordered for headless eyeballing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pe7LgFDS2XN2g6ndBtA5Q4
The ⊞/⊟ toggle sat in the pane's header row as a fourth peer of Apply to
grid / Reset all / Bypass, which is not where you look for chrome that acts
on the list below it — and a worded label there pushed Bypass off the end of
a docked pane.

It now sits flush right on the Export/Save row, directly over the sections
it collapses, styled like VSCode's Explorer toolbar: icon-only and
frameless until hovered (`frame_when_inactive(false)`). The row is renamed
`ui_recolor_toolbar` and always draws, even with no palette to export, so
the toggle is always reachable.

The glyphs are Nerd Font's Codicons — VSCode's own icon set — so the button
reads exactly like the one in the Explorer. They sit below the FontAwesome
range, so per the codepoint rule shadowing was checked explicitly across
every font in `apply_fonts`: none of Ubuntu-Light / NotoEmoji /
emoji-icon-font / Hack / DejaVu Sans has a glyph at U+EAC5 or U+EB95, so
the Nerd Font fallback wins. Both verified rendering in a headless shot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pe7LgFDS2XN2g6ndBtA5Q4
Exporting the palette is about the palette and nothing else, so it now sits
under the swatch grid inside the Palette section rather than on the pane
toolbar. The toolbar keeps the actions that write the *image* — Save
recolored / Save As… / Export textmode — plus the collapse/expand-all
toggle.

The section body is a closure, so the click is raised through a
`gpl_export` out-param threaded via `ui_recolor_one_section`, which also
drops the now-unused `gpl` field and `path` argument from the toolbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pe7LgFDS2XN2g6ndBtA5Q4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants