docs: design spec for the badge bar, readouts dock and slide-over panel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Opus 4.6 committed 2026-11-02 19:28:40 +01:00
1 parent 3ac7a8f230
commit c572ec280f
1 file changed
+175
@@ -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:<name>`, `signals`, `measure`, `cursors`, `events`,
`source-<id>`. 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-<id>` 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.