Feature/source plugins #1
No files matched your search
+22
-32
@@ -2866,20 +2866,6 @@ void on_right_click(GtkGestureClick* gesture, int, double x, double y, gpointer
|
|||||||
open_row_menu(*app, row, x, y, widget);
|
open_row_menu(*app, row, x, y, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scrolls the dock to a section. The dock is one scroller (`App::dock_scroller`) holding the cursors and
|
|
||||||
/// the measurements top to bottom, so "measure" is the cursors panel's offset in the page. Nothing is
|
|
||||||
/// hidden or removed: both stay in the page. An unknown name (the signal list is a slide-over page now,
|
|
||||||
/// not a dock section) is a no-op, so a key bound to a section a later version drops cannot blank anything.
|
|
||||||
void dock_show_section(App& app, const char* section) {
|
|
||||||
if (app.dock_scroller == nullptr || app.dock_page == nullptr || section == nullptr) return;
|
|
||||||
GtkAdjustment* adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(app.dock_scroller));
|
|
||||||
if (std::strcmp(section, "measure") != 0 || app.cursors_panel == nullptr) return;
|
|
||||||
graphene_point_t zero = GRAPHENE_POINT_INIT(0.f, 0.f);
|
|
||||||
graphene_point_t at;
|
|
||||||
if (!gtk_widget_compute_point(app.cursors_panel, app.dock_page, &zero, &at)) return;
|
|
||||||
gtk_adjustment_set_value(adj, at.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The dock is on when the user's sidebar button is in -- from the start, with or without signals; the
|
/// The dock is on when the user's sidebar button is in -- from the start, with or without signals; the
|
||||||
/// two panel buttons appear as soon as a CONFIG describes any signal at all.
|
/// two panel buttons appear as soon as a CONFIG describes any signal at all.
|
||||||
void update_side_visibility(App& app) {
|
void update_side_visibility(App& app) {
|
||||||
@@ -3437,7 +3423,9 @@ gboolean tick(gpointer user) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Captured every frame so the dump has the last live value: see `dbg_measures_pane_w`.
|
// Captured every frame so the dump has the last live value: see `dbg_measures_pane_w`.
|
||||||
if (app->measures_list != nullptr) {
|
// Only while the `measure` page is on screen: a closed page has no allocation, and the dump should
|
||||||
|
// keep the last real size rather than 0.
|
||||||
|
if (app->measures_list != nullptr && gtk_widget_get_width(app->measures_list) > 0) {
|
||||||
app->dbg_measures_pane_w = gtk_widget_get_width(app->measures_list);
|
app->dbg_measures_pane_w = gtk_widget_get_width(app->measures_list);
|
||||||
app->dbg_measures_pane_h = gtk_widget_get_height(app->measures_list);
|
app->dbg_measures_pane_h = gtk_widget_get_height(app->measures_list);
|
||||||
}
|
}
|
||||||
@@ -3993,7 +3981,7 @@ gboolean tick(gpointer user) {
|
|||||||
// The one thing that has to be decided *per frame* about the dock: whether there is room for it
|
// The one thing that has to be decided *per frame* about the dock: whether there is room for it
|
||||||
// beside the plot. Collapsed, the split view puts it *over* the plot rather than giving it a share of
|
// beside the plot. Collapsed, the split view puts it *over* the plot rather than giving it a share of
|
||||||
// a width that is not there -- so a small window shows fewer pixels of plot, never a panel squeezed
|
// a width that is not there -- so a small window shows fewer pixels of plot, never a panel squeezed
|
||||||
// to nothing. `kSidebarRoom` is the sidebar's 320 plus the width below which the plot stops being
|
// to nothing. `kSidebarRoom` is the sidebar's 280 plus the width below which the plot stops being
|
||||||
// worth looking at.
|
// worth looking at.
|
||||||
if (app->side_view != nullptr && app->window != nullptr) {
|
if (app->side_view != nullptr && app->window != nullptr) {
|
||||||
// The split view writes `show-sidebar` itself (at startup and when it collapses), so the wish is
|
// The split view writes `show-sidebar` itself (at startup and when it collapses), so the wish is
|
||||||
@@ -4656,7 +4644,7 @@ void run_app_action(App& app, AppAction action) {
|
|||||||
case AppAction::CursorsPane:
|
case AppAction::CursorsPane:
|
||||||
toggle(app.cursors_toggle);
|
toggle(app.cursors_toggle);
|
||||||
break;
|
break;
|
||||||
case AppAction::ShowMeasure: dock_show_section(app, "measure"); break;
|
case AppAction::ShowMeasure: slideover_toggle(app, "measure"); break;
|
||||||
case AppAction::ShowSignals: {
|
case AppAction::ShowSignals: {
|
||||||
// The `+` badge is insensitive without signals; so is its shortcut.
|
// The `+` badge is insensitive without signals; so is its shortcut.
|
||||||
bool have_signals = false;
|
bool have_signals = false;
|
||||||
@@ -5038,7 +5026,7 @@ void on_activate(GtkApplication* application, gpointer user) {
|
|||||||
|
|
||||||
// The size the window opens at, stated in code as well as in the `.ui`: `default-width` there is the
|
// The size the window opens at, stated in code as well as in the `.ui`: `default-width` there is the
|
||||||
// size it *asks* for, and a window whose content has a larger minimum opens at that minimum instead --
|
// size it *asks* for, and a window whose content has a larger minimum opens at that minimum instead --
|
||||||
// 756 px here, the plot column's own minimum plus the sidebar's 320. The old code set it explicitly;
|
// 756 px here, the plot column's own minimum plus the sidebar's 280. The old code set it explicitly;
|
||||||
// this is where it went when the window moved into the file, and it is why the window came up small.
|
// this is where it went when the window moved into the file, and it is why the window came up small.
|
||||||
gtk_window_set_default_size(GTK_WINDOW(app->window), 1280, 800);
|
gtk_window_set_default_size(GTK_WINDOW(app->window), 1280, 800);
|
||||||
|
|
||||||
@@ -5140,15 +5128,16 @@ void on_activate(GtkApplication* application, gpointer user) {
|
|||||||
gtk_popover_set_has_arrow(GTK_POPOVER(app->status_popover), TRUE);
|
gtk_popover_set_has_arrow(GTK_POPOVER(app->status_popover), TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The right-hand side is the dock: one scroller, the cursors then the measurements. Every section is
|
// The right-hand side is the dock: one scroller holding only the compact read-only readouts (the
|
||||||
// always there -- "go to Measure" scrolls to it instead of switching a tab, so the measurements are as
|
// cursors table and the measurements). The full Cursors and Measurements panels are slide-over pages
|
||||||
// live as the cursors above them. The signal list is a slide-over page (reached by the `+` badge).
|
// (`cursors`, `measure`), live whether or not they are open: the pages hold the same widgets and the
|
||||||
|
// tick writes them either way. The signal list is a page too (reached by the `+` badge).
|
||||||
// `side` and `dock_page`/`dock_scroller` are resolved above with the rest of the skeleton and checked
|
// `side` and `dock_page`/`dock_scroller` are resolved above with the rest of the skeleton and checked
|
||||||
// by the null guard; assign the member here.
|
// by the null guard; assign the member here.
|
||||||
app->side_box = side;
|
app->side_box = side;
|
||||||
|
|
||||||
// Built in the order the panels have always been (cursors, measurements, trigger, signals) and placed in
|
// Built in the order the panels have always been (cursors, measurements, trigger, signals); each is a
|
||||||
// the dock's: the trigger form goes to the slide-over (reached by the Trigger badge).
|
// page of the slide-over, reached by its badge, its key or the header's Cursors toggle.
|
||||||
app->cursors_panel = build_cursors_panel(*app);
|
app->cursors_panel = build_cursors_panel(*app);
|
||||||
GtkWidget* measures_panel = build_measures_panel(*app);
|
GtkWidget* measures_panel = build_measures_panel(*app);
|
||||||
app->trigger_panel = build_trigger_panel(*app);
|
app->trigger_panel = build_trigger_panel(*app);
|
||||||
@@ -5160,13 +5149,14 @@ void on_activate(GtkApplication* application, gpointer user) {
|
|||||||
// `build_slideover`, and registered once.
|
// `build_slideover`, and registered once.
|
||||||
app->signal_panel = build_signal_panel(*app);
|
app->signal_panel = build_signal_panel(*app);
|
||||||
slideover_add_page(*app, "signals", "Signals", app->signal_panel);
|
slideover_add_page(*app, "signals", "Signals", app->signal_panel);
|
||||||
gtk_box_append(GTK_BOX(app->dock_page), app->cursors_panel);
|
// `c` / the header toggle drive the cursors themselves; this page is where they are configured and read
|
||||||
gtk_box_append(GTK_BOX(app->dock_page), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL));
|
// in full. `m` toggles the measurements page.
|
||||||
gtk_box_append(GTK_BOX(app->dock_page), measures_panel);
|
gtk_widget_set_valign(app->cursors_panel, GTK_ALIGN_START);
|
||||||
// The compact readouts above the full panels (which move to slide-over pages later), with their own
|
gtk_widget_set_valign(measures_panel, GTK_ALIGN_START);
|
||||||
// separator: the first child of the dock.
|
slideover_add_page(*app, "cursors", "Cursors", app->cursors_panel);
|
||||||
gtk_box_prepend(GTK_BOX(app->dock_page), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL));
|
slideover_add_page(*app, "measure", "Measurements", measures_panel);
|
||||||
gtk_box_prepend(GTK_BOX(app->dock_page), build_readouts_dock(*app));
|
// The dock is the compact readouts alone (step 4 adds the events to it).
|
||||||
|
gtk_box_append(GTK_BOX(app->dock_page), build_readouts_dock(*app));
|
||||||
|
|
||||||
// The cursors start off, so their readout starts insensitive -- stated here by the one place that
|
// The cursors start off, so their readout starts insensitive -- stated here by the one place that
|
||||||
// knows the default, and the *body* and not the panel, because the panel's heading carries the
|
// knows the default, and the *body* and not the panel, because the panel's heading carries the
|
||||||
@@ -5200,8 +5190,8 @@ void on_activate(GtkApplication* application, gpointer user) {
|
|||||||
|
|
||||||
// Two plots, in a paned so a comparison's divider can move: the primary takes everything while the
|
// Two plots, in a paned so a comparison's divider can move: the primary takes everything while the
|
||||||
// second is hidden, and the width is the user's once it is not.
|
// second is hidden, and the width is the user's once it is not.
|
||||||
// Nothing to state about the sidebar's size. It is the split view's: 320 px from the `.ui`, floored
|
// Nothing to state about the sidebar's size. It is the split view's: 280 px from the `.ui` (min = max),
|
||||||
// at 240, and never a number derived from the window -- which is what the removed
|
// and never a number derived from the window -- which is what the removed
|
||||||
// `gtk_paned_set_position(paned, 940)` was, and why a window narrower than 940 px gave the sidebar
|
// `gtk_paned_set_position(paned, 940)` was, and why a window narrower than 940 px gave the sidebar
|
||||||
// no width at all.
|
// no width at all.
|
||||||
|
|
||||||
|
|||||||
+7
-10
@@ -21,7 +21,7 @@
|
|||||||
What is *not* here is as deliberate as what is. Everything this file nests is fixed — the shape of
|
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 subtrees that do are
|
the window does not depend on the stream, the trigger or the layout — while the subtrees that do are
|
||||||
built by code and put in place: the events pane, into `events_divider`'s start side; the two plot
|
built by code and put in place: the events pane, into `events_divider`'s start side; the two plot
|
||||||
areas, into the split inside `plot_box`; the dock's panels (signals, cursors, measurements), appended to `dock_page`; and the
|
areas, into the split inside `plot_box`; the dock's readouts, appended to `dock_page`; and the
|
||||||
status popover, attached to `status_info`.
|
status popover, attached to `status_info`.
|
||||||
|
|
||||||
The header bar is not here either: it is the window's own titlebar, built by `build_toolbar()`
|
The header bar is not here either: it is the window's own titlebar, built by `build_toolbar()`
|
||||||
@@ -40,22 +40,19 @@
|
|||||||
<child>
|
<child>
|
||||||
<object class="AdwOverlaySplitView" id="side_view">
|
<object class="AdwOverlaySplitView" id="side_view">
|
||||||
<property name="sidebar-position">end</property>
|
<property name="sidebar-position">end</property>
|
||||||
<!-- Its width in pixels, not as a fraction of the window: 320 on a first run, and never less
|
<!-- Its width in pixels, not as a fraction of the window: 280, the width of the compact readouts. -->
|
||||||
than 240 however small the window gets. -->
|
|
||||||
<!-- Both ends of the range, in pixels: `sidebar-width-fraction` is a 0..1 *fraction* of the
|
<!-- Both ends of the range, in pixels: `sidebar-width-fraction` is a 0..1 *fraction* of the
|
||||||
window (setting a pixel count there is a GObject critical and falls back to 0.25), so the
|
window (setting a pixel count there is a GObject critical and falls back to 0.25), so the
|
||||||
width is pinned by min and max instead. -->
|
width is pinned by min and max instead. -->
|
||||||
<property name="sidebar-width-unit">px</property>
|
<property name="sidebar-width-unit">px</property>
|
||||||
<property name="min-sidebar-width">320</property>
|
<property name="min-sidebar-width">280</property>
|
||||||
<property name="max-sidebar-width">320</property>
|
<property name="max-sidebar-width">280</property>
|
||||||
<property name="sidebar">
|
<property name="sidebar">
|
||||||
<!-- The dock: one scroller holding the signal list, then the cursors and the measurements.
|
<!-- The dock: one scroller holding the compact cursor and measurement readouts. The full
|
||||||
It replaces the tab switcher (four text tabs did not fit 320 px and a source can add
|
Cursors and Measurements panels are slide-over pages, and the signal list is a page too. -->
|
||||||
more); it is the temporary home of Measure and Signals until steps 2 and 3 turn them
|
|
||||||
into the badge bar's signals and the compact readouts. -->
|
|
||||||
<object class="GtkBox" id="side_column">
|
<object class="GtkBox" id="side_column">
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="width-request">300</property>
|
<property name="width-request">260</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkScrolledWindow" id="dock_scroller">
|
<object class="GtkScrolledWindow" id="dock_scroller">
|
||||||
<property name="vexpand">1</property>
|
<property name="vexpand">1</property>
|
||||||
|
|||||||
+5
-8
@@ -266,9 +266,9 @@ struct App {
|
|||||||
GtkWidget* trigger_panel = nullptr;
|
GtkWidget* trigger_panel = nullptr;
|
||||||
GtkWidget* signal_panel = nullptr;
|
GtkWidget* signal_panel = nullptr;
|
||||||
GtkWidget* side_box = nullptr;
|
GtkWidget* side_box = nullptr;
|
||||||
/// The dock: the sidebar's one scroller and the box inside it, which holds the cursors and
|
/// The dock: the sidebar's one scroller and the box inside it, which holds only the compact readouts
|
||||||
/// the measurements (`dock_show_section()` scrolls it). A feature's own on/off never
|
/// (`build_readouts_dock()`). The full cursors and measurements panels are the slide-over's `cursors`
|
||||||
/// removes a section (it sets its panel's sensitivity instead).
|
/// and `measure` pages. A feature's own on/off never removes a panel (it sets its sensitivity instead).
|
||||||
GtkWidget* dock_page = nullptr;
|
GtkWidget* dock_page = nullptr;
|
||||||
GtkWidget* dock_scroller = nullptr;
|
GtkWidget* dock_scroller = nullptr;
|
||||||
GtkWidget* arm_button = nullptr;
|
GtkWidget* arm_button = nullptr;
|
||||||
@@ -1609,8 +1609,8 @@ constexpr int kEventThumbH = 46;
|
|||||||
constexpr int kEventThumbMaxH = 104;
|
constexpr int kEventThumbMaxH = 104;
|
||||||
inline int g_stats_phase = 0;
|
inline int g_stats_phase = 0;
|
||||||
inline std::vector<std::uint64_t> g_stats_n_before;
|
inline std::vector<std::uint64_t> g_stats_n_before;
|
||||||
/// The same for the dock-section probe: the accumulator counts recorded while the Measure section was
|
/// The same for the dock-section probe: the accumulator counts recorded while the `measure` page was
|
||||||
/// still scrolled into view, so the report can say whether any of them advanced after it scrolled out.
|
/// still open, so the report can say whether any of them advanced after it was closed.
|
||||||
inline std::vector<std::uint64_t> g_dock_section_n_before;
|
inline std::vector<std::uint64_t> g_dock_section_n_before;
|
||||||
inline double g_trigrenum_edge = 0.0;
|
inline double g_trigrenum_edge = 0.0;
|
||||||
inline std::uint64_t g_trigrenum_latches = 0;
|
inline std::uint64_t g_trigrenum_latches = 0;
|
||||||
@@ -1867,9 +1867,6 @@ void row_menu_fill(RowMenuState& st);
|
|||||||
GtkWidget* open_row_menu(App& app, int row, double x, double y, GtkWidget* parent, bool autohide = true);
|
GtkWidget* open_row_menu(App& app, int row, double x, double y, GtkWidget* parent, bool autohide = true);
|
||||||
void on_right_click(GtkGestureClick* gesture, int, double x, double y, gpointer user);
|
void on_right_click(GtkGestureClick* gesture, int, double x, double y, gpointer user);
|
||||||
gboolean on_drop_channel(GtkDropTarget*, const GValue* value, double x, double y, gpointer user);
|
gboolean on_drop_channel(GtkDropTarget*, const GValue* value, double x, double y, gpointer user);
|
||||||
/// Scrolls the dock to a section: "signals" (the top) or "measure" (the cursors panel, which the
|
|
||||||
/// measurements follow). An unknown name is a no-op.
|
|
||||||
void dock_show_section(App& app, const char* section);
|
|
||||||
/// Reads each pane's own switch back off the header bar's button, and the other way round: the two are
|
/// Reads each pane's own switch back off the header bar's button, and the other way round: the two are
|
||||||
/// one control in two places, and `panel_switch_sync` keeps the write from looking like a click.
|
/// one control in two places, and `panel_switch_sync` keeps the write from looking like a click.
|
||||||
void sync_panel_switches(App& app);
|
void sync_panel_switches(App& app);
|
||||||
|
|||||||
+3
-2
@@ -22,9 +22,10 @@ namespace ui_impl {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// The width, in characters, of a value cell and of a `who` / type cell. Fixed, so the dock is as wide
|
/// The width, in characters, of a value cell and of a `who` / type cell. Fixed, so the dock is as wide
|
||||||
/// with `--` as with `-123.456 mV`.
|
/// with `--` as with `-123.456 mV`; their sum (5 + 3 x 9 characters) is what keeps the readouts inside the
|
||||||
|
/// dock's 280 px.
|
||||||
constexpr int kValueChars = 9;
|
constexpr int kValueChars = 9;
|
||||||
constexpr int kNameChars = 8;
|
constexpr int kNameChars = 5;
|
||||||
|
|
||||||
GtkWidget* fixed_label(const char* text, int chars, GtkAlign halign) {
|
GtkWidget* fixed_label(const char* text, int chars, GtkAlign halign) {
|
||||||
GtkWidget* l = gtk_label_new(text);
|
GtkWidget* l = gtk_label_new(text);
|
||||||
|
|||||||
+54
-102
@@ -18,6 +18,7 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
namespace udpscope {
|
namespace udpscope {
|
||||||
namespace ui_impl {
|
namespace ui_impl {
|
||||||
@@ -183,6 +184,18 @@ gboolean exit_probe_step3b(gpointer user) {
|
|||||||
a->dbg_dock_shown = sidebar_shown;
|
a->dbg_dock_shown = sidebar_shown;
|
||||||
a->dbg_dock_sensitive = gtk_widget_get_sensitive(a->side_box) ? 1 : 0;
|
a->dbg_dock_sensitive = gtk_widget_get_sensitive(a->side_box) ? 1 : 0;
|
||||||
a->dbg_dock_w = a->dbg_side_w;
|
a->dbg_dock_w = a->dbg_side_w;
|
||||||
|
{
|
||||||
|
// The dock holds only the readouts box; the full cursors and measurements panels are slide-over pages,
|
||||||
|
// registered whether or not either is open.
|
||||||
|
int children = 0;
|
||||||
|
for (GtkWidget* c = gtk_widget_get_first_child(a->dock_page); c != nullptr;
|
||||||
|
c = gtk_widget_get_next_sibling(c)) {
|
||||||
|
++children;
|
||||||
|
}
|
||||||
|
std::fprintf(stderr, "[readouts] pages cursors=%d measure=%d dock_children=%d dock_w=%d\n",
|
||||||
|
slideover_has_page(*a, "cursors") ? 1 : 0, slideover_has_page(*a, "measure") ? 1 : 0,
|
||||||
|
children, a->dbg_side_w);
|
||||||
|
}
|
||||||
a->dbg_dock_scrollers = 0;
|
a->dbg_dock_scrollers = 0;
|
||||||
for (GtkWidget* c = gtk_widget_get_first_child(a->side_box); c != nullptr;
|
for (GtkWidget* c = gtk_widget_get_first_child(a->side_box); c != nullptr;
|
||||||
c = gtk_widget_get_next_sibling(c)) {
|
c = gtk_widget_get_next_sibling(c)) {
|
||||||
@@ -1792,24 +1805,11 @@ gboolean stats_probe(gpointer user) {
|
|||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which section the dock's scroller is showing at its top: "measure" once it has been scrolled to the
|
/// Phase two of the dock-section probe: the accumulators must have advanced while the `measure` page was
|
||||||
/// measurements' heading or past it, "cursors" above that (the cursors panel is the dock's first section;
|
/// closed. A statistics readout is *history*, so min/max/avg would gain a gap for exactly as long as the
|
||||||
/// the signal list is a slide-over page). Read from the adjustment, so it is the state the user would see
|
/// page was off screen -- which is the one defect the design's "what runs on a hidden page" rule is there
|
||||||
/// and not the last call made.
|
/// to prevent, and the reason no frame-rate code may be gated on which page is open. (It was a tab once,
|
||||||
static const char* dock_section_in_view(App& a) {
|
/// then a dock section; the rule outlived both.)
|
||||||
if (a.dock_scroller == nullptr || a.measures_head == nullptr || a.dock_page == nullptr) return "none";
|
|
||||||
graphene_point_t zero = GRAPHENE_POINT_INIT(0.f, 0.f);
|
|
||||||
graphene_point_t at;
|
|
||||||
if (!gtk_widget_compute_point(a.measures_head, a.dock_page, &zero, &at)) return "none";
|
|
||||||
GtkAdjustment* adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(a.dock_scroller));
|
|
||||||
return gtk_adjustment_get_value(adj) > 0.5 * at.y ? "measure" : "cursors";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Phase two of the dock-section probe: the accumulators must have advanced while the Measure section was
|
|
||||||
/// scrolled out of view. A statistics readout is *history*, so min/max/avg would gain a gap for exactly as
|
|
||||||
/// long as the section was off screen -- which is the one defect the design's "what runs on a hidden
|
|
||||||
/// page" rule is there to prevent, and the reason no frame-rate code may be gated on which section is in
|
|
||||||
/// view. (It was a tab once; the dock is one scroller, and the rule outlived the tabs.)
|
|
||||||
gboolean dock_section_probe_report(gpointer user) {
|
gboolean dock_section_probe_report(gpointer user) {
|
||||||
App* a = static_cast<App*>(user);
|
App* a = static_cast<App*>(user);
|
||||||
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
||||||
@@ -1824,34 +1824,27 @@ gboolean dock_section_probe_report(gpointer user) {
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (a->dock_page != nullptr) gtk_widget_set_size_request(a->dock_page, -1, -1);
|
|
||||||
if (a->cursors_panel != nullptr) gtk_widget_set_size_request(a->cursors_panel, -1, -1);
|
|
||||||
std::fprintf(stderr,
|
std::fprintf(stderr,
|
||||||
"[side-tab-probe] section=%s rows=%zu accums=%zu advanced=%" G_GUINT64_FORMAT
|
"[side-tab-probe] section=%s rows=%zu accums=%zu advanced=%" G_GUINT64_FORMAT
|
||||||
" min_n=%" G_GUINT64_FORMAT "\n",
|
" min_n=%" G_GUINT64_FORMAT "\n",
|
||||||
dock_section_in_view(*a), a->measures.size(), a->measure_stats.size(), advanced, min_n);
|
slideover_page(*a).empty() ? "none" : slideover_page(*a).c_str(), a->measures.size(), a->measure_stats.size(), advanced, min_n);
|
||||||
std::fflush(stderr);
|
std::fflush(stderr);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase one: four measurements on the first channel, statistics on, then scroll the dock *away* from the
|
/// Phase one: four measurements on the first channel, statistics on, then the `measure` page opened for a
|
||||||
/// Measure section and come back in two seconds to read what ran while it was not in view. (The probe
|
/// forced pass and *closed* again; it comes back in two seconds to read what ran while the page was not on
|
||||||
/// keeps its old environment variable, `UDPSCOPE_PROBE_SIDE_TAB_MS`, and its `[side-tab-probe]` tag.)
|
/// screen. (The probe keeps its old environment variable, `UDPSCOPE_PROBE_SIDE_TAB_MS`, and its
|
||||||
|
/// `[side-tab-probe]` tag.) Run it against a config that has seen the first-run tour, which would close the page.
|
||||||
gboolean dock_section_probe(gpointer user) {
|
gboolean dock_section_probe(gpointer user) {
|
||||||
App* a = static_cast<App*>(user);
|
App* a = static_cast<App*>(user);
|
||||||
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
||||||
// A dock whose content fits has nothing to scroll away from, and a tall window does that. The first
|
// The first pass only waits 400 ms: the enable-all probe switches signals on and off around this time,
|
||||||
// pass makes the page taller than any window (a probe-only minimum height, undone in the report) and
|
// and a buffer rebuild between the baseline and the report would drop the accumulators and read as a
|
||||||
// comes back once it has been laid out, so "scrolled out of view" is a state this run really reaches.
|
// gated pass. (It also gives the layout the pass this probe's own row assignment needs.)
|
||||||
static bool padded = false;
|
static bool waited = false;
|
||||||
if (!padded && a->dock_page != nullptr) {
|
if (!waited) {
|
||||||
padded = true;
|
waited = true;
|
||||||
gtk_widget_set_size_request(a->dock_page, -1, 3000);
|
|
||||||
// ... and the cursors panel (the dock's first section, above the measurements) taller than any window
|
|
||||||
// too, which is what pushes the measurements below the viewport at offset 0 (padding the page's end only
|
|
||||||
// makes it scrollable, and on a window taller than the section's y the section would stay in view).
|
|
||||||
// Undone in the report.
|
|
||||||
if (a->cursors_panel != nullptr) gtk_widget_set_size_request(a->cursors_panel, -1, 3000);
|
|
||||||
g_timeout_add(400, dock_section_probe, a);
|
g_timeout_add(400, dock_section_probe, a);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
@@ -1892,32 +1885,21 @@ gboolean dock_section_probe(gpointer user) {
|
|||||||
if (a->measures_stats_check != nullptr) {
|
if (a->measures_stats_check != nullptr) {
|
||||||
gtk_check_button_set_active(GTK_CHECK_BUTTON(a->measures_stats_check), TRUE);
|
gtk_check_button_set_active(GTK_CHECK_BUTTON(a->measures_stats_check), TRUE);
|
||||||
}
|
}
|
||||||
GtkAdjustment* dock_adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(a->dock_scroller));
|
// On the page: the section is where the user reads the measurements in full.
|
||||||
// From the top, is the measure section (the measurements' heading) below the viewport? Only then is scrolling to it a move *into* view and back out a move *away*; a
|
slideover_open(*a, "measure");
|
||||||
// section already in view at offset 0 would make the whole probe a reading of nothing.
|
const bool was_open = slideover_page(*a) == "measure";
|
||||||
gtk_adjustment_set_value(dock_adj, 0.0);
|
|
||||||
graphene_point_t zero = GRAPHENE_POINT_INIT(0.f, 0.f);
|
|
||||||
graphene_point_t measure_at = GRAPHENE_POINT_INIT(-1.f, -1.f);
|
|
||||||
const bool located =
|
|
||||||
a->measures_head != nullptr && gtk_widget_compute_point(a->measures_head, a->dock_page, &zero, &measure_at);
|
|
||||||
const bool outside_at_top = located && static_cast<double>(measure_at.y) >= gtk_adjustment_get_page_size(dock_adj);
|
|
||||||
dock_show_section(*a, "measure"); // lands on the cursors panel, the dock's top: a no-op scroll
|
|
||||||
if (located) gtk_adjustment_set_value(dock_adj, measure_at.y); // ... so go to the measurements themselves
|
|
||||||
// Where the dock went: `scrolled` is its offset and `reach` the most it can scroll. A reach of 0 would
|
|
||||||
// mean the content fits and "away from the section" is not a state this run can reach.
|
|
||||||
const double scrolled = gtk_adjustment_get_value(dock_adj);
|
|
||||||
const double reach = gtk_adjustment_get_upper(dock_adj) - gtk_adjustment_get_page_size(dock_adj);
|
|
||||||
update_measures(*a, /*force=*/true, /*accumulate=*/true);
|
update_measures(*a, /*force=*/true, /*accumulate=*/true);
|
||||||
g_dock_section_n_before.clear();
|
g_dock_section_n_before.clear();
|
||||||
for (const MeasureStatsAccum& s : a->measure_stats) g_dock_section_n_before.push_back(s.n);
|
for (const MeasureStatsAccum& s : a->measure_stats) g_dock_section_n_before.push_back(s.n);
|
||||||
// Away from the section the measurements are in: they are scrolled out of the viewport (the widgets
|
// Away from the page: it is closed (its widgets stay in the tree, unmapped), and the tick keeps calling
|
||||||
// stay mapped, only clipped), and the tick keeps calling `update_measures()` regardless.
|
// `update_measures()` regardless.
|
||||||
gtk_adjustment_set_value(dock_adj, 0.0);
|
slideover_close(*a);
|
||||||
|
const bool hidden = slideover_page(*a).empty();
|
||||||
std::fprintf(stderr,
|
std::fprintf(stderr,
|
||||||
"[side-tab-probe] section=%s accums=%zu baseline recorded (measure at scroll %.0f of %.0f, "
|
"[side-tab-probe] section=%s accums=%zu baseline recorded (measure page was_open=%d, "
|
||||||
"outside_at_top=%d)\n",
|
"now closed=%d)\n",
|
||||||
dock_section_in_view(*a), g_dock_section_n_before.size(), scrolled, reach,
|
slideover_page(*a).empty() ? "none" : slideover_page(*a).c_str(),
|
||||||
outside_at_top ? 1 : 0);
|
g_dock_section_n_before.size(), was_open ? 1 : 0, hidden ? 1 : 0);
|
||||||
std::fflush(stderr);
|
std::fflush(stderr);
|
||||||
// Long enough for several throttled recomputes (one per 100 ms while the window moves).
|
// Long enough for several throttled recomputes (one per 100 ms while the window moves).
|
||||||
g_timeout_add(2000, dock_section_probe_report, a);
|
g_timeout_add(2000, dock_section_probe_report, a);
|
||||||
@@ -4687,7 +4669,7 @@ gboolean measures_probe_step(gpointer user) {
|
|||||||
m.options.show_on_plot = measure_can_show_on_plot(m.type);
|
m.options.show_on_plot = measure_can_show_on_plot(m.type);
|
||||||
a->measures.push_back(std::move(m));
|
a->measures.push_back(std::move(m));
|
||||||
}
|
}
|
||||||
dock_show_section(*a, "measure");
|
slideover_open(*a, "measure"); // the page the probe reads and edits
|
||||||
rebuild_measures_pane(*a);
|
rebuild_measures_pane(*a);
|
||||||
std::fprintf(stderr, "[measures-probe] added %zu measurements on '%s'\n", a->measures.size(),
|
std::fprintf(stderr, "[measures-probe] added %zu measurements on '%s'\n", a->measures.size(),
|
||||||
signal.c_str());
|
signal.c_str());
|
||||||
@@ -4849,7 +4831,7 @@ gboolean bandavg_probe_step(gpointer user) {
|
|||||||
m.options.show_on_plot = measure_can_show_on_plot(m.type);
|
m.options.show_on_plot = measure_can_show_on_plot(m.type);
|
||||||
a->measures.push_back(std::move(m));
|
a->measures.push_back(std::move(m));
|
||||||
}
|
}
|
||||||
dock_show_section(*a, "measure");
|
slideover_open(*a, "measure"); // the page the probe reads and edits
|
||||||
rebuild_measures_pane(*a);
|
rebuild_measures_pane(*a);
|
||||||
g_timeout_add(250, measure_trace, a);
|
g_timeout_add(250, measure_trace, a);
|
||||||
bandavg_probe_next(*a, 1, 1500);
|
bandavg_probe_next(*a, 1, 1500);
|
||||||
@@ -6414,16 +6396,6 @@ gboolean defaults_probe(gpointer user) {
|
|||||||
|
|
||||||
gboolean keys_probe(gpointer user) {
|
gboolean keys_probe(gpointer user) {
|
||||||
App* a = static_cast<App*>(user);
|
App* a = static_cast<App*>(user);
|
||||||
// `m` scrolls the dock, and a dock whose content fits has nothing to scroll: a run on a tall window
|
|
||||||
// would read 0->0 and prove nothing. So the first pass only makes the page taller than any window
|
|
||||||
// (a probe-only minimum height, undone below) and comes back once it has been laid out.
|
|
||||||
static bool padded = false;
|
|
||||||
if (!padded && a->dock_page != nullptr) {
|
|
||||||
padded = true;
|
|
||||||
gtk_widget_set_size_request(a->dock_page, -1, 3000);
|
|
||||||
g_timeout_add(400, keys_probe, a);
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
|
||||||
std::string line = "[keys]";
|
std::string line = "[keys]";
|
||||||
|
|
||||||
const auto before_after = [&](const char* name, GtkWidget* button, AppAction action) {
|
const auto before_after = [&](const char* name, GtkWidget* button, AppAction action) {
|
||||||
@@ -6459,39 +6431,23 @@ gboolean keys_probe(gpointer user) {
|
|||||||
|
|
||||||
before_after("t: trigger panel", a->trigger_toggle, AppAction::TriggerPanel);
|
before_after("t: trigger panel", a->trigger_toggle, AppAction::TriggerPanel);
|
||||||
before_after("c: cursors", a->cursors_toggle, AppAction::CursorsPane);
|
before_after("c: cursors", a->cursors_toggle, AppAction::CursorsPane);
|
||||||
// `m` and `g` scroll the dock: the reading is the scroller's offset before and after, and `m` must land
|
// `m` and `g` open a slide-over page: `m` the measurements, `g` the signal list, and a second press of
|
||||||
// on the cursors panel's own y (clamped to what the page can scroll, which is why the reachable maximum
|
// either closes it again. The dock does not move (it holds only the readouts).
|
||||||
// is printed beside it), `g` back on 0.
|
|
||||||
const auto dock_adjustment = [a]() {
|
const auto dock_adjustment = [a]() {
|
||||||
return gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(a->dock_scroller));
|
return gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(a->dock_scroller));
|
||||||
};
|
};
|
||||||
const auto dock_value = [&]() { return gtk_adjustment_get_value(dock_adjustment()); };
|
const auto dock_value = [&]() { return gtk_adjustment_get_value(dock_adjustment()); };
|
||||||
{
|
for (const auto& [key, action, page] :
|
||||||
|
{std::tuple<const char*, AppAction, const char*>{"m", AppAction::ShowMeasure, "measure"},
|
||||||
|
{"g", AppAction::ShowSignals, "signals"}}) {
|
||||||
const double before = dock_value();
|
const double before = dock_value();
|
||||||
run_app_action(*a, AppAction::ShowMeasure);
|
run_app_action(*a, action);
|
||||||
|
const bool opened = slideover_page(*a) == page;
|
||||||
const double after = dock_value();
|
const double after = dock_value();
|
||||||
graphene_point_t zero = GRAPHENE_POINT_INIT(0.f, 0.f);
|
run_app_action(*a, action);
|
||||||
graphene_point_t at = GRAPHENE_POINT_INIT(-1.f, -1.f);
|
|
||||||
if (!gtk_widget_compute_point(a->cursors_panel, a->dock_page, &zero, &at)) at.y = -1.f;
|
|
||||||
GtkAdjustment* adj = dock_adjustment();
|
|
||||||
const double reach = gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj);
|
|
||||||
char buf[160];
|
|
||||||
std::snprintf(buf, sizeof(buf), " m: dock %.0f->%.0f (cursors_y=%.0f reach=%.0f at_cursors=%d) |", before,
|
|
||||||
after, static_cast<double>(at.y), reach,
|
|
||||||
std::fabs(after - std::min(static_cast<double>(at.y), reach)) < 1.0 ? 1 : 0);
|
|
||||||
line += buf;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// `g` is the signal list's slide-over page now: it opens it, the dock does not move, and a second `g`
|
|
||||||
// closes it again.
|
|
||||||
const double before = dock_value();
|
|
||||||
run_app_action(*a, AppAction::ShowSignals);
|
|
||||||
const bool opened = slideover_page(*a) == "signals";
|
|
||||||
const double after = dock_value();
|
|
||||||
run_app_action(*a, AppAction::ShowSignals);
|
|
||||||
const bool closed = slideover_page(*a).empty();
|
const bool closed = slideover_page(*a).empty();
|
||||||
char buf[96];
|
char buf[96];
|
||||||
std::snprintf(buf, sizeof(buf), " g: page=%d dock_still=%d closed=%d |", opened ? 1 : 0,
|
std::snprintf(buf, sizeof(buf), " %s: page=%d dock_still=%d closed=%d |", key, opened ? 1 : 0,
|
||||||
std::fabs(after - before) < 1.0 ? 1 : 0, closed ? 1 : 0);
|
std::fabs(after - before) < 1.0 ? 1 : 0, closed ? 1 : 0);
|
||||||
line += buf;
|
line += buf;
|
||||||
}
|
}
|
||||||
@@ -6512,21 +6468,17 @@ gboolean keys_probe(gpointer user) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// An accel must be refused while text is being typed. Focus the window entry, send 'm'
|
// An accel must be refused while text is being typed. Focus the window entry, send 'm'
|
||||||
// through the real handler, and require the dock not to scroll.
|
// through the real handler, and require no page to open.
|
||||||
int refused = -1;
|
int refused = -1;
|
||||||
if (a->window_entry != nullptr) {
|
if (a->window_entry != nullptr) {
|
||||||
gtk_menu_button_popup(GTK_MENU_BUTTON(a->window_button));
|
gtk_menu_button_popup(GTK_MENU_BUTTON(a->window_button));
|
||||||
gtk_widget_grab_focus(a->window_entry);
|
gtk_widget_grab_focus(a->window_entry);
|
||||||
// The dock has to be somewhere other than where `m` would take it, or "did not scroll" proves nothing.
|
const std::string page_before = slideover_page(*a);
|
||||||
gtk_adjustment_set_value(dock_adjustment(), 0.0);
|
|
||||||
const double before_dock = dock_value();
|
|
||||||
const gboolean handled = on_app_key_pressed(nullptr, GDK_KEY_m, 0,
|
const gboolean handled = on_app_key_pressed(nullptr, GDK_KEY_m, 0,
|
||||||
static_cast<GdkModifierType>(0), a);
|
static_cast<GdkModifierType>(0), a);
|
||||||
const double after_dock = dock_value();
|
refused = (handled == FALSE && slideover_page(*a) == page_before) ? 1 : 0;
|
||||||
refused = (handled == FALSE && before_dock == after_dock) ? 1 : 0;
|
|
||||||
gtk_menu_button_popdown(GTK_MENU_BUTTON(a->window_button));
|
gtk_menu_button_popdown(GTK_MENU_BUTTON(a->window_button));
|
||||||
}
|
}
|
||||||
if (a->dock_page != nullptr) gtk_widget_set_size_request(a->dock_page, -1, -1);
|
|
||||||
char tail[64];
|
char tail[64];
|
||||||
std::snprintf(tail, sizeof(tail), " editable focused: 'm' refused=%d\n", refused);
|
std::snprintf(tail, sizeof(tail), " editable focused: 'm' refused=%d\n", refused);
|
||||||
line += tail;
|
line += tail;
|
||||||
|
|||||||
Reference in new issue
Block a user