latest update
[hildon] / hildon-widgets / hildon-number-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-number-editor.c
27  *
28  * This file contains the implementation of Hildon Number Editor
29  *
30  */
31
32 #include <gdk/gdkkeysyms.h>
33 #include <glib.h>
34 #include <gtk/gtk.h>
35 #include <pango/pango.h>
36
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 #include "hildon-number-editor.h"
42 #include "hildon-marshalers.h"
43 #include <hildon-widgets/gtk-infoprint.h>
44 #include "hildon-composite-widget.h"
45 #include <hildon-widgets/hildon-input-mode-hint.h>
46
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
50
51 #include <libintl.h>
52 #define _(String) dgettext(PACKAGE, String)
53
54 /*Pixel spec defines*/
55 #define SPACE_BORDER 6
56 #define NUMBER_EDITOR_HEIGHT 30
57
58 #define BUTTON_HEIGHT 30
59 #define BUTTON_WIDTH 30
60
61 #define HILDON_NUMBER_EDITOR_GET_PRIVATE(obj) \
62         (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_NUMBER_EDITOR, \
63         HildonNumberEditorPrivate));
64
65 typedef struct _HildonNumberEditorPrivate HildonNumberEditorPrivate;
66
67 static void
68 hildon_number_editor_class_init (HildonNumberEditorClass *editor_class);
69
70 static void
71 hildon_number_editor_init (HildonNumberEditor *editor);
72
73 static gboolean
74 hildon_number_editor_entry_focusout (GtkWidget *widget, GdkEventFocus *event,
75                                      gpointer data);
76
77 static void
78 hildon_number_editor_entry_changed (GtkWidget *widget, gpointer data);
79
80 static void
81 hildon_number_editor_size_request (GtkWidget *widget,
82                                    GtkRequisition *requisition);
83
84 static void
85 set_widget_allocation (GtkWidget *widget, GtkAllocation *alloc,
86                        GtkAllocation *allocation);
87
88 static void
89 hildon_number_editor_size_allocate (GtkWidget *widget,
90                                     GtkAllocation *allocation);
91
92 static gboolean
93 hildon_number_editor_entry_keypress (GtkWidget *widget, GdkEventKey *event,
94                                      gpointer data);
95
96 static gboolean
97 hildon_number_editor_button_pressed (GtkWidget *widget, GdkEventButton *event,
98                                      gpointer data);
99
100 static gboolean
101 hildon_number_editor_entry_button_released (GtkWidget *widget,
102                                            GdkEventButton *event,
103                                            gpointer data);
104 static gboolean
105 hildon_number_editor_button_released (GtkWidget *widget,
106                                       GdkEvent *event,
107                                       HildonNumberEditor *editor);
108 static gboolean
109 do_mouse_timeout (HildonNumberEditor *editor);
110
111 static gboolean
112 change_numbers (HildonNumberEditor *editor, gint type, gint cursor_pos);
113
114 static gchar *
115 integer_to_string (gint value);
116
117 static void
118 hildon_number_editor_forall (GtkContainer *container, gboolean include_internals,
119                      GtkCallback callback, gpointer callback_data);
120
121 static void
122 hildon_number_editor_destroy (GtkObject *self);
123
124 static gboolean
125 hildon_number_editor_start_timer (HildonNumberEditor *editor);
126
127 static void
128 hildon_number_editor_finalize (GObject *self);
129
130 static gboolean
131 hildon_number_editor_mnemonic_activate( GtkWidget *widget,
132                                         gboolean group_cycle );
133 static gboolean
134 hildon_number_editor_error_handler(HildonNumberEditor *editor,
135                                    HildonNumberEditorErrorType type);
136
137 enum
138 {
139   RANGE_ERROR,
140
141   LAST_SIGNAL
142 };
143
144 static GtkContainerClass *parent_class;
145
146 static guint HildonNumberEditor_signal[LAST_SIGNAL] = {0};
147
148 struct _HildonNumberEditorPrivate
149 {
150     GtkWidget *num_entry;
151     GtkWidget *plus;
152     GtkWidget *minus;
153
154     gint start;
155     gint end;
156     gint default_val;
157     gint button_type;
158     gint button_event_id;
159
160     gboolean negative;
161 };
162
163
164 GType hildon_number_editor_get_type(void)
165 {
166     static GType editor_type = 0;
167
168     if (!editor_type)
169       {
170         static const GTypeInfo editor_info =
171           {
172             sizeof(HildonNumberEditorClass),
173             NULL,       /* base_init */
174             NULL,       /* base_finalize */
175             (GClassInitFunc) hildon_number_editor_class_init,
176             NULL,       /* class_finalize */
177             NULL,       /* class_data */
178             sizeof(HildonNumberEditor),
179             0,  /* n_preallocs */
180             (GInstanceInitFunc) hildon_number_editor_init,
181           };
182         editor_type = g_type_register_static(GTK_TYPE_CONTAINER,
183                                              "HildonNumberEditor",
184                                              &editor_info, 0);
185       }
186     return editor_type;
187 }
188
189 static void
190 hildon_number_editor_class_init(HildonNumberEditorClass * editor_class)
191 {
192     GtkContainerClass *container_class = GTK_CONTAINER_CLASS(editor_class);
193     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(editor_class);
194
195     g_type_class_add_private(editor_class,
196                              sizeof(HildonNumberEditorPrivate));
197
198     parent_class = g_type_class_peek_parent(editor_class);
199
200     widget_class->size_request = hildon_number_editor_size_request;
201     widget_class->size_allocate = hildon_number_editor_size_allocate;
202     widget_class->mnemonic_activate = hildon_number_editor_mnemonic_activate;
203     widget_class->focus = hildon_composite_widget_focus;
204
205     editor_class->error_handler = hildon_number_editor_error_handler;
206
207     /* Because we derived our widget from GtkContainer, we should override 
208        forall method */
209     container_class->forall = hildon_number_editor_forall;
210     GTK_OBJECT_CLASS(editor_class)->destroy = hildon_number_editor_destroy;
211     G_OBJECT_CLASS(editor_class)->finalize = hildon_number_editor_finalize;
212
213     HildonNumberEditor_signal[RANGE_ERROR] =
214       g_signal_new("range_error", HILDON_TYPE_NUMBER_EDITOR,
215                    G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET
216                    (HildonNumberEditorClass, error_handler),
217                    g_signal_accumulator_true_handled, NULL,
218                    _hildon_marshal_BOOLEAN__INT,
219                    G_TYPE_BOOLEAN, 1, G_TYPE_INT);
220 }
221
222 static void
223 hildon_number_editor_forall(GtkContainer *container, gboolean include_internals,
224                             GtkCallback callback, gpointer callback_data)
225 {
226     HildonNumberEditorPrivate *priv =
227         HILDON_NUMBER_EDITOR_GET_PRIVATE(container);
228
229     g_return_if_fail(callback != NULL);              
230
231     if (!include_internals)
232         return;
233
234     (*callback) (priv->minus, callback_data);
235     (*callback) (priv->num_entry, callback_data);
236     (*callback) (priv->plus, callback_data);
237 }
238
239 static void
240 hildon_number_editor_destroy(GtkObject *self)
241 {
242     HildonNumberEditorPrivate *priv;
243
244     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(self);
245
246     if (priv->minus)
247       {
248         gtk_widget_unparent(priv->minus);
249         priv->minus = NULL;
250       }
251     if (priv->num_entry)
252       {
253         gtk_widget_unparent(priv->num_entry);
254         priv->num_entry = NULL;
255       }
256     if (priv->plus)
257       {
258         gtk_widget_unparent(priv->plus);
259         priv->plus = NULL;
260       }
261
262     if (GTK_OBJECT_CLASS(parent_class)->destroy)
263         GTK_OBJECT_CLASS(parent_class)->destroy(self);
264 }
265
266 static void
267 hildon_number_editor_finalize (GObject *self)
268 {
269    HildonNumberEditorPrivate *priv;
270
271    priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(self);
272
273    /* Free timer */
274    if (priv->button_event_id)
275      g_source_remove (priv->button_event_id);
276
277     /* Call parent class finalize, if have one */
278     if (G_OBJECT_CLASS (parent_class)->finalize)
279         G_OBJECT_CLASS (parent_class)->finalize(self);
280 }
281
282 static void
283 hildon_number_editor_init (HildonNumberEditor *editor)
284 {
285     HildonNumberEditorPrivate *priv;
286
287     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
288     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(editor), GTK_NO_WINDOW);
289
290     priv->num_entry = gtk_entry_new();
291     priv->minus = gtk_button_new();
292     priv->plus = gtk_button_new();
293
294     gtk_widget_set_name( priv->minus, "minus-button" );
295     gtk_widget_set_name( priv->plus, "plus-button" );
296     gtk_widget_set_size_request( priv->minus, BUTTON_WIDTH, BUTTON_HEIGHT );
297     gtk_widget_set_size_request( priv->plus, BUTTON_WIDTH, BUTTON_HEIGHT );
298     gtk_entry_set_alignment (GTK_ENTRY(priv->num_entry), 1);
299     
300     GTK_WIDGET_UNSET_FLAGS( priv->minus, GTK_CAN_FOCUS );
301     GTK_WIDGET_UNSET_FLAGS( priv->plus, GTK_CAN_FOCUS );
302     
303     priv->button_event_id = -1;
304
305     gtk_widget_set_parent(priv->minus, GTK_WIDGET(editor));
306     gtk_widget_set_parent(priv->num_entry, GTK_WIDGET(editor));
307     gtk_widget_set_parent(priv->plus, GTK_WIDGET(editor));
308
309     g_signal_connect(GTK_OBJECT(priv->num_entry), "changed",
310                      G_CALLBACK(hildon_number_editor_entry_changed),
311                      editor);
312
313     g_signal_connect(GTK_OBJECT(priv->num_entry), "focus-out-event",
314                      G_CALLBACK(hildon_number_editor_entry_focusout),
315                      editor);
316
317     g_signal_connect(GTK_OBJECT(priv->num_entry), "key-press-event",
318                      G_CALLBACK(hildon_number_editor_entry_keypress),
319                      editor);
320
321     g_signal_connect(GTK_OBJECT(priv->num_entry), "button-release-event",
322                      G_CALLBACK(hildon_number_editor_entry_button_released),
323                      NULL);
324
325     g_signal_connect(GTK_OBJECT(priv->minus), "button-press-event",
326                      G_CALLBACK(hildon_number_editor_button_pressed),
327                      editor);
328
329     g_signal_connect(GTK_OBJECT(priv->plus), "button-press-event",
330                      G_CALLBACK(hildon_number_editor_button_pressed),
331                      editor);
332                      
333     g_signal_connect(GTK_OBJECT(priv->minus), "button-release-event",
334                      G_CALLBACK(hildon_number_editor_button_released),
335                      editor);
336
337     g_signal_connect(GTK_OBJECT(priv->plus), "button-release-event",
338                      G_CALLBACK(hildon_number_editor_button_released),
339                      editor);
340
341     g_signal_connect(GTK_OBJECT(priv->minus), "leave-notify-event",
342                      G_CALLBACK(hildon_number_editor_button_released),
343                      editor);
344
345     g_signal_connect(GTK_OBJECT(priv->plus), "leave-notify-event",
346                      G_CALLBACK(hildon_number_editor_button_released),
347                      editor);
348
349     g_object_set( G_OBJECT(priv->num_entry),
350                   "input-mode", HILDON_INPUT_MODE_HINT_NUMERIC, NULL );
351     
352     gtk_widget_show(priv->num_entry);
353     gtk_widget_show(priv->minus);
354     gtk_widget_show(priv->plus);
355
356     hildon_number_editor_set_range(editor, G_MININT, G_MAXINT);
357 }
358
359 static gboolean
360 hildon_number_editor_mnemonic_activate (GtkWidget *widget,
361                                         gboolean group_cycle)
362 {
363   HildonNumberEditorPrivate *priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(widget);
364   gtk_widget_grab_focus(priv->num_entry);
365   gtk_editable_select_region(GTK_EDITABLE(priv->num_entry), 0, -1);
366   return TRUE;
367 }
368
369 static gboolean
370 hildon_number_editor_entry_button_released (GtkWidget *widget,
371                                            GdkEventButton *event,
372                                            gpointer data)
373 {
374   gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
375   return FALSE;
376 }
377
378 static gboolean
379 hildon_number_editor_button_released (GtkWidget *widget, GdkEvent *event,
380                                       HildonNumberEditor *editor)
381 {
382     HildonNumberEditorPrivate *priv =
383         HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
384         
385     if (priv->button_event_id != -1)
386       {
387         g_source_remove(priv->button_event_id);
388         priv->button_event_id = -1;
389       }
390     return FALSE;
391 }
392
393 static gboolean
394 hildon_number_editor_button_pressed (GtkWidget *widget, GdkEventButton *event,
395                                      gpointer data)
396 {
397     /* Need to fetch current value from entry and increment or decrement
398        it */
399     HildonNumberEditor *editor;
400     HildonNumberEditorPrivate *priv;
401     GtkSettings *settings;
402     guint timeout;
403
404     editor = HILDON_NUMBER_EDITOR(data);
405     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
406     settings = gtk_settings_get_default();
407     g_object_get(settings, "gtk-initial-timeout", &timeout, NULL);
408
409     if (GTK_BUTTON(widget) == GTK_BUTTON(priv->plus))
410         priv->button_type = 1;
411     else
412         priv->button_type = -1;
413
414     if (priv->button_event_id == -1)
415       {
416         do_mouse_timeout(editor);
417         priv->button_event_id = g_timeout_add (timeout,
418                                 (GSourceFunc) hildon_number_editor_start_timer,
419                                 editor);
420       }
421
422     return FALSE;
423 }
424
425 static gboolean
426 hildon_number_editor_start_timer (HildonNumberEditor *editor)
427 {
428     HildonNumberEditorPrivate *priv;
429     GtkSettings *settings;
430     guint timeout;
431
432     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
433     settings = gtk_settings_get_default();
434     g_object_get(settings, "gtk-update-timeout", &timeout, NULL);
435
436     priv->button_event_id = g_timeout_add(timeout,
437                                           (GSourceFunc) do_mouse_timeout,
438                                           editor);
439     return FALSE;
440 }
441
442 static gboolean
443 do_mouse_timeout (HildonNumberEditor *editor)
444 {
445     HildonNumberEditorPrivate *priv;
446     gboolean success;
447
448     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
449     success = TRUE;
450
451     if (priv->button_type == 1)
452       {
453         if (change_numbers(editor, 1, -1) == FALSE)
454             success = FALSE;
455
456       }
457     else if (change_numbers(editor, 2, -1) == FALSE)
458         success = FALSE;
459
460     if (!success)
461       {
462         gtk_editable_select_region(GTK_EDITABLE(priv->num_entry), 0, -1);
463         return FALSE;
464       }
465     else
466         return TRUE;
467 }
468
469 static gboolean
470 change_numbers (HildonNumberEditor *editor, gint type, gint cursor_pos)
471 {
472     gboolean r;
473     gint nvalue;
474     gchar *snvalue;
475     HildonNumberEditorPrivate *priv =
476         HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
477     nvalue = atoi(GTK_ENTRY(priv->num_entry)->text);
478
479     if (type == 1)
480       {
481         if (nvalue < priv->end)
482             nvalue += 1;
483         else
484           {
485             g_signal_emit(editor, HildonNumberEditor_signal[RANGE_ERROR], 
486                           0, MAXIMUM_VALUE_EXCEED, &r);
487             return FALSE;
488           }
489       }
490     else
491       {
492         if (nvalue > priv->start)
493             nvalue -= 1;
494
495         else
496           {
497             g_signal_emit(editor, HildonNumberEditor_signal[RANGE_ERROR], 
498                           0, MINIMUM_VALUE_EXCEED, &r);
499             return FALSE;
500           }
501       }
502
503     /* write value to num_entry */
504     snvalue = integer_to_string(nvalue);
505     gtk_entry_set_text(GTK_ENTRY(priv->num_entry), snvalue);
506
507     if (cursor_pos != -1)
508         gtk_editable_set_position(GTK_EDITABLE(priv->num_entry),
509                                   cursor_pos);
510
511     if (snvalue)
512         g_free(snvalue);
513
514     return TRUE;
515 }
516
517 static gchar *
518 integer_to_string (gint nvalue)
519 {
520     return g_strdup_printf("%d", nvalue);
521 }
522
523 static void
524 hildon_number_editor_entry_changed (GtkWidget *widget, gpointer data)
525 {
526   HildonNumberEditor *editor;
527   HildonNumberEditorPrivate *priv;
528   gchar *tmpstr;
529   gint value;
530   gchar *tail = NULL;
531   gboolean r;
532
533   editor = HILDON_NUMBER_EDITOR(data);
534   priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
535
536   tmpstr = GTK_ENTRY(priv->num_entry)->text;
537
538   if (strlen(tmpstr) > 0)
539     {
540       tmpstr = NULL;
541       value = strtol(GTK_ENTRY(priv->num_entry)->text, &tail, 10);
542       if (!strncmp(tail, "\0", 1) || !strncmp(tail, "-", 1))
543         {    
544           if (atoi(GTK_ENTRY(priv->num_entry)->text) > priv->end)
545             {
546               g_signal_emit(editor,HildonNumberEditor_signal[RANGE_ERROR], 
547                             0, MAXIMUM_VALUE_EXCEED, &r);
548               tmpstr = integer_to_string(priv->end);
549               gtk_entry_set_text(GTK_ENTRY(priv->num_entry), tmpstr);
550               if (tmpstr)
551                 g_free(tmpstr);
552             }
553           else if (atoi(GTK_ENTRY(priv->num_entry)->text) < priv->start) {
554             g_signal_emit(editor, HildonNumberEditor_signal[RANGE_ERROR], 
555                           0, MINIMUM_VALUE_EXCEED, &r);
556             tmpstr = integer_to_string(priv->start);
557             gtk_entry_set_text(GTK_ENTRY(priv->num_entry), tmpstr);
558             if (tmpstr)
559               g_free(tmpstr);
560           }
561         }
562       else
563         {
564           g_signal_emit(editor, HildonNumberEditor_signal[RANGE_ERROR], 
565                         0, ERRONEOUS_VALUE, &r);
566           tmpstr = integer_to_string(priv->start);
567           gtk_entry_set_text(GTK_ENTRY(priv->num_entry), tmpstr);
568           if (tmpstr)
569             g_free(tmpstr);
570         }
571     }
572 }
573
574 static void
575 hildon_number_editor_size_request (GtkWidget *widget,
576                                   GtkRequisition *requisition)
577 {
578     HildonNumberEditor *editor;
579     HildonNumberEditorPrivate *priv;
580     GtkRequisition req;
581
582     editor = HILDON_NUMBER_EDITOR(widget);
583     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
584
585     gtk_widget_size_request(priv->minus, &req);
586     requisition->width = req.width;
587
588     gtk_widget_size_request(priv->num_entry, &req);
589     requisition->width += req.width;
590
591     gtk_widget_size_request(priv->plus, &req);
592     requisition->width += req.width;
593
594     requisition->width += SPACE_BORDER * 2;
595     requisition->height = NUMBER_EDITOR_HEIGHT;
596 }
597
598 static void
599 set_widget_allocation (GtkWidget *widget, GtkAllocation *alloc,
600                       GtkAllocation *allocation)
601 {
602     GtkRequisition child_requisition;
603
604     gtk_widget_get_child_requisition(widget, &child_requisition);
605
606     if (allocation->width + allocation->x >
607         alloc->x + child_requisition.width)
608         alloc->width = child_requisition.width;
609     else
610       {
611         alloc->width = allocation->width - (alloc->x - allocation->x);
612         if (alloc->width < 0)
613             alloc->width = 0;
614       }
615
616     gtk_widget_size_allocate(widget, alloc);
617     alloc->x += alloc->width;
618 }
619
620 static void
621 hildon_number_editor_size_allocate (GtkWidget *widget,
622                                     GtkAllocation *allocation)
623 {
624   HildonNumberEditor *editor;
625   HildonNumberEditorPrivate *priv;
626   GtkAllocation alloc;
627
628   editor = HILDON_NUMBER_EDITOR(widget);
629   priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
630
631   widget->allocation = *allocation;
632
633 /*Init start values*/
634   alloc.y = widget->allocation.y + widget->style->ythickness;
635
636   if (widget->allocation.height > NUMBER_EDITOR_HEIGHT)
637     {
638       alloc.height = NUMBER_EDITOR_HEIGHT - widget->style->ythickness * 2;
639       alloc.y += (widget->allocation.height - NUMBER_EDITOR_HEIGHT) / 2;
640     }
641   else
642       alloc.height = widget->allocation.height - widget->style->ythickness * 2;
643
644
645   
646   if (alloc.height < 0)
647     alloc.height = 0;
648
649   alloc.x = allocation->x + widget->style->xthickness;
650
651   set_widget_allocation(priv->minus, &alloc, &widget->allocation);
652   alloc.x += SPACE_BORDER;
653
654   set_widget_allocation(priv->num_entry, &alloc, &widget->allocation);
655   alloc.x += SPACE_BORDER;
656
657   set_widget_allocation(priv->plus, &alloc, &widget->allocation);
658 }
659
660 static gboolean
661 hildon_number_editor_entry_focusout (GtkWidget *widget, GdkEventFocus *event,
662                                      gpointer data)
663 {
664     HildonNumberEditor *editor;
665     HildonNumberEditorPrivate *priv;
666     gchar *str;
667     gboolean r;
668
669     editor = HILDON_NUMBER_EDITOR(data);
670     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
671     
672     /* empty entry, must infoprint error message */
673     if (!strlen(GTK_ENTRY(priv->num_entry)->text))
674       {
675         g_signal_emit(editor, HildonNumberEditor_signal[RANGE_ERROR], 
676                       0, ERRONEOUS_VALUE, &r);
677         /* Changing to default value */
678         str = integer_to_string(priv->default_val);
679         gtk_entry_set_text(GTK_ENTRY(priv->num_entry), str);
680         gtk_editable_select_region(GTK_EDITABLE(priv->num_entry), 0, -1);
681         if (str)
682             g_free(str);
683       }
684     return FALSE;
685 }
686
687 static gboolean
688 hildon_number_editor_entry_keypress (GtkWidget *widget, GdkEventKey *event,
689                                      gpointer data)
690 {
691     HildonNumberEditorPrivate *priv;
692     gint tmp_pos;
693     gchar *scnd_chr;
694     gboolean ret_val = FALSE;
695
696     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(data);
697     tmp_pos = gtk_editable_get_position( GTK_EDITABLE(priv->num_entry) );
698     
699     if( (event->keyval == GDK_Left) || (event->keyval == GDK_Right) )
700     {
701       if( ((event->keyval == GDK_Left) && tmp_pos == 0 ) ||
702            (event->keyval == GDK_Left && gtk_editable_get_selection_bounds 
703                                                 (GTK_EDITABLE (priv->num_entry),
704                                                  0, NULL)) )
705       {
706         if (change_numbers(HILDON_NUMBER_EDITOR(data), 2, -1) == FALSE)
707         { 
708           gtk_editable_select_region(GTK_EDITABLE(priv->num_entry), 0, -1);
709           return TRUE;
710         }
711       }
712       else if ( (event->keyval == GDK_Right) )
713       {
714         gchar *str = gtk_editable_get_chars( GTK_EDITABLE(priv->num_entry),
715                                              0, -1 );
716         if( strlen(str) == tmp_pos )
717         {
718           if (change_numbers(HILDON_NUMBER_EDITOR(data), 1, tmp_pos) == FALSE)
719           { 
720             gtk_editable_select_region(GTK_EDITABLE(priv->num_entry), 0, -1);
721             g_free (str);
722             return TRUE;
723           }
724         }
725        g_free (str);
726       }
727       return FALSE;
728     }
729    
730     scnd_chr = gtk_editable_get_chars( GTK_EDITABLE(priv->num_entry),
731                                               0, 1 );
732     if (event->keyval == GDK_minus || event->keyval == GDK_KP_Subtract)
733     {
734       if (tmp_pos > 0)
735            ret_val = TRUE;
736       if (!strncmp (scnd_chr, "-", 1))
737            ret_val = TRUE;
738     }
739     else if ((event->keyval == GDK_Up) || (event->keyval == GDK_Down)
740         || (event->keyval == GDK_KP_Up) || (event->keyval == GDK_KP_Down))
741         ret_val = FALSE;
742     else if (((event->keyval >= GDK_0) && (event->keyval <= GDK_9)) ||
743              ((event->keyval >= GDK_KP_0) && (event->keyval <= GDK_KP_9))
744              || (event->keyval == GDK_BackSpace)
745              || (event->keyval == GDK_Delete)
746              || (event->keyval == GDK_Return)
747              || (((event->keyval == GDK_minus)
748              || (event->keyval == GDK_KP_Subtract))))
749         ret_val = FALSE;
750     else
751       ret_val = TRUE;
752
753    g_free (scnd_chr);
754    return ret_val;
755 }
756
757 static gboolean
758 hildon_number_editor_error_handler(HildonNumberEditor *editor,
759                                    HildonNumberEditorErrorType type)
760 {
761
762   gint min, max;
763   gchar *err_msg = NULL;
764   HildonNumberEditorPrivate *priv;
765
766   priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
767   min = priv->start;
768   max = priv->end;
769
770   /* Construct different error message */
771   switch (type)
772     {
773     case MAXIMUM_VALUE_EXCEED:
774       err_msg = g_strdup_printf(_("Ckct_ib_maximum_value"), max, max);
775       break;
776     case MINIMUM_VALUE_EXCEED:
777       err_msg = g_strdup_printf(_("Ckct_ib_minimum_value"), min, min);
778       break;
779     case ERRONEOUS_VALUE:
780       err_msg =
781         g_strdup_printf(_("Ckct_ib_set_a_value_within_range"), min, max);
782       break;
783     }
784
785   if (err_msg)
786     {
787       gtk_infoprint(GTK_WINDOW(gtk_widget_get_ancestor(GTK_WIDGET(editor),
788                                                        GTK_TYPE_WINDOW)), err_msg);
789       g_free(err_msg);
790     }
791
792   return TRUE;
793 }
794
795
796 /**
797  * hildon_number_editor_new:
798  * @min: Minimum accepted value
799  * @max: Maximum accepted value
800  * 
801  * This function creates new number editor
802  *
803  * Return value: a new #HildonNumberEditor widget.
804  */
805 GtkWidget *
806 hildon_number_editor_new (gint min, gint max)
807 {
808     HildonNumberEditor *editor =
809         g_object_new(HILDON_TYPE_NUMBER_EDITOR, NULL);
810
811     /* Set user inputted range to editor */
812     hildon_number_editor_set_range(editor, min, max);
813
814     return GTK_WIDGET(editor);
815 }
816
817 /**
818  * hildon_number_editor_set_range:
819  * @editor: a #HildonNumberEditor widget
820  * @min: Minimum accepted value
821  * @max: Maximum accepted value
822  *
823  * This function set accepted number range for editor
824  */
825 void
826 hildon_number_editor_set_range (HildonNumberEditor *editor, gint min, gint max)
827 {
828     HildonNumberEditorPrivate *priv;
829     gchar *str, *str2;
830     gint a, b, entry_len;
831
832     g_return_if_fail(HILDON_IS_NUMBER_EDITOR(editor));
833
834     if (min > max)
835       {
836         gint temp = min;
837
838         min = max;
839         max = temp;
840       }
841
842     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
843
844     /* we need to store user inputted values */
845     priv->start = min;
846     priv->end = max;
847     priv->default_val = min;
848
849     priv->negative = min < 0 ? TRUE : FALSE;
850
851     str = integer_to_string(max);
852     str2 = integer_to_string(min);
853     a = strlen(str);
854     b = strlen(str2);
855
856     if (a >= b)
857         entry_len = a;
858     else
859         entry_len = b;
860     
861
862     gtk_entry_set_width_chars(GTK_ENTRY(priv->num_entry), entry_len);
863
864     gtk_entry_set_text(GTK_ENTRY(priv->num_entry), str);
865     gtk_widget_queue_resize(GTK_WIDGET(editor));
866
867     if (str)
868         g_free(str);
869     if (str2)
870         g_free(str2);
871 }
872
873 /**
874  * hildon_number_editor_get_value:
875  * @editor: pointer to #HildonNumberEditor
876  *
877  * This function returns current value of number editor
878  *
879  * Return value: Current NumberEditor value
880  */
881 gint
882 hildon_number_editor_get_value (HildonNumberEditor *editor)
883 {
884     HildonNumberEditorPrivate *priv;
885     gint value;
886
887     g_return_val_if_fail(HILDON_IS_NUMBER_EDITOR(editor), 0);
888
889     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
890
891     value = atoi(GTK_ENTRY(priv->num_entry)->text);
892
893     return value;
894 }
895
896 /**
897  * hildon_number_editor_set_value:
898  * @editor: pointer to #HildonNumberEditor
899  * @value: numeric value for number editor
900  *
901  * This function sets numeric value to number editor
902  */
903 void
904 hildon_number_editor_set_value (HildonNumberEditor *editor, gint value)
905 {
906     HildonNumberEditorPrivate *priv;
907     gchar *str;
908
909     g_return_if_fail(HILDON_IS_NUMBER_EDITOR(editor));
910
911     priv = HILDON_NUMBER_EDITOR_GET_PRIVATE(editor);
912
913     g_return_if_fail(value <= priv->end);
914     g_return_if_fail(value >= priv->start);
915
916     priv->default_val = value;
917         
918     str = integer_to_string(value);
919     gtk_entry_set_text(GTK_ENTRY(priv->num_entry), str);
920     if (str)
921         g_free(str);
922 }