feat: a reserved hole is shaded, so a sub-pixel gap is still a report

This commit is contained in:
Martino Ferrari committed 2026-10-08 20:12:38 +02:00
1 parent b32987d7e0
commit ee55ac84b7
3 files changed
+36

No files matched your search

+17
View File
@@ -371,6 +371,23 @@ void RowSet::bind(ScopeModel& model, DisplayMode mode) {
}
}
void RowSet::set_invalid_spans(ScopeModel& model, DisplayMode mode) {
spans_.clear();
if (mode == DisplayMode::Live || mode == DisplayMode::Capturing) {
// `Hole::x_begin`/`x_end` are stream seconds; the plots' x is `stream_t + epoch`.
const f64 epoch = model.display_epoch();
for (const Hole& h : model.holes()) {
spans_.emplace_back(h.x_begin + epoch, h.x_end + epoch);
}
}
for (int i = 0; i < rows_; ++i) {
Row& r = row(i);
// Every row shares the one x window, so every row gets the same spans: a hole is a gap in
// the stream and not in one signal.
if (r.plot) r.plot->set_invalid_spans(spans_);
}
}
bool RowSet::live_edge(double& newest) const {
bool any = false;
for (int i = 0; i < rows_; ++i) {
+16
View File
@@ -12,6 +12,8 @@
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace udpscope {
@@ -179,6 +181,18 @@ class RowSet {
/// and status line all describe the same display: the producer can open or close a
/// capture between any two reads of `ScopeModel::display_mode()`.
void bind(ScopeModel& model, DisplayMode mode);
/// Publishes `model.holes()` to every row as shading, in display coordinates.
///
/// Separate from `bind()` and called *after* the display epoch has been written, because the
/// epoch the band needs is this frame's: `ui.cpp` recomputes it from the newly bound traces'
/// live edge, and the previous frame's value is a whole production interval stale -- a third
/// of the screen at 1 MS/s over a 50 ms window, which would put the band beside the gap
/// rather than over it.
///
/// Shading only in `Live` and `Capturing`. A `Held` or `Paused` snapshot carries its own
/// stamps and its own x offset, and the live hole table does not address it; shading it would
/// accuse whichever samples happened to land under those coordinates.
void set_invalid_spans(ScopeModel& model, DisplayMode mode);
/// Publishes the live buffer's new samples.
void acquire(ScopeModel& model) { model.acquire_all(); }
@@ -487,6 +501,8 @@ class RowSet {
/// an absent entry means "the palette decides", which is what keeps a new CONFIG's signals
/// coloured without anything having to seed them.
std::map<std::string, plot::u32> signal_colors_;
/// Reused across frames by `set_invalid_spans()`: see there.
std::vector<std::pair<f64, f64>> spans_;
CursorMode cursor_mode_ = CursorMode::Vertical;
bool cursors_on_ = false;
bool relative_x_ = false;
+3
View File
@@ -6292,6 +6292,9 @@ gboolean tick(gpointer user) {
: model.display_epoch();
}
if (model.display_epoch() != want_epoch) model.set_display_epoch(want_epoch);
// The band last, after the epoch it is expressed in: it reads `model.holes()`, which the
// acquisition thread mutates, so it belongs under this lock and not after it.
app->rows->set_invalid_spans(model, display);
}
// The gesture probe's verdicts, one frame after the ask and after this frame's clamp: a