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:
1 parent
8f54841c2c
commit
0e256764d5
41 files changed
+2081
-154
No files matched your search
@@ -0,0 +1,333 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- SPDX-License-Identifier: MIT -->
|
||||
<!-- SPDX-FileCopyrightText: 2026 Martino Ferrari -->
|
||||
<!--
|
||||
The shortcut overview, as a UI file instead of a couple of hundred lines of widget construction, and
|
||||
in gedit's arrangement: one GtkShortcutsWindow holding a section per page (the window draws the
|
||||
sidebar and the search box over them), each section holding a group, each group holding rows.
|
||||
|
||||
The mouse rows are the reason this file exists. An accelerator cannot spell "Ctrl and drag", and
|
||||
libadwaita's AdwShortcutsItem, the modern replacement for this widget, has no icon property at all,
|
||||
so its cell reads "No Shortcut". GtkShortcutsShortcut has exactly one gesture type whose *icon* is
|
||||
drawn (shortcut-type "gesture" plus the icon property, per its own documentation), and that is what
|
||||
puts the mouse glyph where the keycaps would otherwise be.
|
||||
|
||||
Keep this file in step with the tables in shortcuts.cpp: those are what the application handles,
|
||||
this is what it shows. The `[help]` probe's `ui=` against `tables=` is the guard against the two
|
||||
drifting apart.
|
||||
-->
|
||||
<interface>
|
||||
<object class="GtkShortcutsWindow" id="help_overlay">
|
||||
<property name="modal">1</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsSection">
|
||||
<property name="visible">1</property>
|
||||
<property name="section-name">Acquisition</property>
|
||||
<property name="title" translatable="yes">Acquisition</property>
|
||||
<property name="max-height">12</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsGroup">
|
||||
<property name="visible">1</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">space</property>
|
||||
<property name="title" translatable="yes">Pause or resume the display</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">a</property>
|
||||
<property name="title" translatable="yes">Arm or disarm the trigger</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">t</property>
|
||||
<property name="title" translatable="yes">Show or hide the trigger panel</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsSection">
|
||||
<property name="visible">1</property>
|
||||
<property name="section-name">Panes and editors</property>
|
||||
<property name="title" translatable="yes">Panes and editors</property>
|
||||
<property name="max-height">12</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsGroup">
|
||||
<property name="visible">1</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">c</property>
|
||||
<property name="title" translatable="yes">Show or hide the cursors pane</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">m</property>
|
||||
<property name="title" translatable="yes">Show or hide the measurements pane</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">g</property>
|
||||
<property name="title" translatable="yes">Show or hide the math pane</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">l</property>
|
||||
<property name="title" translatable="yes">Show or hide the layout editor</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">s</property>
|
||||
<property name="title" translatable="yes">Show or hide the side panel</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsSection">
|
||||
<property name="visible">1</property>
|
||||
<property name="section-name">Files and windows</property>
|
||||
<property name="title" translatable="yes">Files and windows</property>
|
||||
<property name="max-height">12</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsGroup">
|
||||
<property name="visible">1</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator"><Control>e</property>
|
||||
<property name="title" translatable="yes">Export the visible range</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">F1</property>
|
||||
<property name="title" translatable="yes">Open the help window</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator"><Control>slash</property>
|
||||
<property name="title" translatable="yes">Open this shortcut overview</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator"><Control>q</property>
|
||||
<property name="title" translatable="yes">Quit udpscope</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsSection">
|
||||
<property name="visible">1</property>
|
||||
<property name="section-name">Plot keyboard</property>
|
||||
<property name="title" translatable="yes">Plot keyboard</property>
|
||||
<property name="max-height">12</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsGroup">
|
||||
<property name="visible">1</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">plus minus</property>
|
||||
<property name="title" translatable="yes">Zoom in or out, both axes</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator"><Control>plus <Control>minus</property>
|
||||
<property name="title" translatable="yes">Zoom the time axis only</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator"><Alt>plus <Alt>minus</property>
|
||||
<property name="title" translatable="yes">Zoom the value axis only</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">Left Right</property>
|
||||
<property name="title" translatable="yes">Pan along time</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">Up Down</property>
|
||||
<property name="title" translatable="yes">Pan along values</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">f</property>
|
||||
<property name="title" translatable="yes">Fit the view to the data</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="accelerator">Escape</property>
|
||||
<property name="title" translatable="yes">Cancel the gesture in progress</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsSection">
|
||||
<property name="visible">1</property>
|
||||
<property name="section-name">Plot mouse</property>
|
||||
<property name="title" translatable="yes">Plot mouse</property>
|
||||
<property name="max-height">12</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsGroup">
|
||||
<property name="visible">1</property>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="shortcut-type">gesture</property>
|
||||
<!-- A GIcon property takes an object, not a name: GtkBuilder reads a bare string as a
|
||||
reference to another object and fails the whole file with "Object with ID … not
|
||||
found" (a Gtk-ERROR, which aborts the process by default). -->
|
||||
<property name="icon">
|
||||
<object class="GThemedIcon">
|
||||
<property name="names">input-mouse-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="title" translatable="yes">Zoom about the pointer, both axes</property>
|
||||
<property name="subtitle" translatable="yes">Wheel</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="shortcut-type">gesture</property>
|
||||
<!-- A GIcon property takes an object, not a name: GtkBuilder reads a bare string as a
|
||||
reference to another object and fails the whole file with "Object with ID … not
|
||||
found" (a Gtk-ERROR, which aborts the process by default). -->
|
||||
<property name="icon">
|
||||
<object class="GThemedIcon">
|
||||
<property name="names">input-mouse-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="title" translatable="yes">Zoom the time axis only</property>
|
||||
<property name="subtitle" translatable="yes">Shift and wheel</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="shortcut-type">gesture</property>
|
||||
<!-- A GIcon property takes an object, not a name: GtkBuilder reads a bare string as a
|
||||
reference to another object and fails the whole file with "Object with ID … not
|
||||
found" (a Gtk-ERROR, which aborts the process by default). -->
|
||||
<property name="icon">
|
||||
<object class="GThemedIcon">
|
||||
<property name="names">input-mouse-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="title" translatable="yes">Zoom the value axis only</property>
|
||||
<property name="subtitle" translatable="yes">Ctrl and wheel</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="shortcut-type">gesture</property>
|
||||
<!-- A GIcon property takes an object, not a name: GtkBuilder reads a bare string as a
|
||||
reference to another object and fails the whole file with "Object with ID … not
|
||||
found" (a Gtk-ERROR, which aborts the process by default). -->
|
||||
<property name="icon">
|
||||
<object class="GThemedIcon">
|
||||
<property name="names">input-mouse-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="title" translatable="yes">Pan</property>
|
||||
<property name="subtitle" translatable="yes">Drag</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="shortcut-type">gesture</property>
|
||||
<!-- A GIcon property takes an object, not a name: GtkBuilder reads a bare string as a
|
||||
reference to another object and fails the whole file with "Object with ID … not
|
||||
found" (a Gtk-ERROR, which aborts the process by default). -->
|
||||
<property name="icon">
|
||||
<object class="GThemedIcon">
|
||||
<property name="names">input-mouse-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="title" translatable="yes">Box zoom on time</property>
|
||||
<property name="subtitle" translatable="yes">Ctrl and drag</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="shortcut-type">gesture</property>
|
||||
<!-- A GIcon property takes an object, not a name: GtkBuilder reads a bare string as a
|
||||
reference to another object and fails the whole file with "Object with ID … not
|
||||
found" (a Gtk-ERROR, which aborts the process by default). -->
|
||||
<property name="icon">
|
||||
<object class="GThemedIcon">
|
||||
<property name="names">input-mouse-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="title" translatable="yes">Box zoom on values</property>
|
||||
<property name="subtitle" translatable="yes">Alt and drag</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">1</property>
|
||||
<property name="shortcut-type">gesture</property>
|
||||
<!-- A GIcon property takes an object, not a name: GtkBuilder reads a bare string as a
|
||||
reference to another object and fails the whole file with "Object with ID … not
|
||||
found" (a Gtk-ERROR, which aborts the process by default). -->
|
||||
<property name="icon">
|
||||
<object class="GThemedIcon">
|
||||
<property name="names">input-mouse-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="title" translatable="yes">Box zoom on time and values</property>
|
||||
<property name="subtitle" translatable="yes">Shift and drag</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- SPDX-License-Identifier: MIT -->
|
||||
<!-- SPDX-FileCopyrightText: 2026 Martino Ferrari -->
|
||||
<!--
|
||||
The application's UI files, compiled into the binary beside the icons and the help pages, so there
|
||||
is still exactly one file to run. `preprocess="xml-stripblanks"` is what catches a malformed file:
|
||||
gtk_builder_new_from_resource() on a broken .ui returns nothing usable and the window simply does
|
||||
not open, which is a silent failure at runtime and a loud one here.
|
||||
-->
|
||||
<gresources>
|
||||
<gresource prefix="/org/udpscope/ui">
|
||||
<file preprocess="xml-stripblanks">shortcuts.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
Reference in new issue
Block a user