mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-06-29 16:19:48 +02:00
fix(beamline_states): trigger on Warning checkbox in the setting of the beamline pill
This commit is contained in:
@@ -219,6 +219,7 @@ class _BeamlineStatePillDelegate(QStyledItemDelegate):
|
||||
pill.update_requested.connect(self._manager._update_state_parameters)
|
||||
pill.remove_requested.connect(self._manager._remove_state_requested)
|
||||
pill.scan_interlock_toggle_requested.connect(self._manager._on_interlock_toggle_requested)
|
||||
pill.scan_interlock_statuses_changed.connect(self._manager._on_interlock_statuses_changed)
|
||||
pill.row_height_changed.connect(lambda name=name: self._manager._sync_pill_item_size(name))
|
||||
self._manager._state_pills[str(name)] = pill
|
||||
return pill
|
||||
@@ -712,6 +713,19 @@ class BeamlineStateManager(BECWidget, QWidget):
|
||||
return
|
||||
self._refresh_scan_interlock()
|
||||
|
||||
@SafeSlot(str, object)
|
||||
def _on_interlock_statuses_changed(self, state_name: str, statuses: object) -> None:
|
||||
# Only persist when the state is currently watched; otherwise the pill keeps the
|
||||
# preference for when it is locked later.
|
||||
if state_name not in self._interlock_states:
|
||||
return
|
||||
try:
|
||||
self._scan_interlock.add_state_to_interlock(state_name, list(statuses))
|
||||
except Exception as exc:
|
||||
QMessageBox.warning(self, "Cannot Update Scan Interlock", str(exc))
|
||||
return
|
||||
self._refresh_scan_interlock()
|
||||
|
||||
def _open_persistent_editors(self, expanded_names: set[str] | None = None) -> None:
|
||||
expanded_names = expanded_names or set()
|
||||
for row in range(self._model.rowCount()):
|
||||
|
||||
@@ -9,6 +9,7 @@ from qtpy.QtCore import Property, QEasingCurve, QPropertyAnimation, Qt, Signal
|
||||
from qtpy.QtGui import QColor, QMouseEvent, QPalette
|
||||
from qtpy.QtWidgets import (
|
||||
QApplication,
|
||||
QCheckBox,
|
||||
QFormLayout,
|
||||
QGraphicsDropShadowEffect,
|
||||
QHBoxLayout,
|
||||
@@ -64,6 +65,7 @@ class BeamlineStatePill(BECWidget, QWidget):
|
||||
update_requested = Signal(str, object)
|
||||
remove_requested = Signal(str)
|
||||
scan_interlock_toggle_requested = Signal(str, bool)
|
||||
scan_interlock_statuses_changed = Signal(str, object)
|
||||
row_height_changed = Signal()
|
||||
|
||||
_STATUS_LABELS = BEAMLINE_STATE_STATUS_LABELS
|
||||
@@ -217,11 +219,22 @@ class BeamlineStatePill(BECWidget, QWidget):
|
||||
self._settings_form.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
|
||||
self._settings_form.addRow("Type", self._state_type_value)
|
||||
|
||||
self._interlock_warning_checkbox = QCheckBox(
|
||||
"Trigger ScanInterlock on WARNING state", self._settings
|
||||
)
|
||||
self._interlock_warning_checkbox.setToolTip(
|
||||
"By default both VALID and WARNING are accepted. Enable this so a WARNING status also "
|
||||
"trips the scan interlock (only VALID accepted)."
|
||||
)
|
||||
self._interlock_warning_checkbox.toggled.connect(self._on_interlock_warning_toggled)
|
||||
self._sync_interlock_warning_checkbox()
|
||||
|
||||
settings_layout = QVBoxLayout(self._settings)
|
||||
settings_layout.setContentsMargins(12, 8, 12, 12)
|
||||
settings_layout.setSpacing(8)
|
||||
settings_layout.addLayout(self._settings_form)
|
||||
settings_layout.addLayout(self._config_form_host)
|
||||
settings_layout.addWidget(self._interlock_warning_checkbox)
|
||||
settings_layout.addLayout(button_layout)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
@@ -320,6 +333,7 @@ class BeamlineStatePill(BECWidget, QWidget):
|
||||
triggered = bool(triggered) and required_statuses is not None
|
||||
if required_statuses is not None:
|
||||
self._interlock_statuses = list(required_statuses)
|
||||
self._sync_interlock_warning_checkbox()
|
||||
if (required_statuses, triggered) == (
|
||||
self._interlock_required_statuses,
|
||||
self._interlock_triggered,
|
||||
@@ -343,6 +357,22 @@ class BeamlineStatePill(BECWidget, QWidget):
|
||||
def set_interlock_statuses(self, statuses: list[str]) -> None:
|
||||
"""Configure the accepted scan-interlock statuses for this state."""
|
||||
self._interlock_statuses = list(statuses)
|
||||
self._sync_interlock_warning_checkbox()
|
||||
|
||||
def _sync_interlock_warning_checkbox(self) -> None:
|
||||
trigger_on_warning = "warning" not in self._interlock_statuses
|
||||
self._interlock_warning_checkbox.blockSignals(True)
|
||||
self._interlock_warning_checkbox.setChecked(trigger_on_warning)
|
||||
self._interlock_warning_checkbox.blockSignals(False)
|
||||
|
||||
@SafeSlot(bool)
|
||||
def _on_interlock_warning_toggled(self, trigger_on_warning: bool) -> None:
|
||||
statuses = ["valid"] if trigger_on_warning else ["valid", "warning"]
|
||||
if statuses == self._interlock_statuses:
|
||||
return
|
||||
self._interlock_statuses = statuses
|
||||
if self._state_name is not None:
|
||||
self.scan_interlock_statuses_changed.emit(self._state_name, statuses)
|
||||
|
||||
@SafeSlot()
|
||||
def _emit_interlock_toggle_requested(self) -> None:
|
||||
|
||||
@@ -892,6 +892,66 @@ def test_beamline_state_manager_pill_toggle_calls_backend(qtbot, mocked_client):
|
||||
assert beamline_state_manager._interlock_states == {}
|
||||
|
||||
|
||||
def test_beamline_state_pill_settings_warning_checkbox(qtbot, mocked_client):
|
||||
pill = create_widget(qtbot, BeamlineStatePill, state_name="limits", client=mocked_client)
|
||||
|
||||
# Default accepts VALID and WARNING, so the checkbox is unchecked.
|
||||
assert pill._interlock_warning_checkbox.isChecked() is False
|
||||
assert pill.interlock_statuses == ["valid", "warning"]
|
||||
|
||||
with qtbot.waitSignal(pill.scan_interlock_statuses_changed) as signal:
|
||||
pill._interlock_warning_checkbox.setChecked(True)
|
||||
|
||||
assert signal.args == ["limits", ["valid"]]
|
||||
assert pill.interlock_statuses == ["valid"]
|
||||
|
||||
pill._interlock_warning_checkbox.setChecked(False)
|
||||
assert pill.interlock_statuses == ["valid", "warning"]
|
||||
|
||||
|
||||
def test_beamline_state_pill_settings_warning_checkbox_reflects_statuses(qtbot, mocked_client):
|
||||
pill = create_widget(qtbot, BeamlineStatePill, state_name="limits", client=mocked_client)
|
||||
|
||||
pill.set_interlock_statuses(["valid"])
|
||||
assert pill._interlock_warning_checkbox.isChecked() is True
|
||||
|
||||
pill.set_interlock_statuses(["valid", "warning"])
|
||||
assert pill._interlock_warning_checkbox.isChecked() is False
|
||||
|
||||
|
||||
def test_beamline_state_manager_settings_warning_reenrolls_watched_state(qtbot, mocked_client):
|
||||
beamline_state_manager = create_widget(qtbot, BeamlineStateManager, client=mocked_client)
|
||||
beamline_state_manager.update_available_states({"states": [_limits_state()]}, {})
|
||||
fake_interlock = _FakeScanInterlock(
|
||||
enabled=True, states_watched={"limits": ["valid", "warning"]}
|
||||
)
|
||||
_install_fake_scan_interlock(beamline_state_manager, fake_interlock)
|
||||
pill = beamline_state_manager._state_pills["limits"]
|
||||
assert pill.interlock_statuses == ["valid", "warning"]
|
||||
|
||||
pill._interlock_warning_checkbox.setChecked(True)
|
||||
|
||||
assert fake_interlock.added[-1] == ("limits", ["valid"])
|
||||
assert beamline_state_manager._interlock_states == {"limits": ["valid"]}
|
||||
|
||||
|
||||
def test_beamline_state_manager_settings_warning_no_backend_when_not_watched(qtbot, mocked_client):
|
||||
beamline_state_manager = create_widget(qtbot, BeamlineStateManager, client=mocked_client)
|
||||
beamline_state_manager.update_available_states({"states": [_limits_state()]}, {})
|
||||
fake_interlock = _FakeScanInterlock()
|
||||
_install_fake_scan_interlock(beamline_state_manager, fake_interlock)
|
||||
pill = beamline_state_manager._state_pills["limits"]
|
||||
|
||||
pill._interlock_warning_checkbox.setChecked(True)
|
||||
|
||||
# Not watched yet: no backend write, but the preference is kept and used when locked.
|
||||
assert fake_interlock.added == []
|
||||
assert pill.interlock_statuses == ["valid"]
|
||||
|
||||
pill._interlock_button.click()
|
||||
assert fake_interlock.added == [("limits", ["valid"])]
|
||||
|
||||
|
||||
def test_beamline_state_manager_lock_uses_dialog_status_preference(
|
||||
qtbot, mocked_client, monkeypatch
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user