scope: full-screen figures, second windows, gated measurements, per-configuration events
A batch of view and instrument work, with the probes and docs for each. - **Full screen per figure row**: a toggle on each row's top-right corner, revealed by pointer proximity (`kMaximizeRevealPx` around its placed rect, per row, read from an overlay-level motion controller so a revealed button under the pointer cannot flicker); the plot menu offers the same as *Full screen this figure* / *Restore the layout*. The arrangement is saved and restored through `RowState`, so nothing plotted moves. A layout of one figure carries no toggle. - **Second window**: `open_scope_window()` copies a figure (cells, width shares, signals in their colours) or opens an empty one, with its own `RowSet` and `PlotArea`; the main window's tick binds, acquires and repaints it, mirroring the time window and pin. Entries: the plot menu's *Open this plot in a new window* and the overflow menu's *New scope window*. - **Layout editor from the plot**: the plot menu gains *Edit the layout...* / *Done editing the layout*, flipping the app's one toggle. - **Measurements gate**: `MeasureOptions::gate` restricts a measurement to the held/pause snapshot (live falls back to the live ring), persisted with the session and shown in the measure dialog. - **Crosshair axis badges**: a preference (`crosshair_axis_labels`, on by default) and the plotter's badges where the lines meet the axes, in the axes' own formats; the plot menu and the probe read them. - **Event cache per configuration**: `EventStore` is keyed `<source>/<configuration>/`, `retarget_event_store()` follows every configuration switch, and a pre-configuration cache (loose files) is adopted into the configuration's folder on first start. - **GTK4 lifecycle**: the main window's handlers move from the non-existent `"destroy"` signal to `close-request`; scope windows are closed with it and the application quits explicitly (the exit run's hang). The exit probe closes with `gtk_window_close()`. - Probes: `[maximize-probe]` (single-figure rule and the corner reveal), `[scope-probe]`, `[split-probe]` cell crosshair leg, `[prefs-probe]` store keying, `[configs]` store key, `[rowmenu]` layout-editor entry; docs, help pages, README and AGENT.md updated. Also fixes a probe-only use-after-free: `toggle_maximize_figure_row` replaces the figure object, so the area must be re-pointed (the button's path does; the probe's raw call did not).
This commit is contained in:
1 parent
bfe13630f9
commit
bdf0ff7ddc
39 files changed
+2267
-136
No files matched your search
+11
-1
@@ -39,6 +39,7 @@ Settings read_rows(const PrefsForm& f) {
|
||||
s.relative_time = adw_switch_row_get_active(f.relative_row) != FALSE;
|
||||
s.memory_limit_mb = static_cast<int>(adw_spin_row_get_value(f.memory_row));
|
||||
s.theme = theme_name(adw_combo_row_get_selected(f.theme_row));
|
||||
s.crosshair_axis_labels = adw_switch_row_get_active(f.crosshair_row) != FALSE;
|
||||
// The row shows the *effective* directory, so the default is written out in full rather than
|
||||
// described. Leaving it at that default is not a choice to pin it: the file keeps "unset", and the
|
||||
// setting goes on following the cache directory it is named after.
|
||||
@@ -67,6 +68,7 @@ void fill_rows(PrefsForm& f, const Settings& s) {
|
||||
adw_switch_row_set_active(f.relative_row, s.relative_time ? TRUE : FALSE);
|
||||
adw_spin_row_set_value(f.memory_row, s.memory_limit_mb);
|
||||
adw_combo_row_set_selected(f.theme_row, s.theme == "light" ? 1 : (s.theme == "dark" ? 2 : 0));
|
||||
adw_switch_row_set_active(f.crosshair_row, s.crosshair_axis_labels ? TRUE : FALSE);
|
||||
f.filling = false;
|
||||
}
|
||||
|
||||
@@ -146,6 +148,7 @@ void on_closed(AdwDialog*, gpointer user) {
|
||||
f.relative_row = nullptr;
|
||||
f.memory_row = nullptr;
|
||||
f.theme_row = nullptr;
|
||||
f.crosshair_row = nullptr;
|
||||
f.browse = nullptr;
|
||||
f.parent = nullptr;
|
||||
}
|
||||
@@ -160,13 +163,15 @@ void resolve_rows(PrefsForm& f) {
|
||||
f.relative_row = ADW_SWITCH_ROW(gtk_builder_get_object(f.builder, "relative_row"));
|
||||
f.theme_row = ADW_COMBO_ROW(gtk_builder_get_object(f.builder, "theme_row"));
|
||||
f.memory_row = ADW_SPIN_ROW(gtk_builder_get_object(f.builder, "memory_row"));
|
||||
f.crosshair_row = ADW_SWITCH_ROW(gtk_builder_get_object(f.builder, "crosshair_axis_labels_row"));
|
||||
if (f.dir_row == nullptr || f.keep_row == nullptr || f.relative_row == nullptr ||
|
||||
f.theme_row == nullptr || f.memory_row == nullptr) {
|
||||
f.theme_row == nullptr || f.memory_row == nullptr || f.crosshair_row == nullptr) {
|
||||
f.dir_row = nullptr;
|
||||
f.keep_row = nullptr;
|
||||
f.relative_row = nullptr;
|
||||
f.theme_row = nullptr;
|
||||
f.memory_row = nullptr;
|
||||
f.crosshair_row = nullptr;
|
||||
g_clear_object(&f.builder);
|
||||
}
|
||||
}
|
||||
@@ -222,6 +227,7 @@ void prefs_open(PrefsForm& form, GtkWidget* parent, const Settings& current,
|
||||
g_signal_connect(form.relative_row, "notify::active", G_CALLBACK(on_row_notify), &form);
|
||||
g_signal_connect(form.memory_row, "notify::value", G_CALLBACK(on_row_notify), &form);
|
||||
g_signal_connect(form.theme_row, "notify::selected", G_CALLBACK(on_row_notify), &form);
|
||||
g_signal_connect(form.crosshair_row, "notify::active", G_CALLBACK(on_row_notify), &form);
|
||||
if (GObject* reset = gtk_builder_get_object(form.builder, "reset_row"); reset != nullptr) {
|
||||
g_signal_connect(reset, "activated", G_CALLBACK(on_reset), &form);
|
||||
}
|
||||
@@ -248,6 +254,7 @@ void prefs_probe_change(PrefsForm& form) {
|
||||
adw_switch_row_set_active(form.relative_row, TRUE);
|
||||
adw_spin_row_set_value(form.memory_row, 4096.0);
|
||||
adw_combo_row_set_selected(form.theme_row, 2);
|
||||
adw_switch_row_set_active(form.crosshair_row, FALSE);
|
||||
}
|
||||
|
||||
/// A changed memory limit reaches the running model. Only when it differs from the model's own (every
|
||||
@@ -277,6 +284,9 @@ void open_preferences(App& app) {
|
||||
prefs_open(app.prefs, app.window, app.settings, [&app](const Settings& s, bool written) {
|
||||
app.settings = s;
|
||||
apply_memory_limit(app, s.memory_limit_mb);
|
||||
// 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.
|
||||
app.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
|
||||
// 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);
|
||||
|
||||
Reference in new issue
Block a user