ui: the sidebar is two tabs, and a toggle disables its pane

Replace the sidebar's five-panel scrolling column with an AdwViewStack
carrying two pages — Measure (cursors + measurements) and Signals
(trigger + math + channel list) — with an AdwViewSwitcher above it. The
trigger and cursors toggles change from "reveal/hide my pane" to
"enable/disable my feature, leaving the pane insensitive", following the
disable-not-hide principle. The keys probe loses a duplicate registration
that was toggling the sidebar back on before the exit probe captured its
state; the exit-probe captures now read adw_overlay_split_view_get_show_
sidebar() instead of gtk_widget_get_visible(), which AdwOverlaySplitView
never changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Sonnet 4.6 committed 2026-10-14 11:11:21 +02:00
1 parent e10a92fc52
commit 44d2fd35dc
11 files changed
+227 -232

No files matched your search

+19 -21
View File
@@ -139,18 +139,21 @@ struct App {
/// what we synced is ours -- GTK only notifies on a change, so the user cannot produce it.
int window_sync_unit = -1;
GtkWidget* trigger_toggle = nullptr;
GtkWidget* trigger_revealer = nullptr;
/// The trigger panel's own box, kept so the defaults probe can read its spin buttons without
/// walking the window for them.
GtkWidget* trigger_panel = nullptr;
GtkWidget* signal_toggle = nullptr;
GtkWidget* signal_revealer = nullptr;
GtkWidget* signal_panel = nullptr;
GtkWidget* side_box = nullptr;
/// The sidebar's tab stack and its switcher. The stack is what chooses which panels are on
/// screen; a feature's own on/off never does (it sets its panel's sensitivity instead).
GtkWidget* side_stack = nullptr;
GtkWidget* side_switcher = nullptr;
/// The page name the stack is showing, and the one value the session file persists about the
/// sidebar. "signals" on a first run.
std::string side_tab = "signals";
GtkWidget* arm_button = nullptr;
GtkWidget* trigger_signal_drop = nullptr;
GtkWidget* sidebar_toggle = nullptr;
GtkWidget* side_scroll = nullptr;
GtkWidget* trigger_edge_drop = nullptr;
GtkWidget* trigger_type_drop = nullptr;
GtkWidget* trigger_cmp_drop = nullptr;
@@ -211,10 +214,10 @@ struct App {
/// *titlebar*, not a child of the window, so walking down from the window does not reach it.
GtkWidget* toolbar = nullptr;
GtkWidget* cursors_reset = nullptr;
/// The cursors pane: revealed with the toggle, and listing what the instruments
/// read -- T0/T1/dT always, per row an Y1/Y2/dY where rulers are up, and in `mix` mode
/// the value each cursor crosses each trace at.
GtkWidget* cursors_revealer = nullptr;
/// The cursors panel's root, kept because cursors-off disables it rather than hiding it.
GtkWidget* cursors_panel = nullptr;
/// The cursors pane: listing what the instruments read -- T0/T1/dT always, per row an Y1/Y2/dY
/// where rulers are up, and in `mix` mode the value each cursor crosses each trace at.
GtkWidget* cursors_mode_drop = nullptr;
GtkWidget* cursors_body = nullptr;
/// One line per row (rulers) and one per bound trace (`mix`), in the order the body
@@ -237,16 +240,12 @@ struct App {
/// price the frame tick should pay).
std::vector<Measure> measures;
std::vector<MeasureResult> measure_results;
GtkWidget* measures_revealer = nullptr;
GtkWidget* measures_list = nullptr;
GtkWidget* measures_toggle = nullptr;
// --- math channels --------------------------------------------------------
/// The app's copy of the math channels, and the source of truth for the pane. Every change goes
/// through `apply_math_channels()`, which writes this and hands it to the model -- the model's own
/// copy is what the producer evaluates.
std::vector<MathChannel> math;
GtkWidget* math_toggle = nullptr;
GtkWidget* math_revealer = nullptr;
GtkWidget* math_list = nullptr;
/// The math editor's builder. The editor's window belongs to the builder's object list, so the builder is
/// held for as long as the window is up and cleared on the *next* opening rather than with the window --
@@ -358,7 +357,6 @@ struct App {
/// that memory reused and the read is a **SIGSEGV** in the middle of the dump.
int dbg_measures_pane_w = -1;
int dbg_measures_pane_h = -1;
bool measures_revealed = false;
/// The measurement dialog while one is open (null otherwise). A probe needs a handle on it:
/// it is a window of its own, so the main window's widget tree does not reach its buttons.
GtkWidget* measure_dialog = nullptr;
@@ -508,7 +506,6 @@ struct App {
/// True once the renderer's `Style` has been stated (see `tick()`): the renderer does not
/// exist until the area is realized, so the one-shot has to be a tick's job.
bool style_stated = false;
bool signals_panel_initialised = false;
/// Set once the user edits the trigger level, so the panel stops defaulting it
/// into the middle of the declared range.
bool trigger_level_touched = false;
@@ -690,7 +687,7 @@ struct App {
/// over a run that acquired anything -- that is what "it blinks" means, and a badge
/// stuck lit looks identical to a working one in a screenshot.
int dbg_badge_frames[4] = {0, 0, 0, 0};
int dbg_reset_visible = -1;
int dbg_reset_sensitive = -1;
std::vector<std::uint64_t> last_stored;
std::uint64_t dbg_latches_at_disarm = 0;
std::uint64_t dbg_seq_at_disarm = 0;
@@ -738,12 +735,12 @@ struct App {
int dbg_signal_row_h = 0;
int dbg_trigger_w = 0;
int dbg_trigger_h = 0;
int dbg_signal_revealed = 0;
int dbg_trigger_revealed = 0;
int dbg_signal_page_current = 0;
int dbg_trigger_sensitive = 0;
int dbg_side_visible = 0;
int dbg_trigger_items = 0;
int dbg_trigger_selected = -1;
int dbg_side_scroll_after_hide = 1;
int dbg_side_column_after_hide = 1;
std::string dbg_mode_triggered;
std::string dbg_window_text;
double dbg_marker_x = 0.0;
@@ -751,8 +748,8 @@ struct App {
double dbg_trigger_time = 0.0;
int dbg_trigger_time_valid = -1;
std::string dbg_mode_live;
int dbg_toggles_visible = 0;
int dbg_trigger_revealed_default = 0;
int dbg_switcher_visible = 0;
int dbg_trigger_sensitive_default = 0;
/// The detail string the popover and the exit dump read. The dump used to read the label,
/// which no longer carries these fields.
@@ -1336,7 +1333,6 @@ void rebuild_math_pane(App& app);
GtkWidget* build_measures_panel(App& app);
GtkWidget* build_cursors_panel(App& app);
void on_cursors_toggled(GtkToggleButton* button, gpointer user);
void on_signals_toggled(GtkToggleButton* button, gpointer user);
void on_fit_clicked(GtkButton*, gpointer user);
void on_fit_x_clicked(GtkButton*, gpointer user);
void on_cursors_reset(GtkButton*, gpointer user);
@@ -1359,6 +1355,8 @@ void row_menu_fill(RowMenuState& st);
GtkWidget* open_row_menu(App& app, int row, double x, double y, GtkWidget* parent, bool autohide = true);
void on_right_click(GtkGestureClick* gesture, int, double x, double y, gpointer user);
gboolean on_drop_channel(GtkDropTarget*, const GValue* value, double x, double y, gpointer user);
void on_side_tab_changed(GObject*, GParamSpec*, gpointer user);
void select_side_tab(App& app, const char* name);
void update_side_visibility(App& app);
void on_sidebar_toggled(GtkToggleButton* button, gpointer user);
void rebuild_signal_panels(App& app);