Feature/source plugins #1

Merged
martino merged 130 commits from feature/source-plugins into main 2026-11-04 07:35:21 +01:00
7 changed files with 282 additions and 22 deletions
Showing only changes of commit c8d9d04f59 - Show all commits

No files matched your search

+9 -2
View File
@@ -4013,6 +4013,11 @@ gboolean tick(gpointer user) {
app->sidebar_syncing = false;
}
}
// The readouts strip is on screen exactly when the dock is not. Decided here, right after the wish was
// re-asserted and *before* the collapsing below (which makes the split view write `show-sidebar`
// false itself until the next frame re-asserts it): read after it, the strip would show for one frame
// each time the window narrowed.
sync_readouts_strip(*app);
const int window_w = gtk_widget_get_width(app->window);
if (window_w > 0) {
adw_overlay_split_view_set_collapsed(ADW_OVERLAY_SPLIT_VIEW(app->side_view),
@@ -4976,6 +4981,8 @@ void on_activate(GtkApplication* application, gpointer user) {
app->badge_bar = GTK_WIDGET(gtk_builder_get_object(app->window_ui, "badge_bar"));
app->badge_signals = GTK_WIDGET(gtk_builder_get_object(app->window_ui, "badge_signals"));
app->badge_system = GTK_WIDGET(gtk_builder_get_object(app->window_ui, "badge_system"));
app->readouts_strip = GTK_WIDGET(gtk_builder_get_object(app->window_ui, "readouts_strip"));
app->strip_box = GTK_WIDGET(gtk_builder_get_object(app->window_ui, "readouts_strip_box"));
// A missing id is the one mistake neither the build nor `GtkBuilder` sees, and every use below would
// be a null pointer.
if (app->window == nullptr || side_view == nullptr ||
@@ -4983,7 +4990,7 @@ void on_activate(GtkApplication* application, gpointer user) {
app->status_badge == nullptr ||
app->status_label == nullptr || app->status_info_button == nullptr ||
app->status_row == nullptr || app->badge_bar == nullptr || app->badge_signals == nullptr ||
app->badge_system == nullptr ||
app->badge_system == nullptr || app->readouts_strip == nullptr || app->strip_box == nullptr ||
side == nullptr || app->dock_scroller == nullptr || app->dock_page == nullptr) {
return;
}
@@ -5165,7 +5172,7 @@ void on_activate(GtkApplication* application, gpointer user) {
// switch that turns it back on. The trigger's body is deliberately *not* disabled: a trigger is
// configured before it is switched on, so its settings have to stay editable while it is off.
gtk_widget_set_sensitive(app->cursors_body, FALSE);
gtk_widget_set_sensitive(app->dock_cursor_grid, FALSE);
dock_set_cursors_sensitive(*app, false); // the dock's grid and the strip's chips, together
// The arm controls are the one part of the trigger pane that needs trigger mode running: both of them,
// and the compact line's visibility, are stated from the toggle by `sync_arm_buttons()`.
sync_arm_buttons(*app);
+25 -1
View File
@@ -4,7 +4,8 @@
<!--
The main window's skeleton: the window, the split view that puts the sidebar beside the plot, the
plot column (`left_column`: `plot_overlay` > `plot_box`, the slide-over panel being an overlay child added
in code) with the badge bar and the status line under it, and the sidebar, which is the dock.
in code) with the readouts strip (only while the dock is not on screen), the badge bar and the status
line under it, and the sidebar, which is the dock.
The sidebar is an `AdwOverlaySplitView`, which is what a utility sidebar is in GNOME (as against
`AdwNavigationSplitView`, which is for navigation lists). Three things follow from that, and they are
@@ -96,6 +97,29 @@
</child>
</object>
</child>
<child>
<!-- The readouts strip: the cursors' deltas and the measurements' values on one line, shown
only while the dock is not (hidden with the Dock button, or collapsed and not currently
overlaid; `sync_readouts_strip()` decides, per tick). A fixed height, so the content
never sets it; what does not fit scrolls horizontally with no bar taking height. The
box inside is filled by code (`src/ui_dock.cpp`). Starts hidden: the dock starts shown. -->
<object class="GtkScrolledWindow" id="readouts_strip">
<property name="visible">0</property>
<property name="height-request">26</property>
<property name="vexpand">0</property>
<property name="hscrollbar-policy">external</property>
<property name="vscrollbar-policy">never</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="child">
<object class="GtkBox" id="readouts_strip_box">
<property name="orientation">horizontal</property>
<property name="spacing">8</property>
<property name="valign">center</property>
</object>
</property>
</object>
</child>
<child>
<!-- Setup is reached by the object it configures: a badge per signal on the left
(step 2), the system badges (Trigger, Source) on the right. A fixed height, so
+18
View File
@@ -610,6 +610,17 @@ struct App {
GtkWidget* dock_measures_edit = nullptr;
/// One value label per measurement, in `measures` order (the dock's copy of `measure_labels`).
std::vector<GtkWidget*> dock_measure_labels;
/// The readouts strip under the plot (`main-window.ui` `readouts_strip`, `src/ui_dock.cpp`): shown only
/// while the dock is not. Its value labels mirror the dock's one for one -- `strip_cursor_deltas` the
/// `d` cell of each `dock_cursor_lines` entry, `strip_measure_labels` each of `dock_measure_labels` --
/// and `strip_cursor_who` the cursor lines' `who` cells, all written from the dock setters' arguments.
GtkWidget* readouts_strip = nullptr;
GtkWidget* strip_box = nullptr;
GtkWidget* strip_cursor_box = nullptr; ///< the cursor chips; insensitive with the cursors off
GtkWidget* strip_measure_box = nullptr; ///< the measurement chips
std::vector<GtkWidget*> strip_cursor_who;
std::vector<GtkWidget*> strip_cursor_deltas;
std::vector<GtkWidget*> strip_measure_labels;
/// The measurements the user set up, and what they last computed. The list is the state;
/// the results are recomputed on a throttle (the numbers are window statistics, and the
/// window scrolls every frame -- 60 recomputations a second of every sample is not a
@@ -1784,6 +1795,13 @@ void dock_rebuild_measures(App& app);
void dock_cursor_cell(App& app, std::size_t line, const std::string& a, const std::string& b,
const std::string& d);
void dock_measure_value(App& app, std::size_t i, const std::string& text);
/// The readouts strip under the plot (`src/ui_dock.cpp`): the third reader of the same strings. It is
/// filled by the `dock_*` rebuilds and written by the `dock_*` setters above (so nothing here formats),
/// and shown exactly when the dock is not: `sync_readouts_strip()` is called by the tick after the
/// show-sidebar reconciliation. `dock_set_cursors_sensitive()` is the one writer of the cursor readouts'
/// sensitivity, for the dock's grid and the strip's chips together.
void sync_readouts_strip(App& app);
void dock_set_cursors_sensitive(App& app, bool on);
/// The Events block under the readouts (`src/ui_dock.cpp`): compact rows (marker, title, time; no
/// thumbnails) from `event_store->list()`, newest first, and a Manage button for the `events` page.
/// `dock_rebuild_events()` follows every change of what is *cached*, `dock_mark_events()` every change
+3 -2
View File
@@ -151,8 +151,9 @@ void on_cursors_toggled(GtkToggleButton* button, gpointer user) {
// cursors back on -- and a control inside an insensitive parent cannot be clicked.
gtk_widget_set_sensitive(app->cursors_reset, on);
if (app->cursors_body != nullptr) gtk_widget_set_sensitive(app->cursors_body, on);
// The dock's copy follows: switched off it stays on screen, insensitive, reading `--`.
if (app->dock_cursor_grid != nullptr) gtk_widget_set_sensitive(app->dock_cursor_grid, on);
// The dock's copy and the strip's chips follow: switched off they stay on screen, insensitive, reading
// `--`. One function, so the two cannot disagree.
dock_set_cursors_sensitive(*app, on);
if (!on) update_cursors_pane(*app);
if (on) {
app->rows->reset_cursors();
+137 -17
View File
@@ -9,6 +9,12 @@
// so the two views cannot disagree. Every label is ellipsized at a fixed `width-chars`, so the dock's
// layout does not depend on what a value reads; the full text is the label's tooltip.
//
// The same strings are shown a third time in the readouts strip under the plot (`readouts_strip`, one
// fixed-height line: a "Cursors" button, one chip per cursor line with its delta, a "Measures" button, one
// chip per measurement with its value), which is on screen exactly when the dock is not. The setters below
// write the strip's labels in the same call as the dock's, from the same argument, so there is still one
// string and no second formatter.
//
// Below them, the Events block: one compact row per cached event (marker, title, time; no thumbnails),
// a Manage button for the full list, and one click on a row to replay it. Its rows are built from the
// same `event_store->list()` and the same `event_row_title()` as the events page, so the two cannot
@@ -72,6 +78,46 @@ void on_measure_line_pressed(GtkGestureClick* gesture, int n_press, double, doub
open_measure_dialog(*static_cast<App*>(user), idx);
}
/// The page's `who` cell, verbatim, onto a copy: a chip and a name as markup, or plain text, and its
/// tooltip. The dock's cell and the strip's chip are both made by it.
void copy_who(GtkWidget* dst, GtkWidget* src) {
if (src == nullptr) return;
const char* text = gtk_label_get_label(GTK_LABEL(src));
if (gtk_label_get_use_markup(GTK_LABEL(src))) {
gtk_label_set_markup(GTK_LABEL(dst), text);
} else {
gtk_label_set_text(GTK_LABEL(dst), text);
}
const char* tip = gtk_widget_get_tooltip_text(src);
gtk_widget_set_tooltip_text(dst, tip != nullptr ? tip : gtk_label_get_text(GTK_LABEL(src)));
}
void clear_box(GtkWidget* box) {
GtkWidget* child = gtk_widget_get_first_child(box);
while (child != nullptr) {
GtkWidget* next = gtk_widget_get_next_sibling(child);
gtk_box_remove(GTK_BOX(box), child);
child = next;
}
}
/// The strip's cell widths, in characters. Fixed like the dock's, so the strip's chips are as wide with
/// `--` as with `-123.456 mV` (what does not fit scrolls).
constexpr int kStripWhoChars = 6;
constexpr int kStripTypeChars = 10;
/// A flat text button that opens a slide-over page. It only opens a page, so a rebuild can never free the
/// widget its own signal was emitted from.
GtkWidget* strip_button(const char* label, GCallback on_click, App* app, const char* tip) {
GtkWidget* b = gtk_button_new_with_label(label);
gtk_widget_add_css_class(b, "flat");
gtk_widget_add_css_class(b, "udpscope-strip-button");
gtk_widget_set_valign(b, GTK_ALIGN_CENTER);
gtk_widget_set_tooltip_text(b, tip);
g_signal_connect(b, "clicked", on_click, app);
return b;
}
/// A section's heading row: its title at the left, its Edit button at the right.
GtkWidget* section_head(const char* title, GtkWidget** edit_out, GCallback on_edit, App* app,
const char* tip) {
@@ -101,6 +147,25 @@ void dock_cursors_header(GtkGrid* grid) {
}
}
/// Fills the strip `main-window.ui` declares: the two buttons and the two boxes the rebuilds fill.
void build_readouts_strip(App& app) {
if (app.strip_box == nullptr) return;
clear_box(app.strip_box);
app.strip_cursor_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
app.strip_measure_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
gtk_box_append(GTK_BOX(app.strip_box),
strip_button("Cursors", G_CALLBACK(on_edit_cursors), &app, "the cursors' full panel"));
gtk_box_append(GTK_BOX(app.strip_box), app.strip_cursor_box);
GtkWidget* sep = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
gtk_widget_set_margin_top(sep, 5);
gtk_widget_set_margin_bottom(sep, 5);
gtk_box_append(GTK_BOX(app.strip_box), sep);
gtk_box_append(GTK_BOX(app.strip_box),
strip_button("Measures", G_CALLBACK(on_edit_measures), &app,
"the measurements' full panel"));
gtk_box_append(GTK_BOX(app.strip_box), app.strip_measure_box);
}
} // namespace
GtkWidget* build_readouts_dock(App& app) {
@@ -130,6 +195,7 @@ GtkWidget* build_readouts_dock(App& app) {
gtk_box_append(GTK_BOX(box), app.dock_measures_box);
app.dock_readouts = box;
build_readouts_strip(app);
// The tables are built from the pages' current lines, which exist already when the pages were built
// first; otherwise the pages' own rebuild fills them.
dock_rebuild_cursors(app);
@@ -147,22 +213,17 @@ void dock_rebuild_cursors(App& app) {
child = next;
}
app.dock_cursor_lines.clear();
// The strip's chips are rebuilt with the dock's lines (one per line, same order), so the counts agree by
// construction. The box itself keeps its sensitivity across the rebuild.
if (app.strip_cursor_box != nullptr) clear_box(app.strip_cursor_box);
app.strip_cursor_who.clear();
app.strip_cursor_deltas.clear();
dock_cursors_header(grid);
int at = 1;
for (const App::CursorLine& src : app.cursors_lines) {
App::DockCursorLine line;
line.label = fixed_label("", kNameChars, GTK_ALIGN_START);
if (src.label != nullptr) {
// The page's `who` cell, verbatim: a chip and a name as markup, or plain text.
const char* text = gtk_label_get_label(GTK_LABEL(src.label));
if (gtk_label_get_use_markup(GTK_LABEL(src.label))) {
gtk_label_set_markup(GTK_LABEL(line.label), text);
} else {
gtk_label_set_text(GTK_LABEL(line.label), text);
}
const char* tip = gtk_widget_get_tooltip_text(src.label);
gtk_widget_set_tooltip_text(line.label, tip != nullptr ? tip : gtk_label_get_text(GTK_LABEL(src.label)));
}
copy_who(line.label, src.label);
gtk_grid_attach(grid, line.label, 0, at, 1, 1);
GtkWidget** cells[3] = {&line.a, &line.b, &line.d};
for (int c = 0; c < 3; ++c) {
@@ -173,25 +234,41 @@ void dock_rebuild_cursors(App& app) {
*cells[c] = v;
}
app.dock_cursor_lines.push_back(line);
if (app.strip_cursor_box != nullptr) {
// A chip: the line's `who` and its delta. Not selectable, so a drag on it scrolls the strip.
GtkWidget* chip = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
GtkWidget* who = fixed_label("", kStripWhoChars, GTK_ALIGN_START);
copy_who(who, src.label);
GtkWidget* delta = fixed_label("", kValueChars, GTK_ALIGN_END);
gtk_widget_add_css_class(delta, "numeric");
gtk_box_append(GTK_BOX(chip), who);
gtk_box_append(GTK_BOX(chip), delta);
gtk_box_append(GTK_BOX(app.strip_cursor_box), chip);
app.strip_cursor_who.push_back(who);
app.strip_cursor_deltas.push_back(delta);
}
++at;
}
}
void dock_rebuild_measures(App& app) {
if (app.dock_measures_box == nullptr) return;
GtkWidget* child = gtk_widget_get_first_child(app.dock_measures_box);
while (child != nullptr) {
GtkWidget* next = gtk_widget_get_next_sibling(child);
gtk_box_remove(GTK_BOX(app.dock_measures_box), child);
child = next;
}
clear_box(app.dock_measures_box);
if (app.strip_measure_box != nullptr) clear_box(app.strip_measure_box);
app.dock_measure_labels.clear();
app.strip_measure_labels.clear();
if (app.measures.empty()) {
GtkWidget* none = gtk_label_new("no measurements");
gtk_widget_set_halign(none, GTK_ALIGN_START);
gtk_widget_add_css_class(none, "caption");
gtk_widget_add_css_class(none, "dim-label");
gtk_box_append(GTK_BOX(app.dock_measures_box), none);
if (app.strip_measure_box != nullptr) {
GtkWidget* strip_none = gtk_label_new("no measurements");
gtk_widget_add_css_class(strip_none, "caption");
gtk_widget_add_css_class(strip_none, "dim-label");
gtk_box_append(GTK_BOX(app.strip_measure_box), strip_none);
}
return;
}
for (std::size_t i = 0; i < app.measures.size(); ++i) {
@@ -217,6 +294,29 @@ void dock_rebuild_measures(App& app) {
gtk_widget_add_controller(line, GTK_EVENT_CONTROLLER(click));
gtk_box_append(GTK_BOX(app.dock_measures_box), line);
app.dock_measure_labels.push_back(value);
if (app.strip_measure_box != nullptr) {
// The strip's chip: the signal's chip, the type's short name and the value; a click on it opens the
// same dialog as the dock's line.
GtkWidget* sline = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
g_object_set_data(G_OBJECT(sline), "udpscope-measure-index",
GINT_TO_POINTER(static_cast<int>(i) + 1));
GtkWidget* schip = gtk_label_new("");
gtk_label_set_markup(GTK_LABEL(schip), measure_chip_markup(app, m.signal).c_str());
gtk_widget_set_tooltip_text(schip, m.signal.c_str());
gtk_box_append(GTK_BOX(sline), schip);
GtkWidget* skind = fixed_label(measure_type_name(m.type), kStripTypeChars, GTK_ALIGN_START);
gtk_widget_set_tooltip_text(skind, (m.signal + "\n" + measure_type_name(m.type)).c_str());
gtk_box_append(GTK_BOX(sline), skind);
GtkWidget* svalue = fixed_label("--", kValueChars, GTK_ALIGN_END);
gtk_widget_add_css_class(svalue, "numeric");
gtk_box_append(GTK_BOX(sline), svalue);
GtkGesture* sclick = gtk_gesture_click_new();
g_signal_connect(sclick, "pressed", G_CALLBACK(on_measure_line_pressed), &app);
gtk_widget_add_controller(sline, GTK_EVENT_CONTROLLER(sclick));
gtk_box_append(GTK_BOX(app.strip_measure_box), sline);
app.strip_measure_labels.push_back(svalue);
}
}
}
@@ -227,11 +327,31 @@ void dock_cursor_cell(App& app, std::size_t line, const std::string& a, const st
set_value_text(l.a, a);
set_value_text(l.b, b);
set_value_text(l.d, d);
// The strip's chip takes the delta from the same argument, in the same call.
if (line < app.strip_cursor_deltas.size()) set_value_text(app.strip_cursor_deltas[line], d);
}
void dock_measure_value(App& app, std::size_t i, const std::string& text) {
if (i >= app.dock_measure_labels.size()) return; // mid-rebuild
set_value_text(app.dock_measure_labels[i], text);
if (i < app.strip_measure_labels.size()) set_value_text(app.strip_measure_labels[i], text);
}
void dock_set_cursors_sensitive(App& app, bool on) {
// Disabled, not hidden: the dock's grid and the strip's chips go grey together and read `--`.
if (app.dock_cursor_grid != nullptr) gtk_widget_set_sensitive(app.dock_cursor_grid, on);
if (app.strip_cursor_box != nullptr) gtk_widget_set_sensitive(app.strip_cursor_box, on);
}
void sync_readouts_strip(App& app) {
if (app.readouts_strip == nullptr || app.side_view == nullptr) return;
// The strip is on screen exactly when the dock is not: `show-sidebar` is false when the dock is hidden
// with the Dock button, and when the window is collapsed and the dock is not currently overlaid.
const bool want =
!adw_overlay_split_view_get_show_sidebar(ADW_OVERLAY_SPLIT_VIEW(app.side_view));
if ((gtk_widget_get_visible(app.readouts_strip) != FALSE) != want) {
gtk_widget_set_visible(app.readouts_strip, want);
}
}
namespace {
+88
View File
@@ -4337,6 +4337,90 @@ static int dock_width_fits(App& a, int* dock_w, int* side_w) {
return *dock_w >= 0 && *side_w > 0 && *dock_w <= *side_w ? 1 : 0;
}
/// The readouts strip against the dock it mirrors: `same_text=1` when every strip label's text equals the
/// dock's (the cursors' `who` and delta cells, the measurements' values) and the counts agree. `visible` must
/// be the opposite of `dock_shown` (`show-sidebar`), and `h` the strip's fixed 26 whenever it is visible.
/// `sens_same` is the strip's cursor chips sharing the dock grid's sensitivity.
static void strip_report(App& a, const char* tag, const char* what) {
const auto text = [](GtkWidget* w) { return std::string(gtk_label_get_text(GTK_LABEL(w))); };
int same = a.strip_cursor_deltas.size() == a.dock_cursor_lines.size() &&
a.strip_cursor_who.size() == a.dock_cursor_lines.size() &&
a.strip_measure_labels.size() == a.dock_measure_labels.size()
? 1 : 0;
for (std::size_t i = 0; same != 0 && i < a.dock_cursor_lines.size(); ++i) {
if (text(a.strip_cursor_deltas[i]) != text(a.dock_cursor_lines[i].d) ||
text(a.strip_cursor_who[i]) != text(a.dock_cursor_lines[i].label)) {
same = 0;
}
}
for (std::size_t i = 0; same != 0 && i < a.dock_measure_labels.size(); ++i) {
if (text(a.strip_measure_labels[i]) != text(a.dock_measure_labels[i])) same = 0;
}
const bool dock_shown =
a.side_view != nullptr &&
adw_overlay_split_view_get_show_sidebar(ADW_OVERLAY_SPLIT_VIEW(a.side_view)) != FALSE;
const bool visible = a.readouts_strip != nullptr && gtk_widget_get_visible(a.readouts_strip);
const bool collapsed =
a.side_view != nullptr &&
adw_overlay_split_view_get_collapsed(ADW_OVERLAY_SPLIT_VIEW(a.side_view)) != FALSE;
const bool sens_same =
a.strip_cursor_box != nullptr && a.dock_cursor_grid != nullptr &&
gtk_widget_get_sensitive(a.strip_cursor_box) == gtk_widget_get_sensitive(a.dock_cursor_grid);
std::fprintf(stderr,
"[%s-probe] %-14s strip: visible=%d dock_shown=%d cursors=%zu measures=%zu same_text=%d "
"h=%d sens_same=%d collapsed=%d window=%d\n",
tag, what, visible ? 1 : 0, dock_shown ? 1 : 0, a.strip_cursor_deltas.size(),
a.strip_measure_labels.size(), same, a.readouts_strip != nullptr
? gtk_widget_get_height(a.readouts_strip) : -1,
sens_same ? 1 : 0, collapsed ? 1 : 0,
a.window != nullptr ? gtk_widget_get_width(a.window) : -1);
}
/// Puts the dock away through the wish the tick re-asserts and reads the strip with it hidden
/// (`<tag>-probe ... strip:`: visible must be 1, h 26, same_text 1), then restores the wish and reads it
/// again (visible must be 0). Under `xvfb-run` the window is 756 px wide, below `kSidebarRoom`, so the split
/// view is `collapsed` on every line: both legs are the collapsed case (the tick keeps a wished dock
/// overlaid, a hidden one off), and `collapsed=0` is not reachable from a probe -- a window with no
/// manager cannot be resized by `gtk_window_set_default_size()`.
struct StripDrive {
App* app;
const char* tag;
int step;
};
static gboolean strip_drive_step(gpointer user) {
auto* d = static_cast<StripDrive*>(user);
App& a = *d->app;
if (a.window == nullptr) {
delete d;
return G_SOURCE_REMOVE;
}
switch (d->step) {
case 0:
a.sidebar_wanted = false;
update_side_visibility(a);
break;
case 1:
strip_report(a, d->tag, "dock hidden");
a.sidebar_wanted = true;
update_side_visibility(a);
break;
default:
strip_report(a, d->tag, "dock restored");
std::fflush(stderr);
delete d;
return G_SOURCE_REMOVE;
}
std::fflush(stderr);
++d->step;
g_timeout_add(600, strip_drive_step, d);
return G_SOURCE_REMOVE;
}
static void strip_drive(App& a, const char* tag) {
g_timeout_add(100, strip_drive_step, new StripDrive{&a, tag, 0});
}
static void dock_cursors_report(App& a, const char* what) {
int same = a.dock_cursor_lines.size() == a.cursors_lines.size() ? 1 : 0;
for (std::size_t i = 0; same != 0 && i < a.cursors_lines.size(); ++i) {
@@ -4356,6 +4440,7 @@ static void dock_cursors_report(App& a, const char* what) {
"side_w=%d fits=%d dock_sensitive=%d\n",
what, a.dock_cursor_lines.size(), a.cursors_lines.size(), same, dock_w, side_w, fits,
a.dock_cursor_grid != nullptr && gtk_widget_get_sensitive(a.dock_cursor_grid) ? 1 : 0);
strip_report(a, "cursors", what);
}
static void dock_measures_report(App& a, const char* what) {
@@ -4374,6 +4459,7 @@ static void dock_measures_report(App& a, const char* what) {
"side_w=%d fits=%d\n",
what, a.dock_measure_labels.size(), a.measure_labels.size(), same, dock_w, side_w,
fits);
strip_report(a, "measures", what);
}
void cursors_probe_report(App& a, const char* what) {
@@ -4646,6 +4732,7 @@ gboolean cursors_probe_step(gpointer user) {
}
default:
cursors_probe_report(*a, "after ruler drag");
strip_drive(*a, "cursors"); // the dock put away and the window narrowed, the strip read at each
break;
}
return G_SOURCE_REMOVE;
@@ -4758,6 +4845,7 @@ gboolean measures_probe_step(gpointer user) {
std::fflush(stderr);
measure_dialog_report(*a, "final");
dock_measures_report(*a, "final");
strip_drive(*a, "measures");
break;
}
}
+2
View File
@@ -79,6 +79,8 @@ void install_css() {
".udpscope-badge { padding: 2px 12px; min-height: 0; border-radius: 14px; }\n"
".udpscope-badge-open { background-color: alpha(@accent_bg_color, 0.28); }\n"
".udpscope-badge-state { opacity: 0.7; }\n"
// The readouts strip's two text buttons: Adwaita's 34 px button would be taller than the strip.
"button.udpscope-strip-button { min-height: 0; padding: 1px 8px; }\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. Measured on libadwaita 1.10: the outer `menubutton` node *and* its