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:
1 parent
1ccc70c5ac
commit
c37fbdde21
6 files changed
+88
-22
No files matched your search
@@ -309,3 +309,10 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear
|
|||||||
Related: `gtk_expander_set_child()` asserts that its child has no parent yet, so a block the `.ui` has
|
Related: `gtk_expander_set_child()` asserts that its child has no parent yet, so a block the `.ui` has
|
||||||
already put in the panel cannot then be handed to an expander -- the file's `child` property is the right
|
already put in the panel cannot then be handed to an expander -- the file's `child` property is the right
|
||||||
way, and it works.
|
way, and it works.
|
||||||
|
|
||||||
|
- **`--` is not allowed inside an XML comment, and a `.ui` comment is XML.** `<!-- ... -- ... -->` is a parse
|
||||||
|
error: `xml-stripblanks` fails the build, and `make test-ui` prints `FAIL <file>` with **no** message under
|
||||||
|
it, because blueprint-compiler's decompiler aborts on the malformed XML before it can report anything --
|
||||||
|
the bare `FAIL` line is that mistake and nothing else. The house style for a dash in prose is the em dash,
|
||||||
|
which is why no other `.ui` in `src/ui/` contains a double hyphen. It has cost two slices a debugging
|
||||||
|
round for one character.
|
||||||
@@ -1179,3 +1179,14 @@ The search walk starts at `gtk_expander_get_child()`, not at the panel: an expan
|
|||||||
widget-parent chain at all, so walking up from a search button reaches no ancestor of the panel (see
|
widget-parent chain at all, so walking up from a search button reaches no ancestor of the panel (see
|
||||||
`invariants-gtk-and-chrome.md`). `[defaults] trigger:` prints the same panel's seven spins in tree order, so
|
`invariants-gtk-and-chrome.md`). `[defaults] trigger:` prints the same panel's seven spins in tree order, so
|
||||||
the two lines together read what the file gave and what the code put in it.
|
the two lines together read what the file gave and what the code put in it.
|
||||||
|
|
||||||
|
## `signals panel:`
|
||||||
|
|
||||||
|
```
|
||||||
|
[udpscope] signals panel: labels=2 list=1
|
||||||
|
```
|
||||||
|
|
||||||
|
The signals panel's frame read from the window: the heading and the hint the `.ui` gives it, and the list
|
||||||
|
the rows go in. `labels=1` is a `.ui` that lost one of the two, `list=0` one that lost the list -- both of
|
||||||
|
which otherwise show as a panel quietly missing a piece. `panels: … signals=WxH row_h=26` is the other half:
|
||||||
|
the list's own geometry and the height a row really takes, which is what the compact-row CSS rule is for.
|
||||||
+14
@@ -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>(model.trigger_latches().load()),
|
||||||
static_cast<unsigned long long>(app.dbg_latches_at_disarm));
|
static_cast<unsigned long long>(app.dbg_latches_at_disarm));
|
||||||
std::printf("[udpscope] window control: '%s'\n", app.dbg_window_text.c_str());
|
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 "
|
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 "
|
"(revealed=%d) trigger=%dx%d (revealed=%d) toggles=%d cursors=%d window=%.3fs "
|
||||||
"window_cap=%.1fs\n",
|
"window_cap=%.1fs\n",
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -18,5 +18,6 @@
|
|||||||
<file preprocess="xml-stripblanks">cursors-panel.ui</file>
|
<file preprocess="xml-stripblanks">cursors-panel.ui</file>
|
||||||
<file preprocess="xml-stripblanks">measures-panel.ui</file>
|
<file preprocess="xml-stripblanks">measures-panel.ui</file>
|
||||||
<file preprocess="xml-stripblanks">trigger-panel.ui</file>
|
<file preprocess="xml-stripblanks">trigger-panel.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">signals-panel.ui</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
</gresources>
|
</gresources>
|
||||||
+12
-22
@@ -382,28 +382,18 @@ void rebuild_signal_panels(App& app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget* build_signal_panel(App& app) {
|
GtkWidget* build_signal_panel(App& app) {
|
||||||
GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
|
// The panel's frame -- the heading, the hint under it, and the list -- is a UI file. The rows are not:
|
||||||
gtk_widget_set_margin_top(box, 8);
|
// there is one per signal, carrying that signal's switch, colour, calibration and drop targets, and the
|
||||||
gtk_widget_set_margin_bottom(box, 8);
|
// whole list is rebuilt whenever the stream's signals change. `make test-ui` checks the file's types
|
||||||
gtk_widget_set_margin_start(box, 8);
|
// against the GIR; the id below is what keeps the code and the file agreeing on the name.
|
||||||
gtk_widget_set_margin_end(box, 8);
|
GtkBuilder* ui = ui_load(app, "/org/udpscope/ui/signals-panel.ui");
|
||||||
|
GtkWidget* box = GTK_WIDGET(gtk_builder_get_object(ui, "signal_panel"));
|
||||||
GtkWidget* heading = gtk_label_new("Signals");
|
app.signal_list = GTK_WIDGET(gtk_builder_get_object(ui, "signal_list"));
|
||||||
gtk_widget_set_halign(heading, GTK_ALIGN_START);
|
if (box == nullptr || app.signal_list == nullptr) {
|
||||||
gtk_box_append(GTK_BOX(box), heading);
|
// 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.
|
||||||
GtkWidget* hint = gtk_label_new("drag a signal onto a plot");
|
return box != nullptr ? box : gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
|
||||||
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);
|
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user