From a0473245f1f453bfc87ea1bc9bd479311e8a944b Mon Sep 17 00:00:00 2001 From: Christian Kolset Date: Sun, 20 Sep 2026 23:45:18 -0600 Subject: Persist dock layout to profiles; dedupe port names; Channels-tab Create button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix duplicated device names ("FT231X USB UART - FT231X USB UART (...)") — pyserial on Linux often reports the same udev model string twice for cheap FTDI/CH340-style adapters. Collapse it at the list_ports() source so every consumer (device auto-name, port picker) benefits. - Save Control Panel / Namespace dock area, floating geometry, visibility, size and order to .labui profiles via QMainWindow.saveState()/ restoreState(), round-tripped through the existing Profile.settings passthrough (self._settings) — no profile schema change needed. - Channels tab: replace the per-row Signal ⊕ button (and its pinned/ frozen-column overlay) with a single "Create Channel" button below the Namespace panel. Select one or more Signal/Channel rows (multi-select now supported) and click it — selected rows become the new Channel's sources, or an empty Channel is created if nothing's selected. Fixes a bug in the process: the multi/zero-source path defaulted to kind="expression" with no expression text, which fails to compile and silently dropped the channel; use kind="none" instead, which the user then edits in the Channels pane. NamespacePanel itself (ui/namespace_panel.py) goes back to a plain read-only reference widget — the create-channel button and its logic live entirely in ConfigWindow (config_window.py), so the shared dockable Namespace panel on the main window is unaffected. Co-Authored-By: Claude Sonnet 5 --- api_layers/arduino_layer.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'api_layers/arduino_layer.py') diff --git a/api_layers/arduino_layer.py b/api_layers/arduino_layer.py index 07520d6..cd7cb92 100644 --- a/api_layers/arduino_layer.py +++ b/api_layers/arduino_layer.py @@ -81,6 +81,18 @@ except ImportError: _SERIAL_AVAILABLE = False +def _dedupe_description(desc: str) -> str: + """pyserial on Linux often reports a USB-serial adapter's description as + "X - X" (same udev model string used for both halves when there's no + separate manufacturer/interface field — common on cheap FTDI/CH340 + clones), which then reads as a literal duplicate everywhere this + description gets shown (device name, port picker). Collapse it.""" + parts = desc.split(" - ") + if len(parts) == 2 and parts[0].strip() == parts[1].strip(): + return parts[0].strip() + return desc + + class ArduinoLayer: DEFAULT_ANALOG_PINS = ["A0", "A1", "A2", "A3", "A4", "A5"] @@ -552,7 +564,7 @@ class ArduinoLayer: return [] try: return [ - (p.device, p.description or "") + (p.device, _dedupe_description(p.description or "")) for p in serial.tools.list_ports.comports() ] except Exception as e: -- cgit v1.2.3