e41eebb55fb188ec7616ea3fedfdb3dee63cf0cc
[hildon] / src / hildon-button.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2008 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Karl Lattimer <karl.lattimer@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser Public License as published by
10  * the Free Software Foundation; version 2 of the license.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser Public License for more details.
16  *
17  */
18
19 /**
20  * SECTION:hildon-button
21  * @short_description: Widget representing a button in the Hildon framework.
22  *
23  * The #HildonButton is a GTK widget which represent a clickable
24  * button. It is derived from the GtkButton widget and provides
25  * additional commodities specific to the Hildon framework.
26  *
27  * The height of a #HildonButton can be set to either "finger" height
28  * or "thumb" height. It can also be configured to use halfscreen or
29  * fullscreen width. Alternatively, either dimension can be set to
30  * "auto" so it behaves like a standard GtkButton.
31  *
32  * The #HildonButton can hold any valid child widget, but it usually
33  * contains two labels: title and value (the latter being optional).
34  */
35
36 #include                                        "hildon-button.h"
37
38 #define FINGER_BUTTON_HEIGHT                    70
39 #define THUMB_BUTTON_HEIGHT                     105
40 #define HALFSCREEN_BUTTON_WIDTH                 400
41 #define FULLSCREEN_BUTTON_WIDTH                 800
42
43 G_DEFINE_TYPE                                   (HildonButton, hildon_button, GTK_TYPE_BUTTON);
44
45 #define                                         HILDON_BUTTON_GET_PRIVATE(obj) \
46                                                 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
47                                                 HILDON_TYPE_BUTTON, HildonButtonPrivate));
48
49 typedef struct                                  _HildonButtonPrivate HildonButtonPrivate;
50
51 struct                                          _HildonButtonPrivate
52 {
53     GtkLabel *title;
54     GtkLabel *value;
55     GtkWidget *alignment;
56 };
57
58 enum {
59   PROP_TITLE = 1,
60   PROP_VALUE,
61   PROP_ARRANGEMENT_FLAGS
62 };
63
64 static void
65 hildon_button_set_arrangement                   (HildonButton      *button,
66                                                  HildonButtonFlags  flags);
67
68 static void
69 hildon_button_construct_child                   (HildonButton *button);
70
71 static void
72 hildon_button_set_property                      (GObject      *object,
73                                                  guint         prop_id,
74                                                  const GValue *value,
75                                                  GParamSpec   *pspec)
76 {
77     HildonButton *button = HILDON_BUTTON (object);
78
79     switch (prop_id)
80     {
81     case PROP_TITLE:
82         hildon_button_set_title (button, g_value_get_string (value));
83         break;
84     case PROP_VALUE:
85         hildon_button_set_value (button, g_value_get_string (value));
86         break;
87     case PROP_ARRANGEMENT_FLAGS:
88         hildon_button_set_arrangement (button, g_value_get_int (value));
89         break;
90     default:
91         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92         break;
93     }
94 }
95
96 static void
97 hildon_button_get_property                      (GObject    *object,
98                                                  guint       prop_id,
99                                                  GValue     *value,
100                                                  GParamSpec *pspec)
101 {
102     HildonButton *button = HILDON_BUTTON (object);
103     HildonButtonPrivate *priv = HILDON_BUTTON_GET_PRIVATE (button);
104
105     switch (prop_id)
106     {
107     case PROP_TITLE:
108         g_value_set_string (value, gtk_label_get_text (priv->title));
109         break;
110     case PROP_VALUE:
111         g_value_set_string (value, gtk_label_get_text (priv->value));
112         break;
113     default:
114         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
115         break;
116     }
117 }
118
119 static void
120 hildon_button_class_init                        (HildonButtonClass *klass)
121 {
122     GObjectClass *gobject_class = (GObjectClass *)klass;
123     GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
124
125     gobject_class->set_property = hildon_button_set_property;
126     gobject_class->get_property = hildon_button_get_property;
127
128     g_object_class_install_property (
129         gobject_class,
130         PROP_TITLE,
131         g_param_spec_string (
132             "title",
133             "Title",
134             "Text of the title label inside the button",
135             NULL,
136             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
137
138     g_object_class_install_property (
139         gobject_class,
140         PROP_VALUE,
141         g_param_spec_string (
142             "value",
143             "Value",
144             "Text of the value label inside the button",
145             NULL,
146             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
147
148     g_object_class_install_property (
149         gobject_class,
150         PROP_ARRANGEMENT_FLAGS,
151         g_param_spec_int (
152             "arrangement-flags",
153             "Arrangement flags",
154             "How the button contents must be arranged",
155             0, 64,
156             HILDON_BUTTON_WITH_HORIZONTAL_VALUE,
157             G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
158
159     gtk_widget_class_install_style_property (
160         widget_class,
161         g_param_spec_uint (
162             "horizontal-spacing",
163             "Horizontal spacing between labels",
164             "Horizontal spacing between the title and value labels, when in horizontal mode",
165             0, G_MAXUINT, 25,
166             G_PARAM_READABLE));
167
168     gtk_widget_class_install_style_property (
169         widget_class,
170         g_param_spec_uint (
171             "vertical-spacing",
172             "Vertical spacing between labels",
173             "Vertical spacing between the title and value labels, when in vertical mode",
174             0, G_MAXUINT, 5,
175             G_PARAM_READABLE));
176
177     g_type_class_add_private (klass, sizeof (HildonButtonPrivate));
178 }
179
180 static void
181 hildon_button_init                              (HildonButton *self)
182 {
183     HildonButtonPrivate *priv = HILDON_BUTTON_GET_PRIVATE (self);
184
185     priv->title = GTK_LABEL (gtk_label_new (NULL));
186     priv->value = GTK_LABEL (gtk_label_new (NULL));
187     priv->alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
188
189     gtk_widget_set_name (GTK_WIDGET (priv->title), "hildon-button-title");
190     gtk_widget_set_name (GTK_WIDGET (priv->value), "hildon-button-value");
191
192     gtk_misc_set_alignment (GTK_MISC (priv->title), 0, 0.5);
193     gtk_misc_set_alignment (GTK_MISC (priv->value), 0, 0.5);
194
195     /* The value label is not shown automatically, see hildon_button_set_value() */
196     gtk_widget_set_no_show_all (GTK_WIDGET (priv->value), TRUE);
197 }
198
199 void
200 hildon_button_set_size_groups                   (HildonButton *button,
201                                                  GtkSizeGroup *title_size_group,
202                                                  GtkSizeGroup *value_size_group)
203 {
204     HildonButtonPrivate *priv;
205
206     g_return_if_fail (HILDON_IS_BUTTON (button));
207
208     priv = HILDON_BUTTON_GET_PRIVATE (button);
209
210     if (title_size_group)
211         gtk_size_group_add_widget (title_size_group, GTK_WIDGET (priv->title));
212
213     if (value_size_group)
214         gtk_size_group_add_widget (value_size_group, GTK_WIDGET (priv->value));
215 }
216
217 /**
218  * hildon_button_new:
219  * @flags: flags to set the size and layout of the button
220  *
221  * Creates a new #HildonButton. To add a child widget use gtk_container_add().
222  *
223  * Returns: a new #HildonButton
224  **/
225 GtkWidget *
226 hildon_button_new                               (HildonButtonFlags  flags)
227 {
228     return hildon_button_new_full (flags, NULL, NULL, NULL, NULL);
229 }
230
231 /**
232  * hildon_button_new_with_text:
233  * @flags: flags to set the size and layout of the button
234  * @title: Title of the button (main label)
235  * @value: Value of the button (secondary label), or %NULL
236  *
237  * Creates a new #HildonButton with two labels, @title and @value.
238  *
239  * If you just want to use the main label, set @value to %NULL. You
240  * can set it to a non-%NULL value at any time later.
241  *
242  * Returns: a new #HildonButton
243  **/
244 GtkWidget *
245 hildon_button_new_with_text                     (HildonButtonFlags  flags,
246                                                  const char        *title,
247                                                  const char        *value)
248 {
249     return hildon_button_new_full (flags, title, value, NULL, NULL);
250 }
251
252 GtkWidget *
253 hildon_button_new_full                          (HildonButtonFlags  flags,
254                                                  const char        *title,
255                                                  const char        *value,
256                                                  GtkSizeGroup      *title_size_group,
257                                                  GtkSizeGroup      *value_size_group)
258 {
259     GtkWidget *button;
260
261     /* Create widget */
262     button = g_object_new (HILDON_TYPE_BUTTON,
263                            "arrangement-flags", flags,
264                            "title", title,
265                            "value", value,
266                            "name", "hildon-button",
267                            NULL);
268     /* Set size groups */
269     if (title_size_group || value_size_group)
270         hildon_button_set_size_groups (HILDON_BUTTON (button), title_size_group, value_size_group);
271
272     return button;
273 }
274
275 static void
276 hildon_button_set_arrangement (HildonButton *button,
277                                HildonButtonFlags flags)
278 {
279     GtkWidget *box;
280     HildonButtonPrivate *priv;
281     guint horizontal_spacing;
282     guint vertical_spacing;
283     gint width = -1;
284     gint height = -1;
285     const char *widget_name = NULL;
286
287     priv = HILDON_BUTTON_GET_PRIVATE (button);
288
289     /* Requested height */
290     if (flags & HILDON_BUTTON_FINGER_HEIGHT) {
291         height = FINGER_BUTTON_HEIGHT;
292         widget_name = "hildon-finger-button";
293     } else if (flags & HILDON_BUTTON_THUMB_HEIGHT) {
294         height = THUMB_BUTTON_HEIGHT;
295         widget_name = "hildon-thumb-button";
296     }
297
298     if (widget_name) {
299         gtk_widget_set_name (GTK_WIDGET (button), widget_name);
300     }
301
302     /* Requested width */
303     if (flags & HILDON_BUTTON_HALFSCREEN_WIDTH) {
304         width = HALFSCREEN_BUTTON_WIDTH;
305     } else if (flags & HILDON_BUTTON_FULLSCREEN_WIDTH) {
306         width = FULLSCREEN_BUTTON_WIDTH;
307     }
308
309     g_object_set (button,
310                   "width-request", width,
311                   "height-request", height,
312                   NULL);
313
314     /* Pack everything */
315     gtk_widget_style_get (GTK_WIDGET (button),
316                           "horizontal-spacing", &horizontal_spacing,
317                           "vertical-spacing", &vertical_spacing,
318                           NULL);
319
320     if (flags & HILDON_BUTTON_WITH_VERTICAL_VALUE) {
321         box = gtk_vbox_new (FALSE, vertical_spacing);
322     } else {
323         box = gtk_hbox_new (FALSE, horizontal_spacing);
324     }
325
326     gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (priv->title), TRUE, TRUE, 0);
327     gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (priv->value), TRUE, TRUE, 0);
328
329     gtk_container_add (GTK_CONTAINER (priv->alignment), box);
330 }
331
332 void
333 hildon_button_set_title                         (HildonButton *button,
334                                                  const char   *title)
335 {
336     HildonButtonPrivate *priv;
337
338     g_return_if_fail (HILDON_IS_BUTTON (button));
339
340     priv = HILDON_BUTTON_GET_PRIVATE (button);
341     gtk_label_set_text (priv->title, title);
342
343     if (title)
344         hildon_button_construct_child (button);
345
346     g_object_notify (G_OBJECT (button), "title");
347 }
348
349 void
350 hildon_button_set_value                         (HildonButton *button,
351                                                  const char   *value)
352 {
353     HildonButtonPrivate *priv;
354
355     g_return_if_fail (HILDON_IS_BUTTON (button));
356
357     priv = HILDON_BUTTON_GET_PRIVATE (button);
358     gtk_label_set_text (priv->value, value);
359
360     /* If the button has no value, hide the label so the title is
361      * properly aligned */
362     if (value)
363         gtk_widget_show (GTK_WIDGET (priv->value));
364     else
365         gtk_widget_hide (GTK_WIDGET (priv->value));
366
367     g_object_notify (G_OBJECT (button), "value");
368 }
369
370 const char *
371 hildon_button_get_title                         (HildonButton *button)
372 {
373     HildonButtonPrivate *priv;
374
375     g_return_val_if_fail (HILDON_IS_BUTTON (button), NULL);
376
377     priv = HILDON_BUTTON_GET_PRIVATE (button);
378
379     return gtk_label_get_text (priv->title);
380 }
381
382 const char *
383 hildon_button_get_value                         (HildonButton *button)
384 {
385     HildonButtonPrivate *priv;
386
387     g_return_val_if_fail (HILDON_IS_BUTTON (button), NULL);
388
389     priv = HILDON_BUTTON_GET_PRIVATE (button);
390
391     return gtk_label_get_text (priv->value);
392 }
393
394 void
395 hildon_button_set_text                          (HildonButton *button,
396                                                  const char   *title,
397                                                  const char   *value)
398 {
399     hildon_button_set_title (button, title);
400     hildon_button_set_value (button, value);
401 }
402
403 static void
404 hildon_button_construct_child                   (HildonButton *button)
405 {
406     HildonButtonPrivate *priv = HILDON_BUTTON_GET_PRIVATE (button);
407     GtkBin *bin = GTK_BIN (button);
408
409     /* Return if there's nothing to do */
410     if (bin->child == priv->alignment)
411         return;
412
413     if (bin->child) {
414         gtk_container_remove (GTK_CONTAINER (button), bin->child);
415     }
416
417     gtk_container_add (GTK_CONTAINER (button), priv->alignment);
418     gtk_widget_show_all (priv->alignment);
419 }