feat: two-tier status bar, one glance line with the detail behind an info popover
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
f9490061a1
commit
8242812338
4 files changed
+319
-76
No files matched your search
@@ -0,0 +1,89 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "status_text.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
namespace udpscope {
|
||||
|
||||
/// `12 s`, `3m 07s`, `2h 14m` -- one unit coarser as soon as the finer one would need
|
||||
/// three digits, so the field never grows past six characters and the status line's shape
|
||||
/// does not depend on how long the wait has been.
|
||||
std::string format_elapsed(double seconds) {
|
||||
if (!(seconds >= 0.0)) return "--";
|
||||
char buf[32];
|
||||
if (seconds < 60.0) {
|
||||
std::snprintf(buf, sizeof(buf), "%.0f s", std::floor(seconds));
|
||||
} else if (seconds < 3600.0) {
|
||||
const int m = static_cast<int>(seconds) / 60;
|
||||
std::snprintf(buf, sizeof(buf), "%dm %02ds", m, static_cast<int>(seconds) % 60);
|
||||
} else {
|
||||
const int h = static_cast<int>(seconds) / 3600;
|
||||
std::snprintf(buf, sizeof(buf), "%dh %02dm", h, (static_cast<int>(seconds) / 60) % 60);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// A sample rate in the unit it reads shortest in. Rates here span six decades (a 1 Hz
|
||||
/// housekeeping signal next to a 1 MS/s acquisition), so a fixed unit makes one of the
|
||||
/// two unreadable.
|
||||
std::string format_rate(double per_s) {
|
||||
char buf[32];
|
||||
if (!(per_s > 0.0)) {
|
||||
return "0 S/s";
|
||||
} else if (per_s >= 1.0e6) {
|
||||
std::snprintf(buf, sizeof(buf), "%.3g MS/s", per_s / 1.0e6);
|
||||
} else if (per_s >= 1.0e3) {
|
||||
std::snprintf(buf, sizeof(buf), "%.3g kS/s", per_s / 1.0e3);
|
||||
} else {
|
||||
std::snprintf(buf, sizeof(buf), "%.3g S/s", per_s);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string format_glance(const StatusSnapshot& s) {
|
||||
std::string out = s.state_word;
|
||||
out += " · ";
|
||||
out += s.rate_text.empty() ? "no data" : s.rate_text;
|
||||
out += " · ";
|
||||
out += s.window_text;
|
||||
out += " window";
|
||||
if (s.trigger_on) {
|
||||
out += " · ";
|
||||
if (s.have_event) {
|
||||
out += "event " + format_elapsed(s.since_event_s) + " ago";
|
||||
} else {
|
||||
out += "no event yet";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string format_detail(const StatusSnapshot& s) {
|
||||
char buf[1024];
|
||||
std::snprintf(buf, sizeof(buf),
|
||||
"[%s] %s %s | rate %s | packets %llu frames %llu gaps %llu | %zu signals, "
|
||||
"%zu channels | plot 1: %d trace(s), %zu samples | buffer %.1f MB, %.2f s "
|
||||
"span, time x%llu",
|
||||
s.state_detail.c_str(), s.connected ? "connected" : "waiting",
|
||||
s.have_config ? "configured" : "-",
|
||||
s.rate_text.empty() ? "--" : s.rate_text.c_str(),
|
||||
static_cast<unsigned long long>(s.packets),
|
||||
static_cast<unsigned long long>(s.frames),
|
||||
static_cast<unsigned long long>(s.gaps), s.signals, s.channels,
|
||||
s.plot1_traces, s.plot1_samples, s.buffer_mb, s.span_s,
|
||||
static_cast<unsigned long long>(s.time_stride));
|
||||
std::string out = buf;
|
||||
if (s.trigger_on) {
|
||||
out += s.have_event ? " | last event " + format_elapsed(s.since_event_s) + " ago"
|
||||
: " | no event yet";
|
||||
}
|
||||
if (s.reconnects > 0) {
|
||||
char note[48];
|
||||
std::snprintf(note, sizeof(note), " | %d reconnects", s.reconnects);
|
||||
out += note;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace udpscope
|
||||
Reference in new issue
Block a user