Files
udpscope/src/ui/trigger-panel.ui
T
Martino Ferrari da826f2cb5 fix: persistence is the trace's own phosphor, not a density behind a stroke
The plotter now deposits every acquisition -- the newest included -- into one grid per trace and
draws no solid trace over it, each grid in that trace's colour and with a one-sweep ceiling (its own
commit, **1b8b55d**). This side needed almost no change of its own, because the colour was already
the trace's and the trace's colour is `RowSet::signal_color()` -- the invariants' one route -- but the
figures it reads back are now per trace:

- **The ceiling is left at the library's default of one sweep**, no longer derived from the fade.
  Deriving it from the steady state is the gain offset the user reported between the latest
  acquisition and the persistent image; a signal crossing the same place every acquisition now settles
  at the trace's colour, at full strength, and the newest sweep reads as the trace it is a picture of.
- **`cells`/`grid_bytes` are the sum over the row's traces** -- one grid each, a trace with no series
  holding none -- and both the probe and the exit dump carry `traces=` beside `rows=`. That is what
  makes the per-signal memory figure read: **556 537 cells and 2.2 MB per signal**, at 8904600 bytes
  over the four one-signal rows of the probe's run.

The probes, re-read on this build (the `verification.md` command, `--rate 500000 --batch 1000`):

    [density-probe] off enabled=0 ... rows=0 traces=0 cells=0 ink=0.0 peak=0.0000
    [density-probe] on enabled=1 ... rows=4 traces=4 cells=2226150 ink=226786.0 peak=1.0000
    [density-probe] step-acquisitions ... peak=1.5000
    [density-probe] time-before ... peak=2.1359
    [density-probe] step-time ... ratio=0.367879
    [density-probe] frame cost: tick 0.62 -> 6.96 ms (184/23 frames), draw 2.02 -> 6.16 ms (177/18)
    [udpscope]   density: frames=748 rows=4 traces=4 cells=2226150 grid_bytes=8904600 ink=489400.2 peak=2.2 upload_bytes=2226150

`on` `peak=1.0000`, `step-acquisitions` `peak=1.5000` and `step-time` `ratio=0.367879` are the legs
that were expected, unchanged; the *draw* mean is now **below** the run before the split (2.02 -> 6.16
against 2.09 -> 20.91), because the solid traces are no longer drawn over the image.

Docs updated with it: the trigger manual page (`persistence` is the trace, one image per signal, the
newest included), the README's persistence section, `invariants-trigger-and-pinning.md` (five rules,
the ceiling and the no-stroke rule among them), `verification.md` and `probe-readings.md` (the lines
above), the trigger panel's comment and tooltips, and the plotter submodule.

`cmake --build build --clean-first -j4`: **0 errors, the documented three warnings** (two
`MathNode::source`, one `-Woverlength-strings` at 12352); `make -C build test-ui` **13 ok**;
`make -C build test-help` **green** (15 pages); the self-check **0 `Gtk-WARNING`/`Gtk-CRITICAL`** and
`gtk warnings: 0`, two `buffer allocated:` lines.
2026-10-16 20:21:57 +02:00

