Busy in Sample alignment IS the alignment (centring moves) - yanking
the view away to the combined beamline tab hid exactly what the user
was doing. The motion-watch switch now skips that state; robot
exchange and other busy transitions still switch as before.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_autoscale now defaults on, so the view fits from the first layout
(the constructor's placeholder already carries the camera size and
resizeEvent refits on every resize). update_pixmap additionally
refits when the frame size changes - the real stream resolution can
differ from the placeholder, and only a view resize refit before.
Right-click 'Scale to fit' still toggles back to 1:1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Run/Remove selected/Clear list act on the queue, whose order only the
Queued chip view shows - in other views they are greyed out with a
tooltip pointing at the chip. Run stays enabled while automation runs
so pausing is always possible. Applies to the docked trio and the
pop-out clones alike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The queue engine keeps insertion order and Run pops its head, but the
Queued view sorted by the dewar table's header sort - the top row was
not what runs next. set_queued_ids now keeps the order it is fed (the
queue model's order) and the Queued view displays exactly that; header
clicks no longer reorder it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mirrors the Beamline setup live readout above Set Energy, fed by the
same DAQ tick with the zero-energy guard and repaint skip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
basedpyright disables mypy-style 'type: ignore' comments by default, so
the diff-quality gate still counted the violation; match the existing
'pyright: ignore[reportArgumentType]' convention from main_window.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Status flag on the left (same rich-text scheme as the status bar,
theme-aware via set_theme), Open/Close buttons on the right, wired
to the same daq.open_shutter/close_shutter slots staff-gated in
main_window.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The '?' badge moved to the top middle but the cheat sheet still
opened bottom-left, sending the mouse across the view to close it.
The overlay now drops in where the badge was.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The status column holds no sortable data, so its header click slot
was free: it now does Ctrl+A, pairing with the Unmeasured chip to
grab everything still to be done in one motion. The sort indicator
is put back afterwards - the click drags it onto '#' even though
the model ignores sorting there.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Confirmed by Dawn: any rotation data counts as measured; unmeasured
is exactly rotation count 0. The old > 1 rule left single-rotation
samples looking like still-to-do work in the Unmeasured view.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The '?' badge sat in a corner, which drifts oddly when the view is
scaled to fit; the top middle stays put and out of the sample's way.
Transparency unchanged - visible enough to find, not disturbing.
'More... (F1)' moves to the overlay's right edge, reading like a
dialog's action button.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Unmeasured and All are both 'what is left' views; the hand-applied
labels (Queued/Flagged/Measured) follow. The 1px spacing keeps the
chips readable as separate buttons instead of one solid bar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beam-path order in the status bar: the hutch shutter sits upstream
of the fast shutter, so it reads left to right along the beam.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New 'Current energy / lambda' row above the setpoint, fed per DAQ
tick from diffraction.energy_keV; the setpoint row is renamed
'Set Energy (keV)' so 'what is' and 'what to set' are distinct.
Guards energy 0.0 (server's detector-unavailable fallback) because
the wavelength property divides by it. The copied energy row in the
experiment configuration is renamed to match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Below Mount/Unmount, acting on the selection like the queue actions.
Flagging happens by dropping rows on the Flagged chip; until now
there was no way back. Disabled when nothing in the selection is
flagged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Complement of Measured (rotation count <= 1): one click shows
everything still to be done, so it can be selected wholesale and
queued. Plain chip like All - unmeasured rows carry no tint, so
there is no legend color to wear; cross-status marks (queued/
flagged) show like in the Measured view.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both bottom-dock tables now list mount -> raster -> screening ->
rotation, the order the work actually happens in. In the Auxiliary
table the swap also fixes a real bug: data() feeds get_entry
header-index-minus-1, but rotation/raster were crossed against the
header, so 'Raster count' displayed rotation counts and vice versa.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BEAMLINE BUSY and the robot warnings now hop per letter (clipped sine)
so they read as an in-progress signal, not a frozen label. Gated by a
new BusyOverlayStyle.animate flag: 'In viewing mode' stays static
because it is a passive notice. No timer - the phase rides the wall
clock and repaints ride the ~20 fps camera frames, so the wave freezes
with a stalled feed (which has its own error surface).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
While Moving, the target state sat solid blue and read as already
reached. An opacity pulse (QGraphicsOpacityEffect + QPropertyAnimation)
marks it as in progress; a stylesheet animation would repolish the
button every frame, which the guarded updates in _apply_highlight
exist to avoid.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-window installs of the two QApplication-level filters (cursor,
wheel guard) stacked one stale copy per MainWindow; now installed once
per process, parented to the app. closeEvent overrides in the baton
dialogs replaced by finished.connect(timer.stop); keyPressEvent in
VideoGraphicsView replaced by WidgetShortcut QShortcuts; hover
enter/leave overrides in PlayPauseButton replaced by underMouse();
ValueLabel inherits ClickableLabel instead of duplicating its
mousePressEvent. Dead raster-timer branch and a PyQt5-era
event-position fallback deleted; redundant try/except and getattr
guards dropped now that class-level defaults cover pre-init reads.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The locked-banner and Beamline-tab-bar filters were installed mid
__init__, but MainWindow.eventFilter reads sample_lists_tabs, which is
created later - every event delivered in between raised AttributeError
inside the filter ('Error calling Python override of eventFilter()'
spam) and broke widget teardown, cascading errors across CI tests and
wedging the pxiii_bec job. Filters now install late, next to
installEventFilter(self), and the filter guards its attribute reads so
construction/teardown-time events can never raise.
Also fold the staff-gate assertions into test_main_window_init: every
extra MainWindow construction raises the odds of the pre-existing
PySide SystemError flake, so don't build a window just for them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-test lines and live (uncaptured) output: the pxiii_bec job sat
silent at 81 percent for hours, and file-level dots could not say which
test wedged. With -s -vv a hang names its test and streams the last
log lines before it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diff coverage vs main now 100 percent from the gui suite alone:
non-staff locked banners and both gated-tab popups, remote-close
bookkeeping in update_daq_status, smargon staged moves, camera More
link and Alt-wheel axis fallback, number box relimits, energy row
emit, and the gui.main() banner/graceful-exit path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two changes folded together because they touch the same status path:
- Revert the login-default state POST: a state transition can move
motors, and merely opening the GUI must never move hardware. The GUI
now adopts whatever state the server reports.
- A click on the pgroup-gated (disabled) Beamline tab used to be eaten
silently by the tab bar. An event filter now pops the explanation:
visitor-pgroup wording for staff, the staff-only message for users
(same pattern as the Auxiliary-puck tab).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Promote the illumination panel's __main__ self-check to a real pytest
file so CI counts it, add busy-overlay render checks (status text
paints, video view routes through it), and cover the motor group's
incomplete-entry and below-min Enter paths. Local diff coverage from
the gui suite alone: 82 percent.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rename NumberLineEdit.validator to range_validator: the instance attr
shadowed QLineEdit.validator() and broke type checking at call sites.
Annotate the smargon _move_axes dict and cast the stand-in self in the
prediction subscriber test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ruff format collapsed lines the Beamline setup rename and other edits
left splittable; SIM201 wanted != over 'not ... ==' in the prediction
subscriber's JSON sniff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generalize the robot-mount auto-switch: any busy period now brings up
the combined view so the motion can be watched, and the sample camera
returns when busy clears. Edge-triggered, so manual tab choices
survive between transitions; _mounting renamed to _watching_motion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Busy now empties the available-target set exactly like Moving, so no
entry looks clickable and no transition can be posted mid-operation
(same guard the status-bar menu already had). The current/pending
entry keeps its highlight as orientation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Gonio camera, Beamline view and the combined view showed BEAMLINE BUSY
in the rounded badge pill, which reads as a clickable button. These
views are passive, so draw the same shadowed colored text the sample
camera uses for its warnings; the pill stays only on the sample-camera
session badges, which really are click targets.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Panel title case now matches the other banner names. Also clarify the
splash banner comment in gui.py.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beamline setup, ABR meas. pos. and Beam configuration banners stay
visible for non-staff instead of vanishing, but are locked stand-ins:
clicking one pops the staff-only notice (same pattern as the
Auxiliary-puck tab) telling the user to log in as staff or contact
their local contact.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Staff land in BeamLocation, users in SampleAlignment. One-shot on the
first status tick where the GUI owns the session and the beamline is
idle, so a running operation or a watch-only GUI is never disturbed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Switching to a visitor pgroup means running a user experiment: grey out
the Beamline tab (tooltip: beamline scientists only), bring the
Experiment tab forward with Dataset path and Exp. Config. opened.
Gate applies on transitions only so manual tab choices survive the
1 Hz status ticks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Sliders only emitted on sliderReleased, so right-click+wheel, arrow keys
and groove clicks changed the value locally without a PUT and the 500 ms
status poll snapped it back. setTracking(False) + valueChanged now sends
one PUT per deliberate change; readback setValue is wrapped in
blockSignals to avoid echoing PUTs, and a 1.5 s grace window stops
in-flight stale status responses from bouncing the slider.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Display title only; class and file keep their names. New full-width
'Move Beam to Box (center) (WIP)' button under the Energy row, disabled
with a coming-soon tooltip until a DAQ endpoint exists.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copy of the Beamline Setup energy row (keV display, eV emit), placed
below the ML Loop Centring / Make Raster Grid row and always visible.
Wired to the same daq.change_energy; not staff-gated, server enforces
write permission.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Move button gets its own full-width row instead of sharing row 1 with the
Chi/Phi entries; Step box spans columns 1-4 instead of the narrow Chi
column.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Value column was content-sized, so rows shifted whenever a value flipped
negative. Labels now reserve '-88.888' width; right alignment keeps digits
anchored. Also TODO: red colors on live aerotech while labels display
aerotech_meas - intent unconfirmed, do not change condition until decided.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Underlined 'More… (F1)' line at the bottom of the painted help box emits
open_full_help, wired to the existing Mouse / Keyboard Controls dialog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Chi/Phi boxes in the Smargon tab no longer move on Enter: edits stage
the target (orange), the Move button sends all staged axes at once
(green), and boxes return to neutral when the motor reports arrival.
Out-of-range entries stay red and are never sent; limit tips pop as
tooltips. MotorMoveGroup is opt-in per box so other panels can adopt
the same logic later.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Qt xcb/windows swap wheel axes while Alt is held, so angleDelta().y() is 0
and copysign(_, 0) is always positive. Fall back to angleDelta().x() and
ignore genuine zero deltas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
Sniff for '{' before JSON-parsing zmq parts: JPEG frames start with 0xff
and raised UnicodeDecodeError on every frame. Stop closing the socket
from the GUI thread in stop(): zmq sockets are not thread-safe and the
concurrent close/recv tripped the signaler.cpp POLLIN assertion (core
dump); run() closes it in its own thread via the 500ms RCVTIMEO.
uv.lock: sync version to 0.8.3.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>