udpscope: an oscilloscope view for a UDPStreamer source

GTK4 and libadwaita. It receives one UDP stream through the vendored
udpsclient, buffers it in a large ring, and draws it with the vendored
plotter: a trigger with a pre/post event window, a pause that freezes the
window, cursors, measurements, math channels in a node editor, an event cache,
named configurations, preferences, and an export of the visible window to
.npy/.csv. Waveform files can be opened and analysed in place.

The interface is two threads -- a producer that owns the socket and the GTK
main thread that owns every widget and the GL context -- sharing one model
under one mutex, with samples crossing through lock-free rings.

deps/plotter is a submodule pinned to the commit this tree builds against;
deps/udpsclient is vendored in place. docs/claude/ documents the rules that
cost a defect to learn, and SPECS.md is the requirement document.
This commit is contained in:
Martino Ferrari committed 2026-10-11 15:21:40 +02:00
1 parent 8f54841c2c
commit 0e256764d5
41 files changed
+2081 -154

No files matched your search

+6 -3
View File
@@ -38,9 +38,11 @@ constexpr int kAccelCount = static_cast<int>(sizeof(kAccels) / sizeof(kAccels[0]
/// wheel's: '+' is shift+'=' on common layouts, so Shift could not mean anything there.
///
/// A space-separated accelerator is the two-key alternative form the shortcut label draws
/// as `+ / -`. The mouse rows carry no accelerator at all: neither GTK's accelerator
/// syntax nor libadwaita's knows a wheel or a drag, and asking either to parse "Wheel"
/// is a parse warning and an empty cell. Those rows are prose in the subtitle instead.
/// as `+ / -`. The mouse rows carry no accelerator at all: neither GTK's accelerator syntax nor
/// libadwaita's knows a wheel or a drag, and asking either to parse "Wheel" is a parse warning and an
/// empty cell. The overview draws them from `src/ui/shortcuts.ui`, which gives each one GTK's generic
/// gesture type and an icon where the keycaps would be. That file is the *presentation*; this table is
/// what the application handles, which is why `[help]`'s `ui=` is checked against `tables=`.
constexpr Gesture kGestures[] = {
{"plus minus", "", "Zoom in or out, both axes", "Plot keyboard"},
{"<Control>plus <Control>minus", "", "Zoom the time axis only", "Plot keyboard"},
@@ -55,6 +57,7 @@ constexpr Gesture kGestures[] = {
{"", "Drag", "Pan", "Plot mouse"},
{"", "Ctrl and drag", "Box zoom on time", "Plot mouse"},
{"", "Alt and drag", "Box zoom on values", "Plot mouse"},
{"", "Shift and drag", "Box zoom on time and values", "Plot mouse"},
};
constexpr int kGestureCount = static_cast<int>(sizeof(kGestures) / sizeof(kGestures[0]));