From 2b9943ba0d28449a590acfa8a41555b174b6ba84 Mon Sep 17 00:00:00 2001 From: Christian Kolset Date: Mon, 27 Apr 2026 16:53:14 -0600 Subject: Improved arduino interface. Now allowing the user to configure pins on the fly. --- ui/windows/devices_window.py | 96 +++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 28 deletions(-) (limited to 'ui/windows/devices_window.py') diff --git a/ui/windows/devices_window.py b/ui/windows/devices_window.py index fbaf9fa..8f6a48b 100644 --- a/ui/windows/devices_window.py +++ b/ui/windows/devices_window.py @@ -118,6 +118,17 @@ class DeviceRow(QFrame): class ChannelsTab(QWidget): """Shows all channels across all devices in an editable table.""" + channel_visibility_changed = pyqtSignal(str, str, bool) # dev_id, ch_id, enabled + + # Col indices + _C_DEVICE = 0 + _C_CH_ID = 1 + _C_ENABLED = 2 + _C_NAME = 3 + _C_UNIT = 4 + _C_MIN = 5 + _C_MAX = 6 + def __init__(self, registry: DeviceRegistry): super().__init__() self.registry = registry @@ -129,18 +140,23 @@ class ChannelsTab(QWidget): self._table = QTableWidget() self._table.setObjectName("channelTable") - self._table.setColumnCount(6) + self._table.setColumnCount(7) self._table.setHorizontalHeaderLabels( - ["Device", "Channel ID", "Name", "Unit", "Min", "Max"] + ["Device", "Channel ID", "On", "Name", "Unit", "Min", "Max"] ) - self._table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) - self._table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents) + hdr = self._table.horizontalHeader() + hdr.setSectionResizeMode(self._C_NAME, QHeaderView.ResizeMode.Stretch) + hdr.setSectionResizeMode(self._C_DEVICE, QHeaderView.ResizeMode.ResizeToContents) + hdr.setSectionResizeMode(self._C_CH_ID, QHeaderView.ResizeMode.ResizeToContents) + hdr.setSectionResizeMode(self._C_ENABLED, QHeaderView.ResizeMode.ResizeToContents) self._table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self._table.setAlternatingRowColors(True) self._table.verticalHeader().setVisible(False) + self._table.cellChanged.connect(self._on_cell_changed) lay.addWidget(self._table) def refresh(self): + self._table.blockSignals(True) self._table.setRowCount(0) row = 0 for dev in self.registry.all_instances(): @@ -150,35 +166,57 @@ class ChannelsTab(QWidget): dev_item = QTableWidgetItem(f"{dev.info.icon} {dev.info.device_id}") dev_item.setFlags(dev_item.flags() & ~Qt.ItemFlag.ItemIsEditable) dev_item.setForeground(QColor("#64748b")) - self._table.setItem(row, 0, dev_item) + self._table.setItem(row, self._C_DEVICE, dev_item) ch_item = QTableWidgetItem(ch.channel_id) ch_item.setFlags(ch_item.flags() & ~Qt.ItemFlag.ItemIsEditable) ch_item.setForeground(QColor(ch.color)) - self._table.setItem(row, 1, ch_item) + self._table.setItem(row, self._C_CH_ID, ch_item) + + # Enabled checkbox — centred in cell + chk_container = QWidget() + chk_lay = QHBoxLayout(chk_container) + chk_lay.setContentsMargins(0, 0, 0, 0) + chk_lay.setAlignment(Qt.AlignmentFlag.AlignCenter) + chk = QCheckBox() + chk.setChecked(ch.enabled) + dev_id_cap = dev.info.device_id + ch_id_cap = ch.channel_id + chk.toggled.connect( + lambda checked, d=dev_id_cap, c=ch_id_cap: self._on_enabled(d, c, checked) + ) + chk_lay.addWidget(chk) + self._table.setCellWidget(row, self._C_ENABLED, chk_container) name_item = QTableWidgetItem(ch.name) - self._table.setItem(row, 2, name_item) + name_item.setData(Qt.ItemDataRole.UserRole, (dev.info.device_id, ch.channel_id)) + self._table.setItem(row, self._C_NAME, name_item) unit_item = QTableWidgetItem(ch.unit) - self._table.setItem(row, 3, unit_item) + self._table.setItem(row, self._C_UNIT, unit_item) min_item = QTableWidgetItem(str(ch.min_value)) max_item = QTableWidgetItem(str(ch.max_value)) - self._table.setItem(row, 4, min_item) - self._table.setItem(row, 5, max_item) + self._table.setItem(row, self._C_MIN, min_item) + self._table.setItem(row, self._C_MAX, max_item) - # Store references for saving - name_item.setData(Qt.ItemDataRole.UserRole, (dev.info.device_id, ch.channel_id)) row += 1 - self._table.cellChanged.connect(self._on_cell_changed) + self._table.blockSignals(False) + + def _on_enabled(self, dev_id: str, ch_id: str, checked: bool): + dev = self.registry.get_instance(dev_id) + if dev: + ch = dev.get_channel(ch_id) + if ch: + ch.enabled = checked + self.channel_visibility_changed.emit(dev_id, ch_id, checked) def _on_cell_changed(self, row: int, col: int): - item = self._table.item(row, 2) # name col - if item is None: + name_item = self._table.item(row, self._C_NAME) + if name_item is None: return - ref = item.data(Qt.ItemDataRole.UserRole) + ref = name_item.data(Qt.ItemDataRole.UserRole) if ref is None: return dev_id, ch_id = ref @@ -188,27 +226,28 @@ class ChannelsTab(QWidget): ch = dev.get_channel(ch_id) if not ch: return - if col == 2: - ch.name = self._table.item(row, 2).text() - elif col == 3: - ch.unit = self._table.item(row, 3).text() - elif col == 4: + if col == self._C_NAME: + ch.name = self._table.item(row, self._C_NAME).text() + elif col == self._C_UNIT: + ch.unit = self._table.item(row, self._C_UNIT).text() + elif col == self._C_MIN: try: - ch.min_value = float(self._table.item(row, 4).text()) + ch.min_value = float(self._table.item(row, self._C_MIN).text()) except ValueError: pass - elif col == 5: + elif col == self._C_MAX: try: - ch.max_value = float(self._table.item(row, 5).text()) + ch.max_value = float(self._table.item(row, self._C_MAX).text()) except ValueError: pass class DevicesWindow(QWidget): - device_added = pyqtSignal() - device_removed = pyqtSignal(str) - device_reconfigured = pyqtSignal(str) - closed = pyqtSignal() + device_added = pyqtSignal() + device_removed = pyqtSignal(str) + device_reconfigured = pyqtSignal(str) + channel_visibility_changed = pyqtSignal(str, str, bool) # dev_id, ch_id, enabled + closed = pyqtSignal() def __init__(self, registry: DeviceRegistry, engine: AcquisitionEngine, parent=None): super().__init__(parent, Qt.WindowType.Window | Qt.WindowType.Tool) @@ -265,6 +304,7 @@ class DevicesWindow(QWidget): # Tab 2: Channels self._ch_tab = ChannelsTab(self.registry) + self._ch_tab.channel_visibility_changed.connect(self.channel_visibility_changed) tabs.addTab(self._ch_tab, " Channels ") tabs.currentChanged.connect(lambda i: self._ch_tab.refresh() if i == 1 else None) -- cgit v1.2.3