From 91ca0d2cf669881f40a71c2ec9f05b7e5caba509 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Tue, 1 Jan 2013 08:22:46 -0800 Subject: First step towards grabbing keys and handling them ourselves This commit steals the cursor up and down keys away from gtk so regardless where gtk thinks the focus may be, we can still use the keys to change between dives. In the current UI design where all editing happens in separate windows this works as expected, as we only grab the keys for the main window. If we manage to re-enable in-place editing then we need to make sure that this doesn't cause problems (as gtk uses up/down for the ability to change drop down selections in combo boxes or values in spin buttons. So we must make sure that we stop stealing these keys once we start editing something (in which case simply switching to the next/prev dive wouldn't be a good thing, anyway). Signed-off-by: Dirk Hohndel --- divelist.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ divelist.h | 2 ++ gtk-gui.c | 19 ++++++++++++ 3 files changed, 120 insertions(+) diff --git a/divelist.c b/divelist.c index 2a6829e27..2240ff40e 100644 --- a/divelist.c +++ b/divelist.c @@ -2627,3 +2627,102 @@ void remove_autogen_trips() remove_dive_from_trip(dive); } } + +struct iteridx { + int idx; + GtkTreeIter *iter; +}; + +static gboolean iter_has_idx(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer _data) +{ + struct iteridx *iteridx = _data; + int idx; + /* Get the dive number */ + gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); + if (idx == iteridx->idx) { + iteridx->iter = gtk_tree_iter_copy(iter); + return TRUE; /* end foreach */ + } + return FALSE; +} + +static GtkTreeIter *get_iter_from_idx(int idx) +{ + struct iteridx iteridx = {idx, }; + gtk_tree_model_foreach(MODEL(dive_list), iter_has_idx, &iteridx); + return iteridx.iter; +} + +void select_next_dive(void) +{ + GtkTreeIter *nextiter; + GtkTreeIter *iter = get_iter_from_idx(selected_dive); + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); + GtkTreePath *treepath; + int idx; + + if (!iter) + return; + nextiter = gtk_tree_iter_copy(iter); + if (!gtk_tree_model_iter_next(MODEL(dive_list), nextiter)) { + if (!gtk_tree_model_iter_parent(MODEL(dive_list), nextiter, iter)) + /* we're at the last top level node */ + return; + if (!gtk_tree_model_iter_next(MODEL(dive_list), nextiter)) + /* last trip */ + return; + gtk_tree_model_get(MODEL(dive_list), nextiter, DIVE_INDEX, &idx, -1); + if (idx < 0) { + /* need the first child */ + GtkTreeIter *parent = gtk_tree_iter_copy(nextiter); + if (! gtk_tree_model_iter_children(MODEL(dive_list), nextiter, parent)) + return; + } + } + treepath = gtk_tree_model_get_path(MODEL(dive_list), nextiter); + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath); + gtk_tree_selection_select_iter(selection, nextiter); + gtk_tree_selection_unselect_iter(selection, iter); + gtk_tree_path_free(treepath); +} + +void select_prev_dive(void) +{ + GtkTreeIter previter; + GtkTreeIter *iter = get_iter_from_idx(selected_dive); + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view)); + GtkTreePath *treepath; + int idx; + + if (!iter) + return; + treepath = gtk_tree_model_get_path(MODEL(dive_list), iter); + if (!gtk_tree_path_prev(treepath)) { + if (!gtk_tree_model_iter_parent(MODEL(dive_list), &previter, iter)) + /* we're at the last top level node */ + return; + treepath = gtk_tree_model_get_path(MODEL(dive_list), &previter); + if (!gtk_tree_path_prev(treepath)) + /* first trip */ + return; + if (!gtk_tree_model_get_iter(MODEL(dive_list), &previter, treepath)) + return; + gtk_tree_model_get(MODEL(dive_list), &previter, DIVE_INDEX, &idx, -1); + if (idx < 0) { + /* need the last child */ + GtkTreeIter *parent = gtk_tree_iter_copy(&previter); + if (! gtk_tree_model_iter_nth_child(MODEL(dive_list), &previter, parent, + gtk_tree_model_iter_n_children(MODEL(dive_list), parent) - 1)) + return; + } + treepath = gtk_tree_model_get_path(MODEL(dive_list), &previter); + } else { + if (!gtk_tree_model_get_iter(MODEL(dive_list), &previter, treepath)) + return; + } + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath); + gtk_tree_selection_select_iter(selection, &previter); + gtk_tree_selection_unselect_iter(selection, iter); + gtk_tree_path_free(treepath); +} diff --git a/divelist.h b/divelist.h index 0a635c2ed..b309e9a54 100644 --- a/divelist.h +++ b/divelist.h @@ -13,4 +13,6 @@ extern int unsaved_changes(void); extern void remove_autogen_trips(void); extern void remember_tree_state(void); extern void restore_tree_state(void); +extern void select_next_dive(void); +extern void select_prev_dive(void); #endif diff --git a/gtk-gui.c b/gtk-gui.c index a6ed46942..f241fd313 100644 --- a/gtk-gui.c +++ b/gtk-gui.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -1130,6 +1131,21 @@ static void switch_page(GtkNotebook *notebook, gint arg1, gpointer user_data) repaint_dive(); } +static gboolean on_key_press(GtkWidget *w, GdkEventKey *event, GtkWidget *divelist) +{ + if (event->type != GDK_KEY_PRESS) + return FALSE; + switch (event->keyval) { + case GDK_KEY_Up: + select_prev_dive(); + return TRUE; + case GDK_KEY_Down: + select_next_dive(); + return TRUE; + } + return FALSE; +} + void init_ui(int *argcp, char ***argvp) { GtkWidget *win; @@ -1325,6 +1341,9 @@ void init_ui(int *argcp, char ***argvp) nb_page = total_stats_widget(); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), nb_page, gtk_label_new(_("Stats"))); + /* handle some keys globally (to deal with gtk focus issues) */ + g_signal_connect (G_OBJECT (win), "key_press_event", G_CALLBACK (on_key_press), dive_list); + gtk_widget_set_app_paintable(win, TRUE); gtk_widget_show_all(win); -- cgit v1.2.3-70-g09d2 From 8f364d0094aa0c2999708dca0e1ac6fefed67837 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Tue, 1 Jan 2013 10:20:22 -0800 Subject: Use the Left and Right keys to switch between divecomputers The existing code had the somewhat retarded Ctrl-C binding for displaying the next divecomputer and no way to go back to the previous one. With this commit we use our keyboard grab to map Left and Right to previous and next divecomputer. Much nicer. Signed-off-by: Dirk Hohndel --- gtk-gui.c | 17 ++++++++++++++++- profile.c | 13 +++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/gtk-gui.c b/gtk-gui.c index f241fd313..2b9068681 100644 --- a/gtk-gui.c +++ b/gtk-gui.c @@ -1021,6 +1021,13 @@ static void toggle_zoom(GtkWidget *w, gpointer data) repaint_dive(); } +static void prev_dc(GtkWidget *w, gpointer data) +{ + dc_number--; + /* If the dc number underflows, we'll "wrap around" and use the last dc */ + repaint_dive(); +} + static void next_dc(GtkWidget *w, gpointer data) { dc_number++; @@ -1053,7 +1060,8 @@ static GtkActionEntry menu_items[] = { { "ViewProfile", NULL, N_("Profile"), CTRLCHAR "2", NULL, G_CALLBACK(view_profile) }, { "ViewInfo", NULL, N_("Info"), CTRLCHAR "3", NULL, G_CALLBACK(view_info) }, { "ViewThree", NULL, N_("Three"), CTRLCHAR "4", NULL, G_CALLBACK(view_three) }, - { "NextDC", NULL, N_("Next DC"), CTRLCHAR "C", NULL, G_CALLBACK(next_dc) }, + { "PrevDC", NULL, N_("Prev DC"), NULL, NULL, G_CALLBACK(prev_dc) }, + { "NextDC", NULL, N_("Next DC"), NULL, NULL, G_CALLBACK(next_dc) }, }; static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]); @@ -1095,6 +1103,7 @@ static const gchar* ui_string = " \ \ \ \ + \ \ \ \ @@ -1142,6 +1151,12 @@ static gboolean on_key_press(GtkWidget *w, GdkEventKey *event, GtkWidget *diveli case GDK_KEY_Down: select_next_dive(); return TRUE; + case GDK_KEY_Left: + prev_dc(NULL, NULL); + return TRUE; + case GDK_KEY_Right: + next_dc(NULL, NULL); + return TRUE; } return FALSE; } diff --git a/profile.c b/profile.c index 0962f9ca8..dea1ad6ee 100644 --- a/profile.c +++ b/profile.c @@ -1800,11 +1800,24 @@ static void plot_set_scale(scale_mode_t scale) } } +/* make sure you pass this the FIRST dc - it just walks the list */ +static int nr_dcs(struct divecomputer *main) +{ + int i = 1; + struct divecomputer *dc = main; + + while ((dc = dc->next) != NULL) + i++; + return i; +} + static struct divecomputer *select_dc(struct divecomputer *main) { int i = dc_number; struct divecomputer *dc = main; + while (i < 0) + i += nr_dcs(main); do { if (--i < 0) return dc; -- cgit v1.2.3-70-g09d2