Add a 'size' property to HildonCheckButton and HildonEntry
[hildon] / hildon / hildon-check-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-check-button
19  * @short_description: Button with a check box inside
20  *
21  * #HildonCheckButton is a button containing a label and a check box
22  * which will remain 'pressed-in' when clicked. Clicking again will
23  * make the check box toggle its state.
24  *
25  * The state of a #HildonCheckButton can be set using
26  * hildon_check_button_set_active(), and retrieved using
27  * hildon_check_button_get_active(). The label can be set using
28  * gtk_button_set_label() and retrieved using gtk_button_get_label().
29  *
30  * <note>
31  *   <para>
32  * #HildonCheckButton does NOT support an image, so don't use
33  * gtk_button_set_image().
34  *   </para>
35  * </note>
36  *
37  * <example>
38  * <title>Using a Hildon check button</title>
39  * <programlisting>
40  * void
41  * button_toggled (HildonCheckButton *button, gpointer user_data)
42  * {
43  *     gboolean active;
44  * <!-- -->
45  *     active = hildon_check_button_get_active (button);
46  *     if (active)
47  *        g_debug ("Button is active");
48  *     else
49  *        g_debug ("Button is not active");
50  * }
51  * <!-- -->
52  * GtkWidget *
53  * create_button (void)
54  * {
55  *     GtkWidget *button;
56  * <!-- -->
57  *     button = hildon_check_button_new (HILDON_SIZE_AUTO);
58  *     gtk_button_set_label (GTK_BUTTON (button), "Click me");
59  * <!-- -->
60  *     g_signal_connect (button, "toggled", G_CALLBACK (button_toggled), NULL);
61  * <!-- -->
62  *     return button;
63  * }
64  * </programlisting>
65  * </example>
66  */
67
68 #include                                        "hildon-check-button.h"
69
70 enum {
71   TOGGLED,
72   LAST_SIGNAL
73 };
74
75 enum {
76     PROP_SIZE = 1
77 };
78
79 static guint                                    signals[LAST_SIGNAL] = { 0 };
80
81 G_DEFINE_TYPE                                   (HildonCheckButton, hildon_check_button, GTK_TYPE_BUTTON);
82
83 #define                                         HILDON_CHECK_BUTTON_GET_PRIVATE(obj) \
84                                                 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
85                                                 HILDON_TYPE_CHECK_BUTTON, HildonCheckButtonPrivate));
86
87 struct                                          _HildonCheckButtonPrivate
88 {
89     GtkCellRendererToggle *toggle_renderer;
90 };
91
92 /**
93  * hildon_check_button_toggled:
94  * @button: A #HildonCheckButton
95  *
96  * Emits the #HildonCheckButton::toggled signal on the #HildonCheckButton.
97  * There is no good reason for an application ever to call this function.
98  *
99  * Since: 2.2
100  */
101 void
102 hildon_check_button_toggled                     (HildonCheckButton *button)
103 {
104     g_return_if_fail (HILDON_IS_CHECK_BUTTON (button));
105
106     g_signal_emit (button, signals[TOGGLED], 0);
107 }
108
109 /**
110  * hildon_check_button_set_active:
111  * @button: A #HildonCheckButton
112  * @is_active: new state for the button
113  *
114  * Sets the status of a #HildonCheckButton. Set to %TRUE if you want
115  * @button to be 'pressed-in', and %FALSE to raise it. This action
116  * causes the #HildonCheckButton::toggled signal to be emitted.
117  *
118  * Since: 2.2
119  **/
120 void
121 hildon_check_button_set_active                  (HildonCheckButton *button,
122                                                  gboolean           is_active)
123 {
124     gboolean prev_is_active;
125
126     g_return_if_fail (HILDON_IS_CHECK_BUTTON (button));
127
128     prev_is_active = hildon_check_button_get_active (button);
129
130     if (prev_is_active != is_active) {
131         gtk_button_clicked (GTK_BUTTON (button));
132         gtk_widget_queue_draw (GTK_WIDGET (button));
133     }
134 }
135
136 /**
137  * hildon_check_button_get_active:
138  * @button: A #HildonCheckButton
139  *
140  * Gets the current state of @button.
141  *
142  * Return value: %TRUE if @button is active, %FALSE otherwise.
143  *
144  * Since: 2.2
145  **/
146 gboolean
147 hildon_check_button_get_active                  (HildonCheckButton *button)
148 {
149     g_return_val_if_fail (HILDON_IS_CHECK_BUTTON (button), FALSE);
150
151     return gtk_cell_renderer_toggle_get_active (button->priv->toggle_renderer);
152 }
153
154 /**
155  * hildon_check_button_new:
156  * @size: Flags indicating the size of the new button
157  *
158  * Creates a new #HildonCheckButton.
159  *
160  * Return value: A newly created #HildonCheckButton
161  *
162  * Since: 2.2
163  **/
164 GtkWidget *
165 hildon_check_button_new                         (HildonSizeType size)
166 {
167     return g_object_new (HILDON_TYPE_CHECK_BUTTON, "xalign", 0.0, "size", size, NULL);
168 }
169
170 static void
171 hildon_check_button_clicked                     (GtkButton *button)
172 {
173     HildonCheckButton *checkbutton = HILDON_CHECK_BUTTON (button);
174     gboolean current = hildon_check_button_get_active (checkbutton);
175
176     gtk_cell_renderer_toggle_set_active (checkbutton->priv->toggle_renderer, !current);
177
178     hildon_check_button_toggled (checkbutton);
179 }
180
181 static void
182 hildon_check_button_apply_style                 (GtkWidget *widget)
183 {
184     guint checkbox_size;
185     HildonCheckButtonPrivate *priv = HILDON_CHECK_BUTTON (widget)->priv;
186
187     gtk_widget_style_get (widget, "checkbox-size", &checkbox_size, NULL);
188
189     g_object_set (priv->toggle_renderer, "indicator-size", checkbox_size, NULL);
190 }
191
192 static void
193 hildon_check_button_style_set                   (GtkWidget *widget,
194                                                  GtkStyle  *previous_style)
195 {
196     if (GTK_WIDGET_CLASS (hildon_check_button_parent_class)->style_set)
197         GTK_WIDGET_CLASS (hildon_check_button_parent_class)->style_set (widget, previous_style);
198
199     hildon_check_button_apply_style (widget);
200 }
201
202 static void
203 set_property                                    (GObject      *object,
204                                                  guint         prop_id,
205                                                  const GValue *value,
206                                                  GParamSpec   *pspec)
207 {
208     switch (prop_id)
209     {
210     case PROP_SIZE:
211         hildon_gtk_widget_set_theme_size (GTK_WIDGET (object), g_value_get_flags (value));
212         break;
213     default:
214         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215         break;
216     }
217 }
218
219 static void
220 hildon_check_button_class_init                  (HildonCheckButtonClass *klass)
221 {
222     GObjectClass *gobject_class = (GObjectClass*) klass;
223     GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
224     GtkButtonClass *button_class = (GtkButtonClass*) klass;
225
226     gobject_class->set_property = set_property;
227     widget_class->style_set = hildon_check_button_style_set;
228     button_class->clicked = hildon_check_button_clicked;
229
230     klass->toggled = NULL;
231
232     /**
233      * HildonCheckButton::toggled
234      *
235      * Emitted when the #HildonCheckButton's state is changed.
236      *
237      * Since: 2.2
238      */
239     signals[TOGGLED] =
240         g_signal_new ("toggled",
241                       G_OBJECT_CLASS_TYPE (gobject_class),
242                       G_SIGNAL_RUN_FIRST,
243                       G_STRUCT_OFFSET (HildonCheckButtonClass, toggled),
244                       NULL, NULL,
245                       g_cclosure_marshal_VOID__VOID,
246                       G_TYPE_NONE, 0);
247
248     gtk_widget_class_install_style_property (
249         widget_class,
250         g_param_spec_uint (
251             "checkbox-size",
252             "Size of the check box",
253             "Size of the check box",
254             0, G_MAXUINT, 26,
255             G_PARAM_READABLE));
256
257     g_object_class_install_property (
258         gobject_class,
259         PROP_SIZE,
260         g_param_spec_flags (
261             "size",
262             "Size",
263             "Size request for the button",
264             HILDON_TYPE_SIZE_TYPE,
265             HILDON_SIZE_AUTO,
266             G_PARAM_WRITABLE));
267
268     g_type_class_add_private (klass, sizeof (HildonCheckButtonPrivate));
269 }
270
271 static void
272 hildon_check_button_init                        (HildonCheckButton *button)
273 {
274     HildonCheckButtonPrivate *priv = HILDON_CHECK_BUTTON_GET_PRIVATE (button);
275     GtkWidget *cell_view = gtk_cell_view_new ();
276
277     /* Store private part */
278     button->priv = priv;
279
280     /* Make sure that the check box is always shown, no matter the value of gtk-button-images */
281     g_signal_connect (cell_view, "notify::visible", G_CALLBACK (gtk_widget_show), NULL);
282
283     /* Create toggle renderer and pack it into the cell view */
284     priv->toggle_renderer = GTK_CELL_RENDERER_TOGGLE (gtk_cell_renderer_toggle_new ());
285     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cell_view),
286                                 GTK_CELL_RENDERER (priv->toggle_renderer), FALSE);
287
288     /* Add cell view to the image */
289     gtk_button_set_image (GTK_BUTTON (button), cell_view);
290
291     gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
292
293     hildon_check_button_apply_style (GTK_WIDGET (button));
294 }