<feed xmlns='http://www.w3.org/2005/Atom'>
<title>labUI.git/ui/windows/plot_window.py, branch main</title>
<subtitle>Data acquisition program written in Python for use with serial communication devices.
</subtitle>
<id>https://git.kolset.xyz/labUI.git/atom?h=main</id>
<link rel='self' href='https://git.kolset.xyz/labUI.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/'/>
<updated>2026-07-29T19:10:35Z</updated>
<entry>
<title>Rework channel labeling and add source picker to virtual-channel creation</title>
<updated>2026-07-29T19:10:35Z</updated>
<author>
<name>Christian Kolset</name>
<email>ckolset@colostate.edu</email>
</author>
<published>2026-07-29T19:10:35Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=2c6b4b751ffdd1156254b31745597654b5f2e286'/>
<id>urn:sha1:2c6b4b751ffdd1156254b31745597654b5f2e286</id>
<content type='text'>
Relabel every channel picker/header to "NAME (DEVICE/SIGNAL)" instead of
the previous "DEVICE/SIGNAL (NAME)" ordering, consistently across
channels_window.py (_channel_combo, ChannelPickerDialog,
ChannelPipelineBlock header), plot_builder.py, plot_config.py,
control_editor.py, and plot_window.py.

While touching each of those pickers, added the missing `.enabled`
filter that _make_picker()/_x_cb/_build_channel_picker lacked (the
default-layout builders already filtered disabled channels; these
manual "add channel to pane" pickers didn't).

Devices window Signals tab: removed the separate "Signal ID" column
(folded into the existing non-editable Device column instead of the
editable Name column, to avoid corrupting the in-place channel rename
feature that column already supports).

Channels window Virtual Channels pane: added a "Source" dropdown next
to "+ Add Channel" — picking a source pre-seeds the new derived
channel with it via DerivedBlock._add_src(); leaving it on the default
"none" entry keeps today's behavior of creating an empty channel.

Note: docs/ToDo.md's "Channels window UI" items referred to the *live*
UI (this window's PipelineTab + the Devices window's Signals tab), not
SignalsListTab in this same file, which its own module docstring flags
as dead/unused code kept only for old-profile compatibility — verified
by grepping for any instantiation of it (none exist).

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Merge plot-builder-layout-feature: layout canvas drag-drop fixes</title>
<updated>2026-06-04T18:41:14Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-04T18:41:14Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=254df94e71586216991486242ab4064706177465'/>
<id>urn:sha1:254df94e71586216991486242ab4064706177465</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Fix split zone detection and canvas-edge squeeze behavior</title>
<updated>2026-06-04T18:13:47Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-04T18:13:47Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=d2a555896e11a315084a00c34ef0ec77b25dcf70'/>
<id>urn:sha1:d2a555896e11a315084a00c34ef0ec77b25dcf70</id>
<content type='text'>
Split zone was unreachable: squeezed between outer squeeze (1/6) and
center (1/3), leaving a 1/6-wide band impossible to target reliably.
Users hitting the tile edge always triggered squeeze instead of split.

- Remove squeeze from inside-tile detection entirely. Split now owns
  the outer 1/3 of each tile edge — large, easy to target. Center
  keeps the inner 1/3. Squeeze remains gap-detection only (second pass).

- Fix canvas-edge squeeze (no adjacent neighbor): instead of bisecting
  the edge tile, wrap the entire remaining tree in a new directional
  split with the dragged tile placed at the outer position, then
  equalize — all tiles end up equal size.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fix layout canvas drag-drop: zone logic, pop-out bug, canvas height</title>
<updated>2026-06-04T17:39:33Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-04T17:39:33Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=0388bebbc806d23abab945d52a0f285f966b412a'/>
<id>urn:sha1:0388bebbc806d23abab945d52a0f285f966b412a</id>
<content type='text'>
- Fix squeeze zone pop-out: _adjacent_tile used self._drag_tile (already
  None at drop time) to exclude the dragged tile from neighbor candidates.
  Pass dragged_idx explicitly via exclude_idx param instead.

- Swap split/squeeze detection areas: outer 1/6 now triggers squeeze
  (insert-between), inner 1/6→1/3 band triggers split (bisect target).

- Extend squeeze detection to gaps between tiles and canvas edges via a
  second pass in _zone_at that expands tile rects by _LC_GAP+2 and finds
  the closest outside edge. Canvas-edge squeeze falls through to bisect.

- Dynamic canvas height: sync_panes sets height to
  max(160, n*(min_tile+gap)+2*gap) so 4+ panes never get crushed below
  minimum tile size.

- Remove _tree_grid_size cap of 12: LCM was truncated prematurely,
  causing unequal rowspans in the strip chart for 5+ panes.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fix virtual channels not appearing in Plot Builder</title>
<updated>2026-06-03T23:11:41Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-03T23:11:41Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=a3ff221496f58d67ac962bfa6d011cc3e9d6ad3d'/>
<id>urn:sha1:a3ff221496f58d67ac962bfa6d011cc3e9d6ad3d</id>
<content type='text'>
Root cause: PlotWindow deepcopied _chart._cfg on init, so refresh_channels()
operated on a stale copy. Also, when _win_plot was None, _on_derived_changed
did nothing to prepare the config for when it opened.

Fix:
- refresh_channels() now owns the derived-pane sync: adds panes for new
  virtual channels (updating BSP tree), removes panes for deleted ones
- _open_plot always passes current _chart._cfg reference then calls
  refresh_channels() so derived panes sync on every open
- _on_derived_changed syncs cfg reference before calling refresh_channels()

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fix horizontal zone detection for wide/short tiles</title>
<updated>2026-06-03T22:40:11Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-03T22:40:11Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=7651f515728533506391e6cc719fe8ff32c339e7'/>
<id>urn:sha1:7651f515728533506391e6cc719fe8ff32c339e7</id>
<content type='text'>
_zone_at used absolute pixel distance to pick dominant axis, which always
favoured the short (vertical) axis for landscape tiles. Replaced with
normalized fraction (dist/dimension), so left/right zones are accessible
on wide tiles.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Three-zone drop system: squeeze, split, center</title>
<updated>2026-06-03T22:35:15Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-03T22:35:15Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=f60de21eeaa50f847108a9c103934cc8da7352fb'/>
<id>urn:sha1:f60de21eeaa50f847108a9c103934cc8da7352fb</id>
<content type='text'>
Zone layout (outer to inner per edge):
  0–1/6    squeeze (amber): insert dropped tile between two existing tiles
  1/6–1/3  split (blue):    bisect the target tile 50/50
  1/3–2/3  center (green):  swap/move

Squeeze behaviour: find the tile adjacent to the target in the drop
direction; insert dragged tile to the opposite side of that neighbor
so it lands visually between them. Falls back to split when no neighbor
exists (edge tile).

- _zone_at: returns "squeeze_*"/"split_*"/"center" with dominant-axis
  selection (nearest edge wins)
- _adjacent_tile: finds geometrically adjacent tile by pixel proximity
- _do_drop: routes squeeze→insert-at-neighbor, split→bisect, center→swap
- paintEvent: amber/blue/green per zone type

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add center-zone move (swap); restore center drop zone</title>
<updated>2026-06-03T22:23:35Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-03T22:23:35Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=f007593abc9a666df85120e08c7f1d327d9215da'/>
<id>urn:sha1:f007593abc9a666df85120e08c7f1d327d9215da</id>
<content type='text'>
- Edge zones (left/right/top/bottom): split target tile equally
- Center zone: swap dragged and target tile positions in BSP tree
  (tree structure preserved, only leaf pane values exchanged)
- Center overlay: green highlight (vs blue for split zones)
- _tree_swap: immutable swap of two leaf pane values

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Equalize tile sizes after every BSP tree operation</title>
<updated>2026-06-03T22:17:58Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-03T22:17:58Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=903df67b153ca4af877ba0b534d4802d74cf34df'/>
<id>urn:sha1:903df67b153ca4af877ba0b534d4802d74cf34df</id>
<content type='text'>
After each drag-drop, add, or remove, walk the tree and reset each split's
ratio to left_leaves/(left_leaves+right_leaves). This distributes space
equally per pane regardless of the prior tree structure.

- _tree_equalize_ratios: recomputes all ratios bottom-up by leaf count
- _tree_leaf_count: counts leaves in a subtree
- _tree_grid_size: uses LCM of split denominators (capped at 12) instead
  of 2^depth, giving exact integer rowspans for equal distributions
- _tree_default: balanced binary tree + equalize (not uneven chain)
- Applied in _do_drop, _add_pane, _rm

Result: 3 side-by-side panes → equal widths; any mixed layout → equal area.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Replace grid-snap canvas with BSP-tree drag-to-split tiling</title>
<updated>2026-06-03T21:20:45Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-06-03T21:20:45Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=216a278102e3f63f155d76d62790a3ca60fcec02'/>
<id>urn:sha1:216a278102e3f63f155d76d62790a3ca60fcec02</id>
<content type='text'>
Dragging a tile to the edge (left/right/top/bottom) of another tile
splits that tile's space and inserts the dragged tile on that side.
Drop zones occupy the outer third of each tile edge; center has no zone.
Ghost overlay shows the split target during drag.

Data model: LayoutConfig.tree (BSP tree as nested dict). PaneSpec.row/col
removed. strip_chart uses tree_to_grid() → rowspan/colspan for pyqtgraph.
Backward compat: tree=None falls back to layout_mode stacking path.

Example: 3 stacked → drag Tile 3 to left of Tile 1 → Tile 3|Tile 1 on
top (side-by-side), Tile 2 spans full bottom.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
