scope windows: the same instruments as the main window
A scope or detached window drew its traces and nothing else: no cursors, no gate band, no trigger marker, no measurement marks. They are not per-window state to be recreated -- the cursors are one pair of times, the gate one band, the trigger one instant -- so the main window's row set stays the **owner** and every window is written from it. `sync_scope_instruments()` runs in the main tick after the main's own `sync_cursors()`/ `sync_gate()`: a gesture inside a scope window is read back from *that* window's controllers first (those two calls only adopt while their own plot holds the grab, which is exactly "the drag happened here"), adopted by the owner, and then every window -- the dragged one included -- is written from the owner with the same cursor pair, mode and visibility, gate bounds and visibility, and trigger marker. `RowSet::set_cursors()` is the new pair setter; `trigger_marker_x()`/`_visible()` are the getters the mirror reads. The measurement marks travel by signal name (`RowSet::MeasureMark::signal`, filled by the measures pass), so each window finds the row that plots the signal and draws its ruler or mark there -- or none, when it does not plot it. The search marks are times on the window and are placed on every window by the same per-frame path, and the crosshair-axis-labels preference is restated to open windows when it changes. Probe: `[scope-probe] instruments windows=N cursors=N gate=N trigger=N marks=N (main trigger on=..)`, after adding a real gated `Top` measurement on `sine` -- the gate is restated visible each frame by `update_measures()` and marks come only from `show_on_plot` measurements, so the leg uses the app's own path. Docs: README, the cursors invariant, and the probe readings.
This commit is contained in:
1 parent
a29f38eaa9
commit
91ca29d181
10 files changed
+211
No files matched your search
@@ -151,6 +151,11 @@ you. The overflow menu's **Reopen closed windows (N)** brings them back, arrange
|
|||||||
window that was *attached* is not remembered (its figure is on the main window again), and a
|
window that was *attached* is not remembered (its figure is on the main window again), and a
|
||||||
detached figure is preserved by its window's entry, so quitting with one open no longer loses it.
|
detached figure is preserved by its window's entry, so quitting with one open no longer loses it.
|
||||||
|
|
||||||
|
A scope window draws the **same instruments as the main window** — the two cursors (draggable
|
||||||
|
there, and shared: moving one in any window moves it everywhere), the gate band, the trigger
|
||||||
|
marker and the measurements' marks on the traces each window actually plots. They have one owner
|
||||||
|
(the main window's plot set) and are written into every window each frame, so no window can drift.
|
||||||
|
|
||||||
A scope window also **carries its own layout editor**: `L` (or the grid button in its corner,
|
A scope window also **carries its own layout editor**: `L` (or the grid button in its corner,
|
||||||
revealed like the others) shows the same `+`/`×`/Done controls the main window's editor has, and
|
revealed like the others) shows the same `+`/`×`/Done controls the main window's editor has, and
|
||||||
they change *that* window's rows — so a second window can hold several figures as easily as the
|
they change *that* window's rows — so a second window can hold several figures as easily as the
|
||||||
|
|||||||
@@ -130,3 +130,14 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear
|
|||||||
stages the badge texts, which leave with the rest of the over batch over everything. An
|
stages the badge texts, which leave with the rest of the over batch over everything. An
|
||||||
assertion on badge pixels inside a label's rows is the regression test: with the fill under
|
assertion on badge pixels inside a label's rows is the regression test: with the fill under
|
||||||
the text, the label's glyph pixels are still lit inside the badge's rect.
|
the text, the label's glyph pixels are still lit inside the badge's rect.
|
||||||
|
|
||||||
|
- **The instruments have one owner: the main window's row set.** The two cursors, the gate band,
|
||||||
|
the trigger marker and the measurement marks are *shared*, not copied per window. The main tick's
|
||||||
|
`sync_scope_instruments()` writes the owner's state into every scope window each frame (the
|
||||||
|
setters early-out, so a steady frame is a handful of comparisons), and a gesture inside a scope
|
||||||
|
window is read back from **that** window's controllers first -- `sync_cursors()`/`sync_gate()`
|
||||||
|
only adopt while their own plot holds the grab, which is exactly "the drag happened here" -- and
|
||||||
|
adopted by the owner before anything is written out. The measurement marks travel by **signal
|
||||||
|
name** (`RowSet::MeasureMark::signal`), so a window finds the row that plots it; a window that
|
||||||
|
does not plot the signal draws none. The search marks are times on the window and are placed on
|
||||||
|
every window by the same per-frame path.
|
||||||
@@ -1494,6 +1494,15 @@ alone). `copied=''` with every slot empty is a copy that moved nothing. Measured
|
|||||||
*Reopen closed windows* item ("clicked", the item's own handler) opens every remembered one, and
|
*Reopen closed windows* item ("clicked", the item's own handler) opens every remembered one, and
|
||||||
the list is empty after (`left=0`). A `remembered` that did not grow is a destroy handler that
|
the list is empty after (`left=0`). A `remembered` that did not grow is a destroy handler that
|
||||||
forgot to record; `left` non-zero is an entry the menu did not take.
|
forgot to record; `left` non-zero is an entry the menu did not take.
|
||||||
|
- `instruments windows=N cursors=N gate=N trigger=N marks=N` is the **one owner, every window**:
|
||||||
|
given a cursor pair, a gate band and the trigger marker on the main window, every scope window
|
||||||
|
reports the same (each count is how many windows matched). `marks` is the per-window measurement
|
||||||
|
mark count agreeing with what that window plots -- a window that plots the measured signal has
|
||||||
|
its ruler, one that does not has none. All four counts equal to `windows` is the reading;
|
||||||
|
`trigger` is compared against the **main** (the marker is up only while the trigger is), and the
|
||||||
|
parenthesis reports the main's state so a zero is distinguishable from an unequal one. The leg
|
||||||
|
adds a real gated `Top` measurement on `sine`, because the gate is restated visible every frame
|
||||||
|
by `update_measures()` and `marks` only come from `show_on_plot` measurements.
|
||||||
- The second line is the **window as a drop target and a *Plot on* group**: `drop=1` is
|
- The second line is the **window as a drop target and a *Plot on* group**: `drop=1` is
|
||||||
`on_scope_drop_channel()` — the handler the window's own target wires — putting `square` in
|
`on_scope_drop_channel()` — the handler the window's own target wires — putting `square` in
|
||||||
the copied window's second slot (`slot1=`), the rebuild and the area's re-point then left to
|
the copied window's second slot (`slot1=`), the rebuild and the area's re-point then left to
|
||||||
|
|||||||
@@ -945,6 +945,16 @@ void RowSet::place_cursors(Row& r, plot::CursorPlacement placement) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RowSet::set_cursors(double a, double b) {
|
||||||
|
if (a == cursor_a_x_ && b == cursor_b_x_) return;
|
||||||
|
cursor_a_x_ = a;
|
||||||
|
cursor_b_x_ = b;
|
||||||
|
// `Free`: the pair is the owner's already-committed position (a gesture in another window, or
|
||||||
|
// this window's own last sync); snapping it here would fight the hand still moving it.
|
||||||
|
for (int i = 0; i < rows_; ++i) place_cursors(row(i), plot::CursorPlacement::Free);
|
||||||
|
place_crossings();
|
||||||
|
}
|
||||||
|
|
||||||
void RowSet::set_cursor_mode(CursorMode mode) {
|
void RowSet::set_cursor_mode(CursorMode mode) {
|
||||||
if (mode == cursor_mode_) return;
|
if (mode == cursor_mode_) return;
|
||||||
cursor_mode_ = mode;
|
cursor_mode_ = mode;
|
||||||
|
|||||||
@@ -355,6 +355,16 @@ class RowSet {
|
|||||||
void place_crossings();
|
void place_crossings();
|
||||||
CursorMode cursor_mode() const noexcept { return cursor_mode_; }
|
CursorMode cursor_mode() const noexcept { return cursor_mode_; }
|
||||||
|
|
||||||
|
/// Writes both vertical cursors at once: the two-time pair is one instrument with one owner
|
||||||
|
/// (the main window's row set), and a scope window is written from it each frame -- reading it
|
||||||
|
/// back from that window's own plots is what lets a drag *there* move the same pair.
|
||||||
|
void set_cursors(double a, double b);
|
||||||
|
|
||||||
|
/// The trigger marker's position and whether it is up: what a scope window is written from, the
|
||||||
|
/// same way it is written from the cursor pair.
|
||||||
|
double trigger_marker_x() const noexcept { return trigger_marker_x_; }
|
||||||
|
bool trigger_marker_visible() const noexcept { return trigger_marker_on_; }
|
||||||
|
|
||||||
/// The two vertical cursors' positions, in the **display** x the axis reads -- not stream
|
/// The two vertical cursors' positions, in the **display** x the axis reads -- not stream
|
||||||
/// seconds, which they coincided with only while `display_epoch()` was always 0. A live view
|
/// seconds, which they coincided with only while `display_epoch()` was always 0. A live view
|
||||||
/// is newest-relative now, so a cursor left at -1.5 s keeps meaning "1.5 s ago" and the data
|
/// is newest-relative now, so a cursor left at -1.5 s keeps meaning "1.5 s ago" and the data
|
||||||
@@ -399,6 +409,10 @@ class RowSet {
|
|||||||
/// its label stays empty.
|
/// its label stays empty.
|
||||||
struct MeasureMark {
|
struct MeasureMark {
|
||||||
int row = 0;
|
int row = 0;
|
||||||
|
/// The signal the mark belongs to, so a *scope window* can find the row that plots it (its
|
||||||
|
/// row numbering is its own): a mark that never carried the name could only be placed in a
|
||||||
|
/// copy by index, which a window's own layout editor invalidates.
|
||||||
|
std::string signal;
|
||||||
bool level = false;
|
bool level = false;
|
||||||
double value = 0.0;
|
double value = 0.0;
|
||||||
plot::u32 color = 0;
|
plot::u32 color = 0;
|
||||||
|
|||||||
+79
@@ -1508,6 +1508,76 @@ void set_scope_layout_editing(App& app, App::ScopeWindow& scope, bool on) {
|
|||||||
if (scope.widget != nullptr) gtk_gl_area_queue_render(GTK_GL_AREA(scope.widget));
|
if (scope.widget != nullptr) gtk_gl_area_queue_render(GTK_GL_AREA(scope.widget));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sync_scope_instruments(App& app) {
|
||||||
|
if (app.scopes.empty()) return;
|
||||||
|
// A gesture in a **scope** window moves the same pair of instruments: read it back from that
|
||||||
|
// window's own controllers first, so the main window adopts it before anything is written out.
|
||||||
|
// (`sync_cursors()`/`sync_gate()` only adopt while their own plot is the one being dragged,
|
||||||
|
// which is exactly the question asked here.)
|
||||||
|
for (const std::unique_ptr<App::ScopeWindow>& scope : app.scopes) {
|
||||||
|
if (scope->rows == nullptr || scope->area == nullptr) continue;
|
||||||
|
int cursor_row = -1;
|
||||||
|
int gate_row = -1;
|
||||||
|
for (int i = 0; i < scope->rows->row_count(); ++i) {
|
||||||
|
plot::input::Controller* c = scope->area->row_controller(static_cast<plot::u32>(i));
|
||||||
|
if (c == nullptr) continue;
|
||||||
|
if (cursor_row < 0 && c->grabbed_cursor() != plot::kInvalid) cursor_row = i;
|
||||||
|
if (gate_row < 0 && c->grabbed_region() != plot::kInvalid) gate_row = i;
|
||||||
|
}
|
||||||
|
if (cursor_row < 0 && gate_row < 0) continue;
|
||||||
|
scope->rows->sync_cursors(cursor_row);
|
||||||
|
scope->rows->sync_gate(gate_row);
|
||||||
|
if (cursor_row >= 0) {
|
||||||
|
app.rows->set_cursors(scope->rows->cursor_a_x(), scope->rows->cursor_b_x());
|
||||||
|
}
|
||||||
|
if (gate_row >= 0) app.rows->set_gate(scope->rows->gate_x0(), scope->rows->gate_x1());
|
||||||
|
}
|
||||||
|
// The main window's row set is the owner: every scope is written from it each frame. The setters
|
||||||
|
// early-out when nothing changed, so this is a handful of comparisons on a steady frame.
|
||||||
|
const bool cursors = app.rows->cursors_visible();
|
||||||
|
const bool gate = app.rows->gate_visible();
|
||||||
|
const bool trigger = app.rows->trigger_marker_visible();
|
||||||
|
for (const std::unique_ptr<App::ScopeWindow>& scope : app.scopes) {
|
||||||
|
if (scope->rows == nullptr) continue;
|
||||||
|
scope->rows->set_cursors_visible(cursors);
|
||||||
|
scope->rows->set_cursor_mode(app.rows->cursor_mode());
|
||||||
|
// The pair is shared even while hidden: a window whose cursors are shown later must show them
|
||||||
|
// where the others already stand (`set_cursors()` places them only where the mode and the
|
||||||
|
// visibility let them be drawn).
|
||||||
|
scope->rows->set_cursors(app.rows->cursor_a_x(), app.rows->cursor_b_x());
|
||||||
|
scope->rows->set_gate_visible(gate);
|
||||||
|
scope->rows->set_gate(app.rows->gate_x0(), app.rows->gate_x1());
|
||||||
|
scope->rows->set_trigger_marker(app.rows->trigger_marker_x(), trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mirror_measure_marks(App& app) {
|
||||||
|
if (app.scopes.empty()) return;
|
||||||
|
for (const std::unique_ptr<App::ScopeWindow>& scope : app.scopes) {
|
||||||
|
if (scope->rows == nullptr) continue;
|
||||||
|
std::vector<RowSet::MeasureMark> marks;
|
||||||
|
for (const RowSet::MeasureMark& mk : app.measure_marks_display) {
|
||||||
|
// The window's rows are its own: find the row that plots the mark's signal (a window that
|
||||||
|
// does not show it draws nothing for it, which is what "the mark is on the trace it
|
||||||
|
// measures" means).
|
||||||
|
int row = -1;
|
||||||
|
for (int r = 0; r < scope->rows->row_count() && row < 0; ++r) {
|
||||||
|
for (int sl = 0; sl < RowSet::kSlotsPerRow; ++sl) {
|
||||||
|
if (scope->rows->row(r).signal_name[static_cast<std::size_t>(sl)] == mk.signal) {
|
||||||
|
row = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (row < 0) continue;
|
||||||
|
RowSet::MeasureMark t = mk;
|
||||||
|
t.row = row;
|
||||||
|
marks.push_back(std::move(t));
|
||||||
|
}
|
||||||
|
scope->rows->set_measure_marks(marks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sync_reopen_scopes_item(App& app) {
|
void sync_reopen_scopes_item(App& app) {
|
||||||
if (app.reopen_scopes_item == nullptr) return;
|
if (app.reopen_scopes_item == nullptr) return;
|
||||||
const std::size_t n = app.closed_windows.size();
|
const std::size_t n = app.closed_windows.size();
|
||||||
@@ -2999,6 +3069,11 @@ void place_search_marks(App& app) {
|
|||||||
gtk_label_set_text(GTK_LABEL(app.search_marks_label), text);
|
gtk_label_set_text(GTK_LABEL(app.search_marks_label), text);
|
||||||
}
|
}
|
||||||
app.rows->set_search_marks(xs, current);
|
app.rows->set_search_marks(xs, current);
|
||||||
|
// A hit is a time on the window, not a property of a row: every scope window draws the same
|
||||||
|
// marks (and the same current one) on its own plots.
|
||||||
|
for (const std::unique_ptr<App::ScopeWindow>& scope : app.scopes) {
|
||||||
|
if (scope->rows != nullptr) scope->rows->set_search_marks(xs, current);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4818,6 +4893,10 @@ gboolean tick(gpointer user) {
|
|||||||
}
|
}
|
||||||
app->rows->sync_cursors(cursor_drag_row);
|
app->rows->sync_cursors(cursor_drag_row);
|
||||||
app->rows->sync_gate(gate_drag_row);
|
app->rows->sync_gate(gate_drag_row);
|
||||||
|
// The scope windows' instruments, from the main window's one owner: the cursors, the gate band
|
||||||
|
// and the trigger marker are the same instruments on every window, and a drag on one of them
|
||||||
|
// *there* comes back through here to the one owner.
|
||||||
|
sync_scope_instruments(*app);
|
||||||
// The drag's end is a new pair of gate bounds, and the bounds are session state: save there,
|
// The drag's end is a new pair of gate bounds, and the bounds are session state: save there,
|
||||||
// the way a dragged row sizing is saved when its own gesture ends. During the drag every
|
// the way a dragged row sizing is saved when its own gesture ends. During the drag every
|
||||||
// frame would only re-arm the same 400 ms debounce, but the *end* is the one moment the
|
// frame would only re-arm the same 400 ms debounce, but the *end* is the one moment the
|
||||||
|
|||||||
@@ -2108,6 +2108,13 @@ void remember_closed_window(App& app, const App::ScopeWindow& scope);
|
|||||||
/// Opens a window from a remembered state: an empty scope window, then its rows, weights and
|
/// Opens a window from a remembered state: an empty scope window, then its rows, weights and
|
||||||
/// signals. Returns the opened window (nullptr when it could not be made).
|
/// signals. Returns the opened window (nullptr when it could not be made).
|
||||||
App::ScopeWindow* open_scope_window_from_state(App& app, const LayoutState::Window& state);
|
App::ScopeWindow* open_scope_window_from_state(App& app, const LayoutState::Window& state);
|
||||||
|
/// Writes the main window's instruments -- the two cursors, the gate band, the trigger marker --
|
||||||
|
/// into every scope window, and adopts one dragged *there* back into the main window first. Called
|
||||||
|
/// once per frame from the main tick, after the main's own `sync_cursors()`/`sync_gate()`.
|
||||||
|
void sync_scope_instruments(App& app);
|
||||||
|
/// The main window's measurement marks, translated to each scope window's own rows (by signal
|
||||||
|
/// name) and placed there: a window that plots a measured signal draws its mark.
|
||||||
|
void mirror_measure_marks(App& app);
|
||||||
/// Refreshes the *Reopen closed windows* entry: its count and whether it is sensitive.
|
/// Refreshes the *Reopen closed windows* entry: its count and whether it is sensitive.
|
||||||
void sync_reopen_scopes_item(App& app);
|
void sync_reopen_scopes_item(App& app);
|
||||||
/// Turns a scope window's own layout editor on or off, building or taking down its buttons.
|
/// Turns a scope window's own layout editor on or off, building or taking down its buttons.
|
||||||
|
|||||||
@@ -296,6 +296,7 @@ void place_measure_marks(App& app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.rows->set_measure_marks(app.measure_marks_display);
|
app.rows->set_measure_marks(app.measure_marks_display);
|
||||||
|
mirror_measure_marks(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recomputes every measurement over the window it describes and writes the results into the
|
/// Recomputes every measurement over the window it describes and writes the results into the
|
||||||
@@ -734,6 +735,7 @@ void update_measures(App& app, bool force, bool accumulate) {
|
|||||||
// `MeasureMarkSpec` -- the badge text is built where the display conversion happens).
|
// `MeasureMarkSpec` -- the badge text is built where the display conversion happens).
|
||||||
RowSet::MeasureMark mark;
|
RowSet::MeasureMark mark;
|
||||||
mark.row = row;
|
mark.row = row;
|
||||||
|
mark.signal = m.signal;
|
||||||
mark.level = spec.level;
|
mark.level = spec.level;
|
||||||
mark.value = spec.level ? spec.value : spec.value + s0;
|
mark.value = spec.level ? spec.value : spec.value + s0;
|
||||||
mark.color = color;
|
mark.color = color;
|
||||||
|
|||||||
@@ -287,6 +287,9 @@ void open_preferences(App& app) {
|
|||||||
// The crosshair's axis badges, at once like the theme: it is a drawing flag on the
|
// The crosshair's axis badges, at once like the theme: it is a drawing flag on the
|
||||||
// plots, and a change is the next frame's drawing.
|
// plots, and a change is the next frame's drawing.
|
||||||
app.rows->set_crosshair_axis_labels(s.crosshair_axis_labels);
|
app.rows->set_crosshair_axis_labels(s.crosshair_axis_labels);
|
||||||
|
for (const std::unique_ptr<App::ScopeWindow>& scope : app.scopes) {
|
||||||
|
if (scope->rows != nullptr) scope->rows->set_crosshair_axis_labels(s.crosshair_axis_labels);
|
||||||
|
}
|
||||||
// Only a failure is announced. A change arrives once per keystroke in the directory row, and a
|
// Only a failure is announced. A change arrives once per keystroke in the directory row, and a
|
||||||
// status line that flashed on each one would be the app shouting about its own bookkeeping.
|
// status line that flashed on each one would be the app shouting about its own bookkeeping.
|
||||||
if (!written) set_notice(app, "could not write the preferences file", 4);
|
if (!written) set_notice(app, "could not write the preferences file", 4);
|
||||||
|
|||||||
@@ -2018,6 +2018,77 @@ gboolean scope_probe_step(gpointer user) {
|
|||||||
remembered_name ? 1 : 0, back_rows, back_slot.c_str(),
|
remembered_name ? 1 : 0, back_rows, back_slot.c_str(),
|
||||||
a->closed_windows.size());
|
a->closed_windows.size());
|
||||||
std::fflush(stderr);
|
std::fflush(stderr);
|
||||||
|
// **The instruments are on every window**: the cursors, the gate band and the trigger
|
||||||
|
// marker are written from the main window's one owner (the next tick's
|
||||||
|
// `sync_scope_instruments()`), so the states below are asked for on the main and read on
|
||||||
|
// the scope.
|
||||||
|
a->rows->set_cursors_visible(true);
|
||||||
|
a->rows->set_cursor_mode(RowSet::CursorMode::Both);
|
||||||
|
a->rows->set_cursors(-1.0, 0.0);
|
||||||
|
a->rows->set_gate(-1.2, -0.8);
|
||||||
|
a->rows->set_gate_visible(true);
|
||||||
|
a->rows->set_trigger_marker(0.0, true);
|
||||||
|
// A real measurement on 'sine' with `show_on_plot`: the marks path is the one a user's
|
||||||
|
// measurement takes (`update_measures()` -> `place_measure_marks()` -> the windows), so a
|
||||||
|
// window that plots 'sine' must draw its ruler and one that does not must draw none.
|
||||||
|
{
|
||||||
|
Measure m;
|
||||||
|
m.signal = "sine";
|
||||||
|
m.type = MeasureType::Top;
|
||||||
|
m.options.show_on_plot = true;
|
||||||
|
// Gated: `update_measures()` restates the gate's visibility every frame (it is up while
|
||||||
|
// *any* measurement is gated), so the band is genuinely on and its bounds are the ones
|
||||||
|
// set above rather than a value the mirror would be right to hide.
|
||||||
|
m.options.gate = true;
|
||||||
|
a->measures.push_back(std::move(m));
|
||||||
|
rebuild_measures_pane(*a);
|
||||||
|
}
|
||||||
|
a->dbg_scope_step = 5;
|
||||||
|
g_timeout_add(700, scope_probe_step, a);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
case 5: {
|
||||||
|
// A frame has passed: the tick wrote the main's instruments into every window.
|
||||||
|
int cursor_ok = 0;
|
||||||
|
int gate_ok = 0;
|
||||||
|
int trigger_ok = 0;
|
||||||
|
int marks_ok = 0;
|
||||||
|
for (const std::unique_ptr<App::ScopeWindow>& scope : a->scopes) {
|
||||||
|
if (scope->rows == nullptr) continue;
|
||||||
|
const bool cursors = scope->rows->cursors_visible() &&
|
||||||
|
scope->rows->cursor_mode() == RowSet::CursorMode::Both &&
|
||||||
|
std::fabs(scope->rows->cursor_a_x() + 1.0) < 1e-9 &&
|
||||||
|
std::fabs(scope->rows->cursor_b_x()) < 1e-9;
|
||||||
|
const bool gate = scope->rows->gate_visible() &&
|
||||||
|
std::fabs(scope->rows->gate_x0() + 1.2) < 1e-9 &&
|
||||||
|
std::fabs(scope->rows->gate_x1() + 0.8) < 1e-9;
|
||||||
|
const bool trigger =
|
||||||
|
scope->rows->trigger_marker_visible() == a->rows->trigger_marker_visible() &&
|
||||||
|
std::fabs(scope->rows->trigger_marker_x() - a->rows->trigger_marker_x()) < 1e-9;
|
||||||
|
// The mark: the window that plots 'sine' has it, one that does not has none. Which is
|
||||||
|
// which is read off the same names.
|
||||||
|
bool plots_sine = false;
|
||||||
|
for (int r = 0; r < scope->rows->row_count(); ++r) {
|
||||||
|
for (int sl = 0; sl < RowSet::kSlotsPerRow; ++sl) {
|
||||||
|
if (scope->rows->row(r).signal_name[static_cast<std::size_t>(sl)] == "sine") {
|
||||||
|
plots_sine = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int placed = scope->rows->measure_marks_placed();
|
||||||
|
const bool mark = plots_sine ? placed == 1 : placed == 0;
|
||||||
|
cursor_ok += cursors ? 1 : 0;
|
||||||
|
gate_ok += gate ? 1 : 0;
|
||||||
|
trigger_ok += trigger ? 1 : 0;
|
||||||
|
marks_ok += mark ? 1 : 0;
|
||||||
|
}
|
||||||
|
const int n = static_cast<int>(a->scopes.size());
|
||||||
|
std::fprintf(stderr,
|
||||||
|
"[scope-probe] instruments windows=%d cursors=%d gate=%d trigger=%d "
|
||||||
|
"marks=%d (main trigger on=%d x=%.3f)\n",
|
||||||
|
n, cursor_ok, gate_ok, trigger_ok, marks_ok,
|
||||||
|
a->rows->trigger_marker_visible() ? 1 : 0, a->rows->trigger_marker_x());
|
||||||
|
std::fflush(stderr);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in new issue
Block a user