diff options
| author | Christian Kolset <ckolset@colostate.edu> | 2026-07-29 14:22:46 -0600 |
|---|---|---|
| committer | Christian Kolset <ckolset@colostate.edu> | 2026-07-29 14:22:46 -0600 |
| commit | 34c8b0950398c07e84777479f3534615907f4f58 (patch) | |
| tree | 5050896bbd5c2a4fab0239c6456637ca22306156 /ui/control_panel.py | |
| parent | c98885f503a8a2eb4b691b41404231da8d2aeda5 (diff) | |
| parent | ad7f1c39ef473a327ca3b467b579be0099377f55 (diff) | |
Merge branch 'fix/run-stop-log-master-switch'
Diffstat (limited to 'ui/control_panel.py')
| -rw-r--r-- | ui/control_panel.py | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/ui/control_panel.py b/ui/control_panel.py index 2b936c4..4db18e3 100644 --- a/ui/control_panel.py +++ b/ui/control_panel.py @@ -154,6 +154,21 @@ class ControlWidget(QFrame): except Exception as e: print(f"[Control '{self.title}'] script error: {e}") + def safe_stop(self): + """ + Called on every control when the master Stop is pressed. + + Default: zero the output. Widgets with a latched running/enabled + state (OnOffSwitch, MotorControl, PwmControl) override this to go + through their own toggle handler, so UI state and the write stay + consistent. Widgets that only write on an explicit user action + (SetpointControl, AnalogOutputControl) override with a no-op — + there's no universally "safe" value to force onto an arbitrary + process setpoint or analog output, so Stop leaves them alone + rather than guessing. + """ + self._write(0.0) + # ══════════════════════════════════════════════════════════════════════════════ # On/Off Switch @@ -207,6 +222,9 @@ class OnOffSwitch(ControlWidget): w.style().unpolish(w); w.style().polish(w) self._write(self._logic_level(checked)) + def safe_stop(self): + self._btn.setChecked(False) # routes through _on_toggle: updates UI + writes off + # ══════════════════════════════════════════════════════════════════════════════ # Motor Control @@ -294,6 +312,10 @@ class MotorControl(ControlWidget): else: self._on_speed(self._slider.value()) + def safe_stop(self): + self._run_btn.setChecked(False) # routes through _on_run: stops + writes 0 + self._slider.setValue(0) + # ══════════════════════════════════════════════════════════════════════════════ # Setpoint Control @@ -386,6 +408,9 @@ class SetpointControl(ControlWidget): def _decrement(self): self._sp_spin.setValue(self._sp_spin.value() - self.step) + def safe_stop(self): + pass # no safe universal value for an arbitrary process setpoint — leave it + # ══════════════════════════════════════════════════════════════════════════════ # PWM Control @@ -455,6 +480,10 @@ class PwmControl(ControlWidget): self._en_btn.style().polish(self._en_btn) self._write(float(self._dc_slider.value()) if en else 0.0) + def safe_stop(self): + self._en_btn.setChecked(False) # routes through _on_enable: disables + writes 0 + self._dc_slider.setValue(0) + # ══════════════════════════════════════════════════════════════════════════════ # Generic Analog Output @@ -509,6 +538,9 @@ class AnalogOutputControl(ControlWidget): self._slider.setValue(max(0, min(1000, norm))) self._slider.blockSignals(False) + def safe_stop(self): + pass # only writes on explicit SET click — no safe universal value to force + # ══════════════════════════════════════════════════════════════════════════════ # Control Panel container @@ -566,6 +598,14 @@ class ControlPanel(QWidget): # ── Widget management ───────────────────────────────────────────────────── + def safe_stop_all(self): + """Master Stop — tell every control widget to go to a safe state.""" + for w in self._widgets: + try: + w.safe_stop() + except Exception as e: + print(f"[Control '{w.title}'] safe_stop failed: {e}") + def _make_wrapper(self, widget: ControlWidget, spec) -> QFrame: """Wrap a ControlWidget with Edit / Remove / reorder buttons.""" wrapper = QFrame(); wrapper.setObjectName("controlWidgetWrapper") |
