Skip to content

UI cleanup: declutter the viewer status bar (no more overflow/overlap)#1

Merged
grymmjack merged 9 commits into
mainfrom
claude/pixel-viewer-ui-cleanup-vffyh3
Jun 29, 2026
Merged

UI cleanup: declutter the viewer status bar (no more overflow/overlap)#1
grymmjack merged 9 commits into
mainfrom
claude/pixel-viewer-ui-cleanup-vffyh3

Conversation

@grymmjack

@grymmjack grymmjack commented Jun 29, 2026

Copy link
Copy Markdown
Owner

The problem (reported)

The viewer's bottom status bar overflows on a 1512px Mac (and worse on smaller screens): the left button group and the right control group paint over each other, producing the garbled rid f 1:1 ⤢ Fit·Tilepack.

reported overlap

Why it happens

The single-view bar is one ui.horizontal packing ~18 widgets + 2 sliders + a long hint. The left group (⬅ Grid · 1:1 · Fit · Tile) renders left-to-right and never shrinks; the right group renders right-to-left and never shrinks — so they collide in the middle. The existing Label::truncate() safety net only covers the Grid-mode label; Single mode's left side is buttons, which overflow rather than truncate. Three unrelated concerns (navigation / retro-FX / playback) were all on one strip.

diagnosis

The cleanup passes

Pass A — group by concern, collapse into popovers. Only navigation + zoom stay inline.

  • 📺 CRT menu — scanlines, scale-with-zoom, glow + amt, black background, and (text-mode only) CRT aspect + 9-dot VGA cell.
  • ▶ Auto menu — auto-advance toggle + delay, plus the random-pack screensaver. The button title turns yellow while paused.

Pass B (light) — reclaim the right edge. The always-on Z+1-0 / Ctrl+wheel… hint (~200px) becomes a compact ? carrying the same text as a tooltip.

Pass C — playback transport row. De-duplicated the readout (the byte position was printed three times; the slider already shows it → {pct}% · {size}), and moved the baud picker up next to Play / Replay / seek in the transport row, where it belongs — it used to sit in the bottom status bar.

Pass D — merge the favorites strip into the path row. The near-empty Favorites: ★ Pin panel was a whole row holding one button. ★ Pin + the 📁 chips now live at the right end of the breadcrumb row (a plain horizontal — can only clip at the edge, never overlap). Favorites still show with no folder open (Pin disabled) and are hidden while the path editor is open.

Every toggle keeps identical behavior — purely a relayout. Net: the viewer bar drops from ~18 inline widgets to ~8, collision is structurally impossible, and a whole top row is reclaimed.

Rendered screenshots (the real app, captured in CI)

These are the actual app driven headlessly by the gui_screenshots test (egui_kittest + wgpu/lavapipe) — not mockups. The magenta ring marks where a click landed; per-shot notes are in captions.md.

Pass D — favorites merged onto the breadcrumb row (★ Pin + the 📁 chip, no separate strip):
breadcrumb favorites

Passes A/B/C — the collapsed viewer status bar + the baud picker now in the transport row (top: ▶ Play · ⏮ Replay · ⚡baud · seek; bottom: ▶ Auto · 📺 CRT · Fit W · Snap · N× · ?):
viewer status bar

Pass A — 📺 CRT popover (all retro-monitor effects in one place; ring = click point):
CRT popover

Pass A — ▶ Auto popover (slideshow + random-pack screensaver):
Auto popover

View menu (chrome, unchanged by this PR):
view menu

Preferences dialog (chrome, unchanged by this PR):
preferences

CI

This branch also adds .github/workflows/ci.yml (the repo had no CI):

  • Build & test (gating) — cargo test --locked under xvfb. ✅ green; the full 161 tests pass on a clean runner.
  • GUI screenshots (non-blocking artifact) — installs Mesa lavapipe (software Vulkan) and renders the scenarios above via egui_kittest's wgpu backend, uploading the PNGs + captions.md as the gui-screenshots artifact on every run (confirmed producing all six). Best-effort, so a software-GPU hiccup never red-Xes a PR.

The screenshot scenarios are reusable and parameterized: select a subset with the GUI_SHOTS env var by scenario name or tag, e.g. GUI_SHOTS=ui-change cargo test --features gui-screenshots gui_screenshots. Default renders all. Adding a scenario for a future change is one struct entry. There's also a .claude/ SessionStart hook so Claude-Code-on-the-web sessions can fetch the one github git dependency (no-op locally / for other contributors).

✅ Verified

cargo check clean (0 warnings); full suite green:

