diff options
-rw-r--r-- | docs/reference/gtk/gtk3-sections.txt | 2 | ||||
-rw-r--r-- | gtk/gtk.symbols | 2 | ||||
-rw-r--r-- | gtk/gtkcssprovider.c | 1 | ||||
-rw-r--r-- | gtk/gtkentry.c | 156 | ||||
-rw-r--r-- | gtk/gtkentry.h | 4 |
5 files changed, 155 insertions, 10 deletions
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index 5336a3f69a..024645afd3 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -1028,6 +1028,8 @@ gtk_entry_set_width_chars gtk_entry_get_invisible_char gtk_entry_set_alignment gtk_entry_get_alignment +gtk_entry_set_placeholder_text +gtk_entry_get_placeholder_text gtk_entry_set_overwrite_mode gtk_entry_get_overwrite_mode gtk_entry_get_layout diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 31ecfc429a..39485e0687 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -828,6 +828,7 @@ gtk_entry_get_completion gtk_entry_get_current_icon_drag_source gtk_entry_get_cursor_hadjustment gtk_entry_get_has_frame +gtk_entry_get_placeholder_text gtk_entry_get_icon_activatable gtk_entry_get_icon_area gtk_entry_get_icon_at_pos @@ -866,6 +867,7 @@ gtk_entry_set_buffer gtk_entry_set_completion gtk_entry_set_cursor_hadjustment gtk_entry_set_has_frame +gtk_entry_set_placeholder_text gtk_entry_set_icon_activatable gtk_entry_set_icon_drag_source gtk_entry_set_icon_from_gicon diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c index 51cec89e97..9557a33bf0 100644 --- a/gtk/gtkcssprovider.c +++ b/gtk/gtkcssprovider.c @@ -3772,6 +3772,7 @@ gtk_css_provider_get_default (void) "@define-color selected_fg_color #fff; \n" "@define-color tooltip_bg_color #eee1b3; \n" "@define-color tooltip_fg_color #000; \n" + "@define-color placeholder_text_color #808080; \n" "\n" "@define-color info_fg_color rgb (181, 171, 156);\n" "@define-color info_bg_color rgb (252, 252, 189);\n" diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 84f7204470..6dda7ecbf5 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -155,6 +155,8 @@ struct _GtkEntryPrivate gdouble progress_pulse_fraction; gdouble progress_pulse_current; + gchar *placeholder_text; + gfloat xalign; gint ascent; /* font ascent in pango units */ @@ -306,7 +308,8 @@ enum { PROP_TOOLTIP_MARKUP_PRIMARY, PROP_TOOLTIP_MARKUP_SECONDARY, PROP_IM_MODULE, - PROP_EDITING_CANCELED + PROP_EDITING_CANCELED, + PROP_PLACEHOLDER_TEXT }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -596,7 +599,6 @@ static void begin_change (GtkEntry *entry); static void end_change (GtkEntry *entry); static void emit_changed (GtkEntry *entry); - static void buffer_inserted_text (GtkEntryBuffer *buffer, guint position, const gchar *chars, @@ -619,7 +621,6 @@ static void buffer_connect_signals (GtkEntry *entry); static void buffer_disconnect_signals (GtkEntry *entry); static GtkEntryBuffer *get_buffer (GtkEntry *entry); - G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET, G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, gtk_entry_editable_init) @@ -983,6 +984,21 @@ gtk_entry_class_init (GtkEntryClass *class) GTK_PARAM_READWRITE)); /** + * GtkEntry:placeholder-text: + * + * The text that will be displayed in the #GtkEntry when it is empty and unfocused. + * + * Since: 3.2 + */ + g_object_class_install_property (gobject_class, + PROP_PLACEHOLDER_TEXT, + g_param_spec_string ("placeholder-text", + P_("Placeholder text"), + P_("Show text in the entry when it's empty and unfocused"), + NULL, + GTK_PARAM_READWRITE)); + + /** * GtkEntry:primary-icon-pixbuf: * * A pixbuf to use as the primary icon for the entry. @@ -1967,6 +1983,10 @@ gtk_entry_set_property (GObject *object, gtk_entry_set_progress_pulse_step (entry, g_value_get_double (value)); break; + case PROP_PLACEHOLDER_TEXT: + gtk_entry_set_placeholder_text (entry, g_value_get_string (value)); + break; + case PROP_PIXBUF_PRIMARY: gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_PRIMARY, @@ -2185,6 +2205,10 @@ gtk_entry_get_property (GObject *object, g_value_set_double (value, priv->progress_pulse_fraction); break; + case PROP_PLACEHOLDER_TEXT: + g_value_set_string (value, gtk_entry_get_placeholder_text (entry)); + break; + case PROP_PIXBUF_PRIMARY: g_value_set_object (value, gtk_entry_get_icon_pixbuf (entry, @@ -2581,6 +2605,7 @@ gtk_entry_finalize (GObject *object) if (priv->recompute_idle) g_source_remove (priv->recompute_idle); + g_free (priv->placeholder_text); g_free (priv->im_module); G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object); @@ -2667,7 +2692,6 @@ gtk_entry_get_display_text (GtkEntry *entry, return g_string_free (str, FALSE); } - } static void @@ -4191,8 +4215,16 @@ gtk_entry_focus_in (GtkWidget *widget, g_signal_connect (keymap, "direction-changed", G_CALLBACK (keymap_direction_changed), entry); - gtk_entry_reset_blink_time (entry); - gtk_entry_check_cursor_blink (entry); + if (gtk_entry_buffer_get_bytes (get_buffer (entry)) == 0 && + priv->placeholder_text != NULL) + { + gtk_entry_recompute (entry); + } + else + { + gtk_entry_reset_blink_time (entry); + gtk_entry_check_cursor_blink (entry); + } return FALSE; } @@ -4217,8 +4249,16 @@ gtk_entry_focus_out (GtkWidget *widget, remove_capslock_feedback (entry); } - gtk_entry_check_cursor_blink (entry); - + if (gtk_entry_buffer_get_bytes (get_buffer (entry)) == 0 && + priv->placeholder_text != NULL) + { + gtk_entry_recompute (entry); + } + else + { + gtk_entry_check_cursor_blink (entry); + } + g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry); g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, entry); @@ -5394,6 +5434,35 @@ gtk_entry_recompute (GtkEntry *entry) } } +static void +gtk_entry_get_placeholder_text_color (GtkEntry *entry, + PangoColor *color) +{ + GtkWidget *widget = GTK_WIDGET (entry); + GtkStyleContext *context; + GdkRGBA fg = { 0.5, 0.5, 0.5 }; + + context = gtk_widget_get_style_context (widget); + gtk_style_context_lookup_color (context, "placeholder_text_color", &fg); + + color->red = CLAMP (fg.red * 65535. + 0.5, 0, 65535); + color->green = CLAMP (fg.green * 65535. + 0.5, 0, 65535); + color->blue = CLAMP (fg.blue * 65535. + 0.5, 0, 65535); +} + +static inline gboolean +show_placeholder_text (GtkEntry *entry) +{ + GtkEntryPrivate *priv = entry->priv; + + if (!gtk_widget_has_focus (GTK_WIDGET (entry)) && + gtk_entry_buffer_get_bytes (get_buffer (entry)) == 0 && + priv->placeholder_text != NULL) + return TRUE; + + return FALSE; +} + static PangoLayout * gtk_entry_create_layout (GtkEntry *entry, gboolean include_preedit) @@ -5402,6 +5471,7 @@ gtk_entry_create_layout (GtkEntry *entry, GtkWidget *widget = GTK_WIDGET (entry); PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL); PangoAttrList *tmp_attrs = pango_attr_list_new (); + gboolean placeholder_layout = show_placeholder_text (entry); gchar *preedit_string = NULL; gint preedit_length = 0; @@ -5412,15 +5482,26 @@ gtk_entry_create_layout (GtkEntry *entry, pango_layout_set_single_paragraph_mode (layout, TRUE); - display = gtk_entry_get_display_text (entry, 0, -1); + display = placeholder_layout ? g_strdup (priv->placeholder_text) : gtk_entry_get_display_text (entry, 0, -1); n_bytes = strlen (display); - if (include_preedit) + if (!placeholder_layout && include_preedit) { gtk_im_context_get_preedit_string (priv->im_context, &preedit_string, &preedit_attrs, NULL); preedit_length = priv->preedit_length; } + else if (placeholder_layout) + { + PangoColor color; + PangoAttribute *attr; + + gtk_entry_get_placeholder_text_color (entry, &color); + attr = pango_attr_foreground_new (color.red, color.green, color.blue); + attr->start_index = 0; + attr->end_index = G_MAXINT; + pango_attr_list_insert (tmp_attrs, attr); + } if (preedit_length) { @@ -10132,6 +10213,61 @@ gtk_entry_progress_pulse (GtkEntry *entry) gtk_widget_queue_draw (GTK_WIDGET (entry)); } +/** + * gtk_entry_set_placeholder_text: + * @entry: a #GtkEntry + * @text: a string to be displayed when @entry is empty an unfocused, or %NULL + * + * Sets text to be displayed in @entry when + * it is empty and unfocused. This can be used to give a visual hint + * of the expected contents of the #GtkEntry. + * + * Since: 3.2 + **/ +void +gtk_entry_set_placeholder_text (GtkEntry *entry, + const gchar *text) +{ + GtkEntryPrivate *priv; + + g_return_if_fail (GTK_IS_ENTRY (entry)); + + priv = entry->priv; + + if (g_strcmp0 (priv->placeholder_text, text) == 0) + return; + + g_free (priv->placeholder_text); + priv->placeholder_text = g_strdup (text); + + gtk_entry_recompute (entry); + + g_object_notify (G_OBJECT (entry), "placeholder-text"); +} + +/** + * gtk_entry_get_placeholder_text: + * @entry: a #GtkEntry + * + * Retrieves the text that will be displayed when @entry is empty and unfocused + * + * Returns: a pointer to the placeholder text as a string. This string points to internally allocated + * storage in the widget and must not be freed, modified or stored. + * + * Since: 3.2 + **/ +G_CONST_RETURN gchar * +gtk_entry_get_placeholder_text (GtkEntry *entry) +{ + GtkEntryPrivate *priv; + + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); + + priv = entry->priv; + + return priv->placeholder_text; +} + /* Caps Lock warning for password entries */ static void diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h index 3bd37d35f7..2bca501592 100644 --- a/gtk/gtkentry.h +++ b/gtk/gtkentry.h @@ -213,6 +213,10 @@ gdouble gtk_entry_get_progress_pulse_step (GtkEntry *entry); void gtk_entry_progress_pulse (GtkEntry *entry); +G_CONST_RETURN gchar* gtk_entry_get_placeholder_text (GtkEntry *entry); + +void gtk_entry_set_placeholder_text (GtkEntry *entry, + const gchar *text); /* Setting and managing icons */ void gtk_entry_set_icon_from_pixbuf (GtkEntry *entry, |