Files
Martino FerrariandClaude Opus 4.6 1627abcd4a docs: the sample budget in samples per signal, the memory limit and the planner probe lines
Converts every --buffer-mb / buffer_mb mention to --buffer-samples / buffer_samples,
records the unit change as a deviation (README, SPECS, CLAUDE.md), documents the
buffer: and planner: dump lines and the new Preferences row, and updates the help
pages and the help-shot script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-11-03 02:49:21 +01:00

7.2 KiB

  • (1) fix vertical lines to small to be seen: in some cases (e.g. rect waveform in @mock_upstreamer.py) the vertical lines are to thin to be visible (sometime they glitch in and out of existence):

    1. the antialisaing strategy with phosphore effect should be applied with more stregth done: Style::intensity_grading — the library's phosphor model, off by default because it is a change of look rather than a correction — is turned on for this host on the first tick that finds a renderer (src/ui.cpp), with UDPSCOPE_NO_PHOSPHOR to read the frame cost against the ungraded path.
    2. the lines should be more tick done: what made a vertical edge disappear was the grading, not the width — a segment is graded by its own slope (Renderer::stage_trace_slopes()) with Style::intensity_floor as the floor, so a discontinuity keeps a minimum of ink instead of being graded toward nothing and flickering in and out as it crosses the threshold. Line AA is the library's Style::line_aa_px.
    3. the sample points should be bigger done: Style::marker_px, and the README records the result — a trace's own 3 px sample dots, against the 9 px hover mark that has to read as the answer to a question rather than as one more sample.
  • (2) relative timing done: --relative-time; see README and SPECS.md for the measured history cost.

    • in order to avoid problem with time jitter user can decide to go in relative time mode
    • in this mode absolute signal time is only use for export
    • the plot time depends just on signal sample rate and frame number, e.g.:
      • user is acquiring a signal with 1MSps and 100_000 samples per udp frame
      • last frame as number and previous in this case a 100_000 indexes must be skipped
      • time is simply: ((<N_frame> - <N_last>) * <n_samples_per_frame> - <sample_index>) / <sample rate> (or something like that)
  • (3) named configurations done: one directory per source holding <name>.toml per configuration plus active; a configuration carries a note and the startup settings (buffer_samples, relative_time, capture_packets); the chooser lists them and the menu's Configurations… opens/saves/deletes them.

  • (4) optional udp frame storage for debugging of strange behaviours done: --capture-packets N; see README and the design note in docs/superpowers/specs/ for the ring file, the popover toggle and tools/capture_to_pcap.py.

  • (5) open exported binary waveforms to view/analyse done: --open FILE and the chooser's Waveforms page (the files opened before, newest first, plus Open…); the .npy's dtype names the columns, so a load restores the signals, the samples and the axis the export had, and every instrument works on it — see README and docs/claude/invariants-data-path.md.

  • (6) imporve right click menu on the plots done: the plot's context menu uses the main menu's row style (menu_button + .udpscope-menu, asserted by UDPSCOPE_PROBE_ROWMENU_MS: uniform label_x=26, h=18, the shortcut flush right), and deleting a signal is a Remove signal submenu listing that plot's traces plus All traces on this plot.

  • (7) in layout edit mode add the option to drag plot border to resize them done: every row boundary carries its own udpscope-resize-rows-symbolic handle ("drag to resize the two rows here"), a widget of its own rather than a second gesture on the + so a handle that cannot be clicked cannot be clicked by accident — the figure's own top and bottom edges have no pair to share, so those two are hidden rather than greyed. The sizing is persistent because it is an arrangement: the weights live in the same layout file as the row's signals (LayoutState::Row::weight, RowSet::set_row_weights()), and a file from before weights existed loads as equal rows.

  • (8) add option to automatic save the last triggered acquisitions in a cache folder and let the user replay them done: every latch is written to <cache>/<source>/events/ as a .npy (the export format), a .txt sidecar and a .bmp preview drawn from the samples; the events pane (revealed with trigger mode, switchable) lists them with time, duration, signals and rate, shows the preview, replays one through the --open loader and has Live to go back -- see README and docs/claude/invariants-trigger-and-pinning.md.

  • (9) preferences dialog done: src/settings.{hpp,cpp} (the store: load/save/defaults, GTK-free) + src/ui_prefs.cpp (the dialog, opened from the overflow menu); the cache directory (one events/ directory for every source, each source a folder inside) and the keep count reach EventStore, and relative time is a start-up default; whether anything is cached at all stays the trigger pane's own switch. The same dialog opens from the host selection dialog too (a PrefsForm has no owner, so both windows hold one), where a change still reaches the run about to start.

    • user can choose evnt cache directory (default /.cache/udpscope//events/)
    • maximum number of events to cache
    • disable completly the events storage option
    • enable/disable relative time mode
    • interface dark/light/auto color
    • defaults
    • other parameters
  • (10) move the interface into .ui resources, and to current GTK4/libadwaita widgets while doing it done: one slice per commit, 14 .ui files under src/ui/, every one of them in udpscope-ui.gresource.xml and checked by make test-ui, which type-checks each property and child against the GIR and refuses a file the xml does not list. Moved: the shortcut overview, the preferences, the help window's chrome, the host form, the main window's skeleton, the cursors panel, the source chooser's window (an AdwViewStack under an AdwViewSwitcherBar in place of the notebook), the measurements panel, the trigger panel, the signals panel, the math panel, the math editor's window with its identity row, canvas and action row, the events pane, and the header bar.

    • what stays in code, and why: the rows (one per signal, measurement, event, channel or node, rebuilt from the model); the math editor's palette and parameter form (the palette is the operation table, the form follows the selection); and the layout editor's overlay buttons, whose count is the row count -- a GtkBuilder instantiates a file's objects once, so a file can hold neither the number nor a prototype for the code to copy. That row was closed by factoring the look its three loops shared into one function instead.
    • the reading each slice added: [sidebar-probe], [prefs-probe] mnemonics=, [sources] chooser ui:, measures pane:'s switch_on/reset_sensitive, trigger panel:'s controls_inside, signals panel:, math panel:, [math-probe] dialog build:'s name=/unit=, events pane:'s nested, and the header bar through the unchanged [udpscope] header: geometry -- each of them reading the frame back rather than asserting it.
    • the three GTK facts these slices cost, all in docs/claude/invariants-gtk-and-chrome.md: an expander's child is not in the widget-parent chain; a .ui file instantiates its objects once; and a code-added header-bar child lands after the file's, which is why the window control goes into a slot the file declares.