~carsten-munk/m-r/libhildon-2.1.24

« back to all changes in this revision

Viewing changes to src/hildon-controlbar.c

  • Committer: Carsten V. Munk
  • Date: 2008-12-08 15:00:57 UTC
  • Revision ID: cvm@cs.au.dk-20081208150057-7e0a50c8zdupbzar
initial commit of 2.1.24

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-controlbar
 
27
 * @short_description: A widget that allows increasing or decreasing
 
28
 * a value within a pre-defined range.
 
29
 *
 
30
 * #HildonControlbar is a horizontally positioned range widget that is
 
31
 * visually divided into blocks and supports setting a minimum and
 
32
 * maximum value for the range.
 
33
 * 
 
34
 * <example>
 
35
 * <title>HildonControlbar example</title>
 
36
 * <programlisting>
 
37
 * GtkWidget *cbar = hildon_controlbar_new();
 
38
 * hildon_controlbar_set_max (HILDON_CONTROLBAR (cbar), 12);
 
39
 * hildon_controlbar_set_value (HILDON_CONTROLBAR (cbar), 6);
 
40
 * </programlisting>
 
41
 * </example>
 
42
 * 
 
43
 */
 
44
 
 
45
#undef                                          HILDON_DISABLE_DEPRECATED
 
46
 
 
47
#ifdef                                          HAVE_CONFIG_H
 
48
#include                                        <config.h>
 
49
#endif
 
50
 
 
51
#include                                        <math.h>
 
52
#include                                        <libintl.h>
 
53
#include                                        <gdk/gdk.h>
 
54
#include                                        <gdk/gdkkeysyms.h>
 
55
 
 
56
#include                                        "hildon-controlbar.h"
 
57
#include                                        "hildon-controlbar-private.h"
 
58
 
 
59
#define                                         _(string)\
 
60
                                                dgettext("hildon-libs", string)
 
61
 
 
62
#define                                         DEFAULT_WIDTH 234
 
63
 
 
64
#define                                         DEFAULT_HEIGHT 30
 
65
 
 
66
#define                                         DEFAULT_BORDER_WIDTH 2
 
67
 
 
68
#define                                         HILDON_CONTROLBAR_STEP_INCREMENT 1
 
69
 
 
70
#define                                         HILDON_CONTROLBAR_PAGE_INCREMENT 1
 
71
 
 
72
#define                                         HILDON_CONTROLBAR_PAGE_SIZE 0
 
73
 
 
74
#define                                         HILDON_CONTROLBAR_UPPER_VALUE  10
 
75
 
 
76
#define                                         HILDON_CONTROLBAR_LOWER_VALUE 0.0
 
77
 
 
78
#define                                         HILDON_CONTROLBAR_INITIAL_VALUE 0
 
79
 
 
80
static GtkScaleClass*                           parent_class;
 
81
 
 
82
enum
 
83
{
 
84
    PROP_0,
 
85
    PROP_MIN = 1,
 
86
    PROP_MAX,
 
87
    PROP_VALUE
 
88
};
 
89
 
 
90
enum
 
91
{
 
92
    END_REACHED,
 
93
    LAST_SIGNAL
 
94
};
 
95
 
 
96
static guint                                    signals[LAST_SIGNAL] = { 0 };
 
97
 
 
98
static void
 
99
hildon_controlbar_class_init                    (HildonControlbarClass *controlbar_class);
 
100
 
 
101
static void 
 
102
hildon_controlbar_init                          (HildonControlbar *controlbar);
 
103
 
 
104
static GObject*
 
105
hildon_controlbar_constructor                   (GType type, 
 
106
                                                 guint n_construct_properties, 
 
107
                                                 GObjectConstructParam *construct_properties);
 
108
 
 
109
static gint 
 
110
hildon_controlbar_button_press_event            (GtkWidget *widget,
 
111
                                                 GdkEventButton * event);
 
112
 
 
113
static gint 
 
114
hildon_controlbar_button_release_event          (GtkWidget *widget,
 
115
                                                 GdkEventButton *event);
 
116
 
 
117
static gint
 
118
hildon_controlbar_expose_event                  (GtkWidget *widget, 
 
119
                                                 GdkEventExpose *event);
 
120
 
 
121
static void
 
122
hildon_controlbar_size_request                  (GtkWidget *self, 
 
123
                                                 GtkRequisition *req);
 
124
static void
 
125
hildon_controlbar_paint                         (HildonControlbar *self, 
 
126
                                                 GdkRectangle * area);
 
