2006-08-30 Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
[hildon] / hildon-widgets / hildon-hvolumebar.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation.
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.
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
35
36 /* Horizontal volumebar subclass */
37
38 #include <gtk/gtktoolbar.h>
39 #include "hildon-hvolumebar.h"
40 #include "hildon-volumebar.h"
41 #include "hildon-volumebar-range.h"
42 #include "hildon-volumebar-private.h"
43
44 /* Defines for normal version of HVolumebar */
45 /* Toggle button */
46 #define DEFAULT_TBUTTON_WIDTH  26
47 #define DEFAULT_TBUTTON_HEIGHT 26
48 /* Volume bar */
49 #define MINIMUM_BAR_WIDTH     147
50 #define DEFAULT_BAR_HEIGHT     58
51 #define DEFAULT_ENDING_SIZE    20
52
53 /* Gap to leave for mute button */
54 #define VERTICAL_MUTE_GAP      16
55 #define HORIZONTAL_MUTE_GAP     6
56
57 /* Sizes inside a toolbar */
58 /* Toggle button */
59 #define TOOL_DEFAULT_TBUTTON_WIDTH  26
60 #define TOOL_DEFAULT_TBUTTON_HEIGHT 26
61 /* Volumebar */
62 #define TOOL_MINIMUM_BAR_WIDTH     121
63 #define TOOL_DEFAULT_BAR_HEIGHT     40
64 #define TOOL_DEFAULT_ENDING_SIZE     0
65 #define TOOL_VERTICAL_MUTE_GAP ((TOOL_DEFAULT_BAR_HEIGHT - TOOL_DEFAULT_TBUTTON_HEIGHT) / 2)
66
67 static HildonVolumebarClass *parent_class;
68 static void hildon_hvolumebar_class_init(HildonHVolumebarClass * klass);
69 static void hildon_hvolumebar_init(HildonHVolumebar * hvolumebar);
70
71 static gboolean hildon_hvolumebar_expose(GtkWidget * widget,
72                                          GdkEventExpose * event);
73 static void hildon_hvolumebar_size_request(GtkWidget * widget,
74                                            GtkRequisition * requisition);
75 static void hildon_hvolumebar_size_allocate(GtkWidget * widget,
76                                             GtkAllocation * allocation);
77 static void hildon_hvolumebar_map(GtkWidget * widget);
78
79
80 GType hildon_hvolumebar_get_type(void)
81 {
82     static GType type = 0;
83
84     if (!type) {
85         static const GTypeInfo info = {
86             sizeof(HildonHVolumebarClass),
87             NULL,       /* base_init */
88             NULL,       /* base_finalize */
89             (GClassInitFunc) hildon_hvolumebar_class_init,     /* class_init */
90             NULL,       /* class_finalize */
91             NULL,       /* class_data */
92             sizeof(HildonHVolumebar),
93             0,
94             (GInstanceInitFunc) hildon_hvolumebar_init,
95         };
96         type = g_type_register_static(HILDON_TYPE_VOLUMEBAR,
97                                       "HildonHVolumebar", &info, 0);
98     }
99     return type;
100 }
101
102
103 static void hildon_hvolumebar_class_init(HildonHVolumebarClass * klass)
104 {
105     GtkWidgetClass *volumebar_class = GTK_WIDGET_CLASS(klass);
106
107     parent_class = g_type_class_peek_parent(klass);
108
109     volumebar_class->size_request = hildon_hvolumebar_size_request;
110     volumebar_class->size_allocate = hildon_hvolumebar_size_allocate;
111     volumebar_class->map = hildon_hvolumebar_map;
112     volumebar_class->expose_event = hildon_hvolumebar_expose;
113 }
114
115
116 static void hildon_hvolumebar_init(HildonHVolumebar * hvolumebar)
117 {
118     HildonVolumebarPrivate *priv;
119
120     priv = HILDON_VOLUMEBAR_GET_PRIVATE(hvolumebar);
121
122     priv->volumebar =
123         HILDON_VOLUMEBAR_RANGE(hildon_volumebar_range_new
124                                (GTK_ORIENTATION_HORIZONTAL));
125
126     GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(hvolumebar), GTK_CAN_FOCUS);
127
128     gtk_widget_set_parent(GTK_WIDGET(priv->tbutton), GTK_WIDGET(hvolumebar));
129     gtk_widget_set_parent(GTK_WIDGET(priv->volumebar), GTK_WIDGET(hvolumebar));
130
131     gtk_scale_set_draw_value(GTK_SCALE(priv->volumebar), FALSE);
132
133     /* Signals */
134     g_signal_connect_swapped(G_OBJECT(priv->volumebar), "value-changed",
135                              G_CALLBACK(hildon_volumebar_level_change),
136                              hvolumebar);
137     g_signal_connect_swapped(priv->tbutton, "toggled",
138         G_CALLBACK(_hildon_volumebar_mute_toggled), hvolumebar);
139
140     gtk_widget_show(GTK_WIDGET(priv->volumebar));
141 }
142
143 /**
144  * hildon_hvolumebar_new:
145  *
146  * Creates a new #HildonHVolumebar widget.
147  *
148  * Returns: a new #HildonHVolumebar
149  */
150 GtkWidget *hildon_hvolumebar_new(void)
151 {
152     return GTK_WIDGET(g_object_new(HILDON_TYPE_HVOLUMEBAR, NULL));
153 }
154
155 static void hildon_hvolumebar_map(GtkWidget * widget)
156 {
157     HildonVolumebarPrivate *priv;
158     GtkWidget *parent;
159
160     g_assert(HILDON_IS_HVOLUMEBAR(widget));
161
162     priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
163     parent = gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_TOOLBAR);
164
165     /* Check if the volumebar is in a toolbar */
166     if (parent)
167         priv->is_toolbar = TRUE;
168
169     GTK_WIDGET_CLASS(parent_class)->map(widget);
170 }
171
172 static gboolean hildon_hvolumebar_expose(GtkWidget * widget,
173                                          GdkEventExpose * event)
174 {
175     HildonVolumebarPrivate *priv;
176
177     g_assert(HILDON_IS_HVOLUMEBAR(widget));
178
179     priv = HILDON_VOLUMEBAR_GET_PRIVATE(HILDON_VOLUMEBAR(widget));
180
181     if (GTK_WIDGET_DRAWABLE(widget)) {
182         /* Paint background */
183         gtk_paint_box(widget->style, widget->window,
184                       GTK_WIDGET_STATE(priv->volumebar), GTK_SHADOW_OUT,
185                       NULL, widget, "background",
186                       widget->allocation.x,
187                       widget->allocation.y,
188                       widget->allocation.width,
189                       widget->allocation.height);
190
191         /* The contents of the widget can paint themselves */
192         (*GTK_WIDGET_CLASS(parent_class)->expose_event) (widget, event);
193     }
194
195     return FALSE;
196 }
197
198 static void
199 hildon_hvolumebar_size_request(GtkWidget * widget,
200                                GtkRequisition * requisition)
201 {
202     HildonVolumebarPrivate *priv;
203
204     g_assert(HILDON_IS_HVOLUMEBAR(widget));
205
206     priv = HILDON_VOLUMEBAR_GET_PRIVATE(HILDON_VOLUMEBAR(widget));
207
208     /* Volumebar has different dimensions in toolbar */
209     requisition->width = (priv->is_toolbar
210                           ? TOOL_MINIMUM_BAR_WIDTH
211                           : MINIMUM_BAR_WIDTH);
212     requisition->height = (priv->is_toolbar
213                            ? TOOL_DEFAULT_BAR_HEIGHT
214                            : DEFAULT_BAR_HEIGHT);
215 }
216
217 static void
218 hildon_hvolumebar_size_allocate(GtkWidget * widget,
219                                 GtkAllocation * allocation)
220 {
221     HildonVolumebarPrivate *priv;
222     GtkAllocation button_allocation, range_allocation;
223
224     g_assert(HILDON_IS_HVOLUMEBAR(widget));
225
226     priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
227     
228     button_allocation.x = 0;
229     button_allocation.width = 0;
230     
231     /* Center the widget vertically */
232     if (priv->is_toolbar && allocation->height > TOOL_DEFAULT_BAR_HEIGHT) {
233         allocation->y += (allocation->height - TOOL_DEFAULT_BAR_HEIGHT) / 2;
234         allocation->height = TOOL_DEFAULT_BAR_HEIGHT;
235     }
236     if (!priv->is_toolbar && allocation->height > DEFAULT_BAR_HEIGHT) {
237         allocation->y += (allocation->height - DEFAULT_BAR_HEIGHT) / 2;
238         allocation->height = DEFAULT_BAR_HEIGHT;
239     }
240
241     widget->allocation = *allocation;
242
243     if (priv->tbutton && GTK_WIDGET_VISIBLE(priv->tbutton)) {
244
245         /* Allocate space for the mute button */
246         if (priv->is_toolbar) {
247             button_allocation.x = allocation->x;
248             button_allocation.y = allocation->y + TOOL_VERTICAL_MUTE_GAP;
249             button_allocation.width = TOOL_DEFAULT_TBUTTON_WIDTH;
250             button_allocation.height = TOOL_DEFAULT_TBUTTON_HEIGHT;
251         } else {
252             button_allocation.x = allocation->x + DEFAULT_ENDING_SIZE;
253             button_allocation.y = allocation->y + VERTICAL_MUTE_GAP;
254             button_allocation.width = DEFAULT_TBUTTON_WIDTH;
255             button_allocation.height = DEFAULT_TBUTTON_HEIGHT;
256         }
257         gtk_widget_size_allocate(GTK_WIDGET(priv->tbutton),
258                                  &button_allocation);
259     }
260     if (priv->volumebar && GTK_WIDGET_VISIBLE(priv->volumebar)) {
261
262         /* Allocate space for the slider */
263         range_allocation.y = allocation->y;
264         
265         if (priv->tbutton && GTK_WIDGET_VISIBLE(priv->tbutton))
266         {
267             /* Leave room for the mute button */
268             range_allocation.x = button_allocation.x
269                                  + button_allocation.width
270                                  + HORIZONTAL_MUTE_GAP;
271         
272             if (priv->is_toolbar) 
273             {
274                 /* In toolbar with mute button */
275                 range_allocation.width = MAX(0,
276                                            allocation->width
277                                            - 2 * TOOL_DEFAULT_ENDING_SIZE
278                                            - TOOL_DEFAULT_TBUTTON_WIDTH
279                                            - HORIZONTAL_MUTE_GAP);
280                                          
281                 range_allocation.height = TOOL_DEFAULT_BAR_HEIGHT;
282             
283             } 
284             
285             else 
286             {
287                 /* Standalone with mute button */
288                 range_allocation.width = MAX(0,
289                                              allocation->width
290                                              - 2 * DEFAULT_ENDING_SIZE
291                                              - DEFAULT_TBUTTON_WIDTH
292                                              - HORIZONTAL_MUTE_GAP);
293
294                 range_allocation.height = DEFAULT_BAR_HEIGHT;
295             }
296         
297         }
298         
299         else
300         {
301             if (priv->is_toolbar) 
302             {
303                 /* In toolbar without mute button */
304                 range_allocation.x = allocation->x;
305                 
306                 range_allocation.width = MAX(0,
307                                         allocation->width
308                                         - 2 * TOOL_DEFAULT_ENDING_SIZE );
309                                          
310                 range_allocation.height = TOOL_DEFAULT_BAR_HEIGHT;
311             
312             } 
313             
314             else 
315             {
316                 /* Standalone without mute button */
317                 range_allocation.x = allocation->x + DEFAULT_ENDING_SIZE;
318                 
319                 range_allocation.width = MAX(0,
320                                              allocation->width
321                                              - 2 * DEFAULT_ENDING_SIZE );
322
323                 range_allocation.height = DEFAULT_BAR_HEIGHT;
324             }
325         }
326
327         gtk_widget_size_allocate(GTK_WIDGET(priv->volumebar),
328                                  &range_allocation);
329     }
330 }