test result: ok. 161 passed; 0 failed; 11 ignored

The GUI-screenshot scenarios were also rendered locally under Mesa llvmpipe (software Vulkan) — all six render and every click lands on the right control. No rustfmt drift introduced.

Possible follow-up (not in this PR)

  • Responsive narrowing — collapse labels to glyphs + a overflow below ~700px.

🤖 Generated with Claude Code

claude added 2 commits June 29, 2026 14:40
The single-view bottom status bar packed ~18 widgets + 2 sliders + a long
hint onto one row. Its left button group (Grid/1:1/Fit/Tile) renders
left-to-right and never shrinks, while the right group renders right-to-left
and never shrinks, so on a ~1100px content width they painted over each other
(the garbled "rid f 1:1 Fit·Tilepack" overlap).

Pass A — group the bar by concern and collapse the two low-frequency clusters
into popovers, leaving only navigation + zoom inline:
  - "📺 CRT" menu: scanlines, scale-with-zoom, glow + amt, black background,
    and (text-mode only) CRT aspect + 9-dot cell.
  - "▶ Auto" menu: auto-advance toggle + delay, plus the random-pack
    screensaver controls. The button title goes yellow while paused, keeping
    that visual cue at the top level.
The baud picker stays inline but only appears during playback, so it never
adds to the at-rest width. Every toggle keeps identical behavior; this is
purely a relayout. Result: the row fits well under 1100px with headroom for
smaller screens, and the two groups can no longer collide.

Pass C — de-duplicate the playback readout. It printed the byte position three
times (slider value + "{pos} / {len} bytes"); the slider already shows the
position, so the label now reads "{pct}% · {total size} · {baud} baud".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
…design notes

Pass B (light) — the permanent "Z+1-0 / Ctrl+wheel zoom · drag to pan" hint sat
on the right edge of the viewer status bar on every screen (~200px). Collapse it
to a compact "?" that carries the same text as a tooltip.

Pass D — fold the favorites into the breadcrumb row. The standalone
"Favorites: ★ Pin" panel was a whole row holding (usually) one button; removing
it reclaims a row of vertical height on every screen. ★ Pin + the 📁 favorite
chips now render at the right end of the path row. The row is a plain horizontal,
which can only clip at the panel edge — never overlap another panel — so a long
path stays safe. Favorites still render when no folder is open (Pin disabled),
preserving quick-jump from a fresh launch, and are suppressed while the
full-width path editor is open. ui_favorites is removed (inlined).

Also add docs/ui-cleanup/ — the reported screenshot, a diagnosis mockup, the
four-pass proposal mockup, and a README mapping each to the change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
@grymmjack grymmjack changed the title UI: collapse the viewer status bar so it can't overflow UI cleanup: declutter the viewer status bar (no more overflow/overlap) Jun 29, 2026
claude added 7 commits June 29, 2026 15:32
The repo had no CI. Add .github/workflows/ci.yml with two jobs:

- test (gating): installs the eframe/winit + openssl build deps, then runs
  `cargo test --locked` under xvfb (the 161 tests are headless via egui_kittest
  + AccessKit; xvfb is just a safety net).

- screenshots (non-blocking artifact): installs Mesa lavapipe (software Vulkan)
  and renders real GUI screenshots of the app chrome via egui_kittest's wgpu
  backend, uploading them as a build artifact. continue-on-error so a software-
  GPU hiccup never blocks a PR.

To support the screenshots job without bloating the default build, add an
opt-in `gui-screenshots` cargo feature (enables egui_kittest's wgpu+snapshot
features) and an in-crate, feature-gated test module `gui_screenshots` that
drives the app (startup → View menu → Preferences) and writes PNGs to
target/gui-screenshots/. The module is a unit test rather than a tests/ file
because this is a binary crate (no lib target) and needs PixelView's internals.
Normal `cargo test` neither compiles wgpu nor needs a GPU. Cargo.lock pins the
wgpu deps so both jobs can use --locked reproducibly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
The first run failed with wgpu "No adapter found": the job over-constrained the
software stack. Forcing VK_ICD_FILENAMES to a hardcoded path disabled the Vulkan
loader's auto-discovery of the lavapipe ICD, and WGPU_BACKEND=vulkan removed the
GL/llvmpipe fallback — so no adapter was visible on any backend.

