diff options
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | gtk/gtkentry.c | 43 | ||||
-rw-r--r-- | gtk/gtkentrycompletion.c | 154 | ||||
-rw-r--r-- | gtk/gtkentrycompletion.h | 10 | ||||
-rw-r--r-- | gtk/gtkentryprivate.h | 2 |
5 files changed, 216 insertions, 9 deletions
@@ -1,3 +1,19 @@ +2007-04-27 Xan Lopez <xan@gnome.org> + + Support inline-selection in entries (#318459) + + * gtk/gtkentry.c: + * gtk/gtkentrycompletion.c: + * gtk/gtkentrycompletion.h: + * gtk/gtkentryprivate.h: + + When enabled cursor-match is emited when the cursor is on + a possible completion on the list. The default implementation + will replace the contents on the entry with the contents of + the text column in the completion model. + + Review and improvements by Matthias Clasen. + 2007-04-27 Michael Natterer <mitch@imendio.com> Merged heavily modified patch from maemo-gtk which enables opening diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index e6653d1a0d..992ac6f00b 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -5679,6 +5679,22 @@ gtk_entry_completion_key_press (GtkWidget *widget, path = gtk_tree_path_new_from_indices (completion->priv->current_selected, -1); gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->tree_view), path, NULL, FALSE); + + if (completion->priv->inline_selection) + { + + GtkTreeIter iter; + GtkTreeModel *model = NULL; + GtkTreeSelection *sel; + gboolean entry_set; + + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)); + if (!gtk_tree_selection_get_selected (sel, &model, &iter)) + return FALSE; + + g_signal_emit_by_name (completion, "cursor_on_match", model, + &iter, &entry_set); + } } else if (completion->priv->current_selected - matches >= 0) { @@ -5693,11 +5709,23 @@ gtk_entry_completion_key_press (GtkWidget *widget, return TRUE; } - else if (event->keyval == GDK_Escape) + else if (event->keyval == GDK_Escape || + event->keyval == GDK_Left || + event->keyval == GDK_KP_Left || + event->keyval == GDK_Right || + event->keyval == GDK_KP_Right) { _gtk_entry_reset_im_context (GTK_ENTRY (widget)); _gtk_entry_completion_popdown (completion); + if (completion->priv->inline_selection) + { + if (event->keyval == GDK_Escape) + gtk_editable_delete_selection (GTK_EDITABLE (widget)); + /* Move the cursor to the end */ + gtk_editable_set_position (GTK_EDITABLE (widget), -1); + } + return TRUE; } else if (event->keyval == GDK_Tab || @@ -5750,7 +5778,7 @@ gtk_entry_completion_key_press (GtkWidget *widget, /* move the cursor to the end */ gtk_editable_set_position (GTK_EDITABLE (widget), -1); - g_free (str); + g_free (str); } return TRUE; @@ -5880,12 +5908,18 @@ disconnect_completion_signals (GtkEntry *entry, G_CALLBACK (completion_changed), entry); if (completion->priv->changed_id > 0 && g_signal_handler_is_connected (entry, completion->priv->changed_id)) - g_signal_handler_disconnect (entry, completion->priv->changed_id); + { + g_signal_handler_disconnect (entry, completion->priv->changed_id); + completion->priv->changed_id = 0; + } g_signal_handlers_disconnect_by_func (entry, G_CALLBACK (gtk_entry_completion_key_press), completion); if (completion->priv->insert_text_id > 0 && g_signal_handler_is_connected (entry, completion->priv->insert_text_id)) - g_signal_handler_disconnect (entry, completion->priv->insert_text_id); + { + g_signal_handler_disconnect (entry, completion->priv->insert_text_id); + completion->priv->insert_text_id = 0; + } g_signal_handlers_disconnect_by_func (entry, G_CALLBACK (completion_insert_text_callback), completion); g_signal_handlers_disconnect_by_func (entry, @@ -5919,6 +5953,7 @@ connect_completion_signals (GtkEntry *entry, g_signal_connect (entry, "focus_out_event", G_CALLBACK (accept_completion_callback), completion); } + g_signal_connect (completion, "notify", G_CALLBACK (completion_changed), entry); } diff --git a/gtk/gtkentrycompletion.c b/gtk/gtkentrycompletion.c index d8bc08a06a..f4d74d62f4 100644 --- a/gtk/gtkentrycompletion.c +++ b/gtk/gtkentrycompletion.c @@ -47,6 +47,7 @@ enum INSERT_PREFIX, MATCH_SELECTED, ACTION_ACTIVATED, + CURSOR_ON_MATCH, LAST_SIGNAL }; @@ -60,7 +61,8 @@ enum PROP_INLINE_COMPLETION, PROP_POPUP_COMPLETION, PROP_POPUP_SET_WIDTH, - PROP_POPUP_SINGLE_MATCH + PROP_POPUP_SINGLE_MATCH, + PROP_INLINE_SELECTION }; #define GTK_ENTRY_COMPLETION_GET_PRIVATE(obj)(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY_COMPLETION, GtkEntryCompletionPrivate)) @@ -136,6 +138,9 @@ static gboolean gtk_entry_completion_match_selected (GtkEntryCompletion *co GtkTreeIter *iter); static gboolean gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion, const gchar *prefix); +static gboolean gtk_entry_completion_cursor_on_match (GtkEntryCompletion *completion, + GtkTreeModel *model, + GtkTreeIter *iter); static guint entry_completion_signals[LAST_SIGNAL] = { 0 }; @@ -156,6 +161,7 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass) klass->match_selected = gtk_entry_completion_match_selected; klass->insert_prefix = gtk_entry_completion_real_insert_prefix; + klass->cursor_on_match = gtk_entry_completion_cursor_on_match; /** * GtkEntryCompletion::insert-prefix: @@ -210,6 +216,32 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass) G_TYPE_BOOLEAN, 2, GTK_TYPE_TREE_MODEL, GTK_TYPE_TREE_ITER); + /** + * GtkEntryCompletion::cursor-on-match: + * @widget: the object which received the signal + * @model: the #GtkTreeModel containing the matches + * @iter: a #GtkTreeIter positioned at the selected match + * + * Gets emitted when a match from the cursor is on a match + * of the list.The default behaviour is to replace the contents + * of the entry with the contents of the text column in the row + * pointed to by @iter. + * + * Return value: %TRUE if the signal has been handled + * + * Since: 2.12 + */ + + entry_completion_signals[CURSOR_ON_MATCH] = + g_signal_new (I_("cursor_on_match"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkEntryCompletionClass, cursor_on_match), + _gtk_boolean_handled_accumulator, NULL, + _gtk_marshal_BOOLEAN__OBJECT_BOXED, + G_TYPE_BOOLEAN, 2, + GTK_TYPE_TREE_MODEL, + GTK_TYPE_TREE_ITER); /** * GtkEntryCompletion::action-activated: @@ -330,6 +362,21 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass) P_("If TRUE, the popup window will appear for a single match."), TRUE, GTK_PARAM_READWRITE)); + /** + * GtkEntryCompletion:inline-selection: + * + * Determines whether the possible completions on the popup + * will appear in the entry as you navigate through them. + + * Since: 2.12 + */ + g_object_class_install_property (object_class, + PROP_INLINE_SELECTION, + g_param_spec_boolean ("inline-selection", + P_("Inline selection"), + P_("Your description here"), + FALSE, + GTK_PARAM_READWRITE)); g_type_class_add_private (object_class, sizeof (GtkEntryCompletionPrivate)); } @@ -364,6 +411,7 @@ gtk_entry_completion_init (GtkEntryCompletion *completion) priv->popup_completion = TRUE; priv->popup_set_width = TRUE; priv->popup_single_match = TRUE; + priv->inline_selection = FALSE; /* completions */ priv->filter_model = NULL; @@ -378,6 +426,7 @@ gtk_entry_completion_init (GtkEntryCompletion *completion) g_signal_connect (priv->tree_view, "motion_notify_event", G_CALLBACK (gtk_entry_completion_list_motion_notify), completion); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE); gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->tree_view), TRUE); @@ -505,6 +554,10 @@ gtk_entry_completion_set_property (GObject *object, priv->popup_single_match = g_value_get_boolean (value); break; + case PROP_INLINE_SELECTION: + priv->inline_selection = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -550,6 +603,10 @@ gtk_entry_completion_get_property (GObject *object, g_value_set_boolean (value, gtk_entry_completion_get_popup_single_match (completion)); break; + case PROP_INLINE_SELECTION: + g_value_set_boolean (value, gtk_entry_completion_get_inline_selection (completion)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1277,7 +1334,7 @@ gtk_entry_completion_list_motion_notify (GtkWidget *widget, { GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data); - completion->priv->ignore_enter = FALSE; + completion->priv->ignore_enter = FALSE; return FALSE; } @@ -1468,6 +1525,15 @@ gtk_entry_completion_match_selected (GtkEntryCompletion *completion, return TRUE; } +static gboolean +gtk_entry_completion_cursor_on_match (GtkEntryCompletion *completion, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gtk_entry_completion_insert_completion (completion, model, iter); + + return TRUE; +} static gchar * gtk_entry_completion_compute_prefix (GtkEntryCompletion *completion) @@ -1565,6 +1631,65 @@ gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion, return TRUE; } +void +gtk_entry_completion_insert_completion_text (GtkEntryCompletion *completion, + const gchar *text) +{ + GtkEntryCompletionPrivate *priv = completion->priv; + gint len; + + if (priv->changed_id > 0) + { + g_signal_handler_block (priv->entry, + priv->changed_id); + } + + if (priv->insert_text_id > 0) + { + g_signal_handler_block (completion->priv->entry, + completion->priv->insert_text_id); + } + + gtk_editable_get_selection_bounds (GTK_EDITABLE (priv->entry), &len, NULL); + gtk_entry_set_text (GTK_ENTRY (priv->entry), text); + gtk_editable_select_region (GTK_EDITABLE (priv->entry), len, -1); + + if (priv->changed_id > 0) + { + g_signal_handler_unblock (priv->entry, + priv->changed_id); + } + + if (priv->insert_text_id > 0) + { + g_signal_handler_unblock (priv->entry, + priv->insert_text_id); + } +} + +gboolean +gtk_entry_completion_insert_completion (GtkEntryCompletion *completion, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gchar *str = NULL; + + g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE); + + if (completion->priv->text_column < 0) + return FALSE; + + gtk_tree_model_get (model, iter, + completion->priv->text_column, &str, + -1); + + gtk_entry_completion_insert_completion_text (completion, str); + + g_free (str); + + return TRUE; +} + /** * gtk_entry_completion_insert_prefix: * @completion: a #GtkEntryCompletion @@ -1573,6 +1698,7 @@ gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion, * * Since: 2.6 **/ + void gtk_entry_completion_insert_prefix (GtkEntryCompletion *completion) { @@ -1622,7 +1748,6 @@ gtk_entry_completion_set_inline_completion (GtkEntryCompletion *completion, } } - /** * gtk_entry_completion_get_inline_completion: * @completion: a #GtkEntryCompletion @@ -1782,6 +1907,29 @@ gtk_entry_completion_get_popup_single_match (GtkEntryCompletion *completion) return completion->priv->popup_single_match; } +void +gtk_entry_completion_set_inline_selection (GtkEntryCompletion *completion, + gboolean inline_selection) +{ + g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion)); + + inline_selection = inline_selection != FALSE; + + if (completion->priv->inline_selection != inline_selection) + { + completion->priv->inline_selection = inline_selection; + + g_object_notify (G_OBJECT (completion), "inline-selection"); + } +} + +gboolean +gtk_entry_completion_get_inline_selection (GtkEntryCompletion *completion) +{ + g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE); + + return completion->priv->inline_selection; +} #define __GTK_ENTRY_COMPLETION_C__ #include "gtkaliasdef.c" diff --git a/gtk/gtkentrycompletion.h b/gtk/gtkentrycompletion.h index 01a40fd957..26285d2ac6 100644 --- a/gtk/gtkentrycompletion.h +++ b/gtk/gtkentrycompletion.h @@ -65,11 +65,13 @@ struct _GtkEntryCompletionClass gint index_); gboolean (* insert_prefix) (GtkEntryCompletion *completion, const gchar *prefix); + gboolean (* cursor_on_match) (GtkEntryCompletion *completion, + GtkTreeModel *model, + GtkTreeIter *iter); /* Padding for future expansion */ void (*_gtk_reserved0) (void); void (*_gtk_reserved1) (void); - void (*_gtk_reserved2) (void); }; /* core */ @@ -104,6 +106,9 @@ void gtk_entry_completion_delete_action (GtkEntryComplet void gtk_entry_completion_set_inline_completion (GtkEntryCompletion *completion, gboolean inline_completion); gboolean gtk_entry_completion_get_inline_completion (GtkEntryCompletion *completion); +void gtk_entry_completion_set_inline_selection (GtkEntryCompletion *completion, + gboolean inline_selection); +gboolean gtk_entry_completion_get_inline_selection (GtkEntryCompletion *completion); void gtk_entry_completion_set_popup_completion (GtkEntryCompletion *completion, gboolean popup_completion); gboolean gtk_entry_completion_get_popup_completion (GtkEntryCompletion *completion); @@ -114,7 +119,8 @@ void gtk_entry_completion_set_popup_single_match (GtkEntryComplet gboolean popup_single_match); gboolean gtk_entry_completion_get_popup_single_match (GtkEntryCompletion *completion); - +void gtk_entry_completion_insert_completion_text (GtkEntryCompletion *completion, + const gchar *text); /* convenience */ void gtk_entry_completion_set_text_column (GtkEntryCompletion *completion, gint column); diff --git a/gtk/gtkentryprivate.h b/gtk/gtkentryprivate.h index 6589a0c201..696f744401 100644 --- a/gtk/gtkentryprivate.h +++ b/gtk/gtkentryprivate.h @@ -64,6 +64,8 @@ struct _GtkEntryCompletionPrivate guint popup_completion : 1; guint popup_set_width : 1; guint popup_single_match : 1; + guint inline_selection : 1; + GSource *check_completion_idle; }; |