127
 
 
128
static gboolean
 
129
hildon_controlbar_keypress                      (GtkWidget *widget, 
 
130
                                                 GdkEventKey * event);
 
131
 
 
132
static void 
 
133
hildon_controlbar_set_property                  (GObject *object, 
 
134
                                                 guint param_id,
 
135
                                                 const GValue *value, 
 
136
                                                 GParamSpec *pspec);
 
137
 
 
138
static void 
 
139
hildon_controlbar_get_property                  (GObject *object, 
 
140
                                                 guint param_id,
 
141
                                                 GValue *value, 
 
142
                                                 GParamSpec *pspec);
 
143
 
 
144
static void
 
145
hildon_controlbar_value_changed                 (GtkAdjustment *adj, 
 
146
                                                 GtkRange *range);
 
147
 
 
148
static gboolean
 
149
hildon_controlbar_change_value                  (GtkRange *range, 
 
150
                                                 GtkScrollType scroll,
 
151
                                                 gdouble new_value, 
 
152
                                                 gpointer data);
 
153
 
 
154
/**
 
155
 * hildon_controlbar_get_type:
 
156
 *
 
157
 * Initializes and returns the type of a hildon control bar.
 
158
 *
 
159
 * @Returns: GType of #HildonControlbar
 
160
 */
 
161
GType G_GNUC_CONST
 
162
hildon_controlbar_get_type                      (void)
 
163
{
 
164
    static GType controlbar_type = 0;
 
165
 
 
166
    if (!controlbar_type) {
 
167
        static const GTypeInfo controlbar_info = {
 
168
            sizeof (HildonControlbarClass),
 
169
            NULL,       /* base_init */
 
170
            NULL,       /* base_finalize */
 
171
            (GClassInitFunc) hildon_controlbar_class_init,
 
172
            NULL,       /* class_finalize */
 
173
            NULL,       /* class_data */
 
174
            sizeof (HildonControlbar),
 
175
            0,  /* n_preallocs */
 
176
            (GInstanceInitFunc) hildon_controlbar_init,
 
177
        };
 
178
        controlbar_type = g_type_register_static (GTK_TYPE_SCALE,
 
179
                "HildonControlbar",
 
180
                &controlbar_info, 0);
 
181
    }
 
182
 
 
183
    return controlbar_type;
 
184
}
 
185
 
 
186
static void
 
187
hildon_controlbar_class_init                    (HildonControlbarClass *controlbar_class)
 
188
{
 
189
    GObjectClass *gobject_class = G_OBJECT_CLASS (controlbar_class);
 
190
    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (controlbar_class);
 
191
 
 
192
    parent_class = g_type_class_peek_parent(controlbar_class);
 
193
 
 
194
    g_type_class_add_private(controlbar_class, sizeof (HildonControlbarPrivate));
 
195
 
 
196
    gobject_class->get_property         = hildon_controlbar_get_property;
 
197
    gobject_class->set_property         = hildon_controlbar_set_property;
 
198
    gobject_class->constructor          = hildon_controlbar_constructor;
 
199
    widget_class->size_request          = hildon_controlbar_size_request;
 
200
    widget_class->button_press_event    = hildon_controlbar_button_press_event;
 
201
    widget_class->button_release_event  = hildon_controlbar_button_release_event;
 
202
    widget_class->expose_event          = hildon_controlbar_expose_event;
 
203
    widget_class->key_press_event       = hildon_controlbar_keypress;
 
204
    controlbar_class->end_reached = NULL;
 
205
 
 
206
    /**
 
207
     * HildonControlbar:min:
 
208
     *
 
209
     * Controlbar minimum value.
 
210
     */
 
211
    g_object_class_install_property (gobject_class, PROP_MIN,
 
212
            g_param_spec_int ("min",
 
213
                "Minimum value",
 
214
                "Smallest possible value",
 
215
                G_MININT, G_MAXINT,
 
216
                HILDON_CONTROLBAR_LOWER_VALUE,
 
217
                G_PARAM_READABLE | G_PARAM_WRITABLE));
 
218
 
 
219
    /**
 
220
     * HildonControlbar:max:
 
221
     *
 
222
     * Controlbar maximum value.
 
223
     */
 
224
    g_object_class_install_property (gobject_class, PROP_MAX,
 
225
            g_param_spec_int ("max",
 
226
                "Maximum value",
 
227
                "Greatest possible value",
 
228
                G_MININT, G_MAXINT, 
 
229
                HILDON_CONTROLBAR_UPPER_VALUE,
 
230
                G_PARAM_READABLE | G_PARAM_WRITABLE));
 
231
 
 
232
    /**
 
233
     * HildonControlbar:value:
 
234
     *
 
235
     * Controlbar current value.
 
236
     */
 
237
    g_object_class_install_property (gobject_class, PROP_VALUE,
 
238
            g_param_spec_int ("value",
 
239
                "Current value",
 
240
                "Current value",
 
241
                G_MININT, G_MAXINT,
 
242
                HILDON_CONTROLBAR_INITIAL_VALUE,
 
243
                G_PARAM_READABLE | G_PARAM_WRITABLE) );
 
244
 
 
245
 
 
246
    gtk_widget_class_install_style_property (widget_class,
 
247
            g_param_spec_uint ("inner_border_width",
 
248
                "Inner border width",
 
249
                "The border spacing between the controlbar border and controlbar blocks.",
 
250
                0, G_MAXINT,
 
251
                DEFAULT_BORDER_WIDTH,
 
252
                G_PARAM_READABLE));
 
253
 
 
254
    signals[END_REACHED] =
 
255
        g_signal_new("end-reached",
 
256
                G_OBJECT_CLASS_TYPE (gobject_class),
 
257
                G_SIGNAL_RUN_FIRST,
 
258
                G_STRUCT_OFFSET (HildonControlbarClass, end_reached),
 
259
                NULL, NULL,
 
260
                g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1,
 
261
                G_TYPE_BOOLEAN);
 
262
}
 