Fix: install the Vulkan loader (libvulkan1) + lavapipe and let it auto-discover
(no VK_ICD_FILENAMES, no WGPU_BACKEND — egui_kittest already prefers any CPU
adapter). Add a `vulkaninfo --summary` diagnostic, split the compile (fail-able)
from the render, and make the render best-effort (`|| ::warning::`) so a
software-GPU hiccup never red-Xes the PR; artifacts upload when rendering works.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
Claude Code on the web routes outbound github *git* access through a repo-scoped
proxy that only permits this repo, so a fresh `cargo build`/`test` can't fetch the
icy_parser_core dependency (github.com/mkrueger/icy_tools) — the proxy 403s.

Add a SessionStart hook that, in the web sandbox only, removes the
`https://github.com/` -> local-proxy git rewrite so cargo fetches the dep directly
through the session's general (policy-governed) egress proxy, then warms the cargo
cache. It matches the proxy by its local_proxy@127.0.0.1 marker (the port varies
per session) and removes ONLY that rewrite — commit signing, the repo's own origin
remote, and the ssh->https rewrites are untouched.

Safe + zero-impact off the web: the hook `exit 0`s unless $CLAUDE_CODE_REMOTE=true
and only acts when the rewrite is present, so local machines and anyone else
cloning are unaffected (no Cargo.toml/Cargo.lock/.cargo changes — a normal clone
builds as before). The repo ignores .claude/, so .gitignore is narrowed to track
just this shared hook + settings. Validated: removes a re-armed rewrite, preserves
signing, no-ops locally, is idempotent, and `cargo test` passes afterward.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
Replace the single chrome-only screenshot test with a reusable scenario registry
that drives the actual app and captures the real UI changes:

- 01 breadcrumb-favorites: folder open, pinned — shows favorites merged into the
  breadcrumb row (Change D).
- 02 viewer-status-bar: art opened in the viewer — the collapsed status bar
  (Changes A/B/C).
- 03 crt-popover / 04 auto-popover: clicks the 📺 CRT / ▶ Auto buttons to open the
  new popovers (Change A).
- 05 view-menu / 06 preferences: existing chrome.

It opens art via load_full + Mode::Single (a grid tile has no a11y label) and
clicks status-bar buttons by label. Scenarios are selectable by name or tag via
the GUI_SHOTS env var (e.g. GUI_SHOTS=ui-change); default renders all. The only
thing painted on the image is a magenta ring at the click point (spatial — can't
be a caption); the mouse cursor is kittest's own. Per-shot textual notes (action
/ keys / what each shows) are written to captions.md beside the PNGs rather than
overlaid on the UI. Frames advance with step()/run_steps() (the app repaints
continuously, so run()'s settle assertion never holds). Each scenario is panic-
isolated so one bad shot can't drop the rest. The artifact now uploads the whole
target/gui-screenshots/ dir (PNGs + captions.md).

Verified locally under Mesa llvmpipe (software Vulkan): all six render and the
clicks land on the right controls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
The actual app, rendered headlessly by the gui_screenshots scenario test under
software Vulkan, showing the UI changes (favorites on the breadcrumb row, the
collapsed viewer status bar, the 📺 CRT and ▶ Auto popovers) with the click
marker. captions.md carries the per-shot action notes. Embedded in PR #1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
Per the Pass C mockup, the baud picker now sits next to Play / Replay / seek in
the viewer's playback controls row instead of the bottom status bar — it's a
playback control, so it belongs with the transport. The combo writes to a local
(`baud_choice`) inside the row so it doesn't need `&mut self` while the player is
borrowed; the per-kind speed + restart are applied right after that borrow ends.
Removed the duplicate picker from ui_status. Status-bar readout unchanged
otherwise; the transport readout drops the now-redundant "· baud" suffix.

Refreshes the committed GUI screenshots + caption to show the new location.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
`archive_mount` was set when entering an archive / 16colo.rs pack but never
cleared, so after browsing a pack and navigating to a plain local folder the
stale mount kept `in_colo` true — leaving the 16colo.rs Years/Latest/Groups/
Artists + search nav bar (and the archive breadcrumb) visible when not browsing
16colo at all.

open_folder's local-folder branch now drops the mount when the target folder is
outside the mount's extracted `temp_root`, while keeping it for navigation
*within* the archive (subfolders still work). Both mount entry points set the
mount before opening temp_root, so entry isn't affected.

Adds a regression test (leaving_an_archive_mount_clears_it).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNZKReiP8AYvQcM371cUF9
@grymmjack grymmjack merged commit 774175e into main Jun 29, 2026
2 checks passed
@grymmjack grymmjack deleted the claude/pixel-viewer-ui-cleanup-vffyh3 branch June 29, 2026 21:52
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