From 503431995604508fe1ba6727d4bee15c7c3afee4 Mon Sep 17 00:00:00 2001 From: Gabriel Selzer Date: Tue, 19 Nov 2024 11:25:17 -0600 Subject: [PATCH] Add opt-in for absolute positioning & halt button Additional safety features are always welcome! --- src/pymmcore_widgets/control/_stage_widget.py | 28 ++++++++++++------- tests/test_stage_widget.py | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/pymmcore_widgets/control/_stage_widget.py b/src/pymmcore_widgets/control/_stage_widget.py index 92fb4d02f..5824b081b 100644 --- a/src/pymmcore_widgets/control/_stage_widget.py +++ b/src/pymmcore_widgets/control/_stage_widget.py @@ -18,7 +18,7 @@ QVBoxLayout, QWidget, ) -from superqt.fonticon import setTextIcon +from superqt.fonticon import icon, setTextIcon from superqt.utils import signals_blocked if TYPE_CHECKING: @@ -96,17 +96,17 @@ def __init__( class HaltButton(QPushButton): - def __init__(self, core: CMMCorePlus, parent: QWidget | None = None): - super().__init__("STOP!", parent=parent) + def __init__(self, device: str, core: CMMCorePlus, parent: QWidget | None = None): + super().__init__(parent=parent) + self._device = device self._core = core - self.setStyleSheet("color: red; font-weight: bold;") + self.setIcon(icon(MDI6.close_octagon, color=(255, 0, 0))) + self.setToolTip("Halt stage movement") + self.setText("STOP!") self.clicked.connect(self._on_clicked) def _on_clicked(self) -> None: - for stage in self._core.getLoadedDevicesOfType(DeviceType.Stage): - self._core.stop(stage) - for stage in self._core.getLoadedDevicesOfType(DeviceType.XYStage): - self._core.stop(stage) + self._core.stop(self._device) class StageMovementButtons(QWidget): @@ -210,9 +210,12 @@ class StageWidget(QWidget): Stage device. levels: int | None: Number of "arrow" buttons per widget per direction, by default, 2. + absolute_positioning: bool | None + If True, the position displays can be edited to set absolute positions. + If False, the position displays cannot be edited. position_label_below: bool | None - If True, the position labels will appear below the move buttons. - If False, the position labels will appear to the right of the move buttons. + If True, the position displays will appear below the move buttons. + If False, the position displays will appear to the right of the move buttons. parent : QWidget | None Optional parent widget. mmcore : CMMCorePlus | None @@ -229,6 +232,7 @@ def __init__( device: str, levels: int = 2, *, + absolute_positioning: bool = False, position_label_below: bool = True, parent: QWidget | None = None, mmcore: CMMCorePlus | None = None, @@ -256,16 +260,19 @@ def __init__( if self._is_2axis: self._pos.addWidget(QLabel("X: ")) self._x_pos = MoveStageSpinBox(label="X") + self._x_pos.setEnabled(absolute_positioning) self._pos.addWidget(self._x_pos) self._x_pos.editingFinished.connect(self._move_x_absolute) self._pos.addWidget(QLabel(f"{self._Ylabel}: ")) self._y_pos = MoveStageSpinBox(label="Y") self._y_pos.editingFinished.connect(self._move_y_absolute) + self._y_pos.setEnabled(absolute_positioning) self._pos.addWidget(self._y_pos) self._pos.setAlignment(Qt.AlignmentFlag.AlignCenter) + self._halt = HaltButton(device, self._mmc, self) self._poll_cb = QCheckBox("Poll") self.snap_checkbox = QCheckBox(text="Snap on Click") self._invert_x = QCheckBox(text="Invert X") @@ -291,6 +298,7 @@ def __init__( main_layout.setContentsMargins(5, 5, 5, 5) main_layout.addWidget(self._set_as_default_btn, 0, Qt.AlignmentFlag.AlignCenter) main_layout.addWidget(self._move_btns, Qt.AlignmentFlag.AlignCenter) + main_layout.addWidget(self._halt) main_layout.addLayout(chxbox_grid) # pos label can appear either below or to the right of the move buttons diff --git a/tests/test_stage_widget.py b/tests/test_stage_widget.py index 81a57f7a8..1ae6e7e51 100644 --- a/tests/test_stage_widget.py +++ b/tests/test_stage_widget.py @@ -11,7 +11,7 @@ def test_stage_widget(qtbot: QtBot, global_mmcore: CMMCorePlus) -> None: # test XY stage - stage_xy = StageWidget("XY", levels=3) + stage_xy = StageWidget("XY", levels=3, absolute_positioning=True) qtbot.addWidget(stage_xy) assert global_mmcore.getXYStageDevice() == "XY"