From b58c23d0f65207a6ed15489fbcdeaa04acc2265a Mon Sep 17 00:00:00 2001 From: Dawn Date: Mon, 17 Aug 2026 16:49:30 +0200 Subject: [PATCH] feat: sample camera starts in scale-to-fit _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 --- src/aare/gui/widgets/camera_image.py | 10 +++++++++- tests/unit/gui/test_camera_image.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/aare/gui/widgets/camera_image.py b/src/aare/gui/widgets/camera_image.py index e828e842..423a3bb5 100644 --- a/src/aare/gui/widgets/camera_image.py +++ b/src/aare/gui/widgets/camera_image.py @@ -133,7 +133,9 @@ class SampleCameraImageLabel(QGraphicsView): self._geom = geom self._bookmarks: SmargonBookmarkList = SmargonBookmarkList() - self._autoscale = False + # Fit-to-view from the first frame; the right-click "Scale to fit" + # toggle can still switch back to 1:1. + self._autoscale = True self._show_coords = False self._helical_start = SmargonCoordinate() self._helical_end = SmargonCoordinate() @@ -776,12 +778,18 @@ class SampleCameraImageLabel(QGraphicsView): @Slot(QPixmap) def update_pixmap(self, pixmap: QPixmap): + size_changed = self.pixmap_item is None or self.pixmap_item.pixmap().size() != pixmap.size() if self.pixmap_item is not None: # Ensure pixmap_item exists self.pixmap_item.setPixmap(pixmap) # Update the pixmap in the item else: # If no pixmap item exists (rare case), create one self.pixmap_item = QGraphicsPixmapItem(pixmap) self.scene.addItem(self.pixmap_item) + if size_changed and self._autoscale: + # Refit when the frame size differs from what was fitted (real + # stream resolution vs the 2000x2000 startup placeholder, or a + # camera source switch) — resizeEvent only refits on view resize. + self._scaling() self.viewport().update() # Request an update to redraw the view @Slot(DAQStatusModel) diff --git a/tests/unit/gui/test_camera_image.py b/tests/unit/gui/test_camera_image.py index a5836b95..4730fb6e 100644 --- a/tests/unit/gui/test_camera_image.py +++ b/tests/unit/gui/test_camera_image.py @@ -209,3 +209,19 @@ def test_alt_wheel_axis_swap_still_changes_exposure(camera): n = len(sent) camera.wheelEvent(_wheel(camera)) # zero delta: ignored assert len(sent) == n + + +def test_autoscale_fits_from_the_first_frame(camera): + from PySide6.QtGui import QPixmap + + # Fit-to-view is the default; a frame whose size differs from the fitted + # one (here: the 2000x2000 startup placeholder) must refit immediately, + # not wait for the next view resize. + assert camera._autoscale + camera.update_pixmap(QPixmap(4000, 4000)) + assert camera.transform().m11() < 1.0 + + # The right-click toggle still restores 1:1. + camera._autoscale = False + camera._scaling() + assert camera.transform().isIdentity()