Collapsible panel banners and adaptive window sizing #129

Merged
duan_j merged 57 commits from collapsable-and-adaptive into main 2026-08-11 11:02:31 +02:00
Owner

WIP: test at the beamline (or against a fuller offline backend) before
merging. Prioritise server compatibility over appearance.

Summary

GUI overhaul in four waves, ported from the viz sandbox.

Fit any monitor

  • Window minimum drops to 1400x555; standard page scrolls instead of
    clamping; launchers start maximized; un-maximized geometry is pre-set
    to half-screen so leaving maximized mode fits the display.
  • Collapsible half-height panel banners with per-title persisted state;
    control panels start expanded, the rest collapsed.

One theme file

  • Every color, font size, radius, and border width lives in
    src/aare/gui/styles.py: palette constants, a font-size ladder,
    card_style() helper, QToolTip/scrollbar/slider/tab styling, and
    frame borders as three level knobs. QSS templates substitute tokens,
    so retheming is edits in one file.
  • Light theme retinted; portrait dark theme adopts Catppuccin
    Macchiato. Splash banner is an SVG now.

One sample dock

  • Sample List, Reference Tools, and the automation job list merge into
    a single dock with Dewar/Auxiliary tabs; the dewar table doubles as
    the queue view (queue buttons + Unmount beneath it, membership via
    right-click or dragging rows onto the Queued/Flagged chips).
  • Frozen #+status column with priority tints (mounted > queued >
    flagged > measured); status chip filters; non-staff see Auxiliary
    greyed out with a staff-only popup instead of a vanishing dock.
  • Docks no longer float: a popout button opens an additional fully
    operational window (shared models); closing a pop-out just hides it.

Guard rails

  • Wheel over spin boxes/sliders/combos only adjusts while the right
    mouse button is held; bare wheel always scrolls (motor protection).
  • Camera gains a clickable session badge and a baton gate: watching is
    free, operating clicks are blocked without the baton; losing the
    baton greys out and folds the control columns.
  • Beamline state bar: guarded per-tick updates keep hover cursors
    alive; closing a floating dock re-docks it instead of hiding it.

Tests

26 new unit tests cover the behavior this PR adds: sample-status tint
priority and chip filtering (incl. measured = rotation count > 1),
the right-button wheel guard, PopoutWindow resize/close/title-bar
behavior, chip drag-drop relabeling, and the console-log pop-out
mirror. PR diff coverage 81% (gate 80%).

CI

All green: lint (ruff format + check, basedpyright diff gate), tests
on py3.11/3.12/3.13 and all three beamline plugin variants, diff
coverage above the 80% minimum. One src compat fix rode along:
MLOutputModel.get_class_str is called positionally, since aarecommon
releases disagree on the cls parameter.

WIP: test at the beamline (or against a fuller offline backend) before merging. Prioritise server compatibility over appearance. ## Summary GUI overhaul in four waves, ported from the viz sandbox. ### Fit any monitor - Window minimum drops to 1400x555; standard page scrolls instead of clamping; launchers start maximized; un-maximized geometry is pre-set to half-screen so leaving maximized mode fits the display. - Collapsible half-height panel banners with per-title persisted state; control panels start expanded, the rest collapsed. ### One theme file - Every color, font size, radius, and border width lives in src/aare/gui/styles.py: palette constants, a font-size ladder, card_style() helper, QToolTip/scrollbar/slider/tab styling, and frame borders as three level knobs. QSS templates substitute tokens, so retheming is edits in one file. - Light theme retinted; portrait dark theme adopts Catppuccin Macchiato. Splash banner is an SVG now. ### One sample dock - Sample List, Reference Tools, and the automation job list merge into a single dock with Dewar/Auxiliary tabs; the dewar table doubles as the queue view (queue buttons + Unmount beneath it, membership via right-click or dragging rows onto the Queued/Flagged chips). - Frozen #+status column with priority tints (mounted > queued > flagged > measured); status chip filters; non-staff see Auxiliary greyed out with a staff-only popup instead of a vanishing dock. - Docks no longer float: a popout button opens an additional fully operational window (shared models); closing a pop-out just hides it. ### Guard rails - Wheel over spin boxes/sliders/combos only adjusts while the right mouse button is held; bare wheel always scrolls (motor protection). - Camera gains a clickable session badge and a baton gate: watching is free, operating clicks are blocked without the baton; losing the baton greys out and folds the control columns. - Beamline state bar: guarded per-tick updates keep hover cursors alive; closing a floating dock re-docks it instead of hiding it. ## Tests 26 new unit tests cover the behavior this PR adds: sample-status tint priority and chip filtering (incl. measured = rotation count > 1), the right-button wheel guard, PopoutWindow resize/close/title-bar behavior, chip drag-drop relabeling, and the console-log pop-out mirror. PR diff coverage 81% (gate 80%). ## CI All green: lint (ruff format + check, basedpyright diff gate), tests on py3.11/3.12/3.13 and all three beamline plugin variants, diff coverage above the 80% minimum. One src compat fix rode along: MLOutputModel.get_class_str is called positionally, since aarecommon releases disagree on the cls parameter.

