40da60ed2bf7346fe19efe6bff5c751d0645d217
[hildon] / hildon / 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 enum {
59     PROP_SIZE = 1
60 };
61
62 #define                                         HILDON_ENTRY_GET_PRIVATE(obj) \
63                                                 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
64                                                 HILDON_TYPE_ENTRY, HildonEntryPrivate));
65
66 struct                                          _HildonEntryPrivate
67 {
68     gchar *placeholder;
69     gboolean showing_placeholder;
70 };
71
72 static void
73 set_property                                    (GObject      *object,
74                                                  guint         prop_id,
75                                                  const GValue *value,
76                                                  GParamSpec   *pspec)
77 {
78     switch (prop_id)
79     {
80     case PROP_SIZE:
81         hildon_gtk_widget_set_theme_size (GTK_WIDGET (object), g_value_get_flags (value));
82         break;
83     default:
84         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
85         break;
86     }
87 }
88
89 static void
90 hildon_entry_show_placeholder (HildonEntry *entry)
91 {
92     HildonEntryPrivate *priv = HILDON_ENTRY (entry)->priv;
93
94     priv->showing_placeholder = TRUE;
95     gtk_entry_set_text (GTK_ENTRY (entry), priv->placeholder);
96     hildon_helper_set_logical_color (GTK_WIDGET (entry),
97                                      GTK_RC_TEXT, GTK_STATE_NORMAL, "ReversedSecondaryTextColor");
98 }
99
100 static void
101 hildon_entry_hide_placeholder (HildonEntry *entry, const gchar *text)
102 {
103     HildonEntryPrivate *priv = HILDON_ENTRY (entry)->priv;
104
105     priv->showing_placeholder = FALSE;
106     gtk_entry_set_text (GTK_ENTRY (entry), text);
107     hildon_helper_set_logical_color (GTK_WIDGET (entry),
108                                      GTK_RC_TEXT, GTK_STATE_NORMAL, "ReversedTextColor");
109 }
110
111 /**
112  * hildon_entry_set_text:
113  * @entry: a #HildonEntry
114  * @text: the new text
115  *
116  * Sets the text in @entry to @text, replacing its current contents.
117  *
118  * Note that you must never use gtk_entry_set_text() to set the text
119  * of a #HildonEntry.
120  *
121  * Since: 2.2
122  */
123 void
124 hildon_entry_set_text                           (HildonEntry *entry,
125                                                  const gchar *text)
126 {
127     g_return_if_fail (HILDON_IS_ENTRY (entry) && text != NULL);
128
129     if (text[0] == '\0' && !GTK_WIDGET_HAS_FOCUS (entry)) {
130             hildon_entry_show_placeholder (entry);
131     } else {
132             hildon_entry_hide_placeholder (entry, text);
133     }
134 }
135
136 /**
137  * hildon_entry_get_text:
138  * @entry: a #HildonEntry
139  *
140  * Gets the current text in @entry.
141  *
142  * Note that you must never use gtk_entry_get_text() to get the text
143  * from a #HildonEntry.
144  *
145  * Also note that placeholder text (set using
146  * hildon_entry_set_placeholder()) is never returned. Only text set by
147  * hildon_entry_set_text() or typed by the user is considered.
148  *
149  * Returns: the text in @entry. This text must not be modified or
150  * freed.
151  *
152  * Since: 2.2
153  */
154 const gchar *
155 hildon_entry_get_text                           (HildonEntry *entry)
156 {
157     g_return_val_if_fail (HILDON_IS_ENTRY (entry), NULL);
158
159     if (entry->priv->showing_placeholder) {
160         return "";
161     }
162
163     return gtk_entry_get_text (GTK_ENTRY (entry));
164 }
165
166 /**
167  * hildon_entry_set_placeholder:
168  * @entry: a #HildonEntry
169  * @text: the new text
170  *
171  * Sets the placeholder text in @entry to @text.
172  *
173  * Since: 2.2
174  */
175 void
176 hildon_entry_set_placeholder                    (HildonEntry *entry,
177                                                  const gchar *text)
178 {
179     g_return_if_fail (HILDON_IS_ENTRY (entry) && text != NULL);
180
181     g_free (entry->priv->placeholder);
182     entry->priv->placeholder = g_strdup (text);
183
184     /* Show the placeholder if it needs to be updated or if should be shown now. */
185     if (entry->priv->showing_placeholder ||
186         (!GTK_WIDGET_HAS_FOCUS (entry) && gtk_entry_get_text (GTK_ENTRY (entry)) [0] == '\0')) {
187         hildon_entry_show_placeholder (entry);
188     }
189 }
190
191 /**
192  * hildon_entry_new:
193  * @size: The size of the entry
194  *
195  * Creates a new entry.
196  *
197  * Returns: a new #HildonEntry
198  *
199  * Since: 2.2
200  */
201 GtkWidget *
202 hildon_entry_new                                (HildonSizeType size)
203 {
204     return g_object_new (HILDON_TYPE_ENTRY, "size", size, NULL);
205 }
206
207 static gboolean
208 hildon_entry_focus_in_event                     (GtkWidget     *widget,
209                                                  GdkEventFocus *event)
210 {
211     if (HILDON_ENTRY (widget)->priv->showing_placeholder) {
212             hildon_entry_hide_placeholder (HILDON_ENTRY (widget), "");
213     }
214
215     if (GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_in_event) {
216         return GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_in_event (widget, event);
217     } else {
218         return FALSE;
219     }
220 }
221
222 static gboolean
223 hildon_entry_focus_out_event                    (GtkWidget     *widget,
224                                                  GdkEventFocus *event)
225 {
226     if (gtk_entry_get_text (GTK_ENTRY (widget)) [0] == '\0') {
227         hildon_entry_show_placeholder (HILDON_ENTRY (widget));
228     }
229
230     if (GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_out_event) {
231         return GTK_WIDGET_CLASS (hildon_entry_parent_class)->focus_out_event (widget, event);
232     } else {
233         return FALSE;
234     }
235 }
236
237 static void
238 hildon_entry_finalize                           (GObject *object)
239 {
240     HildonEntryPrivate *priv = HILDON_ENTRY (object)->priv;
241
242     g_free (priv->placeholder);
243
244     if (G_OBJECT_CLASS (hildon_entry_parent_class)->finalize)
245         G_OBJECT_CLASS (hildon_entry_parent_class)->finalize (object);
246 }
247
248 static void
249 hildon_entry_class_init                         (HildonEntryClass *klass)
250 {
251     GObjectClass *gobject_class = (GObjectClass *)klass;
252     GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
253
254     gobject_class->set_property = set_property;
255     gobject_class->finalize = hildon_entry_finalize;
256     widget_class->focus_in_event = hildon_entry_focus_in_event;
257     widget_class->focus_out_event = hildon_entry_focus_out_event;
258
259     g_object_class_install_property (
260         gobject_class,
261         PROP_SIZE,
262         g_param_spec_flags (
263             "size",
264             "Size",
265             "Size request for the entry",
266             HILDON_TYPE_SIZE_TYPE,
267             HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
268             G_PARAM_WRITABLE));
269
270     g_type_class_add_private (klass, sizeof (HildonEntryPrivate));
271 }
272
273 static void
274 hildon_entry_init                               (HildonEntry *self)
275 {
276     self->priv = HILDON_ENTRY_GET_PRIVATE (self);
277     self->priv->placeholder = g_strdup ("");
278     self->priv->showing_placeholder = FALSE;
279 }