From ed2b92c428ce55e8466033d245412b72bbab879b Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Mon, 19 Jun 2023 09:34:12 +0100 Subject: [PATCH 1/4] Fix cursor position when deleting selected text --- gnucash/register/register-gnome/completioncell-gnome.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnucash/register/register-gnome/completioncell-gnome.c b/gnucash/register/register-gnome/completioncell-gnome.c index c4bc0aaceb..6136200854 100644 --- a/gnucash/register/register-gnome/completioncell-gnome.c +++ b/gnucash/register/register-gnome/completioncell-gnome.c @@ -666,6 +666,10 @@ gnc_completion_cell_modify_verify (BasicCell* bcell, box->stop_searching = FALSE; } + // Are were deleting or inserting in the middle. + if (change == NULL || *cursor_position < bcell->value_chars) + *start_selection = *end_selection = *cursor_position; + populate_list_store (cell, newval); if (g_strcmp0 (newval, "") == 0) From 59ec7e4613c6f1213424c87eece836b4cac53790 Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Mon, 19 Jun 2023 09:43:19 +0100 Subject: [PATCH 2/4] Change the search text to be up to the cursor position When editing an existing entry, similar descriptions would not show so instead of using the whole of the description text to search on just use the portion up to the cursor. --- gnucash/register/register-gnome/completioncell-gnome.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gnucash/register/register-gnome/completioncell-gnome.c b/gnucash/register/register-gnome/completioncell-gnome.c index 6136200854..75ed61d2e2 100644 --- a/gnucash/register/register-gnome/completioncell-gnome.c +++ b/gnucash/register/register-gnome/completioncell-gnome.c @@ -670,7 +670,9 @@ gnc_completion_cell_modify_verify (BasicCell* bcell, if (change == NULL || *cursor_position < bcell->value_chars) *start_selection = *end_selection = *cursor_position; - populate_list_store (cell, newval); + gchar *start_of_text = g_utf8_substring (newval, 0, *cursor_position); + populate_list_store (cell, start_of_text); + g_free (start_of_text); if (g_strcmp0 (newval, "") == 0) { From 0449b73e960c62be134265329af160b291273d92 Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Mon, 19 Jun 2023 09:51:58 +0100 Subject: [PATCH 3/4] Bug 798960 - Transaction completion horizontal scrolling When a description popup has long text a horizontal scroll bar will be used. If a subsequent popup has short text which does not need a scroll bar, the previous one is still visible so queue a tree view column resize to reevaluate the need for a scroll bar. --- gnucash/register/register-gnome/completioncell-gnome.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnucash/register/register-gnome/completioncell-gnome.c b/gnucash/register/register-gnome/completioncell-gnome.c index 75ed61d2e2..14eb81af50 100644 --- a/gnucash/register/register-gnome/completioncell-gnome.c +++ b/gnucash/register/register-gnome/completioncell-gnome.c @@ -565,6 +565,10 @@ select_first_entry_in_list (PopBox* box) if (!gtk_tree_model_iter_next (model, &iter)) return; + // reset horizontal scrolling + gtk_tree_view_column_queue_resize (gtk_tree_view_get_column ( + box->item_list->tree_view, TEXT_COL)); + gtk_tree_model_get (model, &iter, TEXT_COL, &string, -1); gnc_item_list_select (box->item_list, string); From d4be0d071182e81f98de8a7b6d8e9a5060a8a621 Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Tue, 20 Jun 2023 12:00:03 +0100 Subject: [PATCH 4/4] Bug 798960 - Transaction completion horizontal scrolling This commit is the second part to the bug that will scroll horizontally to where the matching description text is. --- .../register-gnome/completioncell-gnome.c | 110 +++++++++++++++--- 1 file changed, 97 insertions(+), 13 deletions(-) diff --git a/gnucash/register/register-gnome/completioncell-gnome.c b/gnucash/register/register-gnome/completioncell-gnome.c index 14eb81af50..ff3729d72c 100644 --- a/gnucash/register/register-gnome/completioncell-gnome.c +++ b/gnucash/register/register-gnome/completioncell-gnome.c @@ -54,6 +54,7 @@ typedef struct _PopBox GtkListStore* item_store; // the item list store gchar* newval; // string value to find + gint newval_len; // length of string value to find gboolean signals_connected; // list signals connected gboolean list_popped; // list is popped up @@ -76,9 +77,10 @@ typedef struct _PopBox /** Enumeration for the list-store */ enum GncCompletionColumn { - TEXT_COL, //0 - TEXT_MARKUP_COL, //1 - WEIGHT_COL, //2 + TEXT_COL, //0 + TEXT_MARKUP_COL, //1 + WEIGHT_COL, //2 + FOUND_LOCATION_COL, //3 }; static void gnc_completion_cell_gui_realize (BasicCell* bcell, gpointer w); @@ -116,8 +118,8 @@ gnc_completion_cell_init (CompletionCell* cell) box->sheet = NULL; box->item_edit = NULL; box->item_list = NULL; - box->item_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_INT); + box->item_store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INT, G_TYPE_INT); box->signals_connected = FALSE; box->list_popped = FALSE; box->autosize = FALSE; @@ -156,6 +158,52 @@ select_item_cb (GncItemList* item_list, char* item_string, gpointer user_data) hide_popup (box); } +static gint +text_width (PangoLayout *layout) +{ + PangoRectangle logical_rect; + pango_layout_set_width (layout, -1); + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + return logical_rect.width; +} + +static void +horizontal_scroll_to_found_text (PopBox* box, char* item_string, gint found_location) +{ + GtkAllocation alloc; + gtk_widget_get_allocation (GTK_WIDGET(box->item_list->tree_view), &alloc); + gint scroll_point = 0; + gchar *start_string = g_utf8_substring (item_string, 0, found_location + box->newval_len); + + PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET(box->item_list->tree_view), item_string); + PangoAttrList *atlist = pango_attr_list_new (); + PangoAttribute *bold_weight = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + bold_weight->start_index = found_location; + bold_weight->end_index = found_location + box->newval_len; + pango_attr_list_insert (atlist, bold_weight); + pango_layout_set_attributes (layout, atlist); + + gint item_string_width = text_width (layout); + + pango_layout_set_text (layout, start_string, -1); + + gint start_string_width = text_width (layout); + + pango_attr_list_unref (atlist); + g_object_unref (layout); + g_free (start_string); + + if (item_string_width <= alloc.width) + scroll_point = 0; + else + scroll_point = start_string_width - alloc.width / 2; + + if (scroll_point < 0) + scroll_point = 0; + + gtk_tree_view_scroll_to_point (box->item_list->tree_view, scroll_point, -1); +} + static void change_item_cb (GncItemList* item_list, char* item_string, gpointer user_data) { @@ -165,6 +213,16 @@ change_item_cb (GncItemList* item_list, char* item_string, gpointer user_data) box->in_list_select = TRUE; gnucash_sheet_modify_current_cell (box->sheet, item_string); box->in_list_select = FALSE; + + GtkTreeModel *model = gtk_tree_view_get_model (item_list->tree_view); + GtkTreeSelection *selection = gtk_tree_view_get_selection (item_list->tree_view); + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gint found_location; + gtk_tree_model_get (model, &iter, FOUND_LOCATION_COL, &found_location, -1); + horizontal_scroll_to_found_text (box, item_string, found_location); + } } static void @@ -434,7 +492,7 @@ gnc_completion_cell_set_value (CompletionCell* cell, const char* str) static inline void list_store_append (GtkListStore *store, char* string, - char* markup, gint weight) + char* markup, gint weight, gint found_location) { GtkTreeIter iter; @@ -446,7 +504,8 @@ list_store_append (GtkListStore *store, char* string, gtk_list_store_set (store, &iter, TEXT_COL, string, TEXT_MARKUP_COL, markup, - WEIGHT_COL, weight, -1); + WEIGHT_COL, weight, + FOUND_LOCATION_COL, found_location, -1); } static char* @@ -514,7 +573,7 @@ test_and_add (PopBox* box, const gchar *text, gint start_pos, if (g_strcmp0 (sub_text_norm_fold, box->newval) == 0) // exact match weight = 1; - list_store_append (box->item_store, key, markup, weight); + list_store_append (box->item_store, key, markup, weight, found_location); } g_free (markup); g_free (prefix); @@ -565,10 +624,6 @@ select_first_entry_in_list (PopBox* box) if (!gtk_tree_model_iter_next (model, &iter)) return; - // reset horizontal scrolling - gtk_tree_view_column_queue_resize (gtk_tree_view_get_column ( - box->item_list->tree_view, TEXT_COL)); - gtk_tree_model_get (model, &iter, TEXT_COL, &string, -1); gnc_item_list_select (box->item_list, string); @@ -595,6 +650,8 @@ populate_list_store (CompletionCell* cell, const gchar* str) else return; + box->newval_len = g_utf8_strlen (str, -1); + // disconnect list store from tree view box->item_store = gnc_item_list_disconnect_store (box->item_list); @@ -607,7 +664,7 @@ populate_list_store (CompletionCell* cell, const gchar* str) // add the don't first entry gchar *markup = g_markup_printf_escaped ("%s", DONT_TEXT); - list_store_append (box->item_store, DONT_TEXT, markup, 0); + list_store_append (box->item_store, DONT_TEXT, markup, 0, 0); g_free (markup); // add to the list store @@ -621,6 +678,10 @@ populate_list_store (CompletionCell* cell, const gchar* str) // reconnect list store to tree view gnc_item_list_connect_store (box->item_list, box->item_store); + // reset horizontal scrolling + gtk_tree_view_column_queue_resize (gtk_tree_view_get_column ( + box->item_list->tree_view, TEXT_COL)); + // if no entries, do not show popup if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL(box->item_store), NULL) == 1) { @@ -892,6 +953,26 @@ popup_get_width (GtkWidget* widget, return alloc.width; } +static void +tree_view_size_allocate_cb (GtkWidget *widget, + G_GNUC_UNUSED GtkAllocation *allocation, + gpointer user_data) +{ + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW(widget)); + GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(widget)); + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + PopBox* box = user_data; + gint found_location; + gchar *item_text; + gtk_tree_model_get (model, &iter, TEXT_COL, &item_text, + FOUND_LOCATION_COL, &found_location, -1); + horizontal_scroll_to_found_text (box, item_text, found_location); + g_free (item_text); + } +} + static gboolean gnc_completion_cell_enter (BasicCell* bcell, int* cursor_position, @@ -918,6 +999,9 @@ gnc_completion_cell_enter (BasicCell* bcell, gtk_tree_view_column_add_attribute (column, box->item_list->renderer, "markup", TEXT_MARKUP_COL); + g_signal_connect (G_OBJECT(box->item_list->tree_view), "size-allocate", + G_CALLBACK(tree_view_size_allocate_cb), box); + completion_connect_signals (cell); *cursor_position = -1;