latest update
[hildon] / hildon-widgets / hildon-controlbar.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-caption-control.c
27  *
28  * This file contains the implementation of Hildon Caption Control
29  *
30  */
31
32 #include <math.h>
33 #include <gdk/gdk.h>
34 #include <gdk/gdkkeysyms.h>
35 #include <gtk/gtk.h>
36 #include "hildon-controlbar.h"
37
38 #include <libintl.h>
39 #define _(string) dgettext(PACKAGE, string)
40
41 #define HILDON_CONTROLBAR_GET_PRIVATE(obj) \
42     (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
43      HILDON_TYPE_CONTROLBAR, HildonControlbarPrivate));
44
45 #define DEFAULT_WIDTH 234
46 #define DEFAULT_HEIGHT 30
47 #define DEFAULT_BORDER_WIDTH 2
48
49 #define HILDON_CONTROLBAR_STEP_INCREMENT 1
50 #define HILDON_CONTROLBAR_PAGE_INCREMENT 1
51 #define HILDON_CONTROLBAR_PAGE_SIZE 0
52 #define HILDON_CONTROLBAR_UPPER_VALUE  10
53 #define HILDON_CONTROLBAR_LOWER_VALUE 0.0
54 #define HILDON_CONTROLBAR_INITIAL_VALUE 0
55
56 static GtkScaleClass *parent_class;
57
58 typedef struct _HildonControlbarPrivate HildonControlbarPrivate;
59
60 enum
61 {
62   PROP_MIN = 1,
63   PROP_MAX,
64   PROP_VALUE
65 };
66
67 static void
68 hildon_controlbar_class_init(HildonControlbarClass * controlbar_class);
69 static void hildon_controlbar_init(HildonControlbar * controlbar);
70 static GObject *
71 hildon_controlbar_constructor(GType type, guint n_construct_properties, 
72   GObjectConstructParam *construct_properties);
73
74 static gint hildon_controlbar_button_press_event(GtkWidget * widget,
75                                                  GdkEventButton * event);
76 static gint hildon_controlbar_button_release_event(GtkWidget * widget,
77                                                    GdkEventButton * event);
78 static gint
79 hildon_controlbar_expose_event(GtkWidget * widget, GdkEventExpose * event);
80 static void
81 hildon_controlbar_size_request(GtkWidget * self, GtkRequisition * req);
82 static void
83 hildon_controlbar_paint(HildonControlbar * self, GdkRectangle * area);
84 static gboolean
85 hildon_controlbar_keypress(GtkWidget * widget, GdkEventKey * event);
86
87 static void hildon_controlbar_set_property( GObject *object, guint param_id,
88                                        const GValue *value, GParamSpec *pspec );
89 static void hildon_controlbar_get_property( GObject *object, guint param_id,
90                                          GValue *value, GParamSpec *pspec );
91
92 static void
93 hildon_controlbar_value_changed( GtkAdjustment *adj, GtkRange *range );
94
95 GType hildon_controlbar_get_type(void)
96 {
97     static GType controlbar_type = 0;
98
99     if (!controlbar_type) {
100         static const GTypeInfo controlbar_info = {
101             sizeof(HildonControlbarClass),
102             NULL,       /* base_init */
103             NULL,       /* base_finalize */
104             (GClassInitFunc) hildon_controlbar_class_init,
105             NULL,       /* class_finalize */
106             NULL,       /* class_data */
107             sizeof(HildonControlbar),
108             0,  /* n_preallocs */
109             (GInstanceInitFunc) hildon_controlbar_init,
110         };
111         controlbar_type = g_type_register_static(GTK_TYPE_SCALE,
112                                                  "HildonControlbar",
113                                                  &controlbar_info, 0);
114     }
115     return controlbar_type;
116 }
117
118 struct _HildonControlbarPrivate {
119     gboolean button_press;
120     gint old_value;
121 };
122
123 static void
124 hildon_controlbar_class_init(HildonControlbarClass * controlbar_class)
125 {
126   GObjectClass *gobject_class = G_OBJECT_CLASS(controlbar_class);
127   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(controlbar_class);
128
129   parent_class = g_type_class_peek_parent(controlbar_class);
130
131   g_type_class_add_private(controlbar_class,
132                            sizeof(HildonControlbarPrivate));
133
134   gobject_class->get_property = hildon_controlbar_get_property;
135   gobject_class->set_property = hildon_controlbar_set_property;
136   widget_class->size_request = hildon_controlbar_size_request;
137   widget_class->button_press_event = hildon_controlbar_button_press_event;
138   widget_class->button_release_event = hildon_controlbar_button_release_event;
139   widget_class->expose_event = hildon_controlbar_expose_event;
140   widget_class->key_press_event = hildon_controlbar_keypress;
141   G_OBJECT_CLASS(controlbar_class)->constructor = hildon_controlbar_constructor;
142
143   /**
144    * HildonControlbar:min:
145    *
146    * Controlbar minimum value.
147    */
148   g_object_class_install_property( gobject_class, PROP_MIN,
149                                    g_param_spec_int("min",
150                                    "Minimum value",
151                                    "Smallest possible value",
152                                    G_MININT, G_MAXINT,
153                                    HILDON_CONTROLBAR_LOWER_VALUE,
154                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
155
156   /**
157    * HildonControlbar:max:
158    *
159    * Controlbar maximum value.
160    */
161   g_object_class_install_property( gobject_class, PROP_MAX,
162                                    g_param_spec_int("max",
163                                    "Maximum value",
164                                    "Greatest possible value",
165                                    G_MININT, G_MAXINT, 
166                                    HILDON_CONTROLBAR_UPPER_VALUE,
167                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
168
169   /**
170    * HildonControlbar:value:
171    *
172    * Controlbar value.
173    */
174   g_object_class_install_property( gobject_class, PROP_VALUE,
175                                    g_param_spec_int("value",
176                                    "Current value",
177                                    "Current value",
178                                    G_MININT, G_MAXINT,
179                                    HILDON_CONTROLBAR_INITIAL_VALUE,
180                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
181
182
183   gtk_widget_class_install_style_property(widget_class,
184                                   g_param_spec_uint("inner_border_width",
185                                                     "Inner border width",
186                         "The border spacing between the controlbar border and controlbar blocks.",
187                                                     0, G_MAXINT,
188                                                     DEFAULT_BORDER_WIDTH,
189                                                     G_PARAM_READABLE));
190 }
191
192 static void hildon_controlbar_init(HildonControlbar * controlbar)
193 {
194     GtkRange *range;
195     HildonControlbarPrivate *priv;
196
197     priv = HILDON_CONTROLBAR_GET_PRIVATE(controlbar);
198     priv->button_press = FALSE;
199     priv->old_value = 0;
200     range = GTK_RANGE(controlbar);
201
202     range->has_stepper_a = TRUE;
203     range->has_stepper_d = TRUE;
204     range->round_digits = -1;
205     
206     gtk_widget_set_size_request( GTK_WIDGET(controlbar), DEFAULT_WIDTH,
207                                  DEFAULT_HEIGHT );
208 }
209
210 static GObject *hildon_controlbar_constructor(GType type, 
211   guint n_construct_properties, GObjectConstructParam *construct_properties)
212 {
213   GObject *obj;
214   GtkAdjustment *adj;  
215
216   obj = G_OBJECT_CLASS(parent_class)->constructor(type, 
217     n_construct_properties, construct_properties);
218    
219   gtk_scale_set_draw_value (GTK_SCALE (obj), FALSE);
220
221   adj = GTK_RANGE(obj)->adjustment;
222   adj->step_increment = HILDON_CONTROLBAR_STEP_INCREMENT;
223   adj->page_increment = HILDON_CONTROLBAR_PAGE_INCREMENT;
224   adj->page_size = HILDON_CONTROLBAR_PAGE_SIZE;
225
226   g_signal_connect( adj, "value-changed", 
227                     G_CALLBACK(hildon_controlbar_value_changed), obj );
228   return obj;
229 }
230
231 static void hildon_controlbar_set_property (GObject *object, guint param_id,
232                                        const GValue *value, GParamSpec *pspec)
233 {
234   HildonControlbar *controlbar = HILDON_CONTROLBAR(object);
235   switch (param_id)
236   {
237     case PROP_MIN:
238       hildon_controlbar_set_min (controlbar, g_value_get_int(value));
239       break;
240
241     case PROP_MAX:
242       hildon_controlbar_set_max (controlbar, g_value_get_int(value));
243       break;
244
245     case PROP_VALUE:
246       hildon_controlbar_set_value (controlbar, g_value_get_int(value));
247       break;
248
249     default:
250       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
251       break;
252   }
253 }
254
255 static void hildon_controlbar_get_property( GObject *object, guint param_id,
256                                          GValue *value, GParamSpec *pspec )
257 {
258   HildonControlbar *controlbar = HILDON_CONTROLBAR(object);
259   switch (param_id)
260   {
261     case PROP_MIN:
262       g_value_set_int (value, hildon_controlbar_get_min (controlbar));
263       break;
264
265     case PROP_MAX:
266       g_value_set_int (value, hildon_controlbar_get_max (controlbar));
267       break;
268
269     case PROP_VALUE:
270       g_value_set_int (value, hildon_controlbar_get_value (controlbar));
271       break;
272
273     default:
274       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
275       break;
276   }
277 }
278
279
280 static void
281 hildon_controlbar_value_changed( GtkAdjustment *adj, GtkRange *range )
282 {
283   HildonControlbarPrivate *priv = HILDON_CONTROLBAR_GET_PRIVATE(range);
284
285   if( ABS(ceil(range->adjustment->value) - priv->old_value) >= 1 )
286   {
287     priv->old_value = ceil(range->adjustment->value);
288     range->adjustment->value = priv->old_value;
289   }
290   else
291     g_signal_stop_emission_by_name( range->adjustment, "value-changed" );
292   gtk_adjustment_set_value( range->adjustment, priv->old_value );
293 }
294
295 /**
296  * hildon_controlbar_new:
297  * 
298  * Creates a new #HildonControlbar widget.
299  *
300  * Return value: A #GtkWidget pointer of newly created #HildonControlbar
301  * widget.
302  */
303 GtkWidget *hildon_controlbar_new(void)
304 {
305     return GTK_WIDGET(g_object_new(HILDON_TYPE_CONTROLBAR, NULL));
306 }
307
308 static gboolean
309 hildon_controlbar_keypress(GtkWidget * widget, GdkEventKey * event)
310 {
311     if (event->keyval == GDK_Up || event->keyval == GDK_Down)
312         return FALSE;
313     return ((GTK_WIDGET_CLASS(parent_class)->key_press_event) (widget, event));
314 }
315
316 static void
317 hildon_controlbar_size_request(GtkWidget * self, GtkRequisition * req)
318 {
319     if (GTK_WIDGET_CLASS(parent_class)->size_request)
320         GTK_WIDGET_CLASS(parent_class)->size_request(self, req);
321
322     req->width = DEFAULT_WIDTH;
323     req->height = DEFAULT_HEIGHT;
324 }
325
326 /**
327  * hildon_controlbar_set_value:
328  * @self: Pointer to #HildonControlbar
329  * @value: Value in range of >= 0 && < G_MAX_INT
330  *
331  * This method will change #HildonControlbar current value
332  * to the given value.
333  */
334 void hildon_controlbar_set_value(HildonControlbar * self, gint value)
335 {
336     GtkAdjustment *adj;
337     g_return_if_fail (HILDON_IS_CONTROLBAR (self));
338     adj = GTK_RANGE(self)->adjustment;
339  
340     g_return_if_fail(value >= 0);
341
342     if (value >= adj->upper)
343         value = adj->upper;
344     else if (value <= adj->lower)
345         value = adj->lower;
346
347     adj->value = value;
348     gtk_adjustment_value_changed(adj);
349
350     g_object_notify (G_OBJECT(self), "value");
351 }
352
353 /**
354  * hildon_controlbar_get_value:
355  * @self: Pointer to #HildonControlbar
356  *
357  * Accessor method for getting controlbars current value
358  *
359  * Return value: Current value as gint.
360  */
361 gint hildon_controlbar_get_value(HildonControlbar * self)
362 {
363     GtkAdjustment *adj;
364     g_return_val_if_fail (HILDON_IS_CONTROLBAR (self), 0);
365     adj = GTK_RANGE(self)->adjustment;
366   
367     return (gint) ceil(adj->value);
368 }
369
370 /**
371  * hildon_controlbar_set_max:
372  * @self: Pointer to #HildonControlbar
373  * @max: Maximum value to set. The value needs to be
374  * in range of > 0 && <= G_MAX_INT.
375  * If the new maximum is smaller than current value,
376  * the value will be adjusted so that
377  * it equals the new maximum.
378  *
379  * Accessor method for setting #HildonControlbar maximum to the
380  * given value.
381  **/
382 void hildon_controlbar_set_max(HildonControlbar * self, gint max)
383 {
384     GtkAdjustment *adj;
385     g_return_if_fail (HILDON_IS_CONTROLBAR (self));
386     adj = GTK_RANGE(self)->adjustment;
387
388     if (max < adj->lower)
389       max = adj->lower;
390     
391     if (adj->value > max)
392         hildon_controlbar_set_value (self, max);
393
394     adj->upper = max;
395     gtk_adjustment_changed(adj);
396
397     g_object_notify (G_OBJECT(self), "max");
398 }
399
400 /**
401  * hildon_controlbar_set_min:
402  * @self: Pointer to #HildonControlbar
403  * @min: Minimum value to set. The value needs to be
404  * in range of => 0 && <= G_MAX_INT.
405  * If the new minimum is smaller than current value,
406  * the value will be adjusted so that
407  * it equals the new minimum.
408  *
409  * Accessor method for setting #HildonControlbar minimum to the
410  * given value.
411  **/
412 void hildon_controlbar_set_min(HildonControlbar * self, gint min)
413 {
414     GtkAdjustment *adj;
415     g_return_if_fail (HILDON_IS_CONTROLBAR (self));
416     adj = GTK_RANGE(self)->adjustment;
417
418     if (min > adj->upper)
419       min = adj->upper;
420     
421     if (adj->value < min)
422         hildon_controlbar_set_value (self, min);
423
424     adj->lower = min;
425     gtk_adjustment_changed(adj);
426     g_object_notify (G_OBJECT(self), "min");
427 }
428
429 /**
430  * hildon_controlbar_set_range:
431  * @self: Pointer to #HildonControlbar
432  * @max: Maximum value to set. The value needs to be
433  * in range of > 0 && <= G_MAX_INT.
434  * @min: Minimum value to set. The value needs to be
435  * in range of => 0 && <= G_MAX_INT.
436  * If the new maximum is smaller than current value,
437  * the value will be adjusted so that
438  * it equals the new maximum.
439  * If the new minimum is smaller than current value,
440  * the value will be adjusted so that
441  * it equals the new minimum.
442  *
443  * Accessor method for setting #HildonControlbar maximum to the
444  * given value.
445  **/
446 void hildon_controlbar_set_range(HildonControlbar * self, gint min,
447                                  gint max)
448 {
449     g_return_if_fail (HILDON_IS_CONTROLBAR (self));
450
451     if (min > max)
452       min = max;
453     /* We need to set max first here, because when min is set before
454      * max is set, it would end up 0, because max can't be bigger than 0.
455      */
456     hildon_controlbar_set_max (self, max);
457     hildon_controlbar_set_min (self, min);
458 }
459
460 /**
461  * hildon_controlbar_get_max:
462  * @self: A pointer to #HildonControlbar
463  *
464  * Accessor method for getting controlbars current maximum value
465  *
466  * Return value: Maximum value as gint
467  */
468 gint hildon_controlbar_get_max(HildonControlbar * self)
469 {
470     GtkAdjustment *adj;
471     g_return_val_if_fail (HILDON_IS_CONTROLBAR (self), 0);
472     adj = GTK_RANGE(self)->adjustment;
473
474     return (gint) adj->upper;
475 }
476
477 /**
478  * hildon_controlbar_get_min:
479  * @self: A pointer to #HildonControlbar
480  *
481  * Accessor method for getting controlbars current minimum value
482  *
483  * Return value: Minimum value as gint
484  */
485 gint hildon_controlbar_get_min(HildonControlbar * self)
486 {
487     GtkAdjustment *adj = GTK_RANGE(self)->adjustment;
488     return (gint) adj->lower;
489 }
490
491 /*
492  * Event handler for button press
493  * Need to change button1 to button2 before passing this event to
494  * parent handler. (see specs)
495  * Also updates button_press variable so that we can draw hilites
496  * correctly
497  */
498 static gint hildon_controlbar_button_press_event(GtkWidget * widget,
499                                                  GdkEventButton * event)
500 {
501     HildonControlbar *self;
502     HildonControlbarPrivate *priv;
503     gboolean result = FALSE;
504
505     g_return_val_if_fail(widget, FALSE);
506     g_return_val_if_fail(event, FALSE);
507
508     self = HILDON_CONTROLBAR(widget);
509     priv = HILDON_CONTROLBAR_GET_PRIVATE(self);
510
511     priv->button_press = TRUE;
512     event->button = event->button == 1 ? 2 : event->button;
513
514     /* Ugh dirty hack. We manipulate the mouse event location to
515        compensate for centering the widget in case it is taller than the
516        default height. */
517     if (widget->allocation.height > DEFAULT_HEIGHT) {
518         gint difference = widget->allocation.height - DEFAULT_HEIGHT;
519
520         if (difference & 1)
521             difference += 1;
522         difference = difference / 2;
523
524         event->y -= difference;
525     }
526
527
528     /* call the parent handler */
529     if (GTK_WIDGET_CLASS(parent_class)->button_press_event)
530         result =
531             GTK_WIDGET_CLASS(parent_class)->button_press_event(widget, event);
532
533     return result;
534 }
535
536 /*
537  * Event handler for button release
538  * Need to change button1 to button2 before passing this event to
539  * parent handler. (see specs)
540  * Also updates button_press variable so that we can draw hilites
541  * correctly
542  */
543 static gint hildon_controlbar_button_release_event(GtkWidget * widget,
544                                                    GdkEventButton * event)
545 {
546     HildonControlbar *self;
547     HildonControlbarPrivate *priv;
548     gboolean result = FALSE;
549
550     g_return_val_if_fail(widget, FALSE);
551     g_return_val_if_fail(event, FALSE);
552
553     self = HILDON_CONTROLBAR(widget);
554     priv = HILDON_CONTROLBAR_GET_PRIVATE(self);
555
556     priv->button_press = FALSE;
557     event->button = event->button == 1 ? 2 : event->button;
558
559     /* call the parent handler */
560     if (GTK_WIDGET_CLASS(parent_class)->button_release_event)
561         result =
562             GTK_WIDGET_CLASS(parent_class)->button_release_event(widget, event);
563     return result;
564 }
565
566 /*
567  * Event handler for expose event
568  */
569 static gint hildon_controlbar_expose_event(GtkWidget * widget,
570                                            GdkEventExpose * event)
571 {
572     HildonControlbar *self = NULL;
573
574     gboolean result = FALSE;
575     gint old_height = -1;
576     gint old_y = -1;
577
578     g_return_val_if_fail(widget, FALSE);
579     g_return_val_if_fail(event, FALSE);
580     g_return_val_if_fail(HILDON_IS_CONTROLBAR(widget), FALSE);
581
582     self = HILDON_CONTROLBAR(widget);
583
584     old_height = widget->allocation.height;
585     old_y = widget->allocation.y;
586
587     if (widget->allocation.height > DEFAULT_HEIGHT) {
588         int difference = widget->allocation.height - DEFAULT_HEIGHT;
589
590         if (difference & 1)
591             difference += 1;
592         difference = difference / 2;
593
594         widget->allocation.y += difference;
595         widget->allocation.height = DEFAULT_HEIGHT;
596     }
597
598     /* call the parent handler */
599     if (GTK_WIDGET_CLASS(parent_class)->expose_event)
600         result = GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
601     hildon_controlbar_paint(self, &event->area);
602
603     widget->allocation.height = old_height;
604     widget->allocation.y = old_y;
605
606     return TRUE;
607 }
608
609 /*
610  * Paint method.
611  * This is where all the work is actually done...
612  */
613 static void hildon_controlbar_paint(HildonControlbar * self,
614                                     GdkRectangle * area)
615 {
616     HildonControlbarPrivate *priv;
617     GtkWidget *widget = GTK_WIDGET(self);
618     GtkAdjustment *ctrlbar = GTK_RANGE(self)->adjustment;
619     gint x = widget->allocation.x;
620     gint y = widget->allocation.y;
621     gint h = widget->allocation.height;
622     gint w = widget->allocation.width;
623     gint max = 0;
624     gint stepper_size = 0;
625     gint stepper_spacing = 0;
626     gint inner_border_width = 0;
627     gint block_area = 0, block_width = 0, block_x = 0, block_max = 0, block_height,block_y;
628     /* Number of blocks on the controlbar */
629     guint block_count = 0;
630     /* Number of displayed active blocks */
631     guint block_act = 0;
632     /* Minimum no. of blocks visible */
633     guint block_min = 0;
634     gint separatingpixels = 2;
635     gint block_remains = 0;
636     gint i, start_x, end_x, current_width;
637     GtkStateType state = GTK_STATE_NORMAL;
638
639     g_return_if_fail(area);
640
641     priv = HILDON_CONTROLBAR_GET_PRIVATE(self);
642     if (GTK_WIDGET_SENSITIVE(self) == FALSE)
643         state = GTK_STATE_INSENSITIVE;
644
645     gtk_widget_style_get(GTK_WIDGET(self),
646                          "stepper-size", &stepper_size,
647                          "stepper-spacing", &stepper_spacing,
648                          "inner_border_width", &inner_border_width, NULL);
649     g_object_get(G_OBJECT(self), "minimum_visible_bars", &block_min, NULL);
650
651     block_area = (w - 2 * stepper_size - 2 * stepper_spacing - 2 * inner_border_width);
652     if (block_area <= 0)
653         return;
654
655     block_max = ctrlbar->upper - ctrlbar->lower + block_min; 
656     block_act = priv->old_value - GTK_RANGE(self)->adjustment->lower + block_min;
657  
658     /* We check border width and maximum value and adjust
659      * separating pixels for block width here. If the block size would
660      * become too small, we make the separators smaller. Graceful fallback.
661      */
662     max = ctrlbar->upper;
663     if( ctrlbar->upper == 0 )
664     {
665       separatingpixels = 3;
666     }
667     else if ((block_area - ((max - 1) * 3)) / max >= 4) {
668         separatingpixels = 3;
669     } else if ((block_area - ((max - 1) * 2)) / max >= 4) {
670         separatingpixels = 2;
671     } else if ((block_area - ((max - 1) * 1)) / max >= 4) {
672         separatingpixels = 1;
673     } else
674         separatingpixels = 0;
675
676     if( block_max == 0 )
677     {
678       /* If block max is 0 then we dim the whole control. */
679       state = GTK_STATE_INSENSITIVE;
680       block_width = block_area;
681       block_remains = 0;
682       block_max = 1;
683     }
684     else
685     {
686       block_width =
687           (block_area - (separatingpixels * (block_max - 1))) / block_max;
688       block_remains =
689           (block_area - (separatingpixels * (block_max - 1))) % block_max;
690     }
691
692     block_x = x + stepper_size + stepper_spacing + inner_border_width;
693     block_y = y + inner_border_width;
694     block_height = h - 2 * inner_border_width;
695
696     block_count = ctrlbar->value - ctrlbar->lower +  block_min;
697
698     /* Without this there is vertical block corruption when block_height = 
699        1. This should work from 0 up to whatever */
700
701     if (block_height < 2)
702         block_height = 2;
703
704     /* 
705      * Changed the drawing of the blocks completely,
706      * because of "do-not-resize-when-changing-max"-specs.
707      * Now the code calculates from the block_remains when
708      * it should add one pixel to the block and when not.
709      */
710
711     for (i = 1; i <= block_max; i++) {
712
713         /* Here we calculate whether we add one pixel to current_width or
714            not. */
715         start_x = block_width * (i - 1) + ((i - 1) * block_remains) / block_max;
716         end_x = block_width * i + (i * block_remains) / block_max;
717         current_width = end_x - start_x;
718
719         gtk_paint_box(widget->style, widget->window, state,
720                       (i <= block_count) ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
721                       NULL, widget, "hildon_block",
722                       block_x, block_y, current_width,
723                       block_height);
724
725         /* We keep the block_x separate because of the
726            'separatingpixels' */
727         block_x += current_width + separatingpixels;
728     }
729
730 }