263
 
 
264
static void 
 
265
hildon_controlbar_init                          (HildonControlbar *controlbar)
 
266
{
 
267
    GtkRange *range;
 
268
    HildonControlbarPrivate *priv;
 
269
 
 
270
    /* Initialize the private property */
 
271
    priv = HILDON_CONTROLBAR_GET_PRIVATE(controlbar);
 
272
    g_assert (priv);
 
273
 
 
274
    priv->button_press = FALSE;
 
275
    priv->old_value = 0;
 
276
    range = GTK_RANGE (controlbar);
 
277
 
 
278
    range->round_digits = -1;
 
279
 
 
280
    gtk_widget_set_size_request (GTK_WIDGET (controlbar), 
 
281
            DEFAULT_WIDTH,
 
282
            DEFAULT_HEIGHT);
 
283
 
 
284
    g_signal_connect (range, "change-value",
 
285
            G_CALLBACK (hildon_controlbar_change_value), NULL);
 
286
}
 
287
 
 
288
static GObject*
 
289
hildon_controlbar_constructor                   (GType type, 
 
290
                                                 guint n_construct_properties, 
 
291
                                                 GObjectConstructParam *construct_properties)
 
292
{
 
293
    GObject *obj;
 
294
    GtkAdjustment *adj;  
 
295
 
 
296
    obj = G_OBJECT_CLASS (parent_class)->constructor (type, 
 
297
            n_construct_properties, construct_properties);
 
298
 
 
299
    gtk_scale_set_draw_value (GTK_SCALE (obj), FALSE);
 
300
 
 
301
    /* Initialize the GtkAdjustment of the controlbar*/
 
302
    adj = GTK_RANGE (obj)->adjustment;
 
303
    adj->step_increment = HILDON_CONTROLBAR_STEP_INCREMENT;
 
304
    adj->page_increment = HILDON_CONTROLBAR_PAGE_INCREMENT;
 
305
    adj->page_size = HILDON_CONTROLBAR_PAGE_SIZE;
 
306
 
 
307
    g_signal_connect (adj, "value-changed", 
 
308
            G_CALLBACK (hildon_controlbar_value_changed), obj);
 
309
    return obj;
 
310
}
 
311
 
 
312
static void 
 
313
hildon_controlbar_set_property                  (GObject *object, 
 
314
                                                 guint param_id,
 
315
                                                 const GValue *value, 
 
316
                                                 GParamSpec *pspec)
 
317
{
 
318
    HildonControlbar *controlbar = HILDON_CONTROLBAR (object);
 
319
 
 
320
    switch (param_id)
 
321
    {
 
322
        case PROP_MIN:
 
323
            hildon_controlbar_set_min (controlbar, g_value_get_int(value));
 
324
            break;
 
325
 
 
326
        case PROP_MAX:
 
327
            hildon_controlbar_set_max (controlbar, g_value_get_int(value));
 
328
            break;
 
329
 
 
330
        case PROP_VALUE:
 
331
            hildon_controlbar_set_value (controlbar, g_value_get_int(value));
 
332
            break;
 
333
 
 
334
        default:
 
335
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 
336
            break;
 
337
    }
 
338
}
 
