ui: the signals panel's frame is a .ui file

src/ui/signals-panel.ui holds the panel's shape: the box and its margins, the heading,
the hint that says what a signal is for, and the list. The rows stay in code -- one per
signal, carrying that signal's switch, colour, calibration and drop targets, rebuilt
whenever the stream's signals change -- so the file holds the frame, which is the shape
the plan gives this slice.

The list's width-only size request moved with it, comment and all: a height floor there
made the list occupy 120 px whatever it held, which hid the compact rows' height behind
it.

Read back by a new dump line, `signals panel: labels=2 list=1`, where a lost id reads as
`labels=1` or `list=0` instead of a panel quietly missing its hint; `panels: … row_h=26`
still reads the list's geometry and the height a row takes. check_ui is at 10 ok.
This commit is contained in:
Martino Ferrari committed 2026-10-12 15:50:52 +02:00
1 parent 1ccc70c5ac
commit c37fbdde21
6 files changed
+88 -22

No files matched your search

+14
View File
@@ -5409,6 +5409,20 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
static_cast<unsigned long long>(model.trigger_latches().load()),
static_cast<unsigned long long>(app.dbg_latches_at_disarm));
std::printf("[udpscope] window control: '%s'\n", app.dbg_window_text.c_str());
{
// The signals panel's frame, read from the window rather than from the `.ui`: the two labels and the
// list the file gives it. A `.ui` that lost one of them reads here -- `labels=1` or `list=0` -- rather
// than showing as a panel quietly missing its hint.
GtkWidget* panel = app.signal_list != nullptr ? gtk_widget_get_parent(app.signal_list) : nullptr;
int labels = 0;
int lists = 0;
for (GtkWidget* c = panel != nullptr ? gtk_widget_get_first_child(panel) : nullptr; c != nullptr;
c = gtk_widget_get_next_sibling(c)) {
if (GTK_IS_LABEL(c)) ++labels;
if (GTK_IS_LIST_BOX(c)) ++lists;
}
std::printf("[udpscope] signals panel: labels=%d list=%d\n", labels, lists);
}
std::printf("[udpscope] panels: side=%dx%d (visible=%d) signals=%dx%d row_h=%d "
"(revealed=%d) trigger=%dx%d (revealed=%d) toggles=%d cursors=%d window=%.3fs "
"window_cap=%.1fs\n",
+43
View File
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-License-Identifier: MIT -->
<!-- SPDX-FileCopyrightText: 2026 Martino Ferrari -->
<!--
The signals panel: a heading, the hint that says what a signal is for, and the list they go in.
The rows are not here. There is one per signal in the stream, it carries the switch that decides whether
that signal is acquired, its colour, its calibration and its drop targets, and the whole list is rebuilt
whenever the stream's signals change — so the file holds the frame and the code holds the rows.
The list's size request is **width only**, deliberately. A height floor here made the list occupy 120 px
whatever it held, which hid the compact rows' height behind it and wasted the space on an empty stream;
the scroller this panel sits in already caps how tall it can grow.
-->
<interface>
<object class="GtkBox" id="signal_panel">
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<property name="margin-top">8</property>
<property name="margin-bottom">8</property>
<property name="margin-start">8</property>
<property name="margin-end">8</property>
<child>
<object class="GtkLabel" id="signals_heading">
<property name="label" translatable="yes">Signals</property>
<property name="halign">start</property>
</object>
</child>
<child>
<object class="GtkLabel" id="signals_hint">
<property name="label" translatable="yes">drag a signal onto a plot</property>
<property name="halign">start</property>
<property name="css-classes">dim-label</property>
</object>
</child>
<child>
<object class="GtkListBox" id="signal_list">
<property name="selection-mode">none</property>
<property name="width-request">260</property>
</object>
</child>
</object>
</interface>
+1
View File
@@ -18,5 +18,6 @@
<file preprocess="xml-stripblanks">cursors-panel.ui</file>
<file preprocess="xml-stripblanks">measures-panel.ui</file>
<file preprocess="xml-stripblanks">trigger-panel.ui</file>
<file preprocess="xml-stripblanks">signals-panel.ui</file>
</gresource>
</gresources>
+12 -22
View File
@@ -382,28 +382,18 @@ void rebuild_signal_panels(App& app) {
}
GtkWidget* build_signal_panel(App& app) {
GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
gtk_widget_set_margin_top(box, 8);
gtk_widget_set_margin_bottom(box, 8);
gtk_widget_set_margin_start(box, 8);
gtk_widget_set_margin_end(box, 8);
GtkWidget* heading = gtk_label_new("Signals");
gtk_widget_set_halign(heading, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(box), heading);
GtkWidget* hint = gtk_label_new("drag a signal onto a plot");
gtk_widget_set_halign(hint, GTK_ALIGN_START);
gtk_widget_add_css_class(hint, "dim-label");
gtk_box_append(GTK_BOX(box), hint);
app.signal_list = gtk_list_box_new();
gtk_list_box_set_selection_mode(GTK_LIST_BOX(app.signal_list), GTK_SELECTION_NONE);
// Width only. A height floor here made the list occupy 120 px whatever it held,
// which hid the compact rows' height behind it and wasted the space on an empty
// stream; the scroller above it already caps how tall it can grow.
gtk_widget_set_size_request(app.signal_list, 260, -1);
gtk_box_append(GTK_BOX(box), app.signal_list);
// The panel's frame -- the heading, the hint under it, and the list -- is a UI file. The rows are not:
// there is one per signal, carrying that signal's switch, colour, calibration and drop targets, and the
// whole list is rebuilt whenever the stream's signals change. `make test-ui` checks the file's types
// against the GIR; the id below is what keeps the code and the file agreeing on the name.
GtkBuilder* ui = ui_load(app, "/org/udpscope/ui/signals-panel.ui");
GtkWidget* box = GTK_WIDGET(gtk_builder_get_object(ui, "signal_panel"));
app.signal_list = GTK_WIDGET(gtk_builder_get_object(ui, "signal_list"));
if (box == nullptr || app.signal_list == nullptr) {
// A missing id is a mistake in the `.ui`: the panel comes up empty rather than taking the window with
// it, and `[udpscope] signals panel:` reads the difference.
return box != nullptr ? box : gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
}
return box;
}