Files
udpscope/help/C/org.udpscope.app/layout.page
T
Martino Ferrari c1460a6977 feat: the manual is a Mallard set opened in Yelp, not a GResource in the binary
The help was 14 Pango-markup `.txt` bodies in a second GResource, drawn into a paged `GtkWindow`
built in `help_window.cpp`. That made F1 a viewer of ours with no search index, no cross-references
and no translation, and it kept the manual in the *binary* when every other desktop application's is
a document on disk. It is now a real Mallard set:

  help/C/org.udpscope.app/  index.page + 14 topic pages + figures/*.png

and `show_help()` hands `help:org.udpscope.app` to whatever the desktop registered for the `help:`
scheme -- Yelp on GNOME -- through a `GtkUriLauncher`, reporting a launch failure with a
`GtkAlertDialog` rather than a click that silently does nothing. The paged window's builder, the
page table and `help_self_check()`'s markup validation are gone with the resource.

The document identifier is the desktop file's own basename (its desktop-file id), derived in
CMakeLists from `data/org.udpscope.app.desktop.in`, so the same string is the `.desktop` name, the
GApplication id and the install directory at once. The set is installed by a new `install()` rule to
`<datadir>/help/C/org.udpscope.app/` -- where the freedesktop Help System Specification's `help:`
URI resolves `help:<id>` -- so the manual is read from a datadir by another process even though the
binary has no install step. `UDPSCOPE_HELP_NAME` and `UDPSCOPE_HELP_DIR` are compiled in from that
one place.

The 14 pages were migrated fact for fact, but restructured the Mallard way: a `<desc>` per page
(what a search result shows), `<steps>` for procedures, `<terms>` for option lists,
`<gui>`/`<key>`/`<keyseq>` for interface words and keys, `<note>` for the asides, and a topic graph
via `<link type="guide" xref="index#main"/>`. The figures are annotated screenshots produced by
`tools/make-help-shots.sh`, which drives the app headlessly against `tools/mock_udpstreamer.py` and
draws the boxes with ImageMagick; the side panel's box is measured from the app's own `side=NNNx`
dump reading, the header and status bands come from a documented table, and a crop whose standard
deviation is 0 fails the script.

`cmake --build build --target test-help` checks the set the way `test-ui` checks the `.ui` files:
`yelp-check`'s offline subcommands (links, media, orphans, ids) and a `yelp-build html` render.
`yelp-check validate` is deliberately absent -- it fetches the Mallard RelaxNG schema over the
network and fails offline for that reason, not for a fault in the pages.

The `[help]` probe reading changes with the resource it was written for. `parsed == pages` over
in-binary markup cannot exist now, so `help_self_check()` scans `UDPSCOPE_HELP_DIR` and the line
reads `topics=14 index=1 figures=3`; `topics=0 index=0` is the manual missing from the tree, which
is the finding the old count named.

Verified: clean build with the documented three warnings (the help bundle's `-Woverlength-strings`
is gone, so the baseline moves from four to three); test-ui 14/14; test-help clean (the four
subcommands and 15 pages rendered); a temp-prefix install lands 15 `.page` files and 3 figures at
`share/help/C/org.udpscope.app/`; the headless run reads `[help] topics=14 index=1 figures=3 dir=...`
with 0 Gtk-CRITICAL. Yelp's own window could not be exercised on this box -- it starts under Xvfb,
activates its portals and never maps, the same WebKit/portal limitation that stops a grab -- so its
rendering and its search index are unverified here; the content pipeline was (`yelp-build` renders
the whole set).

Docs: the manual's build/install/open story in `build-and-run.md` and README; the warning baseline
in `verification.md`/CLAUDE.md; the help bullets in `invariants-gtk-and-chrome.md`; the `[help]`
line in `probe-readings.md`.
2026-10-14 16:49:30 +02:00

72 lines
3.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<page xmlns="http://projectmallard.org/1.0/"
type="topic" style="task"
id="layout">
<info>
<link type="guide" xref="index#main"/>
<link type="seealso" xref="signals"/>
<desc>How the figure's rows and traces are arranged, how to drop a signal onto a row, and
how the layout editor adds and removes rows.</desc>
<credit type="author copyright">
<name>Martino Ferrari</name>
</credit>
</info>
<title>Rows, layout and drag &amp; drop</title>
<p>The figure is a stack of rows, 1 to 8 of them, each holding up to 4 traces. Rows share
one time axis and one pair of side margins, so their y labels line up, their data areas
start and end on the same two columns, and their windows cannot drift apart. The left
margin holds the y labels; the right one is empty, and is there so the newest tick's label
and the newest sample's ink have somewhere to land instead of sitting on the frame.</p>
<section id="reach">
<title>How to reach it</title>
<steps>
<item>
<p>Drag a signal's chip out of the side panel (<key>s</key>) and drop it on a row to
add a trace.</p>
</item>
<item>
<p>Press <key>l</key>, or pick <gui>Layout editor</gui> from the overflow menu, to add
and remove rows: a <gui>×</gui> appears at the top left of each row and a <gui>+</gui>
on each boundary between rows, including above the first and below the last.</p>
</item>
<item>
<p>The editor's own button in the top-right corner leaves it.</p>
</item>
</steps>
</section>
<section id="knowing">
<title>Worth knowing</title>
<list>
<item><p>A plot's own <gui>right-click menu</gui> (the same compact rows as the app's
menu) holds the y-axis scale, the two fits, and <gui>Remove signal</gui>, which swaps
the menu to that plot's traces plus <gui>All traces on this plot</gui> — with a
<gui>Back</gui> row to return. That is how a trace comes off a row without going through
the layout editor.</p></item>
<item><p>A drop <em>adds</em> a trace to the row's next free slot; it does not replace
one. With four traces already on a row the drop is refused.</p></item>
<item><p>Inserting a row moves the rows below it <em>with their contents</em>. Inserting
above row 1 puts what row 1 plotted onto row 2 and leaves the new row empty — the rows
are not renumbered under you.</p></item>
<item><p>A trace is remembered by the signal's <em>name</em>, not by its channel number,
because a new CONFIG or an enable renumbers the channels and an index would silently
re-point the trace.</p></item>
<item><p>Adding or removing a row rebuilds the figure, which is cheap, but it also
re-deals every trace. A frozen trigger event survives the rebuild: the pinned window is
restated rather than re-framed on the live edge.</p></item>
</list>
</section>
<section id="example">
<title>Example</title>
<p>With three traces on row 1, pressing <key>l</key> shows 3 buttons (one <gui>×</gui>,
two <gui>+</gui>). Clicking the <gui>+</gui> above row 1 gives 2 rows and 5 buttons, with
the three traces now on row 2 — the layout probe reports exactly this as
<code>rows=2 buttons=5 traces=[0:-|1:sine,ramp,noise]</code>.</p>
</section>
</page>