gtkentry: Add hinting to GtkEntry

gtk_entry_set_placeholder_text() makes the entry display the given text
when it is empty and unfocused. Based on previous patch by Alberto
Garcia.

https://bugzilla.gnome.org/show_bug.cgi?id=440963
This commit is contained in:
Carlos Garcia Campos 2011-02-24 13:29:10 +01:00 committed by Carlos Garcia Campos
parent c8350821e9
commit ef061c4e96
5 changed files with 155 additions and 10 deletions

View File

@ -1028,6 +1028,8 @@ gtk_entry_set_width_chars
gtk_entry_get_invisible_char gtk_entry_get_invisible_char
gtk_entry_set_alignment gtk_entry_set_alignment
gtk_entry_get_alignment gtk_entry_get_alignment
gtk_entry_set_placeholder_text
gtk_entry_get_placeholder_text
gtk_entry_set_overwrite_mode gtk_entry_set_overwrite_mode
gtk_entry_get_overwrite_mode gtk_entry_get_overwrite_mode
gtk_entry_get_layout gtk_entry_get_layout

View File

@ -828,6 +828,7 @@ gtk_entry_get_completion
gtk_entry_get_current_icon_drag_source gtk_entry_get_current_icon_drag_source
gtk_entry_get_cursor_hadjustment gtk_entry_get_cursor_hadjustment
gtk_entry_get_has_frame gtk_entry_get_has_frame
gtk_entry_get_placeholder_text
gtk_entry_get_icon_activatable gtk_entry_get_icon_activatable
gtk_entry_get_icon_area gtk_entry_get_icon_area
gtk_entry_get_icon_at_pos gtk_entry_get_icon_at_pos
@ -866,6 +867,7 @@ gtk_entry_set_buffer
gtk_entry_set_completion gtk_entry_set_completion
gtk_entry_set_cursor_hadjustment gtk_entry_set_cursor_hadjustment
gtk_entry_set_has_frame gtk_entry_set_has_frame
gtk_entry_set_placeholder_text
gtk_entry_set_icon_activatable gtk_entry_set_icon_activatable
gtk_entry_set_icon_drag_source gtk_entry_set_icon_drag_source
gtk_entry_set_icon_from_gicon gtk_entry_set_icon_from_gicon

View File

@ -3772,6 +3772,7 @@ gtk_css_provider_get_default (void)
"@define-color selected_fg_color #fff; \n" "@define-color selected_fg_color #fff; \n"
"@define-color tooltip_bg_color #eee1b3; \n" "@define-color tooltip_bg_color #eee1b3; \n"
"@define-color tooltip_fg_color #000; \n" "@define-color tooltip_fg_color #000; \n"
"@define-color placeholder_text_color #808080; \n"
"\n" "\n"
"@define-color info_fg_color rgb (181, 171, 156);\n" "@define-color info_fg_color rgb (181, 171, 156);\n"
"@define-color info_bg_color rgb (252, 252, 189);\n" "@define-color info_bg_color rgb (252, 252, 189);\n"

View File

