latest update
[hildon] / hildon-widgets / hildon-range-editor.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-range-editor.c
27  * 
28  * This file implements the HildonRangeEditor widget.
29  *
30  */
31
32 /* HILDON DOC
33  * @desc: Range Editor is used to define the range some attribute. Accepted
34  * number type is integer and '-' character is also acceptable. Range can
35  * be used in application area and in dialog.  
36  * 
37  */
38
39 #include <pango/pango.h>
40 #include <gtk/gtkbox.h>
41 #include <gtk/gtkselection.h>
42 #include <gtk/gtklabel.h>
43 #include <gtk/gtkdnd.h>
44 #include <gtk/gtksignal.h>
45 #include <gtk/gtkentry.h>
46 #include <gdk/gdkkeysyms.h>
47 #include <stdio.h>
48 #include <glib/gprintf.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <hildon-widgets/hildon-input-mode-hint.h>
52
53 #include "hildon-range-editor.h"
54
55 #ifdef HAVE_CONFIG_H
56 #include <config.h>
57 #endif
58
59 #include <libintl.h>
60 #define _(string) dgettext(PACKAGE, string)
61
62 /* Alignment in entry box ( 0 = left, 1 = right ) */
63 #define DEFAULT_ALIGNMENT 1
64 /* Amount of padding to add to each side of the separator */
65 #define DEFAULT_PADDING 3
66
67 #define DEFAULT_START -999
68 #define DEFAULT_END 999
69 #define DEFAULT_LENGTH 4
70
71 #define HILDON_RANGE_EDITOR_GET_PRIVATE(obj) \
72  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
73  HILDON_RANGE_EDITOR_TYPE, HildonRangeEditorPrivate));
74
75 typedef struct _HildonRangeEditorPrivate HildonRangeEditorPrivate;
76
77 enum
78 {
79   PROP_LOWER = 1,
80   PROP_HIGHER,
81   PROP_MIN,
82   PROP_MAX,
83   PROP_SEPARATOR
84 };
85
86 /*our parent class*/
87 static GtkContainerClass *parent_class = NULL;
88
89 /*Init functions*/
90 static void
91 hildon_range_editor_class_init (HildonRangeEditorClass *editor_class);
92 static void
93 hildon_range_editor_init (HildonRangeEditor *editor);
94 static void
95 hildon_range_editor_forall (GtkContainer *container,
96                             gboolean include_internals, GtkCallback callback,
97                             gpointer callback_data);
98 static void
99 hildon_range_editor_destroy (GtkObject *self);
100
101 /*size and font functions */
102 static void
103 hildon_range_editor_size_request (GtkWidget *widget,
104                                   GtkRequisition *requisition);
105 static void
106 hildon_range_editor_size_allocate (GtkWidget *widget,
107                                   GtkAllocation *allocation);
108 static gboolean
109 hildon_range_editor_entry_focus_in (GtkEditable *editable,
110                                     GdkEventFocus *event,
111                                     HildonRangeEditor *editor);
112 static gboolean
113 hildon_range_editor_entry_focus_out (GtkEditable *editable,
114                                     GdkEventFocus *event,
115                                     HildonRangeEditor *editor);
116 static gboolean
117 hildon_range_editor_entry_keypress (GtkWidget *widget, GdkEventKey *event,
118                                     HildonRangeEditor *editor);
119 static gboolean
120 hildon_range_editor_released (GtkEditable *editable, GdkEventButton *event,
121                               HildonRangeEditor *editor);
122 static gboolean
123 hildon_range_editor_press (GtkEditable *editable, GdkEventButton *event,
124                            HildonRangeEditor *editor);
125 static gboolean
126 hildon_range_editor_mnemonic_activate (GtkWidget *widget,
127                                        gboolean group_cycling);
128
129 static void hildon_range_editor_set_property( GObject *object, guint param_id,
130                                        const GValue *value, GParamSpec *pspec );
131 static void hildon_range_editor_get_property( GObject *object, guint param_id,
132                                          GValue *value, GParamSpec *pspec );
133
134 /* Private struct */
135 struct _HildonRangeEditorPrivate
136 {
137     GtkWidget *start_entry;
138     GtkWidget *end_entry;
139     GtkWidget *label;
140     gint range_limits_start;
141     gint range_limits_end;
142     gboolean bp;
143 };
144
145 /* Private functions */
146 static void
147 hildon_range_editor_class_init  (HildonRangeEditorClass *editor_class)
148 {
149     GObjectClass *gobject_class = G_OBJECT_CLASS(editor_class);
150     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(editor_class);
151     GtkContainerClass *container_class = GTK_CONTAINER_CLASS(editor_class);
152
153     /* set the global parent_class */
154     parent_class = g_type_class_peek_parent(editor_class);
155
156     /* now the object stuff */
157     g_type_class_add_private(editor_class,
158                              sizeof(HildonRangeEditorPrivate));
159
160     gobject_class->set_property = hildon_range_editor_set_property;
161     gobject_class->get_property = hildon_range_editor_get_property;
162     widget_class->size_request = hildon_range_editor_size_request;
163     widget_class->size_allocate = hildon_range_editor_size_allocate;
164
165     widget_class->mnemonic_activate = hildon_range_editor_mnemonic_activate;
166
167     container_class->forall = hildon_range_editor_forall;
168     GTK_OBJECT_CLASS(editor_class)->destroy = hildon_range_editor_destroy;
169
170     gtk_widget_class_install_style_property(widget_class,
171         g_param_spec_int("hildon_range_editor_entry_alignment",
172                          "Hildon RangeEditor entry alignment",
173                          "Hildon RangeEditor entry alignment", 0, 1,
174                          DEFAULT_ALIGNMENT,
175                          G_PARAM_READABLE));
176
177     gtk_widget_class_install_style_property(widget_class,
178         g_param_spec_int("hildon_range_editor_separator_padding",
179                          "Hildon RangeEditor separator padding",
180                          "Hildon RangeEditor separaror padding",
181                          G_MININT, G_MAXINT,
182                          DEFAULT_PADDING,
183                          G_PARAM_READABLE));
184
185   /**
186    * HildonRangeEditor:min:
187    *
188    * Minimum value in a range.
189    * Default: -999
190    */
191   g_object_class_install_property( gobject_class, PROP_MIN,
192                                    g_param_spec_int("min",
193                                    "Minimum value",
194                                    "Minimum value in a range",
195                                    G_MININT, G_MAXINT,
196                                    DEFAULT_START, G_PARAM_CONSTRUCT | 
197                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
198
199   /**
200    * HildonRangeEditor:max:
201    *
202    * Maximum value in a range.
203    * Default: 999
204    */
205   g_object_class_install_property( gobject_class, PROP_MAX,
206                                    g_param_spec_int("max",
207                                    "Maximum value",
208                                     "Maximum value in a range",
209                                    G_MININT, G_MAXINT,
210                                    DEFAULT_END, G_PARAM_CONSTRUCT | 
211                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
212
213   /**
214    * HildonRangeEditor:lower:
215    *
216    * Current value in the entry presenting lower end of selected range.
217    * Default: -999
218    */
219   g_object_class_install_property( gobject_class, PROP_LOWER,
220                                    g_param_spec_int("lower",
221                                    "Current lower value",
222            "Current value in the entry presenting lower end of selected range",
223                                    G_MININT, G_MAXINT,
224                                    DEFAULT_START, G_PARAM_CONSTRUCT | 
225                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
226
227   /**
228    * HildonRangeEditor:higher:
229    *
230    * Current value in the entry presenting higher end of selected range.
231    * Default: 999
232    */
233   g_object_class_install_property( gobject_class, PROP_HIGHER,
234                                    g_param_spec_int("higher",
235                                    "Current higher value",
236            "Current value in the entry presenting higher end of selected range",
237                                    G_MININT, G_MAXINT,
238                                    DEFAULT_END, G_PARAM_CONSTRUCT | 
239                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
240
241   /**
242    * HildonRangeEditor:separator:
243    *
244    * Separator string to separate range editor entries.
245    * Default: "-"
246    */
247   g_object_class_install_property( gobject_class, PROP_SEPARATOR,
248                                    g_param_spec_string("separator",
249                                    "Separator",
250                                     "Separator string to separate entries",
251                                    _("Ckct_wi_range_separator"),
252                                    G_PARAM_CONSTRUCT | 
253                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
254 }
255
256 static void
257 hildon_range_editor_init (HildonRangeEditor *editor)
258 {
259     HildonRangeEditorPrivate *priv;
260
261     gint range_editor_entry_alignment;
262     gint range_editor_separator_padding;
263
264     priv = HILDON_RANGE_EDITOR_GET_PRIVATE(editor);
265
266     GTK_WIDGET_SET_FLAGS(editor, GTK_NO_WINDOW);
267     
268     gtk_widget_push_composite_child();
269     
270     priv->start_entry = GTK_WIDGET(gtk_entry_new());
271     priv->end_entry = GTK_WIDGET(gtk_entry_new());
272     priv->label = GTK_WIDGET(gtk_label_new(_("Ckct_wi_range_separator")));
273     priv->bp = FALSE;
274
275     /* Get values from gtkrc (or use defaults) */
276     gtk_widget_style_get(GTK_WIDGET(editor),
277                          "hildon_range_editor_entry_alignment",
278                          &range_editor_entry_alignment,
279                          "hildon_range_editor_separator_padding",
280                          &range_editor_separator_padding, NULL);
281
282     /* Add padding to separator */
283     gtk_misc_set_padding (GTK_MISC(priv->label),
284                           range_editor_separator_padding, 0);
285
286     /* Align the text to right in entry box */
287     gtk_entry_set_alignment(GTK_ENTRY(priv->start_entry),
288                             range_editor_entry_alignment);
289     gtk_entry_set_alignment(GTK_ENTRY(priv->end_entry),
290                             range_editor_entry_alignment);
291
292     gtk_widget_set_parent(priv->start_entry, GTK_WIDGET(editor));
293     gtk_widget_set_parent(priv->end_entry, GTK_WIDGET(editor));
294     gtk_widget_set_parent(priv->label, GTK_WIDGET(editor));
295     
296     g_signal_connect(G_OBJECT(priv->start_entry), "button-release-event",
297                      G_CALLBACK(hildon_range_editor_released), editor);
298     g_signal_connect(G_OBJECT(priv->end_entry), "button-release-event",
299                      G_CALLBACK(hildon_range_editor_released), editor);
300                      
301     g_signal_connect(G_OBJECT(priv->start_entry), "button-press-event",
302                      G_CALLBACK(hildon_range_editor_press), editor);
303     g_signal_connect(G_OBJECT(priv->end_entry), "button-press-event",
304                      G_CALLBACK(hildon_range_editor_press), editor);
305                      
306     g_signal_connect(G_OBJECT(priv->start_entry), "key-press-event",
307                        G_CALLBACK(hildon_range_editor_entry_keypress), editor);
308     g_signal_connect(G_OBJECT(priv->end_entry), "key-press-event",
309                        G_CALLBACK(hildon_range_editor_entry_keypress), editor);
310
311     g_signal_connect(G_OBJECT(priv->start_entry), "focus-in-event",
312                      G_CALLBACK(hildon_range_editor_entry_focus_in), editor);
313     g_signal_connect(G_OBJECT(priv->end_entry), "focus-in-event",
314                      G_CALLBACK(hildon_range_editor_entry_focus_in), editor);
315
316     g_signal_connect(G_OBJECT(priv->start_entry), "focus-out-event",
317                      G_CALLBACK(hildon_range_editor_entry_focus_out), editor);
318     g_signal_connect(G_OBJECT(priv->end_entry), "focus-out-event",
319                      G_CALLBACK(hildon_range_editor_entry_focus_out), editor);
320                        
321     g_object_set( G_OBJECT(priv->start_entry),
322                     "input-mode", HILDON_INPUT_MODE_HINT_NUMERIC, NULL );
323     g_object_set( G_OBJECT(priv->end_entry),
324                     "input-mode", HILDON_INPUT_MODE_HINT_NUMERIC, NULL );
325     
326     gtk_widget_show(priv->start_entry);
327     gtk_widget_show(priv->end_entry);
328     gtk_widget_show(priv->label);
329
330     gtk_widget_pop_composite_child();
331 }
332
333 static void hildon_range_editor_set_property (GObject *object, guint param_id,
334                                        const GValue *value, GParamSpec *pspec)
335 {
336   HildonRangeEditor *editor = HILDON_RANGE_EDITOR(object);
337   switch (param_id)
338   {
339     case PROP_LOWER:
340       hildon_range_editor_set_lower (editor, g_value_get_int (value));
341       break;
342
343     case PROP_HIGHER:
344       hildon_range_editor_set_higher (editor, g_value_get_int (value));
345       break;
346
347     case PROP_MIN:
348       hildon_range_editor_set_min (editor, g_value_get_int (value));
349       break;
350
351     case PROP_MAX:
352       hildon_range_editor_set_max (editor, g_value_get_int (value));
353       break;
354
355     case PROP_SEPARATOR:
356       hildon_range_editor_set_separator (editor,
357                                          g_value_get_string (value));
358       break;
359
360     default:
361       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
362       break;
363   }
364 }
365
366 static void hildon_range_editor_get_property( GObject *object, guint param_id,
367                                          GValue *value, GParamSpec *pspec )
368 {
369   HildonRangeEditor *editor = HILDON_RANGE_EDITOR(object);
370   switch (param_id)
371   {
372     case PROP_LOWER:
373       g_value_set_int (value, hildon_range_editor_get_lower (editor));
374       break;
375
376     case PROP_HIGHER:
377       g_value_set_int (value, hildon_range_editor_get_higher (editor));
378       break;
379
380     case PROP_MIN:
381       g_value_set_int (value, hildon_range_editor_get_min (editor));
382       break;
383
384     case PROP_MAX:
385       g_value_set_int (value, hildon_range_editor_get_max (editor));
386       break;
387
388     case PROP_SEPARATOR:
389       g_value_set_string (value, hildon_range_editor_get_separator (editor));
390       break;
391
392     default:
393       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
394       break;
395   }
396 }
397
398 static gboolean
399 hildon_range_editor_entry_focus_in (GtkEditable *editable,
400                                     GdkEventFocus *event,
401                                     HildonRangeEditor *editor)
402 {
403   HildonRangeEditorPrivate *priv = HILDON_RANGE_EDITOR_GET_PRIVATE(editor);
404   if(priv->bp)
405   {
406     priv->bp = FALSE;
407     return FALSE;
408   }
409   if (GTK_WIDGET(editable) == priv->start_entry)
410     gtk_editable_select_region(editable, -1, 0);
411   else
412     gtk_editable_select_region(editable, 0, -1);
413   return FALSE;
414 }
415
416 static gboolean
417 hildon_range_editor_entry_focus_out (GtkEditable *editable,
418                                     GdkEventFocus *event,
419                                     HildonRangeEditor *editor)
420 {
421   HildonRangeEditorPrivate *priv = HILDON_RANGE_EDITOR_GET_PRIVATE(editor);
422   hildon_range_editor_set_range( editor,
423                             g_strtod(GTK_ENTRY(priv->start_entry)->text, NULL),
424                             g_strtod(GTK_ENTRY(priv->end_entry)->text, NULL));
425   return FALSE;
426 }
427
428 static gboolean
429 hildon_range_editor_press (GtkEditable *editable, GdkEventButton *event,
430                            HildonRangeEditor *editor)
431 {
432   HildonRangeEditorPrivate *priv = HILDON_RANGE_EDITOR_GET_PRIVATE(editor);
433   priv->bp = TRUE;
434   return FALSE;
435 }
436
437 static gboolean
438 hildon_range_editor_mnemonic_activate (GtkWidget *widget,
439                                        gboolean group_cycling)
440 {
441   HildonRangeEditorPrivate *priv = HILDON_RANGE_EDITOR_GET_PRIVATE(widget);
442   gtk_widget_grab_focus( priv->start_entry );
443   return TRUE;
444 }
445
446 static void
447 hildon_range_editor_forall (GtkContainer *container,
448                             gboolean include_internals,
449                             GtkCallback callback, gpointer callback_data)
450 {
451     HildonRangeEditorPrivate *priv;
452
453     g_return_if_fail(container);
454     g_return_if_fail(callback);
455
456     priv = HILDON_RANGE_EDITOR_GET_PRIVATE(container);
457
458     if (!include_internals)
459       return;
460     
461     (*callback) (priv->start_entry, callback_data);
462     (*callback) (priv->end_entry, callback_data);
463     (*callback) (priv->label, callback_data);
464 }
465
466 static void
467 hildon_range_editor_destroy(GtkObject *self)
468 {
469     HildonRangeEditorPrivate *priv = HILDON_RANGE_EDITOR_GET_PRIVATE(self);
470
471     if (priv->start_entry)
472     {
473       gtk_widget_unparent(priv->start_entry);
474       priv->start_entry = NULL;
475     }
476     if (priv->end_entry)
477     {
478       gtk_widget_unparent(priv->end_entry);
479       priv->end_entry = NULL;
480     }
481     if (priv->label)
482     {
483       gtk_widget_unparent(priv->label);
484       priv->label = NULL;
485     }
486
487     if (GTK_OBJECT_CLASS(parent_class)->destroy)
488         GTK_OBJECT_CLASS(parent_class)->destroy(self);
489 }
490
491
492 static void
493 hildon_range_editor_size_request(GtkWidget *widget,
494                                  GtkRequisition *requisition)
495 {
496     HildonRangeEditorPrivate *priv = NULL;
497     GtkRequisition lab_req, mreq;
498     
499     priv = HILDON_RANGE_EDITOR_GET_PRIVATE(widget);
500
501     gtk_entry_get_width_chars(GTK_ENTRY(priv->end_entry));
502     
503     gtk_widget_size_request(priv->start_entry, &mreq);
504     gtk_widget_size_request(priv->end_entry, &mreq);
505     gtk_widget_size_request(priv->label, &lab_req);
506
507     requisition->width = mreq.width * 2 + lab_req.width +
508                          widget->style->xthickness * 2;
509     requisition->height = mreq.height + widget->style->ythickness * 2;
510     requisition->height = MAX (requisition->height, lab_req.height);
511 }
512
513 static void
514 hildon_range_editor_size_allocate(GtkWidget *widget,
515                                   GtkAllocation *allocation)
516 {
517     HildonRangeEditorPrivate *priv;
518     GtkAllocation child1_allocation, child2_allocation, child3_allocation;
519
520     priv = HILDON_RANGE_EDITOR_GET_PRIVATE(widget);
521
522     widget->allocation = *allocation;
523
524     if (priv->start_entry && GTK_WIDGET_VISIBLE(priv->start_entry))
525       {
526         GtkRequisition child_requisition;
527
528         gtk_widget_get_child_requisition(priv->start_entry,
529                                          &child_requisition);
530
531         child1_allocation.x = allocation->x;
532         child1_allocation.y = allocation->y;
533
534         child1_allocation.width = child_requisition.width;
535         child1_allocation.height = allocation->height;
536
537         gtk_widget_size_allocate(priv->start_entry, &child1_allocation);
538       }
539
540     if (priv->label && GTK_WIDGET_VISIBLE(priv->label))
541       {
542         GtkRequisition child_requisition;
543
544         gtk_widget_get_child_requisition(priv->label, &child_requisition);
545
546         child2_allocation.x = child1_allocation.x + child1_allocation.width;
547         child2_allocation.y = allocation->y;
548         child2_allocation.width = child_requisition.width + 4;
549         child2_allocation.height = allocation->height;
550
551         gtk_widget_size_allocate (priv->label, &child2_allocation);
552       }
553
554     if (priv->end_entry && GTK_WIDGET_VISIBLE(priv->end_entry))
555       {
556         GtkRequisition child_requisition;
557
558         gtk_widget_get_child_requisition (priv->end_entry, &child_requisition);
559
560         child3_allocation.x = child2_allocation.x + child2_allocation.width;
561         child3_allocation.y = allocation->y;
562
563         child3_allocation.width = child_requisition.width;
564         child3_allocation.height = allocation->height;
565
566         gtk_widget_size_allocate(priv->end_entry, &child3_allocation);
567       }
568 }
569
570 static gboolean
571 hildon_range_editor_released(GtkEditable *editable, GdkEventButton *event,
572                              HildonRangeEditor *editor)
573 {
574     HildonRangeEditorPrivate *priv = HILDON_RANGE_EDITOR_GET_PRIVATE(editor);
575     if (GTK_WIDGET(editable) == priv->start_entry)
576       gtk_editable_select_region(editable, -1, 0);
577     else
578       gtk_editable_select_region(editable, 0, -1); 
579     return FALSE;
580 }
581
582 static gboolean
583 hildon_range_editor_entry_keypress(GtkWidget *widget, GdkEventKey *event,
584                                    HildonRangeEditor *editor)
585 {
586     HildonRangeEditorPrivate *priv;
587     GtkWidget *wdgt;
588     gint pos;
589     gchar *str;
590
591     priv = HILDON_RANGE_EDITOR_GET_PRIVATE(editor);
592
593     wdgt = widget == priv->start_entry ? priv->end_entry : priv->start_entry;
594     str = GTK_ENTRY(widget)->text;
595     pos = gtk_editable_get_position(GTK_EDITABLE(widget));
596  
597     if (pos > 0 && (event->keyval == GDK_minus ||
598                     event->keyval == GDK_KP_Subtract))
599        return TRUE;
600
601     if (strlen(str) == pos)
602       pos = -1;
603
604     if ((widget == priv->start_entry &&
605         (event->keyval == GDK_Tab || (pos == -1 &&
606         (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)))) ||
607         (widget == priv->end_entry &&
608         (event->keyval == GDK_ISO_Left_Tab|| (pos == 0 &&
609         (event->keyval == GDK_Left || event->keyval == GDK_KP_Left)))))
610     {
611       gtk_widget_grab_focus(wdgt);
612       if (widget == priv->start_entry)
613       {
614         gtk_editable_set_position(GTK_EDITABLE(wdgt), -1);
615         gtk_editable_select_region(GTK_EDITABLE(wdgt), 0, -1);
616       }
617       else
618       {
619         gtk_editable_set_position(GTK_EDITABLE(wdgt), 0);
620         gtk_editable_select_region(GTK_EDITABLE(wdgt), -1, 0);
621       }
622     }
623     else if ((event->keyval >= GDK_0 && event->keyval <= GDK_9) ||
624              (event->keyval >= GDK_KP_0 && event->keyval <= GDK_KP_9) ||
625              (event->keyval == GDK_minus || event->keyval == GDK_KP_Subtract) ||
626              event->keyval == GDK_Up || event->keyval == GDK_Down ||
627              event->keyval == GDK_Right || event->keyval == GDK_KP_Right ||
628              event->keyval == GDK_Left || event->keyval == GDK_KP_Left ||
629              event->keyval == GDK_BackSpace || event->keyval == GDK_Delete)
630     {
631       return FALSE;
632     }
633     return TRUE;
634 }
635
636 /* Public functions */
637
638 /**
639  * hildon_range_editor_get_type:
640  * @Returns : GType of #HildonRangeEditor.
641  *
642  * Initialises, and returns the type of a hildon range editor.
643  */
644 GType
645 hildon_range_editor_get_type (void)
646 {
647     static GType editor_type = 0;
648
649     if (!editor_type)
650       {
651         static const GTypeInfo editor_info =
652           {
653             sizeof(HildonRangeEditorClass),
654             NULL,       /* base_init */
655             NULL,       /* base_finalize */
656             (GClassInitFunc) hildon_range_editor_class_init,
657             NULL,       /* class_finalize */
658             NULL,       /* class_data */
659             sizeof(HildonRangeEditor),
660             0,  /* n_preallocs */
661             (GInstanceInitFunc) hildon_range_editor_init,
662           };
663         editor_type = g_type_register_static(GTK_TYPE_CONTAINER,
664                                              "HildonRangeEditor",
665                                              &editor_info, 0);
666       }
667     return editor_type;
668 }
669
670 /**
671  * hildon_range_editor_new:
672  *
673  * HildonRangeEditor contains two GtkEntrys that accept numbers and minus. 
674  *
675  * Return value: pointer to a new @HildonRangeEditor widget.
676  **/
677 GtkWidget *
678 hildon_range_editor_new (void)
679 {
680     return GTK_WIDGET(g_object_new(HILDON_RANGE_EDITOR_TYPE, NULL));
681 }
682
683
684 /**
685  * hildon_range_editor_new_with_separator:
686  * @separator: A string that is shown between the numbers.
687  *
688  * HildonRangeEditor contains two @GtkEntrys that accept numbers. 
689  * @separator is displayed between two entrys.
690  * CHECKME: Use '-' as a separator in the case of null separator?
691  *
692  * Return value: pointer to a new @HildonRangeEditor widget.
693  **/
694 GtkWidget *
695 hildon_range_editor_new_with_separator (gchar *separator)
696 {
697     return GTK_WIDGET (g_object_new (HILDON_RANGE_EDITOR_TYPE,
698                                      "separator", separator, NULL));
699 }
700
701
702 /**
703  * hildon_range_editor_set_range:
704  * @editor: the #HildonRangeEditor widget.
705  * @start: range's start value. 
706  * @end: range's end value.
707  *
708  * Sets a range to the editor. (The current value)
709  *
710  * Sets the range of the @HildonRangeEditor widget.
711  **/
712 void
713 hildon_range_editor_set_range (HildonRangeEditor *editor, gint start, gint end)
714 {
715     g_return_if_fail (editor);
716     g_return_if_fail (HILDON_IS_RANGE_EDITOR (editor));
717
718     hildon_range_editor_set_lower (editor, start);
719     hildon_range_editor_set_higher (editor, end);
720 }
721
722
723 /**
724  * hildon_range_editor_get_range:
725  * @editor: the #HildonRangeEditor widget.
726  * @start: ranges start value.
727  * @end: ranges end value.
728  *
729  * Gets the range of the @HildonRangeEditor widget.
730  **/
731 void
732 hildon_range_editor_get_range (HildonRangeEditor *editor, gint *start,
733                                gint *end)
734 {
735     HildonRangeEditorPrivate *priv;
736     g_return_if_fail (editor);
737     g_return_if_fail (HILDON_IS_RANGE_EDITOR (editor) || start || end);
738     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
739
740     *start = hildon_range_editor_get_lower (editor);
741     *end = hildon_range_editor_get_higher (editor);
742 }
743
744
745 /**
746  * hildon_range_editor_set_limits:
747  * @editor: the #HildonRangeEditor widget.
748  * @start: minimum acceptable value (default: no limit).
749  * @end: maximum accecptable value (default: no limit).
750  *
751  * if start's or end's value is larger than maximum acceptable integer
752  * '999999999', function sets the maximum value for integer
753  *
754  * if start's or end's value is smaller than minimum acceptable integer
755  * '-99999999', function sets the minimum value for integer
756  * 
757  * Sets the range of the @HildonRangeEditor widget.
758  **/
759 void
760 hildon_range_editor_set_limits (HildonRangeEditor *editor, gint start,
761                                 gint end)
762 {
763     hildon_range_editor_set_min (editor, start);
764     hildon_range_editor_set_max (editor, end);
765 }
766
767 void
768 hildon_range_editor_set_lower (HildonRangeEditor *editor, gint value)
769 {
770     HildonRangeEditorPrivate *priv;
771     gchar range[12];
772     g_return_if_fail (editor);
773     g_return_if_fail (HILDON_IS_RANGE_EDITOR (editor));
774     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
775
776     if (priv->range_limits_start <= value && priv->range_limits_end >= value)
777       g_sprintf (range, "%d", value);
778     else
779       g_sprintf (range, "%d", priv->range_limits_start);
780
781     gtk_entry_set_text (GTK_ENTRY (priv->start_entry), range);
782     g_object_notify (G_OBJECT (editor), "lower");
783 }
784
785 void
786 hildon_range_editor_set_higher (HildonRangeEditor *editor, gint value)
787 {
788     HildonRangeEditorPrivate *priv;
789     gchar range[12];
790     g_return_if_fail (editor);
791     g_return_if_fail (HILDON_IS_RANGE_EDITOR (editor));
792     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
793
794     if (priv->range_limits_start <= value && priv->range_limits_end >= value)
795       g_sprintf (range, "%d", value);
796     else
797       g_sprintf (range, "%d", priv->range_limits_end);
798
799     gtk_entry_set_text (GTK_ENTRY (priv->end_entry), range);
800     g_object_notify (G_OBJECT (editor), "higher");
801 }
802
803 gint
804 hildon_range_editor_get_lower (HildonRangeEditor *editor)
805 {
806     HildonRangeEditorPrivate *priv;
807     g_return_val_if_fail (editor, 0);
808     g_return_val_if_fail (HILDON_IS_RANGE_EDITOR (editor), 0);
809     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
810
811     return (gint)g_strtod (GTK_ENTRY (priv->start_entry)->text, NULL);
812 }
813
814 gint
815 hildon_range_editor_get_higher (HildonRangeEditor *editor)
816 {
817     HildonRangeEditorPrivate *priv;
818     g_return_val_if_fail (editor, 0);
819     g_return_val_if_fail (HILDON_IS_RANGE_EDITOR (editor), 0);
820     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
821
822     return (gint)g_strtod (GTK_ENTRY (priv->end_entry)->text, NULL);
823 }
824
825 void
826 hildon_range_editor_set_min (HildonRangeEditor *editor, gint value)
827 {
828     HildonRangeEditorPrivate *priv;
829     gchar end_range[12], start_range[12];
830     GtkEntry *start_entry, *end_entry;
831     gint length = 0;
832
833     g_return_if_fail (editor);
834     g_return_if_fail (HILDON_IS_RANGE_EDITOR (editor));
835
836     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
837
838     g_sprintf (start_range, "%d", value);
839     start_entry = GTK_ENTRY (priv->start_entry);
840
841     if (priv->range_limits_end < value)
842       hildon_range_editor_set_max (editor, value);
843     else
844     {
845       g_sprintf (end_range, "%d", priv->range_limits_end);
846       end_entry = GTK_ENTRY (priv->end_entry);
847       length = MAX (strlen (start_range), strlen (end_range));
848
849       gtk_entry_set_width_chars (start_entry, length);
850       gtk_entry_set_max_length (start_entry, length);
851       gtk_entry_set_width_chars (end_entry, length);
852       gtk_entry_set_max_length (end_entry, length);
853     }
854
855     if (hildon_range_editor_get_lower (editor) < value)
856       gtk_entry_set_text (start_entry, start_range);
857
858     priv->range_limits_start = value;
859     g_object_notify (G_OBJECT (editor), "min");
860 }
861
862 void
863 hildon_range_editor_set_max (HildonRangeEditor *editor, gint value)
864 {
865     HildonRangeEditorPrivate *priv;
866     gchar start_range[12], end_range[12];
867     GtkEntry *start_entry, *end_entry;
868     gint length = 0;
869
870     g_return_if_fail (editor);
871     g_return_if_fail (HILDON_IS_RANGE_EDITOR (editor));
872
873     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
874
875     g_sprintf (end_range, "%d", value);
876     end_entry = GTK_ENTRY (priv->end_entry);
877
878     if (priv->range_limits_start > value)
879       hildon_range_editor_set_min (editor, value);
880     else
881     {
882       g_sprintf (start_range, "%d", priv->range_limits_start);
883       start_entry = GTK_ENTRY (priv->start_entry);
884       length = MAX (strlen (end_range), strlen (start_range));
885
886       gtk_entry_set_width_chars (start_entry, length);
887       gtk_entry_set_max_length (start_entry, length);
888       gtk_entry_set_width_chars (end_entry, length);
889       gtk_entry_set_max_length (end_entry, length);
890     }
891
892     if (hildon_range_editor_get_higher (editor) > value)
893       gtk_entry_set_text (end_entry, end_range);
894
895     priv->range_limits_end = value;
896     g_object_notify (G_OBJECT (editor), "max");
897 }
898
899 gint
900 hildon_range_editor_get_min (HildonRangeEditor *editor)
901 {
902     HildonRangeEditorPrivate *priv;
903     g_return_val_if_fail (editor, 0);
904     g_return_val_if_fail (HILDON_IS_RANGE_EDITOR (editor), 0);
905     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
906
907     return priv->range_limits_start;
908 }
909
910 gint
911 hildon_range_editor_get_max (HildonRangeEditor *editor)
912 {
913     HildonRangeEditorPrivate *priv;
914     g_return_val_if_fail (editor, 0);
915     g_return_val_if_fail (HILDON_IS_RANGE_EDITOR (editor), 0);
916     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
917
918     return priv->range_limits_end;
919 }
920
921 void
922 hildon_range_editor_set_separator (HildonRangeEditor *editor,
923                                    const gchar *separator)
924 {
925     HildonRangeEditorPrivate *priv;
926     g_return_if_fail (editor);
927     g_return_if_fail (HILDON_IS_RANGE_EDITOR (editor));
928     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
929
930     gtk_label_set_text (GTK_LABEL (priv->label), separator);
931     g_object_notify (G_OBJECT(editor), "separator");
932 }
933
934 const gchar *
935 hildon_range_editor_get_separator (HildonRangeEditor *editor)
936 {
937     HildonRangeEditorPrivate *priv;
938     g_return_val_if_fail (editor, 0);
939     g_return_val_if_fail (HILDON_IS_RANGE_EDITOR (editor), 0);
940     priv = HILDON_RANGE_EDITOR_GET_PRIVATE (editor);
941
942     return gtk_label_get_text (GTK_LABEL (priv->label));
943 }