docs: the badge bar, the slide-over and the dock (step 1 of the redesign)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
a1672acc70
commit
0c94caf866
7 files changed
+203
-70
No files matched your search
@@ -73,7 +73,7 @@ switches trigger mode on, waits for an event, then leaves trigger mode the way t
|
||||
"Go live" button does, closes the window, and prints on stdout the status line in
|
||||
both states, the frame and per-channel sample counts, each plot's painted-frame
|
||||
count, which channel each trace slot holds, and the allocated size and reveal
|
||||
state of both side panels.
|
||||
state of the dock and the events pane.
|
||||
|
||||
Every size it prints is read from a value the frame tick captured while the window was alive, not
|
||||
from the widget: the dump runs from the destroy handler, where the widget pointer is already freed
|
||||
@@ -96,9 +96,24 @@ src/plot_host.* the one plot::Figure, its rows' traces and cursors, the x lin
|
||||
src/export.* the visible range as a table, and the .npy / .csv / .mf3 writers
|
||||
src/layout_store.* the per-source session layout file (TOML), written and read back
|
||||
src/event_series.hpp an immutable captured event as a plot::data::Series
|
||||
src/ui.* the GTK4 window: toolbar, trigger panel, signal panel, plot box
|
||||
src/ui.* the GTK4 window: toolbar, trigger form, signal list, plot box, the dock
|
||||
src/ui_slideover.cpp the slide-over panel over the plot's right edge, one page at a time
|
||||
src/ui_badges.cpp the badge bar under the plot: the Trigger and Source badges
|
||||
```
|
||||
|
||||
**The window.** The plot is the window. Under it sits a fixed-height **badge bar** (36 px) whose
|
||||
right-hand end carries two words-only badges: **Trigger** (`off`, `armed`, `capturing`, `triggered`
|
||||
or `disarmed`) and **Source** (the kind's name and `connected`/`disconnected`; a read-out, not a button,
|
||||
for a source with no controls of its own, and for a file). A badge opens the **slide-over**: a 360 px
|
||||
panel laid over the plot's right edge, opaque, with its own title, a *Close* button and one scroller per
|
||||
page. The Trigger badge opens the trigger form; the Source badge opens the source kind's own panels
|
||||
(the E-1608's *Analog out* and *Digital I/O*, behind a segmented switch at the top of the panel). It
|
||||
closes with a second click on its badge, with `Esc`, with *Close*, or with a click on the plot; it never
|
||||
resizes the plot. The right-hand **dock** (the existing sidebar, 320 px) holds what is left of the old
|
||||
tabs in one scroller: the signal list, the cursors and the measurements, shown from the start and
|
||||
insensitive until the stream has signals. It is temporary -- see "Review findings not (yet)
|
||||
implemented" for what the redesign still has to do with it.
|
||||
|
||||
Threading: one producer thread owns the data source (the UDPStreamer client is the built-in
|
||||
one) and calls `poll()`; the GTK main thread owns every widget and the GL contexts.
|
||||
They share `ScopeModel` under one mutex, which the producer takes once per DATA
|
||||
@@ -1006,7 +1021,9 @@ offset = 0.5
|
||||
```
|
||||
|
||||
It also stores `measure_stats` (the measurements statistics toggle, a boolean, absent means
|
||||
`false`). It is written (400 ms after the last change, and flushed on close) whenever the
|
||||
`false`) and `dock` (whether the dock is shown, a boolean, absent means `true`; it replaced the
|
||||
sidebar's `side_tab`, and a file that still carries `side_tab` loads, the key being ignored). The
|
||||
open slide-over page is not stored: a panel that opens by itself at start-up would be a surprise. It is written (400 ms after the last change, and flushed on close) whenever the
|
||||
window, the layout, a drop or a calibration changes, and applied once, when the
|
||||
first CONFIG names the signals -- signal *names* are the identity, because a
|
||||
CONFIG renumbers and an enable/disable rebuilds the channel list. Signals the
|
||||
@@ -1151,18 +1168,23 @@ up, the same delay the first-run auto-start uses, the pending request starts the
|
||||
chooser's rows show **no accelerators** -- the window prints `F1`/`Ctrl+T` because the window binds
|
||||
them, and this dialog binds none.
|
||||
|
||||
**The guided tour is five steps on a `GtkOverlay`** inserted above the window's content: the plot,
|
||||
the side panel, the trigger, the signals and the status line. There is no popover anywhere in it and
|
||||
**The guided tour is six steps on a `GtkOverlay`** inserted above the window's content: the plot,
|
||||
the badge bar, the trigger form, the dock, the signals and the status line. There is no popover anywhere in it and
|
||||
therefore no pointer grab to lose: what makes the tour modal is four dim rectangles -- above, below
|
||||
and either side of the target -- that swallow the clicks that land on them. A stop declares the
|
||||
**page it stands on** (the trigger and the signals steps live on the sidebar's *Signals* page, named
|
||||
in `TourStop::page`), and the tour selects that page as the step is entered -- on the frame *after*
|
||||
the switch, since a stack allocates a new page's widgets a frame late -- so the spotlight lands on a
|
||||
widget the user had left behind on the other tab instead of on nothing. `gtk_widget_get_mapped()`
|
||||
decides which steps exist at all: a stop on the *wrong page* is kept, because selecting its page
|
||||
reveals it, while one whose *pane is collapsed* is dropped, because the stack is unmapped with it
|
||||
(a hidden page keeps its own *visible* flag true -- the widget's own flag, which is all
|
||||
`is_visible()` walks -- so the old test walked over surfaces that were not on screen). The chooser's
|
||||
**slide-over page it stands on** (the trigger step names `trigger`, in `TourStop::page`): the tour opens
|
||||
that page as the step is entered, and a stop with no page *closes* the panel, so the card never points
|
||||
at the status line over an open panel. It does not spotlight the form until the panel has finished
|
||||
sliding in (about 120 ms, during which the surface is dimmed and the card waits in the corner), and the
|
||||
hole is the target's bounds clipped by every scroller above it -- on the documented 756x470 window the
|
||||
trigger form is taller than the panel, and the spotlight covers the part that is on screen, not the
|
||||
badge bar under it. Skip, Escape and the last step close a panel the tour opened (an idle dismissal
|
||||
leaves one the user opened alone). `gtk_widget_get_mapped()`
|
||||
decides which steps exist at all: a stop on a slide-over page is always kept, because opening the page
|
||||
reveals it, while one whose *pane is collapsed* (the dock, in a window too narrow to put it beside the
|
||||
plot) is dropped, because it is unmapped with its pane (a hidden page keeps its own *visible* flag
|
||||
true -- the widget's own flag, which is all `is_visible()` walks -- so the old test walked over
|
||||
surfaces that were not on screen); a narrow window therefore walks four steps. The chooser's
|
||||
tour works the same way over its own two pages: its tabs step shows the *Waveforms* page and
|
||||
stepping off it -- in either direction -- brings the *Sources* page back.
|
||||
|
||||
@@ -2780,12 +2802,13 @@ reaches every widget). The full key table:
|
||||
|---|---|
|
||||
| `a` | arm / disarm the trigger |
|
||||
| `Space` | pause / resume |
|
||||
| `t` | show / hide the trigger panel |
|
||||
| `c` | show / hide cursors |
|
||||
| `m` | show / hide measurements |
|
||||
| `g` | show / hide math channels |
|
||||
| `t` | enable / disable trigger mode |
|
||||
| `c` | enable / disable the cursors |
|
||||
| `m` | go to Measure (scroll the dock to the cursors and the measurements) |
|
||||
| `g` | go to Signals (scroll the dock back to the signal list) |
|
||||
| `l` | show / hide the layout editor |
|
||||
| `s` | show / hide the side panel |
|
||||
| `s` | show / hide the dock |
|
||||
| `Esc` | close the slide-over panel (the guided tour takes it first) |
|
||||
| `f` | fit to data (the plot's own key, not an application accelerator) |
|
||||
| `Ctrl+E` | export visible range |
|
||||
| `F1` | open the manual (`help:org.udpscope.app`) in the desktop help viewer |
|
||||
@@ -2897,32 +2920,42 @@ now — they are listed so they are not mistaken for anything else:
|
||||
progress. What the spec was protecting still holds — a *held* event is bound to its
|
||||
snapshot alone, and the axis is the event's own window from the edge onwards rather
|
||||
than a sliding live view.
|
||||
- **The sidebar is two tabs, and a math channel is a row of the signal list.** `SPECS.md`
|
||||
names the panes as separate collapsible sections — trigger, cursors, measurements, math,
|
||||
signal list — in one scrolling column; with four of them open in a 320 px sidebar every
|
||||
section was short of room, and finding one meant scrolling past the others. The built
|
||||
sidebar is a **Measure** tab (the cursors readout and the measurements) and a **Signals**
|
||||
tab (the trigger and the channels), **each a text tab** (the sidebar was icon-only for a while; glyphs for "cursors and ruler" and
|
||||
"trigger and channel list" were not understandable enough, so the words won). A source kind's own tabs
|
||||
(the E-1608's **Analog out** and **Digital I/O**) sit beside them as text too. Both panes also have a **locked** mode, which is what a returning user gets: the
|
||||
- **The sidebar is one dock, setup is a slide-over, and a math channel is a row of the signal list.**
|
||||
`SPECS.md` names the panes as separate collapsible sections -- trigger, cursors, measurements, math,
|
||||
signal list -- in one scrolling column; with four of them open in a 320 px sidebar every
|
||||
section was short of room, and finding one meant scrolling past the others. The sidebar was then two
|
||||
text tabs (a **Measure** tab and a **Signals** tab, with a source kind's own tabs beside them), and four
|
||||
tabs did not fit 320 px. It is **one dock** now, with no tab switcher: the signal list, the cursors and the
|
||||
measurements in one scroller, shown from the start and insensitive until the stream has signals; `m` and
|
||||
`g` scroll it to the cursors and back to the signal list. The **trigger form** and a **source's own
|
||||
controls** are pages of the slide-over, reached from the badge bar. Both panes also have a **locked** mode, which is what a returning user gets: the
|
||||
trigger pane shows one line saying what it is set to, the signal list shows only the signals that are
|
||||
on, and neither offers a control that changes the configuration — each heading has an `[edit]` button
|
||||
to switch to the full pane, and back. Dragging a signal onto a plot still works while locked — filling
|
||||
plots is what the list is for, not configuration — and a locked row can be dragged from anywhere on it,
|
||||
the colour chip included. In a window too narrow to show both, where the sidebar is *overlaid on* the
|
||||
plot, the sidebar steps aside for the length of the drag so there is something under the pointer to drop
|
||||
on, and neither offers a control that changes the configuration -- each heading has an `[edit]` button
|
||||
to switch to the full pane, and back. Dragging a signal onto a plot still works while locked -- filling
|
||||
plots is what the list is for, not configuration -- and a locked row can be dragged from anywhere on it,
|
||||
the colour chip included. In a window too narrow to show both, where the dock is *overlaid on* the
|
||||
plot, the dock steps aside for the length of the drag so there is something under the pointer to drop
|
||||
onto. A **first run** (no session file for that source) comes up
|
||||
unlocked, because configuring the host is what a first run is for. Each pane's heading also carries its **own switch**, the same control as the
|
||||
header bar's button — clicking either moves both — because a pane that is *disabled* while its
|
||||
feature is off is a pane whose controls you would otherwise have to leave to turn it back on. The
|
||||
sidebar is one **dock** now, with no tab switcher: the signal list, the cursors and the measurements
|
||||
in one scroller, shown from the start and insensitive until the stream has signals; `m` and `g`
|
||||
scroll it to the cursors and back to the signal list. With the math
|
||||
list folded into the signal list under a `MATH` divider whose `+` creates a channel — a derived channel already *is* a channel in
|
||||
header bar's button -- clicking either moves both -- because a pane that is *disabled* while its
|
||||
feature is off is a pane whose controls you would otherwise have to leave to turn it back on. With the math
|
||||
list folded into the signal list under a `MATH` divider whose `+` creates a channel -- a derived channel already *is* a channel in
|
||||
the model, so the two lists were the same list drawn twice. No
|
||||
toggle hides a pane any more: cursors-off **disables** its readout and leaves it in place, and
|
||||
trigger-off leaves the trigger panel fully editable — a trigger is configured *before* it is
|
||||
switched on, and the locked view says `stream (trigger off)` instead of the settings — and the measurements' and math panes' toolbar toggles are gone with the panes.
|
||||
trigger-off leaves the trigger form fully editable -- a trigger is configured *before* it is
|
||||
switched on, and the locked view says `stream (trigger off)` instead of the settings -- and the measurements' and math panes' toolbar toggles are gone with the panes.
|
||||
- **The badge bar / slide-over / dock redesign is in progress; this is its first step, and it deviates
|
||||
from `docs/superpowers/specs/2026-11-02-ui-badges-dock-design.md` in three known ways.**
|
||||
(1) The dock keeps the sidebar's **320 px**, not the spec's ~280: the panels it holds were built for
|
||||
320, and the width changes when they become compact readouts (step 3). (2) The session file gains the
|
||||
dock's *shown* state only, not a width -- the dock's width is fixed, so there is nothing to persist
|
||||
-- and does not store the open slide-over page. (3) The **Trigger badge** shows `off`, `armed` and
|
||||
`triggered` as the spec says, and two more words, `capturing` (a post-trigger window is filling) and
|
||||
`disarmed` (trigger on, not armed), so the label never claims a state the engine is not in. Still to
|
||||
come, in the spec's order: the signal badges and drag (2), the compact readouts (3), the events
|
||||
section in the dock, the deletion of the left pane and the Events toggle, and `USER-GUIDE.md` and the
|
||||
manual's figures (4). Until then the events pane, the header's Events toggle and the manual still
|
||||
describe the previous layout.
|
||||
- **A plot holds at most eight signals** (`RowSet::kSlotsPerRow`), because a `Plot`
|
||||
cannot give up a trace and the slots are therefore created up front.
|
||||
- **One toggle drives both cursor orientations.** The vertical markers and the
|
||||
@@ -3016,6 +3049,10 @@ silence timeout and then resumes, which is the EMI case end to end.
|
||||
rather than rebuilds, and why the frame tick reads the markers back: a parked
|
||||
cursor's snapped position is a real number, so nothing may be inferred from it. The
|
||||
trigger marker is separate: its own cursor, independent of the cursor toggle.
|
||||
- **The slide-over shows a form taller than the plot by scrolling it.** The panel is as tall as the
|
||||
plot and never taller, and each page has a scroller of its own, so on the documented 756x470 window
|
||||
the trigger form (about 474 px) shows 253 px of itself. The tour's spotlight is clipped to that, and at
|
||||
that size the card of the trigger step overlaps the panel's edge by about 18 px (`clear=0`).
|
||||
- **Verified headless only.** Acquisition, partitioning, the trigger state
|
||||
machine and its integration with the buffers, and rendering under Xvfb
|
||||
(llvmpipe) were exercised; the interactive paths (drag and drop, the dialogs,
|
||||
|
||||
Reference in new issue
Block a user