Coverage report (automated)

Total line + branch coverage: 46%
Diff coverage vs main: 82% (minimum 80%)

Full report: coverage artifact on this run.

Coverage report (automated) Total line + branch coverage: 46% Diff coverage vs main: 82% (minimum 80%) Full report: coverage artifact on this run.
duan_j marked the pull request as work in progress 2026-08-06 15:23:46 +02:00
Author
Owner
image.png

It looks like this now...color and style will be improved overtime, but decluttered a lot of outlines and re-arranged tabs...

<img width="1735" alt="image.png" src="attachments/f2b87380-7d19-4763-9a14-c5f59dccdc24"> It looks like this now...color and style will be improved overtime, but decluttered a lot of outlines and re-arranged tabs...
1.2 MiB
duan_j added 57 commits 2026-08-11 10:42:12 +02:00
The window's minimum was 1400x1207 - taller than a 1920x1200 console -
so the status bar was pushed off-screen on every monitor. Three causes:

- the standard page's combined panel minimums: now wrapped in a
  QScrollArea so scrollbars appear instead of clamping the window
- hidden portrait/compact stack pages inflating the QStackedWidget
  minimum (portrait alone demands 720px height): only the visible
  page contributes now
- launching at the natural size hint (1577x1612): launch maximized
  so the window takes whatever the monitor offers

Minimum drops to 1400x555; verified on a 1920x1200 X display that the
status bar is visible and panels scroll when space runs out.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TitleLabel gains an optional collapsible mode: whole-banner click target,
bare +/- glyph (no pill background), per-title collapsed state persisted
in QSettings, and an expand() helper. Banners are halved to 25px with
plain text + QSS font (H3 margins would clip vertically).

- convert Zoom, Light, Omega, Smargon, Sample camera, Monochromator,
  ABR meas. pos., Beam mark, Beam center, Beam size, Dataset path and
  Loop centering to collapsible banners
- new collapsible Exp. Config. section wrapping the scan tabs
- move Manual sample from a bottom dock into the left column between
  Dataset path and Exp. Config.; Ctrl+M now expands it instead of
  raising the dock
- Beamline state banner restyled to match (25px, plain font, bare
  glyph, whole banner clickable)
- universal 11px banner gap via tighten_column() shared by both panel
  columns and the left column stack; ABR banner spans all grid columns
  and file path / manual sample drop side margins so widths align
- abort button sits under the tabs instead of pinned to the bottom
- unit tests for the collapse behavior

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ruff format and import ordering (main_window, data_collection_settings,
  beam_center_panel, beamline_state_panel)
- rename unused unpacked variable in test_title_label
- replace the mousePressEvent monkeypatch on the beamline state title
  with a proper eventFilter so basedpyright accepts the diff

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QLayout.itemAt/QWidget.layout return Optionals; pyright cannot narrow
across repeated method calls, so hold them in locals before use in
tighten_column, _apply_collapsed and _set_visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A fresh GUI shows only the banners; the Beamline state panel keeps its
own expanded default. A user's saved per-title states still override.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- drop the redundant Local Contact banner (the window title carries it)
- remove the three parent=self config spinboxes that painted themselves
  over the top-left corner; parentless placeholders are replaced in
  _build_config_tab
