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