Files
udpscope/src/config.hpp
T
Martino Ferrari d8a79b96ba help: default the contextual layer off, and carry the help into the chooser
The contextual help was on by default, so a first run met a window with a "?"
beside every surface it had not asked to have explained; `contextual_help` now
defaults to false and the layer is asked for from the Help menu, from the
chooser's new help menu, or with Ctrl+H.

The source chooser runs before `App` exists, which makes it the window a user
who does not know how to start is looking at, so it now carries the same three
help affordances the window's Help view does: Documentation (the manual is
another process and needs nothing of the app), Enable contextual help (a row
whose check *is* the setting, written to the file the app reads a moment
later), and Guided tour. The tour is drawn on the app's own window, so the
chooser can only record the wish: it sets `Config::tour_pending` -- the value
`main()` owns and hands to both `choose_source()` and `run_ui()` -- and
`on_activate()` starts it once the window is up and laid out, through its own
callback so the readings can tell a request from the first-run auto-start.
The rows are the window's own `menu_button()`/`menu_toggle()`; `install_css()`
therefore runs from `choose_source()` (it is idempotent now) so the popover
gets the `.udpscope-menu` rules before it is shown.

Opening the manual could also fail with a message that blamed the handler
whatever was missing. `help_installed_path()` now resolves `help:<id>` the way
the specification does and the failure alert says which of the two it is: with
the set installed it names the viewer, without it it names the identifier, the
expected installed path and the install command. `show_help()` gained an
optional reporter, which `UDPSCOPE_PROBE_HELP_MS` uses for a new reading --
`[help] launch attempted= done= ok= error='' installed=` -- since a successful
launch leaves no window of ours to observe.

Tested: clean --clean-first build, three warnings as documented; test-ui 13/13
and test-help pass; no Gtk-CRITICAL in the help, helpui and chooser runs.
2026-10-14 17:22:03 +02:00

79 lines
3.8 KiB
C++

// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2026 Martino Ferrari
#pragma once
#include <cstdint>
#include <string>
namespace udpscope {
/// Everything the command line can say. Defaults are the ones the spec names
/// (200 MB per buffer, 10 ms trigger hold-off) unless the user overrides them.
struct Config {
std::string server = "127.0.0.1"; ///< IPv4 dotted quad of the stream source.
std::uint16_t port = 8000; ///< UDP port (unicast) or TCP port (multicast).
std::string multicast; ///< Empty selects unicast.
std::string interface_addr; ///< Local IPv4 to join the group on; empty = default route.
/// Whether `--server` was given. Absent, the application asks which source to open rather
/// than silently taking the default above -- so this is "did the user choose", not "is
/// `server` valid". The default stays a usable value for every other path.
bool server_specified = false;
/// Size of *each* of the two sample buffers, in megabytes. The application
/// always allocates two identical buffers (spec item 1).
double buffer_mb = 200.0;
/// Whether `--buffer-mb` was given. A stored configuration's buffer size fills in only when the
/// flag was *absent*: an explicit flag beats a saved setting, and "not asked" is not the same
/// question as "asked for 200".
bool buffer_mb_specified = false;
/// Largest time window the toolbar offers, in seconds. The buffer partition is
/// sized to hold at least this much time (spec: decimation).
double max_window_s = 600.0;
double trigger_holdoff_s = 0.010;
int recv_buffer_bytes = 8 * 1024 * 1024;
/// Number of stacked plots (rows) to start with, 1..`RowSet::kMaxRows`. Only the
/// starting point: rows are added and removed from the layout editor.
int plots = 1;
/// Take the plot's time from the packet counter and the declared sample rate rather than
/// from the stream's own time signal, so arrival and producer-clock jitter cannot move a
/// sample's x. Absolute stream time is still recorded, for export only (`todo.md` item 2).
bool relative_time = false;
/// Whether relative time was *stated* rather than left at its default -- by `--relative-time`, or
/// by the preferences, which the source chooser can reach before this run is planned. A source's
/// stored configuration is a statement from an *older* session, so it only fills in the gap.
bool relative_time_specified = false;
/// `--capture-packets N`: the ring size of the raw-datagram capture, 1..100000.
/// 0 means the flag was absent: the capture is off, and the popover button then
/// uses the 1000-slot default when the user toggles it.
std::uint32_t capture_packets = 0;
/// `--open FILE`: a `.npy` an earlier run exported, opened for viewing and analysis instead of a
/// live source. File mode and source mode are exclusive -- there is no acquisition behind a file,
/// and the chooser's Waveforms page sets this rather than the connection fields.
std::string open_waveform;
/// The source chooser's "Guided tour" entry. The tour is drawn on the application's own window,
/// which does not exist while the chooser runs, so the request rides on the one value `main()`
/// owns and hands to both the chooser and the front end (`open_waveform` and the preferences'
/// relative time cross the same way) and the window starts the tour once it is up and laid out.
/// It is *not* a preference: it describes this request and nothing else, so nothing persists it.
bool tour_pending = false;
};
/// Parses argv. On `--help` prints usage to stdout and exits(0); on a bad
/// argument prints a diagnostic to stderr and exits(2).
Config parse_args(int argc, char** argv);
/// Writes the usage text to `out`.
void print_usage(std::FILE* out, const char* argv0);
} // namespace udpscope