339
 
 
340
static void hildon_controlbar_get_property      (GObject *object, 
 
341
                                                 guint param_id,
 
342
                                                 GValue *value, 
 
343
                                                 GParamSpec *pspec)
 
344
{
 
345
    HildonControlbar *controlbar = HILDON_CONTROLBAR(object);
 
346
 
 
347
    switch (param_id)
 
348
    {
 
349
        case PROP_MIN:
 
350
            g_value_set_int (value, hildon_controlbar_get_min (controlbar));
 
351
            break;
 
352
 
 
353
        case PROP_MAX:
 
354
            g_value_set_int (value, hildon_controlbar_get_max (controlbar));
 
355
            break;
 
356
 
 
357
        case PROP_VALUE:
 
358
            g_value_set_int (value, hildon_controlbar_get_value (controlbar));
 
359
            break;
 
360
 
 
361
        default:
 
362
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 
363
            break;
 
364
    }
 
365
}
 
366
 
 
367
 
 
368
static void
 
369
hildon_controlbar_value_changed                 (GtkAdjustment *adj, 
 
370
                                                 GtkRange *range)
 
371
{
 
372
    HildonControlbarPrivate *priv = HILDON_CONTROLBAR_GET_PRIVATE(range);
 
373
    g_assert (priv);
 
374
 
 
375
    /* Change the controlbar value if the adjusted value is large enough 
 
376
     * otherwise, keep the old value
 
377
     */
 
378
    if (ABS(ceil (adj->value) - priv->old_value) >= 1)
 
379
    {
 
380
        priv->old_value = ceil (adj->value);
 
381
        adj->value = priv->old_value;
 
382
    }
 
383
    else
 
384
        g_signal_stop_emission_by_name (adj, "value-changed");
 
385
 
 
386
    gtk_adjustment_set_value (adj, priv->old_value);
 
387
}
 
388
 
 
389
/**
 
390
 * hildon_controlbar_new:
 
391
 * 
 
392
 * Creates a new #HildonControlbar widget.
 
393
 *
 
394
 * Returns: a #GtkWidget pointer of newly created control bar
 
395
 * widget
 
396
 */
 
397
GtkWidget*
 
398
hildon_controlbar_new                           (void)
 
399
{
 
400
    return GTK_WIDGET (g_object_new (HILDON_TYPE_CONTROLBAR, NULL));
 
401
}
 
402
 
 
403
/* This function prevents Up and Down keys from changing the
 
404
 * widget's value (like Left and Right).
 
405
 * Instead they are used for changing focus to other widgtes.
 
406
 */
 
407
static gboolean
 
408
hildon_controlbar_keypress                      (GtkWidget *widget, 
 
409
                                                 GdkEventKey *event)
 
410
{
 
411
    if (event->keyval == GDK_Up || event->keyval == GDK_Down)
 
412
        return FALSE;
 
413
 
 
414
    return ((GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event));
 
415
}
 
416
 
 
417
static void
 
418
hildon_controlbar_size_request                  (GtkWidget *self, 
 
419
                                                 GtkRequisition *req)
 
420
{
 
421
    if (GTK_WIDGET_CLASS (parent_class)->size_request)
 
422
        GTK_WIDGET_CLASS (parent_class)->size_request(self, req);
 
423
 
 
424
    req->width = DEFAULT_WIDTH;
 
425
    req->height = DEFAULT_HEIGHT;
 
426
}
 
427
 
 
428
/**
 
429
 * hildon_controlbar_set_value:
 
430
 * @self: pointer to #HildonControlbar
 
431
 * @value: value in range of >= 0 && < G_MAX_INT
 
432
 *
 
433
 * Set the current value of the control bar to the specified value.
 
434
 */
 
435
void 
 
436
hildon_controlbar_set_value                     (HildonControlbar * self, 
 
437
                                                 gint value)
 
438
{
 
439
    GtkAdjustment *adj;
 
440
    g_return_if_fail (HILDON_IS_CONTROLBAR (self));
 
441
    adj = GTK_RANGE (self)->adjustment;
 
442
 
 
443
    g_return_if_fail (value >= 0);
 
444
 
 
445
    if (value >= adj->upper)
 
446
        value = adj->upper;
 
447
    else if (value <= adj->lower)
 
448
        value = adj->lower;
 
449
 
 
450
    adj->value = value;
 
451
    gtk_adjustment_value_changed (adj);
 
452
 
 
453
    g_object_notify (G_OBJECT(self), "value");
 
454
}
 
