Skip to content

Commit

Permalink
Handle tabs more like browsers do (#1149)
Browse files Browse the repository at this point in the history
* Add Ctrl-Tab and Ctrl-Shift-Tab tab navigation

* Reorder tabs (see desc); WIP
Can either drag-drop tabs with the mouse or use Ctrl-Shift-PgUp/PgDown.
Tab arrangement does not persist between sessions; will need to look into that.

* Persist tab reorders

* Allow closing any tab with their X button

* Add comments to PgUp/PgDown shortcuts

* Add Ctrl-W shortcut (close current tab)

* Middle click any tab to close it

* Remove notebook_main's Ctrl-PgUp/PgDown shortcuts

* Fix formatting

* Correct return value in comments

* Add missing function to header file

* Make tab_reorder_out_of_sync static in function

* Fix long-distance tab reorder issue
  • Loading branch information
nwalkewicz authored Jun 23, 2024
1 parent 9346668 commit ffbaee8
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 7 deletions.
47 changes: 47 additions & 0 deletions src/gtk/main_window.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
/* we must define the categories of #definitions we need. */
#define XK_MISCELLANY
#define XK_LATIN1
#define XK_XKB_KEYS
#include <X11/keysymdef.h>

WIDGETS widgets;
Expand Down Expand Up @@ -797,6 +798,52 @@ static gboolean on_vbox1_key_press_event(GtkWidget *widget, GdkEventKey *event,
kbd_toggle_option(true, "Transliteration");
break;

case XK_Tab:
if (state == GDK_CONTROL_MASK) // Ctrl-Tab next tab
if (GTK_NOTEBOOK(widgets.notebook_main) != NULL) {
gtk_notebook_next_page(GTK_NOTEBOOK(widgets.notebook_main));
return TRUE; // Need to prevent Tab from navigating between widgets here
}
break;

case XK_ISO_Left_Tab:
if (state == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) // Ctrl-Shift-Tab previous tab
if (GTK_NOTEBOOK(widgets.notebook_main) != NULL) {
gtk_notebook_prev_page(GTK_NOTEBOOK(widgets.notebook_main));
return TRUE; // Need to prevent Shift-Tab from navigating between widgets here
}
break;

case XK_Page_Up:
if (state == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) { // Ctrl-Shift-PgUp reorder tab to left
gint current_tab_idx = gtk_notebook_get_current_page(GTK_NOTEBOOK(widgets.notebook_main));
GtkWidget *current_tab = gtk_notebook_get_nth_page(GTK_NOTEBOOK(widgets.notebook_main), current_tab_idx);
if (current_tab_idx != 0) {
gtk_notebook_reorder_child(GTK_NOTEBOOK(widgets.notebook_main), current_tab, current_tab_idx - 1);
}
}
break;

case XK_Page_Down:
if (state == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) { // Ctrl-Shift-PgDown reorder tab to right
gint current_tab_idx = gtk_notebook_get_current_page(GTK_NOTEBOOK(widgets.notebook_main));
gint n_tabs = gtk_notebook_get_n_pages(GTK_NOTEBOOK(widgets.notebook_main));
GtkWidget *current_tab = gtk_notebook_get_nth_page(GTK_NOTEBOOK(widgets.notebook_main), current_tab_idx);
if (current_tab_idx < n_tabs - 1) {
gtk_notebook_reorder_child(GTK_NOTEBOOK(widgets.notebook_main), current_tab, current_tab_idx + 1);
}
}
break;

case XK_w:
if (state == GDK_CONTROL_MASK) { // Ctrl-W close current tab
if (GTK_NOTEBOOK(widgets.notebook_main) != NULL) {
gint pagenum = gtk_notebook_get_current_page(GTK_NOTEBOOK(widgets.notebook_main));
gui_close_passage_tab(pagenum);
}
}
break;

case XK_z:
case XK_Z:
if (state == GDK_MOD1_MASK) // Alt-Z open personal commentary
Expand Down
149 changes: 142 additions & 7 deletions src/gtk/tabbed_browser.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,9 @@ void set_current_tab(PASSAGE_TAB_INFO *pt)
if (stop_refresh)
return;

if (!closing_tab && ot != NULL && ot->button_close != NULL) {
gtk_widget_set_sensitive(ot->button_close, FALSE);
}
cur_passage_tab = pt;
if (pt != NULL && pt->button_close != NULL) {
//main_update_tab_history_menu((PASSAGE_TAB_INFO*)pt);
gtk_widget_set_sensitive(pt->button_close, TRUE);

/* adopt panel shows from passage tab memory. */
settings.showtexts = pt->showtexts;
Expand Down Expand Up @@ -299,6 +295,9 @@ void notebook_main_add_page(PASSAGE_TAB_INFO *tbinf)
gtk_notebook_append_page(GTK_NOTEBOOK(widgets.notebook_main),
tbinf->page_widget, tab_widget);

gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(widgets.notebook_main),
tbinf->page_widget, TRUE);

gtk_notebook_set_menu_label_text(GTK_NOTEBOOK(widgets.notebook_main),
tbinf->page_widget, str->str);

Expand Down Expand Up @@ -792,6 +791,49 @@ void gui_load_tabs(const gchar *filename)
gui_recompute_view_menu_choices();
}

/******************************************************************************
* Name
* on_notebook_main_tab_clicked
*
* Synopsis
* #include "tabbed_browser.h"
*
* void on_notebook_main_tab_clicked(GtkWidget *self,
* GdkEventButton *event,
* gpointer user_data)
*
* Description
* Handle click events for tabs
*
* Return value
* void
*/
static gboolean on_notebook_main_tab_clicked(GtkWidget *self,
GdkEventButton *event,
gpointer user_data)
{
GtkWidget *notebook = widgets.notebook_main;
PASSAGE_TAB_INFO *pt = user_data;
const gchar *label_text = gtk_label_get_text(pt->tab_label);

switch (event->type) {
case GDK_BUTTON_PRESS: {
if (event->button == 2) { // Middle-Click
GtkWidget *page = pt->page_widget;
gint pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
gui_close_passage_tab(pagenum);
return TRUE;
}
break;
}

default:
return FALSE;
}

return FALSE;
}

/******************************************************************************
* Name
* on_notebook_main_close_page
Expand All @@ -805,7 +847,7 @@ void gui_load_tabs(const gchar *filename)
*
*
* Return value
* void
* gpointer
*/

static void on_notebook_main_close_page(GtkButton *button,
Expand Down Expand Up @@ -881,8 +923,11 @@ static GtkWidget *tab_widget_new(PASSAGE_TAB_INFO *tbinf,
gtk_widget_size_request(tbinf->button_close, &r);
#endif

gtk_widget_set_sensitive(tbinf->button_close, FALSE);
gtk_widget_show(tbinf->button_close);

tbinf->tab_label_eventbox = GTK_EVENT_BOX(gtk_event_box_new());
gtk_widget_show(GTK_WIDGET(tbinf->tab_label_eventbox));

tbinf->tab_label = GTK_LABEL(gtk_label_new(label_text));
gtk_widget_show(GTK_WIDGET(tbinf->tab_label));

Expand All @@ -905,19 +950,104 @@ static GtkWidget *tab_widget_new(PASSAGE_TAB_INFO *tbinf,
#endif

UI_HBOX(box, FALSE, 0);
gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(tbinf->tab_label),
gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(tbinf->tab_label_eventbox),
TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(box), tbinf->button_close, FALSE, FALSE,
0);

gtk_container_add(GTK_CONTAINER(tbinf->tab_label_eventbox),
GTK_WIDGET(tbinf->tab_label));
gtk_widget_set_events(GTK_WIDGET(tbinf->tab_label_eventbox), GDK_BUTTON_PRESS_MASK);

gtk_widget_show(box);

g_signal_connect(G_OBJECT(tbinf->button_close), "clicked",
G_CALLBACK(on_notebook_main_close_page), tbinf);

g_signal_connect(G_OBJECT(tbinf->tab_label_eventbox), "button-press-event",
G_CALLBACK(on_notebook_main_tab_clicked), tbinf);

return box;
}

/******************************************************************************
* Name
* gui_notebook_main_page_reordered
*
* Synopsis
* #include "tabbed_browser.h"
*
* void gui_notebook_main_page_reordered(GtkNotebook *notebook,
* GtkNotebookPage *page,
* guint page_num, GList **tl)
*
* Description
* updates passage_list with changed tab order
*
* Return value
* void
*/
void gui_notebook_main_page_reordered(GtkNotebook *notebook,
gpointer page,
guint page_num,
GList **tl)
{
static gboolean tab_order_out_of_sync = FALSE;
if (tab_order_out_of_sync) {
return;
}

guint new_index = page_num;

// Get index of passage_list entry that matches `page`
GList *passage_list = *tl;
PASSAGE_TAB_INFO *pt = passage_list->data;
gint old_index = -1;
gint idx = 0;
for (GList *cur = passage_list; cur != NULL; cur = cur->next) {
pt = cur->data;
GtkWidget *pw = pt->page_widget;
if (pw == page) {
old_index = idx;
break;
}

idx++;
}

if (old_index == -1) {
// Page not found (this theoretically shouldn't be possible)
g_warning("Couldn't find reordered page in passage_list!\
`widgets.notebook_main` and `passage_list` might be out of sync! Refusing to\
persist further tab rearrangements.\n");
tab_order_out_of_sync = true;
return;
}

// Swap pointers inside of passage_list to match swap
// performed by notebook.
if (old_index == new_index) { return; }

bool shifting_right = false;
if (new_index > old_index) {
shifting_right = true;
}

GList *sibling = NULL;
if (new_index < g_list_length(passage_list) - 1) {
sibling = g_list_nth(passage_list, new_index);
if (shifting_right) {
sibling = sibling->next;
}
}

GList *link = g_list_nth(passage_list, old_index);
passage_list = g_list_remove_link(passage_list, link);
passage_list = g_list_insert_before_link(passage_list, sibling, link);

*tl = passage_list;
}

/******************************************************************************
* Name
* gui_notebook_main_switch_page
Expand Down Expand Up @@ -1592,6 +1722,11 @@ void gui_notebook_main_setup(int tabs, const char *tabsfile)
G_CALLBACK(gui_notebook_main_switch_page),
&passage_list);

g_signal_connect(G_OBJECT(widgets.notebook_main),
"page-reordered",
G_CALLBACK(gui_notebook_main_page_reordered),
&passage_list);

g_signal_connect(G_OBJECT(widgets.button_new_tab), "clicked",
G_CALLBACK(on_notebook_main_new_tab_clicked),
NULL);
Expand Down
5 changes: 5 additions & 0 deletions src/gui/tabbed_browser.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct _passage_tab_info
{
GtkWidget *page_widget;
GtkLabel *tab_label;
GtkEventBox *tab_label_eventbox;
GtkWidget *button_close;
GtkWidget *editor;
GtkWidget *paratab;
Expand Down Expand Up @@ -103,6 +104,10 @@ void gui_recompute_shows(gboolean flush);
void gui_recompute_view_menu_choices(void);
void setup_book_editor_tab(PASSAGE_TAB_INFO *pt);
GString *pick_tab_label(PASSAGE_TAB_INFO *pt);
void gui_notebook_main_page_reordered(GtkNotebook *notebook,
gpointer page,
guint page_num,
GList **tl);
#ifdef USE_GTK_3
void gui_notebook_main_switch_page(GtkNotebook *notebook,
gpointer arg1, gint page_num,
Expand Down

0 comments on commit ffbaee8

Please sign in to comment.