2 * This file is part of hildon-libs
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@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; either version 2.1 of
11 * the License, or (at your option) any later version.
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;
150 hildon_volumebar_range_set_property(GObject * object,
152 const GValue * value,
155 HildonVolumebarRange *range = HILDON_VOLUMEBAR_RANGE(object);
159 hildon_volumebar_range_set_level(range, g_value_get_double(value));
162 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
168 hildon_volumebar_range_get_property(GObject * object,
173 HildonVolumebarRange *range = HILDON_VOLUMEBAR_RANGE(object);
177 g_value_set_double(value, hildon_volumebar_range_get_level(range));
180 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
186 gboolean hildon_volumebar_range_keypress(GtkWidget * widget,
189 /* Accept arrow keys only if they match the orientation of the widget */
190 if (GTK_RANGE (widget)->orientation == GTK_ORIENTATION_HORIZONTAL)
192 if (event->keyval == GDK_Up || event->keyval == GDK_Down) {
198 if (event->keyval == GDK_Left || event->keyval == GDK_Right) {
203 return ((GTK_WIDGET_CLASS(parent_class)->key_press_event) (widget,
208 hildon_volumebar_range_new(GtkOrientation orientation)
210 GtkAdjustment * adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (VOLUMEBAR_RANGE_INITIAL_VALUE,
211 VOLUMEBAR_RANGE_MINIMUM_VALUE,
212 VOLUMEBAR_RANGE_MAXIMUM_VALUE,
213 VOLUMEBAR_RANGE_STEP_INCREMENT_VALUE,
214 VOLUMEBAR_RANGE_PAGE_INCREMENT_VALUE,
215 VOLUMEBAR_RANGE_PAGE_SIZE_VALUE));
216 HildonVolumebarRange *self =
217 g_object_new(HILDON_VOLUMEBAR_RANGE_TYPE,
218 "adjustment", adjustment,
221 GTK_RANGE(self)->orientation = orientation;
223 /* Default vertical range is upside down for purposes of this widget */
224 gtk_range_set_inverted(GTK_RANGE(self),
225 (orientation == GTK_ORIENTATION_VERTICAL));
227 return GTK_WIDGET(self);
231 hildon_volumebar_range_get_level(HildonVolumebarRange * self)
233 g_return_val_if_fail(self, -1.0);
234 return GTK_RANGE (self)->adjustment->value;
238 hildon_volumebar_range_set_level(HildonVolumebarRange * self,
242 g_return_if_fail(self);
244 /* Although the range can clamp by itself, we do the clamping
245 * here to prevent sending value-changed signal when someone
246 * unsuccessfully tries to set level to illegal value. */
247 newlevel = CLAMP (level, GTK_RANGE (self)->adjustment->lower,
248 GTK_RANGE (self)->adjustment->upper);
250 /* Check that value is actually changed. Note that it's not safe to
251 * just compare if floats are equivalent or not */
252 if (ABS(GTK_RANGE (self)->adjustment->value - newlevel) > CHANGE_THRESHOLD) {
253 /* This might be a bit faster because this skips
254 * gtkadjustment's own clamping and check if value has
256 GTK_RANGE (self)->adjustment->value = newlevel;
257 gtk_adjustment_value_changed(GTK_RANGE (self)->adjustment);
262 hildon_volumebar_range_button_press_event(GtkWidget * widget,
266 gboolean result = FALSE;
268 /* FIXME: Ugly hack to trick GtkRange event handler */
269 event->button = (event->button == 1) ? 2 : event->button;
270 if (GTK_WIDGET_CLASS(parent_class)->button_press_event) {
272 GTK_WIDGET_CLASS(parent_class)->button_press_event(widget,
279 hildon_volumebar_range_button_release_event(GtkWidget * widget,
283 gboolean result = FALSE;
285 /* FIXME: Ugly hack to trick GtkRange event handler */
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,