455
 
 
456
/**
 
457
 * hildon_controlbar_get_value:
 
458
 * @self: pointer to #HildonControlbar
 
459
 *
 
460
 * Returns: current value as gint
 
461
 */
 
462
gint
 
463
hildon_controlbar_get_value                     (HildonControlbar * self)
 
464
{
 
465
    GtkAdjustment *adj;
 
466
    g_return_val_if_fail (HILDON_IS_CONTROLBAR (self), 0);
 
467
    adj = GTK_RANGE(self)->adjustment;
 
468
 
 
469
    return (gint) ceil(adj->value);
 
470
}
 
471
 
 
472
/**
 
473
 * hildon_controlbar_set_max:
 
474
 * @self: pointer to #HildonControlbar
 
475
 * @max: maximum value to set. The value needs to be greater than 0.
 
476
 *
 
477
 * Set the control bar's maximum to the given value.
 
478
 * 
 
479
 * If the new maximum is smaller than current value, the value will be
 
480
 * adjusted so that it equals the new maximum.
 
481
 */
 
482
void 
 
483
hildon_controlbar_set_max                       (HildonControlbar * self, 
 
484
                                                 gint max)
 
485
{
 
486
    GtkAdjustment *adj;
 
487
    g_return_if_fail (HILDON_IS_CONTROLBAR (self));
 
488
    adj = GTK_RANGE (self)->adjustment;
 
489
 
 
490
    if (max < adj->lower)
 
491
        max = adj->lower;
 
492
 
 
493
    if (adj->value > max)
 
494
        hildon_controlbar_set_value (self, max);
 
495
 
 
496
    adj->upper = max;
 
497
    gtk_adjustment_changed (adj);
 
498
 
 
499
    g_object_notify (G_OBJECT(self), "max");
 
500
}
 
501
 
 
502
/**
 
503
 * hildon_controlbar_set_min:
 
504
 * @self: pointer to #HildonControlbar
 
505
 * @min: minimum value to set. The value needs to be greater than or
 
506
 * equal to 0.
 
507
 *
 
508
 * Set the control bar's minimum to the given value.
 
509
 *
 
510
 * If the new minimum is smaller than current value, the value will be
 
511
 * adjusted so that it equals the new minimum.
 
512
 */
 
513
void
 
514
hildon_controlbar_set_min                       (HildonControlbar *self, 
 
515
                                                 gint min)
 
516
{
 
517
    GtkAdjustment *adj;
 
518
    g_return_if_fail (HILDON_IS_CONTROLBAR (self));
 
519
    adj = GTK_RANGE (self)->adjustment;
 
520
 
 
521
    if (min > adj->upper)
 
522
        min = adj->upper;
 
523
 
 
524
    if (adj->value < min)
 
525
        hildon_controlbar_set_value (self, min);
 
526
 
 
527
    adj->lower = min;
 
528
    gtk_adjustment_changed (adj);
 
529
    g_object_notify (G_OBJECT(self), "min");
 
530
}
 
531
 
 
532
/**
 
533
 * hildon_controlbar_set_range:
 
534
 * @self: pointer to #HildonControlbar
 
535
 * @max: maximum value to set. The value needs to be greater than 0.
 
536
 * @min: Minimum value to set. The value needs to be greater than or
 
537
 * equal to 0.
 
538
 *
 
539
 * Set the controlbars range to the given value
 
540
 * 
 
541
 * If the new maximum is smaller than current value, the value will be
 
542
 * adjusted so that it equals the new maximum.
 
543
 *
 
544
 * If the new minimum is smaller than current value, the value will be
 
545
 * adjusted so that it equals the new minimum.
 
546
 */
 
547
void 
 
548
hildon_controlbar_set_range                     (HildonControlbar *self, 
 
549
                                                 gint min,
 
550
                                                 gint max)
 
551
{
 
552
    g_return_if_fail (HILDON_IS_CONTROLBAR (self));
 
553
 
 
554
    if (min > max)
 
555
        min = max;
 
556
 
 
557
    /* We need to set max first here, because when min is set before
 
558
     * max is set, it would end up 0, because max can't be bigger than 0.
 
559
     */
 
560
    hildon_controlbar_set_max (self, max);
 
561
    hildon_controlbar_set_min (self, min);
 
562
}
 
