ui: one way to open the events page, and stale wording after the pane's removal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
8c866300d8
commit
794df9b4d0
5 files changed
+40
-30
No files matched your search
+2
-3
@@ -4187,7 +4187,7 @@ gboolean tick(gpointer user) {
|
||||
next_channels = now_c + G_TIME_SPAN_SECOND;
|
||||
app->last_channels_meas = now_c;
|
||||
// The cache's own question, on the same cadence as the channel dump: a directory read per second,
|
||||
// and the button's availability re-decided only when the answer changed.
|
||||
// and the dock block's and the events page's availability re-decided only when the answer changed.
|
||||
if (app->event_store != nullptr) {
|
||||
const bool cached = !app->event_store->list().empty();
|
||||
if (cached != app->events_cached) {
|
||||
@@ -5708,8 +5708,7 @@ void report_events_availability(App& a, const char* what) {
|
||||
}
|
||||
|
||||
|
||||
/// Walks the whole event-cache loop the way a user does: trigger mode on (the real toggle, which is
|
||||
/// what reveals the pane), a latch recorded automatically, the cache listed, the newest event
|
||||
/// Walks the whole event-cache loop the way a user does: trigger mode on (the real toggle), a latch recorded automatically, the cache listed, the newest event
|
||||
/// replayed through the loader `--open` uses, and *Live* taken back. What it reports is what each
|
||||
/// step must be able to do -- a cache nothing can replay is a directory of files, and a replay with
|
||||
/// no way back is a one-way door.
|
||||
|
||||
@@ -1945,6 +1945,12 @@ GdkTexture* scale_texture(GdkTexture* source, int width, int height);
|
||||
EventThumbCache* event_thumb_cache(App& app);
|
||||
GdkTexture* event_preview_texture(App& app, const std::string& path);
|
||||
void refresh_events_pane(App& app);
|
||||
/// Opens the `events` page. **Every route that opens that page must use this** and never `slideover_open()`
|
||||
/// directly: the page's list is rebuilt only while the page is open (see `record_event()`), and the
|
||||
/// slide-over has no on-open hook, so the list is refreshed here, once, before the page shows. The refresh
|
||||
/// is skipped when the page is already open -- it is current then, and a rebuild would drop the
|
||||
/// Compare/Accumulate selection and the scroll position. Returns what `slideover_open()` returns.
|
||||
bool open_events_page(App& app);
|
||||
/// Re-marks which row is the event currently on screen, **without rebuilding the list**.
|
||||
///
|
||||
/// The mark is the only thing about a row that a replay changes -- the picture and the numbers
|
||||
|
||||
+3
-6
@@ -249,13 +249,10 @@ const char* dock_event_marker(const App& app, const EventRecord& r) {
|
||||
return " ";
|
||||
}
|
||||
|
||||
/// Opens the `events` page. The page's list is rebuilt only while the page is open (see `record_event()`),
|
||||
/// so it is refreshed here, once, before the page shows: the slide-over has no on-open hook, and the list
|
||||
/// is small. The button is not a child of either list, so the rebuild cannot free the widget it runs from.
|
||||
/// Opens the `events` page through `open_events_page()` (which refreshes the list only if it is not
|
||||
/// already open). The button is not a child of either list, so the rebuild cannot free the widget it runs from.
|
||||
void on_manage_events(GtkButton*, gpointer user) {
|
||||
App& app = *static_cast<App*>(user);
|
||||
refresh_events_pane(app);
|
||||
slideover_open(app, "events");
|
||||
open_events_page(*static_cast<App*>(user));
|
||||
}
|
||||
|
||||
/// One click on a row replays it, as the page list's activation does: `replay_event()` and then the in-place
|
||||
|
||||
+19
-12
@@ -622,7 +622,7 @@ EventThumbCache* event_thumb_cache(App& app) {
|
||||
// Created on first use and owned by the list. Nothing used to create it, and a missing cache is
|
||||
// not a slow path here but a *blank* one: `event_preview_texture()` answers from the cache or not
|
||||
// at all, so every row came up without a picture -- which is what the previews were reported for.
|
||||
// Owned by the list because nothing else has the pane's lifetime: textures of a list that no
|
||||
// Owned by the list because nothing else has the events page's lifetime: textures of a list that no
|
||||
// longer exists are so much held memory.
|
||||
cache = new EventThumbCache();
|
||||
g_object_set_data_full(G_OBJECT(app.events_list), "udpscope-event-thumbs", cache,
|
||||
@@ -707,7 +707,7 @@ GdkTexture* event_preview_texture(App& app, const std::string& path) {
|
||||
///
|
||||
/// Through GTK's own tooltip rather than a popover of ours, for lifetime: a tooltip is shown, placed,
|
||||
/// dismissed and destroyed by GTK, and it takes no pointer grab -- a popover per row would be a
|
||||
/// parented widget to unparent on every rebuild of the pane, and a grab to lose (see the GTK
|
||||
/// parented widget to unparent on every rebuild of the page, and a grab to lose (see the GTK
|
||||
/// invariants on both). The texture is decoded in the handler and dropped with the tooltip's picture,
|
||||
/// so a hover costs nothing once it is over and the row cache keeps holding only the small one.
|
||||
gboolean on_preview_query_tooltip(GtkWidget*, int, int, gboolean, GtkTooltip* tooltip, gpointer user) {
|
||||
@@ -842,7 +842,7 @@ static void rebuild_events_pane_list(App& app, std::vector<EventRecord>& records
|
||||
// to grow and the text keeps the rest of the width.
|
||||
gtk_widget_set_size_request(frame, kEventThumbW, kEventThumbH);
|
||||
// `halign` START, not the default FILL: a filling widget is given whatever the row has left over,
|
||||
// which made the picture as wide as the pane and cropped by the height it was pinned to.
|
||||
// which made the picture as wide as the page and cropped by the height it was pinned to.
|
||||
gtk_widget_set_halign(frame, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign(frame, GTK_ALIGN_CENTER);
|
||||
gtk_widget_add_css_class(frame, "udpscope-event-thumb");
|
||||
@@ -870,7 +870,7 @@ static void rebuild_events_pane_list(App& app, std::vector<EventRecord>& records
|
||||
++unreadable;
|
||||
}
|
||||
gtk_box_append(GTK_BOX(line), frame);
|
||||
// The newest event is the first row: what the probe measures, and nothing the pane treats
|
||||
// The newest event is the first row: what the probe measures, and nothing the page treats
|
||||
// specially.
|
||||
if (app.events_thumb == nullptr) app.events_thumb = shot;
|
||||
|
||||
@@ -926,10 +926,11 @@ static void rebuild_events_pane_list(App& app, std::vector<EventRecord>& records
|
||||
}
|
||||
}
|
||||
|
||||
/// Both views of the cache, rebuilt from the same list: the pane's rows (with their pictures) and the
|
||||
/// dock's compact ones. The dock follows even when the pane's list does not exist.
|
||||
/// Both views of the cache, rebuilt from the same list: the events page's rows (with their pictures) and the
|
||||
/// dock block's compact ones. The dock follows even when the page's list does not exist. To *open* the page
|
||||
/// use `open_events_page()`, which calls this only when the page is not already open.
|
||||
void refresh_events_pane(App& app) {
|
||||
// One read of the cache directory for both views (none without a store, which the pane's rebuild
|
||||
// One read of the cache directory for both views (none without a store, which the page's rebuild
|
||||
// and the dock's both treat as nothing to list).
|
||||
std::vector<EventRecord> records;
|
||||
if (app.event_store != nullptr) records = app.event_store->list();
|
||||
@@ -937,9 +938,14 @@ void refresh_events_pane(App& app) {
|
||||
if (app.event_store != nullptr) dock_rebuild_events(app, records);
|
||||
}
|
||||
|
||||
bool open_events_page(App& app) {
|
||||
if (slideover_page(app) != "events") refresh_events_pane(app);
|
||||
return slideover_open(app, "events");
|
||||
}
|
||||
|
||||
/// Clicking a row replays it: the same loader `--open` uses, on the event's file. The acquisition is
|
||||
/// stopped by `replay_event()` -- a live producer would overwrite the samples within a frame -- so the
|
||||
/// pane's own *Live* button is the way back.
|
||||
/// page's own *Live* button is the way back.
|
||||
void on_event_row_activated(GtkListBox*, GtkListBoxRow* row, gpointer user) {
|
||||
App& app = *static_cast<App*>(user);
|
||||
if (row == nullptr) return;
|
||||
@@ -976,7 +982,7 @@ GtkWidget* build_events_pane(App& app) {
|
||||
return app.events_box != nullptr ? app.events_box : gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
}
|
||||
|
||||
// What the pane *does*, which a file cannot hold: the two group actions read the selection, the list
|
||||
// What the page *does*, which a file cannot hold: the two group actions read the selection, the list
|
||||
// replays an event on a double click, and the header's button goes back to the live stream.
|
||||
g_signal_connect(app.events_compare, "clicked", G_CALLBACK(on_group_clicked), &app);
|
||||
g_signal_connect(app.events_accumulate, "clicked", G_CALLBACK(on_group_clicked), &app);
|
||||
@@ -993,9 +999,10 @@ GtkWidget* build_events_pane(App& app) {
|
||||
return app.events_box;
|
||||
}
|
||||
|
||||
/// The recording switch, which lives here because it is a trigger option and not a pane option: it
|
||||
/// decides whether latches are written at all, and the pane that lists them must not be the only
|
||||
/// place to reach the control that stops them. Flipping it re-decides the pane's availability.
|
||||
/// The recording switch, which lives here because it is a trigger option and not an events-page option: it
|
||||
/// decides whether latches are written at all, and the page that lists them must not be the only
|
||||
/// place to reach the control that stops them. Flipping it re-decides the availability of the dock's
|
||||
/// Events block and of the page.
|
||||
void on_events_record_toggled(GObject* o, GParamSpec*, gpointer user) {
|
||||
App& app = *static_cast<App*>(user);
|
||||
app.event_recording = gtk_switch_get_active(GTK_SWITCH(o));
|
||||
|
||||
+10
-9
@@ -5674,7 +5674,7 @@ gboolean events_probe_step(gpointer user) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a->trigger_toggle), TRUE);
|
||||
}
|
||||
report_events_availability(*a, "after trigger on");
|
||||
slideover_open(*a, "events");
|
||||
open_events_page(*a);
|
||||
// Read straight after the open, before anything else can call the availability rule.
|
||||
report_events_availability(*a, "after events page opened");
|
||||
// ... and again a few frames later, still with no replay in the way: this is the *open alone*
|
||||
@@ -5747,11 +5747,15 @@ gboolean events_probe_step(gpointer user) {
|
||||
r.stem.c_str(), r.duration_s, r.pre_s, r.post_s, r.edge, r.signals, r.samples,
|
||||
r.rate_hz, static_cast<unsigned long long>(r.seq), thumb_bytes,
|
||||
a->event_recording ? 1 : 0, slideover_page(*a) == "events" ? 1 : 0);
|
||||
// The first latch must not have moved the plot: the list is a slide-over page over the plot's
|
||||
// edge, and the dock is a fixed column, so nothing about an event changes the plot's width.
|
||||
}
|
||||
// The first latch must not have moved the plot: the list is a slide-over page over the plot's
|
||||
// edge, and the dock is a fixed column, so nothing about an event changes the plot's width. Both
|
||||
// widths must be real (> 0): two unrealised -1s are equal and would read as stable.
|
||||
{
|
||||
const int plot_w_now = a->area_widget != nullptr ? gtk_widget_get_width(a->area_widget) : -1;
|
||||
std::fprintf(stderr, " plot_w_stable=%d plot_w=%d/%d", plot_w_now == a->dbg_events_plot_w ? 1 : 0,
|
||||
a->dbg_events_plot_w, plot_w_now);
|
||||
std::fprintf(stderr, " plot_w_stable=%d plot_w=%d/%d",
|
||||
(plot_w_now > 0 && plot_w_now == a->dbg_events_plot_w) ? 1 : 0, a->dbg_events_plot_w,
|
||||
plot_w_now);
|
||||
}
|
||||
std::fprintf(stderr, "\n");
|
||||
std::fflush(stderr);
|
||||
@@ -5898,10 +5902,7 @@ gboolean events_group_probe_step(gpointer user) {
|
||||
a->dbg_events_wait = 0;
|
||||
// Open the page first: its list is only rebuilt while the page is *open* (or by the Manage button), so
|
||||
// a selection made against a closed page selects rows that are not current.
|
||||
if (slideover_page(*a) != "events") {
|
||||
refresh_events_pane(*a);
|
||||
slideover_open(*a, "events");
|
||||
}
|
||||
open_events_page(*a);
|
||||
// The selection *is* the input, so select the two newest rows the way a user does and press the
|
||||
// button: `on_group_clicked()` reads the list, not a parameter.
|
||||
GtkListBox* list = GTK_LIST_BOX(a->events_list);
|
||||
|
||||
Reference in new issue
Block a user