refactor: build the shortcut overview from AdwShortcutsDialog
The hand-rolled grid existed to avoid GTK's deprecated GtkShortcutsWindow; libadwaita 1.8's AdwShortcutsDialog is the supported replacement, so use the platform widget and get its search, sectioning and shortcut labels for free. The table strings become GTK accelerator syntax, since the shortcut label parses them. The six mouse rows cannot: no accelerator syntax names a wheel or a drag, so they carry an empty accelerator and prose in the new subtitle field. adw_init() is called in run_ui() and in choose_source() (replacing its gtk_init()), which means the whole app is drawn with libadwaita's stylesheet. Verified settled: viewport.w 870..870, axes.w changes 2, x-desync 0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
018b98eddf
commit
d65a121a9a
7 files changed
+123
-92
No files matched your search
@@ -24,6 +24,18 @@ form for a new host. Every probe below passes `--server`, so none of them sees i
|
|||||||
(`PLOT_BUILD_GTK4`); its tests and examples are forced off. `deps/udpsclient` is a
|
(`PLOT_BUILD_GTK4`); its tests and examples are forced off. `deps/udpsclient` is a
|
||||||
vendored C99 source pair compiled into a static lib.
|
vendored C99 source pair compiled into a static lib.
|
||||||
|
|
||||||
|
**libadwaita ≥ 1.8 is a system dependency** (`pkg_check_modules(ADWAITA ... libadwaita-1>=1.8)`),
|
||||||
|
for exactly one widget: the shortcut overview is an `AdwShortcutsDialog`. GTK4's own
|
||||||
|
`GtkShortcutsWindow` is deprecated as of 4.18 and that is its replacement. Two consequences
|
||||||
|
worth knowing before editing. `adw_init()` is called — in `run_ui()` and, since the chooser
|
||||||
|
runs first and must be styled the same, in `choose_source()` in place of its `gtk_init()`
|
||||||
|
(both are idempotent) — so **the whole app is drawn with libadwaita's stylesheet**, not
|
||||||
|
GTK's: a metric change there reaches every widget, and `layout over N frames` /
|
||||||
|
`axes.w changes` is what says whether the layout still settles. And an `AdwDialog` is
|
||||||
|
**not** a `GtkWindow`: `show_shortcuts()` keeps an `AdwDialog*`, clears it on `::closed`
|
||||||
|
(there is no `::close-request`) and closes it with `adw_dialog_close()`. Presenting it on
|
||||||
|
this app's plain `GtkApplicationWindow` is supported and warning-free; it was checked.
|
||||||
|
|
||||||
`deps/plotter` is upstream's own repository and this app's figure support was added
|
`deps/plotter` is upstream's own repository and this app's figure support was added
|
||||||
there rather than worked around here: `Figure::set_min_y_gutter()` (a floor under the
|
there rather than worked around here: `Figure::set_min_y_gutter()` (a floor under the
|
||||||
common left gutter), and in the GTK4 adapter `PlotArea`'s **figure mode** —
|
common left gutter), and in the GTK4 adapter `PlotArea`'s **figure mode** —
|
||||||
@@ -1253,6 +1265,16 @@ far the largest file.
|
|||||||
`gtk_icon_theme_has_icon()` is checked for every toolbar button and reported by the dump (see
|
`gtk_icon_theme_has_icon()` is checked for every toolbar button and reported by the dump (see
|
||||||
`toolbar icons:` under Verification): a resource path that was never added does not raise an
|
`toolbar icons:` under Verification): a resource path that was never added does not raise an
|
||||||
error, it draws `image-missing`.
|
error, it draws `image-missing`.
|
||||||
|
- **A shortcut table row's `accel` is GTK accelerator syntax, and a pointer gesture has
|
||||||
|
none.** `src/shortcuts.cpp`'s strings are handed to `AdwShortcutsItem`, which parses them
|
||||||
|
with `gtk_accelerator_parse()` — so they are `"space"`, `"<Control>e"`, `"<Control>slash"`,
|
||||||
|
`"plus minus"` (a space-separated pair is the "either of these" form the label draws as
|
||||||
|
`+ / -`), never the prose `"Ctrl+E"` or `"+ / -"`. Neither GTK's syntax nor libadwaita's
|
||||||
|
knows a **wheel or a drag**: `"Wheel"` costs a `Failed to parse` warning and draws an empty
|
||||||
|
cell. Those six rows therefore carry `accel = ""` and put the prose in `subtitle`, which is
|
||||||
|
the one field that is free text. A row added with a parse error is otherwise silent — the
|
||||||
|
overview still opens and the row is simply blank — so read the probe run's stderr for
|
||||||
|
`Failed to parse` after touching either table.
|
||||||
- **The chooser runs before `ScopeModel` exists, and `--server` is what decides.** `Config` carries
|
- **The chooser runs before `ScopeModel` exists, and `--server` is what decides.** `Config` carries
|
||||||
`server_specified`, set only by the `--server` branch, and `main()` asks only when it is false —
|
`server_specified`, set only by the `--server` branch, and `main()` asks only when it is false —
|
||||||
so declining costs no buffer and no socket, and `ScopeModel`, `Acquisition`, `RowSet` and
|
so declining costs no buffer and no socket, and `ScopeModel`, `Acquisition`, `RowSet` and
|
||||||
|
|||||||
+11
-1
@@ -12,6 +12,15 @@ endif()
|
|||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
# --- libadwaita: the shortcut overview ---------------------------------------
|
||||||
|
# GTK4's own `GtkShortcutsWindow` is deprecated as of 4.18 and libadwaita's
|
||||||
|
# `AdwShortcutsDialog` (1.8) is its replacement, so the overview is built from the
|
||||||
|
# platform widget rather than from a hand-rolled grid. This is the only thing libadwaita
|
||||||
|
# is used for; `adw_init()` is called for it, which also means the app picks up
|
||||||
|
# libadwaita's stylesheet.
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(ADWAITA REQUIRED IMPORTED_TARGET libadwaita-1>=1.8)
|
||||||
|
|
||||||
# --- deps/plotter: built from the submodule, GTK4 adapter only ----------------
|
# --- deps/plotter: built from the submodule, GTK4 adapter only ----------------
|
||||||
set(PLOT_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
set(PLOT_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
set(PLOT_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
set(PLOT_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
@@ -109,7 +118,8 @@ add_executable(udpscope
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(udpscope PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
target_include_directories(udpscope PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
target_link_libraries(udpscope PRIVATE plot::gtk4 udpsclient Threads::Threads)
|
target_link_libraries(udpscope PRIVATE plot::gtk4 udpsclient Threads::Threads
|
||||||
|
PkgConfig::ADWAITA)
|
||||||
add_dependencies(udpscope udpscope_build_info)
|
add_dependencies(udpscope udpscope_build_info)
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||||
target_compile_options(udpscope PRIVATE -Wall -Wextra -Wpedantic)
|
target_compile_options(udpscope PRIVATE -Wall -Wextra -Wpedantic)
|
||||||
|
|||||||
+47
-62
@@ -1,6 +1,8 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
#include "help_window.hpp"
|
#include "help_window.hpp"
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -15,7 +17,10 @@ namespace {
|
|||||||
/// One pointer per window, file-scope because there is one application.
|
/// One pointer per window, file-scope because there is one application.
|
||||||
GtkWidget* g_about = nullptr;
|
GtkWidget* g_about = nullptr;
|
||||||
GtkWidget* g_help = nullptr;
|
GtkWidget* g_help = nullptr;
|
||||||
GtkWidget* g_shortcuts = nullptr;
|
|
||||||
|
/// The shortcut overview is an `AdwDialog`, not a window, so it has its own pointer and
|
||||||
|
/// its own clearing signal (`::closed` rather than `::close-request`).
|
||||||
|
AdwDialog* g_shortcuts = nullptr;
|
||||||
|
|
||||||
gboolean on_window_close(GtkWindow* window, gpointer slot) {
|
gboolean on_window_close(GtkWindow* window, gpointer slot) {
|
||||||
(void)window;
|
(void)window;
|
||||||
@@ -23,6 +28,12 @@ gboolean on_window_close(GtkWindow* window, gpointer slot) {
|
|||||||
return FALSE; // let the default handler destroy it
|
return FALSE; // let the default handler destroy it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void on_shortcuts_closed(AdwDialog* dialog, gpointer user) {
|
||||||
|
(void)dialog;
|
||||||
|
(void)user;
|
||||||
|
g_shortcuts = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
struct HelpPage {
|
struct HelpPage {
|
||||||
const char* section; ///< the group heading in the sidebar
|
const char* section; ///< the group heading in the sidebar
|
||||||
const char* title; ///< the row's label and the page's heading
|
const char* title; ///< the row's label and the page's heading
|
||||||
@@ -216,91 +227,65 @@ void show_help(GtkWindow* parent) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// One `accel description` pair appended to `grid` at `row`. The accel column is
|
/// Appends one table row to `dialog`, opening a new section whenever the row's `section`
|
||||||
/// monospaced and right-aligned so the descriptions line up down the window.
|
/// string differs from the last one. `*current` is the section being filled, `*title` the
|
||||||
void append_shortcut_row(GtkWidget* grid, int row, const char* accel_text,
|
/// name it carries; both are owned by the caller so the two tables share one run.
|
||||||
const char* description) {
|
///
|
||||||
GtkWidget* keys = gtk_label_new(nullptr);
|
/// `accel` is handed to `AdwShortcutsItem` as an accelerator when it is non-empty and
|
||||||
char markup[256];
|
/// `subtitle` is used when it is not, which is how a wheel or a drag gets a row: neither
|
||||||
std::snprintf(markup, sizeof(markup), "<tt>%s</tt>", accel_text);
|
/// GTK's nor libadwaita's accelerator syntax can name one, and asking them to parse
|
||||||
gtk_label_set_markup(GTK_LABEL(keys), markup);
|
/// "Wheel" costs a parse warning and draws nothing.
|
||||||
gtk_label_set_xalign(GTK_LABEL(keys), 1.0f);
|
void append_shortcut(AdwShortcutsDialog* dialog, AdwShortcutsSection** current,
|
||||||
gtk_widget_set_margin_end(keys, 14);
|
const char** title, const char* section, const char* accel,
|
||||||
gtk_grid_attach(GTK_GRID(grid), keys, 0, row, 1, 1);
|
const char* subtitle, const char* description) {
|
||||||
|
if (*current == nullptr || std::string(*title) != section) {
|
||||||
GtkWidget* what = gtk_label_new(description);
|
*current = adw_shortcuts_section_new(section);
|
||||||
gtk_label_set_xalign(GTK_LABEL(what), 0.0f);
|
*title = section;
|
||||||
gtk_grid_attach(GTK_GRID(grid), what, 1, row, 1, 1);
|
adw_shortcuts_dialog_add(dialog, *current);
|
||||||
}
|
}
|
||||||
|
AdwShortcutsItem* item = adw_shortcuts_item_new(description, accel);
|
||||||
/// A section heading spanning both columns.
|
if (subtitle != nullptr && *subtitle != '\0') {
|
||||||
void append_shortcut_heading(GtkWidget* grid, int row, const char* section) {
|
adw_shortcuts_item_set_subtitle(item, subtitle);
|
||||||
GtkWidget* heading = gtk_label_new(nullptr);
|
}
|
||||||
char markup[128];
|
adw_shortcuts_section_add(*current, item);
|
||||||
std::snprintf(markup, sizeof(markup), "<b>%s</b>", section);
|
|
||||||
gtk_label_set_markup(GTK_LABEL(heading), markup);
|
|
||||||
gtk_label_set_xalign(GTK_LABEL(heading), 0.0f);
|
|
||||||
gtk_widget_set_margin_top(heading, row == 0 ? 0 : 14);
|
|
||||||
gtk_widget_set_margin_bottom(heading, 4);
|
|
||||||
gtk_grid_attach(GTK_GRID(grid), heading, 0, row, 2, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void show_shortcuts(GtkWindow* parent) {
|
void show_shortcuts(GtkWindow* parent) {
|
||||||
if (g_shortcuts != nullptr) {
|
if (g_shortcuts != nullptr) {
|
||||||
gtk_window_present(GTK_WINDOW(g_shortcuts));
|
adw_dialog_present(g_shortcuts, GTK_WIDGET(parent));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget* window = gtk_window_new();
|
AdwDialog* dialog = adw_shortcuts_dialog_new();
|
||||||
g_shortcuts = window;
|
g_shortcuts = dialog;
|
||||||
gtk_window_set_title(GTK_WINDOW(window), "Keyboard and mouse shortcuts");
|
adw_dialog_set_title(dialog, "Keyboard and mouse shortcuts");
|
||||||
gtk_window_set_default_size(GTK_WINDOW(window), 560, 680);
|
|
||||||
gtk_window_set_transient_for(GTK_WINDOW(window), parent);
|
|
||||||
|
|
||||||
GtkWidget* grid = gtk_grid_new();
|
AdwShortcutsSection* section = nullptr;
|
||||||
gtk_grid_set_row_spacing(GTK_GRID(grid), 2);
|
const char* section_title = nullptr;
|
||||||
gtk_widget_set_margin_start(grid, 20);
|
|
||||||
gtk_widget_set_margin_end(grid, 20);
|
|
||||||
gtk_widget_set_margin_top(grid, 16);
|
|
||||||
gtk_widget_set_margin_bottom(grid, 16);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
const char* section = nullptr;
|
|
||||||
int accel_count = 0;
|
int accel_count = 0;
|
||||||
const Accel* accels = app_accels(&accel_count);
|
const Accel* accels = app_accels(&accel_count);
|
||||||
for (int i = 0; i < accel_count; ++i) {
|
for (int i = 0; i < accel_count; ++i) {
|
||||||
if (section == nullptr || std::string(section) != accels[i].section) {
|
append_shortcut(ADW_SHORTCUTS_DIALOG(dialog), §ion, §ion_title,
|
||||||
section = accels[i].section;
|
accels[i].section, accels[i].accel, "", accels[i].description);
|
||||||
append_shortcut_heading(grid, row++, section);
|
|
||||||
}
|
|
||||||
append_shortcut_row(grid, row++, accels[i].accel_text, accels[i].description);
|
|
||||||
}
|
}
|
||||||
int gesture_count = 0;
|
int gesture_count = 0;
|
||||||
const Gesture* gestures = plot_gestures(&gesture_count);
|
const Gesture* gestures = plot_gestures(&gesture_count);
|
||||||
for (int i = 0; i < gesture_count; ++i) {
|
for (int i = 0; i < gesture_count; ++i) {
|
||||||
if (section == nullptr || std::string(section) != gestures[i].section) {
|
append_shortcut(ADW_SHORTCUTS_DIALOG(dialog), §ion, §ion_title,
|
||||||
section = gestures[i].section;
|
gestures[i].section, gestures[i].accel, gestures[i].subtitle,
|
||||||
append_shortcut_heading(grid, row++, section);
|
gestures[i].description);
|
||||||
}
|
|
||||||
append_shortcut_row(grid, row++, gestures[i].accel_text, gestures[i].description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget* scroll = gtk_scrolled_window_new();
|
g_signal_connect(dialog, "closed", G_CALLBACK(on_shortcuts_closed), nullptr);
|
||||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER,
|
adw_dialog_present(dialog, GTK_WIDGET(parent));
|
||||||
GTK_POLICY_AUTOMATIC);
|
|
||||||
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), grid);
|
|
||||||
gtk_window_set_child(GTK_WINDOW(window), scroll);
|
|
||||||
|
|
||||||
g_signal_connect(window, "close-request", G_CALLBACK(on_window_close), &g_shortcuts);
|
|
||||||
gtk_window_present(GTK_WINDOW(window));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_help_windows() {
|
void close_help_windows() {
|
||||||
if (g_help != nullptr) gtk_window_close(GTK_WINDOW(g_help));
|
if (g_help != nullptr) gtk_window_close(GTK_WINDOW(g_help));
|
||||||
if (g_about != nullptr) gtk_window_close(GTK_WINDOW(g_about));
|
if (g_about != nullptr) gtk_window_close(GTK_WINDOW(g_about));
|
||||||
if (g_shortcuts != nullptr) gtk_window_close(GTK_WINDOW(g_shortcuts));
|
if (g_shortcuts != nullptr) adw_dialog_close(g_shortcuts);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace udpscope
|
} // namespace udpscope
|
||||||
+29
-24
@@ -9,47 +9,52 @@ namespace {
|
|||||||
/// Bare letters are toggles, Ctrl is for files and windows. Nothing here shadows a key the
|
/// Bare letters are toggles, Ctrl is for files and windows. Nothing here shadows a key the
|
||||||
/// plot's own controller handles ('+', '-', 'f', the arrows, Escape).
|
/// plot's own controller handles ('+', '-', 'f', the arrows, Escape).
|
||||||
constexpr Accel kAccels[] = {
|
constexpr Accel kAccels[] = {
|
||||||
{GDK_KEY_space, 0, AppAction::PauseToggle, "Space", "Pause or resume the display",
|
{GDK_KEY_space, 0, AppAction::PauseToggle, "space", "Pause or resume the display",
|
||||||
"Acquisition"},
|
"Acquisition"},
|
||||||
{GDK_KEY_a, 0, AppAction::TriggerArm, "A", "Arm or disarm the trigger", "Acquisition"},
|
{GDK_KEY_a, 0, AppAction::TriggerArm, "a", "Arm or disarm the trigger", "Acquisition"},
|
||||||
{GDK_KEY_t, 0, AppAction::TriggerPanel, "T", "Show or hide the trigger panel",
|
{GDK_KEY_t, 0, AppAction::TriggerPanel, "t", "Show or hide the trigger panel",
|
||||||
"Acquisition"},
|
"Acquisition"},
|
||||||
{GDK_KEY_c, 0, AppAction::CursorsPane, "C", "Show or hide the cursors pane",
|
{GDK_KEY_c, 0, AppAction::CursorsPane, "c", "Show or hide the cursors pane",
|
||||||
"Panes and editors"},
|
"Panes and editors"},
|
||||||
{GDK_KEY_m, 0, AppAction::MeasuresPane, "M", "Show or hide the measurements pane",
|
{GDK_KEY_m, 0, AppAction::MeasuresPane, "m", "Show or hide the measurements pane",
|
||||||
"Panes and editors"},
|
"Panes and editors"},
|
||||||
{GDK_KEY_g, 0, AppAction::MathPane, "G", "Show or hide the math pane",
|
{GDK_KEY_g, 0, AppAction::MathPane, "g", "Show or hide the math pane",
|
||||||
"Panes and editors"},
|
"Panes and editors"},
|
||||||
{GDK_KEY_l, 0, AppAction::LayoutEditor, "L", "Show or hide the layout editor",
|
{GDK_KEY_l, 0, AppAction::LayoutEditor, "l", "Show or hide the layout editor",
|
||||||
"Panes and editors"},
|
"Panes and editors"},
|
||||||
{GDK_KEY_s, 0, AppAction::SidePanel, "S", "Show or hide the side panel",
|
{GDK_KEY_s, 0, AppAction::SidePanel, "s", "Show or hide the side panel",
|
||||||
"Panes and editors"},
|
"Panes and editors"},
|
||||||
{GDK_KEY_e, GDK_CONTROL_MASK, AppAction::Export, "Ctrl+E",
|
{GDK_KEY_e, GDK_CONTROL_MASK, AppAction::Export, "<Control>e",
|
||||||
"Export the visible range", "Files and windows"},
|
"Export the visible range", "Files and windows"},
|
||||||
{GDK_KEY_F1, 0, AppAction::Help, "F1", "Open the help window", "Files and windows"},
|
{GDK_KEY_F1, 0, AppAction::Help, "F1", "Open the help window", "Files and windows"},
|
||||||
{GDK_KEY_slash, GDK_CONTROL_MASK, AppAction::Shortcuts, "Ctrl+/",
|
{GDK_KEY_slash, GDK_CONTROL_MASK, AppAction::Shortcuts, "<Control>slash",
|
||||||
"Open this shortcut overview", "Files and windows"},
|
"Open this shortcut overview", "Files and windows"},
|
||||||
{GDK_KEY_q, GDK_CONTROL_MASK, AppAction::Quit, "Ctrl+Q", "Quit udpscope",
|
{GDK_KEY_q, GDK_CONTROL_MASK, AppAction::Quit, "<Control>q", "Quit udpscope",
|
||||||
"Files and windows"},
|
"Files and windows"},
|
||||||
};
|
};
|
||||||
constexpr int kAccelCount = static_cast<int>(sizeof(kAccels) / sizeof(kAccels[0]));
|
constexpr int kAccelCount = static_cast<int>(sizeof(kAccels) / sizeof(kAccels[0]));
|
||||||
|
|
||||||
/// The plot's own interactions, documentation only. The keyboard's modifiers are not the
|
/// The plot's own interactions, documentation only. The keyboard's modifiers are not the
|
||||||
/// wheel's: '+' is shift+'=' on common layouts, so Shift could not mean anything there.
|
/// 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.
|
||||||
constexpr Gesture kGestures[] = {
|
constexpr Gesture kGestures[] = {
|
||||||
{"+ / -", "Zoom in or out, both axes", "Plot keyboard"},
|
{"plus minus", "", "Zoom in or out, both axes", "Plot keyboard"},
|
||||||
{"Ctrl + / Ctrl -", "Zoom the time axis only", "Plot keyboard"},
|
{"<Control>plus <Control>minus", "", "Zoom the time axis only", "Plot keyboard"},
|
||||||
{"Alt + / Alt -", "Zoom the value axis only", "Plot keyboard"},
|
{"<Alt>plus <Alt>minus", "", "Zoom the value axis only", "Plot keyboard"},
|
||||||
{"Left / Right", "Pan along time", "Plot keyboard"},
|
{"Left Right", "", "Pan along time", "Plot keyboard"},
|
||||||
{"Up / Down", "Pan along values", "Plot keyboard"},
|
{"Up Down", "", "Pan along values", "Plot keyboard"},
|
||||||
{"F", "Fit the view to the data", "Plot keyboard"},
|
{"f", "", "Fit the view to the data", "Plot keyboard"},
|
||||||
{"Escape", "Cancel the gesture in progress", "Plot keyboard"},
|
{"Escape", "", "Cancel the gesture in progress", "Plot keyboard"},
|
||||||
{"Wheel", "Zoom about the pointer, both axes", "Plot mouse"},
|
{"", "Wheel", "Zoom about the pointer, both axes", "Plot mouse"},
|
||||||
{"Shift+wheel", "Zoom the time axis only", "Plot mouse"},
|
{"", "Shift and wheel", "Zoom the time axis only", "Plot mouse"},
|
||||||
{"Ctrl+wheel", "Zoom the value axis only", "Plot mouse"},
|
{"", "Ctrl and wheel", "Zoom the value axis only", "Plot mouse"},
|
||||||
{"Drag", "Pan", "Plot mouse"},
|
{"", "Drag", "Pan", "Plot mouse"},
|
||||||
{"Ctrl+drag", "Box zoom on time", "Plot mouse"},
|
{"", "Ctrl and drag", "Box zoom on time", "Plot mouse"},
|
||||||
{"Alt+drag", "Box zoom on values", "Plot mouse"},
|
{"", "Alt and drag", "Box zoom on values", "Plot mouse"},
|
||||||
};
|
};
|
||||||
constexpr int kGestureCount = static_cast<int>(sizeof(kGestures) / sizeof(kGestures[0]));
|
constexpr int kGestureCount = static_cast<int>(sizeof(kGestures) / sizeof(kGestures[0]));
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -22,10 +22,10 @@ enum class AppAction {
|
|||||||
|
|
||||||
/// One application accelerator: what to press, what it does, and where the overview lists it.
|
/// One application accelerator: what to press, what it does, and where the overview lists it.
|
||||||
struct Accel {
|
struct Accel {
|
||||||
unsigned keyval; ///< GDK keyval
|
unsigned keyval; ///< GDK keyval
|
||||||
unsigned mods; ///< GdkModifierType mask, 0 for a bare key
|
unsigned mods; ///< GdkModifierType mask, 0 for a bare key
|
||||||
AppAction action;
|
AppAction action;
|
||||||
const char* accel_text; ///< what the overview prints
|
const char* accel; ///< GTK accelerator syntax, as `gtk_accelerator_parse()` reads it
|
||||||
const char* description;
|
const char* description;
|
||||||
const char* section;
|
const char* section;
|
||||||
};
|
};
|
||||||
@@ -33,7 +33,8 @@ struct Accel {
|
|||||||
/// One documented plot interaction. These have no AppAction: the plotter's own controller
|
/// One documented plot interaction. These have no AppAction: the plotter's own controller
|
||||||
/// implements them, and this table exists so the overview can list them.
|
/// implements them, and this table exists so the overview can list them.
|
||||||
struct Gesture {
|
struct Gesture {
|
||||||
const char* accel_text;
|
const char* accel; ///< GTK accelerator syntax, or "" for a pointer gesture
|
||||||
|
const char* subtitle; ///< prose for what no accelerator can express ("Wheel"), else ""
|
||||||
const char* description;
|
const char* description;
|
||||||
const char* section;
|
const char* section;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "layout_store.hpp"
|
#include "layout_store.hpp"
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -351,7 +352,10 @@ bool choose_source(Config& cfg) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_init();
|
// `adw_init()` rather than `gtk_init()`: it does everything the latter does and also
|
||||||
|
// installs libadwaita's stylesheet, which the shortcut overview's `AdwShortcutsDialog`
|
||||||
|
// is drawn with. Both are idempotent, so `run_ui()` calling it again costs nothing.
|
||||||
|
adw_init();
|
||||||
|
|
||||||
Chooser c;
|
Chooser c;
|
||||||
c.cfg = &cfg;
|
c.cfg = &cfg;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "model.hpp"
|
#include "model.hpp"
|
||||||
#include "plot_host.hpp"
|
#include "plot_host.hpp"
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -7293,6 +7294,9 @@ gboolean help_probe(gpointer user) {
|
|||||||
int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisition& acq,
|
int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisition& acq,
|
||||||
RowSet& rows) {
|
RowSet& rows) {
|
||||||
(void)argc;
|
(void)argc;
|
||||||
|
// Installs libadwaita's stylesheet, which the shortcut overview's `AdwShortcutsDialog`
|
||||||
|
// needs to be drawn at all. Idempotent, and `choose_source()` may already have run it.
|
||||||
|
adw_init();
|
||||||
App app;
|
App app;
|
||||||
app.model = &model;
|
app.model = &model;
|
||||||
app.acq = &acq;
|
app.acq = &acq;
|
||||||
|
|||||||
Reference in new issue
Block a user