563
 
 
564
/**
 
565
 * hildon_controlbar_get_max:
 
566
 * @self: a pointer to #HildonControlbar
 
567
 *
 
568
 * Returns: maximum value of control bar
 
569
 */
 
570
gint hildon_controlbar_get_max                  (HildonControlbar *self)
 
571
{
 
572
    GtkAdjustment *adj;
 
573
    g_return_val_if_fail (HILDON_IS_CONTROLBAR (self), 0);
 
574
    adj = GTK_RANGE (self)->adjustment;
 
575
 
 
576
    return (gint) adj->upper;
 
577
}
 
578
 
 
579
/**
 
580
 * hildon_controlbar_get_min:
 
581
 * @self: a pointer to #HildonControlbar
 
582
 *
 
583
 * Returns: minimum value of controlbar
 
584
 */
 
585
gint 
 
586
hildon_controlbar_get_min                       (HildonControlbar *self)
 
587
{
 
588
    GtkAdjustment *adj = GTK_RANGE (self)->adjustment;
 
589
    return (gint) adj->lower;
 
590
}
 
591
 
 
592
/*
 
593
 * Event handler for button press
 
594
 * Need to change button1 to button2 before passing this event to
 
595
 * parent handler. (see specs)
 
596
 * Also updates button_press variable so that we can draw highlights
 
597
 * correctly
 
598
 */
 
599
static gint 
 
600
hildon_controlbar_button_press_event            (GtkWidget *widget,
 
601
                                                 GdkEventButton *event)
 
602
{
 
603
    HildonControlbar *self;
 
604
    HildonControlbarPrivate *priv;
 
605
    gboolean result = FALSE;
 
606
 
 
607
    g_return_val_if_fail (widget, FALSE);
 
608
    g_return_val_if_fail (event, FALSE);
 
609
 
 
610
    self = HILDON_CONTROLBAR (widget);
 
611
    priv = HILDON_CONTROLBAR_GET_PRIVATE (self);
 
612
    g_assert (priv);
 
613
 
 
614
    priv->button_press = TRUE;
 
615
    event->button = event->button == 1 ? 2 : event->button;
 
616
 
 
617
    /* Ugh dirty hack. We manipulate the mouse event location to
 
618
       compensate for centering the widget in case it is taller than the
 
619
       default height. */
 
620
    if (widget->allocation.height > DEFAULT_HEIGHT) {
 
621
        gint difference = widget->allocation.height - DEFAULT_HEIGHT;
 
622
 
 
623
        if (difference & 1)
 
624
            difference += 1;
 
625
        difference = difference / 2;
 
626
 
 
627
        event->y -= difference;
 
628
    }
 
629
 
 
630
 
 
631
    /* call the parent handler */
 
632
    if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
 
633
        result = GTK_WIDGET_CLASS (parent_class)->button_press_event(widget, event);
 
634
 
 
635
    return result;
 
636
}
 
637
 
 
638
/*
 
639
 * Purpose of this function is to prevent Up and Down keys from 
 
640
 * changing the widget's value (like Left and Right). Instead they 
 
641
 * are used for changing focus to other widgtes.
 
642
 */
 
643
static gboolean
 
644
hildon_controlbar_change_value                  (GtkRange *range,
 
645
                                                 GtkScrollType scroll,
 
646
                                                 gdouble new_value,
 
647
                                                 gpointer data)
 
648
{
 
649
    HildonControlbarPrivate *priv;
 
650
    GtkAdjustment *adj = range->adjustment;
 
651
    gdouble vv = adj->upper - adj->lower;
 
652
    gint calc = ((new_value - adj->lower) / vv) * (vv + 1.0) + adj->lower;
 
653
 
 
654
    priv = HILDON_CONTROLBAR_GET_PRIVATE(range);
 
655
    g_assert (priv);
 
656
 
 
657
    /* Emit a signal when upper or lower limit is reached */
 
658
    switch (scroll)
 
659
    {
 
660
        case GTK_SCROLL_STEP_FORWARD :
 
661
        case GTK_SCROLL_PAGE_FORWARD :
 
662
            if( adj->value == priv->old_value )
 
663
                if( adj->value == adj->upper )
 
664
                    g_signal_emit( G_OBJECT(range), signals[END_REACHED], 0, TRUE );
 
665
            break;
 
666
 
 
667
        case GTK_SCROLL_STEP_BACKWARD :
 
668
        case GTK_SCROLL_PAGE_BACKWARD :
 
669
            if( adj->value == priv->old_value )
 
670
                if( adj->value == adj->lower )
 
671
                    g_signal_emit( G_OBJECT(range), signals[END_REACHED], 0, FALSE );
 
672
            break;
 
673
 
 
674
        default:
 
675
            break;
 
676
    }
 
677
 
 
678
    GTK_RANGE_CLASS (parent_class)->change_value (range, scroll, calc);
 
679
 
 
680
    return TRUE;
 
681
}
 
