diff options
| author | Christian Kolset <ckolset@colostate.edu> | 2026-08-13 13:39:25 -0600 |
|---|---|---|
| committer | Christian Kolset <ckolset@colostate.edu> | 2026-08-13 13:39:25 -0600 |
| commit | 34c12b2b5b280206890cd03153b1c95116acc85e (patch) | |
| tree | 9b3dee7e0818d94c0bae87a35e7bf930a612ca2c /core/signal_processor.py | |
| parent | a6e812dcbf3f2fc27565e52b6c0c6f9b7e4363ee (diff) | |
Channels tab drag-to-reorder, Namespace absolute references, fix stale Channel ID renames
Generalized the Plot pane drag-to-reorder (_PaneDragHandle/_PlotDropContainer
-> _DragHandle/_DragReorderContainer) and reused it for the Channels tab's
derived-channel list; reordering also updates SignalProcessor's evaluation
order (list order matters for chained Channels) via new reorder_derived().
Namespace panel: added an ID column (bare channel_id, matching the actual
channels.get(...) script convention) and fixed the Source column for
Channels to show resolved absolute references (dev_id/ch_id for a Signal,
bare id for a chained Channel) instead of the operation kind, so a chain
is traceable by eye.
Fixed a real bug this surfaced: renaming a Channel's ID never propagated
to other Channels' sources, leaving dangling ("derived", old_id)
references that silently stopped updating. Added
SignalProcessor.rename_derived() to fix up sources plus carry the ring
buffer/latest-value cache to the new key, wired to DerivedBlock's Apply.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'core/signal_processor.py')
| -rw-r--r-- | core/signal_processor.py | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/core/signal_processor.py b/core/signal_processor.py index 8abaff8..4781e91 100644 --- a/core/signal_processor.py +++ b/core/signal_processor.py @@ -437,6 +437,47 @@ class SignalProcessor(QObject): self._derived = [d for d in self._derived if d.channel_id != channel_id] self._derived_bufs.pop(channel_id, None) + def rename_derived(self, old_id: str, new_id: str): + """Propagate a Channel ID rename to every other derived channel's + sources — otherwise anything chained from it keeps a dangling + ("derived", old_id) reference (SignalProcessor._evaluate_derived + looks sources up by exact match) and silently stops updating. + Also carries the ring buffer and latest-value cache over under the + new key so the rename doesn't reset plotted history or blank the + Value column for a poll cycle. Does NOT touch source_names or + expression/script text — those are display labels / user-authored + code, out of scope for an automatic rewrite.""" + if old_id == new_id: + return + with self._lock: + for dc in self._derived: + if dc.channel_id == new_id: + continue + new_sources = [ + ("derived", new_id) if d == "derived" and c == old_id else (d, c) + for d, c in dc.sources + ] + if new_sources != dc.sources: + dc.sources = new_sources + + buf = self._derived_bufs.pop(old_id, None) + if buf is not None: + self._derived_bufs[new_id] = buf + + entry = self._latest.pop(("derived", old_id), None) + if entry is not None: + self._latest[("derived", new_id)] = entry + + def reorder_derived(self, src_idx: int, dst_idx: int): + """Move the derived channel at src_idx to dst_idx — list order is + evaluation order (see _evaluate_derived): a Channel sourced from + another Channel needs that source evaluated earlier in the same + pass, or it reads a stale value and lags by one sample cycle.""" + with self._lock: + if 0 <= src_idx < len(self._derived) and 0 <= dst_idx < len(self._derived): + dc = self._derived.pop(src_idx) + self._derived.insert(dst_idx, dc) + def get_derived(self) -> List[DerivedChannel]: return list(self._derived) |
