WIP: resizable camera region, menu panel collapse, zoom ladder

- center splitter: left controls | camera tabs | beamline column;
  drag resizes the camera width, View menu check actions collapse
  the fixed-width side panels (no on-screen buttons)
- font zoom restricted to a 100/125/150 percent ladder; the
  fixed-width side boxes scale with it so zoomed text does not clip
- camera tab widget min width clamped to 1/3 of its natural minimum
- resize bars: short centered grip PNGs shared by QMainWindow
  separators and QSplitter handles, single style source in styles.py
- window min width 1244 -> ~376: automation row and sample-list
  chip row stop propagating their natural minimums (Ignored-width
  hosts), portrait page fixed width removed (portrait mode pins the
  window width itself)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
duan_jandClaude Fable 5 authored and duan_j committed 2026-09-16 13:28:16 +02:00
1 parent 30151b4441
commit fd0edffdc9
12 files changed
+173 -88

No files matched your search

+29 -6
View File
@@ -72,6 +72,21 @@ def test_main_window_init(qtbot, mock_ui_state, daq_status_factory):
win.data_collection._emit_change_energy()
assert sent and abs(sent[0] - 12400.0) < 1e-6
# Side panels collapse from the View menu (no on-screen buttons), and
# the camera region sits in a splitter so its width is drag-resizable.
assert win.center_splitter.widget(1) is win.video_tab
# The clamp lets the splitter shrink the camera region well below the
# natural minimum the tab labels + controls rows would demand.
assert 0 < win.video_tab.minimumWidth() < win.video_tab.minimumSizeHint().width()
win._show_left_panel_action.trigger()
assert win.collection_controls_scroll.isHidden()
win._show_left_panel_action.trigger()
assert not win.collection_controls_scroll.isHidden()
win._show_right_panel_action.trigger()
assert win.beamline_controls_scroll.isHidden()
win._show_right_panel_action.trigger()
assert not win.beamline_controls_scroll.isHidden()
# Motion watch: only the robot station switches to the combined
# beamline view. Moving no longer does (users kept losing the sample
# camera on short gonio moves), and busy alone never does — Sample
@@ -525,20 +540,28 @@ def test_font_zoom_steps_clamps_and_resets(qtbot, mock_ui_state):
try:
base_pt = win._default_app_font.pointSizeF()
win._change_font_zoom(1)
assert styles.font_scale() == pytest.approx(1.1)
assert styles.font_scale() == pytest.approx(1.25)
# Part 2 of the zoom: the app default font scales with the ladder.
app = QApplication.instance()
assert isinstance(app, QApplication) # narrow from QCoreApplication|None
assert app.font().pointSizeF() == pytest.approx(base_pt * 1.1)
for _ in range(20):
assert app.font().pointSizeF() == pytest.approx(base_pt * 1.25)
# Part 3: the fixed-width side boxes follow the ladder, else the
# zoomed text clips inside them.
assert win.data_collection.minimumWidth() == round(win.data_collection.set_width * 1.25)
assert win.collection_controls_scroll.maximumWidth() == (
round(win.data_collection.set_width * 1.25) + 10
)
assert win.beamline.minimumWidth() == round(win.beamline.set_width * 1.25)
for _ in range(5):
win._change_font_zoom(1)
assert styles.font_scale() == styles.FONT_SCALE_MAX
assert styles.font_scale() == styles.FONT_SCALE_LADDER[-1]
win._change_font_zoom(0)
assert styles.font_scale() == 1.0
assert app.font().pointSizeF() == pytest.approx(base_pt)
for _ in range(20):
assert win.data_collection.minimumWidth() == win.data_collection.set_width
for _ in range(5):
win._change_font_zoom(-1)
assert styles.font_scale() == styles.FONT_SCALE_MIN
assert styles.font_scale() == styles.FONT_SCALE_LADDER[0] # floor is 100%
finally:
styles.set_font_scale(1.0)
if saved is None: