diff --git a/src/ui.cpp b/src/ui.cpp index 45fa158..d4e8532 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -7181,6 +7181,48 @@ gboolean measures_probe_step(gpointer user) { return G_SOURCE_REMOVE; } +/// Drives the plot's keyboard zoom with Ctrl and with Alt and reports which axis moved. +/// Run it inside a pinned state (the pause probe makes a stable one) so the `_held` +/// readings mean "the other axis did not move", not "the frame re-framed anyway": +/// UDPSCOPE_PROBE_PAUSE_MS=1500 UDPSCOPE_PROBE_ZOOMKEYS_MS=2200 +gboolean zoomkeys_probe(gpointer user) { + App* a = static_cast(user); + if (a->rows->row_count() == 0 || a->rows->row(0).plot == nullptr) return G_SOURCE_REMOVE; + plot::Plot& p = *a->rows->row(0).plot; + const plot::u32 ax = a->rows->row(0).axis_x; + const plot::u32 ay = a->rows->row(0).axis_y; + + plot::input::Controller* c = + a->area != nullptr ? a->area->row_controller(static_cast(0)) : nullptr; + if (c == nullptr) { + std::fprintf(stderr, "[zoomkeys] no controller for row 0\n"); + std::fflush(stderr); + return G_SOURCE_REMOVE; + } + + const plot::Range x0 = p.x_range(ax); + const plot::Range y0 = p.y_range(ay); + c->on_key({plot::input::kKeyZoomIn, + static_cast(plot::input::Mod::Ctrl), true}); + const plot::Range x1 = p.x_range(ax); + const plot::Range y1 = p.y_range(ay); + const int y_held = std::abs(y1.span() - y0.span()) < 1e-9 ? 1 : 0; + + c->on_key({plot::input::kKeyZoomIn, + static_cast(plot::input::Mod::Alt), true}); + const plot::Range x2 = p.x_range(ax); + const plot::Range y2 = p.y_range(ay); + const int x_held = std::abs(x2.span() - x1.span()) < 1e-9 ? 1 : 0; + + std::fprintf(stderr, + "[zoomkeys] ctrl+plus x=[%.4f..%.4f]->[%.4f..%.4f] y_held=%d | " + "alt+plus y=[%.4f..%.4f]->[%.4f..%.4f] x_held=%d\n", + x0.min, x0.max, x1.min, x1.max, y_held, y1.min, y1.max, y2.min, y2.max, + x_held); + std::fflush(stderr); + return G_SOURCE_REMOVE; +} + int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisition& acq, RowSet& rows) { (void)argc; @@ -7261,6 +7303,9 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit if (const char* env = g_getenv("UDPSCOPE_EXPORT_MS")) { g_timeout_add(static_cast(std::atoi(env)), export_probe, &app); } + if (const char* env = g_getenv("UDPSCOPE_PROBE_ZOOMKEYS_MS")) { + g_timeout_add(static_cast(std::atoi(env)), zoomkeys_probe, &app); + } // Our own options were consumed by parse_args(); GTK would reject them, so only // the program name is handed to g_application_run().