2008-09-24 Claudio Saavedra <csaavedra@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
55 G_DEFINE_TYPE                                   (HildonEntry, hildon_entry, GTK_TYPE_ENTRY);
56
57 #define                                         HILDON_ENTRY_GET_PRIVATE(obj) \
58                                                 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
59                                                 HILDON_TYPE_ENTRY, HildonEntryPrivate));
60
61 typedef struct                                  _HildonEntryPrivate HildonEntryPrivate;
62
63 struct                                          _HildonEntryPrivate
64 {
65     gchar *placeholder;
66 };
67
68 static const gchar *placeholder_widget_name     = "hildon-entry-placeholder";
69
70 /* Function used to decide whether to show the placeholder or not */
71 static void
72 hildon_entry_refresh_contents                   (GtkWidget *entry)
73 {
74     HildonEntryPrivate *priv = HILDON_ENTRY_GET_PRIVATE (entry);
75     gboolean showing_placeholder, entry_has_focus;
76
77     showing_placeholder = g_str_equal (gtk_widget_get_name (entry), placeholder_widget_name);
78     entry_has_focus = GTK_WIDGET_HAS_FOCUS (entry);
79
80     if (showing_placeholder) {
81         if (entry_has_focus) {
82             /* Remove the placeholder when the widget obtains focus */
83             gtk_widget_set_name (entry, NULL);
84             gtk_entry_set_text (GTK_ENTRY (entry), "");
85         } else {
86             /* Update the placeholder (it may have been changed) */
87             gtk_entry_set_text (GTK_ENTRY (entry), priv->placeholder);
88         }
89     } else {
90         /* Show the placeholder when the widget is empty and has no focus */
91         const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
92         if (text[0] == '\0' && !entry_has_focus) {
93             if (priv->placeholder[0] != '\0') {
94                 gtk_widget_set_name (entry, placeholder_widget_name);
95                 gtk_entry_set_text (GTK_ENTRY (entry), priv->placeholder);
96             }
97         }
98     }
99 }
100
101 /**
102  * hildon_entry_set_text:
103  * @entry: a #HildonEntry
104  * @text: the new text
105  *
106  * Sets the text in @entry to @text, replacing its current contents.
107  *
108  * Note that you must never use gtk_entry_set_text() to set the text
109  * of a #HildonEntry.
110  */
111 void
112 hildon_entry_set_text                           (HildonEntry *entry,
113                                                  const gchar *text)
114 {
115     g_return_if_fail (HILDON_IS_ENTRY (entry) && text != NULL);
116
117     gtk_widget_set_name (GTK_WIDGET (entry), NULL);
118     gtk_entry_set_text (GTK_ENTRY (entry), text);
119
120     /* If the entry is cleared show the placeholder */
121     if (text[0] == '\0')
122         hildon_entry_refresh_contents (GTK_WIDGET (entry));
123 }
124
125 /**
126  * hildon_entry_get_text:
127  * @entry: a #HildonEntry
128  *
129  * Gets the current text in @entry.
130  *
131  * Note that you must never use gtk_entry_get_text() to get the text
132  * from a #HildonEntry.
133  *
134  * Also note that placeholder text (set using
135  * hildon_entry_set_placeholder()) is never returned. Only text set by
136  * hildon_entry_set_text() or typed by the user is considered.
137  *
138  * Returns: the text in @entry. This text must not be modified or
139  * freed.
140  */
141 const gchar *
142 hildon_entry_get_text                           (HildonEntry *entry)
143 {
144     g_return_val_if_fail (HILDON_IS_ENTRY (entry), NULL);
145
146     if (g_str_equal (gtk_widget_get_name (GTK_WIDGET (entry)), placeholder_widget_name)) {
147         return "";
148     }
149
150     return gtk_entry_get_text (GTK_ENTRY (entry));
151 }
152
153 /**
154  * hildon_entry_set_placeholder:
155  * @entry: a #HildonEntry
156  * @text: the new text
157  *
158  * Sets the placeholder text in @entry to @text.
159  */
160 void
161 hildon_entry_set_placeholder                    (HildonEntry *entry,
162                                                  const gchar *text)
163 {
164     HildonEntryPrivate *priv;
165
166     g_return_if_fail (HILDON_IS_ENTRY (entry) && text != NULL);
167
168     priv = HILDON_ENTRY_GET_PRIVATE (entry);
169
170     g_free (priv->placeholder);
171     priv->placeholder = g_strdup (text);
172     hildon_entry_refresh_contents (GTK_WIDGET (entry));
173 }
174
175 /**
176  * hildon_entry_new:
177  * @size: The size of the entry
178  *
179  * Creates a new entry.
180  *
181  * Returns: a new #HildonEntry
182  */
183 GtkWidget *
184 hildon_entry_new                                (HildonSizeType size)
185 {
186     GtkWidget *entry = g_object_new (HILDON_TYPE_ENTRY, NULL);
187
188     hildon_gtk_widget_set_theme_size (entry, size);
189
190     return entry;
191 }
192
193 static gboolean
194 hildon_entry_focus_in_event                     (GtkWidget     *widget,
195                                                  GdkEventFocus *event)
196 {
197     hildon_entry_refresh_contents (widget);
198
199     if (GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_in_event) {
200         return GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_in_event (widget, event);
201     } else {
202         return FALSE;
203     }
204 }
205
206 static gboolean
207 hildon_entry_focus_out_event                    (GtkWidget     *widget,
208                                                  GdkEventFocus *event)
209 {
210     hildon_entry_refresh_contents (widget);
211
212     if (GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_out_event) {
213         return GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_out_event (widget, event);
214     } else {
215         return FALSE;
216     }
217 }
218
219 static void
220 hildon_entry_finalize                           (GObject *object)
221 {
222     HildonEntryPrivate *priv = HILDON_ENTRY_GET_PRIVATE (object);
223
224     g_free (priv->placeholder);
225
226     if (G_OBJECT_CLASS (hildon_entry_parent_class)->finalize)
227         G_OBJECT_CLASS (hildon_entry_parent_class)->finalize (object);
228 }
229
230 static void
231 hildon_entry_class_init                         (HildonEntryClass *klass)
232 {
233     GObjectClass *gobject_class = (GObjectClass *)klass;
234     GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
235
236     gobject_class->finalize = hildon_entry_finalize;
237     widget_class->focus_in_event = hildon_entry_focus_in_event;
238     widget_class->focus_out_event = hildon_entry_focus_out_event;
239
240     g_type_class_add_private (klass, sizeof (HildonEntryPrivate));
241 }
242
243 static void
244 hildon_entry_init                               (HildonEntry *self)
245 {
246     HildonEntryPrivate *priv = HILDON_ENTRY_GET_PRIVATE (self);
247
248     priv->placeholder = g_strdup ("");
249 }