682
 
 
683
/*
 
684
 * Event handler for button release
 
685
 * Need to change button1 to button2 before passing this event to
 
686
 * parent handler. (see specs)
 
687
 * Also updates button_press variable so that we can draw hilites
 
688
 * correctly
 
689
 */
 
690
static gint 
 
691
hildon_controlbar_button_release_event          (GtkWidget *widget,
 
692
                                                 GdkEventButton *event)
 
693
{
 
694
    HildonControlbar *self;
 
695
    HildonControlbarPrivate *priv;
 
696
    gboolean result = FALSE;
 
697
 
 
698
    g_return_val_if_fail (widget, FALSE);
 
699
    g_return_val_if_fail (event, FALSE);
 
700
 
 
701
    self = HILDON_CONTROLBAR (widget);
 
702
    priv = HILDON_CONTROLBAR_GET_PRIVATE (self);
 
703
    g_assert (priv);
 
704
 
 
705
    priv->button_press = FALSE;
 
706
    event->button = event->button == 1 ? 2 : event->button;
 
707
 
 
708
    /* call the parent handler */
 
709
    if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
 
710
        result = GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
 
711
 
 
712
    return result;
 
713
}
 
714
 
 
715
/*
 
716
 * Event handler for expose event
 
717
 */
 
718
static gint 
 
719
hildon_controlbar_expose_event                  (GtkWidget *widget,
 
720
                                                 GdkEventExpose * event)
 
721
{
 
722
    HildonControlbar *self = NULL;
 
723
 
 
724
    gboolean result = FALSE;
 
725
    gint old_height = -1;
 
726
    gint old_y = -1;
 
727
 
 
728
    g_return_val_if_fail (event, FALSE);
 
729
    g_return_val_if_fail (HILDON_IS_CONTROLBAR(widget), FALSE);
 
730
 
 
731
    self = HILDON_CONTROLBAR(widget);
 
732
 
 
733
    old_height = widget->allocation.height;
 
734
    old_y = widget->allocation.y;
 
735
 
 
736
    if (widget->allocation.height > DEFAULT_HEIGHT) {
 
737
        int difference = widget->allocation.height - DEFAULT_HEIGHT;
 
738
 
 
739
        if (difference & 1)
 
740
            difference += 1;
 
741
 
 
742
        difference = difference / 2;
 
743
 
 
744
        widget->allocation.y += difference;
 
745
        widget->allocation.height = DEFAULT_HEIGHT;
 
746
    }
 
747
 
 
748
    /* call the parent handler */
 
749
    if (GTK_WIDGET_CLASS (parent_class)->expose_event)
 
750
        result = GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
 
751
 
 
752
    hildon_controlbar_paint (self, &event->area);
 
753
 
 
754
    widget->allocation.height = old_height;
 
755
    widget->allocation.y = old_y;
 
756
 
 
757
    return TRUE;
 
758
}
 
759
 
 
760
/*
 
761
 * Paint method.
 
762
 * This is where all the work is actually done...
 
763
 */
 
764
static void
 
765
hildon_controlbar_paint                         (HildonControlbar *self,
 
766
                                                 GdkRectangle *area)
 
