ui: Arm is disabled with trigger mode off, and the redundant Go-live button is gone
**`Arm` is now disabled while trigger mode is off**, and labelled `Arm` again: it is the one control in that pane that is *runtime* rather than setting, so with no engine running there is nothing to arm. It is also the only thing in the body that stays disabled — the settings themselves stay editable, which is the point of the previous commit. `arm sensitive with the trigger off=0` is the reading. **`Go live (trigger off)` is deleted.** Its handler was `trigger_toggle → FALSE`, i.e. exactly the toolbar's trigger switch and the pane's own switch, which is what it was for: "the way out of trigger mode, from inside the panel that froze the view: it is the toolbar's trigger switch, so there is exactly one piece of state." With that switch now in the pane's own heading, the button was the same control drawn a third time. The status line that told users about it says "or switch the trigger off to stream" instead. The events pane's own `events_live` button is a different button on a different path — the file view restore — and is untouched. **And one silent regression this work uncovered.** The `trigger panel:` frame reading had been walking the *wrapper* box the app puts around the `.ui`'s panel (heading row + locked summary + panel) ever since the heading moved out of the file in the lock commit, so it reported `boxes=2 … search_inside=0/4` against a panel that was entirely correct. It reads `trigger_body` — the file's own panel — again, and now says so in its comment, because a reading that can silently start describing the wrong widget is the failure it exists to catch. Verified: `trigger panel: boxes=15 controls_inside=15/15 search_widgets=4/4 search_inside=4/4` (the documented shape, restored); `arm sensitive with the trigger off=0`; `trigger panel sensitive …=1`; `panes:`/`panel switches:`/`pane edits:` unchanged; `make test-ui` 14 files; zero `Gtk-CRITICAL`.
This commit is contained in:
1 parent
796dda4ad5
commit
d8705a369f
6 files changed
+40
-36
No files matched your search
@@ -1169,6 +1169,9 @@ its pane.
|
|||||||
a trigger is configured before it is switched on — so this reads `1` always, and a `0` means the
|
a trigger is configured before it is switched on — so this reads `1` always, and a `0` means the
|
||||||
settings have been made unreachable again. The *cursors'* body is disabled with the cursors, and that
|
settings have been made unreachable again. The *cursors'* body is disabled with the cursors, and that
|
||||||
is the pane whose readout has nothing to show.
|
is the pane whose readout has nothing to show.
|
||||||
|
- **`arm sensitive with the trigger off=0`** is the one exception inside that body: `Arm` is a *runtime*
|
||||||
|
control, so with trigger mode off there is no engine to arm and it is disabled (and labelled `Arm`
|
||||||
|
again). `1` here is an Arm button that does nothing when clicked.
|
||||||
- **`summary`** is the locked trigger pane's whole content, as `key: value` pairs separated by ` |`. The
|
- **`summary`** is the locked trigger pane's whole content, as `key: value` pairs separated by ` |`. The
|
||||||
pane draws it as a small definition list — `signal`, `condition`, `level`, `mode` on four lines, and
|
pane draws it as a small definition list — `signal`, `condition`, `level`, `mode` on four lines, and
|
||||||
then only the figures that are *not* at their defaults (`noise band`, `HF reject`, `pre-trigger`,
|
then only the figures that are *not* at their defaults (`noise band`, `HF reject`, `pre-trigger`,
|
||||||
@@ -1348,7 +1351,11 @@ through one row type, for the reason in `invariants-gtk-and-chrome.md`. The form
|
|||||||
[udpscope] trigger panel: boxes=15 controls_inside=15/15 search_widgets=4/4 search_inside=4/4
|
[udpscope] trigger panel: boxes=15 controls_inside=15/15 search_widgets=4/4 search_inside=4/4
|
||||||
```
|
```
|
||||||
|
|
||||||
The trigger panel's frame, read from the window: `boxes` is the row boxes the `.ui` holds, `controls_inside`
|
The trigger panel's frame, read from the window: **the `.ui`'s own panel** (`trigger_body`), not the box
|
||||||
|
this app wraps it in — the heading row and the locked summary are the code's arrangement, and reading the
|
||||||
|
*wrapper* made this line report `boxes=2 … search_inside=0/4` the moment the heading moved out of the file.
|
||||||
|
That is the failure this line is for, so it is worth knowing it can happen to itself. `boxes` is the row
|
||||||
|
boxes the `.ui` holds, `controls_inside`
|
||||||
counts the fifteen controls the code built and then appended into those rows -- the last two being the
|
counts the fifteen controls the code built and then appended into those rows -- the last two being the
|
||||||
noise band and the HF reject, whose rows arrived with the noise-rejection work, `search_widgets` is the four
|
noise band and the HF reject, whose rows arrived with the noise-rejection work, `search_widgets` is the four
|
||||||
search buttons having resolved by id, and `search_inside` is those four being inside the block the expander
|
search buttons having resolved by id, and `search_inside` is those four being inside the block the expander
|
||||||
|
|||||||
+25
-21
@@ -4082,7 +4082,7 @@ gboolean tick(gpointer user) {
|
|||||||
if (app->capturing) {
|
if (app->capturing) {
|
||||||
mode = "trigger: CAPTURING (post-trigger window filling)";
|
mode = "trigger: CAPTURING (post-trigger window filling)";
|
||||||
} else if (app->event_held) {
|
} else if (app->event_held) {
|
||||||
mode = "trigger: EVENT HELD (Arm to re-arm, or 'Go live' for streaming)";
|
mode = "trigger: EVENT HELD (Arm to re-arm, or switch the trigger off to stream)";
|
||||||
} else if (armed && have_trigger_value) {
|
} else if (armed && have_trigger_value) {
|
||||||
static char waiting[192];
|
static char waiting[192];
|
||||||
std::snprintf(waiting, sizeof(waiting),
|
std::snprintf(waiting, sizeof(waiting),
|
||||||
@@ -4857,6 +4857,8 @@ void on_activate(GtkApplication* application, gpointer user) {
|
|||||||
// switch that turns it back on. The trigger's body is deliberately *not* disabled: a trigger is
|
// switch that turns it back on. The trigger's body is deliberately *not* disabled: a trigger is
|
||||||
// configured before it is switched on, so its settings have to stay editable while it is off.
|
// configured before it is switched on, so its settings have to stay editable while it is off.
|
||||||
gtk_widget_set_sensitive(app->cursors_body, FALSE);
|
gtk_widget_set_sensitive(app->cursors_body, FALSE);
|
||||||
|
// The trigger's Arm button is the one control in its pane that needs trigger mode running.
|
||||||
|
if (app->arm_button != nullptr) gtk_widget_set_sensitive(app->arm_button, FALSE);
|
||||||
gtk_widget_set_sensitive(app->cursors_reset, FALSE);
|
gtk_widget_set_sensitive(app->cursors_reset, FALSE);
|
||||||
|
|
||||||
if (app->side_stack != nullptr) {
|
if (app->side_stack != nullptr) {
|
||||||
@@ -5968,10 +5970,10 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
|
|||||||
app.dbg_badge_frames[3]);
|
app.dbg_badge_frames[3]);
|
||||||
std::printf("[udpscope] trigger panel sensitive before the probe toggled it: %d; "
|
std::printf("[udpscope] trigger panel sensitive before the probe toggled it: %d; "
|
||||||
"signal list items=%d selected=%d; column visible after sidebar toggle off=%d; "
|
"signal list items=%d selected=%d; column visible after sidebar toggle off=%d; "
|
||||||
"pane switches live while their panes are off=%d\n",
|
"pane switches live while their panes are off=%d; arm sensitive with the trigger off=%d\n",
|
||||||
app.dbg_trigger_sensitive_default, app.dbg_trigger_items,
|
app.dbg_trigger_sensitive_default, app.dbg_trigger_items,
|
||||||
app.dbg_trigger_selected, app.dbg_side_column_after_hide,
|
app.dbg_trigger_selected, app.dbg_side_column_after_hide,
|
||||||
app.dbg_panel_switch_live);
|
app.dbg_panel_switch_live, app.dbg_arm_sensitive);
|
||||||
{
|
{
|
||||||
// The panel's *frame* read back: the row boxes the `.ui` holds, and that every control the code built
|
// The panel's *frame* read back: the row boxes the `.ui` holds, and that every control the code built
|
||||||
// ended up inside the panel rather than in a row that is not there. A control is created in code and
|
// ended up inside the panel rather than in a row that is not there. A control is created in code and
|
||||||
@@ -5985,8 +5987,10 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
// The *file's* panel (`trigger_body`), not the wrapper this app puts it in: the heading row and the
|
||||||
|
// locked summary are the code's arrangement, and what these counts read is what the `.ui` holds.
|
||||||
int boxes = 0;
|
int boxes = 0;
|
||||||
for (GtkWidget* c = gtk_widget_get_first_child(app.trigger_panel); c != nullptr;
|
for (GtkWidget* c = gtk_widget_get_first_child(app.trigger_body); c != nullptr;
|
||||||
c = gtk_widget_get_next_sibling(c)) {
|
c = gtk_widget_get_next_sibling(c)) {
|
||||||
if (GTK_IS_BOX(c)) ++boxes;
|
if (GTK_IS_BOX(c)) ++boxes;
|
||||||
}
|
}
|
||||||
@@ -5998,8 +6002,8 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
|
|||||||
// a throwaway program, all three ways of setting it). So the walk the search widgets are read with has
|
// a throwaway program, all three ways of setting it). So the walk the search widgets are read with has
|
||||||
// to start at the expander's child and not at the panel -- walking to the panel reads 0/4 on a panel
|
// to start at the expander's child and not at the panel -- walking to the panel reads 0/4 on a panel
|
||||||
// that is entirely correct, which is what this line did first.
|
// that is entirely correct, which is what this line did first.
|
||||||
GtkWidget* search_root = app.trigger_panel;
|
GtkWidget* search_root = app.trigger_body;
|
||||||
for (GtkWidget* c = gtk_widget_get_first_child(app.trigger_panel); c != nullptr;
|
for (GtkWidget* c = gtk_widget_get_first_child(app.trigger_body); c != nullptr;
|
||||||
c = gtk_widget_get_next_sibling(c)) {
|
c = gtk_widget_get_next_sibling(c)) {
|
||||||
if (GTK_IS_EXPANDER(c)) {
|
if (GTK_IS_EXPANDER(c)) {
|
||||||
if (GtkWidget* inner = gtk_expander_get_child(GTK_EXPANDER(c))) search_root = inner;
|
if (GtkWidget* inner = gtk_expander_get_child(GTK_EXPANDER(c))) search_root = inner;
|
||||||
@@ -6013,21 +6017,21 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
|
|||||||
"[udpscope] trigger panel: boxes=%d controls_inside=%d/15 search_widgets=%d/4 "
|
"[udpscope] trigger panel: boxes=%d controls_inside=%d/15 search_widgets=%d/4 "
|
||||||
"search_inside=%d/4\n",
|
"search_inside=%d/4\n",
|
||||||
boxes,
|
boxes,
|
||||||
inside(app.trigger_signal_drop, app.trigger_panel) +
|
inside(app.trigger_signal_drop, app.trigger_body) +
|
||||||
inside(app.trigger_type_drop, app.trigger_panel) +
|
inside(app.trigger_type_drop, app.trigger_body) +
|
||||||
inside(app.trigger_edge_drop, app.trigger_panel) +
|
inside(app.trigger_edge_drop, app.trigger_body) +
|
||||||
inside(app.trigger_cmp_drop, app.trigger_panel) +
|
inside(app.trigger_cmp_drop, app.trigger_body) +
|
||||||
inside(app.trigger_mode_drop, app.trigger_panel) +
|
inside(app.trigger_mode_drop, app.trigger_body) +
|
||||||
inside(app.trigger_width_spin, app.trigger_panel) +
|
inside(app.trigger_width_spin, app.trigger_body) +
|
||||||
inside(app.trigger_width2_spin, app.trigger_panel) +
|
inside(app.trigger_width2_spin, app.trigger_body) +
|
||||||
inside(app.trigger_level2_spin, app.trigger_panel) +
|
inside(app.trigger_level2_spin, app.trigger_body) +
|
||||||
inside(app.trigger_timeout_spin, app.trigger_panel) +
|
inside(app.trigger_timeout_spin, app.trigger_body) +
|
||||||
inside(app.trigger_level_spin, app.trigger_panel) +
|
inside(app.trigger_level_spin, app.trigger_body) +
|
||||||
inside(app.trigger_pre_spin, app.trigger_panel) +
|
inside(app.trigger_pre_spin, app.trigger_body) +
|
||||||
inside(app.trigger_holdoff_spin, app.trigger_panel) +
|
inside(app.trigger_holdoff_spin, app.trigger_body) +
|
||||||
inside(app.trigger_band_spin, app.trigger_panel) +
|
inside(app.trigger_band_spin, app.trigger_body) +
|
||||||
inside(app.trigger_hf_spin, app.trigger_panel) +
|
inside(app.trigger_hf_spin, app.trigger_body) +
|
||||||
inside(app.events_record_switch, app.trigger_panel),
|
inside(app.events_record_switch, app.trigger_body),
|
||||||
search_present,
|
search_present,
|
||||||
inside(app.search_run_button, search_root) + inside(app.search_cancel_button, search_root) +
|
inside(app.search_run_button, search_root) + inside(app.search_cancel_button, search_root) +
|
||||||
inside(app.search_prev_button, search_root) + inside(app.search_next_button, search_root));
|
inside(app.search_prev_button, search_root) + inside(app.search_next_button, search_root));
|
||||||
|
|||||||
@@ -212,12 +212,6 @@
|
|||||||
<property name="label" translatable="yes">Arm</property>
|
<property name="label" translatable="yes">Arm</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="trigger_live">
|
|
||||||
<property name="label" translatable="yes">Go live (trigger off)</property>
|
|
||||||
<property name="tooltip-text" translatable="yes">disable trigger mode and stream continuously</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkExpander" id="search_exp">
|
<object class="GtkExpander" id="search_exp">
|
||||||
<property name="label" translatable="yes">Search the buffer</property>
|
<property name="label" translatable="yes">Search the buffer</property>
|
||||||
|
|||||||
+3
-1
@@ -239,6 +239,9 @@ struct App {
|
|||||||
/// parent cannot be clicked, so a switch that went insensitive with its own pane could never turn
|
/// parent cannot be clicked, so a switch that went insensitive with its own pane could never turn
|
||||||
/// it back on.
|
/// it back on.
|
||||||
int dbg_panel_switch_live = -1;
|
int dbg_panel_switch_live = -1;
|
||||||
|
/// The Arm button, read with the trigger off: it is the pane's one runtime control, so it is the one
|
||||||
|
/// thing in the body that *is* disabled with the mode.
|
||||||
|
int dbg_arm_sensitive = -1;
|
||||||
int dbg_switcher_policy = -1;
|
int dbg_switcher_policy = -1;
|
||||||
/// Whether `name_side_tabs()` has named the pills: it can only run once the switcher is mapped.
|
/// Whether `name_side_tabs()` has named the pills: it can only run once the switcher is mapped.
|
||||||
bool side_tabs_named = false;
|
bool side_tabs_named = false;
|
||||||
@@ -1347,7 +1350,6 @@ void on_layout_drag_begin(GtkGestureDrag* gesture, double x, double y, gpointer
|
|||||||
void on_layout_drag_update(GtkGestureDrag* gesture, double offset_x, double offset_y, gpointer user);
|
void on_layout_drag_update(GtkGestureDrag* gesture, double offset_x, double offset_y, gpointer user);
|
||||||
void on_layout_drag_end(GtkGestureDrag* gesture, double offset_x, double offset_y, gpointer user);
|
void on_layout_drag_end(GtkGestureDrag* gesture, double offset_x, double offset_y, gpointer user);
|
||||||
void on_trigger_toggled(GtkToggleButton* button, gpointer user);
|
void on_trigger_toggled(GtkToggleButton* button, gpointer user);
|
||||||
void on_go_live(GtkButton*, gpointer user);
|
|
||||||
plot::u32 measure_color(std::size_t index);
|
plot::u32 measure_color(std::size_t index);
|
||||||
bool visible_samples(App& app, std::size_t channel, std::vector<double>& time, std::vector<double>& value);
|
bool visible_samples(App& app, std::size_t channel, std::vector<double>& time, std::vector<double>& value);
|
||||||
int measure_channel(App& app, const std::string& signal);
|
int measure_channel(App& app, const std::string& signal);
|
||||||
|
|||||||
@@ -2341,6 +2341,7 @@ gboolean exit_probe_step1(gpointer user) {
|
|||||||
// The summary's text comes from the sync that wrote it: the container is a grid of key/value rows,
|
// The summary's text comes from the sync that wrote it: the container is a grid of key/value rows,
|
||||||
// and asking it for a label's text was itself a critical.
|
// and asking it for a label's text was itself a critical.
|
||||||
a->dbg_trigger_summary_early = a->dbg_trigger_summary; // as found, before this probe touches it
|
a->dbg_trigger_summary_early = a->dbg_trigger_summary; // as found, before this probe touches it
|
||||||
|
a->dbg_arm_sensitive = a->arm_button != nullptr && gtk_widget_get_sensitive(a->arm_button) ? 1 : 0;
|
||||||
a->dbg_panel_switch_live =
|
a->dbg_panel_switch_live =
|
||||||
a->trigger_switch != nullptr && gtk_widget_get_sensitive(a->trigger_switch) &&
|
a->trigger_switch != nullptr && gtk_widget_get_sensitive(a->trigger_switch) &&
|
||||||
a->cursors_switch != nullptr && gtk_widget_get_sensitive(a->cursors_switch)
|
a->cursors_switch != nullptr && gtk_widget_get_sensitive(a->cursors_switch)
|
||||||
|
|||||||
+3
-7
@@ -410,17 +410,15 @@ void on_trigger_toggled(GtkToggleButton* button, gpointer user) {
|
|||||||
// `sync_events_availability()`'s call and not the trigger's alone.
|
// `sync_events_availability()`'s call and not the trigger's alone.
|
||||||
sync_events_availability(*app);
|
sync_events_availability(*app);
|
||||||
gtk_button_set_label(GTK_BUTTON(app->arm_button), on ? "Disarm" : "Arm");
|
gtk_button_set_label(GTK_BUTTON(app->arm_button), on ? "Disarm" : "Arm");
|
||||||
|
// Arming is a *runtime* control: with trigger mode off there is no engine to arm, and the button is the
|
||||||
|
// one part of this pane that is not a setting. (The body itself stays live -- see above.)
|
||||||
|
if (app->arm_button != nullptr) gtk_widget_set_sensitive(app->arm_button, on);
|
||||||
// The pane's own switch shows the same state, whichever of the two was clicked.
|
// The pane's own switch shows the same state, whichever of the two was clicked.
|
||||||
sync_panel_switches(*app);
|
sync_panel_switches(*app);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The way out of trigger mode, from inside the panel that froze the view: it is
|
/// The way out of trigger mode, from inside the panel that froze the view: it is
|
||||||
/// the toolbar's trigger switch, so there is exactly one piece of state.
|
/// the toolbar's trigger switch, so there is exactly one piece of state.
|
||||||
void on_go_live(GtkButton*, gpointer user) {
|
|
||||||
App* app = static_cast<App*>(user);
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(app->trigger_toggle), FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The row the `.ui` declares for a control, with the control appended to it.
|
/// The row the `.ui` declares for a control, with the control appended to it.
|
||||||
///
|
///
|
||||||
/// The label is the file's, because it is text a translator owns; the control is code's, because a
|
/// The label is the file's, because it is text a translator owns; the control is code's, because a
|
||||||
@@ -545,8 +543,6 @@ GtkWidget* build_trigger_panel(App& app) {
|
|||||||
if (app.arm_button != nullptr) {
|
if (app.arm_button != nullptr) {
|
||||||
g_signal_connect(app.arm_button, "clicked", G_CALLBACK(on_arm_clicked), &app);
|
g_signal_connect(app.arm_button, "clicked", G_CALLBACK(on_arm_clicked), &app);
|
||||||
}
|
}
|
||||||
GtkWidget* live = GTK_WIDGET(gtk_builder_get_object(ui, "trigger_live"));
|
|
||||||
if (live != nullptr) g_signal_connect(live, "clicked", G_CALLBACK(on_go_live), &app);
|
|
||||||
|
|
||||||
for (GtkWidget* w : {app.trigger_level_spin, app.trigger_pre_spin, app.trigger_holdoff_spin,
|
for (GtkWidget* w : {app.trigger_level_spin, app.trigger_pre_spin, app.trigger_holdoff_spin,
|
||||||
app.trigger_width_spin, app.trigger_width2_spin,
|
app.trigger_width_spin, app.trigger_width2_spin,
|
||||||
|
|||||||
Reference in new issue
Block a user