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