ui: each pane carries its own switch, the same one the header bar has
The trigger pane and the cursors pane now have a `GtkSwitch` in their heading, and it is *one control in
two places* with the header bar's button: both run the same action (`run_app_action()`), and
`sync_panel_switches()` re-reads each pair from the toolbar's state after any change, so clicking either
end moves both. A pane whose feature is off is disabled, which is exactly the state you need the switch
in, so it belongs *in* the pane rather than only in the toolbar.
Three things it needed:
- **The sensitive target moved to the pane's body.** A control inside an insensitive parent cannot be
clicked, so a switch that greyed out with its own pane could never turn it back on. `on_trigger_toggled`
and `on_cursors_toggled` now disable `trigger_body` / `cursors_body`, and so does the startup default;
the headings, with their switches, stay live.
- **The trigger's heading moved out of `trigger-panel.ui`** and is built in `build_trigger_panel()`,
which returns the heading row and the panel together. It has to be a sibling of the body for the switch
to stay usable, and keeping it in the file would have meant the file owning a widget the code must
arrange. The file's own panel is unchanged otherwise, so the `[trigger panel:]` counts still read.
- **A guard on the sync.** Setting a `GtkSwitch` emits `notify::active` for a programmatic write just as
it does for a click, so without `App::panel_switch_sync` the program's own write would come back as a
click and flip the feature again.
Readings, both directions in one line:
trigger panel sensitive before the probe toggled it: 0; … ; pane switches live while their panes are off=1
panel switches: trigger=1/1 cursors=1/1 drove_toolbar=1 (pane switch / header bar button)
`pane switches live …=1` is the design's point and is read before anything turns either pane on; `0` would
be a switch drawn, greyed and useless. The trigger pair is moved from the *toolbar* end and the cursors
pair from the *pane* end, so the line carries both halves of the sync, and `drove_toolbar=1` is the pane's
own switch having turned the cursors on with the button following. `trigger panel sensitive …=0` is the
body, not the panel.
Verified: the two lines above; `[side-tab-probe] … advanced=4`; `make test-ui` 14 files; zero
`Gtk-CRITICAL` and no missing icon. Docs: the new reading in `probe-readings.md` with what a `0` means,
the invariants bullet for the one-control-in-two-places rule and its two traps, the sidebar bullet's
sensitive target, and the README note on why the switch is in the pane.
This commit is contained in:
1 parent
d9287ea826
commit
cc8335c514
10 files changed
+201
-26
No files matched your search
+31
-3
@@ -196,14 +196,18 @@ void on_trigger_toggled(GtkToggleButton* button, gpointer user) {
|
||||
app->model->set_signal_enabled(static_cast<std::size_t>(signal), true);
|
||||
}
|
||||
// Disabled, not hidden: a panel you can still see is a panel you can read, and the settings you
|
||||
// are about to switch back on must not vanish while you look for them.
|
||||
gtk_widget_set_sensitive(app->trigger_panel, on);
|
||||
// are about to switch back on must not vanish while you look for them. The *body* is what goes
|
||||
// insensitive and not the panel, because the panel's heading row carries the switch that turns
|
||||
// this back on -- and a control inside an insensitive parent cannot be clicked.
|
||||
gtk_widget_set_sensitive(app->trigger_body, on);
|
||||
// The event-history button is part of trigger mode and the pane it opens is *on demand*; leaving
|
||||
// trigger mode takes the button away and collapses the pane, so going back to streaming is not a
|
||||
// column of stale events beside the plot. Recording is the other half of that answer, so this is
|
||||
// `sync_events_availability()`'s call and not the trigger's alone.
|
||||
sync_events_availability(*app);
|
||||
gtk_button_set_label(GTK_BUTTON(app->arm_button), on ? "Disarm" : "Arm");
|
||||
// The pane's own switch shows the same state, whichever of the two was clicked.
|
||||
sync_panel_switches(*app);
|
||||
}
|
||||
|
||||
/// The way out of trigger mode, from inside the panel that froze the view: it is
|
||||
@@ -236,6 +240,8 @@ GtkWidget* build_trigger_panel(App& app) {
|
||||
GtkBuilder* ui = ui_load(app, "/org/udpscope/ui/trigger-panel.ui");
|
||||
GtkWidget* box = GTK_WIDGET(gtk_builder_get_object(ui, "trigger_panel"));
|
||||
if (box == nullptr) return gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
|
||||
// The *body* is what trigger-off disables; this panel's index into it is `trigger_body`.
|
||||
app.trigger_body = box;
|
||||
|
||||
app.trigger_signal_drop = gtk_drop_down_new(G_LIST_MODEL(gtk_string_list_new(nullptr)), nullptr);
|
||||
g_signal_connect(app.trigger_signal_drop, "notify::selected",
|
||||
@@ -422,7 +428,29 @@ GtkWidget* build_trigger_panel(App& app) {
|
||||
&app);
|
||||
}
|
||||
sync_trigger_rows(app);
|
||||
return box;
|
||||
|
||||
// The heading row, and the switch that is the *same* control as the header bar's button. Built here
|
||||
// rather than in the file because it must not go insensitive with the body: turning trigger mode
|
||||
// back on would otherwise mean finding the toolbar button that greyed the panel out.
|
||||
GtkWidget* head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
gtk_widget_set_margin_top(head, 8);
|
||||
gtk_widget_set_margin_start(head, 8);
|
||||
gtk_widget_set_margin_end(head, 8);
|
||||
GtkWidget* title = gtk_label_new("Trigger");
|
||||
gtk_widget_set_halign(title, GTK_ALIGN_START);
|
||||
gtk_widget_set_hexpand(title, TRUE);
|
||||
gtk_box_append(GTK_BOX(head), title);
|
||||
app.trigger_switch = gtk_switch_new();
|
||||
gtk_widget_set_valign(app.trigger_switch, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_tooltip_text(app.trigger_switch,
|
||||
"trigger mode, the same switch the header bar carries");
|
||||
g_signal_connect(app.trigger_switch, "notify::active", G_CALLBACK(on_panel_switch_toggled), &app);
|
||||
gtk_box_append(GTK_BOX(head), app.trigger_switch);
|
||||
|
||||
GtkWidget* outer = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_append(GTK_BOX(outer), head);
|
||||
gtk_box_append(GTK_BOX(outer), box);
|
||||
return outer;
|
||||
}
|
||||
|
||||
} // namespace ui_impl
|
||||
|
||||
Reference in new issue
Block a user