Gated measurements #2
No files matched your search
@@ -629,3 +629,11 @@ samples. Three rules keep that honest:
|
||||
its ink is not in the widget's paint tree, so `gtk_snapshot_free_to_node()` on a widget paintable of
|
||||
it returns NULL and the "screenshot" would be an empty file. Drawing it in the store also keeps that
|
||||
class GTK-free, which is what makes the cache testable without a window.
|
||||
|
||||
- **A pin is mirrored as a *range*, never as a pair of numbers that might be spans.** `Range`
|
||||
(`pinned_range()`: `{-pre, +post}`) and the pin's *spans* (`pin_event_window(pre, post)`) are two
|
||||
different things that both look like a pair, and mixing them inverts the window: a second view
|
||||
that handed `pinned_range().min` to `pin_event_window()` pinned to `[+pre, +post]`, and the plot
|
||||
drew nothing — no trace, no axis labels — because the x range was degenerate. Views that mirror a
|
||||
pin use `pin_display_range(x0, x1)`, the range's own form. `[scope-probe] pin_mirror=1` reads the
|
||||
two windows' pins and the scope's x range, and an inverted pin reads `0`.
|
||||
@@ -1474,6 +1474,7 @@ a defect in the copy. Measured output:
|
||||
[scope-probe] gl copy=ok(67f) empty=ok(39f) empty_bound=1
|
||||
[scope-probe] gl detached ok=1 frames=42 rows=1 slot0='sine'
|
||||
[scope-probe] rclick=1
|
||||
[scope-probe] pin_mirror=1 main=[-1.000..1.000] scope=[-1.000..1.000] x=[-1.000..1.000]
|
||||
```
|
||||
|
||||
- `count=2` is both windows having been created and retained; `windows=1` each being a visible
|
||||
@@ -1493,6 +1494,12 @@ a defect in the copy. Measured output:
|
||||
signal into it" — landing in its row set. `drop=0` names a refused drop (a full plot or an
|
||||
unacquirable signal); `page_groups` less than the window count is a page rebuilt before the
|
||||
windows were read or a group that lost its window.
|
||||
- `pin_mirror=1` is a scope window **mirroring a pin as a range**: the probe pins the main window
|
||||
and reads the scope's pin and its plot's x range a frame later. Both must agree and the x range
|
||||
must be ordered (`x=[min..max]`, `min < max`). A `0` with an inverted scope pin (`[+pre, +post]`)
|
||||
is the defect this exists for: `pin_event_window()` takes **spans**, and passing it a range's
|
||||
signed `min` turned the window inside out, so a scope in Held or Paused mode drew no trace and no
|
||||
x labels at all.
|
||||
- `rclick=1` is the scope window's **own right-click menu** being wired (one click gesture with
|
||||
button 3 on its GL area, beside the drop target): the menu's actions act on that window's row
|
||||
set.
|
||||
|
||||
@@ -1509,6 +1509,19 @@ void RowSet::pin_event_window(double pre_s, double post_s) {
|
||||
figure_->set_x_link_range(x_group_, {-pre_s, post_s});
|
||||
}
|
||||
|
||||
void RowSet::pin_display_range(double x0, double x1) {
|
||||
if (!(x1 > x0)) return;
|
||||
window_s_ = std::max(1.0e-3, x1 - x0);
|
||||
pinned_ = true;
|
||||
pinned_pre_ = -x0;
|
||||
pinned_post_ = x1;
|
||||
if (!figure_) return;
|
||||
// The same two statements `pin_event_window()` makes, from the range instead of the spans: the
|
||||
// group stops following the live edge and is placed on the event's own window.
|
||||
figure_->set_x_link_follow(x_group_, plot::XFollow::Off);
|
||||
figure_->set_x_link_range(x_group_, {x0, x1});
|
||||
}
|
||||
|
||||
void RowSet::fit_all() {
|
||||
for (int i = 0; i < rows_; ++i) {
|
||||
Row& r = row(i);
|
||||
|
||||
@@ -570,6 +570,13 @@ class RowSet {
|
||||
/// 0, so nothing outside the pre+post window is visible.
|
||||
void pin_event_window(double pre_s, double post_s);
|
||||
|
||||
/// The same pin, stated as the **range** a second view mirrors: the caller has the display
|
||||
/// range (`x0 < x1`) and not the spans -- a scope window takes `pinned_range()` from the main
|
||||
/// window and hands it on. `pin_event_window()` takes *spans*, and passing it a range's signed
|
||||
/// `min` turned the pin inside out (a scope in Held mode pinned to `[+pre, +post]`: no trace
|
||||
/// and no x labels). A degenerate or inverted range pins nothing.
|
||||
void pin_display_range(double x0, double x1);
|
||||
|
||||
/// Fits every row's y axis to the data it holds, and puts x back on the whole time window --
|
||||
/// `fit_x()`'s x half exactly, so the two cannot drift apart. Like it, **this does not change
|
||||
/// the time window**: the y axes are fitted to their data, x is merely un-zoomed.
|
||||
|
||||
+12
-6
@@ -4633,17 +4633,23 @@ gboolean tick(gpointer user) {
|
||||
const double window_s = app->rows->time_window();
|
||||
for (const std::unique_ptr<App::ScopeWindow>& scope : app->scopes) {
|
||||
if (pinned) {
|
||||
scope->rows->pin_event_window(pin.min, pin.max);
|
||||
// The pin as a *range*: `pin_event_window()` takes spans (pre, post), and handing it
|
||||
// `pin.min` -- a signed time -- inverted the window, so a scope in Held or Paused mode
|
||||
// drew no trace and no x labels at all.
|
||||
scope->rows->pin_display_range(pin.min, pin.max);
|
||||
} else if (std::fabs(scope->rows->time_window() - window_s) > 1.0e-12) {
|
||||
scope->rows->set_time_window(window_s);
|
||||
}
|
||||
// An arrangement change (a drop, a *Plot on* button) rebuilt the row set: point the area at
|
||||
// the new figure here, in the tick -- the change arrives from inside this very widget (a drop
|
||||
// signal), and a synchronous rebuild would reset the drag controller under it.
|
||||
// REPRO-TEMP: rebuild disabled
|
||||
// if (scope->rows->rebuild_if_dirty() && scope->area != nullptr) {
|
||||
// scope->area->set_figure(&scope->rows->figure());
|
||||
// }
|
||||
// signal), and a synchronous rebuild would reset the drag controller under it. The traces
|
||||
// themselves are `SlotSeries` rebinds, so a slot that gains or loses a source draws either
|
||||
// way; what *does* need this is the figure's own state: a row's legend, its cell structure,
|
||||
// and the trace objects `install()` creates only for the slots that hold a signal at rebuild
|
||||
// time -- a window opened empty and filled by a drop has none until this runs.
|
||||
if (scope->rows->rebuild_if_dirty() && scope->area != nullptr) {
|
||||
scope->area->set_figure(&scope->rows->figure());
|
||||
}
|
||||
if (scope->detached) sync_scope_attach(*app, *scope);
|
||||
// **A window that cannot paint says so.** A blank plot is indistinguishable from a
|
||||
// context that failed or an area that never got a frame, and the report ("nothing is
|
||||
|
||||
+28
-3
@@ -1915,11 +1915,13 @@ gboolean scope_probe_step(gpointer user) {
|
||||
det.rows != nullptr && det.rows->row_count() > 0
|
||||
? det.rows->row(0).signal_name[0].c_str()
|
||||
: "");
|
||||
}
|
||||
// The scope window carries its own right-click menu (its gesture is on the GL area, wired
|
||||
// beside the drop target): one click gesture whose button is 3, per window.
|
||||
int right_clicks = 0;
|
||||
if (det.widget != nullptr) {
|
||||
GListModel* controllers = gtk_widget_observe_controllers(det.widget);
|
||||
GtkWidget* det_widget = a->scopes.empty() ? nullptr : a->scopes.back()->widget;
|
||||
if (det_widget != nullptr) {
|
||||
GListModel* controllers = gtk_widget_observe_controllers(det_widget);
|
||||
const guint n = g_list_model_get_n_items(G_LIST_MODEL(controllers));
|
||||
for (guint i = 0; i < n; ++i) {
|
||||
GObject* c = G_OBJECT(g_list_model_get_item(controllers, i));
|
||||
@@ -1933,8 +1935,31 @@ gboolean scope_probe_step(gpointer user) {
|
||||
}
|
||||
std::fprintf(stderr, "[scope-probe] rclick=%d\n", right_clicks);
|
||||
std::fflush(stderr);
|
||||
}
|
||||
// **The pin mirror**: a held event pins the main window, and every scope must be pinned to
|
||||
// the *same range*. `pin_event_window()` takes spans (pre, post) and passing it a range's
|
||||
// signed min turned the pin inside out (a scope in Held drew no trace and no x labels).
|
||||
a->rows->pin_event_window(1.6, 0.4);
|
||||
a->dbg_scope_step = 4;
|
||||
g_timeout_add(350, scope_probe_step, a);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
case 4: {
|
||||
const plot::Range main_pin = a->rows->pinned_range();
|
||||
const plot::Range scope_pin = a->scopes[0]->rows->pinned_range();
|
||||
const plot::Range scope_x = a->scopes[0]->rows->row(0).plot != nullptr
|
||||
? a->scopes[0]->rows->row(0).plot->x_range(0)
|
||||
: plot::Range{};
|
||||
const bool pinned = a->scopes[0]->rows->window_pinned() == a->rows->window_pinned();
|
||||
const bool same = std::fabs(scope_pin.min - main_pin.min) < 1e-9 &&
|
||||
std::fabs(scope_pin.max - main_pin.max) < 1e-9 &&
|
||||
scope_x.max > scope_x.min;
|
||||
std::fprintf(stderr,
|
||||
"[scope-probe] pin_mirror=%d main=[%.3f..%.3f] scope=[%.3f..%.3f] "
|
||||
"x=[%.3f..%.3f]\n",
|
||||
pinned && same ? 1 : 0, main_pin.min, main_pin.max, scope_pin.min,
|
||||
scope_pin.max, scope_x.min, scope_x.max);
|
||||
std::fflush(stderr);
|
||||
a->rows->set_time_window(2.0); // unpin: leave the window as the run found it
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in new issue
Block a user