- remove all rounded corners (status card, value badges, group boxes,
  transfer-error frame, recovery panels)
- tighten status rows to 2px spacing with a per-row minimum height so
  word-wrapped value labels can never compress rows until text clips
  (previously visible on the Hardware tab)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the vertical station map that consumed left-column space with a
slim always-visible strip in the bottom toolbar area, directly above the
status bar:

- states in physical beamline order, 18px text, one line when the bar is
  wide enough and wrapped at the last space otherwise
- availability coloring from the route graph plus the status-bar shortcut
  transitions: bold blue = active (red for Maintenance), orange =
  reachable in one step, grey = not reachable; no backgrounds or rounded
  corners
- transitions only via right-click 'Go to <state>'; left click shows a
  reminder tip for available states and the reachability explanation for
  grey ones; hovering a grey state for 3 s shows the same explanation
- whole entry is the hover/click region; tips anchor to the entry and
  disappear when the mouse leaves
- always visible: no View-menu toggle, not hidden by portrait or compact
  modes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dialog's explicit minimum size is smaller than some tabs' content;
without a scroll area Qt squeezes rows below text height (clipped labels
on the Hardware tab). Wrap every tab in a QScrollArea.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Availability sets (routes + menu shortcuts, Moving/unknown), signal
gating, palette and cursors per availability, red/blue active states,
adaptive label wrapping, left-click hint paths, hover-hint timer
lifecycle, and pending-target clearing. Lifts the PR diff coverage back
over the 80 percent gate (measured 88 percent locally).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dynamic _beamline_state assignment was a pre-existing pattern, but
the panel rewrite turned its line into a changed line, so the
basedpyright diff gate now counts it. Declare the attribute instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every color literal in the GUI moves into one palette module: ~200
grouped constants, a qcolor() helper (hue from the theme, alpha at the
call site), and both QSS stylesheets become string.Templates fed by
_palette() so a renamed constant fails loudly. Also retints: light
background #d8e4fd -> #e2e7ee, banner indigo -> #a2b7e4, and the
portrait dark theme adopts Catppuccin Macchiato.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mechanical swap of hardcoded color literals for styles.py constants and
qcolor() across panels, models, and scan_logic. portrait_mode.py drops
its private palette block; beamline_controls and data_collection_settings
gain object names so the new $border QSS rules can target them. The
status-panel test asserts the palette hex instead of 'red'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same mechanical swap for the widgets and the tutorial manager: painter
QColors go through qcolor(), inline QSS literals become palette
constants (baton dialog, busy overlay, status bar, camera overlays,
splash screen, numeric inputs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The QSS gains a role-named font-size ladder (FONT_HERO..FONT_FINE),
borderless QToolTip styling for both themes, soft rounded scrollbars
without end arrows, and a card_style() helper with one shared
CARD_RADIUS so card-shaped frames keep uniform geometry. Banner text
flips to near-white with a shadow constant for the painted emboss.
Recovery-card and console-log colors are marked TODO for a later
retheme.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Inline font-size literals become FONT_* tokens and hand-written card
QSS collapses into card_style() (recovery cards and console-log
notifications keep FLAT_CARD_RADIUS). TitleLabel paints its text by
hand — QSS has no text-shadow — for an embossed banner title, elided
when narrow, and gains a section_title() helper for small in-panel
headings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The three small beam panels shared a column with three collapsible
banners; BeamConfigPanel puts them under a single collapsible
'Beam Config.' TitleLabel with section_title() sub-headings.
beam_mark/beam_center/beam_size stay as aliases on BeamlineControls so
main_window signal wiring is untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three main-window chrome fixes: the un-maximized geometry is pre-set to
half-screen centered so leaving maximized mode no longer restores an
oversized size hint (the beamline state bar also stops imposing its
~2000px minimum width); closing a popped-out dock re-docks it instead
of silently hiding the panel, and pop-outs open enlarged and clamped to
the screen; state-bar buttons only update font/stylesheet/cursor when
values change, since repolishing every DAQ tick dropped the hover
cursor under a resting mouse.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The PNG banner is replaced by an SVG so the splash artwork scales; the
old aare_banner.png is removed and gui.py loads the .svg path (the
stale path yielded a null splash pixmap).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SELECTION_BG/TEXT pin the app-wide selection blue to the banner color
(was Qt's undeclared palette default); FRAME_L1/L2/L3 knobs put window,
panel, and data-view borders on three tunable levels (panel etching off
by default); QTabBar tabs and filter chips go borderless with a hover
underline; QSlider matches the scrollbar look; scrollbar tracks turn
square with a track-colored corner; SAMPLE_STATUS_* and
SAMPLE_ROW_ALT_BG drive the sample-table status tints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TitleLabel gains default_collapsed; the small motor/light panels start
open (their per-title persisted choice still wins).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WheelValueGuard (app-level event filter, installed by MainWindow) makes
a bare wheel over spin boxes, sliders, dials, and combos scroll the
enclosing scroll area instead of nudging the value - motor protection.
NoWheelScrollArea stops swallowing wheel events since values are now
guarded at the widget.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Floating a dock rips it from the row and reshuffles the rest, so
PopoutWindow opens an ADDITIONAL frameless top-level window instead:
12px outer resize halo (border painted OUTER_GRIP inside the real edge
so an outside-looking grab still works), hand-painted borderless
titlebar glyphs, close hides and keeps geometry. DockTitleBar puts the
popout button next to the close box. The console log adopts it: dock
floating disabled, the pop-out view is a second QPlainTextEdit fed by
the same emitter (a shared QTextDocument would make two views fight
over one layout), clear() clears both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Vertical-space pass: samcam merges exposure+gain onto one row, ABR and
monochromator tighten their grids (energy now displayed in keV, DAQ API
stays eV), beam-mark's clear button shares the readings row, the data
collection pages move Run/Abort under the last configurable row and the
tab area becomes QTabBar+QStackedWidget, the raster grid table gets a
fixed height, and the automation panel drops its own title since the
dock title bar already says it. Control panels start expanded via
default_collapsed=False.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The camera overlay gains a clickable session badge (opens the session
menu at the click position) and a baton gate: watching stays free,
operating clicks are blocked when the baton is elsewhere. The legend
collapses to a ? badge until clicked - the full box covered too much
image.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reference Tools was a separate staff-only dock tabified behind Sample
List and kept vanishing (saved dock state, raise order); the automation
job list was a third dock for what is conceptually the same table. One
tabbed dock now holds Dewar samples + Auxiliary puck (concept from
aaregui2's QueuePanel): the dewar table doubles as the queue view with
the queue buttons and an Unmount button in a row beneath it,
SampleQueuePanel lives on hidden as the queue engine, and queue/flag
membership is edited via right-click or row drags onto the Queued and
Flagged chips. Column 0 is a frozen #+status cell (mounted > queued >
flagged > measured, tints context-dependent per chip filter); non-staff
see Auxiliary greyed out with a Staff-only popup instead of hidden.
Ctrl+L/Ctrl+R raise the Dewar/Auxiliary tab. The Sample List and log
pop-outs are fully operational second views on shared models. Riders:
MainWindow installs WheelValueGuard, wires the camera session badge,
and moves samcam/monochromator/ABR/beam-config into the left column's
Beamline group (BeamlineControls keeps only zoom/light/omega/smargon).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The frozen #+status column shifted data columns +1, so the User-column
model tests move from index 5 to 6; ruff import-sort fixes for
main_window and log_panel ride along.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Declare MainWindow's lazily-set attributes, guard Optional layouts and
the sample tab bar, wrap QSettings reads (typed object even with
type=...), include _press_geom in the pop-out resize guard, and ignore
the PySide6 stub gap on setGraphicsEffect(None).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sandbox port was ruff-check clean but not ruff-format clean (CI
formats before linting); splash_screen's alignment flags move to the
scoped enum since the port put that line into the diff gate's scope.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sample-name labels are created in __init__ now (the build helper
only styles and mounts them) so reportUninitializedInstanceVariable
stops firing on the ported styling lines, and the queue placeholder
uses the scoped Qt.AlignmentFlag.AlignCenter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New tests for what the port added: status tint priority and
context-dependent chip filters on the dewar/queue model, the
right-button wheel guard (motor protection), PopoutWindow edge maths,
manual-resize fallback, close-hides behavior and DockTitleBar, the
chip drag-drop relabeling, and the console-log pop-out mirror. The
widgets' __main__ self-checks are superseded by these and removed.
Brings PR diff coverage from 70% to 81% (gate: 80%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Optional _popout_view is assert-narrowed once after opening; the
unguarded accesses were the last three diff-gate violations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both stylesheets move to transparent children over a gradient painted
only by top-level windows; inputs, buttons, headers, and menus get
opaque faces back. Sunset drops Catppuccin Macchiato for the Daemmerung
dusk palette. Spin/combo arrows and check indicators become theme-tinted
PNGs. Widgets stop carrying inline input/text stylesheets so the theme
QSS can win (empty stylesheet = theme reset).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The panel paints availability/message colors in code per DAQ tick, so
QSS can't retint it — state_colors(theme) hands it a per-theme dict
(Catppuccin Mocha inks for Sunset) and _apply_theme pushes theme flips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Freeze the old look in a click-through screenshot overlay and fade it
out over the restyled window — QSS has no transitions and animating the
palette would re-polish every widget per frame. Sunset also flips the
app-palette text roles so native primitives QSS can't recolor (spin and
combo arrow glyphs) follow the theme.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QSS cannot set cursors and per-widget setCursor calls get forgotten as
widgets are added, so an app-level filter catches every Polish event on
buttons, combos, and sliders — dialogs and pop-outs included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Separators stay invisible until the mouse rests on one for ~1s (or a
drag starts); the QSS ::separator:hover rule does the hit-testing and a
dynamic separatorHint property gates it, so event() never needs to know
where separators are.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Without the baton the GUI now shows only the camera stream and status
bar; every operating surface (panels, docks, pop-out mirrors) is hidden
outright. Regaining the baton restores dock layout via saveState/
restoreState — per-dock visibility snapshots lose docks tabbed behind
others — so LogDock gains the objectName restoreState requires.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A transparent top-level renders black on the container's non-composited
X11, so floating docks get a dynamic floating property feeding the
QSS [floating="true"] opaque face, and PopoutWindow sets
WA_StyledBackground. Pop-out titlebar glyphs are now painted in the
palette's WindowText color and re-tint on PaletteChange, so they stay
visible after a theme flip.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Legacy/Portrait themes become Sunrise (default)/Sunset. Automation View
and Portrait (now Playlist) Mode leave the menubar for the View menu
with in-progress labels; Return to Main View stays top-level since it
only shows inside the automation view.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Energy unit moves from spinbox suffix to the label (the suffix ate
field width next to the new spin arrows); samcam exposure/gain get a
3:2 stretch so 3-decimal exposure isn't cut; the Exp. Config. tab bar
gets a BANNER_TAB_GAP spacer under its banner.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The warm glow at the bottom of the dusk sky didn't fit — stay in the
blue range.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Narrow QApplication.instance() before use, wrap the theme QSettings
read in str(), hand QPropertyAnimation a real QByteArray, and declare
the lazily-set watch-mode attributes on the class.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sunrise/sunset replace the original/portrait tokens (QSettings values
migrate on restore); bluebird is sunrise with a flat sky. The light
palette is repainted with Catppuccin Latte across alerts, chips, cards,
log, splash, inputs, and status flags, plus button/input height caps
and hover rules in the QSS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The controls cheatsheet gets its own help badge/overlay instead of
riding the detection legend; the camera-unavailable state now draws the
actual error reason bottom-center (pushed from MainWindow to all three
camera views); the session badge shows hover feedback and the vacant
overlay reads 'In viewing mode' with a grab-baton hint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A window state saved during the watch-only fold restores as every dock
hidden (the vanished-Sample-List-on-restart bug). Fall back to the
default layout when a restore comes back all-hidden, and put the
pre-watch layout back before saving state in closeEvent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
load_spreadsheet/load_reference_tools log a GET they never send every
~12.5s poll while base_url is None; fix later by demoting to debug or
logging once on the None->set edge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The diff-vs-main basedpyright gate flags QRect(self._press_geom) because
only _press_global was narrowed; both are set together in
mousePressEvent, so the extra check is a no-op at runtime.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copied from aare_banner_w.svg; the black glyphs vanished on the dark
splash panel, the white fills read on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diff coverage vs main was 77%, under the 80% CI gate; the new camera
help/error/badge code and the theme+layout main_window paths were the
uncovered bulk. Locally: 82%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two tabified bottom docks left their switcher tabs stranded at the
window bottom; one Information dock with proper tabs mirrors the Sample
List dock's layout. LogDock becomes the LogPanel widget with mirror
views for the pop-out and a reveal_requested signal so the owner
controls visibility (Ctrl+Shift+L, notifications).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Banners in the root layout shifted the whole UI on every message; now
they float over the content root (repositioned on resize) and the baton
toast anchors as a compact pill under the camera view, auto-clearing in
4s instead of 10s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
draw_busy_badge in busy_overlay renders the title+subtext pill once;
the sample camera and axis video overlays both delegate to it instead
of keeping diverging copies. The axis panel's dot+label status pill and
its per-theme QSS go away with it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Status-bar flags get status_colors(theme) (Mocha variants on Sunset) via
a new set_theme; sample tables stop hard-filling rows WHITE and pin dark
ink on tinted rows via ForegroundRole; dewar tab and log panel get solid
dark surfaces (transparent renders black on the non-composited X11
container); developer help cards go square for the same reason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reference table gets a display-only '#' column (like the Dewar
list) with sort indices shifted around it; the sample dock switches to
the Auxiliary puck tab on entering alignment/maintenance states and
back to Dewar elsewhere, only on state transitions so a manual choice
sticks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
style: visual and interaction polish
CI / test (3.11) (pull_request) Successful in 1m23s
CI / test (3.12) (pull_request) Successful in 1m22s
CI / test (3.13) (pull_request) Successful in 1m21s
CI / test-with-beamline-plugins (pxii_bec) (pull_request) Successful in 1m26s
CI / test-with-beamline-plugins (pxi_bec) (pull_request) Successful in 1m42s
CI / test-with-beamline-plugins (pxiii_bec) (pull_request) Successful in 1m40s
CI / test-with-coverage (pull_request) Successful in 2m2s
CI / coverage-analysis (pull_request) Successful in 4s
CI / lint (pull_request) Successful in 2m37s
CI / lint (push) Successful in 29s
Docs build and publish / docker (push) Successful in 12s
CI / test (3.11) (push) Canceled after 34s
CI / test (3.12) (push) Canceled after 30s
CI / test (3.13) (push) Canceled after 29s
CI / test-with-beamline-plugins (pxi_bec) (push) Canceled after 25s
CI / test-with-coverage (push) Canceled after 19s
CI / test-with-beamline-plugins (pxii_bec) (push) Canceled after 24s
CI / test-with-beamline-plugins (pxiii_bec) (push) Canceled after 20s
CI / coverage-analysis (push) Canceled after 0s
Build and Publish / release (push) Failing after 5s
833a6d136f
Windowed startup at 50%x70% instead of maximized; overlay legend now
defaults off (it covers the camera image); square slider handles with
grip-line PNG assets (the round handle clipped flat); warmer sunrise
gradient bottom; abr/beam-mark layout tweaks; hover cues on the
beamline-state entries; DPI/font-aware pop-out titlebar icons; the
out-of-date Tutorial menu entries are hidden until content is redone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
duan_j force-pushed collapsable-and-adaptive from 4d845aa568 to 833a6d136f 2026-08-11 10:42:12 +02:00 Compare
duan_j marked the pull request as ready for review 2026-08-11 11:01:48 +02:00
duan_j merged commit 833a6d136f into main 2026-08-11 11:02:31 +02:00
Sign in to join this conversation.