From fc5daaefa4b196ec4b071e3ca0123b81dfd04038 Mon Sep 17 00:00:00 2001 From: Dawn Date: Mon, 24 Aug 2026 13:18:05 +0200 Subject: [PATCH] style: linting fix --- src/aare/gui/main_window.py | 757 ++++++++++-------------------------- 1 file changed, 214 insertions(+), 543 deletions(-) diff --git a/src/aare/gui/main_window.py b/src/aare/gui/main_window.py index 76c4ef87..fa823a63 100644 --- a/src/aare/gui/main_window.py +++ b/src/aare/gui/main_window.py @@ -1,6 +1,65 @@ import time import jwt +from aarecommon.config.logger import setup_logger +from aarecommon.math.coordinate import Coordinate, SmargonCoordinate +from aarecommon.math.diffraction_geometry import DiffractionGeometry +from aarecommon.math.sample_geometry import SampleGeometryModel + +# Common imports +from aarecommon.models.auth import BatonStatus +from aarecommon.models.models import ( + BeamlineStateEnum, + DAQStatusModel, + SampleShortInfoList, + SessionsStateEnum, + TokenData, +) +from PySide6.QtCore import ( + QByteArray, + QEvent, + QObject, + QPropertyAnimation, + QSettings, + Qt, + QTimer, + Signal, + Slot, +) +from PySide6.QtGui import ( + QAction, + QActionGroup, + QColor, + QCursor, + QGuiApplication, + QKeySequence, + QPalette, +) +from PySide6.QtWidgets import ( + QAbstractButton, + QApplication, + QCheckBox, + QComboBox, + QDockWidget, + QFrame, + QGraphicsColorizeEffect, + QGraphicsOpacityEffect, + QHBoxLayout, + QLabel, + QMainWindow, + QMessageBox, + QPushButton, + QScrollArea, + QSizePolicy, + QSlider, + QStackedWidget, + QTabWidget, + QToolBar, + QToolTip, + QVBoxLayout, + QWidget, +) + from aare.gui.about import about_text from aare.gui.constants import LOGGER_NAME @@ -76,64 +135,6 @@ from aare.gui.widgets.status_bar import StatusBar from aare.gui.widgets.title_label import TitleLabel, tighten_column from aare.gui.widgets.video_image import VideoGraphicsView from aare.gui.widgets.wheel_value_guard import WheelValueGuard -from aarecommon.config.logger import setup_logger -from aarecommon.math.coordinate import Coordinate, SmargonCoordinate -from aarecommon.math.diffraction_geometry import DiffractionGeometry -from aarecommon.math.sample_geometry import SampleGeometryModel - -# Common imports -from aarecommon.models.auth import BatonStatus -from aarecommon.models.models import ( - BeamlineStateEnum, - DAQStatusModel, - SampleShortInfoList, - SessionsStateEnum, - TokenData, -) -from PySide6.QtCore import ( - QByteArray, - QEvent, - QObject, - QPropertyAnimation, - QSettings, - Qt, - QTimer, - Signal, - Slot, -) -from PySide6.QtGui import ( - QAction, - QActionGroup, - QColor, - QCursor, - QGuiApplication, - QKeySequence, - QPalette, -) -from PySide6.QtWidgets import ( - QAbstractButton, - QApplication, - QCheckBox, - QComboBox, - QDockWidget, - QFrame, - QGraphicsColorizeEffect, - QGraphicsOpacityEffect, - QHBoxLayout, - QLabel, - QMainWindow, - QMessageBox, - QPushButton, - QScrollArea, - QSizePolicy, - QSlider, - QStackedWidget, - QTabWidget, - QToolBar, - QToolTip, - QVBoxLayout, - QWidget, -) logger = setup_logger(LOGGER_NAME) @@ -289,9 +290,7 @@ class MainWindow(QMainWindow): self._separator_hint_timer = QTimer(self) self._separator_hint_timer.setSingleShot(True) self._separator_hint_timer.setInterval(SEPARATOR_HINT_DELAY_MS) - self._separator_hint_timer.timeout.connect( - lambda: self._set_separator_hint(True) - ) + self._separator_hint_timer.timeout.connect(lambda: self._set_separator_hint(True)) root_widget = _AlertBannerHost(parent=self) root_widget.setObjectName("mainContentRoot") @@ -347,17 +346,12 @@ class MainWindow(QMainWindow): self.left_column_layout.setContentsMargins(0, 0, 0, 0) self.data_collection = DataCollectionSettings( - s=geom, - parent=self.left_column, - raster_mgr=self.raster, - diffraction=diffraction, + s=geom, parent=self.left_column, raster_mgr=self.raster, diffraction=diffraction ) # The beamline state strip lives in a bottom toolbar row (created # after the docks), not in the left column. Always visible. - self.beamline_state_panel = BeamlineStatePanel( - staff=self._decoded_token.staff, parent=self - ) + self.beamline_state_panel = BeamlineStatePanel(staff=self._decoded_token.staff, parent=self) # Anchor for _show_admin_tip: QToolTip inherits QSS from the widget # it is shown for, so this hidden label carries the red warning wash @@ -428,9 +422,7 @@ class MainWindow(QMainWindow): for i in range(self.left_column_tabs.count()): page = self.left_column_tabs.widget(i) vertical = ( - QSizePolicy.Policy.Preferred - if i == index - else QSizePolicy.Policy.Ignored + QSizePolicy.Policy.Preferred if i == index else QSizePolicy.Policy.Ignored ) page.setSizePolicy(QSizePolicy.Policy.Preferred, vertical) @@ -448,11 +440,7 @@ class MainWindow(QMainWindow): else self._locked_beamline_banners[0].parentWidget() ) assert beamline_first is not None # the locked banner always has its holder - for first in ( - beamline_first, - self.data_collection, - self.data_collection.file_path_panel, - ): + for first in (beamline_first, self.data_collection, self.data_collection.file_path_panel): first_layout = first.layout() assert first_layout is not None # panels build their layouts in __init__ m = first_layout.contentsMargins() @@ -479,17 +467,12 @@ class MainWindow(QMainWindow): # scrollbar pops into spare space and nothing moves. self.collection_controls_scroll.setFrameShape(QFrame.Shape.NoFrame) self.left_column.setFixedWidth(self.data_collection.set_width) - self.collection_controls_scroll.setFixedWidth( - self.data_collection.set_width + 10 - ) + self.collection_controls_scroll.setFixedWidth(self.data_collection.set_width + 10) self.video_tab = QTabWidget(parent=top_widget) self.sample_camera = SampleCameraImageLabel( - geom=geom, - raster=self.raster, - parent=top_widget, - default_image=default_image, + geom=geom, raster=self.raster, parent=top_widget, default_image=default_image ) # Baton toasts sit as a compact pill under the camera view instead of # a full-width bar at the top of the window. @@ -502,9 +485,7 @@ class MainWindow(QMainWindow): self.beamline_view_panel.refresh_requested.connect(self.refresh_axis_cameras) self.gonio_view = VideoGraphicsView() - self.gonio_view_panel = AxisVideoPanel( - "Gonio camera", self.gonio_view, parent=top_widget - ) + self.gonio_view_panel = AxisVideoPanel("Gonio camera", self.gonio_view, parent=top_widget) self.gonio_view_panel.refresh_requested.connect(self.refresh_axis_cameras) self.beamline_view_container = QWidget(parent=top_widget) @@ -520,9 +501,7 @@ class MainWindow(QMainWindow): self.beamline_combined_panel = AxisVideoPanel( "Beamline combined view", self.beamline_view_container, parent=top_widget ) - self.beamline_combined_panel.refresh_requested.connect( - self.refresh_axis_cameras - ) + self.beamline_combined_panel.refresh_requested.connect(self.refresh_axis_cameras) self.video_tab.addTab(self.sample_camera, "Sample camera") self.video_tab.addTab(self.gonio_view_panel, "Gonio camera") @@ -537,10 +516,7 @@ class MainWindow(QMainWindow): # self.video_tab.addTab(self.secondary_beamline_view_panel, "Secondary view") self.compact_sample_camera = SampleCameraImageLabel( - geom=geom, - raster=self.raster, - parent=root_widget, - default_image=default_image, + geom=geom, raster=self.raster, parent=root_widget, default_image=default_image ) self.compact_automation_panel = CompactAutomationPanel( self.compact_sample_camera, parent=root_widget @@ -555,10 +531,7 @@ class MainWindow(QMainWindow): # ── Portrait mode page ────────────────────────────────────────── self.portrait_sample_camera = SampleCameraImageLabel( - geom=geom, - raster=self.raster, - parent=root_widget, - default_image=default_image, + geom=geom, raster=self.raster, parent=root_widget, default_image=default_image ) self.portrait_mode_panel = PortraitModePanel( sample_camera_widget=self.portrait_sample_camera, parent=root_widget @@ -569,9 +542,7 @@ class MainWindow(QMainWindow): portrait_page_layout = QHBoxLayout(self.portrait_mode_page) portrait_page_layout.setContentsMargins(0, 0, 0, 0) portrait_page_layout.setSpacing(0) - self.portrait_mode_page.setFixedWidth( - self.portrait_mode_panel.PORTRAIT_WIDTH + 24 - ) + self.portrait_mode_page.setFixedWidth(self.portrait_mode_panel.PORTRAIT_WIDTH + 24) portrait_page_layout.addWidget( self.portrait_mode_panel, alignment=Qt.AlignmentFlag.AlignHCenter ) @@ -598,21 +569,15 @@ class MainWindow(QMainWindow): self.ref_tools_panel = ReferenceToolsPanel(samples=SampleShortInfoList(s=[])) self.job_list_panel = SampleQueuePanel(show_user=self._decoded_token.staff) - self.compact_automation_panel.play_pause_clicked.connect( - self.job_list_panel.run - ) - self.compact_automation_panel.skip_clicked.connect( - self.job_list_panel.skip_current_sample - ) + self.compact_automation_panel.play_pause_clicked.connect(self.job_list_panel.run) + self.compact_automation_panel.skip_clicked.connect(self.job_list_panel.skip_current_sample) self.compact_automation_panel.step_through_toggled.connect( self.job_list_panel.set_step_through ) self.compact_automation_panel.show_full_view_requested.connect( self._return_from_compact_automation_view ) - self.compact_automation_panel.annotation_selected.connect( - self._handle_compact_annotation - ) + self.compact_automation_panel.annotation_selected.connect(self._handle_compact_annotation) # One dock for both lists: the old tabified Reference Tools dock was # staff-only and hid behind the Sample List tab, so it "sometimes" @@ -630,9 +595,7 @@ class MainWindow(QMainWindow): dewar_layout.addWidget(self.tell_samples) self.quick_unmount_button = QPushButton("⏏ Unmount", dewar_tab) - self.quick_unmount_button.clicked.connect( - lambda: self._on_manual_unmount_requested() - ) + self.quick_unmount_button.clicked.connect(lambda: self._on_manual_unmount_requested()) automation_row = QHBoxLayout() for w in ( @@ -651,9 +614,7 @@ class MainWindow(QMainWindow): self.job_list_panel.remove_button.clicked.disconnect( self.job_list_panel.remove_selected_samples ) - self.job_list_panel.remove_button.clicked.connect( - self._remove_selected_from_queue - ) + self.job_list_panel.remove_button.clicked.connect(self._remove_selected_from_queue) self.job_list_panel.hide() # Queue controls act on the queue, whose order only the Queued chip @@ -706,9 +667,7 @@ class MainWindow(QMainWindow): self.tell_samples_dock.setObjectName("tell_samples_dock") self.tell_samples_dock.setWidget(sample_lists_wrap) self.tell_samples_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea) - self.addDockWidget( - Qt.DockWidgetArea.BottomDockWidgetArea, self.tell_samples_dock - ) + self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.tell_samples_dock) # No floating: popping the dock out ripped the panel from the row and # reshuffled the rest. The ⤢ button (in the title bar, next to ✕) @@ -761,9 +720,7 @@ class MainWindow(QMainWindow): self.information_dock.setObjectName("information_dock") self.information_dock.setWidget(information_wrap) self.information_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea) - self.addDockWidget( - Qt.DockWidgetArea.BottomDockWidgetArea, self.information_dock - ) + self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.information_dock) self.information_dock.setFeatures( QDockWidget.DockWidgetFeature.DockWidgetMovable | QDockWidget.DockWidgetFeature.DockWidgetClosable @@ -793,9 +750,7 @@ class MainWindow(QMainWindow): | Qt.DockWidgetArea.BottomDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea ) - self.addDockWidget( - Qt.DockWidgetArea.BottomDockWidgetArea, self.fluor_panel_dock - ) + self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.fluor_panel_dock) self.fluor_panel_dock.hide() self.job_list_panel.samples_in_queue_changed.connect( @@ -804,9 +759,7 @@ class MainWindow(QMainWindow): self.job_list_panel.automation_running_changed.connect( self.automation_progress_panel.set_running ) - self.job_list_panel.automation_running_changed.connect( - self._on_automation_running_changed - ) + self.job_list_panel.automation_running_changed.connect(self._on_automation_running_changed) self.job_list_panel.automation_running_changed.connect( self.compact_automation_panel.set_running ) @@ -816,28 +769,20 @@ class MainWindow(QMainWindow): self.job_list_panel.samples_in_queue_changed.connect( self.compact_automation_panel.set_samples_in_queue ) - self.job_list_panel.samples_in_queue_changed.connect( - self._refresh_compact_queue_preview - ) + self.job_list_panel.samples_in_queue_changed.connect(self._refresh_compact_queue_preview) # Portrait mode: queue size + running state + preview - self.job_list_panel.automation_running_changed.connect( - self.portrait_mode_panel.set_running - ) + self.job_list_panel.automation_running_changed.connect(self.portrait_mode_panel.set_running) self.job_list_panel.samples_in_queue_changed.connect( self.portrait_mode_panel.set_samples_in_queue ) - self.job_list_panel.samples_in_queue_changed.connect( - self._refresh_portrait_queue_preview - ) + self.job_list_panel.samples_in_queue_changed.connect(self._refresh_portrait_queue_preview) self.automation_progress_panel.set_samples_in_queue( len(self.job_list_panel.table_model.samples) ) self.automation_progress_panel.set_running(self.job_list_panel.is_running()) self.compact_automation_panel.set_running(self.job_list_panel.is_running()) - self.compact_automation_panel.set_step_through( - self.job_list_panel.is_step_through() - ) + self.compact_automation_panel.set_step_through(self.job_list_panel.is_step_through()) self.compact_automation_panel.set_samples_in_queue( len(self.job_list_panel.table_model.samples) ) @@ -853,9 +798,7 @@ class MainWindow(QMainWindow): | Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.BottomDockWidgetArea ) - self.addDockWidget( - Qt.DockWidgetArea.RightDockWidgetArea, self.smargon_trace_dock - ) + self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.smargon_trace_dock) self.smargon_trace_dock.hide() # Target stability panel @@ -868,9 +811,7 @@ class MainWindow(QMainWindow): | Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.BottomDockWidgetArea ) - self.addDockWidget( - Qt.DockWidgetArea.RightDockWidgetArea, self.target_stability_dock - ) + self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.target_stability_dock) self.target_stability_dock.hide() # Prediction Metrics Panel @@ -883,9 +824,7 @@ class MainWindow(QMainWindow): | Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.BottomDockWidgetArea ) - self.addDockWidget( - Qt.DockWidgetArea.RightDockWidgetArea, self.prediction_metrics_dock - ) + self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.prediction_metrics_dock) self.prediction_metrics_dock.hide() # Full-width state strip directly above the status bar: the bottom @@ -924,11 +863,7 @@ class MainWindow(QMainWindow): def _only_current_page_counts(index: int) -> None: for i in range(self.content_stack.count()): page = self.content_stack.widget(i) - policy = ( - QSizePolicy.Policy.Preferred - if i == index - else QSizePolicy.Policy.Ignored - ) + policy = QSizePolicy.Policy.Preferred if i == index else QSizePolicy.Policy.Ignored page.setSizePolicy(policy, policy) self.content_stack.currentChanged.connect(_only_current_page_counts) @@ -947,9 +882,7 @@ class MainWindow(QMainWindow): # the default-state capture so "reset layout" gets it too; a saved # user layout (restored below) still wins. self.resizeDocks( - [self.tell_samples_dock, self.information_dock], - [240, 240], - Qt.Orientation.Vertical, + [self.tell_samples_dock, self.information_dock], [240, 240], Qt.Orientation.Vertical ) # Equal oversized requests -> Qt distributes proportionally = 50/50. self.resizeDocks( @@ -1000,21 +933,15 @@ class MainWindow(QMainWindow): self._remote_close_timer.timeout.connect(self._check_remote_close_deadline) self._axis_camera_refresh_timer = QTimer(self) - self._axis_camera_refresh_timer.setInterval( - self._axis_camera_refresh_interval_ms - ) + self._axis_camera_refresh_timer.setInterval(self._axis_camera_refresh_interval_ms) self._axis_camera_refresh_timer.timeout.connect(self.refresh_axis_cameras) self._axis_camera_refresh_timer.start() self.portrait_mode_panel.wire_to_main_window( job_list_panel=self.job_list_panel, tell_samples=self.tell_samples ) - self.portrait_mode_panel._back_btn.clicked.connect( - self._return_from_portrait_mode - ) - self.portrait_mode_panel.grab_session_requested.connect( - self.status_bar.request_baton - ) + self.portrait_mode_panel._back_btn.clicked.connect(self._return_from_portrait_mode) + self.portrait_mode_panel.grab_session_requested.connect(self.status_bar.request_baton) # Route alert banner signals through portrait-aware interceptors self.daq.polled_devices_status.connect(self._portrait_alert_primary) @@ -1030,9 +957,7 @@ class MainWindow(QMainWindow): self.daq.baton_request_result.connect(self._on_baton_request_result) self.daq.baton_response_result.connect(self._on_baton_response_result) self.daq.baton_timeout_checked.connect(self._on_baton_timeout_checked) - self.daq.automation_progress.connect( - self.automation_progress_panel.set_progress - ) + self.daq.automation_progress.connect(self.automation_progress_panel.set_progress) self.daq.automation_progress.connect(self.compact_automation_panel.set_progress) self.daq.automation_progress.connect(self.portrait_mode_panel.set_progress) @@ -1046,9 +971,7 @@ class MainWindow(QMainWindow): self.samcam.changed.connect(self.daq.samcam_settings) self.samcam.screenshot_requested.connect(self.daq.send_screenshot_db) - self.samcam.save_beam_location_setting.connect( - self.daq.save_beam_location_camera_setting - ) + self.samcam.save_beam_location_setting.connect(self.daq.save_beam_location_camera_setting) self.data_collection.find_tip.clicked.connect(self.daq.center_loop) self.data_collection.bounding_box.clicked.connect(self.daq.ml_bounding_box) self.daq.raster_generated_by_ml.connect(self.raster.update_active_grid_request) @@ -1093,24 +1016,16 @@ class MainWindow(QMainWindow): self.beam_size.beam_size.connect(self.daq.beam_size_mm) self.sample_camera.load_image.connect(self.raster.load_image) - self.sample_camera.switch_raster_grid.connect( - self.data_collection.switch_to_raster - ) - self.samcam.show_detections_changed.connect( - self.sample_camera.set_show_detections - ) + self.sample_camera.switch_raster_grid.connect(self.data_collection.switch_to_raster) + self.samcam.show_detections_changed.connect(self.sample_camera.set_show_detections) self.samcam.show_detection_polygons_changed.connect( self.sample_camera.set_show_detection_polygons ) - self.samcam.show_target_point_changed.connect( - self.sample_camera.set_show_target_point - ) + self.samcam.show_target_point_changed.connect(self.sample_camera.set_show_target_point) self.samcam.show_target_coordinates_changed.connect( self.sample_camera.set_show_target_coordinates ) - self.samcam.show_overlay_legend_changed.connect( - self.sample_camera.set_show_overlay_legend - ) + self.samcam.show_overlay_legend_changed.connect(self.sample_camera.set_show_overlay_legend) self.samcam.compact_overlay_legend_changed.connect( self.sample_camera.set_compact_overlay_legend ) @@ -1121,31 +1036,17 @@ class MainWindow(QMainWindow): if sample_feed_addr is not None: logger.debug(f"Starting prediction subscriber thread {sample_feed_addr}") - self.prediction_thread = PredictionSubscriber( - pred_zmq_url=sample_feed_addr, topic=b"" - ) + self.prediction_thread = PredictionSubscriber(pred_zmq_url=sample_feed_addr, topic=b"") self.prediction_thread.image.connect(self.sample_camera.update_pixmap) - self.prediction_thread.image.connect( - self.compact_sample_camera.update_pixmap - ) - self.prediction_thread.image.connect( - self.portrait_sample_camera.update_pixmap - ) - self.prediction_thread.prediction.connect( - self.sample_camera.update_detections - ) - self.prediction_thread.prediction.connect( - self.compact_sample_camera.update_detections - ) - self.prediction_thread.prediction.connect( - self.portrait_sample_camera.update_detections - ) + self.prediction_thread.image.connect(self.compact_sample_camera.update_pixmap) + self.prediction_thread.image.connect(self.portrait_sample_camera.update_pixmap) + self.prediction_thread.prediction.connect(self.sample_camera.update_detections) + self.prediction_thread.prediction.connect(self.compact_sample_camera.update_detections) + self.prediction_thread.prediction.connect(self.portrait_sample_camera.update_detections) self.prediction_thread.prediction.connect( self.prediction_metrics_panel.update_from_prediction ) - self.prediction_thread.target_point.connect( - self.sample_camera.update_target_point - ) + self.prediction_thread.target_point.connect(self.sample_camera.update_target_point) self.prediction_thread.target_point.connect( self.compact_sample_camera.update_target_point ) @@ -1155,12 +1056,8 @@ class MainWindow(QMainWindow): self.prediction_thread.target_point.connect( self.target_stability_panel.update_target_point ) - self.prediction_thread.focus_measure.connect( - self.status_bar.update_sharpness - ) - self.prediction_thread.fps_measure.connect( - self.status_bar.update_samcam_fps - ) + self.prediction_thread.focus_measure.connect(self.status_bar.update_sharpness) + self.prediction_thread.fps_measure.connect(self.status_bar.update_samcam_fps) self.prediction_thread.camera_availability_changed.connect( self.sample_camera.set_camera_available ) @@ -1180,9 +1077,7 @@ class MainWindow(QMainWindow): self.sample_camera.set_camera_available(False) self.compact_sample_camera.set_camera_available(False) self.portrait_sample_camera.set_camera_available(False) - self._show_samcam_feed_banner( - "Sample camera feed unavailable: no stream configured" - ) + self._show_samcam_feed_banner("Sample camera feed unavailable: no stream configured") # # self.data_collection.helical.helical_scan.connect(self.worker.helical_scan) @@ -1195,13 +1090,9 @@ class MainWindow(QMainWindow): self.sample_camera.evaluate_grid.connect(self.raster.run_grid_scan) self.data_collection.raster.evaluate_grid.connect(self.raster.run_grid_scan) - self.data_collection.raster.evaluate_grid_auto.connect( - self.raster.run_grid_scan_auto - ) + self.data_collection.raster.evaluate_grid_auto.connect(self.raster.run_grid_scan_auto) - self.sample_camera.clear_evaluated_grids.connect( - self.raster.clear_completed_grids - ) + self.sample_camera.clear_evaluated_grids.connect(self.raster.clear_completed_grids) self.sample_camera.clear_grid.connect(self.raster.clear_active_grid) self.daq.run_number_incremented.connect( self.data_collection.file_path_panel.increment_run_number @@ -1229,28 +1120,18 @@ class MainWindow(QMainWindow): ) self.job_list_panel.table_model.modelReset.connect(self._sync_queue_row_tints) - self.data_collection.raster.grid_size_updated.connect( - self.raster.update_grid_size - ) - self.data_collection.raster.exp_time_updated.connect( - self.raster.update_exposure_time - ) - self.data_collection.raster.transmission_updated.connect( - self.raster.update_transmission - ) + self.data_collection.raster.grid_size_updated.connect(self.raster.update_grid_size) + self.data_collection.raster.exp_time_updated.connect(self.raster.update_exposure_time) + self.data_collection.raster.transmission_updated.connect(self.raster.update_transmission) self.data_collection.raster.dtz_updated.connect(self.raster.update_dtz) self.data_collection.raster.grid_metric_updated.connect(self.raster.metric) - self.data_collection.raster.raster_alpha_changed.connect( - self.sample_camera.raster_alpha - ) + self.data_collection.raster.raster_alpha_changed.connect(self.sample_camera.raster_alpha) self.data_collection.cancel.connect(self.daq.cancel) self.raster.grid_scan.connect(self.daq.raster_scan) self.raster.grid_scan_auto.connect(self.daq.raster_scan_auto) self.data_collection.screening.rotation_scan.connect(self.daq.standard_scan) - self.data_collection.simple.rotation_scan.connect( - self._on_simple_rotation_requested - ) + self.data_collection.simple.rotation_scan.connect(self._on_simple_rotation_requested) self.data_collection.simple.parameters_changed.connect(self.daq.smart_params) self.raster.grid_scan_size_changed.connect( @@ -1283,28 +1164,20 @@ class MainWindow(QMainWindow): self.beamline_state_panel.sample_exchange.connect(self.daq.sample_exchange) self.beamline_state_panel.sample_alignment.connect(self.daq.sample_alignment) self.beamline_state_panel.beam_location.connect(self.daq.beam_location) - self.beamline_state_panel.beamstop_alignment.connect( - self.daq.beamstop_alignment - ) + self.beamline_state_panel.beamstop_alignment.connect(self.daq.beamstop_alignment) self.beamline_state_panel.flux_measurement.connect(self.daq.flux_measurement) self.beamline_state_panel.data_collection.connect(self.daq.data_collection) self.beamline_state_panel.xtal_snapshot.connect(self.daq.xtal_snapshot) self.beamline_state_panel.xray_fluorescence.connect(self.daq.xray_fluorescence) - self.beamline_state_panel.robot_sample_exchange.connect( - self.daq.robot_sample_exchange - ) + self.beamline_state_panel.robot_sample_exchange.connect(self.daq.robot_sample_exchange) self.rotation.file_ready.connect(self.viewer.load_image) self.raster.image_selected.connect(self.viewer.load_image) self.raster.viewer_track_online.connect(self.viewer.load_online) - self.data_collection.screening.viewer_track_online.connect( - self.viewer.load_online - ) + self.data_collection.screening.viewer_track_online.connect(self.viewer.load_online) self.job_list_panel.viewer_track_online.connect(self.viewer.load_online) - self.sample_logic.sample_changed.connect( - self.data_collection.file_path_panel.update_sample - ) + self.sample_logic.sample_changed.connect(self.data_collection.file_path_panel.update_sample) self.daq.update.connect(self.beamline.omega_panel.update_daq_status) self.daq.update.connect(self.beamline.smargon_panel.update_daq_status) @@ -1350,9 +1223,7 @@ class MainWindow(QMainWindow): self.daq.automated_scan_done.connect(self.job_list_panel.automated_scan_done) self.daq.automated_scan_done.connect(self._mark_scan_result) - self.daq.automation_critical_failure.connect( - self._on_automation_critical_failure - ) + self.daq.automation_critical_failure.connect(self._on_automation_critical_failure) self.daq.manual_collection_critical_failure.connect( self._on_manual_collection_critical_failure ) @@ -1369,9 +1240,7 @@ class MainWindow(QMainWindow): self.data_collection.fluo.fluo_scan.connect(self._on_fluo_scan_requested) self.daq.fluorimeter_spectrum_update.connect(self.fluor_panel.update_plot) - self.daq.fluorimeter_spectrum_update.connect( - lambda: self.fluor_panel_dock.setVisible(True) - ) + self.daq.fluorimeter_spectrum_update.connect(lambda: self.fluor_panel_dock.setVisible(True)) # === Alert/Status Message Routing === # Status bar: General status messages (not device connection status) @@ -1412,13 +1281,9 @@ class MainWindow(QMainWindow): # Reference tools now live inside the Sample List dock as the # Auxiliary-puck tab — Ctrl+R raises the dock on that tab. - self._shortcut_raise_reference_tools_list = QAction( - "Raise reference tools", self - ) + self._shortcut_raise_reference_tools_list = QAction("Raise reference tools", self) self._shortcut_raise_reference_tools_list.setShortcut(QKeySequence("Ctrl+R")) - self._shortcut_raise_reference_tools_list.triggered.connect( - self._raise_reference_tools - ) + self._shortcut_raise_reference_tools_list.triggered.connect(self._raise_reference_tools) self.addAction(self._shortcut_raise_reference_tools_list) # The automation controls live under the Dewar samples tab now. @@ -1433,9 +1298,7 @@ class MainWindow(QMainWindow): ) self.addAction(self._shortcut_raise_job_list) - self._shortcut_toggle_target_stability = QAction( - "Toggle target stability panel", self - ) + self._shortcut_toggle_target_stability = QAction("Toggle target stability panel", self) self._shortcut_toggle_target_stability.setShortcut(QKeySequence("Ctrl+Shift+T")) self._shortcut_toggle_target_stability.triggered.connect( lambda: self.target_stability_dock.setVisible( @@ -1444,12 +1307,8 @@ class MainWindow(QMainWindow): ) self.addAction(self._shortcut_toggle_target_stability) - self._shortcut_toggle_prediction_metrics = QAction( - "Toggle prediction metrics panel", self - ) - self._shortcut_toggle_prediction_metrics.setShortcut( - QKeySequence("Ctrl+Shift+P") - ) + self._shortcut_toggle_prediction_metrics = QAction("Toggle prediction metrics panel", self) + self._shortcut_toggle_prediction_metrics.setShortcut(QKeySequence("Ctrl+Shift+P")) self._shortcut_toggle_prediction_metrics.triggered.connect( lambda: self.prediction_metrics_dock.setVisible( not self.prediction_metrics_dock.isVisible() @@ -1457,14 +1316,10 @@ class MainWindow(QMainWindow): ) self.addAction(self._shortcut_toggle_prediction_metrics) - self._shortcut_toggle_smargon_trace = QAction( - "Toggle smargon trace panel", self - ) + self._shortcut_toggle_smargon_trace = QAction("Toggle smargon trace panel", self) self._shortcut_toggle_smargon_trace.setShortcut(QKeySequence("Ctrl+Shift+S")) self._shortcut_toggle_smargon_trace.triggered.connect( - lambda: self.smargon_trace_dock.setVisible( - not self.smargon_trace_dock.isVisible() - ) + lambda: self.smargon_trace_dock.setVisible(not self.smargon_trace_dock.isVisible()) ) self.addAction(self._shortcut_toggle_smargon_trace) @@ -1531,9 +1386,7 @@ class MainWindow(QMainWindow): lambda chip: dewar_panel.set_status_chip(chip.property("status_key")) ) dewar_panel.status_chips.buttonClicked.connect( - lambda chip: self.tell_samples.set_status_chip( - chip.property("status_key") - ) + lambda chip: self.tell_samples.set_status_chip(chip.property("status_key")) ) # Pop-out chips drive the same shared filter — regate the queue # buttons from here too. @@ -1566,9 +1419,7 @@ class MainWindow(QMainWindow): if self._information_popout is None: # Automation mirror wired to the same feeds as the docked panel. panel = AutomationProgressWidget() - self.job_list_panel.samples_in_queue_changed.connect( - panel.set_samples_in_queue - ) + self.job_list_panel.samples_in_queue_changed.connect(panel.set_samples_in_queue) self.job_list_panel.automation_running_changed.connect(panel.set_running) self.daq.automation_progress.connect(panel.set_progress) panel.set_samples_in_queue(len(self.job_list_panel.table_model.samples)) @@ -1603,9 +1454,7 @@ class MainWindow(QMainWindow): lambda running: run_button.setText("⏸ Pause" if running else "▶ Run") ) remove_button = QPushButton("🗑 Remove selected") - remove_button.clicked.connect( - lambda: self._unqueue_panel_selection(dewar_panel) - ) + remove_button.clicked.connect(lambda: self._unqueue_panel_selection(dewar_panel)) clear_button = QPushButton("✖ Clear list") clear_button.clicked.connect(jl.clear) unmount_button = QPushButton("⏏ Unmount") @@ -1682,10 +1531,7 @@ class MainWindow(QMainWindow): current_widget = self.content_stack.currentWidget() - if ( - hasattr(self, "portrait_mode_page") - and current_widget is self.portrait_mode_page - ): + if hasattr(self, "portrait_mode_page") and current_widget is self.portrait_mode_page: self._return_from_portrait_mode() elif bool(getattr(self, "_in_compact_automation_view", False)): self._return_from_compact_automation_view() @@ -1693,31 +1539,23 @@ class MainWindow(QMainWindow): if hasattr(self, "content_stack") and hasattr(self, "_standard_main_page"): self.content_stack.setCurrentWidget(self._standard_main_page) except Exception as e: - logger.warning( - f"Failed to return to main view during shutdown: {e}", exc_info=True - ) + logger.warning(f"Failed to return to main view during shutdown: {e}", exc_info=True) def _restore_samcam_overlay_settings(self) -> None: settings = QSettings("PSI", "AareGUI") # bool()/str() wraps: QSettings.value is typed "object" even with # type=..., so the wraps are runtime no-ops for the pyright gate. - show_detections = bool( - settings.value("samcam/show_detections", True, type=bool) - ) + show_detections = bool(settings.value("samcam/show_detections", True, type=bool)) show_detection_polygons = bool( settings.value("samcam/show_detection_polygons", True, type=bool) ) - show_target_point = bool( - settings.value("samcam/show_target_point", True, type=bool) - ) + show_target_point = bool(settings.value("samcam/show_target_point", True, type=bool)) show_target_coordinates = bool( settings.value("samcam/show_target_coordinates", True, type=bool) ) # Legend defaults off — it covers the camera image; users opt in and # the choice persists via QSettings. - show_overlay_legend = bool( - settings.value("samcam/show_overlay_legend", False, type=bool) - ) + show_overlay_legend = bool(settings.value("samcam/show_overlay_legend", False, type=bool)) compact_overlay_legend = bool( settings.value("samcam/compact_overlay_legend", False, type=bool) ) @@ -1748,13 +1586,9 @@ class MainWindow(QMainWindow): "samcam/show_detection_polygons", overlay["show_detection_polygons"] ) # NEW settings.setValue("samcam/show_target_point", overlay["show_target_point"]) - settings.setValue( - "samcam/show_target_coordinates", overlay["show_target_coordinates"] - ) + settings.setValue("samcam/show_target_coordinates", overlay["show_target_coordinates"]) settings.setValue("samcam/show_overlay_legend", overlay["show_overlay_legend"]) - settings.setValue( - "samcam/compact_overlay_legend", overlay["compact_overlay_legend"] - ) + settings.setValue("samcam/compact_overlay_legend", overlay["compact_overlay_legend"]) settings.setValue("samcam/target_color", overlay["target_color"]) @Slot(bool) @@ -1776,9 +1610,7 @@ class MainWindow(QMainWindow): getattr(self, "portrait_sample_camera", None), ): if cam is not None: - cam.set_camera_error_message( - message or "Sample camera feed unavailable" - ) + cam.set_camera_error_message(message or "Sample camera feed unavailable") def _show_samcam_feed_banner(self, message: str) -> None: self._samcam_feed_banner_message = message @@ -1819,9 +1651,7 @@ class MainWindow(QMainWindow): try: activity_name = tell_state.activity.display_name() except Exception: - logger.debug( - "Could not derive the axis busy text from status", exc_info=True - ) + logger.debug("Could not derive the axis busy text from status", exc_info=True) activity_name = activity_value.capitalize() if activity_value else "Busy" return f"TELL {activity_name}".upper() @@ -1831,9 +1661,7 @@ class MainWindow(QMainWindow): if self._beamline_cam_addr: self.beamline_camera_thread = VideoThread(ip=self._beamline_cam_addr) - self.beamline_camera_thread.frame_ready.connect( - self.beamline_view.update_frame - ) + self.beamline_camera_thread.frame_ready.connect(self.beamline_view.update_frame) self.beamline_camera_thread.frame_ready.connect( self.beamline_view_2_combined.update_frame ) @@ -1844,9 +1672,7 @@ class MainWindow(QMainWindow): ip=self._gonio_cam_addr, camera=self._gonio_cam_id ) self.gonio_camera_thread.frame_ready.connect(self.gonio_view.update_frame) - self.gonio_camera_thread.frame_ready.connect( - self.beamline_view_1_combined.update_frame - ) + self.gonio_camera_thread.frame_ready.connect(self.beamline_view_1_combined.update_frame) self.gonio_camera_thread.start() def _all_tell_samples_in_default_order(self) -> list: @@ -1876,12 +1702,8 @@ class MainWindow(QMainWindow): if not self._in_compact_automation_view: self._pre_automation_window_state = self.saveState() - self._pre_automation_left_column_visible = ( - self.collection_controls_scroll.isVisible() - ) - self._pre_automation_right_column_visible = ( - self.beamline_controls_scroll.isVisible() - ) + self._pre_automation_left_column_visible = self.collection_controls_scroll.isVisible() + self._pre_automation_right_column_visible = self.beamline_controls_scroll.isVisible() self.tell_samples_dock.setVisible(False) self.information_dock.setVisible(False) @@ -1905,12 +1727,8 @@ class MainWindow(QMainWindow): if self._pre_automation_window_state is not None: self.restoreState(self._pre_automation_window_state) - self.collection_controls_scroll.setVisible( - self._pre_automation_left_column_visible - ) - self.beamline_controls_scroll.setVisible( - self._pre_automation_right_column_visible - ) + self.collection_controls_scroll.setVisible(self._pre_automation_left_column_visible) + self.beamline_controls_scroll.setVisible(self._pre_automation_right_column_visible) self._in_compact_automation_view = False self._update_view_mode_actions() @@ -1920,12 +1738,8 @@ class MainWindow(QMainWindow): @Slot() def _refresh_compact_queue_preview(self) -> None: - current_sample, next_sample, next_next_sample = ( - self.job_list_panel.queue_preview() - ) - self.compact_automation_panel.set_samples( - current_sample, next_sample, next_next_sample - ) + current_sample, next_sample, next_next_sample = self.job_list_panel.queue_preview() + self.compact_automation_panel.set_samples(current_sample, next_sample, next_next_sample) @Slot() def enter_portrait_mode(self) -> None: @@ -1933,9 +1747,7 @@ class MainWindow(QMainWindow): self._pre_portrait_geometry = self.saveGeometry() self.portrait_mode_panel.set_running(self.job_list_panel.is_running()) - self.portrait_mode_panel.set_samples_in_queue( - len(self.job_list_panel.table_model.samples) - ) + self.portrait_mode_panel.set_samples_in_queue(len(self.job_list_panel.table_model.samples)) self._refresh_portrait_queue_preview() self.content_stack.setCurrentWidget(self.portrait_mode_page) @@ -2077,9 +1889,7 @@ class MainWindow(QMainWindow): return mapping.get(annotation, str(annotation).strip()) @staticmethod - def _append_annotation_to_comment( - existing_comment: str | None, annotation: str - ) -> str: + def _append_annotation_to_comment(existing_comment: str | None, annotation: str) -> str: token = MainWindow._annotation_token(annotation) current = str(existing_comment or "").strip() @@ -2096,18 +1906,14 @@ class MainWindow(QMainWindow): def _handle_compact_annotation(self, annotation: str) -> None: current_sample, _, _ = self.job_list_panel.queue_preview() if current_sample is None: - self.status_bar.show_connection_message( - "No sample selected for annotation.", True - ) + self.status_bar.show_connection_message("No sample selected for annotation.", True) return updated_comment = self._append_annotation_to_comment( getattr(current_sample, "comment", None), annotation ) - self.job_list_panel.annotate_sample_comment( - current_sample.db_id, updated_comment - ) + self.job_list_panel.annotate_sample_comment(current_sample.db_id, updated_comment) self.tell_samples.annotate_sample_comment(current_sample.db_id, updated_comment) self._refresh_compact_queue_preview() @@ -2220,21 +2026,15 @@ class MainWindow(QMainWindow): # Prototype views live in the View menu (below the themes), not on the # menubar; only their in-progress labels changed, the internal # action/slot names stay. - self._enter_automation_view_action = QAction( - "Automation View (prototyping)", self - ) + self._enter_automation_view_action = QAction("Automation View (prototyping)", self) self._enter_automation_view_action.setShortcut(QKeySequence("Ctrl+5")) - self._enter_automation_view_action.triggered.connect( - self.enter_compact_automation_view - ) + self._enter_automation_view_action.triggered.connect(self.enter_compact_automation_view) # Stays top-level: it only shows while INSIDE the automation view, # where the way back must not hide in a menu. self._return_main_view_action = QAction("Return to Main View", self) self._return_main_view_action.setShortcut(QKeySequence("Ctrl+Shift+5")) - self._return_main_view_action.triggered.connect( - self._return_from_compact_automation_view - ) + self._return_main_view_action.triggered.connect(self._return_from_compact_automation_view) menu_bar.addAction(self._return_main_view_action) self._portrait_mode_action = QAction("Playlist Mode (work in progress)", self) @@ -2252,9 +2052,7 @@ class MainWindow(QMainWindow): self._use_legacy_theme_action.triggered.connect(self.use_legacy_theme) self._theme_action_group.addAction(self._use_legacy_theme_action) - self._use_portrait_theme_action = QAction( - "Sunset Theme (work in progress)", self - ) + self._use_portrait_theme_action = QAction("Sunset Theme (work in progress)", self) self._use_portrait_theme_action.setCheckable(True) self._use_portrait_theme_action.setChecked(self._theme_mode == THEME_SUNSET) self._use_portrait_theme_action.triggered.connect(self.use_portrait_theme) @@ -2289,9 +2087,7 @@ class MainWindow(QMainWindow): show_face_panel_action.triggered.connect( lambda checked: self.face_panel_dock.setVisible(checked) ) - self.face_panel_dock.visibilityChanged.connect( - show_face_panel_action.setChecked - ) + self.face_panel_dock.visibilityChanged.connect(show_face_panel_action.setChecked) view_menu.addAction(show_face_panel_action) show_fluor_panel_action = QAction("Show fluorescence", self) @@ -2300,9 +2096,7 @@ class MainWindow(QMainWindow): show_fluor_panel_action.triggered.connect( lambda checked: self.fluor_panel_dock.setVisible(checked) ) - self.fluor_panel_dock.visibilityChanged.connect( - show_fluor_panel_action.setChecked - ) + self.fluor_panel_dock.visibilityChanged.connect(show_fluor_panel_action.setChecked) view_menu.addAction(show_fluor_panel_action) show_smargon_trace_action = QAction("Show Smargon trace", self) @@ -2311,13 +2105,9 @@ class MainWindow(QMainWindow): show_smargon_trace_action.triggered.connect( lambda checked: self.smargon_trace_dock.setVisible(checked) ) + self.smargon_trace_dock.visibilityChanged.connect(show_smargon_trace_action.setChecked) self.smargon_trace_dock.visibilityChanged.connect( - show_smargon_trace_action.setChecked - ) - self.smargon_trace_dock.visibilityChanged.connect( - lambda visible: ( - self.smargon_trace_panel.refresh_plot(force=True) if visible else None - ) + lambda visible: self.smargon_trace_panel.refresh_plot(force=True) if visible else None ) view_menu.addAction(show_smargon_trace_action) @@ -2349,39 +2139,29 @@ class MainWindow(QMainWindow): show_information_action.triggered.connect( lambda checked: self.information_dock.setVisible(checked) ) - self.information_dock.visibilityChanged.connect( - show_information_action.setChecked - ) + self.information_dock.visibilityChanged.connect(show_information_action.setChecked) view_menu.addAction(show_information_action) view_menu.addSeparator() sample_camera_tab_action = QAction("Sample camera tab", self) sample_camera_tab_action.setShortcut(QKeySequence("Ctrl+1")) - sample_camera_tab_action.triggered.connect( - lambda: self.video_tab.setCurrentIndex(0) - ) + sample_camera_tab_action.triggered.connect(lambda: self.video_tab.setCurrentIndex(0)) view_menu.addAction(sample_camera_tab_action) gonio_camera_tab_action = QAction("Gonio camera tab", self) gonio_camera_tab_action.setShortcut(QKeySequence("Ctrl+2")) - gonio_camera_tab_action.triggered.connect( - lambda: self.video_tab.setCurrentIndex(1) - ) + gonio_camera_tab_action.triggered.connect(lambda: self.video_tab.setCurrentIndex(1)) view_menu.addAction(gonio_camera_tab_action) beamline_view_tab_action = QAction("Beamline view tab", self) beamline_view_tab_action.setShortcut(QKeySequence("Ctrl+3")) - beamline_view_tab_action.triggered.connect( - lambda: self.video_tab.setCurrentIndex(2) - ) + beamline_view_tab_action.triggered.connect(lambda: self.video_tab.setCurrentIndex(2)) view_menu.addAction(beamline_view_tab_action) beamline_combined_tab_action = QAction("Beamline combined view tab", self) beamline_combined_tab_action.setShortcut(QKeySequence("Ctrl+4")) - beamline_combined_tab_action.triggered.connect( - lambda: self.video_tab.setCurrentIndex(3) - ) + beamline_combined_tab_action.triggered.connect(lambda: self.video_tab.setCurrentIndex(3)) view_menu.addAction(beamline_combined_tab_action) view_menu.addSeparator() @@ -2483,11 +2263,7 @@ class MainWindow(QMainWindow): auto_clear_ms: int | None = None, ) -> None: self.log_panel.show_notification( - title=title, - message=message, - level=level, - sticky=sticky, - auto_clear_ms=auto_clear_ms, + title=title, message=message, level=level, sticky=sticky, auto_clear_ms=auto_clear_ms ) def _show_runtime_waiting_notification(self, *, title: str, message: str) -> None: @@ -2616,9 +2392,7 @@ class MainWindow(QMainWindow): "complete the safety search before mounting." ) if getattr(bl, "pss_alarm", False): - return ( - "The hutch safety alarm is active. Mounting is blocked until it clears." - ) + return "The hutch safety alarm is active. Mounting is blocked until it clears." return None def _on_manual_mount_requested(self, sample, reference: bool = False) -> None: @@ -2734,23 +2508,13 @@ class MainWindow(QMainWindow): progress = AutomationProgress( current_step=None, steps=[ + StepState(step=WorkflowStateKind.MOUNT, status=StepStatus.PENDING), + StepState(step=WorkflowStateKind.LOOP_CENTRE, status=StepStatus.PENDING), + StepState(step=WorkflowStateKind.RASTER, status=StepStatus.PENDING), StepState( - step=WorkflowStateKind.MOUNT, status=StepStatus.PENDING - ), - StepState( - step=WorkflowStateKind.LOOP_CENTRE, - status=StepStatus.PENDING, - ), - StepState( - step=WorkflowStateKind.RASTER, status=StepStatus.PENDING - ), - StepState( - step=WorkflowStateKind.DATA_COLLECTION, - status=StepStatus.PENDING, - ), - StepState( - step=WorkflowStateKind.FINAL, status=StepStatus.PENDING + step=WorkflowStateKind.DATA_COLLECTION, status=StepStatus.PENDING ), + StepState(step=WorkflowStateKind.FINAL, status=StepStatus.PENDING), ], finished=False, success=None, @@ -2766,9 +2530,7 @@ class MainWindow(QMainWindow): progress.success = False self.automation_progress_panel.set_progress(progress) except Exception: - logger.exception( - "Failed to update automation progress after critical failure" - ) + logger.exception("Failed to update automation progress after critical failure") self._show_runtime_notification( title="Automation paused", message=message, level="error", sticky=True @@ -2825,9 +2587,7 @@ class MainWindow(QMainWindow): if not bool(getattr(self._decoded_token, "staff", False)): return if self._beamline_recovery_dialog is None: - self._beamline_recovery_dialog = BeamlineRecoveryDialog( - daq=self.daq, parent=self - ) + self._beamline_recovery_dialog = BeamlineRecoveryDialog(daq=self.daq, parent=self) self._beamline_recovery_dialog.show() self._beamline_recovery_dialog.raise_() self._beamline_recovery_dialog.activateWindow() @@ -2862,18 +2622,11 @@ class MainWindow(QMainWindow): # No baton -> watching only: camera views stay live, every operating # surface is greyed. The SESSION VACANT badge (and the status bar # session menu) remain the way back in. - owned = session_state in ( - SessionsStateEnum.OwnedByYou, - SessionsStateEnum.PendingElseToYou, - ) + owned = session_state in (SessionsStateEnum.OwnedByYou, SessionsStateEnum.PendingElseToYou) if owned == getattr(self, "_session_operations_enabled", None): return self._session_operations_enabled = owned - for widget in ( - self.left_column_tabs, - self.beamline, - self.tell_samples_dock.widget(), - ): + for widget in (self.left_column_tabs, self.beamline, self.tell_samples_dock.widget()): widget.setEnabled(owned) if owned: # None clears the effect (Qt API contract); the PySide6 stub @@ -2890,16 +2643,14 @@ class MainWindow(QMainWindow): # Vacant folds every panel shut; grabbing reopens exactly the ones # that were open before. Transient (persist=False) so the fold never # overwrites the user's saved per-panel choices. - banners = self.left_column_tabs.findChildren( + banners = self.left_column_tabs.findChildren(TitleLabel) + self.beamline.findChildren( TitleLabel - ) + self.beamline.findChildren(TitleLabel) + ) if owned: for banner in getattr(self, "_pre_vacancy_open_banners", []): banner.set_collapsed(False, persist=False) else: - self._pre_vacancy_open_banners = [ - b for b in banners if not b.is_collapsed() - ] + self._pre_vacancy_open_banners = [b for b in banners if not b.is_collapsed()] for banner in banners: banner.set_collapsed(True, persist=False) @@ -2935,9 +2686,7 @@ class MainWindow(QMainWindow): # before the window is shown, where isVisible() is False for # everything and the restore would then "restore" all-hidden. self._pre_watch_dock_state = self.saveState() - self._pre_watch_visibility = [ - (w, not w.isHidden()) for w in hide_in_watch_mode - ] + self._pre_watch_visibility = [(w, not w.isHidden()) for w in hide_in_watch_mode] for widget in hide_in_watch_mode + self.findChildren(QDockWidget): widget.hide() @@ -2986,9 +2735,7 @@ class MainWindow(QMainWindow): def update_daq_status(self, s: DAQStatusModel): self._latest_daq_status = s self._apply_session_gate(getattr(getattr(s, "session", None), "session", None)) - self._apply_pgroup_gate( - getattr(getattr(s, "session", None), "current_pgroup", None) - ) + self._apply_pgroup_gate(getattr(getattr(s, "session", None), "current_pgroup", None)) # No login-default state: the GUI adopts whatever state the server # reports and never posts a transition on startup — a state POST can @@ -3004,16 +2751,10 @@ class MainWindow(QMainWindow): if self._is_automation_active(): self._refresh_idle_activity(report_backend=False) - if ( - hasattr(self, "beamline_camera_thread") - and self.beamline_camera_thread is not None - ): + if hasattr(self, "beamline_camera_thread") and self.beamline_camera_thread is not None: self.beamline_camera_thread.set_busy(s.busy) - if ( - hasattr(self, "gonio_camera_thread") - and self.gonio_camera_thread is not None - ): + if hasattr(self, "gonio_camera_thread") and self.gonio_camera_thread is not None: self.gonio_camera_thread.set_busy(s.busy) # Sample alignment busy is the alignment itself (same exception as @@ -3024,17 +2765,11 @@ class MainWindow(QMainWindow): session_state=getattr(getattr(s, "session", None), "session", None), ) - if ( - hasattr(self, "beamline_view_panel") - and self.beamline_view_panel is not None - ): + if hasattr(self, "beamline_view_panel") and self.beamline_view_panel is not None: self.beamline_view_panel.set_busy_style(busy_style) if hasattr(self, "gonio_view_panel") and self.gonio_view_panel is not None: self.gonio_view_panel.set_busy_style(busy_style) - if ( - hasattr(self, "beamline_combined_panel") - and self.beamline_combined_panel is not None - ): + if hasattr(self, "beamline_combined_panel") and self.beamline_combined_panel is not None: self.beamline_combined_panel.set_busy_style(busy_style) self.target_stability_panel.set_beam_center( @@ -3097,9 +2832,7 @@ class MainWindow(QMainWindow): self._baton_request_dialog.accepted_signal.connect( self.status_bar._on_baton_dialog_accepted ) - self._baton_request_dialog.refused_signal.connect( - self.status_bar._on_baton_dialog_refused - ) + self._baton_request_dialog.refused_signal.connect(self.status_bar._on_baton_dialog_refused) self._baton_request_dialog.show() self._baton_request_dialog.raise_() self._baton_request_dialog.activateWindow() @@ -3124,9 +2857,7 @@ class MainWindow(QMainWindow): self._close_baton_pending_dialog() if status.you_are_holder: - self.alert_banner.show_message( - "Baton acquired!", False, auto_clear_ms=4000 - ) + self.alert_banner.show_message("Baton acquired!", False, auto_clear_ms=4000) else: self.alert_banner.show_message( "Request declined or cancelled", False, auto_clear_ms=4000 @@ -3134,9 +2865,7 @@ class MainWindow(QMainWindow): # Manage incoming request dialog (when someone requests from us) if not status.incoming_request and self._baton_request_dialog is not None: - logger.info( - "Incoming baton request no longer active, closing request dialog" - ) + logger.info("Incoming baton request no longer active, closing request dialog") self._close_baton_dialog() @Slot(dict) @@ -3162,15 +2891,12 @@ class MainWindow(QMainWindow): if getattr(self, "_baton_pending_dialog", None) is None: target_user = holder.replace("Request sent to ", "").replace( - " (Note: beamline is currently busy, transfer will be queued if accepted)", - "", + " (Note: beamline is currently busy, transfer will be queued if accepted)", "" ) self._baton_pending_dialog = BatonPendingDialog( target_user=target_user, timeout_seconds=timeout, parent=self ) - self._baton_pending_dialog.cancelled_signal.connect( - self.daq.cancel_baton_request - ) + self._baton_pending_dialog.cancelled_signal.connect(self.daq.cancel_baton_request) self._baton_pending_dialog.show() else: self._baton_pending_dialog.update_remaining(timeout) @@ -3180,18 +2906,14 @@ class MainWindow(QMainWindow): elif result.get("queued"): self._waiting_for_baton_response = True - self.alert_banner.show_waiting( - "Control transfer queued - waiting for beamline" - ) + self.alert_banner.show_waiting("Control transfer queued - waiting for beamline") logger.info("Baton transfer queued") if getattr(self, "_baton_pending_dialog", None) is None: self._baton_pending_dialog = BatonPendingDialog( target_user="Current Holder", timeout_seconds=0, parent=self ) - self._baton_pending_dialog.cancelled_signal.connect( - self.daq.cancel_baton_request - ) + self._baton_pending_dialog.cancelled_signal.connect(self.daq.cancel_baton_request) self._baton_pending_dialog.show() self._baton_pending_dialog.set_queued_state() @@ -3217,16 +2939,12 @@ class MainWindow(QMainWindow): logger.debug(f"Baton response result: {result}") if result.get("accepted"): self._waiting_for_baton_response = False - self.alert_banner.show_message( - "Control transferred", False, auto_clear_ms=4000 - ) + self.alert_banner.show_message("Control transferred", False, auto_clear_ms=4000) self._close_baton_dialog() self.status_bar.update_baton_status(self.status_bar._baton_status) elif result.get("refused"): self._waiting_for_baton_response = False - self.alert_banner.show_message( - "Request declined", False, auto_clear_ms=4000 - ) + self.alert_banner.show_message("Request declined", False, auto_clear_ms=4000) self._close_baton_dialog() self.status_bar.update_baton_status(self.status_bar._baton_status) else: @@ -3250,9 +2968,7 @@ class MainWindow(QMainWindow): elif result.get("queued"): self._waiting_for_baton_response = True - self.alert_banner.show_waiting( - "Control transfer queued - waiting for beamline" - ) + self.alert_banner.show_waiting("Control transfer queued - waiting for beamline") if getattr(self, "_baton_pending_dialog", None) is not None: self._baton_pending_dialog.set_queued_state() @@ -3260,17 +2976,13 @@ class MainWindow(QMainWindow): self._baton_pending_dialog = BatonPendingDialog( target_user="Current Holder", timeout_seconds=0, parent=self ) - self._baton_pending_dialog.cancelled_signal.connect( - self.daq.cancel_baton_request - ) + self._baton_pending_dialog.cancelled_signal.connect(self.daq.cancel_baton_request) self._baton_pending_dialog.show() self._baton_pending_dialog.set_queued_state() elif result.get("refused"): self._waiting_for_baton_response = False - self.alert_banner.show_message( - "Request declined", False, auto_clear_ms=4000 - ) + self.alert_banner.show_message("Request declined", False, auto_clear_ms=4000) self._close_baton_pending_dialog() else: @@ -3301,9 +3013,7 @@ class MainWindow(QMainWindow): settings.beginGroup("panel_visibility") settings.setValue("smargon_trace", self.smargon_trace_dock.isVisible()) settings.setValue("target_stability", self.target_stability_dock.isVisible()) - settings.setValue( - "prediction_metrics", self.prediction_metrics_dock.isVisible() - ) + settings.setValue("prediction_metrics", self.prediction_metrics_dock.isVisible()) settings.setValue("face_detection", self.face_panel_dock.isVisible()) settings.setValue("fluorescence", self.fluor_panel_dock.isVisible()) settings.setValue("information", self.information_dock.isVisible()) @@ -3315,9 +3025,7 @@ class MainWindow(QMainWindow): settings.beginGroup("panel_visibility") if settings.contains("smargon_trace"): - self.smargon_trace_dock.setVisible( - settings.value("smargon_trace", False, type=bool) - ) + self.smargon_trace_dock.setVisible(settings.value("smargon_trace", False, type=bool)) if settings.contains("target_stability"): self.target_stability_dock.setVisible( settings.value("target_stability", False, type=bool) @@ -3327,21 +3035,15 @@ class MainWindow(QMainWindow): settings.value("prediction_metrics", False, type=bool) ) if settings.contains("face_detection"): - self.face_panel_dock.setVisible( - settings.value("face_detection", False, type=bool) - ) + self.face_panel_dock.setVisible(settings.value("face_detection", False, type=bool)) if settings.contains("fluorescence"): - self.fluor_panel_dock.setVisible( - settings.value("fluorescence", False, type=bool) - ) + self.fluor_panel_dock.setVisible(settings.value("fluorescence", False, type=bool)) # New key: the old "log" flag described a dock that defaulted hidden; # the merged Information dock defaults visible, so old values would # wrongly hide it. if settings.contains("information"): # bool() wrap: settings.value is typed object even with type=bool. - self.information_dock.setVisible( - bool(settings.value("information", True, type=bool)) - ) + self.information_dock.setVisible(bool(settings.value("information", True, type=bool))) settings.endGroup() @@ -3354,11 +3056,7 @@ class MainWindow(QMainWindow): # them. Fall back to the default layout instead of resurrecting it # (the vanished-Sample-List-on-restart bug). docks = self.findChildren(QDockWidget) - if ( - docks - and all(d.isHidden() for d in docks) - and self._default_window_state is not None - ): + if docks and all(d.isHidden() for d in docks) and self._default_window_state is not None: self.restoreState(self._default_window_state) self._restore_panel_visibility_settings() @@ -3375,9 +3073,7 @@ class MainWindow(QMainWindow): def _apply_default_dock_split(self) -> None: self.resizeDocks( - [self.tell_samples_dock, self.information_dock], - [240, 240], - Qt.Orientation.Vertical, + [self.tell_samples_dock, self.information_dock], [240, 240], Qt.Orientation.Vertical ) self.resizeDocks( [self.tell_samples_dock, self.information_dock], @@ -3389,17 +3085,12 @@ class MainWindow(QMainWindow): try: self._return_to_main_view_for_shutdown() except Exception as e: - logger.warning( - f"Failed to restore main view before close: {e}", exc_info=True - ) + logger.warning(f"Failed to restore main view before close: {e}", exc_info=True) try: # Closing while watch-only would persist the all-hidden fold and # poison every future start — put the pre-watch layout back first. - if ( - self._session_operations_enabled is False - and self._pre_watch_dock_state is not None - ): + if self._session_operations_enabled is False and self._pre_watch_dock_state is not None: self.restoreState(self._pre_watch_dock_state) # TODO put all setting related handling into state_manager self.state_manager.save_window(self) @@ -3430,17 +3121,12 @@ class MainWindow(QMainWindow): try: self._return_to_main_view_for_shutdown() except Exception as e: - logger.warning( - f"Failed to restore main view during cleanup: {e}", exc_info=True - ) + logger.warning(f"Failed to restore main view during cleanup: {e}", exc_info=True) self._cleanup_done = True try: - if ( - hasattr(self, "_samcam_source_timer") - and self._samcam_source_timer is not None - ): + if hasattr(self, "_samcam_source_timer") and self._samcam_source_timer is not None: self._samcam_source_timer.stop() except Exception as e: logger.warning(f"Failed to stop _samcam_source_timer: {e}", exc_info=True) @@ -3452,10 +3138,7 @@ class MainWindow(QMainWindow): logger.warning(f"Failed to stop _idle_timer: {e}", exc_info=True) try: - if ( - hasattr(self, "_remote_close_timer") - and self._remote_close_timer is not None - ): + if hasattr(self, "_remote_close_timer") and self._remote_close_timer is not None: self._remote_close_timer.stop() except Exception as e: logger.warning(f"Failed to stop _remote_close_timer: {e}", exc_info=True) @@ -3467,9 +3150,7 @@ class MainWindow(QMainWindow): ): self._axis_camera_refresh_timer.stop() except Exception as e: - logger.warning( - f"Failed to stop _axis_camera_refresh_timer: {e}", exc_info=True - ) + logger.warning(f"Failed to stop _axis_camera_refresh_timer: {e}", exc_info=True) try: if hasattr(self, "daq") and self.daq is not None: @@ -3498,9 +3179,7 @@ class MainWindow(QMainWindow): if hasattr(self, "job_list_panel") and self.job_list_panel is not None: return bool(self.job_list_panel.is_running()) except Exception: - logger.debug( - "Could not read the job list panel running state", exc_info=True - ) + logger.debug("Could not read the job list panel running state", exc_info=True) try: progress = getattr(self.automation_progress_panel, "_progress", None) @@ -3518,10 +3197,7 @@ class MainWindow(QMainWindow): return now = time.monotonic() - if ( - now - self._last_interaction_report_ts - < self._interaction_report_min_interval_s - ): + if now - self._last_interaction_report_ts < self._interaction_report_min_interval_s: return self._last_interaction_report_ts = now @@ -3603,11 +3279,7 @@ class MainWindow(QMainWindow): # Closing a floated (popped-out) dock re-docks it instead of hiding — # otherwise the panel silently disappears and has to be restored via # the View menu. - if ( - event.type() == QEvent.Type.Close - and isinstance(obj, QDockWidget) - and obj.isFloating() - ): + if event.type() == QEvent.Type.Close and isinstance(obj, QDockWidget) and obj.isFloating(): obj.setFloating(False) event.ignore() return True @@ -3709,8 +3381,7 @@ class MainWindow(QMainWindow): if not self._can_close_for_idle_or_remote(): if self._remote_close_banner_active: self.alert_banner_secondary.show_message( - "GUI close requested, waiting for beamline/automation to become idle.", - True, + "GUI close requested, waiting for beamline/automation to become idle.", True ) return