From b5e6159118d9d4067b779fc3e43eb4e4c1f9dc84 Mon Sep 17 00:00:00 2001 From: Dawn Date: Fri, 18 Sep 2026 09:14:31 +0200 Subject: [PATCH] fix(gui): add "Show beam crosshair" toggle to the camera right-click menu Right-clicking the sample camera now offers a checkable "Show beam crosshair" entry. When on, two full-frame lines through the beam center are drawn with the same pen as the beam box, so the crosshair follows the beam state color. Off by default so the view stays as before. Co-Authored-By: Claude Fable 5.1 --- src/aare/gui/widgets/camera_image.py | 15 +++++++++++++++ tests/unit/gui/test_camera_image.py | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/aare/gui/widgets/camera_image.py b/src/aare/gui/widgets/camera_image.py index dc3b42b2..93c820b9 100644 --- a/src/aare/gui/widgets/camera_image.py +++ b/src/aare/gui/widgets/camera_image.py @@ -139,6 +139,9 @@ class SampleCameraImageLabel(QGraphicsView): # toggle can still switch back to 1:1. self._autoscale = True self._show_coords = False + # Full-frame crosshair through the beam center; off by default so the + # default view stays as before, toggled from the right-click menu. + self._show_beam_crosshair = False self._helical_start = SmargonCoordinate() self._helical_end = SmargonCoordinate() self._raster_alpha = 127 @@ -682,6 +685,9 @@ class SampleCameraImageLabel(QGraphicsView): autofocus_action = menu.addAction("Auto-focus") beam_mark_action = menu.addAction("Mark beam center") + crosshair_action = menu.addAction("Show beam crosshair") + crosshair_action.setCheckable(True) + crosshair_action.setChecked(self._show_beam_crosshair) delete_action = None evaluate_action = None @@ -730,6 +736,8 @@ class SampleCameraImageLabel(QGraphicsView): elif action == beam_mark_action: c = self.mapToScene(event.pos()) self.update_beam_mark.emit(c.x(), c.y()) + elif action == crosshair_action: + self._show_beam_crosshair = not self._show_beam_crosshair self.update() def _screenshot_with_dialog(self, overlay: bool): @@ -1446,6 +1454,13 @@ class SampleCameraImageLabel(QGraphicsView): int(beam_size_pxl.y), ) ) + if self._show_beam_crosshair: + # Same pen as the box so the crosshair follows the beam state color. + r = self.sceneRect() + cx = int(self._geom.beam_location_pxl.x) + cy = int(self._geom.beam_location_pxl.y) + painter.drawLine(int(r.left()), cy, int(r.right()), cy) + painter.drawLine(cx, int(r.top()), cx, int(r.bottom())) @staticmethod def _draw_circle(painter, coord: Coordinate, color: QColor, radius=10): diff --git a/tests/unit/gui/test_camera_image.py b/tests/unit/gui/test_camera_image.py index 51ff331a..428129ba 100644 --- a/tests/unit/gui/test_camera_image.py +++ b/tests/unit/gui/test_camera_image.py @@ -334,3 +334,27 @@ def test_mounted_hud_ink_follows_theme(camera): assert camera._mounted_hud_ink() == (SHADOW, WHITE) camera.set_theme(THEME_SUNSET) assert camera._mounted_hud_ink() == (WHITE, SHADOW) + + +def test_beam_crosshair_toggle_draws(camera, monkeypatch): + from PySide6.QtWidgets import QMenu + + assert camera._show_beam_crosshair is False + # Pick the crosshair action out of the real menu instead of exec'ing it. + monkeypatch.setattr( + QMenu, + "exec_", + lambda self, *_: next(a for a in self.actions() if a.text() == "Show beam crosshair"), + ) + camera._camera_interaction_enabled = lambda: True + press = QMouseEvent( + QEvent.Type.MouseButtonPress, + QPointF(10, 10), + QPointF(camera.mapToGlobal(QPoint(10, 10))), + Qt.MouseButton.RightButton, + Qt.MouseButton.RightButton, + Qt.KeyboardModifier.NoModifier, + ) + camera._right_click_menu(press) + assert camera._show_beam_crosshair is True + camera.grab() # exercises the crosshair draw path