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