2008-09-24 Claudio Saavedra <csaavedra@igalia.com>
[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 };
50
51 /* Signals */
52 enum
53 {
54   VALUE_CHANGED,
55   LAST_SIGNAL
56 };
57
58 enum
59 {
60   PROP_SELECTOR = 1,
61 };
62
63 static guint picker_button_signals[LAST_SIGNAL] = { 0 };
64
65 static void
66 hildon_picker_button_get_property (GObject * object, guint property_id,
67                                    GValue * value, GParamSpec * pspec)
68 {
69   switch (property_id) {
70   case PROP_SELECTOR:
71     g_value_set_object (value,
72                         hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (object)));
73     break;
74   default:
75     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
76   }
77 }
78
79 static void
80 hildon_picker_button_set_property (GObject * object, guint property_id,
81                                    const GValue * value, GParamSpec * pspec)
82 {
83   switch (property_id) {
84   case PROP_SELECTOR:
85     hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (object),
86                                        g_value_get_object (value));
87     break;
88   default:
89     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
90   }
91 }
92
93 static void
94 hildon_picker_button_finalize (GObject * object)
95 {
96   HildonPickerButtonPrivate *priv;
97
98   priv = GET_PRIVATE (object);
99
100   if (priv->selector) {
101     g_object_unref (priv->selector);
102     priv->selector = NULL;
103   }
104   if (priv->dialog) {
105     gtk_widget_destroy (priv->dialog);
106     priv->dialog = NULL;
107   }
108
109   G_OBJECT_CLASS (hildon_picker_button_parent_class)->finalize (object);
110 }
111
112 static void
113 hildon_picker_button_clicked (GtkButton * button)
114 {
115   GtkWidget *parent;
116   HildonPickerButtonPrivate *priv;
117   gint response;
118
119   priv = GET_PRIVATE (HILDON_PICKER_BUTTON (button));
120
121   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (priv->selector));
122
123   /* Create the dialog if it doesn't exist already.  */
124   if (!priv->dialog) {
125     parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
126     if (GTK_WIDGET_TOPLEVEL (parent)) {
127       priv->dialog = hildon_picker_dialog_new (GTK_WINDOW (parent));
128     } else {
129       priv->dialog = hildon_picker_dialog_new (NULL);
130     }
131
132     hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (priv->dialog),
133                                        HILDON_TOUCH_SELECTOR (priv->selector));
134
135     gtk_window_set_modal (GTK_WINDOW (priv->dialog),
136                           gtk_window_get_modal (GTK_WINDOW (parent)));
137     gtk_window_set_title (GTK_WINDOW (priv->dialog),
138                           hildon_button_get_title (HILDON_BUTTON (button)));
139   }
140
141   response = gtk_dialog_run (GTK_DIALOG (priv->dialog));
142   switch (response) {
143   case GTK_RESPONSE_OK:
144     hildon_button_set_value (HILDON_BUTTON (button),
145                              hildon_touch_selector_get_current_text
146                              (HILDON_TOUCH_SELECTOR (priv->selector)));
147     g_signal_emit (HILDON_PICKER_BUTTON (button),
148                    picker_button_signals[VALUE_CHANGED], 0);
149     break;
150   }
151   gtk_widget_hide (priv->dialog);
152 }
153
154 static void
155 hildon_picker_button_class_init (HildonPickerButtonClass * klass)
156 {
157   GObjectClass *object_class = G_OBJECT_CLASS (klass);
158   GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
159
160   g_type_class_add_private (klass, sizeof (HildonPickerButtonPrivate));
161
162   object_class->get_property = hildon_picker_button_get_property;
163   object_class->set_property = hildon_picker_button_set_property;
164   object_class->finalize = hildon_picker_button_finalize;
165
166   button_class->clicked = hildon_picker_button_clicked;
167
168   g_object_class_install_property (object_class,
169                                    PROP_SELECTOR,
170                                    g_param_spec_object ("touch-selector",
171                                                         "HildonTouchSelector widget",
172                                                         "HildonTouchSelector widget to be launched on button clicked",
173                                                         HILDON_TYPE_TOUCH_SELECTOR,
174                                                         G_PARAM_READWRITE));
175
176   /**
177    * HildonPickerButton::value-changed:
178    * @widget: the widget that received the signal
179    *
180    * The ::value-changed signal is emitted each time the user chooses a different
181    * item from the #HildonTouchSelector related, and the value label gets updated.
182    */
183   picker_button_signals[VALUE_CHANGED] =
184     g_signal_new ("value-changed",
185                   G_TYPE_FROM_CLASS (klass),
186                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
187                   0,
188                   NULL, NULL,
189                   g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
190 }
191
192 static void
193 hildon_picker_button_init (HildonPickerButton * self)
194 {
195   HildonPickerButtonPrivate *priv;
196
197   priv = GET_PRIVATE (self);
198
199   priv->dialog = NULL;
200   priv->selector = NULL;
201 }
202
203 /**
204  * hildon_picker_button_new:
205  * @size: One of #HildonSizeType, specifying the size of the new button.
206  * @arrangement: one of #HildonButtonArrangement, specifying the placement of the
207  * labels.
208  *
209  * Creates a new #HildonPickerButton. See hildon_button_new() for details on the
210  * parameters.
211  *
212  * Returns: a newly created #HildonPickerButton
213  **/
214 GtkWidget *
215 hildon_picker_button_new (HildonSizeType          size,
216                           HildonButtonArrangement arrangement)
217 {
218   GtkWidget *button;
219
220   button = g_object_new (HILDON_TYPE_PICKER_BUTTON,
221                          "arrangement", arrangement, "size", size, NULL);
222
223   return button;
224 }
225
226 /**
227  * hildon_picker_button_set_selector:
228  * @button: a #HildonPickerButton
229  * @selector: a #HildonTouchSelector
230  *
231  * Sets @selector as the #HildonTouchSelector to be shown in the
232  * #HildonPickerDialog that @button brings up.
233  **/
234 void
235 hildon_picker_button_set_selector (HildonPickerButton * button,
236                                    HildonTouchSelector * selector)
237 {
238   HildonPickerButtonPrivate *priv;
239   const gchar *value;
240
241   g_return_if_fail (HILDON_IS_PICKER_BUTTON (button));
242   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
243
244   priv = GET_PRIVATE (button);
245
246   if (priv->selector) {
247     g_object_unref (priv->selector);
248   }
249
250   priv->selector = g_object_ref (selector);
251
252   value = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (priv->selector));
253   if (value) {
254     hildon_button_set_value (HILDON_BUTTON (button), value);
255     g_signal_emit (HILDON_PICKER_BUTTON (button),
256                    picker_button_signals[VALUE_CHANGED], 0);
257   }
258 }
259
260 /**
261  * hildon_picker_button_get_selector:
262  * @button: a #HildonPickerButton
263  *
264  * Retrieves the #HildonTouchSelector associated to @button.
265  *
266  * Returns: a #HildonTouchSelector
267  **/
268 HildonTouchSelector *
269 hildon_picker_button_get_selector (HildonPickerButton * button)
270 {
271   HildonPickerButtonPrivate *priv;
272
273   g_return_val_if_fail (HILDON_IS_PICKER_BUTTON (button), NULL);
274
275   priv = GET_PRIVATE (button);
276
277   return HILDON_TOUCH_SELECTOR (priv->selector);
278 }
279
280 /**
281  * hildon_picker_button_get_active:
282  * @button: a #HildonPickerButton
283  *
284  * Returns the index of the currently active item, or -1 if there's no
285  * active item. If the selector has several columns, only the first
286  * one is used.
287  *
288  * Returns: an integer which is the index of the currently active item, or -1 if there's no active item.
289  **/
290 gint
291 hildon_picker_button_get_active                 (HildonPickerButton * button)
292 {
293   HildonTouchSelector *sel;
294   g_return_val_if_fail (HILDON_IS_PICKER_BUTTON (button), -1);
295
296   sel = hildon_picker_button_get_selector (button);
297
298   return hildon_touch_selector_get_active (sel, 0);
299 }
300
301 /**
302  * hildon_picker_button_set_active:
303  * @button: a #HildonPickerButton
304  * @index: the index of the item to select, or -1 to have no active item
305  *
306  * Sets the active item of the #HildonTouchSelector associated to
307  * @button to @index. If the selector has several columns, only the
308  * first one is used.
309  **/
310 void
311 hildon_picker_button_set_active                 (HildonPickerButton * button,
312                                                  gint index)
313 {
314   HildonTouchSelector *sel;
315   gchar *text;
316   g_return_if_fail (HILDON_IS_PICKER_BUTTON (button));
317
318   sel = hildon_picker_button_get_selector (button);
319   hildon_touch_selector_set_active (sel, 0, index);
320
321   text = hildon_touch_selector_get_current_text (sel);
322   hildon_button_set_value (HILDON_BUTTON (button), text);
323   g_free (text);
324 }