feat: keyboard and mouse shortcut overview window
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
3e0d0de325
commit
018b98eddf
6 files changed
+248
-3
No files matched your search
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "build_info.hpp"
|
||||
#include "layout_store.hpp"
|
||||
#include "shortcuts.hpp"
|
||||
|
||||
namespace udpscope {
|
||||
namespace {
|
||||
@@ -14,6 +15,7 @@ namespace {
|
||||
/// One pointer per window, file-scope because there is one application.
|
||||
GtkWidget* g_about = nullptr;
|
||||
GtkWidget* g_help = nullptr;
|
||||
GtkWidget* g_shortcuts = nullptr;
|
||||
|
||||
gboolean on_window_close(GtkWindow* window, gpointer slot) {
|
||||
(void)window;
|
||||
@@ -212,9 +214,93 @@ void show_help(GtkWindow* parent) {
|
||||
gtk_window_present(GTK_WINDOW(window));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// One `accel description` pair appended to `grid` at `row`. The accel column is
|
||||
/// monospaced and right-aligned so the descriptions line up down the window.
|
||||
void append_shortcut_row(GtkWidget* grid, int row, const char* accel_text,
|
||||
const char* description) {
|
||||
GtkWidget* keys = gtk_label_new(nullptr);
|
||||
char markup[256];
|
||||
std::snprintf(markup, sizeof(markup), "<tt>%s</tt>", accel_text);
|
||||
gtk_label_set_markup(GTK_LABEL(keys), markup);
|
||||
gtk_label_set_xalign(GTK_LABEL(keys), 1.0f);
|
||||
gtk_widget_set_margin_end(keys, 14);
|
||||
gtk_grid_attach(GTK_GRID(grid), keys, 0, row, 1, 1);
|
||||
|
||||
GtkWidget* what = gtk_label_new(description);
|
||||
gtk_label_set_xalign(GTK_LABEL(what), 0.0f);
|
||||
gtk_grid_attach(GTK_GRID(grid), what, 1, row, 1, 1);
|
||||
}
|
||||
|
||||
/// A section heading spanning both columns.
|
||||
void append_shortcut_heading(GtkWidget* grid, int row, const char* section) {
|
||||
GtkWidget* heading = gtk_label_new(nullptr);
|
||||
char markup[128];
|
||||
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
|
||||
|
||||
void show_shortcuts(GtkWindow* parent) {
|
||||
if (g_shortcuts != nullptr) {
|
||||
gtk_window_present(GTK_WINDOW(g_shortcuts));
|
||||
return;
|
||||
}
|
||||
|
||||
GtkWidget* window = gtk_window_new();
|
||||
g_shortcuts = window;
|
||||
gtk_window_set_title(GTK_WINDOW(window), "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();
|
||||
gtk_grid_set_row_spacing(GTK_GRID(grid), 2);
|
||||
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;
|
||||
const Accel* accels = app_accels(&accel_count);
|
||||
for (int i = 0; i < accel_count; ++i) {
|
||||
if (section == nullptr || std::string(section) != accels[i].section) {
|
||||
section = accels[i].section;
|
||||
append_shortcut_heading(grid, row++, section);
|
||||
}
|
||||
append_shortcut_row(grid, row++, accels[i].accel_text, accels[i].description);
|
||||
}
|
||||
int gesture_count = 0;
|
||||
const Gesture* gestures = plot_gestures(&gesture_count);
|
||||
for (int i = 0; i < gesture_count; ++i) {
|
||||
if (section == nullptr || std::string(section) != gestures[i].section) {
|
||||
section = gestures[i].section;
|
||||
append_shortcut_heading(grid, row++, section);
|
||||
}
|
||||
append_shortcut_row(grid, row++, gestures[i].accel_text, gestures[i].description);
|
||||
}
|
||||
|
||||
GtkWidget* scroll = gtk_scrolled_window_new();
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER,
|
||||
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() {
|
||||
if (g_help != nullptr) gtk_window_close(GTK_WINDOW(g_help));
|
||||
if (g_about != nullptr) gtk_window_close(GTK_WINDOW(g_about));
|
||||
if (g_shortcuts != nullptr) gtk_window_close(GTK_WINDOW(g_shortcuts));
|
||||
}
|
||||
|
||||
} // namespace udpscope
|
||||
Reference in new issue
Block a user