GUI: added shortcuts and a helper
This commit is contained in:
1 parent
2802a72e43
commit
7e0a27f992
4 files changed
+177
-5
No files matched your search
@@ -3,7 +3,7 @@ import requests
|
||||
|
||||
import jwt
|
||||
from PySide6.QtCore import Qt, Slot, Signal, QTimer, QSettings
|
||||
from PySide6.QtGui import QAction, QPixmap
|
||||
from PySide6.QtGui import QAction, QPixmap, QKeySequence
|
||||
from PySide6.QtWidgets import (
|
||||
QMainWindow,
|
||||
QWidget,
|
||||
@@ -347,6 +347,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.setWindowTitle("AareGUI")
|
||||
self.create_menu_bar()
|
||||
self._setup_global_shortcuts()
|
||||
self._capture_default_window_state()
|
||||
self._restore_window_state()
|
||||
|
||||
@@ -635,6 +636,69 @@ class MainWindow(QMainWindow):
|
||||
# Initial load
|
||||
QTimer.singleShot(1000, self.daq.workflow_load_queue)
|
||||
|
||||
def _setup_global_shortcuts(self) -> None:
|
||||
self._shortcut_manual_sample = QAction("Raise Manual Sample Dock", self)
|
||||
self._shortcut_manual_sample.setShortcut(QKeySequence("Ctrl+M"))
|
||||
self._shortcut_manual_sample.triggered.connect(
|
||||
lambda: (self.manual_sample_dock.setVisible(True), self.manual_sample_dock.raise_()))
|
||||
self.addAction(self._shortcut_manual_sample)
|
||||
|
||||
self._shortcut_raise_sample_list = QAction("Raise sample list", self)
|
||||
self._shortcut_raise_sample_list.setShortcut(QKeySequence("Ctrl+L"))
|
||||
self._shortcut_raise_sample_list.triggered.connect(
|
||||
lambda: (self.tell_samples_dock.setVisible(True), self.tell_samples_dock.raise_())
|
||||
)
|
||||
self.addAction(self._shortcut_raise_sample_list)
|
||||
|
||||
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(
|
||||
lambda: (self.ref_tools_dock.setVisible(True), self.ref_tools_dock.raise_())
|
||||
)
|
||||
self.addAction(self._shortcut_raise_reference_tools_list)
|
||||
|
||||
self._shortcut_raise_job_list = QAction("Raise automation list", self)
|
||||
self._shortcut_raise_job_list.setShortcut(QKeySequence("Ctrl+J"))
|
||||
self._shortcut_raise_job_list.triggered.connect(
|
||||
lambda: (self.job_list_dock.setVisible(True), self.job_list_dock.raise_())
|
||||
)
|
||||
self.addAction(self._shortcut_raise_job_list)
|
||||
|
||||
self._shortcut_toggle_workflow = QAction("Toggle workflow panel", self)
|
||||
self._shortcut_toggle_workflow.setShortcut(QKeySequence("Ctrl+W"))
|
||||
self._shortcut_toggle_workflow.triggered.connect(
|
||||
lambda: self.workflow_dock.setVisible(not self.workflow_dock.isVisible())
|
||||
)
|
||||
self.addAction(self._shortcut_toggle_workflow)
|
||||
|
||||
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(not self.target_stability_dock.isVisible())
|
||||
)
|
||||
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.triggered.connect(
|
||||
lambda: self.prediction_metrics_dock.setVisible(not self.prediction_metrics_dock.isVisible())
|
||||
)
|
||||
self.addAction(self._shortcut_toggle_prediction_metrics)
|
||||
|
||||
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())
|
||||
)
|
||||
self.addAction(self._shortcut_toggle_smargon_trace)
|
||||
|
||||
self._shortcut_console_log = QAction("Toggle Console Log", self)
|
||||
self._shortcut_console_log.setShortcut(QKeySequence("Ctrl+Shift+L"))
|
||||
self._shortcut_console_log.triggered.connect(
|
||||
lambda: (self.log_dock.setVisible(True), self.log_dock.raise_())
|
||||
)
|
||||
self.addAction(self._shortcut_console_log)
|
||||
|
||||
def _restore_samcam_overlay_settings(self) -> None:
|
||||
settings = QSettings("PSI", "AareGUI")
|
||||
show_detections = settings.value("samcam/show_detections", True, type=bool)
|
||||
@@ -735,8 +799,9 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# File menu
|
||||
file_menu = menu_bar.addMenu("File")
|
||||
quit_action = QAction("&Quit", self) # Action for 'Quit'
|
||||
quit_action.triggered.connect(self.close) # Connect to window's `close` method
|
||||
quit_action = QAction("&Quit", self)
|
||||
quit_action.setShortcut(QKeySequence.StandardKey.Quit)
|
||||
quit_action.triggered.connect(self.close)
|
||||
file_menu.addAction(quit_action)
|
||||
|
||||
view_menu = menu_bar.addMenu("View")
|
||||
@@ -830,16 +895,40 @@ class MainWindow(QMainWindow):
|
||||
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
view_menu.addAction(beamline_combined_tab_action)
|
||||
|
||||
view_menu.addSeparator()
|
||||
|
||||
restore_default_view_action = QAction("Restore Default View", self)
|
||||
restore_default_view_action.setShortcut(QKeySequence("Ctrl+Shift+R"))
|
||||
restore_default_view_action.triggered.connect(self.restore_default_view)
|
||||
view_menu.addAction(restore_default_view_action)
|
||||
|
||||
help_menu = menu_bar.addMenu("Help")
|
||||
about_action = QAction("About", self) # Action for 'About'
|
||||
about_action = QAction("About", self)
|
||||
about_action.triggered.connect(self.show_about_dialog)
|
||||
help_menu.addAction(about_action)
|
||||
|
||||
controls_help_action = QAction("Mouse / Keyboard Controls", self)
|
||||
controls_help_action.setShortcut(QKeySequence(Qt.Key.Key_F1))
|
||||
controls_help_action.triggered.connect(self.show_controls_help)
|
||||
help_menu.addAction(controls_help_action)
|
||||
|
||||
@@ -1188,11 +1277,13 @@ class MainWindow(QMainWindow):
|
||||
settings.endGroup()
|
||||
|
||||
def _restore_window_state(self) -> None:
|
||||
#TODO put all setting related handlign into state_manager
|
||||
self.state_manager.restore_window(self)
|
||||
self._restore_panel_visibility_settings()
|
||||
|
||||
def closeEvent(self, event) -> None:
|
||||
try:
|
||||
# TODO put all setting related handling into state_manager
|
||||
self.state_manager.save_window(self)
|
||||
self._save_samcam_overlay_settings()
|
||||
self._save_panel_visibility_settings()
|
||||
|
||||
@@ -297,6 +297,7 @@ class WorkflowPanel(QWidget):
|
||||
self._automation_enabled = False
|
||||
self._was_paused_before_automation = False # Track pause state before automation
|
||||
self._setup_ui()
|
||||
self._setup_shortcuts()
|
||||
|
||||
def _setup_ui(self) -> None:
|
||||
layout = QVBoxLayout(self)
|
||||
@@ -436,6 +437,19 @@ class WorkflowPanel(QWidget):
|
||||
# Initial state
|
||||
self._update_button_states()
|
||||
|
||||
def _setup_shortcuts(self) -> None:
|
||||
self._pause_resume_shortcut = QShortcut(QKeySequence(Qt.Key.Key_Space), self)
|
||||
self._pause_resume_shortcut.setContext(Qt.ShortcutContext.WidgetWithChildrenShortcut)
|
||||
self._pause_resume_shortcut.activated.connect(self._on_pause_resume)
|
||||
|
||||
self._refresh_shortcut = QShortcut(QKeySequence("Ctrl+R"), self)
|
||||
self._refresh_shortcut.setContext(Qt.ShortcutContext.WidgetWithChildrenShortcut)
|
||||
self._refresh_shortcut.activated.connect(self.request_queue_refresh.emit)
|
||||
|
||||
self._clear_shortcut = QShortcut(QKeySequence("Ctrl+Delete"), self)
|
||||
self._clear_shortcut.setContext(Qt.ShortcutContext.WidgetWithChildrenShortcut)
|
||||
self._clear_shortcut.activated.connect(self._on_clear_queue)
|
||||
|
||||
def _on_start_guided(self) -> None:
|
||||
"""Start guided mode with the first pending sample."""
|
||||
pending = [i for i in self._queue_items if i.status == QueueItemStatus.PENDING]
|
||||
|
||||
@@ -36,6 +36,7 @@ class ControlsHelpDialog(QDialog):
|
||||
<ul>
|
||||
<li><b>Left click</b>: move sample to clicked position</li>
|
||||
<li><b>Shift + Left click</b>: move using the special Z-alignment click behaviour</li>
|
||||
<li><b>Ctrl + Left click on active raster grid</b>: move to the clicked position under the grid</li>
|
||||
<li><b>Left drag on active raster grid</b>: move active raster grid</li>
|
||||
<li><b>Right click</b>: open sample camera context menu</li>
|
||||
<li><b>Right drag on empty area</b>: draw raster grid</li>
|
||||
@@ -102,6 +103,10 @@ class ControlsHelpDialog(QDialog):
|
||||
<li><b>R</b>: reset zoom</li>
|
||||
<li><b>+</b> or <b>=</b>: zoom in</li>
|
||||
<li><b>-</b>: zoom out</li>
|
||||
<li><b>Ctrl + 1</b>: switch to Sample camera tab</li>
|
||||
<li><b>Ctrl + 2</b>: switch to Gonio camera tab</li>
|
||||
<li><b>Ctrl + 3</b>: switch to Beamline view tab</li>
|
||||
<li><b>Ctrl + 4</b>: switch to Beamline combined view tab</li>
|
||||
</ul>
|
||||
"""
|
||||
),
|
||||
@@ -115,13 +120,46 @@ class ControlsHelpDialog(QDialog):
|
||||
<h3>Sample Queue</h3>
|
||||
<ul>
|
||||
<li><b>Delete</b>: remove selected samples from the queue</li>
|
||||
<li><b>Space</b>: run / pause queue automation</li>
|
||||
<li><b>Drag and drop</b>: reorder queue items or add samples from the Sample List</li>
|
||||
</ul>
|
||||
|
||||
<h3>Workflow Panel</h3>
|
||||
<ul>
|
||||
<li><b>Delete</b>: remove selected queue items</li>
|
||||
<li><b>Space</b>: pause / resume workflow</li>
|
||||
<li><b>Ctrl + R</b>: refresh workflow queue</li>
|
||||
<li><b>Ctrl + Delete</b>: clear non-running workflow queue items</li>
|
||||
<li><b>Right click on workflow queue item</b>: start item, remove it, or move it in the queue</li>
|
||||
</ul>
|
||||
|
||||
<h3>Sample / Reference Tables</h3>
|
||||
<ul>
|
||||
<li><b>Right click on sample row</b>: open row actions such as mount</li>
|
||||
<li><b>Right click on table header</b>: open column filter options</li>
|
||||
</ul>
|
||||
|
||||
<h3>Fluorescence Plot</h3>
|
||||
<ul>
|
||||
<li><b>Delete</b>: remove selected samples from the queue</li>
|
||||
|
||||
<li><b>Mouse move</b>: show energy/count tooltip and vertical marker line</li>
|
||||
<li><b>Right click</b>: save spectrum as CSV</li>
|
||||
</ul>
|
||||
|
||||
<h3>Target Stability Panel</h3>
|
||||
<ul>
|
||||
<li><b>Mouse wheel</b>: zoom the selected wheel axis</li>
|
||||
<li><b>Shift + Mouse wheel</b>: zoom score axis</li>
|
||||
<li><b>Left drag</b>: pan selected axes</li>
|
||||
<li><b>Right click</b>: reset view / auto-scale</li>
|
||||
<li><b>Click a visible trace point</b>: target wheel/pan controls to that trace's axis group</li>
|
||||
</ul>
|
||||
|
||||
<h3>Status Bar / Labels</h3>
|
||||
<ul>
|
||||
<li><b>Left click</b> on session, p-group, shutter, and state labels: open quick action menus</li>
|
||||
</ul>
|
||||
|
||||
<h3>General Widgets</h3>
|
||||
<ul>
|
||||
@@ -137,6 +175,31 @@ class ControlsHelpDialog(QDialog):
|
||||
),
|
||||
"Other Panels",
|
||||
)
|
||||
self._tabs.addTab(
|
||||
self._create_tab(
|
||||
"""
|
||||
<h2>Application Shortcuts</h2>
|
||||
|
||||
<ul>
|
||||
<li><b>F1</b>: open Mouse / Keyboard Controls help</li>
|
||||
<li><b>Ctrl + Q</b>: quit application</li>
|
||||
<li><b>Ctrl + Shift + R</b>: restore default view layout</li>
|
||||
<li><b>Ctrl + 1</b>: switch to Sample camera tab</li>
|
||||
<li><b>Ctrl + 2</b>: switch to Gonio camera tab</li>
|
||||
<li><b>Ctrl + 3</b>: switch to Beamline view tab</li>
|
||||
<li><b>Ctrl + 4</b>: switch to Beamline combined view tab</li>
|
||||
<li><b>Ctrl + L</b>: raise Sample List panel</li>
|
||||
<li><b>Ctrl + J</b>: raise Automation list panel</li>
|
||||
<li><b>Ctrl + M</b>: go to Sample camera tab</li>
|
||||
<li><b>Ctrl + W</b>: toggle Workflow panel</li>
|
||||
<li><b>Ctrl + Shift + T</b>: toggle Target stability panel</li>
|
||||
<li><b>Ctrl + Shift + P</b>: toggle Prediction Metrics panel</li>
|
||||
<li><b>Ctrl + Shift + S</b>: toggle Smargon trace panel</li>
|
||||
</ul>
|
||||
"""
|
||||
),
|
||||
"App Shortcuts",
|
||||
)
|
||||
layout.addWidget(self._tabs)
|
||||
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close, parent=self)
|
||||
|
||||
@@ -352,6 +352,7 @@ class SampleCameraImageLabel(QGraphicsView):
|
||||
return
|
||||
|
||||
self.start_point = self.mapToScene(event.pos())
|
||||
ctrl_override_move = bool(event.modifiers() & Qt.KeyboardModifier.ControlModifier)
|
||||
|
||||
match self.__state:
|
||||
case SampleCameraImageState.BEAM_MARKING:
|
||||
@@ -364,7 +365,10 @@ class SampleCameraImageLabel(QGraphicsView):
|
||||
else:
|
||||
self.__state = SampleCameraImageState.DRAWING_RASTER_GRID
|
||||
elif event.button() == Qt.MouseButton.LeftButton:
|
||||
if self.__raster_mgr.is_part_of_active_grid(self.start_point):
|
||||
if (
|
||||
self.__raster_mgr.is_part_of_active_grid(self.start_point)
|
||||
and not ctrl_override_move
|
||||
):
|
||||
self.__state = SampleCameraImageState.MOVING_RASTER_GRID
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user