From c572ec280fd7db25f30bbeabaa707424b16b53d7 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Mon, 2 Nov 2026 19:28:40 +0100 Subject: [PATCH] docs: design spec for the badge bar, readouts dock and slide-over panel Co-Authored-By: Claude Opus 4.6 --- .../specs/2026-11-02-ui-badges-dock-design.md | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 docs/superpowers/specs/2026-11-02-ui-badges-dock-design.md diff --git a/docs/superpowers/specs/2026-11-02-ui-badges-dock-design.md b/docs/superpowers/specs/2026-11-02-ui-badges-dock-design.md new file mode 100644 index 0000000..c089c63 --- /dev/null +++ b/docs/superpowers/specs/2026-11-02-ui-badges-dock-design.md @@ -0,0 +1,175 @@ +# Badge bar, readouts dock and slide-over panel -- design + +Date: 2026-11-02. Status: approved in conversation, awaiting written-spec review. + +## Goal + +Replace the sidebar's tab switcher and the separate events pane with a layout built the way bench +scopes build theirs: setup is reached by *the object it configures* (a badge under the plot), results +are always on screen (a compact dock), and anything bigger than a readout opens in one slide-over +panel. The sidebar tabs and the left events pane go away. + +## Why (the problems, as found in the code) + +- **Unreadable tab titles.** `side_view` is pinned at 320 px (`min-sidebar-width` = `max-sidebar-width` + in `main-window.ui`), so four text tabs ("Measure / Signals / Analog out / Digital I/O") ellipsize, + and a source can add more. +- **Hard to find things.** The Signals tab stacks a trigger form of up to 15 rows (plus two + expanders) on top of the signal list. Cursors and measurements are in Measure, source controls are + in their own tabs, the header is icon-only, and the trigger/cursor toggles live apart from their + panels. +- **The events pane is a different application.** A `GtkPaned` + `GtkRevealer` on the left with its + own bold title and header, a dragged width that is not saved, thumbnails the rest of the UI does + not have, and a header toggle that is hidden until events exist. + +## State of the art this follows + +- Tektronix 5/6 Series: a badge bar under the waveform (a badge per channel/math waveform, plus + Horizontal, Trigger, Acquisition badges); a tap opens *only that item's* settings; results + (measurements, cursors, search) are a separate bar that does not cover the waveform. +- Scopy and PicoScope 7: a channel list at the edge and a settings panel that slides in for the + selected item (PicoScope lets it overlay or squeeze the trace). +- Saleae Logic 2: one side panel at a time; decoded results also in a list beside the waveform. +- Keysight InfiniiVision: dialogs that can be undocked so cursor and measurement values show together. + +## Layout + +``` +┌ header: [window 2 s ▾] [Trigger] [Pause] [Cursors] [Dock] [☰] ┐ +├──────────────────────────────────────────────┬────────────────────┤ +│ plot rows ┌───────────┐ │ READOUTS │ +│ │ slide-over│ │ cursors, measures │ +│ │ settings │ ├────────────────────┤ +│ └───────────┘ │ EVENTS (n) │ +├───────────────────────────────────────────────┴────────────────────┤ +│ [●sine][●square][+] … [Trigger ▸][Source ▸]│ +├ status line ───────────────────────────────────────────────────────┤ +``` + +### Header bar + +Keeps the time-window control, the Trigger, Pause and Cursors toggles and the overflow menu. The +Events toggle is removed (Events is always in the dock). The sidebar toggle becomes the **Dock** +toggle, so a narrow window can still hide the dock. There is no "Window" badge: the header's control +is the timebase, and a second one would duplicate it. + +### Right dock ("Readouts" and "Events") + +- Fixed width, about 280 px; always on screen, shown but insensitive until the stream has signals + ("disable, do not hide"). It stays an `AdwOverlaySplitView` sidebar, which already gives it its + own fixed width, the hide toggle and the overlay behaviour on a narrow window + (`invariants-plot-and-layout.md`). +- **Readouts** (top): the active cursor values and measurement values, read-only, one compact line per + value, through the one formatter both panes share (`invariants-readouts-and-cursors.md`). + An "Edit" affordance opens the slide-over's `measure` or `cursors` page; clicking a measurement row + opens that measurement's editor. +- **Events** (bottom): compact rows -- title, time, a small marker; no thumbnails. Insensitive outside + trigger mode. A "Manage" affordance opens the slide-over's `events` page. + +### Badge bar + +A fixed-height row between the plot and the status line. + +- **Signals** (left): one badge per enabled signal, up to 6; beyond that a single "N signals" badge. + A badge shows a colour dot and the name, is a drag handle (reorder, or drop on a plot row, which + replaces today's drag from the signal list), and opens that signal's page (colour, calibration, + row, math). A trailing `+` opens the `signals` page (the full list, to enable more; the math editor + entry). +- **System** (right): **Trigger** shows its state (off / armed / triggered) and opens the trigger + form; **Source** shows the connection state and the source name and opens that source's pages + (`SourcePanel` pages, behind a small segmented switch inside the panel when there are several, as + E-1608 has Analog out and Digital I/O). + +### Slide-over panel + +- Overlays the plot's right edge (about 360 px wide), never the dock; one page at a time; Esc or a + click outside closes it. The plot is not resized by it. +- Pages, by id: `trigger`, `signal:`, `signals`, `measure`, `cursors`, `events`, + `source-`. Each page has its own scroller, so a tall page does not leave a shorter one scrolled + (the reason the sidebar had a scroller per page). +- Content: the trigger form (conditional rows, Advanced, Search the buffer), signal and calibration + settings, measurement add/edit/remove and statistics, cursor options, event actions (Live, Compare, + Accumulate), the math editor entry, and source pages. + +### Status line + +Unchanged. + +## Components + +New files, because `ui.cpp` is already very large. + +| Unit | File | Responsibility | +| --- | --- | --- | +| `BadgeBar` | `ui_badges.cpp` | Builds signal / Trigger / Source badges from the model; emits "open page X"; owns badge drag. | +| `SlideOver` | `ui_slideover.cpp` | A `GtkOverlay` child of the plot area: revealer + page stack keyed by id; Esc/click-away; open/close API. | +| `ReadoutsDock` | `ui_dock.cpp` | The compact readouts and the compact events list, reading the same model the panes read today. | + +Reuse, not rewrite: + +- The trigger form, signal list and calibration, measurement editor and cursor options are + **reparented** into slide-over pages. +- `SourcePanel{id, title, widget}` is unchanged, so the E-1608 and Flat UDP panels need no change. +- Only the events *list and actions* of the old pane move; the left `GtkPaned`/`GtkRevealer` and its + divider sync are deleted. + +## Invariants kept + +- **Layout must not depend on content** (`invariants-plot-and-layout.md`): the dock has a fixed width, + the badge bar a fixed height, and the slide-over overlays instead of resizing the plot. Rows that + appear by trigger condition appear inside the slide-over's scroller. +- **A `GtkOverlay` child is picked wherever its allocation is**: the slide-over is one opaque widget + aligned to the end edge by margin and width, never a full-area transparent child, so pan, drop and + hover on the rest of the plot are untouched. +- The header's Trigger/Cursors/Pause toggles keep their two-way mirroring with the panels. + +## State and session file + +- The session file drops `side_tab` and gains the dock's shown state and width. An old file's + `side_tab` is ignored (an unknown name is already harmless to `select_side_tab`). +- The open slide-over page is not saved. +- The tab ids `measure`, `signals` and `source-` stop being a session format; they remain page ids. + +## What must be rewritten around it + +- **Tour and context help:** steps and help-figure surfaces that point at `side_switcher`, + `side_stack` and `side_box` (`ui_tour.cpp`, `ui_context_help.cpp`) are re-pointed at the badge bar, + slide-over and dock, and the tour text is rewritten. +- **Probes:** the `switcher: policy=... pills=... labels=... images=... pages=...` line and + `side_tab_probe` become probes that count badges, dock rows and the open slide-over page; the events + divider probe goes away with the divider. +- **Keyboard:** `SideTabMeasure` / `SideTabSignals` become "open the measure / signals page". +- **Docs:** `README.md`, `USER-GUIDE.md`, `docs/claude/*` (architecture, verification, + probe-readings, the plot-and-layout and gtk-and-chrome invariants), and the Mallard manual's + figures. + +## Rollout + +Four steps, each its own plan, each leaving the app building, passing the probes and usable. + +1. **Shell.** The plot overlay, the badge bar with Trigger and Source, the slide-over holding the + existing trigger form and source pages. The sidebar tabs are removed; the existing Measure and + Signals panels move into a temporary dock so nothing is lost. +2. **Signal badges.** Per-signal badges, the `+` and "N signals" overflow, drag to reorder and to + move to a row. +3. **Compact readouts.** Read-only cursors and measurements in the dock; their editors in the + slide-over. +4. **Events.** The compact events section in the dock, the left pane and divider deleted, then the + tour / help / docs sweep. + +## Risks + +- **Overlay above the GL plot.** The panel must composite and take input correctly above the + plotter's GL area. The layout editor already places overlay children over the plot, so this is + expected to work; step 1 confirms it before anything else is built on it. +- **Reparenting the trigger form.** Its two-way mirroring with the header toggle, `sync_trigger_rows` + and the locked summary view must keep working from a hidden-by-default page. Step 1 verifies it with + the existing trigger probes. +- **Many signals.** The badge bar's six-badge limit and horizontal behaviour are the one place the + E-1608 (up to about 17 signals) stresses the design; step 2 includes a run on it. + +## Out of scope + +User-arranged or undockable panels, saved layouts of the panels themselves, a touch-specific mode, +and any change to the plot, trigger, measurement or source engines. Per-source tab names do not +change.