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