summaryrefslogtreecommitdiff
path: root/daq_system/ui/device_panel.py
diff options
context:
space:
mode:
Diffstat (limited to 'daq_system/ui/device_panel.py')
-rw-r--r--daq_system/ui/device_panel.py127
1 files changed, 127 insertions, 0 deletions
diff --git a/daq_system/ui/device_panel.py b/daq_system/ui/device_panel.py
new file mode 100644
index 0000000..9b6c7e4
--- /dev/null
+++ b/daq_system/ui/device_panel.py
@@ -0,0 +1,127 @@
+"""
+ui/device_panel.py
+
+Left sidebar showing all registered devices with status indicators.
+"""
+
+from PyQt6.QtWidgets import (
+ QWidget, QVBoxLayout, QLabel, QPushButton,
+ QHBoxLayout, QScrollArea, QFrame
+)
+from PyQt6.QtCore import Qt, pyqtSignal
+
+from devices.base_device import DeviceStatus
+from devices.device_registry import DeviceRegistry
+from core.acquisition import AcquisitionEngine
+
+
+class DeviceCard(QFrame):
+ config_clicked = pyqtSignal(str)
+ toggle_clicked = pyqtSignal(str, bool)
+
+ STATUS_COLORS = {
+ DeviceStatus.CONNECTED: "#3fb950",
+ DeviceStatus.SIMULATED: "#58a6ff",
+ DeviceStatus.DISCONNECTED: "#8b949e",
+ DeviceStatus.CONNECTING: "#d29922",
+ DeviceStatus.ERROR: "#f85149",
+ }
+
+ def __init__(self, device, parent=None):
+ super().__init__(parent)
+ self.device = device
+ self.setObjectName("deviceCard")
+ self._build()
+
+ def _build(self):
+ layout = QVBoxLayout(self)
+ layout.setContentsMargins(8, 8, 8, 8)
+ layout.setSpacing(4)
+
+ # Header row
+ hdr = QHBoxLayout()
+ icon = QLabel(self.device.info.icon)
+ icon.setObjectName("deviceIcon")
+ hdr.addWidget(icon)
+
+ name = QLabel(self.device.info.name)
+ name.setObjectName("deviceName")
+ hdr.addWidget(name)
+ hdr.addStretch()
+
+ color = self.STATUS_COLORS.get(self.device.status, "#8b949e")
+ self.status_dot = QLabel("●")
+ self.status_dot.setStyleSheet(f"color: {color}; font-size: 10px;")
+ hdr.addWidget(self.status_dot)
+
+ layout.addLayout(hdr)
+
+ # ID + type
+ sub = QLabel(f"{self.device.info.device_id} · {self.device.info.device_type}")
+ sub.setObjectName("deviceSub")
+ layout.addWidget(sub)
+
+ # Channel count
+ ch_count = sum(1 for ch in self.device.info.channels if ch.enabled)
+ ch_lbl = QLabel(f"{ch_count} channel{'s' if ch_count != 1 else ''}")
+ ch_lbl.setObjectName("deviceChannelCount")
+ layout.addWidget(ch_lbl)
+
+ # Config button
+ cfg_btn = QPushButton("Configure")
+ cfg_btn.setObjectName("configButton")
+ cfg_btn.clicked.connect(lambda: self.config_clicked.emit(self.device.info.device_id))
+ layout.addWidget(cfg_btn)
+
+ def refresh_status(self):
+ color = self.STATUS_COLORS.get(self.device.status, "#8b949e")
+ self.status_dot.setStyleSheet(f"color: {color}; font-size: 10px;")
+
+
+class DevicePanel(QWidget):
+ config_requested = pyqtSignal(str)
+
+ def __init__(self, registry: DeviceRegistry, engine: AcquisitionEngine):
+ super().__init__()
+ self.registry = registry
+ self.engine = engine
+ self._cards = {}
+ self._build_ui()
+ self.refresh()
+
+ def _build_ui(self):
+ layout = QVBoxLayout(self)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.setSpacing(0)
+
+ header = QLabel(" DEVICES")
+ header.setObjectName("panelHeader")
+ layout.addWidget(header)
+
+ scroll = QScrollArea()
+ scroll.setWidgetResizable(True)
+ scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
+ scroll.setObjectName("deviceScroll")
+
+ self._container = QWidget()
+ self._inner = QVBoxLayout(self._container)
+ self._inner.setContentsMargins(8, 8, 8, 8)
+ self._inner.setSpacing(8)
+ self._inner.addStretch()
+
+ scroll.setWidget(self._container)
+ layout.addWidget(scroll)
+
+ def refresh(self):
+ # Remove old cards
+ for card in self._cards.values():
+ self._inner.removeWidget(card)
+ card.deleteLater()
+ self._cards.clear()
+
+ for dev in self.registry.all_instances():
+ card = DeviceCard(dev)
+ card.config_clicked.connect(self.config_requested.emit)
+ # Insert before the stretch
+ self._inner.insertWidget(self._inner.count() - 1, card)
+ self._cards[dev.info.device_id] = card