Upgrading the license headers, moving package name to "hildon" etc.
[hildon] / src / hildon-volumebar-range.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.
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  * @file hildon-volumebar-range.c
27  *
28  * This file contains the implementation of the HildonVolumebarRange.
29  * This widget is an "workhorse" for #HildonVolumebar widget. 
30  * It is not designed to be used as a standalone widget.
31  *
32  * Purpose of this widget is to act as an "container" for GtkScale
33  * widget. #HildonVolumebarRange changes some event parameters so
34  * that #HildonVolumebar can meet its specifications.
35  *
36  * Currently #HildonVolumebarRange models range of [0..100].
37  * 
38  */
39
40 #include                                        "hildon-volumebar-range.h"
41 #include                                        <gtk/gtkrange.h>
42 #include                                        <gdk/gdkkeysyms.h>
43
44 #define                                         VOLUMEBAR_RANGE_INITIAL_VALUE 50.0
45
46 #define                                         VOLUMEBAR_RANGE_MINIMUM_VALUE 0.0
47
48 #define                                         VOLUMEBAR_RANGE_MAXIMUM_VALUE 100.0
49
50 #define                                         VOLUMEBAR_RANGE_STEP_INCREMENT_VALUE 5.0
51
52 #define                                         VOLUMEBAR_RANGE_PAGE_INCREMENT_VALUE 5.0
53
54 #define                                         VOLUMEBAR_RANGE_PAGE_SIZE_VALUE 0.0
55
56 #define                                         CHANGE_THRESHOLD 0.001
57
58 static GtkScaleClass*                           parent_class;
59
60 static void 
61 hildon_volumebar_range_class_init               (HildonVolumebarRangeClass*
62                                                  volumerange_class);
63
64 static void 
65 hildon_volumebar_range_init                     (HildonVolumebarRange*
66                                                  volumerange);
67
68 static void 
69 hildon_volumebar_range_set_property             (GObject *object,
70                                                  guint prop_id,
71                                                  const GValue *value,
72                                                  GParamSpec *pspec);
73
74 static void 
75 hildon_volumebar_range_get_property             (GObject *object,
76                                                  guint prop_id,
77                                                  GValue *value,
78                                                  GParamSpec *pspec);
79
80 static gint 
81 hildon_volumebar_range_button_press_event       (GtkWidget *widget,
82                                                  GdkEventButton *event);
83
84 static gint 
85 hildon_volumebar_range_button_release_event     (GtkWidget *widget,
86                                                  GdkEventButton *event);
87
88 static gboolean
89 hildon_volumebar_range_keypress                 (GtkWidget *widget,
90                                                  GdkEventKey *event);
91
92 enum 
93 {
94   PROP_0,
95   PROP_LEVEL
96 };
97
98 GType G_GNUC_CONST
99 hildon_volumebar_range_get_type                 (void)
100 {
101     static GType volumerange_type = 0;
102
103     if (!volumerange_type) {
104         static const GTypeInfo volumerange_info = {
105             sizeof (HildonVolumebarRangeClass),
106             NULL,       /* base_init */
107             NULL,       /* base_finalize */
108             (GClassInitFunc) hildon_volumebar_range_class_init,
109             NULL,       /* class_finalize */
110             NULL,       /* class_data */
111             sizeof (HildonVolumebarRange),
112             0,  /* n_preallocs */
113             (GInstanceInitFunc) hildon_volumebar_range_init,
114         };
115         volumerange_type = g_type_register_static (GTK_TYPE_SCALE,
116                 "HildonVolumebarRange",
117                 &volumerange_info, 0);
118     }
119
120     return volumerange_type;
121 }
122
123 static void 
124 hildon_volumebar_range_class_init               (HildonVolumebarRangeClass *volumerange_class)
125 {
126     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (volumerange_class);
127     GObjectClass *object_class = G_OBJECT_CLASS (volumerange_class);
128
129     parent_class = g_type_class_peek_parent (volumerange_class);
130
131     widget_class->button_press_event =
132         hildon_volumebar_range_button_press_event;
133     widget_class->button_release_event =
134         hildon_volumebar_range_button_release_event;
135     widget_class->key_press_event = hildon_volumebar_range_keypress;
136
137     object_class->set_property = hildon_volumebar_range_set_property;
138     object_class->get_property = hildon_volumebar_range_get_property; 
139
140     g_object_class_install_property (object_class,
141             PROP_LEVEL,
142             g_param_spec_double ("level",
143                 "Level",
144                 "Current volume level",
145                 VOLUMEBAR_RANGE_MINIMUM_VALUE,
146                 VOLUMEBAR_RANGE_MAXIMUM_VALUE,
147                 VOLUMEBAR_RANGE_INITIAL_VALUE,
148                 G_PARAM_READWRITE));
149     return;
150 }
151
152 static void 
153 hildon_volumebar_range_init                     (HildonVolumebarRange *volumerange)
154 {
155     /* stepper_a = "less", stepper_d = "more" */
156     GTK_RANGE (volumerange)->has_stepper_a = TRUE;
157     GTK_RANGE (volumerange)->has_stepper_d = TRUE;
158 }
159
160 static void
161 hildon_volumebar_range_set_property             (GObject *object,
162                                                  guint prop_id,
163                                                  const GValue *value,
164                                                  GParamSpec *pspec)
165 {
166     HildonVolumebarRange *range = HILDON_VOLUMEBAR_RANGE (object);
167
168     switch (prop_id) {
169         case PROP_LEVEL:
170             hildon_volumebar_range_set_level (range, g_value_get_double (value));
171             break;
172
173         default:
174             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
175             break;
176
177     }
178 }
179
180 static void
181 hildon_volumebar_range_get_property             (GObject *object,
182                                                  guint prop_id,
183                                                  GValue *value,
184                                                  GParamSpec *pspec)
185 {
186     HildonVolumebarRange *range = HILDON_VOLUMEBAR_RANGE (object);
187
188     switch (prop_id) {
189
190         case PROP_LEVEL:
191             g_value_set_double (value, hildon_volumebar_range_get_level(range));
192             break;
193
194         default:
195             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
196             break;
197     }
198 }
199
200 static gboolean
201 hildon_volumebar_range_keypress                 (GtkWidget *widget,
202                                                  GdkEventKey *event)
203 {
204     /* Accept arrow keys only if they match the orientation of the widget */
205     if (GTK_RANGE (widget)->orientation == GTK_ORIENTATION_HORIZONTAL)
206     {
207         if (event->keyval == GDK_Up || event->keyval == GDK_Down) {
208             return FALSE;
209         }
210     }
211     else
212     {
213         if (event->keyval == GDK_Left || event->keyval == GDK_Right) {
214             return FALSE;
215         }
216     }
217
218     return ((GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget,
219                 event));
220 }
221
222 GtkWidget*
223 hildon_volumebar_range_new                      (GtkOrientation orientation)
224 {
225     GtkAdjustment * adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (VOLUMEBAR_RANGE_INITIAL_VALUE,
226                 VOLUMEBAR_RANGE_MINIMUM_VALUE,
227                 VOLUMEBAR_RANGE_MAXIMUM_VALUE,
228                 VOLUMEBAR_RANGE_STEP_INCREMENT_VALUE,
229                 VOLUMEBAR_RANGE_PAGE_INCREMENT_VALUE,
230                 VOLUMEBAR_RANGE_PAGE_SIZE_VALUE));
231
232     HildonVolumebarRange *self =
233         g_object_new(HILDON_TYPE_VOLUMEBAR_RANGE,
234                 "adjustment", adjustment,
235                 NULL);
236
237     GTK_RANGE (self)->orientation = orientation;
238
239     /* Default vertical range is upside down for purposes of this widget */
240     gtk_range_set_inverted (GTK_RANGE (self),
241             (orientation == GTK_ORIENTATION_VERTICAL));
242
243     return GTK_WIDGET(self);
244 }
245
246 gdouble 
247 hildon_volumebar_range_get_level                (HildonVolumebarRange *self)
248 {
249     g_return_val_if_fail (HILDON_IS_VOLUMEBAR_RANGE(self), -1.0);
250
251     return gtk_adjustment_get_value (gtk_range_get_adjustment(GTK_RANGE (self)));
252 }
253
254 void 
255 hildon_volumebar_range_set_level                (HildonVolumebarRange * self,
256                                                  gdouble level)
257 {
258     GtkAdjustment *adjustment;
259
260     g_return_if_fail (HILDON_IS_VOLUMEBAR_RANGE (self));
261
262     adjustment = gtk_range_get_adjustment (GTK_RANGE (self));
263
264     /* Check that value has actually changed. Note that it's not safe to
265      * just compare if floats are equivalent or not */
266     if (ABS (gtk_adjustment_get_value (adjustment) - level) > CHANGE_THRESHOLD) {
267         gtk_adjustment_set_value(adjustment, level);
268     }
269 }
270
271 static gint 
272 hildon_volumebar_range_button_press_event       (GtkWidget *widget,
273                                                  GdkEventButton *event)
274 {
275     gboolean result = FALSE;
276
277     /* FIXME: By default, clicking left mouse button on GtkRange moves the
278        slider by one step towards the click location. However, we want stylus
279        taps to move the slider to the position of the tap, which by default
280        is the middle button behaviour. To avoid breaking default GtkRange
281        behaviour, this has been implemented by faking a middle button press. */
282
283     event->button = (event->button == 1) ? 2 : event->button;
284     if (GTK_WIDGET_CLASS (parent_class)->button_press_event) {
285         result = GTK_WIDGET_CLASS (parent_class)->button_press_event(widget, event);
286     }
287
288     return result;
289 }
290
291 static gint
292 hildon_volumebar_range_button_release_event     (GtkWidget *widget,
293                                                  GdkEventButton *event)
294 {
295     gboolean result = FALSE;
296
297     /* FIXME: By default, clicking left mouse button on GtkRange moves the
298        slider by one step towards the click location. However, we want stylus
299        taps to move the slider to the position of the tap, which by default
300        is the middle button behaviour. To avoid breaking default GtkRange
301        behaviour, this has been implemented by faking a middle button press. */
302
303     event->button = event->button == 1 ? 2 : event->button;
304     if (GTK_WIDGET_CLASS (parent_class)->button_release_event) {
305         result = GTK_WIDGET_CLASS(parent_class)->button_release_event(widget, event);
306     }
307
308     return result;
309 }
310