feat: the main window's skeleton is a UI file

src/ui/main-window.ui holds the window, its two panes, the plot column with the status line under it,
and the sidebar's scroller. What stays in code is what depends on the stream: the events pane, the two
plot areas, the sidebar's panels and the status popover, each put into a slot by id.

The header bar is deliberately not in the file. It is the window's own titlebar, every button on it is
wired to an action, and an AdwApplicationWindow refuses a titlebar outright -- a fatal Adwaita-ERROR
rather than a warning that leaves the window merely ugly -- so the window is a GtkApplicationWindow and
the header bar stays where it was.

gtk_paned_set_position() is the other thing that had to stay in code, and the reason is order rather
than shape: it clamps against its children *now*, so stating it before the sidebar's panels exist moved
the plot column by ~180 px.

The layout, events and box-zoom probes read what they read before this change, and the header reads
window_button_w=130 bar_w=756 as it always has -- checked by building the previous commit and running
the same probe against it, because the layout numbers in the notes turned out to be stale from an
earlier session. Five UI files now.
This commit is contained in:
Martino Ferrari committed 2026-10-11 17:39:04 +02:00
1 parent 68743a7d7f
commit 8073e7b3fd
8 files changed
+196 -70

No files matched your search

+122
View File
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-License-Identifier: MIT -->
<!-- SPDX-FileCopyrightText: 2026 Martino Ferrari -->
<!--
The main window's skeleton: the window, the two panes that make its three columns, the plot column
with the status line under it, and the sidebar's scroller.
What is *not* here is as deliberate as what is. Everything this file nests is fixed — the shape of
the window does not depend on the stream, the trigger or the layout — while the four subtrees that
do are built by code and put in place:
- the events pane, into the inner paned's start side;
- the two plot areas, into the split inside `plot_box`;
- the sidebar's panels, appended to `side_column`;
- the status popover, attached to `status_info`.
A `GtkApplicationWindow` and not an `AdwApplicationWindow`, deliberately: the header bar is the
window's own titlebar and Adw's window refuses one outright (`gtk_window_set_titlebar() is not
supported for AdwApplicationWindow`, which is a fatal `Adwaita-ERROR`, not a warning). An Adw window
would want its header as an `AdwToolbarView`'s top bar instead, and this one is a `GtkHeaderBar`
packed by hand — a change for its own sake, and one that would take the window controls away from it
(a GtkHeaderBar draws those only as a titlebar).
The header bar is *not* in this file: it is the window's own titlebar,
built by `build_toolbar()` because every button on it is wired to an action. The status line is not a
bottom bar either — it belongs to the plot column, not to the window, so it stays inside `left_column`
where the paned divider can move past it.
The `GtkPaned`s are here rather than in code because their *rules* are the skeleton: the events pane
is shrinkable and does not resize (so a closed pane costs the plot nothing), and the sidebar is
neither. `gtk_paned_set_position()` is not, because it has to run after the children exist.
-->
<interface>
<object class="GtkApplicationWindow" id="main_window">
<property name="title">udpscope</property>
<property name="icon-name">org.udpscope.app</property>
<property name="default-width">1280</property>
<property name="default-height">800</property>
<child>
<object class="GtkPaned" id="paned">
<property name="orientation">horizontal</property>
<property name="resize-end-child">0</property>
<property name="shrink-end-child">0</property>
<child type="start">
<object class="GtkPaned" id="events_divider">
<property name="orientation">horizontal</property>
<!-- Shrinkable, or the pane's own minimum is reserved as an empty column even while it is
closed and the plot pays for a pane nobody opened. -->
<property name="shrink-start-child">1</property>
<property name="resize-start-child">0</property>
<child type="end">
<object class="GtkBox" id="left_column">
<property name="orientation">vertical</property>
<property name="hexpand">1</property>
<child>
<object class="GtkBox" id="plot_box">
<property name="orientation">vertical</property>
<property name="homogeneous">1</property>
<property name="spacing">4</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkPaned" id="plot_split">
<property name="orientation">horizontal</property>
<property name="shrink-end-child">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="status_row">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
<property name="margin-start">6</property>
<child>
<object class="GtkLabel" id="status_badge"/>
</child>
<child>
<!-- The line is rewritten every frame and its counters grow, so it is
ellipsized: a label's minimum width is its text, and an unellipsized one
would push the paned divider around as the numbers change. -->
<object class="GtkLabel" id="status_label">
<property name="label">starting…</property>
<property name="ellipsize">end</property>
<property name="hexpand">1</property>
<property name="halign">fill</property>
</object>
</child>
<child>
<object class="GtkMenuButton" id="status_info">
<property name="icon-name">help-about-symbolic</property>
<property name="tooltip-text" translatable="yes">Stream and buffer detail</property>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child type="end">
<!-- The column scrolls as a whole, so a long signal list or a revealed trigger panel can
never push either panel out of the window. -->
<object class="GtkScrolledWindow" id="side_scroll">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<property name="width-request">320</property>
<child>
<object class="GtkBox" id="side_column">
<property name="orientation">vertical</property>
<property name="width-request">300</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>