diff options
Diffstat (limited to 'ui/control_editor.py')
| -rw-r--r-- | ui/control_editor.py | 96 |
1 files changed, 31 insertions, 65 deletions
diff --git a/ui/control_editor.py b/ui/control_editor.py index 111a71f..d167517 100644 --- a/ui/control_editor.py +++ b/ui/control_editor.py @@ -204,31 +204,26 @@ class ControlEditorDialog(QDialog): root.addWidget(id_grp) - # ── Device & channel ──────────────────────────────────────────── + # ── Target signal ──────────────────────────────────────────────── + # Sourced from the same writable-channel set Configuration > Channels > + # Signals shows as "OUT" — the Signals tab is the central place hardware + # endpoints (including button targets) are registered. hw_grp = QGroupBox("Hardware Assignment") hw_form = QFormLayout(hw_grp); hw_form.setContentsMargins(10, 16, 10, 10) - self._dev_cb = QComboBox() - self._dev_cb.addItem("— none —", userData="") + self._target_cb = QComboBox() + self._target_cb.addItem("— none —", userData=("", "")) for dev in self.registry.all_instances(): - label = f"{dev.info.device_id} ({dev.info.name})" - self._dev_cb.addItem(label, userData=dev.info.device_id) - self._dev_cb.currentIndexChanged.connect(self._on_dev_changed) - hw_form.addRow("Device:", self._dev_cb) - - self._ch_cb = QComboBox() - self._ch_cb.setEditable(True) # allow typing custom pin like "D7" - self._ch_cb.setInsertPolicy(QComboBox.InsertPolicy.NoInsert) - hw_form.addRow("Channel / Pin:", self._ch_cb) + for ch in dev.info.channels: + if not ch.enabled or not ch.writable: + continue + label = f"{dev.info.device_id} / {ch.name} ({ch.channel_id})" + self._target_cb.addItem(label, userData=(dev.info.device_id, ch.channel_id)) + hw_form.addRow("Target Signal:", self._target_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) - hw_form.addRow(self._ch_hint) - root.addWidget(hw_grp) # ── Type-specific params ──────────────────────────────────────── @@ -256,7 +251,10 @@ class ControlEditorDialog(QDialog): _help = QLabel( "Runs every time this control changes value.\n" "Available: value, channel_id, device_id, vars (shared dict), " - "channels (latest values by channel_id), math" + "channels (latest values by channel_id), math\n" + "vars set here are readable from any Channel's script " + "(Configuration > Channels) via vars.get('key', default) — " + "this is how a button feeds a value into Channel math." ) _help.setObjectName("traceSource"); _help.setWordWrap(True) script_lay.addWidget(_help) @@ -316,21 +314,22 @@ class ControlEditorDialog(QDialog): self._type_cb.setCurrentIndex(idx) self._title_edit.setText(self.spec.title) - # Device - for i in range(self._dev_cb.count()): - if self._dev_cb.itemData(i) == self.spec.device_id: - self._dev_cb.setCurrentIndex(i); break - - # Channel (populated after device selection) - self._on_dev_changed() + # Target signal found = False - for i in range(self._ch_cb.count()): - if self._ch_cb.itemData(i) == self.spec.channel_id: - self._ch_cb.setCurrentIndex(i) + target = (self.spec.device_id, self.spec.channel_id) + for i in range(self._target_cb.count()): + if self._target_cb.itemData(i) == target: + self._target_cb.setCurrentIndex(i) found = True break - if not found: - self._ch_cb.setCurrentText(self.spec.channel_id) + if not found and self.spec.device_id: + # Not in the current writable-signal list (e.g. a legacy raw pin + # target, or the channel/device is now disabled/removed) — keep it + # as a synthetic entry so editing this control doesn't silently + # clear its saved hardware assignment. + label = f"{self.spec.device_id} / {self.spec.channel_id} (not currently available)" + self._target_cb.addItem(label, userData=target) + self._target_cb.setCurrentIndex(self._target_cb.count() - 1) self._active_low_chk.setChecked(bool(self.spec.active_low)) # Params @@ -351,50 +350,17 @@ class ControlEditorDialog(QDialog): self._title_edit.text() in CONTROL_TYPES: self._title_edit.setText(type_name) - def _on_dev_changed(self): - self._ch_cb.clear() - dev_id = self._dev_cb.currentData() - if not dev_id: - self._ch_hint.setText("No device selected — type a channel manually") - return - dev = self.registry.get_instance(dev_id) - if not dev: - return - # Add actual channels (skip disabled — can't be driven while switched - # off — and skip read-only channels — a control writes, so a channel - # with no write mapping should never be offered as a target) - for ch in dev.info.channels: - if not ch.enabled or not ch.writable: - continue - self._ch_cb.addItem(f"{ch.name} ({ch.channel_id})", - userData=ch.channel_id) - # For Arduino backends also suggest digital pins for output - if hasattr(dev, "backend") and dev.backend == "arduino": - self._ch_cb.insertSeparator(self._ch_cb.count()) - for pin in ["D5", "D6", "D7", "D8", "D9", "D10", "D11", "D13"]: - self._ch_cb.addItem(f"{pin} (digital out)", userData=pin) - self._ch_hint.setText( - "Analog pins (A0…) for reading.\n" - "Digital pins (D5…) for on/off output.\n" - "D9, D10, D11 support PWM." - ) - else: - self._ch_hint.setText("") - def _on_ok(self): ctype = self._type_cb.currentText() title = self._title_edit.text().strip() or ctype - # Resolve channel_id — prefer userData if it's a real combo item - ch_text = self._ch_cb.currentText().strip() - ch_data = self._ch_cb.currentData() - channel_id = ch_data if ch_data else ch_text.split()[0] # strip "(name)" part + dev_id, channel_id = self._target_cb.currentData() or ("", "") spec = ControlSpec( control_type=ctype, title=title, icon=CONTROL_ICONS.get(ctype, "⚙"), - device_id=self._dev_cb.currentData() or "", + device_id=dev_id, channel_id=channel_id, active_low=self._active_low_chk.isChecked(), on_action_script=self._script_edit.toPlainText().strip(), |
