style(dialogs): unify picker tables (selection, edit, sort, header)#188
style(dialogs): unify picker tables (selection, edit, sort, header)#188facontidavide wants to merge 3 commits into
Conversation
Bring the topic/channel/camera/sequence picker tables onto one idiom: - Multi-select pickers all use MultiSelection (bare click toggles/accumulates) instead of ExtendedSelection (bare click silently clears the prior pick). Converts ros2 listRosTopics and mosaico topicTable. - Every picker gets NoEditTriggers, SelectRows, verticalHeaderVisible=false, and sortingEnabled=true (Qt's default indicator starts the table sorted by column 0 ascending). Fixes foxglove/pj_bridge topicsList and webrtc camerasList, which were accidentally editable and had no consistent header. - mosaico seqTable intentionally stays SingleSelection; mosaico sorting stays off (its index-based setVisibleRows filtering would desync under re-sort). Per-column resize-to-content is deliberately not addressed here: column sizing is owned by the host's installTreeLikeHeader() and cannot be expressed in a .ui file. That is tracked as a follow-up SDK protocol change (see docs/superpowers/specs/2026-07-03-dialog-table-column-resize-mode-design.md). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Design and TDD implementation plan for a follow-up SDK protocol addition that lets a plugin declare per-column Qt resize modes for dialog tables (name column Stretch, short data columns ResizeToContents) — the one picker-table axis that cannot be set from a .ui file because column sizing is owned by the host's installTreeLikeHeader(). Additive, header-only WidgetData::setColumnResizeMode / WidgetDataView:: columnResizeModes across plotjuggler_sdk -> PJ4 -> pj-official-plugins; no compiled-ABI break. Not yet implemented; this only captures the approved design. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codex review follow-up (pushed 973a78c)An independent Codex review flagged a real issue in the original branch: the host realizes plugin Per-picker selection contract (verified in code):
Fix in 973a78c: drop the Follow-up (not this PR): |
Follow-up: mcap + ros2 sort now fixed in-PR (0b994d3)Digging into the two pre-existing index-based pickers, the desync turned out to be latent behind a coincidence, not a live bug: both row vectors are already name-sorted (mcap Rather than leave that fragility, per request this PR now drops Final state — built-in sort is on iff selection restore is text-based:
|
The pickers now keep Qt's built-in column sorting (sortingEnabled, default
column-0 ascending) AND restore selection correctly, by identifying the
selection by first-column text instead of row index.
Background: the host realizes the .ui via QUiLoader, which honors sortingEnabled
and gives the widget a *sorted* view. Any selection restored by row index
(setSelectedRows) then desyncs — the plugin's row vector stays in its own order
while the widget re-orders. Restoring by text (setSelectedItems) is
sort-agnostic: the host matches items by their first-column string. This is the
same pattern foxglove/pj_bridge already use.
- ros2 listRosTopics: drop the name->index translation (and the now-unused
ordered_names vector); hand the host the selected topic names directly.
- webrtc camerasList: collect the selected rows' unique display labels (1:1 with
the stream id within a render) instead of row indices. Read-back already maps
labels back to ids, so the round-trip stays lossless.
Neither plugin uses setVisibleRows/setDisabledRows, so selection was their only
index dependency — converting it makes built-in sort fully safe. Verified:
webrtc compiles clean under -Werror -Wconversion.
Deferred (need cross-repo work, not in this PR): mcap tableWidget also disables
empty channels by row index (setDisabledRows, no text-keyed equivalent yet), and
mosaico filters by row index (setVisibleRows). Making those sort-correct wants
plugin-owned onHeaderClicked sorting, which needs the host to wire
QHeaderView::sectionClicked -> onHeaderClicked (declared in the SDK but currently
undelivered for tables) plus a sort-indicator API.
Docs: correct foxglove topicsList to 3 columns {Topic Name, DataType, Encoding}.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0b994d3 to
9c41ae1
Compare
Course correction: pickers are now genuinely sortable (force-pushed, 9c41ae1)I initially misread the goal and removed built-in sorting to dodge the index-desync bug. That was backwards — the ask is for sortable columns (default column-0). I've dropped that detour (force-pushed) and instead fixed the root cause the right way: restore selection by first-column text, not row index, so it survives Qt's built-in sort. This is the same pattern foxglove/pj_bridge already use. Now sortable (built-in sort on, default column 0):
Deferred to a follow-up (need cross-repo work):
Branch (3 commits): unify pickers → resize-mode docs → make ros2/webrtc sortable. mcap/mosaico left exactly as they were on |
What
Brings the topic / channel / camera / sequence picker tables across the plugin dialogs onto one consistent idiom, and captures a follow-up SDK design for the one axis that can't live in a
.uifile (per-column resize behavior).Picker idiom (the 5 multi-select lists)
All now share: MultiSelection · SelectRows · NoEditTriggers · sortingEnabled · verticalHeaderVisible=false.
topicsListtopicsListcamerasListlistRosTopicstopicTableWhy MultiSelection over ExtendedSelection: in a picker, a bare click under ExtendedSelection silently clears the previous selection — a footgun when users expect to accumulate picks. MultiSelection makes a bare click toggle/accumulate, which matches the "Select one or multiple…" labels these dialogs already show.
Deliberate exceptions (unchanged):
seqTablestays SingleSelection (single-select by design, now explicit).setVisibleRows, and user re-sorting would desync that index mapping.Not addressed here (tracked)
Per-column resize-to-content (e.g. MCAP
Encoding,Msg Counthugging their content while the name column stretches) can't be expressed in a.uifile — column sizing is owned by the host'sinstallTreeLikeHeader(). The second commit adds a design spec + TDD implementation plan for an additive, header-onlyWidgetData::setColumnResizeMode/WidgetDataView::columnResizeModesprotocol addition spanningplotjuggler_sdk→PJ4→ this repo. Not implemented in this PR.Notes
.uifiles are embedded verbatim and parsed at runtime (nouic); all 5 were validated well-formed..uiattributes + docs.🤖 Generated with Claude Code