2 * This file is part of hildon-libs
4 * Copyright (C) 2005, 2006 Nokia Corporation.
6 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
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
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.
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
26 * @file hildon-volumebar-range.c
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.
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.
36 * Currently #HildonVolumebarRange models range of [0..100].
44 #include <gtk/gtkrange.h>
45 #include <gdk/gdkkeysyms.h>
46 #include "hildon-volumebar-range.h"
48 #define VOLUMEBAR_RANGE_INITIAL_VALUE 50.0
49 #define VOLUMEBAR_RANGE_MINIMUM_VALUE 0.0
50 #define VOLUMEBAR_RANGE_MAXIMUM_VALUE 100.0
51 #define VOLUMEBAR_RANGE_STEP_INCREMENT_VALUE 5.0
52 #define VOLUMEBAR_RANGE_PAGE_INCREMENT_VALUE 5.0
53 #define VOLUMEBAR_RANGE_PAGE_SIZE_VALUE 0.0
55 #define CHANGE_THRESHOLD 0.001
57 static GtkScaleClass *parent_class;
59 static void hildon_volumebar_range_class_init(HildonVolumebarRangeClass *
61 static void hildon_volumebar_range_init(HildonVolumebarRange *
63 static void hildon_volumebar_range_set_property(GObject * object,
67 static void hildon_volumebar_range_get_property(GObject * object,
71 static gint hildon_volumebar_range_button_press_event(GtkWidget * widget,
74 static gint hildon_volumebar_range_button_release_event(GtkWidget * widget,
77 static gboolean hildon_volumebar_range_keypress(GtkWidget * widget,
86 hildon_volumebar_range_get_type(void)
88 static GType volumerange_type = 0;
90 if (!volumerange_type) {
91 static const GTypeInfo volumerange_info = {
92 sizeof(HildonVolumebarRangeClass),
94 NULL, /* base_finalize */
95 (GClassInitFunc) hildon_volumebar_range_class_init,
96 NULL, /* class_finalize */
97 NULL, /* class_data */
98 sizeof(HildonVolumebarRange),
100 (GInstanceInitFunc) hildon_volumebar_range_init,
102 volumerange_type = g_type_register_static(GTK_TYPE_SCALE,
103 "HildonVolumebarRange",
104 &volumerange_info, 0);
106 return volumerange_type;
110 hildon_volumebar_range_class_init(HildonVolumebarRangeClass *
113 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(volumerange_class);
114 GObjectClass *object_class = G_OBJECT_CLASS(volumerange_class);
116 parent_class = g_type_class_peek_parent(volumerange_class);
118 widget_class->button_press_event =
119 hildon_volumebar_range_button_press_event;
120 widget_class->button_release_event =
121 hildon_volumebar_range_button_release_event;
122 widget_class->key_press_event = hildon_volumebar_range_keypress;
124 object_class->set_property = hildon_volumebar_range_set_property;
125 object_class->get_property = hildon_volumebar_range_get_property;
127 g_object_class_install_property(object_class,
129 g_param_spec_double("level",
131 "Current volume level",
132 VOLUMEBAR_RANGE_MINIMUM_VALUE,
133 VOLUMEBAR_RANGE_MAXIMUM_VALUE,
134 VOLUMEBAR_RANGE_INITIAL_VALUE,
140 hildon_volumebar_range_init(HildonVolumebarRange * volumerange)
142 /* stepper_a = "less", stepper_d = "more" */
143 GTK_RANGE(volumerange)->has_stepper_a = TRUE;
144 GTK_RANGE(volumerange)->has_stepper_d = TRUE;
148 hildon_volumebar_range_set_property(GObject * object,
150 const GValue * value,
153 HildonVolumebarRange *range = HILDON_VOLUMEBAR_RANGE(object);
157 hildon_volumebar_range_set_level(range, g_value_get_double(value));
160 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
166 hildon_volumebar_range_get_property(GObject * object,
171 HildonVolumebarRange *range = HILDON_VOLUMEBAR_RANGE(object);
175 g_value_set_double(value, hildon_volumebar_range_get_level(range));
178 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
184 gboolean hildon_volumebar_range_keypress(GtkWidget * widget,
187 /* Accept arrow keys only if they match the orientation of the widget */
188 if (GTK_RANGE (widget)->orientation == GTK_ORIENTATION_HORIZONTAL)
190 if (event->keyval == GDK_Up || event->keyval == GDK_Down) {
196 if (event->keyval == GDK_Left || event->keyval == GDK_Right) {
201 return ((GTK_WIDGET_CLASS(parent_class)->key_press_event) (widget,
206 hildon_volumebar_range_new(GtkOrientation orientation)
208 GtkAdjustment * adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (VOLUMEBAR_RANGE_INITIAL_VALUE,
209 VOLUMEBAR_RANGE_MINIMUM_VALUE,
210 VOLUMEBAR_RANGE_MAXIMUM_VALUE,
211 VOLUMEBAR_RANGE_STEP_INCREMENT_VALUE,
212 VOLUMEBAR_RANGE_PAGE_INCREMENT_VALUE,
213 VOLUMEBAR_RANGE_PAGE_SIZE_VALUE));
214 HildonVolumebarRange *self =
215 g_object_new(HILDON_TYPE_VOLUMEBAR_RANGE,
216 "adjustment", adjustment,
219 GTK_RANGE(self)->orientation = orientation;
221 /* Default vertical range is upside down for purposes of this widget */
222 gtk_range_set_inverted(GTK_RANGE(self),
223 (orientation == GTK_ORIENTATION_VERTICAL));
225 return GTK_WIDGET(self);
229 hildon_volumebar_range_get_level(HildonVolumebarRange * self)
231 g_return_val_if_fail(HILDON_IS_VOLUMEBAR_RANGE(self), -1.0);
233 return gtk_adjustment_get_value(gtk_range_get_adjustment(GTK_RANGE(self)));
237 hildon_volumebar_range_set_level(HildonVolumebarRange * self,
240 GtkAdjustment *adjustment;
242 g_return_if_fail(HILDON_IS_VOLUMEBAR_RANGE(self));
244 adjustment = gtk_range_get_adjustment(GTK_RANGE(self));
246 /* Check that value has actually changed. Note that it's not safe to
247 * just compare if floats are equivalent or not */
248 if (ABS(gtk_adjustment_get_value(adjustment) - level) > CHANGE_THRESHOLD) {
249 gtk_adjustment_set_value(adjustment, level);
254 hildon_volumebar_range_button_press_event(GtkWidget * widget,
258 gboolean result = FALSE;
260 /* FIXME: By default, clicking left mouse button on GtkRange moves the
261 slider by one step towards the click location. However, we want stylus
262 taps to move the slider to the position of the tap, which by default
263 is the middle button behaviour. To avoid breaking default GtkRange
264 behaviour, this has been implemented by faking a middle button press. */
265 event->button = (event->button == 1) ? 2 : event->button;
266 if (GTK_WIDGET_CLASS(parent_class)->button_press_event) {
268 GTK_WIDGET_CLASS(parent_class)->button_press_event(widget,
275 hildon_volumebar_range_button_release_event(GtkWidget * widget,
279 gboolean result = FALSE;
281 /* FIXME: By default, clicking left mouse button on GtkRange moves the
282 slider by one step towards the click location. However, we want stylus
283 taps to move the slider to the position of the tap, which by default
284 is the middle button behaviour. To avoid breaking default GtkRange
285 behaviour, this has been implemented by faking a middle button press. */
286 event->button = event->button == 1 ? 2 : event->button;
287 if (GTK_WIDGET_CLASS(parent_class)->button_release_event) {
289 GTK_WIDGET_CLASS(parent_class)->button_release_event(widget,