421 lines
18 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-License-Identifier: MIT -->
<!-- SPDX-FileCopyrightText: 2026 Martino Ferrari -->
<!--
The trigger panel's frame: one labelled row per setting, the pair of buttons that run it
(Arm/Disarm and Force), and the search block. Its *heading* is not here: the heading row carries the
switch that turns trigger mode on and off, and this panel's body is what goes insensitive when it is
off, so the heading has to be its sibling rather than a child of it (`build_trigger_panel()` returns
the two together).
Every row here is a label and a place for a control, and the control itself is built in code. A
dropdown's model and a spin button's range are the *application's* (the condition list, the level
range that follows the channel's scale), while a label is text a translator owns, so the split runs
between them: the row is the file's and the control is appended into it. That is the arrangement
`labeled_box()` used to make in code, with the label moved where all the other labels are.
Between the controls, the labels and the search block are what "read the panel" means, so they are
here: which of these rows `sync_trigger_rows()` shows depends on the condition (a pulse width has a
width, a window has two levels, a dropout has a timeout), and that is the code's decision, not this
file's — this file just has to have a row for each of them to show or hide.
-->
<interface>
<object class="GtkBox" id="trigger_panel">
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<property name="margin-top">8</property>
<property name="margin-bottom">8</property>
<property name="margin-start">8</property>
<property name="margin-end">8</property>
<child>
<object class="GtkBox" id="signal_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">signal</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="condition_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">condition</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="edge_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">edge</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="cmp_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">width is</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="width_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">width s</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="width2_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">and s</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="level2_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">to level</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="timeout_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">timeout s</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="level_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">level</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="pre_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">pre-trigger %</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="holdoff_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">hold-off s</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="band_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">noise band</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="hf_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">HF reject Hz</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="mode_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">mode</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="record_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="record_label">
<property name="label" translatable="yes">record events</property>
<property name="halign">start</property>
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
<child>
<!-- The trigger's *display* settings: what the mode does with the acquisitions it takes, as
against the condition that decides when it takes them. Collapsed by default; a trigger
is set up once and run for hours, and these are what you come back to when the display
is what you are looking at. The rows are the file's, as everywhere in this panel; the
controls are appended into them by `build_trigger_panel()`.
Both displays live here and they are two different things: *multiple events* keeps the
last N acquisitions as N traces, dimmer with age, while *persistence* accumulates every
acquisition into an image (one screen-sized grid per trace, in that trace's own colour,
the plotter's `Plot::set_density()`), drawn in place of the traces. The first is a
count and the second is a decay, which is why neither is a mode of the other. -->
<object class="GtkExpander" id="advanced_exp">
<property name="tooltip-text" translatable="yes">what the trigger mode does with the acquisitions it takes: the last few kept as dimmer traces, and a persistence image (one per signal, in its own colour) every acquisition is accumulated into</property>
<child type="label">
<!-- A box rather than a plain label, for the search block's reason: the contextual
help's "(i)" joins its last child and a hint hung on the expander's own *child* is
off screen while the block is collapsed (see
docs/claude/invariants-gtk-and-chrome.md). -->
<object class="GtkBox" id="advanced_head">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Advanced</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<property name="child">
<object class="GtkBox" id="advanced_box">
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<property name="margin-top">4</property>
<child>
<object class="GtkBox" id="persistence_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="multiple_event_label">
<property name="label" translatable="yes">multiple events</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="density_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="density_label">
<property name="label" translatable="yes">persistence</property>
<property name="halign">start</property>
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="density_decay_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">fades by</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="density_tau_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">time constant s</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="density_factor_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">per acquisition</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkBox" id="arm_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkButton" id="trigger_arm">
<property name="label" translatable="yes">Arm</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="trigger_force">
<property name="label" translatable="yes">Force</property>
<property name="hexpand">1</property>
<property name="tooltip-text" translatable="yes">take one acquisition now, with the pre/post window above, without waiting for the condition</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkExpander" id="search_exp">
<property name="tooltip-text" translatable="yes">find every place in the retained buffer where the condition above holds, and step through them</property>
<!-- The header is a box, not a plain label, so the contextual help's "(i)" has a row to join
as its last child and sits beside the text while the block is collapsed. The block's own
*child* is not in the widget-parent chain until the expander is expanded (see
docs/claude/invariants-gtk-and-chrome.md), so a hint hung there would be off screen. -->
<child type="label">
<object class="GtkBox" id="search_head">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Search the buffer</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<property name="child">
<object class="GtkBox" id="search_sbox">
<property name="orientation">vertical</property>
<property name="spacing">4</property>
<property name="margin-top">4</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkButton" id="search_run">
<property name="label" translatable="yes">Search</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="search_cancel">
<property name="label" translatable="yes">Stop</property>
<property name="sensitive">0</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel" id="search_status">
<property name="label" translatable="yes">not searched</property>
<property name="halign">start</property>
<property name="wrap">1</property>
<property name="css-classes">dim-label</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkButton" id="search_prev">
<property name="icon-name">go-previous-symbolic</property>
<property name="tooltip-text" translatable="yes">the previous hit</property>
<property name="sensitive">0</property>
</object>
</child>
<child>
<object class="GtkLabel" id="search_pos">
<property name="label">--</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="search_next">
<property name="icon-name">go-next-symbolic</property>
<property name="tooltip-text" translatable="yes">the next hit</property>
<property name="sensitive">0</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel" id="search_marks">
<property name="label"> </property>
<property name="halign">start</property>
<property name="css-classes">dim-label</property>
<property name="ellipsize">3</property>
</object>
</child>
</object>
</property>
</object>
</child>
</object>
</interface>