@ -155,6 +155,8 @@ struct _GtkEntryPrivate
gdouble progress_pulse_fraction; gdouble progress_pulse_fraction;
gdouble progress_pulse_current; gdouble progress_pulse_current;
gchar *placeholder_text;
gfloat xalign; gfloat xalign;
gint ascent; /* font ascent in pango units */ gint ascent; /* font ascent in pango units */
@ -306,7 +308,8 @@ enum {
PROP_TOOLTIP_MARKUP_PRIMARY, PROP_TOOLTIP_MARKUP_PRIMARY,
PROP_TOOLTIP_MARKUP_SECONDARY, PROP_TOOLTIP_MARKUP_SECONDARY,
PROP_IM_MODULE, PROP_IM_MODULE,
PROP_EDITING_CANCELED PROP_EDITING_CANCELED,
PROP_PLACEHOLDER_TEXT
}; };
static guint signals[LAST_SIGNAL] = { 0 }; static guint signals[LAST_SIGNAL] = { 0 };
@ -596,7 +599,6 @@ static void begin_change (GtkEntry *entry);
static void end_change (GtkEntry *entry); static void end_change (GtkEntry *entry);
static void emit_changed (GtkEntry *entry); static void emit_changed (GtkEntry *entry);
static void buffer_inserted_text (GtkEntryBuffer *buffer, static void buffer_inserted_text (GtkEntryBuffer *buffer,
guint position, guint position,
const gchar *chars, const gchar *chars,
@ -619,7 +621,6 @@ static void buffer_connect_signals (GtkEntry *entry);
static void buffer_disconnect_signals (GtkEntry *entry); static void buffer_disconnect_signals (GtkEntry *entry);
static GtkEntryBuffer *get_buffer (GtkEntry *entry); static GtkEntryBuffer *get_buffer (GtkEntry *entry);
G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET, G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
gtk_entry_editable_init) gtk_entry_editable_init)
@ -982,6 +983,21 @@ gtk_entry_class_init (GtkEntryClass *class)
0.1, 0.1,
GTK_PARAM_READWRITE)); 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: * GtkEntry:primary-icon-pixbuf:
* *
@ -1967,6 +1983,10 @@ gtk_entry_set_property (GObject *object,
gtk_entry_set_progress_pulse_step (entry, g_value_get_double (value)); gtk_entry_set_progress_pulse_step (entry, g_value_get_double (value));
break; break;
case PROP_PLACEHOLDER_TEXT:
gtk_entry_set_placeholder_text (entry, g_value_get_string (value));
break;
case PROP_PIXBUF_PRIMARY: case PROP_PIXBUF_PRIMARY:
gtk_entry_set_icon_from_pixbuf (entry, gtk_entry_set_icon_from_pixbuf (entry,
GTK_ENTRY_ICON_PRIMARY, GTK_ENTRY_ICON_PRIMARY,
@ -2185,6 +2205,10 @@ gtk_entry_get_property (GObject *object,
g_value_set_double (value, priv->progress_pulse_fraction); g_value_set_double (value, priv->progress_pulse_fraction);
break; break;
case PROP_PLACEHOLDER_TEXT:
g_value_set_string (value, gtk_entry_get_placeholder_text (entry));
break;
case PROP_PIXBUF_PRIMARY: case PROP_PIXBUF_PRIMARY:
g_value_set_object (value, g_value_set_object (value,
gtk_entry_get_icon_pixbuf (entry, gtk_entry_get_icon_pixbuf (entry,
@ -2581,6 +2605,7 @@ gtk_entry_finalize (GObject *object)
if (priv->recompute_idle) if (priv->recompute_idle)
g_source_remove (priv->recompute_idle); g_source_remove (priv->recompute_idle);
g_free (priv->placeholder_text);
g_free (priv->im_module); g_free (priv->im_module);
G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object); 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); return g_string_free (str, FALSE);
} }
} }
static void static void
@ -4191,8 +4215,16 @@ gtk_entry_focus_in (GtkWidget *widget,
g_signal_connect (keymap, "direction-changed", g_signal_connect (keymap, "direction-changed",
G_CALLBACK (keymap_direction_changed), entry); G_CALLBACK (keymap_direction_changed), 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_reset_blink_time (entry);
gtk_entry_check_cursor_blink (entry); gtk_entry_check_cursor_blink (entry);
}
return FALSE; return FALSE;
} }
@ -4217,7 +4249,15 @@ gtk_entry_focus_out (GtkWidget *widget,
remove_capslock_feedback (entry); remove_capslock_feedback (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); 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_state_changed, entry);
g_signal_handlers_disconnect_by_func (keymap, keymap_direction_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 * static PangoLayout *
gtk_entry_create_layout (GtkEntry *entry, gtk_entry_create_layout (GtkEntry *entry,
gboolean include_preedit) gboolean include_preedit)
@ -5402,6 +5471,7 @@ gtk_entry_create_layout (GtkEntry *entry,
GtkWidget *widget = GTK_WIDGET (entry); GtkWidget *widget = GTK_WIDGET (entry);
PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL); PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL);
PangoAttrList *tmp_attrs = pango_attr_list_new (); PangoAttrList *tmp_attrs = pango_attr_list_new ();
gboolean placeholder_layout = show_placeholder_text (entry);
gchar *preedit_string = NULL; gchar *preedit_string = NULL;
gint preedit_length = 0; gint preedit_length = 0;
@ -5412,15 +5482,26 @@ gtk_entry_create_layout (GtkEntry *entry,
pango_layout_set_single_paragraph_mode (layout, TRUE); 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); n_bytes = strlen (display);
if (include_preedit) if (!placeholder_layout && include_preedit)
{ {
gtk_im_context_get_preedit_string (priv->im_context, gtk_im_context_get_preedit_string (priv->im_context,
&preedit_string, &preedit_attrs, NULL); &preedit_string, &preedit_attrs, NULL);
preedit_length = priv->preedit_length; 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) if (preedit_length)
{ {
@ -10132,6 +10213,61 @@ gtk_entry_progress_pulse (GtkEntry *entry)
gtk_widget_queue_draw (GTK_WIDGET (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 */ /* Caps Lock warning for password entries */
static void static void

View File

@ -213,6 +213,10 @@ gdouble gtk_entry_get_progress_pulse_step (GtkEntry *entry);
void gtk_entry_progress_pulse (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 /* Setting and managing icons
*/ */
void gtk_entry_set_icon_from_pixbuf (GtkEntry *entry, void gtk_entry_set_icon_from_pixbuf (GtkEntry *entry,