* src/hildon-button.h * src/hildon-button.c (hildon_button_new) (hildon_button_new_wi...
[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
28 #include                                        "hildon-button.h"
29
30 #define FINGER_BUTTON_HEIGHT                    70
31 #define THUMB_BUTTON_HEIGHT                     105
32 #define HALFSCREEN_BUTTON_WIDTH                 400
33 #define FULLSCREEN_BUTTON_WIDTH                 800
34
35 G_DEFINE_TYPE                                   (HildonButton, hildon_button, GTK_TYPE_BUTTON);
36
37 #define                                         HILDON_BUTTON_GET_PRIVATE(obj) \
38                                                 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
39                                                 HILDON_TYPE_BUTTON, HildonButtonPrivate));
40
41 typedef struct                                  _HildonButtonPrivate HildonButtonPrivate;
42
43 struct                                          _HildonButtonPrivate
44 {
45     GtkLabel *title;
46     GtkLabel *value;
47     GtkWidget *alignment;
48 };
49
50 enum {
51   PROP_TITLE = 1,
52   PROP_VALUE,
53   PROP_ARRANGEMENT_FLAGS
54 };
55
56 static void
57 hildon_button_set_arrangement                   (HildonButton      *button,
58                                                  HildonButtonFlags  flags);
59
60 static void
61 hildon_button_construct_child                   (HildonButton *button);
62
63 static void
64 hildon_button_set_property                      (GObject      *object,
65                                                  guint         prop_id,
66                                                  const GValue *value,
67                                                  GParamSpec   *pspec)
68 {
69     HildonButton *button = HILDON_BUTTON (object);
70
71     switch (prop_id)
72     {
73     case PROP_TITLE:
74         hildon_button_set_title (button, g_value_get_string (value));
75         break;
76     case PROP_VALUE:
77         hildon_button_set_value (button, g_value_get_string (value));
78         break;
79     case PROP_ARRANGEMENT_FLAGS:
80         hildon_button_set_arrangement (button, g_value_get_int (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_button_get_property                      (GObject    *object,
90                                                  guint       prop_id,
91                                                  GValue     *value,
92                                                  GParamSpec *pspec)
93 {
94     HildonButton *button = HILDON_BUTTON (object);
95     HildonButtonPrivate *priv = HILDON_BUTTON_GET_PRIVATE (button);
96
97     switch (prop_id)
98     {
99     case PROP_TITLE:
100         g_value_set_string (value, gtk_label_get_text (priv->title));
101         break;
102     case PROP_VALUE:
103         g_value_set_string (value, gtk_label_get_text (priv->value));
104         break;
105     default:
106         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
107         break;
108     }
109 }
110
111 static void
112 hildon_button_class_init                        (HildonButtonClass *klass)
113 {
114     GObjectClass *gobject_class = (GObjectClass *)klass;
115     GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
116
117     gobject_class->set_property = hildon_button_set_property;
118     gobject_class->get_property = hildon_button_get_property;
119
120     g_object_class_install_property (
121         gobject_class,
122         PROP_TITLE,
123         g_param_spec_string (
124             "title",
125             "Title",
126             "Text of the title label inside the button",
127             NULL,
128             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
129
130     g_object_class_install_property (
131         gobject_class,
132         PROP_VALUE,
133         g_param_spec_string (
134             "value",
135             "Value",
136             "Text of the value label inside the button",
137             NULL,
138             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
139
140     g_object_class_install_property (
141         gobject_class,
142         PROP_ARRANGEMENT_FLAGS,
143         g_param_spec_int (
144             "arrangement-flags",
145             "Arrangement flags",
146             "How the button contents must be arranged",
147             0, 64,
148             HILDON_BUTTON_WITH_HORIZONTAL_VALUE,
149             G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
150
151     gtk_widget_class_install_style_property (
152         widget_class,
153         g_param_spec_uint (
154             "horizontal-spacing",
155             "Horizontal spacing between labels",
156             "Horizontal spacing between the title and value labels, when in horizontal mode",
157             0, G_MAXUINT, 25,
158             G_PARAM_READABLE));
159
160     gtk_widget_class_install_style_property (
161         widget_class,
162         g_param_spec_uint (
163             "vertical-spacing",
164             "Vertical spacing between labels",
165             "Vertical spacing between the title and value labels, when in vertical mode",
166             0, G_MAXUINT, 5,
167             G_PARAM_READABLE));
168
169     g_type_class_add_private (klass, sizeof (HildonButtonPrivate));
170 }
171
172 static void
173 hildon_button_init                              (HildonButton *self)
174 {
175     HildonButtonPrivate *priv = HILDON_BUTTON_GET_PRIVATE (self);
176
177     priv->title = GTK_LABEL (gtk_label_new (NULL));
178     priv->value = GTK_LABEL (gtk_label_new (NULL));
179     priv->alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
180
181     gtk_widget_set_name (GTK_WIDGET (priv->title), "hildon-button-title");
182     gtk_widget_set_name (GTK_WIDGET (priv->value), "hildon-button-value");
183
184     gtk_misc_set_alignment (GTK_MISC (priv->title), 0, 0.5);
185     gtk_misc_set_alignment (GTK_MISC (priv->value), 0, 0.5);
186
187     /* The value label is not shown automatically, see hildon_button_set_value() */
188     gtk_widget_set_no_show_all (GTK_WIDGET (priv->value), TRUE);
189 }
190
191 void
192 hildon_button_set_size_groups                   (HildonButton *button,
193                                                  GtkSizeGroup *title_size_group,
194                                                  GtkSizeGroup *value_size_group)
195 {
196     HildonButtonPrivate *priv;
197
198     g_return_if_fail (HILDON_IS_BUTTON (button));
199
200     priv = HILDON_BUTTON_GET_PRIVATE (button);
201
202     if (title_size_group)
203         gtk_size_group_add_widget (title_size_group, GTK_WIDGET (priv->title));
204
205     if (value_size_group)
206         gtk_size_group_add_widget (value_size_group, GTK_WIDGET (priv->value));
207 }
208
209 GtkWidget *
210 hildon_button_new                               (HildonButtonFlags  flags)
211 {
212     return hildon_button_new_full (flags, NULL, NULL, NULL, NULL);
213 }
214
215 GtkWidget *
216 hildon_button_new_with_text                     (HildonButtonFlags  flags,
217                                                  const char        *title,
218                                                  const char        *value)
219 {
220     return hildon_button_new_full (flags, title, value, NULL, NULL);
221 }
222
223 GtkWidget *
224 hildon_button_new_full                          (HildonButtonFlags  flags,
225                                                  const char        *title,
226                                                  const char        *value,
227                                                  GtkSizeGroup      *title_size_group,
228                                                  GtkSizeGroup      *value_size_group)
229 {
230     GtkWidget *button;
231
232     /* Create widget */
233     button = g_object_new (HILDON_TYPE_BUTTON,
234                            "arrangement-flags", flags,
235                            "title", title,
236                            "value", value,
237                            "name", "hildon-button",
238                            NULL);
239     /* Set size groups */
240     if (title_size_group || value_size_group)
241         hildon_button_set_size_groups (HILDON_BUTTON (button), title_size_group, value_size_group);
242
243     return button;
244 }
245
246 static void
247 hildon_button_set_arrangement (HildonButton *button,
248                                HildonButtonFlags flags)
249 {
250     GtkWidget *box;
251     HildonButtonPrivate *priv;
252     guint horizontal_spacing;
253     guint vertical_spacing;
254     gint width = -1;
255     gint height = -1;
256     const char *widget_name = NULL;
257
258     priv = HILDON_BUTTON_GET_PRIVATE (button);
259
260     /* Requested height */
261     if (flags & HILDON_BUTTON_FINGER_HEIGHT) {
262         height = FINGER_BUTTON_HEIGHT;
263         widget_name = "hildon-finger-button";
264     } else if (flags & HILDON_BUTTON_THUMB_HEIGHT) {
265         height = THUMB_BUTTON_HEIGHT;
266         widget_name = "hildon-thumb-button";
267     }
268
269     if (widget_name) {
270         gtk_widget_set_name (GTK_WIDGET (button), widget_name);
271     }
272
273     /* Requested width */
274     if (flags & HILDON_BUTTON_HALFSCREEN_WIDTH) {
275         width = HALFSCREEN_BUTTON_WIDTH;
276     } else if (flags & HILDON_BUTTON_FULLSCREEN_WIDTH) {
277         width = FULLSCREEN_BUTTON_WIDTH;
278     }
279
280     g_object_set (button,
281                   "width-request", width,
282                   "height-request", height,
283                   NULL);
284
285     /* Pack everything */
286     gtk_widget_style_get (GTK_WIDGET (button),
287                           "horizontal-spacing", &horizontal_spacing,
288                           "vertical-spacing", &vertical_spacing,
289                           NULL);
290
291     if (flags & HILDON_BUTTON_WITH_VERTICAL_VALUE) {
292         box = gtk_vbox_new (FALSE, vertical_spacing);
293     } else {
294         box = gtk_hbox_new (FALSE, horizontal_spacing);
295     }
296
297     gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (priv->title), TRUE, TRUE, 0);
298     gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (priv->value), TRUE, TRUE, 0);
299
300     gtk_container_add (GTK_CONTAINER (priv->alignment), box);
301 }
302
303 void
304 hildon_button_set_title                         (HildonButton *button,
305                                                  const char   *title)
306 {
307     HildonButtonPrivate *priv;
308
309     g_return_if_fail (HILDON_IS_BUTTON (button));
310
311     priv = HILDON_BUTTON_GET_PRIVATE (button);
312     gtk_label_set_text (priv->title, title);
313
314     if (title)
315         hildon_button_construct_child (button);
316
317     g_object_notify (G_OBJECT (button), "title");
318 }
319
320 void
321 hildon_button_set_value                         (HildonButton *button,
322                                                  const char   *value)
323 {
324     HildonButtonPrivate *priv;
325
326     g_return_if_fail (HILDON_IS_BUTTON (button));
327
328     priv = HILDON_BUTTON_GET_PRIVATE (button);
329     gtk_label_set_text (priv->value, value);
330
331     /* If the button has no value, hide the label so the title is
332      * properly aligned */
333     if (value)
334         gtk_widget_show (GTK_WIDGET (priv->value));
335     else
336         gtk_widget_hide (GTK_WIDGET (priv->value));
337
338     g_object_notify (G_OBJECT (button), "value");
339 }
340
341 const char *
342 hildon_button_get_title                         (HildonButton *button)
343 {
344     HildonButtonPrivate *priv;
345
346     g_return_val_if_fail (HILDON_IS_BUTTON (button), NULL);
347
348     priv = HILDON_BUTTON_GET_PRIVATE (button);
349
350     return gtk_label_get_text (priv->title);
351 }
352
353 const char *
354 hildon_button_get_value                         (HildonButton *button)
355 {
356     HildonButtonPrivate *priv;
357
358     g_return_val_if_fail (HILDON_IS_BUTTON (button), NULL);
359
360     priv = HILDON_BUTTON_GET_PRIVATE (button);
361
362     return gtk_label_get_text (priv->value);
363 }
364
365 void
366 hildon_button_set_text                          (HildonButton *button,
367                                                  const char   *title,
368                                                  const char   *value)
369 {
370     hildon_button_set_title (button, title);
371     hildon_button_set_value (button, value);
372 }
373
374 static void
375 hildon_button_construct_child                   (HildonButton *button)
376 {
377     HildonButtonPrivate *priv = HILDON_BUTTON_GET_PRIVATE (button);
378     GtkBin *bin = GTK_BIN (button);
379
380     /* Return if there's nothing to do */
381     if (bin->child == priv->alignment)
382         return;
383
384     if (bin->child) {
385         gtk_container_remove (GTK_CONTAINER (button), bin->child);
386     }
387
388     gtk_container_add (GTK_CONTAINER (button), priv->alignment);
389     gtk_widget_show_all (priv->alignment);
390 }