From d8b4a4ad19d383b809eda56a4621a11dbb244f95 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Thu, 23 Apr 2020 15:53:37 -0700 Subject: [PATCH] Extract several functions for managing GtkEntry position and selection GncTable uses separate values for entry position, selection start, and selection end while GtkEntry maintains only position and selection bound. These functions provide for a consistent bridge between the two. --- .../register/register-gnome/gnucash-sheet.c | 163 ++++++++++-------- .../register/register-gnome/gnucash-sheetP.h | 2 +- 2 files changed, 95 insertions(+), 70 deletions(-) diff --git a/gnucash/register/register-gnome/gnucash-sheet.c b/gnucash/register/register-gnome/gnucash-sheet.c index 3b4bf04ddd..81603fdebb 100644 --- a/gnucash/register/register-gnome/gnucash-sheet.c +++ b/gnucash/register/register-gnome/gnucash-sheet.c @@ -103,6 +103,65 @@ gboolean gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr, /** Implementation *****************************************************/ + +/* gtk_editable_set_position sets both current_pos and selection_bound to the + * supplied value. gtk_editable_select_region(start, end) sets current_pos to + * end and selection_bound to start; if either is < 0 it's changed to length. + * + * That's a bit orthogonal to the way GncTable sees things, so the following + * functions translate between the two. + */ + +static inline void +gnucash_sheet_set_entry_selection (GnucashSheet *sheet) +{ + // We usually want the cursor at the beginning of the selection. + gtk_editable_select_region (GTK_EDITABLE (sheet->entry), + sheet->pos, sheet->bound); +} + +static inline void +gnucash_sheet_set_selection (GnucashSheet *sheet, int pos, int bound) +{ + sheet->pos = pos; + sheet->bound = bound; + gnucash_sheet_set_entry_selection (sheet); +} + +// The variable names here are intended to match the GncTable usage. +static inline void +gnucash_sheet_set_position_and_selection (GnucashSheet* sheet, int pos, + int start, int end) +{ + if (pos == end || start == -1) + gnucash_sheet_set_selection (sheet, pos, start); + else if (pos == start || end == -1) + gnucash_sheet_set_selection (sheet, start, end); + else if (start == end) + gnucash_sheet_set_selection (sheet, pos, pos); + else + gnucash_sheet_set_selection (sheet, pos, end); +} + +static inline void +gnucash_sheet_set_position (GnucashSheet* sheet, int pos) +{ + gnucash_sheet_set_position_and_selection (sheet, pos, pos, pos); +} + +static inline void +gnucash_sheet_get_selection (GnucashSheet *sheet, int *start, int *end) +{ + *start = sheet->pos; + *end = sheet->bound; +} + +static inline void +gnucash_sheet_clear_selection (GnucashSheet *sheet) +{ + gnucash_sheet_set_selection (sheet, sheet->pos, sheet->pos); +} + static inline void gnucash_sheet_set_entry_value (GnucashSheet *sheet, const char* value) { @@ -411,13 +470,14 @@ gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet, // mouse position if (sheet->button != 1) { - gtk_editable_set_position (editable, cursor_pos); - gtk_editable_select_region (editable, start_sel, end_sel); + gnucash_sheet_set_position_and_selection (sheet, cursor_pos, + start_sel, end_sel); } else - gtk_editable_set_position (editable, - gnucash_sheet_get_text_cursor_position (sheet, virt_loc)); - + { + int pos = gnucash_sheet_get_text_cursor_position (sheet, virt_loc); + gnucash_sheet_set_position (sheet, pos); + } sheet->direct_update_cell = gnucash_sheet_check_direct_update_cell (sheet, virt_loc); } @@ -902,12 +962,9 @@ gnucash_sheet_modify_current_cell (GnucashSheet *sheet, const gchar *new_text) if (retval) { gnucash_sheet_set_entry_value (sheet, retval); - + gnucash_sheet_set_position_and_selection (sheet, cursor_position, + start_sel, end_sel); } - - gtk_editable_set_position (editable, cursor_position); - gtk_editable_select_region(editable, start_sel, end_sel); - return retval; } @@ -1089,7 +1146,7 @@ gnucash_sheet_insert_cb (GtkWidget *widget, ((strcmp (retval, new_text) != 0) || (*position != old_position))) { - gnucash_sheet_set_entry_value (sheet, table_val); + gnucash_sheet_set_entry_value (sheet, retval); g_signal_stop_emission_by_name (G_OBJECT(sheet->entry), "insert_text"); } @@ -1107,18 +1164,16 @@ gnucash_sheet_insert_cb (GtkWidget *widget, /* sync cursor position and selection to preedit if it exists */ if (sheet->preedit_length) { - gtk_editable_set_position (editable, - sheet->preedit_start_position - + sheet->preedit_cursor_position); + + int pos = (sheet->preedit_start_position == -1) ? + gtk_editable_get_position (editable) : + sheet->preedit_start_position; + gnucash_sheet_set_position (sheet, pos); + gnucash_sheet_im_context_reset_flags (sheet); } else if (*position < 0) *position = g_utf8_strlen(retval, -1); - if (start_sel != end_sel) - gtk_editable_select_region(editable, start_sel, end_sel); - /* Save the selected region in case the input module eats it. */ - sheet->start_sel = start_sel; - sheet->end_sel = end_sel; g_string_free (new_text_gs, TRUE); g_string_free (change_text_gs, TRUE); @@ -1209,11 +1264,8 @@ gnucash_sheet_delete_cb (GtkWidget *widget, "delete_text"); } - gtk_editable_set_position (editable, cursor_position); - - if (start_sel != end_sel) - gtk_editable_select_region (editable, start_sel, end_sel); - + gnucash_sheet_set_position_and_selection (sheet, cursor_position, + start_sel, end_sel); g_string_free (new_text_gs, TRUE); } @@ -1716,7 +1768,7 @@ gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event) case GDK_KEY_KP_Enter: g_signal_emit_by_name(sheet->reg, "activate_cursor"); /* Clear the saved selection. */ - sheet->end_sel = sheet->start_sel; + sheet->pos = sheet->bound; return TRUE; break; case GDK_KEY_Tab: @@ -1781,7 +1833,7 @@ gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event) cur_virt_loc)) gnc_item_edit_show_popup (item_edit); /* Clear the saved selection for the new cell. */ - sheet->end_sel = sheet->start_sel; + sheet->pos = sheet->bound; return TRUE; } @@ -1805,14 +1857,14 @@ gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event) case GDK_KEY_Home: case GDK_KEY_End: /* Clear the saved selection, we're not using it. */ - sheet->end_sel = sheet->start_sel; + sheet->pos = sheet->bound; pass_on = TRUE; break; default: if (gnucash_sheet_clipboard_event(sheet, event)) { /* Clear the saved selection. */ - sheet->end_sel = sheet->start_sel; + sheet->pos = sheet->bound; return TRUE; } pass_on = TRUE; @@ -1829,16 +1881,8 @@ gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event) // If sheet is readonly, entry is not realized if (gtk_widget_get_realized (GTK_WIDGET(editable))) { + gnucash_sheet_clear_selection (sheet); result = gtk_widget_event (GTK_WIDGET(editable), (GdkEvent*)event); - /* Restore the stored selection in case it was eaten by the input - * module. - */ - if (sheet->start_sel != sheet->end_sel) - { - gtk_editable_select_region(editable, sheet->start_sel, - sheet->end_sel); - sheet->end_sel = sheet->start_sel; - } } return result; } @@ -1856,7 +1900,7 @@ gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event) } /* Clear the saved selection for the new cell. */ - sheet->end_sel = sheet->start_sel; + sheet->pos = sheet->bound; gnucash_sheet_cursor_move (sheet, new_virt_loc); /* return true because we handled the key press */ @@ -2003,28 +2047,11 @@ static void gnucash_sheet_preedit_changed_cb (GtkIMContext *context, GnucashSheet *sheet) { gchar *preedit_string; - GtkEditable *editable; + GtkEditable *editable = GTK_EDITABLE (sheet->entry); g_return_if_fail(context != NULL); g_return_if_fail(sheet->editing == TRUE); - editable = GTK_EDITABLE (sheet->entry); - - /* save preedit start position and selection */ - if (sheet->preedit_length == 0) - { - int start_pos, end_pos; - if ( gtk_editable_get_selection_bounds (editable, &start_pos, &end_pos)) - { - sheet->preedit_start_position = start_pos; - sheet->preedit_selection_length = end_pos - start_pos; - } - else - { - sheet->preedit_start_position = - gtk_editable_get_position (editable); - } - } #ifdef G_OS_WIN32 else /* sheet->preedit_length != 0 */ { @@ -2057,6 +2084,7 @@ gnucash_sheet_preedit_changed_cb (GtkIMContext *context, GnucashSheet *sheet) if (sheet->preedit_length) { + int start_sel, end_sel; int tmp_pos = sheet->preedit_start_position; g_signal_handler_block (G_OBJECT (sheet->entry), sheet->insert_signal); @@ -2065,21 +2093,18 @@ gnucash_sheet_preedit_changed_cb (GtkIMContext *context, GnucashSheet *sheet) g_signal_handler_unblock (G_OBJECT (sheet->entry), sheet->insert_signal); - gtk_editable_set_position (editable, sheet->preedit_start_position - + sheet->preedit_cursor_position); - - if ( sheet->preedit_selection_length != 0) - { - gtk_editable_select_region (editable, - sheet->preedit_start_position - + sheet->preedit_char_length, - sheet->preedit_start_position - + sheet->preedit_char_length - + sheet->preedit_selection_length); - } + start_sel = sheet->preedit_start_position + sheet->preedit_char_length; + end_sel = sheet->preedit_start_position + sheet->preedit_char_length + + sheet->preedit_selection_length; + gnucash_sheet_set_position_and_selection (sheet, start_sel, + start_sel, end_sel); } else { + /* Reset the selection to saved because GtkEntry's handlers have messed + * with it. + */ + gnucash_sheet_set_entry_selection (sheet); gnucash_sheet_im_context_reset_flags(sheet); } @@ -2625,7 +2650,7 @@ gnucash_sheet_init (GnucashSheet *sheet) sheet->delete_surrounding_signal = 0; sheet->shift_state = 0; sheet->keyval_state = 0; - sheet->start_sel = sheet->end_sel = 0; + sheet->bound = sheet->pos = 0; } diff --git a/gnucash/register/register-gnome/gnucash-sheetP.h b/gnucash/register/register-gnome/gnucash-sheetP.h index dc9d18e094..80484fec50 100644 --- a/gnucash/register/register-gnome/gnucash-sheetP.h +++ b/gnucash/register/register-gnome/gnucash-sheetP.h @@ -114,7 +114,7 @@ struct _GnucashSheet guint shift_state; guint keyval_state; - int start_sel, end_sel; + int pos, bound ; /** Corresponds to GtkEditable's current_pos and selection_bound */ };