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