Gazpacho support, added the following properties:
[hildon] / hildon-widgets / hildon-volumebar-range.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Luc Pionchon <luc.pionchon@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; either 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  * @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 it's specifications.
35  *
36  * Currently #HildonVolumebarRange models range of [0..100].
37  * 
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #include <gtk/gtkrange.h>
45 #include <gdk/gdkkeysyms.h>
46 #include "hildon-volumebar-range.h"
47
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
54
55 #define CHANGE_THRESHOLD 0.001
56
57 static GtkScaleClass *parent_class;
58
59 static void hildon_volumebar_range_class_init(HildonVolumebarRangeClass *  
60                                               volumerange_class);
61 static void hildon_volumebar_range_init(HildonVolumebarRange *
62                                         volumerange);
63 static void hildon_volumebar_range_set_property(GObject * object,
64                                                 guint prop_id,
65                                                 const GValue * value,
66                                                 GParamSpec * pspec);
67 static void hildon_volumebar_range_get_property(GObject * object,
68                                                 guint prop_id,
69                                                 GValue * value,
70                                                 GParamSpec * pspec);
71 static gint hildon_volumebar_range_button_press_event(GtkWidget * widget,
72                                                       GdkEventButton *
73                                                       event);
74 static gint hildon_volumebar_range_button_release_event(GtkWidget * widget,
75                                                         GdkEventButton *
76                                                         event);
77 static gboolean hildon_volumebar_range_keypress(GtkWidget * widget,
78                                                 GdkEventKey * event);
79
80 enum {
81   PROP_NONE = 0,
82   PROP_LEVEL
83 };
84
85 GType 
86 hildon_volumebar_range_get_type(void)
87 {
88     static GType volumerange_type = 0;
89
90     if (!volumerange_type) {
91         static const GTypeInfo volumerange_info = {
92             sizeof(HildonVolumebarRangeClass),
93             NULL,       /* base_init */
94             NULL,       /* base_finalize */
95             (GClassInitFunc) hildon_volumebar_range_class_init,
96             NULL,       /* class_finalize */
97             NULL,       /* class_data */
98             sizeof(HildonVolumebarRange),
99             0,  /* n_preallocs */
100             (GInstanceInitFunc) hildon_volumebar_range_init,
101         };
102         volumerange_type = g_type_register_static(GTK_TYPE_SCALE,
103                                                   "HildonVolumebarRange",
104                                                   &volumerange_info, 0);
105     }
106     return volumerange_type;
107 }
108
109 static void 
110 hildon_volumebar_range_class_init(HildonVolumebarRangeClass *
111                                   volumerange_class)
112 {
113     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(volumerange_class);
114     GObjectClass *object_class = G_OBJECT_CLASS(volumerange_class);
115
116     parent_class = g_type_class_peek_parent(volumerange_class);
117
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;
123
124     object_class->set_property = hildon_volumebar_range_set_property;
125     object_class->get_property = hildon_volumebar_range_get_property; 
126
127     g_object_class_install_property(object_class,
128                                     PROP_LEVEL,
129                                     g_param_spec_double("level",
130                                                         "Level",
131                                                         "Current volume level",
132                                                         VOLUMEBAR_RANGE_MINIMUM_VALUE,
133                                                         VOLUMEBAR_RANGE_MAXIMUM_VALUE,
134                                                         VOLUMEBAR_RANGE_INITIAL_VALUE,
135                                                         G_PARAM_READWRITE));
136     return;
137 }
138
139 static void 
140 hildon_volumebar_range_init(HildonVolumebarRange * volumerange)
141 {
142    
143   GTK_RANGE(volumerange)->has_stepper_a = TRUE;
144   GTK_RANGE(volumerange)->has_stepper_d = TRUE;
145   
146   return;
147 }
148
149 static void
150 hildon_volumebar_range_set_property(GObject * object,
151                                     guint prop_id,
152                                     const GValue * value,
153                                     GParamSpec * pspec)
154 {
155     HildonVolumebarRange *range = HILDON_VOLUMEBAR_RANGE(object);
156
157     switch (prop_id) {
158     case PROP_LEVEL:
159         hildon_volumebar_range_set_level(range, g_value_get_double(value));
160         break;
161     default:
162         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
163         break;
164     }
165 }
166
167 static void
168 hildon_volumebar_range_get_property(GObject * object,
169                                     guint prop_id,
170                                     GValue * value,
171                                     GParamSpec * pspec)
172 {
173     HildonVolumebarRange *range = HILDON_VOLUMEBAR_RANGE(object);
174
175     switch (prop_id) {
176     case PROP_LEVEL:
177         g_value_set_double(value, hildon_volumebar_range_get_level(range));
178         break;
179     default:
180         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
181         break;
182     }
183 }
184
185 static
186 gboolean hildon_volumebar_range_keypress(GtkWidget * widget,
187                                          GdkEventKey * event)
188 {
189     if (GTK_RANGE (widget)->orientation == GTK_ORIENTATION_HORIZONTAL)
190       {
191         if (event->keyval == GDK_Up || event->keyval == GDK_Down) {
192           return FALSE;
193         }
194       }
195     else
196       {
197         if (event->keyval == GDK_Left || event->keyval == GDK_Right) {
198           return FALSE;
199         }
200       }
201
202     return ((GTK_WIDGET_CLASS(parent_class)->key_press_event) (widget,
203                                                                event));
204 }
205
206 GtkWidget *
207 hildon_volumebar_range_new(GtkOrientation orientation)
208 {
209     GtkAdjustment * adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (VOLUMEBAR_RANGE_INITIAL_VALUE,
210                                               VOLUMEBAR_RANGE_MINIMUM_VALUE,
211                                               VOLUMEBAR_RANGE_MAXIMUM_VALUE,
212                                               VOLUMEBAR_RANGE_STEP_INCREMENT_VALUE,
213                                               VOLUMEBAR_RANGE_PAGE_INCREMENT_VALUE,
214                                               VOLUMEBAR_RANGE_PAGE_SIZE_VALUE));
215     HildonVolumebarRange *self =
216         g_object_new(HILDON_VOLUMEBAR_RANGE_TYPE,
217                      "adjustment", adjustment,
218                      NULL);
219
220     GTK_RANGE(self)->orientation = orientation;
221
222     /* invert vertical range */
223     gtk_range_set_inverted(GTK_RANGE(self),
224                            (orientation == GTK_ORIENTATION_VERTICAL));
225
226     return GTK_WIDGET(self);
227 }
228
229 gdouble 
230 hildon_volumebar_range_get_level(HildonVolumebarRange * self)
231 {
232     g_return_val_if_fail(self, -1.0);
233     return GTK_RANGE (self)->adjustment->value;
234 }
235
236 void 
237 hildon_volumebar_range_set_level(HildonVolumebarRange * self,
238                                  gdouble level)
239 {
240     gdouble newlevel;
241     g_return_if_fail(self);
242    
243     /* Although the range can clamp by itself, we do the clamping
244      * here to prevent sending value-changed signal when someone
245      * unsuccessfully tries to set level to illegal value. */
246     newlevel = CLAMP (level, GTK_RANGE (self)->adjustment->lower,
247                       GTK_RANGE (self)->adjustment->upper);
248
249     /* Check that value is actually changed. Note that it's not safe to
250      * just compare if floats are equivalent or not */
251     if (ABS(GTK_RANGE (self)->adjustment->value - newlevel) > CHANGE_THRESHOLD) {
252         /* This might be a bit faster because this skips
253          * gtkadjustment's own clamping and check if value has
254          * indeed changed. */
255         GTK_RANGE (self)->adjustment->value = newlevel;
256         gtk_adjustment_value_changed(GTK_RANGE (self)->adjustment);
257     }
258 }
259
260 static gint 
261 hildon_volumebar_range_button_press_event(GtkWidget * widget,
262                                           GdkEventButton *
263                                           event)
264 {
265     gboolean result = FALSE;
266
267     event->button = event->button == 1 ? 2 : event->button;
268     if (GTK_WIDGET_CLASS(parent_class)->button_press_event) {
269         result =
270             GTK_WIDGET_CLASS(parent_class)->button_press_event(widget,
271                                                                event);
272     }
273     return result;
274 }
275
276 static gint 
277 hildon_volumebar_range_button_release_event(GtkWidget * widget,
278                                             GdkEventButton *
279                                             event)
280 {
281     gboolean result = FALSE;
282
283     event->button = event->button == 1 ? 2 : event->button;
284     if (GTK_WIDGET_CLASS(parent_class)->button_release_event) {
285         result =
286             GTK_WIDGET_CLASS(parent_class)->button_release_event(widget,
287                                                                  event);
288     }
289     return result;
290 }