UI cleanup: declutter the viewer status bar (no more overflow/overlap)#1
Merged
Merged
Conversation
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
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.Why it happens
The single-view bar is one
ui.horizontalpacking ~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 existingLabel::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.The cleanup passes
Pass A — group by concern, collapse into popovers. Only navigation + zoom stay inline.
📺 CRTmenu — scanlines, scale-with-zoom, glow + amt, black background, and (text-mode only) CRT aspect + 9-dot VGA cell.▶ Automenu — 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: ★ Pinpanel 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_screenshotstest (egui_kittest + wgpu/lavapipe) — not mockups. The magenta ring marks where a click landed; per-shot notes are incaptions.md.Pass D — favorites merged onto the breadcrumb row (
![breadcrumb favorites]()
★ Pin+ the📁chip, no separate strip):Passes A/B/C — the collapsed viewer status bar + the baud picker now in the transport row (top:
![viewer status bar]()
▶ Play · ⏮ Replay · ⚡baud · seek; bottom:▶ Auto · 📺 CRT · Fit W · Snap · N× · ?):Pass A —

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

▶ Autopopover (slideshow + random-pack screensaver):View menu (chrome, unchanged by this PR):

Preferences dialog (chrome, unchanged by this PR):

CI
This branch also adds
.github/workflows/ci.yml(the repo had no CI):Build & test(gating) —cargo test --lockedunder 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.mdas thegui-screenshotsartifact 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_SHOTSenv var by scenarionameortag, 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 checkclean (0 warnings); full suite green: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
rustfmtdrift introduced.Possible follow-up (not in this PR)
⋯overflow below ~700px.🤖 Generated with Claude Code