import SDK release
[hildon] / hildon-widgets / hildon-time-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 /* HILDON DOC
26  * @shortdesc: TimeEditor is a widget for setting, getting and showing a
27  * time.
28  * @longdesc: The Time Editor widget is used to enter the system time
29  * (hours and minutes) in the Date/Time system plugin. It is a composite
30  * widget consisting of two GtkEntry widgets that are placed next to each
31  * other. The leftmost GtkEntry is used to enter the hours, and it accepts
32  * the values 0--23, while the rightmost GtkEntry accepts values 0--59
33  * and is used to set the minutes. Between the two GtkEntries there
34  * is a label displaying a colon.
35  * </para><para>
36  * From the usability point of view, the GtkSpinbutton widget would
37  * have been a better choice than the GtkEntry widgets, but it uses
38  * floating point operations and is thus not acceptable in this
39  * project.
40  *
41  * @seealso: #HildonDateEditor
42  */
43
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 #include <pango/pango.h>
49 #include <gtk/gtkbox.h>
50 #include <gtk/gtkentry.h>
51 #include <gtk/gtk.h>
52 #include <gdk/gdkkeysyms.h>
53 #include <gtk/gtkwidget.h>
54
55 #include <string.h>
56 #include <time.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <ctype.h>
60 #include <langinfo.h>
61 #include <libintl.h>
62
63 #include <hildon-widgets/hildon-defines.h>
64 #include <hildon-widgets/hildon-time-editor.h>
65 #include <hildon-widgets/hildon-time-picker.h>
66 #include <hildon-widgets/gtk-infoprint.h>
67 #include "hildon-composite-widget.h"
68
69 #define _(String) dgettext(PACKAGE, String)
70
71 /* empty space on left and right side of a GtkEntry. Space needed
72 is 12, we add 4 extra pixels so that the arabic locale works
73 correctly. (With 12 only one digit would be shown in the entries).
74 */
75 #define TIME_EDITOR_LBORDER         6
76 #define TIME_EDITOR_RBORDER         6
77 #define TIME_EDITOR_HEIGHT         30
78 #define TIME_EDITOR_CLOCK_BORDER    6
79 #define ICON_WIDTH                 26
80 #define ICON_HEIGHT                26
81 #define ICON_NAME                  "qgn_widg_timedit"
82 #define ICON_SIZE                  "timepicker-size"
83 #define HILDON_TIME_EDITOR_GET_PRIVATE(obj) \
84     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
85      HILDON_TYPE_TIME_EDITOR, HildonTimeEditorPrivate));
86 #define MIN_DURATION 0
87 #define MAX_DURATION (3600 * 99) + (60 * 59) + 59
88
89 static GtkContainerClass *parent_class;
90
91 typedef struct _HildonTimeEditorPrivate HildonTimeEditorPrivate;
92
93 static void
94 hildon_time_editor_class_init(HildonTimeEditorClass * editor_class);
95
96 static void hildon_time_editor_init(HildonTimeEditor * editor);
97
98 static void hildon_time_editor_finalize(GObject * obj_self);
99
100 static gboolean
101 hildon_time_editor_entry_focusout(GtkWidget * widget,
102                                   GdkEventFocus * event, gpointer data);
103 static void hildon_time_editor_entry_activate(GtkWidget * widget,
104                                               gpointer data);
105
106 static void
107 hildon_time_editor_entry_activate(GtkWidget * widget, gpointer data);
108
109 static gboolean
110 hildon_time_editor_mnemonic_activate(GtkWidget * widget,
111                                      gboolean group_cycling);
112
113 static gboolean
114 hildon_time_editor_ampm_clicked(GtkWidget * widget, GdkEventButton * event,
115                                 gpointer data);
116 static gboolean
117 hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data);
118
119 static gboolean
120 hildon_time_editor_entry_clicked(GtkWidget * widget,
121                                  GdkEventButton * event, gpointer data);
122
123 static void
124 hildon_time_editor_size_request(GtkWidget * widget,
125                                 GtkRequisition * requisition);
126
127 static void
128 hildon_time_editor_size_allocate(GtkWidget * widget,
129                                  GtkAllocation * allocation);
130 static void
131 hildon_time_editor_forall(GtkContainer * container,
132                           gboolean include_internals, GtkCallback callback,
133                           gpointer callback_data);
134 static void hildon_time_editor_destroy(GtkObject * self);
135
136 static gboolean
137 hildon_time_editor_entry_keypress(GtkWidget * widget, GdkEventKey * event,
138                                   gpointer data);
139 static void hildon_time_editor_add_style(void);
140
141 static void
142 set_widget_allocation(GtkWidget * widget, GtkAllocation * alloc,
143                       GtkAllocation * allocation);
144 static guint
145 hildon_time_editor_check_duration_validity(HildonTimeEditor * editor);
146
147 static void
148 hildon_time_editor_duration_handle_error(HildonTimeEditor * editor,
149                                          guint type);
150
151 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor);
152
153 static
154 void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
155                                            GtkWidget * menu,
156                                            GtkCallback func,
157                                            GtkWidgetTapAndHoldFlags flags);
158
159 enum {
160     DURATION_MIN_EXCEED,
161     DURATION_MAX_EXCEED,
162     DURATION_OK
163 };
164
165 struct _HildonTimeEditorPrivate {
166     gchar h_time[4];    /* These hold current */
167     gchar m_time[4];    /* time */
168     gchar s_time[4];
169     gchar *am_symbol;
170     gchar *pm_symbol;
171
172     GtkWidget *eventbox;        /* hold entries */
173     GtkWidget *iconbutton;      /* button for icon */
174
175     GtkWidget *h_entry;
176     GtkWidget *m_entry;
177     GtkWidget *s_entry;
178     GtkWidget *label;   /* between h and m */
179     GtkWidget *label2;  /* between m and s */
180     GtkWidget *ampm;    /* label for showing am or pm */
181     GtkWidget *icon;    /* label for showing am or pm */
182     GtkWidget *frame;   /* frame around the entries */
183
184     gboolean duration_mode;     /* In HildonDurationEditor mode */
185     gboolean show_s;    /* show seconds */
186     gboolean ampm_pos_after;    /* is the am/pm shown after others */
187     gboolean clock_24h; /* whether to show a 24h clock */
188     gboolean am;        /* TRUE == showing am, FALSE == pm */
189     gboolean valid_value; /* If entry has an valid value */
190
191     /* Duration editor ranges */
192     guint duration_min;
193     guint duration_max;
194 };
195
196 GType hildon_time_editor_get_type(void)
197 {
198     static GType editor_type = 0;
199
200     if (!editor_type) {
201         static const GTypeInfo editor_info = {
202             sizeof(HildonTimeEditorClass),
203             NULL,       /* base_init */
204             NULL,       /* base_finalize */
205             (GClassInitFunc) hildon_time_editor_class_init,
206             NULL,       /* class_finalize */
207             NULL,       /* class_data */
208             sizeof(HildonTimeEditor),
209             0,  /* n_preallocs */
210             (GInstanceInitFunc) hildon_time_editor_init,
211         };
212         editor_type = g_type_register_static(GTK_TYPE_CONTAINER,
213                                              "HildonTimeEditor",
214                                              &editor_info, 0);
215     }
216     return editor_type;
217 }
218
219 static void hildon_time_editor_forall(GtkContainer * container,
220                                       gboolean include_internals,
221                                       GtkCallback callback,
222                                       gpointer callback_data)
223 {
224     HildonTimeEditor *editor;
225     HildonTimeEditorPrivate *priv;
226
227     editor = HILDON_TIME_EDITOR(container);
228     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
229
230     g_return_if_fail(container);
231     g_return_if_fail(callback);
232
233     if (!include_internals)
234         return;
235
236
237     /* widget that are always shown */
238     (*callback) (priv->h_entry, callback_data);
239     (*callback) (priv->m_entry, callback_data);
240     (*callback) (priv->label, callback_data);
241     (*callback) (priv->iconbutton, callback_data);
242     (*callback) (priv->frame, callback_data);
243     (*callback) (priv->label2, callback_data);
244     (*callback) (priv->s_entry, callback_data);
245     (*callback) (priv->eventbox, callback_data);
246 }
247
248 static void hildon_time_editor_destroy(GtkObject * self)
249 {
250     HildonTimeEditorPrivate *priv;
251
252     priv = HILDON_TIME_EDITOR_GET_PRIVATE(self);
253
254     if (priv->h_entry) {
255         gtk_widget_unparent(priv->h_entry);
256         priv->h_entry = NULL;
257     }
258     if (priv->m_entry) {
259         gtk_widget_unparent(priv->m_entry);
260         priv->m_entry = NULL;
261     }
262     if (priv->label) {
263         gtk_widget_unparent(priv->label);
264         priv->label = NULL;
265     }
266     if (priv->iconbutton) {
267         gtk_widget_unparent(priv->iconbutton);
268         priv->iconbutton = NULL;
269     }
270     if (priv->frame) {
271         gtk_widget_unparent(priv->frame);
272         priv->frame = NULL;
273     }
274     if (priv->eventbox) {
275         gtk_widget_unparent(priv->eventbox);
276         priv->eventbox = NULL;
277         priv->ampm = NULL;
278     }
279     if (priv->label2) {
280         gtk_widget_unparent(priv->label2);
281         priv->label2 = NULL;
282     }
283     if (priv->s_entry) {
284         gtk_widget_unparent(priv->s_entry);
285         priv->s_entry = NULL;
286     }
287
288     if (GTK_OBJECT_CLASS(parent_class)->destroy)
289         GTK_OBJECT_CLASS(parent_class)->destroy(self);
290
291 }
292
293 static void
294 hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
295 {
296     GObjectClass *object_class = G_OBJECT_CLASS(editor_class);
297     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(editor_class);
298     GtkContainerClass *container_class = GTK_CONTAINER_CLASS(editor_class);
299
300     parent_class = g_type_class_peek_parent(editor_class);
301
302     g_type_class_add_private(editor_class,
303                              sizeof(HildonTimeEditorPrivate));
304
305     widget_class->mnemonic_activate = hildon_time_editor_mnemonic_activate;
306     widget_class->size_request = hildon_time_editor_size_request;
307     widget_class->size_allocate = hildon_time_editor_size_allocate;
308     widget_class->tap_and_hold_setup =
309         hildon_time_editor_tap_and_hold_setup;
310     widget_class->focus = hildon_composite_widget_focus;
311
312     container_class->forall = hildon_time_editor_forall;
313     GTK_OBJECT_CLASS(editor_class)->destroy = hildon_time_editor_destroy;
314
315     object_class->finalize = hildon_time_editor_finalize;
316 }
317
318 static
319 void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
320                                            GtkWidget * menu,
321                                            GtkCallback func,
322                                            GtkWidgetTapAndHoldFlags flags)
323 {
324     HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
325
326     gtk_widget_tap_and_hold_setup(priv->h_entry, menu, func,
327                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
328     gtk_widget_tap_and_hold_setup(priv->m_entry, menu, func,
329                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
330     gtk_widget_tap_and_hold_setup(priv->s_entry, menu, func,
331                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
332     gtk_widget_tap_and_hold_setup(priv->eventbox, menu, func,
333                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
334     gtk_widget_tap_and_hold_setup(priv->iconbutton, menu, func,
335                                   GTK_TAP_AND_HOLD_NONE);
336 }
337
338 static void hildon_time_editor_init(HildonTimeEditor * editor)
339 {
340     HildonTimeEditorPrivate *priv;
341     gchar hours[3] = "01";
342     gchar minutes[3] = "00";
343     gchar seconds[3] = "00";
344
345     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
346
347     gtk_widget_push_composite_child();
348     
349     priv->show_s = FALSE;
350     priv->ampm_pos_after = TRUE;
351     priv->clock_24h = TRUE;
352     priv->duration_mode = FALSE;
353     priv->iconbutton = gtk_button_new();
354     priv->h_entry = gtk_entry_new();
355     priv->m_entry = gtk_entry_new();
356     priv->s_entry = gtk_entry_new();
357     priv->ampm = gtk_label_new(NULL);
358     priv->label = gtk_label_new(":");
359     priv->label2 = gtk_label_new(":");
360     priv->icon = gtk_image_new_from_icon_name(ICON_NAME, HILDON_ICON_SIZE_26);
361     priv->frame = gtk_frame_new(NULL);
362     priv->eventbox = gtk_event_box_new();
363     priv->valid_value = TRUE;
364     
365     GTK_WIDGET_SET_FLAGS(editor, GTK_NO_WINDOW);
366     GTK_WIDGET_UNSET_FLAGS(priv->iconbutton, GTK_CAN_FOCUS);
367     
368     gtk_event_box_set_visible_window(GTK_EVENT_BOX(priv->eventbox), FALSE);
369
370     gtk_container_add(GTK_CONTAINER(priv->iconbutton), priv->icon);
371     gtk_container_add(GTK_CONTAINER(priv->eventbox), priv->ampm);
372
373     gtk_entry_set_has_frame(GTK_ENTRY(priv->h_entry), FALSE);
374     gtk_entry_set_has_frame(GTK_ENTRY(priv->m_entry), FALSE);
375     gtk_entry_set_has_frame(GTK_ENTRY(priv->s_entry), FALSE);
376
377     /* connect the activate signal to a function. */
378     g_signal_connect(G_OBJECT(priv->h_entry), "activate",
379                      G_CALLBACK(hildon_time_editor_entry_activate),
380                      editor);
381     g_signal_connect(G_OBJECT(priv->m_entry), "activate",
382                      G_CALLBACK(hildon_time_editor_entry_activate),
383                      editor);
384     g_signal_connect(G_OBJECT(priv->s_entry), "activate",
385                      G_CALLBACK(hildon_time_editor_entry_activate),
386                      editor);
387
388     /* clicked signal for am/pm label */
389     g_signal_connect(G_OBJECT(priv->eventbox), "button_press_event",
390                      G_CALLBACK(hildon_time_editor_ampm_clicked), editor);
391
392     /* clicked signal for icon */
393     g_signal_connect(G_OBJECT(priv->iconbutton), "clicked",
394                      G_CALLBACK(hildon_time_editor_icon_clicked), editor);
395
396     /* clicked signal for hour entry */
397     g_signal_connect(G_OBJECT(priv->h_entry), "button_release_event",
398                      G_CALLBACK(hildon_time_editor_entry_clicked), editor);
399
400     /* clicked signal for minute entry */
401     g_signal_connect(G_OBJECT(priv->m_entry), "button_release_event",
402                      G_CALLBACK(hildon_time_editor_entry_clicked), editor);
403
404     /* clicked signal for second entry */
405     g_signal_connect(G_OBJECT(priv->s_entry), "button_release_event",
406                      G_CALLBACK(hildon_time_editor_entry_clicked), editor);
407
408     /* focus out events */
409     g_signal_connect(G_OBJECT(priv->h_entry), "focus-out-event",
410                      G_CALLBACK(hildon_time_editor_entry_focusout),
411                      editor);
412     g_signal_connect(G_OBJECT(priv->m_entry), "focus-out-event",
413                      G_CALLBACK(hildon_time_editor_entry_focusout),
414                      editor);
415     g_signal_connect(G_OBJECT(priv->s_entry), "focus-out-event",
416                      G_CALLBACK(hildon_time_editor_entry_focusout),
417                      editor);
418
419     /* key press events */
420     g_signal_connect(G_OBJECT(priv->h_entry), "key-press-event",
421                      G_CALLBACK(hildon_time_editor_entry_keypress),
422                      editor);
423     g_signal_connect(G_OBJECT(priv->m_entry), "key-press-event",
424                      G_CALLBACK(hildon_time_editor_entry_keypress),
425                      editor);
426     g_signal_connect(G_OBJECT(priv->s_entry), "key-press-event",
427                      G_CALLBACK(hildon_time_editor_entry_keypress),
428                      editor);
429
430     gtk_widget_set_parent(priv->iconbutton, GTK_WIDGET(editor));
431     gtk_widget_set_parent(priv->label, GTK_WIDGET(editor));
432
433     gtk_widget_set_parent(priv->label2, GTK_WIDGET(editor));
434     gtk_widget_set_parent(priv->s_entry, GTK_WIDGET(editor));
435     gtk_widget_set_parent(priv->eventbox, GTK_WIDGET(editor));
436     gtk_widget_set_parent(priv->m_entry, GTK_WIDGET(editor));
437     gtk_widget_set_parent(priv->h_entry, GTK_WIDGET(editor));
438
439     gtk_widget_show(priv->h_entry);
440     gtk_widget_show(priv->m_entry);
441     gtk_widget_show_all(priv->iconbutton);
442     gtk_widget_show(priv->label);
443
444     gtk_widget_set_parent(priv->frame, GTK_WIDGET(editor));
445     gtk_widget_show_all(priv->frame);
446
447     /* Check if we are in am/pm time locale */
448     if (!hildon_time_editor_check_locale(editor)) {
449         priv->clock_24h = FALSE;
450         gtk_widget_show_all(priv->eventbox);
451     }
452
453     {   /* get current time */
454         time_t tm;
455         struct tm *stm;
456
457         tm = time(NULL);
458         stm = localtime(&tm);
459
460         if (stm) {
461             if (!priv->clock_24h) {
462                 /* Clock is showed in 24h format If hour is 12 we can be
463                    either in am or pm mode */
464                 if (stm->tm_hour > 12) {
465                     priv->am = FALSE;
466                     sprintf(hours, "%2d", stm->tm_hour - 12);
467                 } else if (stm->tm_hour < 12) {
468                     priv->am = TRUE;
469                     sprintf(hours, "%2d", stm->tm_hour);
470                 } else if (stm->tm_hour == 12) {
471                     priv->am = FALSE;
472                     sprintf(hours, "%2d", stm->tm_hour);
473                 }
474             } else
475                 sprintf(hours, "%02d", stm->tm_hour);
476             sprintf(minutes, "%02d", stm->tm_min);
477             sprintf(seconds, "%02d", stm->tm_sec);
478         }
479     }
480
481     /* set current time (am/pm) */
482     gtk_label_set_label(GTK_LABEL(priv->ampm), priv->am ? priv->am_symbol :
483                         priv->pm_symbol);
484
485     /* Read time values to our internal struct */
486     g_snprintf(priv->h_time, 4, "%s", hours);
487     g_snprintf(priv->m_time, 4, "%s", minutes);
488     g_snprintf(priv->s_time, 4, "%s", seconds);
489
490     gtk_entry_set_text(GTK_ENTRY(priv->h_entry), hours);
491     gtk_entry_set_text(GTK_ENTRY(priv->m_entry), minutes);
492     gtk_entry_set_text(GTK_ENTRY(priv->s_entry), seconds);
493
494     gtk_entry_set_max_length(GTK_ENTRY(priv->h_entry), 2);
495     gtk_entry_set_width_chars(GTK_ENTRY(priv->h_entry), 2);
496     gtk_entry_set_max_length(GTK_ENTRY(priv->m_entry), 2);
497     gtk_entry_set_width_chars(GTK_ENTRY(priv->m_entry), 2);
498     gtk_entry_set_max_length(GTK_ENTRY(priv->s_entry), 2);
499     gtk_entry_set_width_chars(GTK_ENTRY(priv->s_entry), 2);
500
501     hildon_time_editor_add_style();
502     gtk_widget_set_name(GTK_WIDGET(priv->iconbutton),
503                         "hildon-time-editor-icon");
504     
505     gtk_widget_pop_composite_child();
506 }
507
508 static gboolean
509 hildon_time_editor_mnemonic_activate( GtkWidget *widget,
510                                       gboolean group_cycling)
511 {
512   HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
513   gtk_widget_grab_focus( priv->h_entry );
514   gtk_editable_select_region(GTK_EDITABLE(priv->h_entry), 0, 2);
515   return TRUE;
516 }
517
518 /**
519  * hildon_time_editor_new:
520  *
521  * This function creates a new time editor. 
522  *
523  * Return value: pointer to a new #HildonTimeEditor widget.
524  **/
525
526 GtkWidget *hildon_time_editor_new(void)
527 {
528     return GTK_WIDGET(g_object_new(HILDON_TYPE_TIME_EDITOR, NULL));
529 }
530
531 static void hildon_time_editor_finalize(GObject * obj_self)
532 {
533     HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(obj_self);
534
535     if (priv->am_symbol)
536         g_free(priv->am_symbol);
537     if (priv->pm_symbol)
538         g_free(priv->pm_symbol);
539
540     if (G_OBJECT_CLASS(parent_class)->finalize)
541         G_OBJECT_CLASS(parent_class)->finalize(obj_self);
542 }
543
544 static void hildon_time_editor_add_style(void)
545 {
546     gtk_rc_parse_string("  style \"hildon-time-editor-icon\" {"
547                         "    GtkButton::default_border = { 0, 0, 0, 0 }"
548                         "    xthickness = 0"
549                         "    ythickness = 0"
550                         "    engine \"pixmap\" {"
551                         "      image {"
552                         "        function = BOX"
553                         "      }"
554                         "    }"
555                         "  }"
556                         "  widget \"*.hildon-time-editor-icon\""
557                         "    style \"hildon-time-editor-icon\"");
558 }
559
560 /**
561  * hildon_time_editor_set_time:
562  * @editor: the @HildonTimeEditor widget.
563  * @hours: hours
564  * @minutes: minutes
565  * @seconds: seconds
566  *
567  * This function sets the time on an existing time editor. If the
568  * time specified by the arguments is invalid, the function returns
569  * without doing anything else. 
570  **/
571
572 void hildon_time_editor_set_time(HildonTimeEditor * editor, guint hours,
573                                  guint minutes, guint seconds)
574 {
575     HildonTimeEditorPrivate *priv;
576     gchar h_time[3];
577     gchar m_time[3];
578     gchar s_time[3];
579
580     g_return_if_fail(time);
581     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
582
583     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
584
585     if ((priv->duration_mode && hours > 99) ||
586         (!priv->duration_mode && hours > 23) ||
587          minutes > 59 || seconds > 59)
588         return;
589
590     if (priv->clock_24h || priv->duration_mode)
591         sprintf(h_time, "%02u", hours);
592     else {
593         /* we are showing 12h clock and its after noon */
594         if (hours > 12) {
595             hours -= 12;
596             priv->am = FALSE;
597             gtk_label_set_text(GTK_LABEL(priv->ampm), priv->pm_symbol);
598         }
599         /* before noon */
600         else if (hours < 12) {
601             if (hours == 0)
602                 hours = 12;
603             priv->am = TRUE;
604             gtk_label_set_text(GTK_LABEL(priv->ampm), priv->am_symbol);
605         } else if (hours == 12) {
606             priv->am = FALSE;
607             gtk_label_set_text(GTK_LABEL(priv->ampm), priv->pm_symbol);
608         }
609
610
611         sprintf(h_time, "%2u", hours);
612     }
613     sprintf(m_time, "%02u", minutes);
614     sprintf(s_time, "%02u", seconds);
615
616     gtk_entry_set_text(GTK_ENTRY(priv->h_entry), h_time);
617     gtk_entry_set_text(GTK_ENTRY(priv->m_entry), m_time);
618     gtk_entry_set_text(GTK_ENTRY(priv->s_entry), s_time);
619
620     /* If in duration mode check time validity */
621     if (priv->duration_mode) {
622         guint response =
623             hildon_time_editor_check_duration_validity(editor);
624         if (response != DURATION_OK)
625             hildon_time_editor_duration_handle_error(editor, response);
626     }
627 }
628
629 /**
630  * hildon_time_editor_get_time:
631  * @editor: the @HildonTimeEditor widget.
632  * @hours: hours
633  * @minutes: minutes
634  * @seconds: seconds
635  *
636  * Gets the time of the @HildonTimeEditor widget. 
637  **/
638
639 void hildon_time_editor_get_time(HildonTimeEditor * editor,
640                                  guint * hours,
641                                  guint * minutes, guint * seconds)
642 {
643     HildonTimeEditorPrivate *priv;
644
645     g_return_if_fail(editor);
646     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
647
648     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
649
650     *hours = atoi(GTK_ENTRY(priv->h_entry)->text);
651
652     if( !priv->duration_mode )
653     {
654         /* if using 12h clock and its after noon, add 12h hours to get 24h
655            clock */
656         if (!priv->clock_24h && !priv->am) {
657             if (*hours != 12)
658                 *hours += 12;
659         }
660         if (*hours == 12 && priv->am)
661             *hours = 0;
662     }
663
664     *minutes = atoi(GTK_ENTRY(priv->m_entry)->text);
665     *seconds = atoi(GTK_ENTRY(priv->s_entry)->text);
666 }
667
668 /**
669  * hildon_time_editor_set_duration_range:
670  * @editor: the @HildonTimeEditor widget.
671  * @min_seconds: minimum allowed time in seconds
672  * @max_seconds: maximum allowed time in seconds
673  *
674  * Sets the duration editor time range of the @HildonTimeEditor widget.
675  **/
676
677 void hildon_time_editor_set_duration_range(HildonTimeEditor * editor,
678                                            guint min_seconds,
679                                            guint max_seconds)
680 {
681     HildonTimeEditorPrivate *priv;
682     guint hours, minutes, seconds;
683
684     g_return_if_fail(editor);
685     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
686
687     g_return_if_fail(min_seconds >= MIN_DURATION);
688     g_return_if_fail(max_seconds <= MAX_DURATION);
689     g_return_if_fail(min_seconds < max_seconds);
690
691     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
692
693
694     if( !priv->duration_mode )
695       return;
696
697     priv->duration_min = min_seconds;
698     priv->duration_max = max_seconds;
699
700     hours = (min_seconds / 3600);
701     seconds = min_seconds - (hours * 3600);
702     minutes = (seconds / 60);
703     seconds = seconds - (minutes * 60);
704
705     /* Set minimum allowed value for duration editor */
706     hildon_time_editor_set_time(editor, hours, minutes, seconds);
707 }
708
709 /**
710  * hildon_time_editor_get_duration_range:
711  * @editor: the @HildonTimeEditor widget.
712  * @min_seconds: pointer to guint
713  * @max_seconds: pointer to guint
714  *
715  * Gets the duration editor time range of the @HildonTimeEditor widget.
716  **/
717
718 void hildon_time_editor_get_duration_range(HildonTimeEditor * editor,
719                                            guint * min_seconds,
720                                            guint * max_seconds)
721 {
722     HildonTimeEditorPrivate *priv;
723
724     g_return_if_fail(editor);
725     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
726
727     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
728
729     *min_seconds = priv->duration_min;
730     *max_seconds = priv->duration_max;
731 }
732
733 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor)
734 {
735     HildonTimeEditorPrivate *priv;
736     gchar *t_fm;
737
738     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
739
740     priv->am_symbol = g_strdup(nl_langinfo(AM_STR));
741     priv->pm_symbol = g_strdup(nl_langinfo(PM_STR));
742
743     if (!strcmp(priv->am_symbol, ""))
744         return TRUE;
745     else {
746         t_fm = g_strdup(nl_langinfo(T_FMT_AMPM));
747         /* Check what format am/pm time should be */
748         if (!strncmp(t_fm, "%p", 2))
749             priv->ampm_pos_after = FALSE;
750         priv->am_symbol =
751             g_ascii_strdown((const gchar *) priv->am_symbol, -1);
752         priv->pm_symbol =
753             g_ascii_strdown((const gchar *) priv->pm_symbol, -1);
754         g_free(t_fm);
755         return FALSE;
756     }
757 }
758
759 static
760 guint hildon_time_editor_check_duration_validity(HildonTimeEditor * editor)
761 {
762     HildonTimeEditorPrivate *priv;
763     guint seconds;
764
765     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
766
767     /* Get current time */
768     seconds =
769         3600 * (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->h_entry)))
770         + 60 * (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)))
771         + (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->s_entry)));
772
773     if (seconds > priv->duration_max)
774         return DURATION_MAX_EXCEED;
775     else if (seconds < priv->duration_min)
776         return DURATION_MIN_EXCEED;
777     else
778         return DURATION_OK;
779 }
780
781 static gboolean hildon_time_editor_entry_focusout(GtkWidget * widget,
782                                                   GdkEventFocus * event,
783                                                   gpointer data)
784 {
785     HildonTimeEditor *editor;
786     HildonTimeEditorPrivate *priv;
787
788     editor = HILDON_TIME_EDITOR(data);
789     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
790
791     /* If entry is deleted we should restore previous value for it and
792        infoprint is showed */
793     if (!strcmp(GTK_ENTRY(widget)->text, "")) {
794         if (widget == priv->h_entry) {
795             if (!priv->duration_mode && priv->clock_24h) {
796                 gtk_infoprintf(GTK_WINDOW
797                               (gtk_widget_get_ancestor
798                                (widget, GTK_TYPE_WINDOW)),
799                               _("Ckct_ib_set_a_value_within_range"), 0, 23);
800             } else if (!priv->duration_mode && !priv->clock_24h) {
801                 gtk_infoprintf(GTK_WINDOW
802                               (gtk_widget_get_ancestor
803                                (widget, GTK_TYPE_WINDOW)),
804                               _("Ckct_ib_set_a_value_within_range"), 1, 12); 
805             } else if (priv->duration_mode) {
806                 gtk_infoprintf(GTK_WINDOW
807                               (gtk_widget_get_ancestor
808                                (widget, GTK_TYPE_WINDOW)),
809                               _("Ckct_ib_set_a_value_within_range"), 0, 99);
810             }
811             gtk_entry_set_text(GTK_ENTRY(priv->h_entry), priv->h_time);
812             gtk_widget_grab_focus (widget);
813             gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
814             priv->valid_value = FALSE;
815         } else if (widget == priv->m_entry) {
816             gtk_infoprintf(GTK_WINDOW
817                           (gtk_widget_get_ancestor
818                            (widget, GTK_TYPE_WINDOW)),
819                           _("Ckct_ib_set_a_value_within_range"), 0, 59);
820             gtk_entry_set_text(GTK_ENTRY(priv->m_entry), priv->m_time);
821             gtk_widget_grab_focus (widget);
822             gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
823             priv->valid_value = FALSE;
824         } else {
825             gtk_infoprintf(GTK_WINDOW
826                           (gtk_widget_get_ancestor
827                            (widget, GTK_TYPE_WINDOW)),
828                           _("Ckct_ib_set_a_value_within_range"), 0, 59);
829             gtk_entry_set_text(GTK_ENTRY(priv->s_entry), priv->s_time);
830             gtk_widget_grab_focus (widget);
831             gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
832             priv->valid_value = FALSE;
833         }
834     }
835
836     hildon_time_editor_entry_activate(widget, data);
837
838     /* FIXME - Next part is a kludge. This can only be fixed by writing
839      *         some parts of the widget again.
840      *         Widget has went trough many changes in time, so it would be
841      *         smart to re-write the whole widget and remove this kind of
842      *         kludges at the same time.
843      */
844     if( GTK_WINDOW(gtk_widget_get_ancestor(widget,
845         GTK_TYPE_WINDOW))->focus_widget == widget )
846     {
847       gtk_editable_select_region( GTK_EDITABLE(widget), 0, 2);
848       return TRUE; /*This has to be here! , I hope it wont break any other
849                      implementations runned after this*/
850     }
851     return FALSE;
852 }
853
854 static void hildon_time_editor_entry_activate(GtkWidget * widget,
855                                               gpointer data)
856 {
857
858     HildonTimeEditor *editor;
859     HildonTimeEditorPrivate *priv;
860     gint val;
861     gchar str[3];
862
863     g_return_if_fail(widget);
864     g_return_if_fail(data);
865
866     editor = HILDON_TIME_EDITOR(data);
867     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
868
869     /* check value of the entry */
870     val = atoi(GTK_ENTRY(widget)->text);
871
872     /* check limit of the hour entry */
873     if (widget == priv->h_entry) {
874         /* 24h clock or in duration editor mode */
875         if (priv->clock_24h || priv->duration_mode) {
876             /* too big */
877             if (!priv->duration_mode && val > 23) {
878                 gtk_infoprintf(GTK_WINDOW
879                               (gtk_widget_get_ancestor
880                                (widget, GTK_TYPE_WINDOW)),
881                               _("Ckct_ib_maximum_value"), 23);
882                 gtk_entry_set_text(GTK_ENTRY(widget), "23");
883                 gtk_widget_grab_focus(widget);
884                 gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
885                 priv->valid_value = FALSE;
886             }
887             /* ok, pad with 0 */
888             /* too big */
889             else if (priv->duration_mode && val > 99) {
890                 gtk_infoprintf(GTK_WINDOW
891                               (gtk_widget_get_ancestor
892                                (widget, GTK_TYPE_WINDOW)),
893                               _("Ckct_ib_maximum_value"), 99);
894                 gtk_entry_set_text(GTK_ENTRY(widget), "99");
895                 gtk_widget_grab_focus(widget);
896                 gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
897                 priv->valid_value = FALSE;
898             } else {
899                 sprintf(str, "%02d", val);
900                 gtk_entry_set_text(GTK_ENTRY(widget), str);
901             }
902         }
903         /* 12h clock */
904         else {
905             /* too big */
906             if (val > 12) {
907                 gtk_infoprintf(GTK_WINDOW
908                               (gtk_widget_get_ancestor
909                                (widget, GTK_TYPE_WINDOW)),
910                               _("Ckct_ib_maximum_value"), 12);
911                 gtk_entry_set_text(GTK_ENTRY(widget), "12");
912                 gtk_widget_grab_focus(widget);
913                 gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
914                 priv->valid_value = FALSE;
915             }
916             /* ok, no padding */
917             else if (val < 1) {
918                 gtk_infoprintf(GTK_WINDOW
919                               (gtk_widget_get_ancestor
920                                (widget, GTK_TYPE_WINDOW)),
921                               _("Ckct_ib_minimum_value"), 1);
922                 gtk_entry_set_text(GTK_ENTRY(widget), "01");
923                 gtk_widget_grab_focus(widget);
924                 gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
925                 priv->valid_value = FALSE;
926             } else {
927                 sprintf(str, "%02d", val);
928                 gtk_entry_set_text(GTK_ENTRY(widget), str);
929             }
930         }
931
932     }
933     /* check limit of the minute entries */
934     else if (widget == priv->m_entry) {
935         /* too big */
936         if (val > 59) {
937             gtk_infoprintf(GTK_WINDOW
938                           (gtk_widget_get_ancestor
939                            (widget, GTK_TYPE_WINDOW)),
940                           _("Ckct_ib_maximum_value"), 59);
941             gtk_entry_set_text(GTK_ENTRY(widget), "59");
942             gtk_widget_grab_focus(widget);
943             gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
944             priv->valid_value = FALSE;
945         }
946         /* ok, pad with 0 */
947         else {
948             sprintf(str, "%02d", val);
949             gtk_entry_set_text(GTK_ENTRY(widget), str);
950         }
951     }
952     /* check limit of the seconds entries */
953     else if (widget == priv->s_entry) {
954         /* too big */
955         if (val > 59) {
956             gtk_infoprintf(GTK_WINDOW
957                           (gtk_widget_get_ancestor
958                            (widget, GTK_TYPE_WINDOW)),
959                           _("Ckct_ib_maximum_value"), 59);
960             gtk_entry_set_text(GTK_ENTRY(widget), "59");
961             gtk_widget_grab_focus(widget);
962             gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
963             priv->valid_value = FALSE;
964         }
965         /* ok, pad with 0 */
966         else {
967             sprintf(str, "%02d", val);
968             gtk_entry_set_text(GTK_ENTRY(widget), str);
969         }
970     }
971     /* Handle duration mode minimum and maximum range */
972     if (priv->duration_mode) {
973         guint response;
974
975         response = hildon_time_editor_check_duration_validity(editor);
976         if (response != DURATION_OK)
977         {
978             hildon_time_editor_duration_handle_error(editor, response);
979             /* We have to grab focus back, as the specification says. */
980             if( GTK_IS_EDITABLE(widget) )
981               gtk_widget_grab_focus( widget );
982         }
983     }
984 }
985
986 static void
987 hildon_time_editor_duration_handle_error(HildonTimeEditor * editor,
988                                          guint type)
989 {
990     HildonTimeEditorPrivate *priv;
991     guint hours, minutes, seconds, totalsecs;
992     gchar str[256], t_str[3];
993
994     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
995
996     if (type == DURATION_MAX_EXCEED)
997         totalsecs = priv->duration_max;
998     else
999         totalsecs = priv->duration_min;
1000
1001     hours = (totalsecs / 3600);
1002     seconds = totalsecs - (hours * 3600);
1003     minutes = (seconds / 60);
1004     seconds = seconds - (minutes * 60);
1005
1006     if (!type)
1007         g_snprintf(str, 256,
1008                    _("Minimum allowed duration is %02d:%02d:%02d\n"),
1009                    hours, minutes, seconds);
1010      
1011     else
1012         g_snprintf(str, 256,
1013                    _("Maximum allowed duration is %02d:%02d:%02d\n"),
1014                    hours, minutes, seconds);
1015
1016     /* set correct values to duration editor */
1017     sprintf(t_str, "%02u", hours);
1018     gtk_entry_set_text(GTK_ENTRY(priv->h_entry), t_str);
1019     sprintf(t_str, "%02u", minutes);
1020     gtk_entry_set_text(GTK_ENTRY(priv->m_entry), t_str);
1021     sprintf(t_str, "%02u", seconds);
1022     gtk_entry_set_text(GTK_ENTRY(priv->s_entry), t_str);
1023
1024     /* show infoprint */
1025     gtk_infoprint(GTK_WINDOW
1026                   (gtk_widget_get_ancestor
1027                   (GTK_WIDGET(editor), GTK_TYPE_WINDOW)), str);
1028 }
1029
1030 static gboolean
1031 hildon_time_editor_ampm_clicked(GtkWidget * widget,
1032                                 GdkEventButton * event, gpointer data)
1033 {
1034     HildonTimeEditor *editor;
1035     HildonTimeEditorPrivate *priv;
1036
1037     g_return_val_if_fail(widget, FALSE);
1038     g_return_val_if_fail(data, FALSE);
1039
1040     editor = HILDON_TIME_EDITOR(data);
1041     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1042
1043     if (priv->am) {
1044         gtk_label_set_text(GTK_LABEL(priv->ampm), priv->pm_symbol);
1045         priv->am = FALSE;
1046     } else {
1047         gtk_label_set_text(GTK_LABEL(priv->ampm), priv->am_symbol);
1048         priv->am = TRUE;
1049     }
1050     return FALSE;
1051 }
1052
1053 static gboolean
1054 hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
1055 {
1056     HildonTimeEditor *editor;
1057     HildonTimeEditorPrivate *priv;
1058     GtkWidget *picker;
1059     GtkWidget *parent;
1060     guint h, m, s, result;
1061
1062     g_return_val_if_fail(widget, FALSE);
1063     g_return_val_if_fail(data, FALSE);
1064
1065     editor = HILDON_TIME_EDITOR(data);
1066     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1067
1068     /* icon is passive in duration editor mode */
1069     if (priv->duration_mode)
1070         return FALSE;
1071
1072     /* Check that we have valid values in entries */
1073     hildon_time_editor_entry_activate(priv->h_entry, data);
1074     hildon_time_editor_entry_activate(priv->m_entry, data);
1075     hildon_time_editor_entry_activate(priv->s_entry, data);
1076
1077     parent = gtk_widget_get_ancestor(GTK_WIDGET(editor), GTK_TYPE_WINDOW);
1078     picker = hildon_time_picker_new(GTK_WINDOW(parent));
1079
1080     hildon_time_editor_get_time(editor, &h, &m, &s);
1081     hildon_time_picker_set_time(HILDON_TIME_PICKER(picker), h, m);
1082
1083     result = gtk_dialog_run(GTK_DIALOG(picker));
1084     switch (result) {
1085     case GTK_RESPONSE_OK:
1086     case GTK_RESPONSE_ACCEPT:
1087         hildon_time_picker_get_time(HILDON_TIME_PICKER(picker), &h, &m);
1088         hildon_time_editor_set_time(editor, h, m, 0);
1089         break;
1090     default:
1091         break;
1092     }
1093
1094     gtk_widget_destroy(picker);
1095     return FALSE;
1096 }
1097
1098 static gboolean hildon_time_editor_entry_clicked(GtkWidget * widget,
1099                                                  GdkEventButton * event,
1100                                                  gpointer data)
1101 {
1102      HildonTimeEditor *editor;
1103      HildonTimeEditorPrivate *priv;
1104
1105      editor = HILDON_TIME_EDITOR (data);
1106      priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1107      
1108      if (!priv->valid_value)
1109        priv->valid_value = TRUE;
1110      else
1111        gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
1112
1113     return FALSE;
1114 }
1115
1116 static void hildon_time_editor_size_request(GtkWidget * widget,
1117                                             GtkRequisition * requisition)
1118 {
1119     HildonTimeEditor *editor;
1120     HildonTimeEditorPrivate *priv;
1121     GtkRequisition req;
1122
1123     editor = HILDON_TIME_EDITOR(widget);
1124     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1125
1126     gtk_widget_size_request(priv->frame, &req);
1127     *requisition = req;
1128
1129     requisition->width = TIME_EDITOR_LBORDER +
1130         TIME_EDITOR_RBORDER + TIME_EDITOR_CLOCK_BORDER +
1131         widget->style->xthickness * 2;
1132
1133
1134     gtk_widget_size_request(priv->h_entry, &req);
1135     requisition->width += req.width;
1136
1137     gtk_widget_size_request(priv->m_entry, &req);
1138     requisition->width += req.width;
1139
1140     gtk_widget_size_request(priv->label, &req);
1141     requisition->width += req.width;
1142
1143     gtk_widget_size_request(priv->iconbutton, &req);
1144     requisition->width += req.width;
1145
1146     if (priv->show_s) {
1147         gtk_widget_size_request(priv->s_entry, &req);
1148         requisition->width += req.width;
1149
1150         gtk_widget_size_request(priv->label2, &req);
1151         requisition->width += req.width;
1152     }
1153
1154     if (!priv->clock_24h && !priv->duration_mode) {
1155         gtk_widget_size_request(priv->eventbox, &req);
1156         requisition->width += req.width + 4;
1157     }
1158
1159     requisition->height = TIME_EDITOR_HEIGHT;
1160 }
1161
1162 static void set_widget_allocation(GtkWidget * widget,
1163                                   GtkAllocation * alloc,
1164                                   GtkAllocation * allocation)
1165 {
1166     GtkRequisition child_requisition;
1167
1168     gtk_widget_get_child_requisition(widget, &child_requisition);
1169
1170     if (allocation->width + allocation->x >
1171         alloc->x + child_requisition.width)
1172         alloc->width = child_requisition.width;
1173     else {
1174         alloc->width = allocation->width - (alloc->x - allocation->x);
1175         if (alloc->width < 0)
1176             alloc->width = 0;
1177     }
1178     gtk_widget_size_allocate(widget, alloc);
1179     alloc->x += alloc->width;
1180 }
1181
1182 static void hildon_time_editor_size_allocate(GtkWidget * widget,
1183                                              GtkAllocation * allocation)
1184 {
1185         HildonTimeEditor *editor;
1186         HildonTimeEditorPrivate *priv;
1187         GtkAllocation alloc;
1188         GtkRequisition child_requisition;
1189         gint frame_w = 0, mod_w = 0;
1190
1191         editor = HILDON_TIME_EDITOR(widget);
1192         priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1193
1194         widget->allocation = *allocation;
1195
1196 /*Init start values*/
1197         alloc.y = widget->allocation.y + widget->style->ythickness;
1198         
1199         if (widget->allocation.height > TIME_EDITOR_HEIGHT) {
1200             alloc.height =
1201                 TIME_EDITOR_HEIGHT - widget->style->ythickness * 2;
1202             alloc.y +=
1203                 (widget->allocation.height - TIME_EDITOR_HEIGHT) / 2;
1204         } else
1205             alloc.height =
1206                 widget->allocation.height - widget->style->ythickness * 2;
1207
1208         if (alloc.height < 0)
1209             alloc.height = 0;
1210
1211         gtk_widget_size_request(widget, &child_requisition);
1212         if (allocation->width > child_requisition.width) {
1213             mod_w = (allocation->width - child_requisition.width) / 2;
1214             alloc.x = allocation->x + mod_w + widget->style->xthickness +
1215                       TIME_EDITOR_LBORDER;
1216         } else
1217             alloc.x = allocation->x + widget->style->xthickness +
1218                       TIME_EDITOR_LBORDER;
1219
1220         /* am/pm label */
1221         if (!priv->duration_mode) {
1222             if (!priv->clock_24h && !priv->ampm_pos_after) {
1223                 gint tmp = alloc.height;
1224
1225                 alloc.x += 4;
1226                 alloc.y -= 5;
1227                 alloc.height = 27;
1228                 set_widget_allocation(priv->eventbox, &alloc,
1229                                       &widget->allocation);
1230                 alloc.y += 5;
1231                 alloc.height = tmp;
1232             }
1233         }
1234         
1235         /* hour */
1236         if (priv->h_entry && GTK_WIDGET_VISIBLE(priv->h_entry))
1237             set_widget_allocation(priv->h_entry, &alloc,
1238                                   &widget->allocation);
1239
1240 /* -5/+5 just to make it look nice -- Hildon --
1241  * Same y -value for the label, does not just look good
1242  * This may be a kludge, or then not
1243  */
1244         /* first label */
1245         if (priv->label && GTK_WIDGET_VISIBLE(priv->label)) {
1246             alloc.y -= 5;
1247             set_widget_allocation(priv->label, &alloc,
1248                                   &widget->allocation);
1249             alloc.y += 5;
1250         }
1251
1252         /* minutes */
1253         if (priv->m_entry && GTK_WIDGET_VISIBLE(priv->m_entry))
1254             set_widget_allocation(priv->m_entry, &alloc,
1255                                   &widget->allocation);
1256
1257         if (priv->show_s) {
1258             /* seconds label */
1259             if (priv->label2) {
1260                 alloc.y -= 5;
1261                 set_widget_allocation(priv->label2, &alloc,
1262                                       &widget->allocation);
1263                 alloc.y += 5;
1264             }
1265
1266             /* seconds */
1267             if (priv->s_entry)
1268                 set_widget_allocation(priv->s_entry, &alloc,
1269                                       &widget->allocation);
1270         }
1271
1272         /* am/pm label after the rest */
1273         if (!priv->duration_mode) {
1274             if (!priv->clock_24h && priv->ampm_pos_after) {
1275                 gint tmp = alloc.height;
1276
1277                 alloc.y -= 5;
1278                 alloc.height = 27;
1279                 set_widget_allocation(priv->eventbox, &alloc,
1280                                       &widget->allocation);
1281                 alloc.y += 5;
1282                 alloc.height = tmp;
1283                 alloc.x += 4;
1284             }
1285         }
1286         frame_w = alloc.x - widget->allocation.x + TIME_EDITOR_RBORDER;
1287
1288         /* icon */
1289         if (priv->iconbutton && GTK_WIDGET_VISIBLE(priv->iconbutton)) {
1290             alloc.x += TIME_EDITOR_CLOCK_BORDER;
1291             alloc.height = ICON_HEIGHT;
1292             alloc.width = ICON_WIDTH;
1293             set_widget_allocation(priv->iconbutton, &alloc,
1294                                   &widget->allocation);
1295         }
1296
1297         /* frame */
1298         if (allocation->width > child_requisition.width) {
1299             alloc.x = allocation->x + mod_w;
1300             alloc.width = frame_w - mod_w;
1301
1302         } else {
1303             alloc.x = allocation->x;
1304             alloc.width = frame_w;
1305         }
1306
1307         gtk_widget_get_child_requisition(priv->frame, &child_requisition);
1308
1309         alloc.y = allocation->y;
1310         
1311         if (widget->allocation.height > TIME_EDITOR_HEIGHT) {
1312             alloc.height = TIME_EDITOR_HEIGHT;
1313             alloc.y +=
1314                 (widget->allocation.height - TIME_EDITOR_HEIGHT) / 2;
1315
1316         } else
1317             alloc.height = widget->allocation.height;
1318
1319         gtk_widget_size_allocate(priv->frame, &alloc);
1320 }
1321
1322 static gboolean hildon_time_editor_entry_keypress(GtkWidget * widget,
1323                                                   GdkEventKey * event,
1324                                                   gpointer data)
1325 {
1326     HildonTimeEditor *editor;
1327     HildonTimeEditorPrivate *priv;
1328     gint pos;
1329
1330     g_return_val_if_fail(widget, FALSE);
1331     g_return_val_if_fail(event, FALSE);
1332     g_return_val_if_fail(data, FALSE);
1333
1334     editor = HILDON_TIME_EDITOR(data);
1335     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1336
1337     pos = gtk_editable_get_position(GTK_EDITABLE(widget));
1338
1339     if (event->keyval == GDK_KP_Enter || event->keyval == GDK_Return) {
1340         /* Check that we have correct values in entries */
1341         hildon_time_editor_entry_activate(widget, data);
1342         _gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), TRUE);
1343         hildon_time_editor_icon_clicked(widget, data);
1344         _gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), FALSE);
1345     }
1346
1347     /* We don't want wrap */
1348     if (event->keyval == GDK_KP_Left || event->keyval == GDK_Left) {
1349         if (pos == 0 && widget == priv->h_entry) {
1350             return TRUE;
1351         }
1352     }
1353
1354     if (event->keyval == GDK_KP_Right || event->keyval == GDK_Right) {
1355         if (pos >= strlen(GTK_ENTRY(widget)->text)) {
1356             if ((widget == priv->m_entry
1357                  && !GTK_WIDGET_REALIZED(priv->s_entry))
1358                 || (widget == priv->s_entry
1359                     && GTK_WIDGET_REALIZED(priv->s_entry))) {
1360                 return TRUE;
1361             }
1362         }
1363     }
1364
1365     /* numeric key pressed */
1366     if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
1367         GtkWidgetClass *c = GTK_WIDGET_GET_CLASS(widget);
1368
1369         c->key_press_event(widget, event);
1370
1371         /* Set time values to our internal struct */
1372         g_snprintf(priv->h_time, 4, "%s", GTK_ENTRY(priv->h_entry)->text);
1373         g_snprintf(priv->m_time, 4, "%s", GTK_ENTRY(priv->m_entry)->text);
1374         g_snprintf(priv->s_time, 4, "%s", GTK_ENTRY(priv->s_entry)->text);
1375
1376         return TRUE;
1377     }
1378     /* tab pressed in hour entry */
1379     else if (widget == priv->h_entry && (event->keyval == GDK_Tab ||
1380                    event->keyval == GDK_KP_Tab)) {
1381         gtk_widget_grab_focus(priv->m_entry);
1382         return TRUE;
1383     }
1384     /* tab pressed in minute entry */
1385     else if (widget == priv->m_entry && (event->keyval == GDK_Tab ||
1386                    event->keyval == GDK_KP_Tab)) {
1387         if (priv->show_s)
1388             gtk_widget_grab_focus(priv->s_entry);
1389         else
1390             gtk_widget_grab_focus(priv->h_entry);
1391         return TRUE;
1392     }
1393     /* tab pressed in second entry */
1394     else if (widget == priv->s_entry && (event->keyval == GDK_Tab ||
1395                    event->keyval == GDK_KP_Tab)) {
1396         gtk_widget_grab_focus(priv->h_entry);
1397         return TRUE;
1398     }
1399     /* left tab pressed in second entry */
1400     else if (widget == priv->s_entry &&
1401              event->keyval == GDK_ISO_Left_Tab) {
1402         gtk_widget_grab_focus(priv->m_entry);
1403         return TRUE;
1404     }
1405     /* left tab pressed in minute entry */
1406     else if (widget == priv->m_entry &&
1407              event->keyval == GDK_ISO_Left_Tab) {
1408         gtk_widget_grab_focus(priv->h_entry);
1409         return TRUE;
1410     }
1411     /* left tab pressed in hour entry */
1412     else if (widget == priv->h_entry &&
1413              event->keyval == GDK_ISO_Left_Tab) {
1414         if (priv->show_s)
1415             gtk_widget_grab_focus(priv->s_entry);
1416         else
1417             gtk_widget_grab_focus(priv->m_entry);
1418         return TRUE;
1419     }
1420     /* right arrow pressed in hour entry */
1421     else if (widget == priv->h_entry &&
1422              (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
1423              && pos >= GTK_ENTRY(priv->h_entry)->text_length) {
1424         gtk_widget_grab_focus(priv->m_entry);
1425         gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), 0);
1426         return TRUE;
1427     }
1428     /* right arrow pressed in minute entry */
1429     else if (widget == priv->m_entry &&
1430              (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
1431              && pos >= GTK_ENTRY(priv->m_entry)->text_length) {
1432         if (priv->show_s) {
1433             gtk_widget_grab_focus(priv->s_entry);
1434             gtk_editable_set_position(GTK_EDITABLE(priv->s_entry), 0);
1435         } else {
1436             gtk_widget_grab_focus(priv->h_entry);
1437             gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), 0);
1438         }
1439         return TRUE;
1440     }
1441     /* right arrow pressed in second entry */
1442     else if (widget == priv->s_entry &&
1443              (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
1444              && pos >= GTK_ENTRY(priv->s_entry)->text_length) {
1445         gtk_widget_grab_focus(priv->h_entry);
1446         gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), 0);
1447         return TRUE;
1448     }
1449     /* left arrow key pressed in hour entry */
1450     else if (widget == priv->h_entry &&
1451              (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
1452              pos <= 0) {
1453         if (priv->show_s) {
1454             gtk_widget_grab_focus(priv->s_entry);
1455             gtk_editable_set_position(GTK_EDITABLE(priv->s_entry), -1);
1456         } else {
1457             gtk_widget_grab_focus(priv->m_entry);
1458             gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), -1);
1459         }
1460         return TRUE;
1461     }
1462     /* left arrow key pressed in minute entry */
1463     else if (widget == priv->m_entry &&
1464              (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
1465              pos <= 0) {
1466         gtk_widget_grab_focus(priv->h_entry);
1467         gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), -1);
1468         return TRUE;
1469     }
1470     /* left arrow key pressed in seconds entry */
1471     else if (widget == priv->s_entry &&
1472              (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
1473              pos <= 0) {
1474         gtk_widget_grab_focus(priv->m_entry);
1475         gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), -1);
1476         return TRUE;
1477     }
1478     /* pass other arrow key presses and backspace and del onwards */
1479     else if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left ||
1480              event->keyval == GDK_Right || event->keyval == GDK_KP_Right ||
1481              event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1482              event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1483              event->keyval == GDK_BackSpace || event->keyval == GDK_Delete
1484              || event->keyval == GDK_KP_Delete)
1485         return FALSE;   /* pass the keypress on */
1486
1487     /* ingore other keys */
1488     return TRUE;
1489 }
1490
1491 /**
1492  * hildon_time_editor_show_seconds:
1493  * @editor: The #HildonTimeEditor.
1494  * @enable: Enable or disable showing of seconds.
1495  *
1496  * This function shows or hides the seconds field.
1497  *
1498  **/
1499 void hildon_time_editor_show_seconds(HildonTimeEditor * editor,
1500                                      gboolean enable)
1501 {
1502     HildonTimeEditorPrivate *priv;
1503
1504     g_return_if_fail(editor);
1505
1506     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1507
1508     if (!priv->show_s && enable) {
1509         priv->show_s = TRUE;
1510
1511         gtk_widget_show(priv->s_entry);
1512         gtk_widget_show(priv->label2);
1513         
1514     } else if (priv->show_s && !enable) {
1515
1516         gtk_widget_hide(priv->s_entry);
1517         gtk_widget_hide(priv->label2);
1518
1519         priv->show_s = FALSE;
1520     } else
1521         return;
1522
1523     gtk_widget_queue_resize(GTK_WIDGET(editor));
1524 }
1525
1526 /**
1527  * hildon_time_editor_enable_duration_mode:
1528  * @editor: The #HildonTimeEditor.
1529  * @enable: Enable or disable duration editor mode
1530  *
1531  * This function sets the duration editor mode in which the maximum hours
1532  * is 99 and the #HildonTimePicker is disabled.
1533  *
1534  **/
1535 void hildon_time_editor_enable_duration_mode(HildonTimeEditor * editor,
1536                                              gboolean enable)
1537 {
1538     HildonTimeEditorPrivate *priv;
1539
1540     g_return_if_fail(editor);
1541
1542     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1543
1544     /* switch to duration editor mode */
1545     if (enable && !priv->duration_mode) {
1546         priv->duration_mode = enable;
1547         hildon_time_editor_set_duration_range(editor, MIN_DURATION,
1548                                               MAX_DURATION);
1549
1550         if (!priv->clock_24h)
1551             gtk_widget_hide(GTK_WIDGET(priv->ampm));
1552
1553         gtk_widget_hide(GTK_WIDGET(priv->eventbox));
1554         gtk_widget_hide(GTK_WIDGET(priv->icon));
1555
1556         /* Show seconds for duration editor */
1557         hildon_time_editor_show_seconds(editor, TRUE);
1558     }
1559     /* switch to time editor mode */
1560     else if (!enable && priv->duration_mode) {
1561         priv->duration_mode = enable;
1562
1563         if (!priv->clock_24h)
1564             gtk_widget_show(GTK_WIDGET(priv->ampm));
1565
1566         gtk_widget_show(GTK_WIDGET(priv->eventbox));
1567         gtk_widget_show(GTK_WIDGET(priv->icon));
1568     }
1569     gtk_widget_queue_resize(GTK_WIDGET(editor));
1570 }
1571