UI polish: themed labels, colormap swatches, drop feedback, Open Recent, draggable clim - #37
Merged
Merged
Conversation
The anomaly/error (red) and sampled/downsampled/truncated (#b8860b) label colors were hardcoded inline in five files and did not adapt to dark themes, where darkgoldenrod turns muddy and pure red glares. Add ErrorLabel/CautionLabel (in views/base.py) carrying per-scheme colors. QPalette has no error/caution roles to ride the way the empty- state text uses PlaceholderText, so they re-resolve their color from changeEvent(PaletteChange) — an OS theme switch updates the palette, so the event doubles as the scheme-change hook. Unlike the matplotlib canvas (whose style is fixed at startup), a label restyle is free, so these follow theme switches live. "Dark" uses the same colorScheme() criterion as the canvas theme, by convention; Unknown counts as light, leaving the light-theme colors unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UpLDoWW6e5sdXFd7B572Ck
The 11 colormap entries were text-only, so picking one meant knowing its gradient by name. Render each map as a small square dark-to-light swatch (matplotlib RGBA row -> QImage -> QIcon) at the style's menu icon size, device-pixel-ratio aware. A square native QAction icon is used instead of a wide QWidgetAction gradient bar: it keeps the exclusive-group check marks and native macOS menu rendering. The swatches re-render when Reverse is toggled, reusing _effective_colormap as the single source of the _r suffix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UpLDoWW6e5sdXFd7B572Ck
Dragging a .npy/.npz over the window gave no visual feedback until the drop landed. Add a DropOverlay child of the central container: shown on dragEnter of a valid drag, hidden on dragLeave/drop. The overlay is mouse/drop-transparent (WA_TransparentForMouseEvents) so it can never intercept the drag it announces, tracks the container size via an event filter, and paints entirely from the Highlight palette role so it follows light/dark themes with no color constants. Invalid drags are not accepted and show no overlay. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UpLDoWW6e5sdXFd7B572Ck
Reopening yesterday's data file meant walking the file dialog every time. Keep the last 8 successfully opened paths in QSettings and show them in a File > Open Recent submenu, rebuilt on aboutToShow like the dynamic Export menu. Entries show ~-abbreviated full paths (same-named files in different dirs stay distinguishable) with the absolute path as tooltip, plus a Clear Recent action. Missing files are greyed rather than pruned, so entries on a temporarily unmounted drive come back on their own. Two Snap guards: XDG document-portal paths (/run/user/<uid>/doc/...) are never recorded, since their grants may not survive a restart; and greyed entries under confinement explain that File > Open reaches files the sandbox cannot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UpLDoWW6e5sdXFd7B572Ck
The histogram already draws the image's vmin/vmax as dashed markers, but adjusting them meant going back to the Image tab and typing numbers. Make the two markers draggable: pixel-radius hit testing mirrors the cross-section endpoints in ImageCanvas, the artists move in place during the drag, and vmin/vmax are clamped to stay strictly ordered so imshow's normalization remains valid. The drag drives a new histogram -> app -> image callback, the reverse of the existing image -> histogram marker sync. The image side applies it through a silent sink (same no-echo convention as set_view / set_endpoints) that also refills the vmin/vmax edits, so the two directions never chain. Complex/RGB modes are unaffected: they never have markers, and the sink guards them defensively. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UpLDoWW6e5sdXFd7B572Ck
LiukDiihMieu
force-pushed
the
feature/ui-polish-round2
branch
from
July 4, 2026 14:01
9a5691d to
11c4c87
Compare
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.
A round of visual and interaction polish for the viewer. Five independent, low-risk changes, each in its own commit with tests; all 354 tests pass. Verified in the real GUI on the pip build (Snap-specific paths noted below, to be checked once merged).
Theme warning-label colors, tracking runtime switches
The anomaly/error (red) and sampled/downsampled/truncated (
#b8860b) labels were hardcoded inline in five files and read poorly on dark themes. NewErrorLabel/CautionLabel(inviews/base.py) carry per-scheme colors and re-resolve them onPaletteChange, so they follow an OS light/dark switch live — unlike the matplotlib canvas, whose style is fixed at startup, a label restyle is free. "Dark" uses the samecolorScheme()criterion as the canvas theme, by convention.Colormap gradient swatches in the View menu
Each of the 11 colormap entries now shows a small square dark-to-light swatch, rendered from the matplotlib map. A native
QActionicon (not aQWidgetActionbar) keeps the exclusive-group check marks and native macOS menus; the swatches flip when Reverse is toggled.Drop-target overlay
Dragging a
.npy/.npzover the window now shows a translucent "Drop to open" overlay with a dashed border, hidden on leave/drop. It is mouse/drop-transparent so it can't intercept the drag it announces, and paints from the Highlight palette role so it follows the theme. Invalid drags show nothing.File › Open Recent
Keeps the last 8 successfully opened files in QSettings, shown in a submenu rebuilt on open. Entries use
~-abbreviated full paths with the absolute path as tooltip, plus Clear Recent. Missing files are greyed rather than pruned, so entries on a temporarily unmounted drive return on their own. Two Snap guards: XDG document-portal paths (/run/user/<uid>/doc/…) are never recorded, and greyed entries under confinement explain that File › Open reaches files the sandbox cannot.Draggable vmin/vmax markers on the histogram
The histogram already drew the image's clim as dashed markers; now they can be dragged to adjust image brightness directly, with the Image tab's vmin/vmax fields syncing live. Hit testing and cursor feedback mirror the cross-section endpoints; vmin/vmax stay strictly ordered. The drag drives a new histogram→image callback via a silent sink (the same no-echo convention as the linked-view code), so it never chains with the existing image→histogram sync. Complex/RGB modes have no markers and are unaffected.
Not included
An empty-state page icon was prototyped and shelved: the packaged icon has a transparent background and needs the light/dark asset pair to look right — deferred with the dark-icon backlog item.
🤖 Generated with Claude Code