summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/__pycache__/add_device_dialog.cpython-312.pycbin29737 -> 29737 bytes
-rw-r--r--ui/__pycache__/control_editor.cpython-312.pycbin20099 -> 20704 bytes
-rw-r--r--ui/__pycache__/control_panel.cpython-312.pycbin42162 -> 42676 bytes
-rw-r--r--ui/__pycache__/main_window.cpython-312.pycbin25329 -> 26317 bytes
-rw-r--r--ui/add_device_dialog.py2
-rw-r--r--ui/control_editor.py7
-rw-r--r--ui/control_panel.py14
-rw-r--r--ui/main_window.py14
-rw-r--r--ui/plot_builder.py4
9 files changed, 36 insertions, 5 deletions
diff --git a/ui/__pycache__/add_device_dialog.cpython-312.pyc b/ui/__pycache__/add_device_dialog.cpython-312.pyc
index e9aab22..2da95a6 100644
--- a/ui/__pycache__/add_device_dialog.cpython-312.pyc
+++ b/ui/__pycache__/add_device_dialog.cpython-312.pyc
Binary files differ
diff --git a/ui/__pycache__/control_editor.cpython-312.pyc b/ui/__pycache__/control_editor.cpython-312.pyc
index 42855d5..ccecd3e 100644
--- a/ui/__pycache__/control_editor.cpython-312.pyc
+++ b/ui/__pycache__/control_editor.cpython-312.pyc
Binary files differ
diff --git a/ui/__pycache__/control_panel.cpython-312.pyc b/ui/__pycache__/control_panel.cpython-312.pyc
index 8761466..1c101a8 100644
--- a/ui/__pycache__/control_panel.cpython-312.pyc
+++ b/ui/__pycache__/control_panel.cpython-312.pyc
Binary files differ
diff --git a/ui/__pycache__/main_window.cpython-312.pyc b/ui/__pycache__/main_window.cpython-312.pyc
index a290571..d89b2e6 100644
--- a/ui/__pycache__/main_window.cpython-312.pyc
+++ b/ui/__pycache__/main_window.cpython-312.pyc
Binary files differ
diff --git a/ui/add_device_dialog.py b/ui/add_device_dialog.py
index 50f234d..7e8e935 100644
--- a/ui/add_device_dialog.py
+++ b/ui/add_device_dialog.py
@@ -401,7 +401,7 @@ class AddDeviceDialog(QDialog):
self.created_device = None
self.setWindowTitle("Add Device")
self.setMinimumSize(480, 460)
- self.resize(500, 520)
+ self.resize(500, 600)
self._build()
def _build(self):
diff --git a/ui/control_editor.py b/ui/control_editor.py
index 4d18aef..901d6f8 100644
--- a/ui/control_editor.py
+++ b/ui/control_editor.py
@@ -51,6 +51,7 @@ class ControlSpec:
icon: str = "⏻"
device_id: str = ""
channel_id: str = ""
+ active_low: bool = False
# Type-specific params
unit: str = ""
min_val: float = 0.0
@@ -206,6 +207,9 @@ class ControlEditorDialog(QDialog):
self._ch_cb.setInsertPolicy(QComboBox.InsertPolicy.NoInsert)
hw_form.addRow("Channel / Pin:", self._ch_cb)
+ self._active_low_chk = QCheckBox("Active-low output (ON sends LOW)")
+ hw_form.addRow("Polarity:", self._active_low_chk)
+
self._ch_hint = QLabel("")
self._ch_hint.setObjectName("traceSource")
self._ch_hint.setWordWrap(True)
@@ -255,6 +259,7 @@ class ControlEditorDialog(QDialog):
# Channel (populated after device selection)
self._on_dev_changed()
self._ch_cb.setCurrentText(self.spec.channel_id)
+ self._active_low_chk.setChecked(bool(self.spec.active_low))
# Params
for name, panel in self._param_panels.items():
@@ -263,6 +268,7 @@ class ControlEditorDialog(QDialog):
def _on_type_changed(self, type_name: str):
idx = list(_PARAM_PANELS.keys()).index(type_name)
self._stack.setCurrentIndex(idx)
+ self._active_low_chk.setEnabled(type_name == "On/Off Switch")
# Auto-set title if still default
if not self._title_edit.text() or \
self._title_edit.text() in CONTROL_TYPES:
@@ -309,6 +315,7 @@ class ControlEditorDialog(QDialog):
icon=CONTROL_ICONS.get(ctype, "⚙"),
device_id=self._dev_cb.currentData() or "",
channel_id=channel_id,
+ active_low=self._active_low_chk.isChecked(),
)
# Save type-specific params
panel = self._param_panels.get(ctype)
diff --git a/ui/control_panel.py b/ui/control_panel.py
index efd4f17..7a3e416 100644
--- a/ui/control_panel.py
+++ b/ui/control_panel.py
@@ -43,16 +43,24 @@ class ControlWidget(QFrame):
def __init__(self, title: str, icon: str = "⚙",
device_id: str = "", channel_id: str = "",
- registry: Optional[DeviceRegistry] = None):
+ registry: Optional[DeviceRegistry] = None,
+ active_low: bool = False):
super().__init__()
self.title = title
self.icon = icon
self.device_id = device_id
self.channel_id = channel_id
self.registry = registry
+ self.active_low = active_low
self.setObjectName("controlWidget")
self._build_frame()
+ def _logic_level(self, enabled: bool) -> float:
+ """Map logical ON/OFF to electrical level, respecting active-low outputs."""
+ if self.active_low:
+ return 0.0 if enabled else 1.0
+ return 1.0 if enabled else 0.0
+
def _build_frame(self):
"""Build the common outer frame; subclasses fill self._body."""
outer = QVBoxLayout(self)
@@ -155,7 +163,7 @@ class OnOffSwitch(ControlWidget):
# Re-polish so QSS picks up new objectName
for w in (self._btn, self._indicator, self._state_lbl):
w.style().unpolish(w); w.style().polish(w)
- self._write(1.0 if checked else 0.0)
+ self._write(self._logic_level(checked))
# ══════════════════════════════════════════════════════════════════════════════
@@ -568,6 +576,7 @@ class ControlPanel(QWidget):
spec = ControlSpec(
title=widget.title, icon=widget.icon,
device_id=widget.device_id, channel_id=widget.channel_id,
+ active_low=getattr(widget, "active_low", False),
)
wrapper = self._make_wrapper(widget, spec)
self._widgets.append(widget)
@@ -673,6 +682,7 @@ def _build_widget_from_spec(spec, registry: DeviceRegistry) -> Optional[ControlW
device_id=spec.device_id,
channel_id=spec.channel_id,
registry=registry,
+ active_low=getattr(spec, "active_low", False),
)
t = spec.control_type
ttl = spec.title
diff --git a/ui/main_window.py b/ui/main_window.py
index 9df7ef7..d4bb203 100644
--- a/ui/main_window.py
+++ b/ui/main_window.py
@@ -92,6 +92,12 @@ class MainWindow(QMainWindow):
self._log_btn.setEnabled(False); self._log_btn.clicked.connect(self._toggle_log)
tb.addWidget(self._log_btn)
+ self._clear_btn = QPushButton("⌫ Clear")
+ self._clear_btn.setObjectName("toolbarSectionBtn")
+ self._clear_btn.setToolTip("Clear plot history")
+ self._clear_btn.clicked.connect(self._clear_history)
+ tb.addWidget(self._clear_btn)
+
tb.addWidget(_sep())
dev_btn = QPushButton("⊞ Devices")
@@ -265,12 +271,15 @@ class MainWindow(QMainWindow):
processor=self.processor,
control_panel=self._ctrl,
settings_ref=self._settings,
+ engine=self.engine,
)
if plot_cfg:
self._chart.apply_layout(plot_cfg)
else:
self._chart.refresh()
# Refresh open windows
+ if self._win_devices:
+ self._win_devices.refresh()
if self._win_plot:
self._win_plot.refresh_channels()
self._status.setText(f"Profile loaded: {profile.name}")
@@ -309,6 +318,11 @@ class MainWindow(QMainWindow):
self._log_btn.setEnabled(False); self._clock.stop()
self._status.setText("Stopped")
+ def _clear_history(self):
+ self.engine.clear_history()
+ self._chart.refresh()
+ self._status.setText("History cleared.")
+
def _toggle_log(self, c: bool):
if c:
p = self.engine.start_logging(
diff --git a/ui/plot_builder.py b/ui/plot_builder.py
index beda116..ad6d231 100644
--- a/ui/plot_builder.py
+++ b/ui/plot_builder.py
@@ -356,8 +356,8 @@ class PlotBuilderWindow(QWidget):
else build_default_layout(registry, processor)
self.setWindowTitle("Plot Builder")
- self.setMinimumSize(700, 560)
- self.resize(800, 680)
+ self.setMinimumSize(700, 780)
+ self.resize(800, 780)
self._blocks: List[PlotBlock] = []
self._build()
self._populate()