// SPDX-License-Identifier: MIT #pragma once #include #include #include namespace udpscope { /// Everything either tier of the status bar shows, gathered once per frame by the tick so the /// two cannot disagree. No GTK here on purpose: this is the one part of the status bar that /// can be reasoned about as text. struct StatusSnapshot { /// One word from the fixed set: "connecting", "live", "paused", "armed", "capturing", /// "event held", "disarmed". It is a word from a *fixed* set because the bar sits directly /// above the plot and a field whose width tracked the stream would relayout it every frame -- /// so a word added here must be no wider than the widest already in it ("connecting" and /// "event held" are both ten characters). "connecting" is the state before a CONFIG has /// arrived, in which there is no signal list and so nothing any other word here can describe. const char* state_word = "live"; /// The long prose the old single-line bar carried, kept for the detail string and the dump. std::string state_detail; bool connected = false; bool have_config = false; bool trigger_on = false; /// Already collapsed to one figure or a range by the caller, without the "rate " prefix. std::string rate_text; double stored_rate_hz = 0.0; double declared_rate_hz = 0.0; /// Pre-formatted by ui.cpp's format_window(), which the window control and the Fit notices /// also use, so it stays there rather than moving here. std::string window_text; std::uint64_t packets = 0; std::uint64_t frames = 0; std::uint64_t gaps = 0; std::size_t signals = 0; std::size_t channels = 0; int plot1_traces = 0; std::size_t plot1_samples = 0; double buffer_mb = 0.0; double span_s = 0.0; std::uint64_t time_stride = 1; bool have_event = false; double since_event_s = 0.0; int reconnects = 0; /// How long the view has been frozen, in **wall** seconds, and whether it is. The producer /// never stops while paused -- it keeps filling the live ring, which is what makes the resume /// seamless -- so the stream's own clock says nothing about how long the user has been looking /// at a still picture. Written through `format_elapsed()` like the event age, for the same /// reason: it steps to a coarser unit instead of growing digits, and the bar is directly above /// the plot. bool paused = false; double paused_for_s = 0.0; /// The resequencing counters, gathered with `packets`/`frames`/`gaps` so the detail tier and /// the dump quote one consistent set. All six zero means the stream never lost ordering, and /// the detail tier then says nothing about it at all. std::uint64_t resequenced = 0; std::uint64_t late = 0; std::uint64_t stale = 0; std::uint64_t holes = 0; std::uint64_t hole_slots = 0; std::uint64_t backfilled = 0; }; /// The bar: "live · 10 kS/s · 2 s window", plus " · event 4.2 s ago" in trigger mode, " · for /// 12 s" while paused, and nothing else ever. The badge glyph is a separate widget and is not /// part of this string. std::string format_glance(const StatusSnapshot& s); /// The popover's prose and the exit dump's line, field for field as the old single-line bar /// wrote it. CLAUDE.md asserts those fields are read out of the dump, so the field names and /// their order must not change without updating it. std::string format_detail(const StatusSnapshot& s); /// A sample rate as "10 kS/s" — `%.3g`, so a trailing zero is dropped and the field's width /// cannot track the stream. Moved here from ui.cpp, which still calls it. std::string format_rate(double hz); /// An elapsed time, stepping to a coarser unit rather than growing digits, so its width /// cannot track the stream. Moved here from ui.cpp. std::string format_elapsed(double seconds); } // namespace udpscope