fix: the math editor's body was a child of the window, not of the box above it
Moving the editor's frame into math-editor.ui left `math_body` and `math_actions` as <child> elements of the *window* rather than of `math_outer`, because those edits were anchored on the file's tail and closed the outer box two elements early. A GtkWindow takes exactly one default <child>, so nothing failed loudly: the body -- with the canvas and the parameter form inside it -- was left parentless, visible but never mapped, 0x0, drawing nothing. Two symptoms, one cause: the canvas is blank, and the window is sized around the head row and the buttons alone. Measured against the pre-move revision in a worktree, same probe, same environment: before this fix `canvas=0x0 mapped=0 window=756x940`; after it `canvas=420x836 mapped=1 window=938x940`, which is the old revision's own reading exactly. It survived because that slice's probe read the editor's *values* (nodes, gain, output, name, unit) and nothing about its structure. Every other panel moved that day has a structural reading -- `controls_inside=13/13`, `nested=1`, `labels=2 list=1` -- and none of them was affected. `[math-probe] editor frame:` is that reading now: the canvas's allocation, its mapped state, and whether the canvas and the name entry are inside the dialog at all, delayed 500 ms because an allocation only exists after a layout. In the broken build it read `0x0 mapped=0 in_dialog=0`. check_ui passes both files: the XML was valid and every property type-checked.
This commit is contained in:
1 parent
0e891ada04
commit
c3d588f03d
4 files changed
+48
-3
No files matched your search
@@ -335,3 +335,14 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear
|
||||
reads the *reverse* of the file: `header-bar.ui` declares menu, sidebar, math, measures, cursors and the
|
||||
screen shows cursors, measures, math, sidebar, menu. The three comments this replaced each had it wrong
|
||||
once, which is why the order is the file's now and a byte-for-byte diff of the probe is the check.
|
||||
|
||||
- **A widget can end up in the wrong container, and only a *structural* read notices.** `math_body` was
|
||||
written as a `<child>` of the *window* instead of the box above it when the math editor's frame moved into a
|
||||
`.ui`. A `GtkWindow` takes exactly one default `<child>`, so nothing failed: the body -- with the canvas and
|
||||
the parameter form inside it -- was left parentless, `visible` but never `mapped`, size `0x0`, drawing
|
||||
nothing. The symptom was "the editor opens and the canvas is blank", with the window sized around its
|
||||
remaining children. `check_ui` passes such a file; `xml-stripblanks` passes it; so does every probe that
|
||||
reads *values* off the widgets inside. What catches it is a reading that walks *up* from the widget
|
||||
(`in_dialog=1`) or asks whether it was ever given an allocation (`mapped=1`, `canvas=420x836`). When a frame
|
||||
moves into a file, the probe that proves it has to read the frame's *structure*, not only the numbers it
|
||||
holds.
|
||||
@@ -41,7 +41,12 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear
|
||||
anywhere in 78--101 ns/slot is one reading of the same thing.
|
||||
The probe also asserts the new editor mechanics. `dialog build:` reads the identity row back as well --
|
||||
`name='math3' unit=''` -- which is the pair the `.ui` holds the widgets for and the code fills from the
|
||||
channel being edited, so a row that stopped being the one the code writes shows there. Each line carries
|
||||
channel being edited, so a row that stopped being the one the code writes shows there.
|
||||
`editor frame:` is the same idea one level down: it reads the canvas's allocation, whether that canvas is
|
||||
*mapped*, and whether the canvas and the name entry are inside the dialog at all -- delayed by 500 ms, because
|
||||
an allocation only exists after a layout. A canvas that is visible but parentless never maps and stays `0x0`,
|
||||
and reading values off the widgets *inside* the editor cannot see that. It is the reading that catches
|
||||
`math_body` written as a child of the window instead of the box above it. Each line carries
|
||||
`(want ...)` and the reading
|
||||
taken from a real run is the reference:
|
||||
* `[math-probe] hit: inside node=0 which=-1, past-edge node=0 which=-1 (want 0 -1 0 -1)` — the
|
||||
|
||||
@@ -46,8 +46,6 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="math_body">
|
||||
<property name="orientation">horizontal</property>
|
||||
@@ -80,5 +78,7 @@
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -386,6 +386,35 @@ gboolean math_probe(gpointer user) {
|
||||
if (ed->gain != nullptr) gtk_spin_button_set_value(GTK_SPIN_BUTTON(ed->gain), 2.0);
|
||||
if (ed->offset != nullptr) gtk_spin_button_set_value(GTK_SPIN_BUTTON(ed->offset), 0.0);
|
||||
on_math_param_changed(nullptr, ed);
|
||||
// The frame, structurally: the canvas being *in* the dialog and given an allocation. A `.ui`
|
||||
// mistake this has already paid for once -- `math_body` nested under the window instead of the
|
||||
// outer box -- leaves the canvas visible but parentless: it never maps, stays 0x0 and draws
|
||||
// nothing, which a user reads as "the editor opens and the canvas is blank". The values below
|
||||
// cannot see that, and the reading is delayed because an allocation only exists after a layout.
|
||||
g_timeout_add(500, +[](gpointer u) -> gboolean {
|
||||
App* app = static_cast<App*>(u);
|
||||
if (app->math_dialog == nullptr) {
|
||||
std::fprintf(stderr, "[math-probe] editor frame: (dialog closed before the reading)\n");
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
MathDialog* m = static_cast<MathDialog*>(
|
||||
g_object_get_data(G_OBJECT(app->math_dialog), "udpscope-math-dialog"));
|
||||
if (m == nullptr) return G_SOURCE_REMOVE;
|
||||
const auto in_dialog = [app](GtkWidget* w) {
|
||||
for (GtkWidget* p = w; p != nullptr; p = gtk_widget_get_parent(p)) {
|
||||
if (p == app->math_dialog) return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
std::fprintf(stderr,
|
||||
"[math-probe] editor frame: canvas=%dx%d mapped=%d in_dialog=%d "
|
||||
"name_in_dialog=%d\n",
|
||||
m->canvas != nullptr ? gtk_widget_get_width(m->canvas) : -1,
|
||||
m->canvas != nullptr ? gtk_widget_get_height(m->canvas) : -1,
|
||||
m->canvas != nullptr ? gtk_widget_get_mapped(m->canvas) : -1,
|
||||
in_dialog(m->canvas), in_dialog(m->name));
|
||||
return G_SOURCE_REMOVE;
|
||||
}, a);
|
||||
const std::size_t built = ed->nodes.size();
|
||||
const double gain_read = ed->nodes.empty() ? 0.0 : ed->nodes.back().gain;
|
||||
const double offset_read = ed->nodes.empty() ? 0.0 : ed->nodes.back().offset;
|
||||
|
||||
Reference in new issue
Block a user