From 257edc25f87a88d22a34b2410af47bfdb491eeea Mon Sep 17 00:00:00 2001 From: Dawn Date: Sat, 8 Aug 2026 15:08:18 +0200 Subject: [PATCH] feat: pointing-hand cursor on all interactive widgets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/aare/gui/main_window.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/aare/gui/main_window.py b/src/aare/gui/main_window.py index 516d680c..90e2521c 100644 --- a/src/aare/gui/main_window.py +++ b/src/aare/gui/main_window.py @@ -15,7 +15,7 @@ from aarecommon.models.models import ( SessionsStateEnum, TokenData, ) -from PySide6.QtCore import QEvent, QPropertyAnimation, QSettings, Qt, QTimer, Signal, Slot +from PySide6.QtCore import QEvent, QObject, QPropertyAnimation, QSettings, Qt, QTimer, Signal, Slot from PySide6.QtGui import ( QAction, QActionGroup, @@ -26,8 +26,10 @@ from PySide6.QtGui import ( QPalette, ) from PySide6.QtWidgets import ( + QAbstractButton, QApplication, QCheckBox, + QComboBox, QDockWidget, QFrame, QGraphicsColorizeEffect, @@ -39,6 +41,7 @@ from PySide6.QtWidgets import ( QPushButton, QScrollArea, QSizePolicy, + QSlider, QStackedWidget, QTabWidget, QToolBar, @@ -122,6 +125,22 @@ from aare.gui.widgets.wheel_value_guard import WheelValueGuard logger = setup_logger(LOGGER_NAME) +class ClickableCursorFilter(QObject): + """App-wide pointing-hand cursor on every button/combo/slider, present + and future. QSS cannot set cursors, and per-widget setCursor calls are + forgotten whenever a new widget is added — the Polish event fires once + for each widget when its style is applied, so this catches them all. + Widgets that manage their own cursor afterwards (beamline state strip's + forbidden cursor) still win: they set it later.""" + + def eventFilter(self, obj, event): + if event.type() == QEvent.Type.Polish and isinstance( + obj, (QAbstractButton, QComboBox, QSlider) + ): + obj.setCursor(Qt.CursorShape.PointingHandCursor) + return False + + class MainWindow(QMainWindow): sample_geometry = Signal(SampleGeometryModel) @@ -196,6 +215,10 @@ class MainWindow(QMainWindow): self._tutorial_text_resolver = DictionaryTextResolver(MANUAL_MOUNT_TUTORIAL) self.state_manager = UIStateManager("PSI", "AareGUI") + # App-level, not window-level: dialogs and pop-outs get it too. + self._clickable_cursor_filter = ClickableCursorFilter(self) + QApplication.instance().installEventFilter(self._clickable_cursor_filter) + # Wheel safety: sliders/spin boxes/combos only react to the wheel # while the right mouse button is held; a bare wheel just scrolls # the page — it can never nudge a value or move a motor.