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