summaryrefslogtreecommitdiff
path: root/daq_system/ui/device_panel.py
blob: 9b6c7e419579744c1586bee70f5ea198d513dfe0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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