2009-03-12 Alberto Garcia <agarcia@igalia.com>
[hildon] / src / hildon-entry.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2008 Nokia Corporation, all rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser Public License as published by
8  * the Free Software Foundation; version 2 of the license.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser Public License for more details.
14  *
15  */
16
17 /**
18  * SECTION:hildon-entry
19  * @short_description: Widget representing a text entry in the Hildon framework.
20  *
21  * The #HildonEntry is a GTK widget which represents a text entry. It
22  * is derived from the #GtkEntry widget and provides additional
23  * commodities specific to the Hildon framework.
24  *
25  * Besides all the features inherited from #GtkEntry, a #HildonEntry
26  * can also have a placeholder text. This text will be shown if the
27  * entry is empty and doesn't have the input focus, but it's otherwise
28  * ignored. Thus, calls to hildon_entry_get_text() will never return
29  * the placeholder text, not even when it's being displayed.
30  *
31  * Although #HildonEntry is derived from #GtkEntry,
32  * gtk_entry_get_text() and gtk_entry_set_text() must never be used to
33  * get/set the text in this widget. hildon_entry_get_text() and
34  * hildon_entry_set_text() must be used instead.
35  *
36  * <example>
37  * <title>Creating a HildonEntry with a placeholder</title>
38  * <programlisting>
39  * GtkWidget *
40  * create_entry (void)
41  * {
42  *     GtkWidget *entry;
43  * <!-- -->
44  *     entry = hildon_entry_new (HILDON_SIZE_AUTO);
45  *     hildon_entry_set_placeholder (HILDON_ENTRY (entry), "First name");
46  * <!-- -->
47  *     return entry;
48  * }
49  * </programlisting>
50  * </example>
51  */
52
53 #include                                        "hildon-entry.h"
54 #include                                        "hildon-helper.h"
55
56 G_DEFINE_TYPE                                   (HildonEntry, hildon_entry, GTK_TYPE_ENTRY);
57
58 #define                                         HILDON_ENTRY_GET_PRIVATE(obj) \
59                                                 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
60                                                 HILDON_TYPE_ENTRY, HildonEntryPrivate));
61
62 struct                                          _HildonEntryPrivate
63 {
64     gchar *placeholder;
65     gboolean showing_placeholder;
66 };
67
68 /* Function used to decide whether to show the placeholder or not */
69 static void
70 hildon_entry_refresh_contents                   (GtkWidget *entry)
71 {
72     HildonEntryPrivate *priv = HILDON_ENTRY (entry)->priv;
73     gboolean entry_has_focus;
74
75     entry_has_focus = GTK_WIDGET_HAS_FOCUS (entry);
76
77     if (priv->showing_placeholder) {
78         if (entry_has_focus) {
79             /* Remove the placeholder when the widget obtains focus */
80             hildon_helper_set_logical_color (entry, GTK_RC_TEXT, GTK_STATE_NORMAL, "ReversedTextColor");
81             priv->showing_placeholder = FALSE;
82             gtk_entry_set_text (GTK_ENTRY (entry), "");
83         } else {
84             /* Update the placeholder (it may have been changed) */
85             gtk_entry_set_text (GTK_ENTRY (entry), priv->placeholder);
86         }
87     } else {
88         /* Show the placeholder when the widget is empty and has no focus */
89         const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
90         if (text[0] == '\0' && !entry_has_focus) {
91             if (priv->placeholder[0] != '\0') {
92                 hildon_helper_set_logical_color (entry, GTK_RC_TEXT, GTK_STATE_NORMAL, "SecondaryTextColor");
93                 priv->showing_placeholder = TRUE;
94                 gtk_entry_set_text (GTK_ENTRY (entry), priv->placeholder);
95             }
96         }
97     }
98 }
99
100 /**
101  * hildon_entry_set_text:
102  * @entry: a #HildonEntry
103  * @text: the new text
104  *
105  * Sets the text in @entry to @text, replacing its current contents.
106  *
107  * Note that you must never use gtk_entry_set_text() to set the text
108  * of a #HildonEntry.
109  *
110  * Since: 2.2
111  */
112 void
113 hildon_entry_set_text                           (HildonEntry *entry,
114                                                  const gchar *text)
115 {
116     g_return_if_fail (HILDON_IS_ENTRY (entry) && text != NULL);
117
118     gtk_widget_set_name (GTK_WIDGET (entry), NULL);
119     gtk_entry_set_text (GTK_ENTRY (entry), text);
120
121     /* If the entry is cleared show the placeholder */
122     if (text[0] == '\0')
123         hildon_entry_refresh_contents (GTK_WIDGET (entry));
124 }
125
126 /**
127  * hildon_entry_get_text:
128  * @entry: a #HildonEntry
129  *
130  * Gets the current text in @entry.
131  *
132  * Note that you must never use gtk_entry_get_text() to get the text
133  * from a #HildonEntry.
134  *
135  * Also note that placeholder text (set using
136  * hildon_entry_set_placeholder()) is never returned. Only text set by
137  * hildon_entry_set_text() or typed by the user is considered.
138  *
139  * Returns: the text in @entry. This text must not be modified or
140  * freed.
141  *
142  * Since: 2.2
143  */
144 const gchar *
145 hildon_entry_get_text                           (HildonEntry *entry)
146 {
147     g_return_val_if_fail (HILDON_IS_ENTRY (entry), NULL);
148
149     if (entry->priv->showing_placeholder) {
150         return "";
151     }
152
153     return gtk_entry_get_text (GTK_ENTRY (entry));
154 }
155
156 /**
157  * hildon_entry_set_placeholder:
158  * @entry: a #HildonEntry
159  * @text: the new text
160  *
161  * Sets the placeholder text in @entry to @text.
162  *
163  * Since: 2.2
164  */
165 void
166 hildon_entry_set_placeholder                    (HildonEntry *entry,
167                                                  const gchar *text)
168 {
169     g_return_if_fail (HILDON_IS_ENTRY (entry) && text != NULL);
170
171     g_free (entry->priv->placeholder);
172     entry->priv->placeholder = g_strdup (text);
173     hildon_entry_refresh_contents (GTK_WIDGET (entry));
174 }
175
176 /**
177  * hildon_entry_new:
178  * @size: The size of the entry
179  *
180  * Creates a new entry.
181  *
182  * Returns: a new #HildonEntry
183  *
184  * Since: 2.2
185  */
186 GtkWidget *
187 hildon_entry_new                                (HildonSizeType size)
188 {
189     GtkWidget *entry = g_object_new (HILDON_TYPE_ENTRY, NULL);
190
191     hildon_gtk_widget_set_theme_size (entry, size);
192
193     return entry;
194 }
195
196 static gboolean
197 hildon_entry_focus_in_event                     (GtkWidget     *widget,
198                                                  GdkEventFocus *event)
199 {
200     hildon_entry_refresh_contents (widget);
201
202     if (GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_in_event) {
203         return GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_in_event (widget, event);
204     } else {
205         return FALSE;
206     }
207 }
208
209 static gboolean
210 hildon_entry_focus_out_event                    (GtkWidget     *widget,
211                                                  GdkEventFocus *event)
212 {
213     hildon_entry_refresh_contents (widget);
214
215     if (GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_out_event) {
216         return GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_out_event (widget, event);
217     } else {
218         return FALSE;
219     }
220 }
221
222 static void
223 hildon_entry_finalize                           (GObject *object)
224 {
225     HildonEntryPrivate *priv = HILDON_ENTRY (object)->priv;
226
227     g_free (priv->placeholder);
228
229     if (G_OBJECT_CLASS (hildon_entry_parent_class)->finalize)
230         G_OBJECT_CLASS (hildon_entry_parent_class)->finalize (object);
231 }
232
233 static void
234 hildon_entry_class_init                         (HildonEntryClass *klass)
235 {
236     GObjectClass *gobject_class = (GObjectClass *)klass;
237     GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
238
239     gobject_class->finalize = hildon_entry_finalize;
240     widget_class->focus_in_event = hildon_entry_focus_in_event;
241     widget_class->focus_out_event = hildon_entry_focus_out_event;
242
243     g_type_class_add_private (klass, sizeof (HildonEntryPrivate));
244 }
245
246 static void
247 hildon_entry_init                               (HildonEntry *self)
248 {
249     self->priv = HILDON_ENTRY_GET_PRIVATE (self);
250     self->priv->placeholder = g_strdup ("");
251     self->priv->showing_placeholder = FALSE;
252 }