help: the search block's (i) on its header, a 12 px mark, and a real search page

This commit is contained in:
Martino Ferrari committed 2026-10-14 23:29:00 +02:00
1 parent d549223889
commit fe499bfe41
10 files changed
+178 -53

No files matched your search

+21 -13
View File
@@ -544,26 +544,34 @@ The `Help` submenu, the contextual help's "?" and the guided tour, and the traps
sits *on* whatever is under it -- and every panel heading already has a switch or a pencil in a
corner. `src/ui_context_help.cpp` is a table of (id, title, body, shortcut, host) where the host is
the *row* -- a panel's heading usually, and the row of a specific control (the "record events"
switch, the pre-trigger share) where that is the thing being explained. The one exception is the
switch, the pre-trigger share, the search block's expander *header*) where that is the thing being
explained. The one exception is the
plot, which has no heading: its "(i)" is an overlay child of the overlay the layout editor already
uses, and its corner is free. The icon is **`dialog-information-symbolic`** -- `help-about-symbolic`
is *already* the status bar's information button, and two "help" glyphs meaning different things on
the same line is the trap the seven app icons exist to avoid; the dump reads the name back through
the theme for the same reason the pane [edit] buttons do. `math_head` exists only while the math
editor is open, so that row is skipped when it is null.
- **A `GtkMenuButton` ignores both `min-width` and a size request; its subnodes are where a small
one is made.** The "(i)" is meant to be a *mark*, not a button, and the default is 34x34 (a 24 px
floor plus 5 px of padding from Adwaita's `button` rule). Measured on libadwaita 1.10: setting
- **A `GtkMenuButton` ignores both `min-width` and a size request, and the icon is a node *below*
its `button` subnode.** The "(i)" is meant to be a *mark*, not a button, and the default is 34x34 (a
24 px floor plus 5 px of padding from Adwaita's `button` rule). Measured on libadwaita 1.10: setting
`min-width`/`min-height` on the widget changed nothing, and neither did `gtk_widget_set_size_request()`
-- the menu button's own measure wins. Three selectors are needed, all in `install_css()`:
`menubutton.udpscope-hint` (the outer node), `menubutton.udpscope-hint > button` (its subnode) and
`... > button > image` (the glyph), with `min-width: 0; min-height: 0; padding: 0` -- and the result
is **16x16**, the glyph's own size, because a `min-width` is a floor and not a cap. (A class on the
outer node alone leaves the subnode at 34; a class on the subnode alone shrank the width to 16 and
left the height at 26.) The dump's `hint=` reading is that number, and it is measured with
`gtk_widget_compute_bounds()` on the first *visible* hint -- a hint inside a collapsed `GtkExpander`
is not in the widget-parent chain at all and reads 0x0, which would look like a mark shrunk to
nothing.
-- the menu button's own measure wins. The node tree is `menubutton > button > box > image` (read off
the CSS node dump), so `install_css()` reaches the glyph as
`menubutton.udpscope-hint > button > box > image`. The direct-grandchild form `> button > image`
matches **nothing** and is silent about it -- the glyph keeps its natural 16 px, which is why an
earlier version shipped a 16x16 mark and took that for the floor it was not. Zeroing the outer node
and the `button` subnode and asking the glyph for **12 px** (`min-width`/`min-height` *and*
`-gtk-icon-size`, the latter what actually *scales* the drawing rather than clamping its box) gives
**12x12**. (A class on the outer node alone leaves the subnode at 34; a class on the subnode alone
shrank the width to 16 and left the height at 26.) There is no lower floor: the symbolic glyph renders
at any request (measured down to 4 px), so 12 px is a legibility choice and not a limit. The dump's
`hint=` reading is that number, measured with `gtk_widget_compute_bounds()` on the first *visible*
hint -- a hint inside a collapsed `GtkExpander`'s *child* is not in the widget-parent chain at all and
reads 0x0, which would look like a mark shrunk to nothing. That is why the search block's hint rides
the expander's **header** (a `label-widget` box, `search_head` in `src/ui/trigger-panel.ui`, which
*is* in the tree) rather than its child, and why the `[helpui] collapsed search:` reading asserts the
header hint is mapped and 12x12 while the block is collapsed.
- **Off is gone, not greyed, and the buttons are found by a data key rather than kept in a list.** The
list is what the math editor cannot survive: its heading lives in a builder that is dropped and
rebuilt on every opening, so a stored pointer into it would go stale one dialog later. A key on the
+36 -21
View File
@@ -395,15 +395,17 @@ Two lines of the self-check output are assertions in disguise:
on the first tick for the same reason the toolbar's are. **Both must read `(ok)`**: the page titles are
empty on purpose, so an icon that does not resolve leaves a *blank* pill, and a blank pill looks
exactly like a page with nothing in it.
- `help layer: contextual=on hints=11 ids={events plot status cursors measures trigger trigger_advanced events_record signals signals_config window} icon=dialog-information-symbolic(ok) hint=16x16; tour=idle steps=5 step=0 auto=1 requested=0` (in the exit
- `help layer: contextual=on hints=12 ids={events plot status cursors measures trigger trigger_advanced events_record trigger_search signals signals_config window} icon=dialog-information-symbolic(ok) hint=12x12; tour=idle steps=5 step=0 auto=1 requested=0` (in the exit
dump, beside `switcher:`) — the help affordance layer as the last tick found it. **`hints=` must equal
the number of ids**, and the ids are the surfaces the contextual help is on: ten of the window
the number of ids**, and the ids are the surfaces the contextual help is on: eleven of the window
itself, and `math` only while the math editor is open (its heading lives in a builder that is rebuilt
on every opening, so it is not one of the window's own). Three of the ten are not a pane's *heading*
on every opening, so it is not one of the window's own). Four of the eleven are not a pane's *heading*
but the row of a specific control — `events_record` (the "record events" switch in the trigger
panel), `trigger_advanced` (the pre-trigger share row) and `signals_config` (the signals pane's hint
line, whose box exists so a hint can join it) — which is the rule the layer follows: a hint is a
sibling of the thing it explains and never an overlay on it. The layer is **off by default**
panel), `trigger_advanced` (the pre-trigger share row), `trigger_search` (the *header* of the search
block's expander, which is what lets it be on screen while the block is collapsed) and
`signals_config` (the signals pane's hint line, whose box exists so a hint can join it) — which is
the rule the layer follows: a hint is a sibling of the thing it explains and never an overlay on
it. The layer is **off by default**
(`contextual_help` in `settings.toml` is false for a missing file), so a fresh-config run reads
`contextual=off hints=0` and that line above is the state *after* the Help row was switched on;
`contextual=off` beside a non-zero count is the toggle not having removed its buttons — **off is
@@ -412,11 +414,17 @@ Two lines of the self-check output are assertions in disguise:
is `dialog-information-symbolic`, the plain information mark; `help-about-symbolic` is the status
bar's ⓘ and a second meaning for it is what the app's own icons exist to avoid. `hint=WxH` is the
size the **first visible** hint was allocated, measured the way every other rectangle here is
(`gtk_widget_compute_bounds()`), and **16x16 is the reading a "much tinier" mark must keep**: the
class zeroes the outer `menubutton` node, its `button` subnode and the glyph, which is what a
`GtkMenuButton` needs (its measure ignores both `min-width` on the widget and a size request) — the
default 34x34 is the number to compare against. Hints inside a collapsed expander are skipped, so the
number is never a hidden widget's 0x0. `tour=` is `running`/`idle` with the plan's `steps=` and the
(`gtk_widget_compute_bounds()`), and **12x12 is the reading a "much tinier" mark must keep**: the
class zeroes the outer `menubutton` node and its `button` subnode (a `GtkMenuButton`'s measure
ignores both `min-width` on the widget and a size request), and the glyph is a third node *below*
the subnode — `menubutton > button > box > image`, read off the CSS node dump. The direct-grandchild
form `> button > image` matches **nothing** and silently leaves the glyph at its natural 16 px,
which is the 16x16 an earlier version shipped by mistake; and there is no lower floor to find
(the symbolic glyph renders at any request, measured down to 4 px), so 12 px is a legibility
choice. The default 34x34 is the number to compare against. A hint inside a collapsed expander's
*child* is skipped, so the number is never a hidden widget's 0x0 — but a hint on the expander's
*header* is in the widget tree and reads its real size while the block is collapsed (see the
`collapsed search:` entry below). `tour=` is `running`/`idle` with the plan's `steps=` and the
current `step=`; `auto=1` is the first-run auto-start having fired *in this process* — the flag is
`tour_seen` in `settings.toml`, so a second run against the same config directory reads `auto=0` —
and `requested=1` is the **chooser's** tour having handed over (`Config::tour_pending`), which is
@@ -506,7 +514,7 @@ Two lines of the self-check output are assertions in disguise:
the saved-source list and the waveforms page's action row; the form's `AdwEntryRow`s are *not*
hosts (a row is not a box and its editor is internal, so a hint cannot join it as a sibling) and
the connection fields are explained by their group's `description` instead. `hint=WxH` is the
same 16x16 the window's line reads: the button is `ui_impl::context_help_button()`, the one
same 12x12 the window's line reads: the button is `ui_impl::context_help_button()`, the one
`udpscope-hint` affordance both windows draw.
- `[sources] tour: first run -- auto_started=1 in the chooser` then
`[sources] chooser tour: visible=1 steps=5 step=0` (stderr) — **a first run's tour starts in the
@@ -751,16 +759,16 @@ two also catch a row whose accelerator went missing. `settings=` must be a real
touches anything: `auto_started=1 visible=1` is the tour that started itself, and the parenthetical is
`settings.tour_seen` as the process found it — `tour_seen already set` with `auto=0` is the *second*
run against the same config directory, which is the assertion that the flag persisted. Then:
- `[helpui] contextual on: hints=11 ids={events plot status cursors measures trigger trigger_advanced events_record signals signals_config window} hint=16x16` —
the eleven "(i)" affordances, by id, and the size the first visible one was allocated. Ten are the
window's own surfaces (three of them a specific control's row rather than a heading — see the
`help layer:` entry) and the eleventh is `math`, which is present only while the math editor
window is open; it reads 10 with the editor shut. **On a fresh config this reads `hints=0 ids={}`
- `[helpui] contextual on: hints=12 ids={events plot status cursors measures trigger trigger_advanced events_record trigger_search signals signals_config window} hint=12x12` —
the twelve "(i)" affordances, by id, and the size the first visible one was allocated. Eleven are
the window's own surfaces (four of them a specific control's row rather than a heading — see the
`help layer:` entry) and the twelfth is `math`, which is present only while the math editor
window is open; it reads 11 with the editor shut. **On a fresh config this reads `hints=0 ids={}`
and `hint=0x0`**, because the layer is off by default; the example is the state after the row below
was switched on, and a fresh run's `hints=0` beside a `settings.toml` with no `contextual_help`
key is the default being read rather than assumed. **`hint=16x16` is the "much tinier" assertion**
key is the default being read rather than assumed. **`hint=12x12` is the "much tinier" assertion**
— the default menu-button mark is 34x34 (see `help layer:`), and anything near that is the class
not reaching the outer `menubutton` node.
not reaching the glyph's own node.
- `[helpui] main view: rows=7 help_row=1` and one `[helpui] entry N '<label>' accel='<key>' order=O`
per row of the **Help view** — `entry 0 'Back'` with no accelerator and then the four the submenu
promises: `entry 1 'Keyboard shortcuts' accel='Ctrl+/'`, `entry 2 'Documentation' accel='F1'`,
@@ -771,10 +779,10 @@ two also catch a row whose accelerator went missing. `settings=` must be a real
`toggle=` being the contextual-help row's check, which *is* `settings.contextual_help`. It reads `0`
on a fresh config (the default) and `1` on one where the setting is on; the probe's next step drives
it both ways, which is why the example here is the `1` side.
- `[helpui] toggle: off -> hints=0 ids={}; on -> hints=11 ids={…}; setting=on` — the toggle's effect
- `[helpui] toggle: off -> hints=0 ids={}; on -> hints=12 ids={…}; setting=on` — the toggle's effect
read both ways through the row itself. **`hints=0` with `off` is the assertion**: off means the
affordances are *gone*, not greyed, so anything else is a row that hid its buttons instead of
removing them. The count comes back to the same eleven, which is the other half — a toggle that
removing them. The count comes back to the same twelve, which is the other half — a toggle that
removed and could not restore is a one-way switch.
- `[helpui] tour started from the probe: visible=1 steps=5 step=0` — the tour started the way
`Ctrl+T` starts it. `steps=5` is the plan: the table's five steps whose surface is on screen or
@@ -804,6 +812,13 @@ two also catch a row whose accelerator went missing. `settings=` must be a real
rather than leaving them to find the mode. `trigger_panel`'s height differs between them (508 px in
configuration mode against 72 locked — the body is replaced by the summary), which is the check
that the mode really moved.
- `[helpui] collapsed search: expanded=0 mapped=1 mapped_header=1 hint=12x12` (the last step, in
configuration mode, after the figures line) — the search block's "(i)" read on the expander's
**header** with the block **collapsed**. **`expanded=0 mapped=1` is the assertion**: a hint on the
expander's own *child* is not in the widget-parent chain while the block is collapsed and would
read `mapped=0` (and `0x0`), which is exactly why the header box exists (`search_head` in
`src/ui/trigger-panel.ui`) and why the hint joins it as its last child. `mapped_header=` is the
header box beside it, and `hint=WxH` is the same 12x12 the layer's own line reads.
- `[toursurface] …` (stderr, `UDPSCOPE_PROBE_TOUR_SURFACE_MS`) — a stop that stands on a page it is
not on, entered from the page it is not on. It puts the sidebar on **Measure**, starts the window's
tour, and walks it a stop per tick (400 ms), because a stack allocates the new page's widgets on
+4 -3
View File
@@ -314,8 +314,9 @@ as distinct from the fault injection below, which exercises ingest:
figures:` read in both of the trigger pane's modes. Its lines and what each asserts are in
[probe-readings.md](probe-readings.md); the two things to read first are **`hints=0`** while the
toggle is off (off is *gone*, not greyed) and **`controllers=12 (was 12)`** after the dismissal (no
lingering input grab — a tour of ordinary overlay widgets takes none), and **`hint=16x16`** is the
size the shrunk "(i)" must keep (the default menu-button mark is 34x34). The chooser's own tour is
lingering input grab — a tour of ordinary overlay widgets takes none), and **`hint=12x12`** is the
size the shrunk "(i)" must keep (the default menu-button mark is 34x34). The `collapsed search:` line
is the header hint read on the search block's expander while it is collapsed. The chooser's own tour is
the other half and has its own entry points — see the **chooser** bullet below. Give it
`UDPSCOPE_EXIT_AFTER_MS=9500 UDPSCOPE_EXIT_DUMP=1` to get the `help layer:`/`help figures:` dump
lines as well, and note the tour **auto-starts** in any run whose settings file does not carry
@@ -345,7 +346,7 @@ as distinct from the fault injection below, which exercises ingest:
configuration carried, into the `Config` the model is built from. **With no `--server` and no probe
the chooser blocks in its own nested loop** (no frame to end and no dump), so a chooser run is
always this probe. It also prints the dialog's frame *and its own help layer*:
`[sources] chooser ui: … hints=[2 {chooser_sources chooser_waveform}] hint=16x16` with the setting
`[sources] chooser ui: … hints=[2 {chooser_sources chooser_waveform}] hint=12x12` with the setting
on, `hints=[0 {}] hint=0x0` with it off. `UDPSCOPE_PROBE_CHOOSER_HELP=1` drives the **Enable
contextual help** row and reads the file back; `UDPSCOPE_PROBE_CHOOSER_TOUR=1` drives the **Guided
tour** row and walks the chooser's own tour to its last stop, printing `[sources] chooser tour: …`