6b3e2b06ef18cabcc5f12c24f122dc065d880aa9
[hildon] / src / hildon-picker-button.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-picker-button
19  * @short_description: A button that launches a #HildonPickerDialog and displays the
20  * selected item
21  * @see_also: #HildonTouchSelector, #HildonPickerDialog
22  *
23  * #HildonPickerButton is a widget that lets the user select a particular item from
24  * a list. Visually, it's a button with title and value labels that brings up a
25  * #HildonPickerDialog. The user can then use this dialog to choose an item, which
26  * will be displayed in the value label of the button.
27  *
28  * You should create your own #HildonTouchSelector at convenience and set it
29  * to the #HildonPickerButton with hildon_picker_button_set_selector(). For
30  * the common use cases of buttons to select date and time, you can use #HildonDateButton
31  * and #HildonTimeButton.
32  *
33  */
34
35 #include "hildon-picker-button.h"
36 #include "hildon-picker-dialog.h"
37
38 G_DEFINE_TYPE (HildonPickerButton, hildon_picker_button, HILDON_TYPE_BUTTON)
39
40 #define GET_PRIVATE(o)                                                  \
41   (G_TYPE_INSTANCE_GET_PRIVATE ((o), HILDON_TYPE_PICKER_BUTTON, HildonPickerButtonPrivate))
42
43 typedef struct _HildonPickerButtonPrivate HildonPickerButtonPrivate;
44
45 struct _HildonPickerButtonPrivate
46 {
47   GtkWidget *selector;
48   GtkWidget *dialog;
49   gchar *done_button_text;
50 };
51
52 /* Signals */
53 enum
54 {
55   VALUE_CHANGED,
56   LAST_SIGNAL
57 };
58
59 enum
60 {
61   PROP_SELECTOR = 1,
62   PROP_DONE_BUTTON_TEXT
63 };
64
65 static guint picker_button_signals[LAST_SIGNAL] = { 0 };
66
67 static void
68 hildon_picker_button_get_property (GObject * object, guint property_id,
69                                    GValue * value, GParamSpec * pspec)
70 {
71   switch (property_id) {
72   case PROP_SELECTOR:
73     g_value_set_object (value,
74                         hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (object)));
75     break;
76   case PROP_DONE_BUTTON_TEXT:
77     g_value_set_string (value,
78                         hildon_picker_button_get_done_button_text (HILDON_PICKER_BUTTON (object)));
79     break;
80   default:
81     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
82   }
83 }
84
85 static void
86 hildon_picker_button_set_property (GObject * object, guint property_id,
87                                    const GValue * value, GParamSpec * pspec)
88 {
89   switch (property_id) {
90   case PROP_SELECTOR:
91     hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (object),
92                                        g_value_get_object (value));
93     break;
94   case PROP_DONE_BUTTON_TEXT:
95     hildon_picker_button_set_done_button_text (HILDON_PICKER_BUTTON (object),
96                                                g_value_get_string (value));
97     break;
98   default:
99     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
100   }
101 }
102
103 static void
104 hildon_picker_button_finalize (GObject * object)
105 {
106   HildonPickerButtonPrivate *priv;
107
108   priv = GET_PRIVATE (object);
109
110   if (priv->selector) {
111     g_object_unref (priv->selector);
112     priv->selector = NULL;
113   }
114   if (priv->dialog) {
115     gtk_widget_destroy (priv->dialog);
116     priv->dialog = NULL;
117   }
118
119   G_OBJECT_CLASS (hildon_picker_button_parent_class)->finalize (object);
120 }
121
122 static void
123 hildon_picker_button_clicked (GtkButton * button)
124 {
125   GtkWidget *parent;
126   HildonPickerButtonPrivate *priv;
127   gint response;
128
129   priv = GET_PRIVATE (HILDON_PICKER_BUTTON (button));
130
131   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (priv->selector));
132
133   /* Create the dialog if it doesn't exist already.  */
134   if (!priv->dialog) {
135     parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
136     if (GTK_WIDGET_TOPLEVEL (parent)) {
137       priv->dialog = hildon_picker_dialog_new (GTK_WINDOW (parent));
138     } else {
139       priv->dialog = hildon_picker_dialog_new (NULL);
140     }
141
142     hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (priv->dialog),
143                                        HILDON_TOUCH_SELECTOR (priv->selector));
144     if (priv->done_button_text) {
145       hildon_picker_dialog_set_done_label (HILDON_PICKER_DIALOG (priv->dialog),
146                                            priv->done_button_text);
147     }
148
149     gtk_window_set_modal (GTK_WINDOW (priv->dialog),
150                           gtk_window_get_modal (GTK_WINDOW (parent)));
151     gtk_window_set_title (GTK_WINDOW (priv->dialog),
152                           hildon_button_get_title (HILDON_BUTTON (button)));
153   }
154
155   response = gtk_dialog_run (GTK_DIALOG (priv->dialog));
156   switch (response) {
157   case GTK_RESPONSE_OK:
158     hildon_button_set_value (HILDON_BUTTON (button),
159                              hildon_touch_selector_get_current_text
160                              (HILDON_TOUCH_SELECTOR (priv->selector)));
161     g_signal_emit (HILDON_PICKER_BUTTON (button),
162                    picker_button_signals[VALUE_CHANGED], 0);
163     break;
164   }
165   gtk_widget_hide (priv->dialog);
166 }
167
168 static void
169 hildon_picker_button_class_init (HildonPickerButtonClass * klass)
170 {
171   GObjectClass *object_class = G_OBJECT_CLASS (klass);
172   GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
173
174   g_type_class_add_private (klass, sizeof (HildonPickerButtonPrivate));
175
176   object_class->get_property = hildon_picker_button_get_property;
177   object_class->set_property = hildon_picker_button_set_property;
178   object_class->finalize = hildon_picker_button_finalize;
179
180   button_class->clicked = hildon_picker_button_clicked;
181
182   g_object_class_install_property (object_class,
183                                    PROP_SELECTOR,
184                                    g_param_spec_object ("touch-selector",
185                                                         "HildonTouchSelector widget",
186                                                         "HildonTouchSelector widget to be launched on button clicked",
187                                                         HILDON_TYPE_TOUCH_SELECTOR,
188                                                         G_PARAM_READWRITE));
189   g_object_class_install_property (object_class,
190                                    PROP_DONE_BUTTON_TEXT,
191                                    g_param_spec_string ("done-button-text",
192                                                         "HildonPickerDialog \"done\" button text",
193                                                         "The text for the \"done\" button in the dialog launched",
194                                                         NULL,
195                                                         G_PARAM_READWRITE));
196
197   /**
198    * HildonPickerButton::value-changed:
199    * @widget: the widget that received the signal
200    *
201    * The ::value-changed signal is emitted each time the user chooses a different
202    * item from the #HildonTouchSelector related, and the value label gets updated.
203    */
204   picker_button_signals[VALUE_CHANGED] =
205     g_signal_new ("value-changed",
206                   G_TYPE_FROM_CLASS (klass),
207                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
208                   0,
209                   NULL, NULL,
210                   g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
211 }
212
213 static void
214 hildon_picker_button_init (HildonPickerButton * self)
215 {
216   HildonPickerButtonPrivate *priv;
217
218   priv = GET_PRIVATE (self);
219
220   priv->dialog = NULL;
221   priv->selector = NULL;
222   priv->done_button_text = NULL;
223 }
224
225 /**
226  * hildon_picker_button_new:
227  * @size: One of #HildonSizeType, specifying the size of the new button.
228  * @arrangement: one of #HildonButtonArrangement, specifying the placement of the
229  * labels.
230  *
231  * Creates a new #HildonPickerButton. See hildon_button_new() for details on the
232  * parameters.
233  *
234  * Returns: a newly created #HildonPickerButton
235  **/
236 GtkWidget *
237 hildon_picker_button_new (HildonSizeType          size,
238                           HildonButtonArrangement arrangement)
239 {
240   GtkWidget *button;
241
242   button = g_object_new (HILDON_TYPE_PICKER_BUTTON,
243                          "arrangement", arrangement, "size", size, NULL);
244
245   return button;
246 }
247
248 /**
249  * hildon_picker_button_set_selector:
250  * @button: a #HildonPickerButton
251  * @selector: a #HildonTouchSelector
252  *
253  * Sets @selector as the #HildonTouchSelector to be shown in the
254  * #HildonPickerDialog that @button brings up.
255  **/
256 void
257 hildon_picker_button_set_selector (HildonPickerButton * button,
258                                    HildonTouchSelector * selector)
259 {
260   HildonPickerButtonPrivate *priv;
261   const gchar *value;
262
263   g_return_if_fail (HILDON_IS_PICKER_BUTTON (button));
264   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
265
266   priv = GET_PRIVATE (button);
267
268   if (priv->selector) {
269     g_object_unref (priv->selector);
270   }
271
272   priv->selector = g_object_ref (selector);
273
274   value = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (priv->selector));
275   if (value) {
276     hildon_button_set_value (HILDON_BUTTON (button), value);
277     g_signal_emit (HILDON_PICKER_BUTTON (button),
278                    picker_button_signals[VALUE_CHANGED], 0);
279   }
280 }
281
282 /**
283  * hildon_picker_button_get_selector:
284  * @button: a #HildonPickerButton
285  *
286  * Retrieves the #HildonTouchSelector associated to @button.
287  *
288  * Returns: a #HildonTouchSelector
289  **/
290 HildonTouchSelector *
291 hildon_picker_button_get_selector (HildonPickerButton * button)
292 {
293   HildonPickerButtonPrivate *priv;
294
295   g_return_val_if_fail (HILDON_IS_PICKER_BUTTON (button), NULL);
296
297   priv = GET_PRIVATE (button);
298
299   return HILDON_TOUCH_SELECTOR (priv->selector);
300 }
301
302 /**
303  * hildon_picker_button_get_active:
304  * @button: a #HildonPickerButton
305  *
306  * Returns the index of the currently active item, or -1 if there's no
307  * active item. If the selector has several columns, only the first
308  * one is used.
309  *
310  * Returns: an integer which is the index of the currently active item, or -1 if there's no active item.
311  **/
312 gint
313 hildon_picker_button_get_active                 (HildonPickerButton * button)
314 {
315   HildonTouchSelector *sel;
316   g_return_val_if_fail (HILDON_IS_PICKER_BUTTON (button), -1);
317
318   sel = hildon_picker_button_get_selector (button);
319
320   return hildon_touch_selector_get_active (sel, 0);
321 }
322
323 /**
324  * hildon_picker_button_set_active:
325  * @button: a #HildonPickerButton
326  * @index: the index of the item to select, or -1 to have no active item
327  *
328  * Sets the active item of the #HildonTouchSelector associated to
329  * @button to @index. If the selector has several columns, only the
330  * first one is used.
331  **/
332 void
333 hildon_picker_button_set_active                 (HildonPickerButton * button,
334                                                  gint index)
335 {
336   HildonTouchSelector *sel;
337   gchar *text;
338   g_return_if_fail (HILDON_IS_PICKER_BUTTON (button));
339
340   sel = hildon_picker_button_get_selector (button);
341   hildon_touch_selector_set_active (sel, 0, index);
342
343   text = hildon_touch_selector_get_current_text (sel);
344   hildon_button_set_value (HILDON_BUTTON (button), text);
345   g_free (text);
346 }
347
348 /**
349  * hildon_picker_button_get_done_button_text:
350  * @button: a #HildonPickerButton
351  *
352  * Gets the text used in the #HildonPickerDialog that is launched by
353  * @button. If no custom text is set, then %NULL is returned.
354  *
355  * Returns: the custom string to be used, or %NULL if the default
356  * #HildonPickerDialog::done-button-text is to be used.
357  **/
358 const gchar *
359 hildon_picker_button_get_done_button_text (HildonPickerButton *button)
360 {
361   HildonPickerButtonPrivate *priv;
362
363   g_return_val_if_fail (HILDON_IS_PICKER_BUTTON (button), NULL);
364
365   priv = GET_PRIVATE (button);
366
367   return priv->done_button_text;
368 }
369
370 /**
371  * hildon_picker_button_set_done_button_text:
372  * @button: a #HildonPickerButton
373  * @done_button_text: a string
374  *
375  * Sets a custom string to be used in the \"done\" button in the #HildonPickerDialog
376  * launched. If not set, the default HildonPickerButton::done-button-text property
377  * value will be used.
378  **/
379 void
380 hildon_picker_button_set_done_button_text (HildonPickerButton *button,
381                                            const gchar *done_button_text)
382 {
383   HildonPickerButtonPrivate *priv;
384
385   g_return_if_fail (HILDON_IS_PICKER_BUTTON (button));
386   g_return_if_fail (done_button_text != NULL);
387
388   priv = GET_PRIVATE (button);
389
390   g_free (priv->done_button_text);
391   priv->done_button_text = g_strdup (done_button_text);
392 }