help: the search block's (i) on its header, a 12 px mark, and a real search page

This commit is contained in:
Martino Ferrari committed 2026-10-14 23:29:00 +02:00
1 parent d549223889
commit fe499bfe41
10 files changed
+178 -53

No files matched your search

+16 -1
View File
@@ -214,8 +214,23 @@
</child>
<child>
<object class="GtkExpander" id="search_exp">
<property name="label" translatable="yes">Search the buffer</property>
<property name="tooltip-text" translatable="yes">find every place in the retained buffer where the condition above holds, and step through them</property>
<!-- The header is a box, not a plain label, so the contextual help's "(i)" has a row to join
as its last child and sits beside the text while the block is collapsed. The block's own
*child* is not in the widget-parent chain until the expander is expanded (see
docs/claude/invariants-gtk-and-chrome.md), so a hint hung there would be off screen. -->
<child type="label">
<object class="GtkBox" id="search_head">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Search the buffer</property>
<property name="halign">start</property>
</object>
</child>
</object>
</child>
<property name="child">
<object class="GtkBox" id="search_sbox">
+8 -1
View File
@@ -246,6 +246,9 @@ struct App {
GtkWidget* search_marks_label = nullptr;
GtkWidget* search_prev_button = nullptr;
GtkWidget* search_next_button = nullptr;
/// The expander the block lives in, so the probe can read its collapsed state when it reads the
/// header hint.
GtkWidget* search_exp = nullptr;
/// Set true when the last `search_jump()` produced an empty cut — the hit was so close to the
/// oldest retained sample that `publish_pause_view()` held nothing. Cleared at every jump.
bool search_jump_empty = false;
@@ -284,10 +287,14 @@ struct App {
GtkWidget* status_row = nullptr;
GtkWidget* window_control_slot = nullptr;
/// The hint hosts that are *not* a pane's heading row: a specific control's own row, so the "?" sits
/// beside the thing it explains -- the "record events" switch, the search block's action row, and the
/// beside the thing it explains -- the "record events" switch, the pre-trigger share row, and the
/// signals pane's hint line (whose box exists so a hint can join it beside the text).
GtkWidget* trigger_record_row = nullptr;
GtkWidget* trigger_pre_row = nullptr;
/// The search block's expander *header* -- the box the contextual help's "trigger_search" hint joins
/// as its last child. The header, not the block: the expander's child is out of the widget-parent
/// chain until the block is expanded, so a hint there is invisible while it is collapsed.
GtkWidget* trigger_search = nullptr;
GtkWidget* signals_note = nullptr;
/// The guided tour. `tour.overlay` is a `GtkOverlay` inserted above the window's content, and the
/// four dim rectangles, the spotlight and the card are its overlay children; `tour.plan` is the
+6
View File
@@ -109,6 +109,12 @@ constexpr HelpHint kHelpHints[] = {
"is the quiet time after a latch in which nothing new can be armed -- the two that decide what a "
"capture looks like. The condition rows above appear and disappear with the condition chosen.",
"", &App::trigger_pre_row},
{"trigger_search", "Searching the buffer",
"Applies the condition above to the whole retained ring -- the *same* evaluator the trigger runs, "
"so a hit is an instant the trigger would have fired on -- and lists every place it holds. The "
"arrows step through the hits, pausing centred on each, and up to sixteen in view are marked on "
"every row.",
"", &App::trigger_search},
{"signals_config", "Configuring signals",
"The list is locked until the pencil above opens the per-signal controls: the calibration that "
"maps raw counts to a unit, the colour a trace is drawn in, and which plot a signal is dragged "
+18
View File
@@ -4773,6 +4773,24 @@ gboolean helpui_probe_step(gpointer user) {
helpui_probe_next(*a, 8, 400);
return G_SOURCE_REMOVE;
}
// The search block's "(i)" rides the expander's *header* box, which is in the widget tree and on
// screen while the block is collapsed -- unlike the expander's child, which is out of the
// widget-parent chain until it is expanded (see the invariant). Read here, in config mode with the
// pane and the sidebar up and the block still collapsed: `mapped=1` and a real size *on a collapsed
// expander* is the whole point, and a hint hung on the child would read 0x0 here.
if (a->trigger_search != nullptr) {
GtkWidget* hint = gtk_widget_get_last_child(a->trigger_search);
int sw = 0;
int sh = 0;
context_help_size_in(hint, &sw, &sh);
std::fprintf(stderr,
"[helpui] collapsed search: expanded=%d mapped=%d mapped_header=%d hint=%dx%d\n",
a->search_exp != nullptr && gtk_expander_get_expanded(GTK_EXPANDER(a->search_exp))
? 1
: 0,
hint != nullptr && gtk_widget_get_mapped(hint) ? 1 : 0,
gtk_widget_get_mapped(a->trigger_search) ? 1 : 0, sw, sh);
}
std::fflush(stderr);
return G_SOURCE_REMOVE;
}
+5
View File
@@ -599,6 +599,11 @@ GtkWidget* build_trigger_panel(App& app) {
app.search_pos_label = GTK_WIDGET(gtk_builder_get_object(ui, "search_pos"));
app.search_next_button = GTK_WIDGET(gtk_builder_get_object(ui, "search_next"));
app.search_marks_label = GTK_WIDGET(gtk_builder_get_object(ui, "search_marks"));
app.search_exp = GTK_WIDGET(gtk_builder_get_object(ui, "search_exp"));
// The expander's header box, where the contextual help's "trigger_search" hint joins as its last
// child (see `ui_context_help.cpp`): a hint on the block's own child would leave it unreachable
// while the block is collapsed.
app.trigger_search = GTK_WIDGET(gtk_builder_get_object(ui, "search_head"));
if (app.search_run_button != nullptr) {
g_signal_connect(app.search_run_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer user) {
App* a = static_cast<App*>(user);
+16 -8
View File
@@ -71,16 +71,24 @@ void install_css() {
" border-radius: 12px; padding: 12px; box-shadow: 0 3px 12px rgba(0, 0, 0, 0.45); }\n"
// The contextual-help "(i)": a *mark*, not a button. Adwaita's menu button is a 34x34 control
// (a 24 px floor plus 5 px of padding) with a 16 px glyph, which beside a heading reads as a
// second toolbar button -- the size the ask calls too big. Measured on libadwaita 1.10: the
// outer `menubutton` node *and* its `button` subnode both carry a floor and padding, and a class
// selector on either alone leaves the other at 34 (`min-width` on the widget itself is ignored
// by `GtkMenuButton`'s measure, and so is a size request -- tried both). Zeroing all three --
// the outer node, the subnode and its glyph -- is what brings it to **16x16**: the icon's own
// size and nothing else, because a `min-width` is a floor, not a cap, so 16 px is where a 16 px
// Adwaita glyph stops. That is the reading `hint=WxH` in the dump prints.
// second toolbar button. Measured on libadwaita 1.10: the outer `menubutton` node *and* its
// `button` subnode both carry a floor and padding, and a class selector on either alone leaves
// the other at 34 (`min-width` on the widget itself is ignored by `GtkMenuButton`'s measure, and
// so is a size request -- tried both). Beyond those two there is a third node, and getting its
// path wrong is silent: the button's own tree is `menubutton > button > box > image` (read off
// the CSS node dump), so the direct-grandchild form `> button > image` matches *nothing* and
// leaves the glyph at its natural 16 px -- which is the 16x16 the first version shipped and
// mistook for a floor. The glyph is reached through the `box`; trimming the outer node, the
// `button` subnode and the glyph together, and asking the glyph for 12 px with
// `-gtk-icon-size` (which `GtkImage` honours when it is `GTK_ICON_SIZE_INHERIT`, and which
// *scales* the drawing rather than merely clamping its box), is what brings the mark to
// **12x12**. There is no lower floor to find: the symbolic glyph renders at any request
// (measured down to 4 px), so 12 px is a legibility choice, and it is the size the rule always
// meant -- the first version already wrote 12 px, on a selector that never matched. That is
// the reading `hint=WxH` in the dump prints.
"menubutton.udpscope-hint { min-width: 0; min-height: 0; padding: 0; margin: 0; }\n"
"menubutton.udpscope-hint > button { min-width: 0; min-height: 0; padding: 0; }\n"
"menubutton.udpscope-hint > button > image { min-width: 12px; min-height: 12px;"
"menubutton.udpscope-hint > button > box > image { min-width: 12px; min-height: 12px;"
" -gtk-icon-size: 12px; }\n";
GtkCssProvider* p = gtk_css_provider_new();
gtk_css_provider_load_from_string(p, kCss);