2008-09-15 Alberto Garcia <agarcia@igalia.com>
[hildon] / src / hildon-hvolumebar.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-hvolumebar
27  * @short_description: A widget that displays a horizontal volume bar.
28  * @see_also: #HildonVVolumebar, #HildonVolumebar
29  * 
30  * The #HildonHVolumebar widget displays a horizontal volume bar that allows
31  * increasing or decreasing volume within a pre-defined range, and includes 
32  * a mute icon which users can click to mute the sound.
33  * 
34  * <example>
35  * <programlisting>
36  * GtkWidget *volbar = hildon_hvolumebar_new ();
37  * g_signal_connect (G_OBJECT(volbar), "mute_toggled", G_CALLBACK(mute_toggle), NULL);
38  * g_signal_connect (G_OBJECT(volbar), "level_changed", G_CALLBACK(level_change), NULL);
39  * </programlisting>
40  * </example>
41  *
42  */
43
44 #include                                        "hildon-hvolumebar.h"
45 #include                                        "hildon-volumebar.h"
46 #include                                        "hildon-volumebar-range.h"
47 #include                                        "hildon-volumebar-private.h"
48
49 /* Defines for normal version of HVolumebar */
50 /* Toggle button */
51
52 #define                                         DEFAULT_TBUTTON_WIDTH 26
53
54 #define                                         DEFAULT_TBUTTON_HEIGHT 26
55
56 /* Volume bar */
57 #define                                         MINIMUM_BAR_WIDTH 147
58
59 #define                                         DEFAULT_BAR_HEIGHT 58
60
61 #define                                         DEFAULT_ENDING_SIZE 20
62
63 /* Gap to leave for mute button */
64 #define                                         VERTICAL_MUTE_GAP 16
65
66 #define                                         HORIZONTAL_MUTE_GAP 6
67
68 /* Sizes inside a toolbar */
69 /* Toggle button */
70
71 #define                                         TOOL_DEFAULT_TBUTTON_WIDTH 26
72
73 #define                                         TOOL_DEFAULT_TBUTTON_HEIGHT 26
74
75 /* Volumebar */
76
77 #define                                         TOOL_MINIMUM_BAR_WIDTH 121
78
79 #define                                         TOOL_DEFAULT_BAR_HEIGHT 40
80
81 #define                                         TOOL_DEFAULT_ENDING_SIZE 0
82
83 #define                                         TOOL_VERTICAL_MUTE_GAP \
84                                                 ((TOOL_DEFAULT_BAR_HEIGHT - TOOL_DEFAULT_TBUTTON_HEIGHT) / 2)
85
86 static HildonVolumebarClass*                    parent_class;
87
88 static void 
89 hildon_hvolumebar_class_init                    (HildonHVolumebarClass *klass);
90
91 static void 
92 hildon_hvolumebar_init                          (HildonHVolumebar *hvolumebar);
93
94 static gboolean
95 hildon_hvolumebar_expose                        (GtkWidget *widget,
96                                                  GdkEventExpose *event);
97 static void 
98 hildon_hvolumebar_size_request                  (GtkWidget *widget,
99                                                  GtkRequisition *requisition);
100 static void 
101 hildon_hvolumebar_size_allocate                 (GtkWidget *widget,
102                                                  GtkAllocation *allocation);
103 static void 
104 hildon_hvolumebar_map                           (GtkWidget *widget);
105
106 /**
107  * hildon_hvolumebar_get_type:
108  *
109  * Returns GType for HildonHVolumebar.
110  *
111  * Returns: HildonHVolumebar type
112  */
113 GType G_GNUC_CONST
114 hildon_hvolumebar_get_type                      (void)
115 {
116     static GType type = 0;
117
118     if (!type) {
119         static const GTypeInfo info = {
120             sizeof (HildonHVolumebarClass),
121             NULL,       /* base_init */
122             NULL,       /* base_finalize */
123             (GClassInitFunc) hildon_hvolumebar_class_init,     /* class_init */
124             NULL,       /* class_finalize */
125             NULL,       /* class_data */
126             sizeof (HildonHVolumebar),
127             0,
128             (GInstanceInitFunc) hildon_hvolumebar_init,
129         };
130         type = g_type_register_static (HILDON_TYPE_VOLUMEBAR,
131                 "HildonHVolumebar", &info, 0);
132     }
133     return type;
134 }
135
136 static void
137 hildon_hvolumebar_class_init                    (HildonHVolumebarClass *klass)
138 {
139     GtkWidgetClass *volumebar_class = GTK_WIDGET_CLASS (klass);
140
141     parent_class = g_type_class_peek_parent (klass);
142
143     volumebar_class->size_request   = hildon_hvolumebar_size_request;
144     volumebar_class->size_allocate  = hildon_hvolumebar_size_allocate;
145     volumebar_class->map            = hildon_hvolumebar_map;
146     volumebar_class->expose_event   = hildon_hvolumebar_expose;
147 }
148
149 static void 
150 hildon_hvolumebar_init                          (HildonHVolumebar *hvolumebar)
151 {
152     HildonVolumebarPrivate *priv;
153
154     priv = HILDON_VOLUMEBAR_GET_PRIVATE (hvolumebar);
155
156     priv->volumebar =
157         HILDON_VOLUMEBAR_RANGE(hildon_volumebar_range_new
158                 (GTK_ORIENTATION_HORIZONTAL));
159
160     gtk_widget_set_parent (GTK_WIDGET (priv->tbutton), GTK_WIDGET (hvolumebar));
161     gtk_widget_set_parent (GTK_WIDGET (priv->volumebar), GTK_WIDGET (hvolumebar));
162
163     gtk_scale_set_draw_value (GTK_SCALE (priv->volumebar), FALSE);
164
165     /* Signals */
166     g_signal_connect_swapped (G_OBJECT (priv->volumebar), "value-changed",
167             G_CALLBACK(hildon_volumebar_level_change),
168             hvolumebar);
169
170     g_signal_connect_swapped (priv->tbutton, "toggled",
171             G_CALLBACK (hildon_volumebar_mute_toggled), hvolumebar);
172
173     gtk_widget_show (GTK_WIDGET (priv->volumebar));
174 }
175
176 /**
177  * hildon_hvolumebar_new:
178  *
179  * Creates a new #HildonHVolumebar widget.
180  *
181  * Returns: a new #HildonHVolumebar
182  */
183 GtkWidget*
184 hildon_hvolumebar_new                           (void)
185 {
186     return GTK_WIDGET (g_object_new(HILDON_TYPE_HVOLUMEBAR, NULL));
187 }
188
189 static void 
190 hildon_hvolumebar_map                           (GtkWidget* widget)
191 {
192     HildonVolumebarPrivate *priv;
193     GtkWidget *parent;
194
195     priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
196     g_assert (priv);
197
198     parent = gtk_widget_get_ancestor (GTK_WIDGET (widget), GTK_TYPE_TOOLBAR);
199
200     /* Check if the volumebar is in a toolbar */
201     if (parent)
202         priv->is_toolbar = TRUE;
203
204     GTK_WIDGET_CLASS (parent_class)->map (widget);
205 }
206
207 static gboolean 
208 hildon_hvolumebar_expose                        (GtkWidget * widget,
209                                                  GdkEventExpose * event)
210 {
211     HildonVolumebarPrivate *priv;
212
213     priv = HILDON_VOLUMEBAR_GET_PRIVATE(HILDON_VOLUMEBAR(widget));
214     g_assert (priv);
215
216     if (GTK_WIDGET_DRAWABLE (widget)) {
217         /* Paint background */
218         gtk_paint_box (widget->style, widget->window,
219                 GTK_WIDGET_STATE (priv->volumebar), GTK_SHADOW_OUT,
220                 NULL, widget, "background",
221                 widget->allocation.x,
222                 widget->allocation.y,
223                 widget->allocation.width,
224                 widget->allocation.height);
225
226         /* The contents of the widget can paint themselves */
227         /* FIXME Not sure if this is even needed here */
228         (*GTK_WIDGET_CLASS(parent_class)->expose_event) (widget, event);
229     }
230
231     return FALSE;
232 }
233
234 static void
235 hildon_hvolumebar_size_request                  (GtkWidget * widget,
236                                                  GtkRequisition * requisition)
237 {
238     HildonVolumebarPrivate *priv;
239
240     priv = HILDON_VOLUMEBAR_GET_PRIVATE(HILDON_VOLUMEBAR(widget));
241     g_assert (priv);
242
243     /* Volumebar has different dimensions in toolbar */
244     requisition->width = (priv->is_toolbar
245             ? TOOL_MINIMUM_BAR_WIDTH
246             : MINIMUM_BAR_WIDTH);
247
248     requisition->height = (priv->is_toolbar
249             ? TOOL_DEFAULT_BAR_HEIGHT
250             : DEFAULT_BAR_HEIGHT);
251 }
252
253 static void
254 hildon_hvolumebar_size_allocate                 (GtkWidget * widget,
255                                                  GtkAllocation * allocation)
256 {
257     HildonVolumebarPrivate *priv;
258     GtkAllocation button_allocation, range_allocation;
259
260     priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
261     g_assert (priv);
262
263     button_allocation.x = 0;
264     button_allocation.width = 0;
265
266     /* Center the widget vertically */
267     if (priv->is_toolbar && allocation->height > TOOL_DEFAULT_BAR_HEIGHT) {
268         allocation->y += (allocation->height - TOOL_DEFAULT_BAR_HEIGHT) / 2;
269         allocation->height = TOOL_DEFAULT_BAR_HEIGHT;
270     }
271
272     if (!priv->is_toolbar && allocation->height > DEFAULT_BAR_HEIGHT) {
273         allocation->y += (allocation->height - DEFAULT_BAR_HEIGHT) / 2;
274         allocation->height = DEFAULT_BAR_HEIGHT;
275     }
276
277     GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
278
279     if (priv->tbutton && GTK_WIDGET_VISIBLE (priv->tbutton)) {
280
281         /* Allocate space for the mute button */
282         if (priv->is_toolbar) {
283             button_allocation.x = allocation->x;
284             button_allocation.y = allocation->y + TOOL_VERTICAL_MUTE_GAP;
285             button_allocation.width = TOOL_DEFAULT_TBUTTON_WIDTH;
286             button_allocation.height = TOOL_DEFAULT_TBUTTON_HEIGHT;
287         } else {
288             button_allocation.x = allocation->x + DEFAULT_ENDING_SIZE;
289             button_allocation.y = allocation->y + VERTICAL_MUTE_GAP;
290             button_allocation.width = DEFAULT_TBUTTON_WIDTH;
291             button_allocation.height = DEFAULT_TBUTTON_HEIGHT;
292         }
293         gtk_widget_size_allocate (GTK_WIDGET (priv->tbutton),
294                 &button_allocation);
295     }
296     if (priv->volumebar && GTK_WIDGET_VISIBLE (priv->volumebar)) {
297
298         /* Allocate space for the slider */
299         range_allocation.y = allocation->y;
300
301         if (priv->tbutton && GTK_WIDGET_VISIBLE (priv->tbutton))
302         {
303             /* Leave room for the mute button */
304             range_allocation.x = button_allocation.x
305                 + button_allocation.width
306                 + HORIZONTAL_MUTE_GAP;
307
308             if (priv->is_toolbar) 
309             {
310                 /* In toolbar with mute button */
311                 range_allocation.width = MAX(0,
312                         allocation->width
313                         - 2 * TOOL_DEFAULT_ENDING_SIZE
314                         - TOOL_DEFAULT_TBUTTON_WIDTH
315                         - HORIZONTAL_MUTE_GAP);
316
317                 range_allocation.height = TOOL_DEFAULT_BAR_HEIGHT;
318
319             } 
320
321             else 
322             {
323                 /* Standalone with mute button */
324                 range_allocation.width = MAX(0,
325                         allocation->width
326                         - 2 * DEFAULT_ENDING_SIZE
327                         - DEFAULT_TBUTTON_WIDTH
328                         - HORIZONTAL_MUTE_GAP);
329
330                 range_allocation.height = DEFAULT_BAR_HEIGHT;
331             }
332
333         }
334
335         else
336         {
337             if (priv->is_toolbar) 
338             {
339                 /* In toolbar without mute button */
340                 range_allocation.x = allocation->x;
341
342                 range_allocation.width = MAX(0,
343                         allocation->width
344                         - 2 * TOOL_DEFAULT_ENDING_SIZE );
345
346                 range_allocation.height = TOOL_DEFAULT_BAR_HEIGHT;
347
348             } 
349
350             else 
351             {
352                 /* Standalone without mute button */
353                 range_allocation.x = allocation->x + DEFAULT_ENDING_SIZE;
354
355                 range_allocation.width = MAX(0,
356                         allocation->width
357                         - 2 * DEFAULT_ENDING_SIZE );
358
359                 range_allocation.height = DEFAULT_BAR_HEIGHT;
360             }
361         }
362
363         gtk_widget_size_allocate (GTK_WIDGET (priv->volumebar),
364                 &range_allocation);
365     }
366 }
367