767
{
 
768
    HildonControlbarPrivate *priv;
 
769
    GtkWidget *widget = GTK_WIDGET(self);
 
770
    GtkAdjustment *ctrlbar = GTK_RANGE(self)->adjustment;
 
771
    gint x = widget->allocation.x;
 
772
    gint y = widget->allocation.y;
 
773
    gint h = widget->allocation.height;
 
774
    gint w = widget->allocation.width;
 
775
    gint max = 0;
 
776
    gint stepper_size = 0;
 
777
    gint stepper_spacing = 0;
 
778
    gint inner_border_width = 0;
 
779
    gint block_area = 0, block_width = 0, block_x = 0, block_max = 0, block_height,block_y;
 
780
    /* Number of blocks on the controlbar */
 
781
    guint block_count = 0;
 
782
    /* Number of displayed active blocks */
 
783
    guint block_act = 0;
 
784
    /* Minimum no. of blocks visible */
 
785
    guint block_min = 0;
 
786
    gint separatingpixels = 2;
 
787
    gint block_remains = 0;
 
788
    gint i, start_x, end_x, current_width;
 
789
    GtkStateType state = GTK_STATE_NORMAL;
 
790
 
 
791
    g_return_if_fail(area);
 
792
 
 
793
    priv = HILDON_CONTROLBAR_GET_PRIVATE(self);
 
794
    g_assert (priv);
 
795
 
 
796
    if (GTK_WIDGET_SENSITIVE (self) == FALSE)
 
797
        state = GTK_STATE_INSENSITIVE;
 
798
 
 
799
    gtk_widget_style_get (GTK_WIDGET (self),
 
800
            "stepper-size", &stepper_size,
 
801
            "stepper-spacing", &stepper_spacing,
 
802
            "inner_border_width", &inner_border_width, NULL);
 
803
 
 
804
    block_area = (w - 2 * stepper_size - 2 * stepper_spacing - 2 * inner_border_width);
 
805
 
 
806
    if (block_area <= 0)
 
807
        return;
 
808
 
 
809
    block_min = 1;
 
810
    block_max = ctrlbar->upper - ctrlbar->lower + block_min; 
 
811
    block_act = priv->old_value - GTK_RANGE (self)->adjustment->lower + block_min;
 
812
 
 
813
    /* We check border width and maximum value and adjust
 
814
     * separating pixels for block width here. If the block size would
 
815
     * become too small, we make the separators smaller. Graceful fallback.
 
816
     */
 
817
    max = ctrlbar->upper;
 
818
    if(ctrlbar->upper == 0)
 
819
        separatingpixels = 3;
 
820
    else if ((block_area - ((max - 1) * 3)) / max >= 4) 
 
821
        separatingpixels = 3;
 
822
    else if ((block_area - ((max - 1) * 2)) / max >= 4) 
 
823
        separatingpixels = 2;
 
824
    else if ((block_area - ((max - 1) * 1)) / max >= 4)
 
825
        separatingpixels = 1;
 
826
    else
 
827
        separatingpixels = 0;
 
828
 
 
829
    if (block_max == 0)
 
830
    {
 
831
        /* If block max is 0 then we dim the whole control. */
 
832
        state = GTK_STATE_INSENSITIVE;
 
833
        block_width = block_area;
 
834
        block_remains = 0;
 
835
        block_max = 1;
 
836
    }
 
837
    else
 
838
    {
 
839
        block_width =
 
840
            (block_area - (separatingpixels * (block_max - 1))) / block_max;
 
841
        block_remains =
 
842
            (block_area - (separatingpixels * (block_max - 1))) % block_max;
 
843
    }
 
844
 
 
845
    block_x = x + stepper_size + stepper_spacing + inner_border_width;
 
846
    block_y = y + inner_border_width;
 
847
    block_height = h - 2 * inner_border_width;
 
848
 
 
849
    block_count = ctrlbar->value - ctrlbar->lower +  block_min;
 
850
 
 
851
    if (block_count == 0)
 
852
            block_count = 1;
 
853
    /* Without this there is vertical block corruption when block_height = 
 
854
       1. This should work from 0 up to whatever */
 
855
 
 
856
    if (block_height < 2)
 
857
        block_height = 2;
 
858
 
 
859
    /* 
 
860
     * Changed the drawing of the blocks completely,
 
861
     * because of "do-not-resize-when-changing-max"-specs.
 
862
     * Now the code calculates from the block_remains when
 
863
     * it should add one pixel to the block and when not.
 
864
     */
 
865
 
 
866
    for (i = 1; i <= block_max; i++) {
 
867
 
 
868
        /* Here we calculate whether we add one pixel to current_width or
 
869
           not. */
 
870
        start_x = block_width * (i - 1) + ((i - 1) * block_remains) / block_max;
 
871
        end_x = block_width * i + (i * block_remains) / block_max;
 
872
        current_width = end_x - start_x;
 
873
 
 
874
        gtk_paint_box (widget->style, widget->window, state,
 
875
                (i <= block_count) ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
 
876
                NULL, widget, "hildon_block",
 
877
                block_x, block_y, current_width,
 
878
                block_height);
 
879
 
 
880
        /* We keep the block_x separate because of the
 
881
           'separatingpixels' */
 
882
        block_x += current_width + separatingpixels;
 
883
    }
 
884
 
 
885
}