""" ui/config_dialog.py — Per-device configuration dialog. """ from PyQt6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTabWidget, QWidget, QFormLayout, QLineEdit, QDoubleSpinBox, QCheckBox, QScrollArea ) from PyQt6.QtCore import Qt class DeviceConfigDialog(QDialog): def __init__(self, device, parent=None): super().__init__(parent) self.device = device self.setWindowTitle(f"Configure: {device.info.name} [{device.info.device_id}]") self.setMinimumSize(500, 400) self._build() def _build(self): layout = QVBoxLayout(self) tabs = QTabWidget() # Tab 1: Device-specific config widget dev_tab = QScrollArea() dev_tab.setWidgetResizable(True) dev_tab.setWidget(self.device.get_config_widget()) tabs.addTab(dev_tab, "Device Settings") # Tab 2: Channel config ch_tab = self._build_channel_tab() tabs.addTab(ch_tab, "Channels") layout.addWidget(tabs) # Buttons btn_row = QHBoxLayout() btn_row.addStretch() ok = QPushButton("Close") ok.setDefault(True) ok.clicked.connect(self.accept) btn_row.addWidget(ok) layout.addLayout(btn_row) def _build_channel_tab(self): w = QWidget() layout = QVBoxLayout(w) for ch in self.device.info.channels: grp_layout = QFormLayout() name_edit = QLineEdit(ch.name) unit_edit = QLineEdit(ch.unit) en_check = QCheckBox() en_check.setChecked(ch.enabled) lo_spin = QDoubleSpinBox() lo_spin.setRange(-1e9, 1e9) lo_spin.setValue(ch.alarm_low or 0.0) hi_spin = QDoubleSpinBox() hi_spin.setRange(-1e9, 1e9) hi_spin.setValue(ch.alarm_high or 100.0) grp_layout.addRow(f"[{ch.channel_id}] Name:", name_edit) grp_layout.addRow("Unit:", unit_edit) grp_layout.addRow("Enabled:", en_check) grp_layout.addRow("Alarm Low:", lo_spin) grp_layout.addRow("Alarm High:", hi_spin) def make_apply(c, ne, ue, ec, ls, hs): def apply(): c.name = ne.text() c.unit = ue.text() c.enabled = ec.isChecked() c.alarm_low = ls.value() c.alarm_high = hs.value() return apply apply_btn = QPushButton("Apply") apply_btn.clicked.connect(make_apply(ch, name_edit, unit_edit, en_check, lo_spin, hi_spin)) grp_layout.addRow(apply_btn) layout.addLayout(grp_layout) layout.addStretch() return w # ------------------------------------------------------------------ # # Add Device Dialog # # ------------------------------------------------------------------ # """ ui/add_device_dialog.py — Dialog for adding a new device to the system. """ from PyQt6.QtWidgets import ( QDialog, QVBoxLayout, QFormLayout, QComboBox, QLineEdit, QCheckBox, QSpinBox, QPushButton, QHBoxLayout, QLabel ) from devices.device_registry import DeviceRegistry from devices.analog_input import AnalogInputDevice from devices.digital_io import DigitalIODevice from devices.temperature import TemperatureDevice from devices.serial_device import SerialDevice DEVICE_CONSTRUCTORS = { "Analog Input": AnalogInputDevice, "Digital I/O": DigitalIODevice, "Temperature": TemperatureDevice, "Serial / UART": SerialDevice, } class AddDeviceDialog(QDialog): def __init__(self, registry: DeviceRegistry, parent=None): super().__init__(parent) self.registry = registry self.created_device = None self.setWindowTitle("Add Device") self.setMinimumWidth(340) self._build() def _build(self): layout = QVBoxLayout(self) form = QFormLayout() self.type_cb = QComboBox() self.type_cb.addItems(list(DEVICE_CONSTRUCTORS.keys())) form.addRow("Device Type:", self.type_cb) self.id_edit = QLineEdit() self.id_edit.setPlaceholderText("e.g. ai_1") form.addRow("Device ID:", self.id_edit) self.ch_spin = QSpinBox() self.ch_spin.setRange(1, 16) self.ch_spin.setValue(4) form.addRow("# Channels:", self.ch_spin) self.sim_check = QCheckBox("Simulation Mode") self.sim_check.setChecked(True) form.addRow(self.sim_check) layout.addLayout(form) btns = QHBoxLayout() btns.addStretch() cancel = QPushButton("Cancel") cancel.clicked.connect(self.reject) add = QPushButton("Add") add.setDefault(True) add.clicked.connect(self._on_add) btns.addWidget(cancel) btns.addWidget(add) layout.addLayout(btns) def _on_add(self): dev_type = self.type_cb.currentText() dev_id = self.id_edit.text().strip() or f"dev_{len(self.registry)}" cls = DEVICE_CONSTRUCTORS[dev_type] try: dev = cls( device_id=dev_id, num_channels=self.ch_spin.value(), simulate=self.sim_check.isChecked() ) self.created_device = dev self.accept() except Exception as e: from PyQt6.QtWidgets import QMessageBox QMessageBox.critical(self, "Error", str(e))