Files
udpscope/src/status_text.hpp
T

90 lines
3.8 KiB
C++

// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
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