2 * This file is part of hildon-libs
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@nokia.com>
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.
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.
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
26 * SECTION:hildon-time-editor
27 * @short_description: A widget used to enter time or duration in hours, minutes,
28 * and optional seconds
29 * @see_also: #HildonTimePicker
31 * HildonTimeEditor is used to edit time or duration. Time mode is
32 * restricted to normal 24 hour cycle, but Duration mode can select any
33 * amount of time up to 99 hours. It consists of entries for hours,
34 * minutes and seconds, and pm/am indicator as well as a button which
35 * popups a #HildonTimePicker dialog.
42 #include <gtk/gtkhbox.h>
43 #include <gtk/gtkeventbox.h>
44 #include <gtk/gtkentry.h>
45 #include <gtk/gtkbutton.h>
46 #include <gtk/gtklabel.h>
47 #include <gtk/gtkframe.h>
48 #include <gdk/gdkkeysyms.h>
56 #include <hildon-widgets/hildon-defines.h>
57 #include <hildon-widgets/hildon-time-editor.h>
58 #include <hildon-widgets/hildon-time-picker.h>
59 #include <hildon-widgets/hildon-banner.h>
60 #include <hildon-widgets/hildon-input-mode-hint.h>
61 #include "hildon-composite-widget.h"
63 #define _(String) dgettext(PACKAGE, String)
65 #define HILDON_TIME_EDITOR_GET_PRIVATE(obj) \
66 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
67 HILDON_TYPE_TIME_EDITOR, HildonTimeEditorPrivate));
69 #define TICKS(h,m,s) ((h) * 3600 + (m) * 60 + (s))
71 #define TIME_EDITOR_HEIGHT 30
72 #define ICON_PRESSED 4
73 #define ICON_NAME "qgn_widg_timedit"
74 #define ICON_SIZE "timepicker-size"
75 #define MIN_DURATION 0
76 #define MAX_DURATION TICKS(99, 59, 59)
78 /* Default values for properties */
79 #define HILDON_TIME_EDITOR_TICKS_VALUE 0
80 #define HILDON_TIME_EDITOR_DURATION_MODE FALSE
81 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE 0
82 #define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE TICKS(99, 59, 59)
84 #define HOURS_MAX_24 23
85 #define HOURS_MAX_12 12
86 #define HOURS_MIN_24 0
87 #define HOURS_MIN_12 1
88 #define MINUTES_MAX 59
89 #define SECONDS_MAX 59
93 static GtkContainerClass *parent_class;
95 typedef struct _HildonTimeEditorPrivate HildonTimeEditorPrivate;
115 struct _HildonTimeEditorPrivate {
116 guint ticks; /* Current duration in seconds */
121 gchar *hm_sep_symbol; /* hours/minutes separator */
122 gchar *ms_sep_symbol; /* minutes/seconds separator */
124 GtkWidget *eventbox; /* hold entries */
125 GtkWidget *iconbutton; /* button for icon */
127 GtkWidget *frame; /* frame around the entries */
128 GtkWidget *entries[ENTRY_COUNT]; /* h, m, s entries */
129 GtkWidget *hm_label; /* between hour and minute */
130 GtkWidget *sec_label; /* between minute and second */
131 GtkWidget *ampm_label; /* label for showing am or pm */
133 GtkWidget *error_widget; /* field to highlight in idle */
136 gboolean duration_mode; /* In HildonDurationEditor mode */
137 gboolean show_seconds; /* show seconds */
138 gboolean show_hours; /* show hours */
140 gboolean ampm_pos_after; /* is am/pm shown after others */
141 gboolean clock_24h; /* whether to show a 24h clock */
142 gboolean am; /* TRUE == am, FALSE == pm */
144 guint duration_min; /* duration editor ranges */
145 guint duration_max; /* duration editor ranges */
147 guint highlight_idle;
154 static void hildon_time_editor_class_init (HildonTimeEditorClass *editor_class);
155 static void hildon_time_editor_init (HildonTimeEditor *editor);
157 static void hildon_time_editor_finalize (GObject *obj_self);
159 static void hildon_time_editor_set_property(GObject *object,
164 static void hildon_time_editor_get_property(GObject *object,
169 static void hildon_time_editor_forall(GtkContainer *container,
170 gboolean include_internals,
171 GtkCallback callback,
172 gpointer callback_data);
174 static void hildon_time_editor_destroy(GtkObject * self);
180 static gboolean hildon_time_editor_entry_focusout(GtkWidget *widget,
181 GdkEventFocus *event,
184 static gboolean hildon_time_editor_entry_focusin(GtkWidget *widget,
185 GdkEventFocus *event,
188 static gboolean hildon_time_editor_ampm_clicked(GtkWidget *widget,
189 GdkEventButton *event,
192 static gboolean hildon_time_editor_icon_clicked(GtkWidget *widget,
195 static gboolean hildon_time_editor_entry_clicked(GtkWidget *widget,
196 GdkEventButton *event,
199 static void hildon_time_editor_size_request(GtkWidget *widget,
200 GtkRequisition *requisition);
202 static void hildon_time_editor_size_allocate(GtkWidget *widget,
203 GtkAllocation *allocation);
205 static gboolean hildon_time_editor_entry_keypress(GtkWidget *widget,
213 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor);
216 void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
219 GtkWidgetTapAndHoldFlags flags);
221 hildon_time_editor_validate (HildonTimeEditor *editor, gboolean allow_intermediate);
223 static void hildon_time_editor_set_to_current_time (HildonTimeEditor * editor);
229 static void convert_to_12h (guint *h, gboolean *am);
230 static void convert_to_24h (guint *h, gboolean am);
232 static void ticks_to_time (guint ticks,
238 hildon_time_editor_inserted_text (GtkEditable * editable,
240 gint new_text_length,
244 GType hildon_time_editor_get_type(void)
246 static GType editor_type = 0;
249 static const GTypeInfo editor_info = {
250 sizeof(HildonTimeEditorClass),
251 NULL, /* base_init */
252 NULL, /* base_finalize */
253 (GClassInitFunc) hildon_time_editor_class_init,
254 NULL, /* class_finalize */
255 NULL, /* class_data */
256 sizeof(HildonTimeEditor),
258 (GInstanceInitFunc) hildon_time_editor_init,
260 editor_type = g_type_register_static(GTK_TYPE_CONTAINER,
267 static void hildon_time_editor_forall(GtkContainer * container,
268 gboolean include_internals,
269 GtkCallback callback,
270 gpointer callback_data)
272 HildonTimeEditor *editor;
273 HildonTimeEditorPrivate *priv;
275 g_assert(HILDON_IS_TIME_EDITOR(container));
276 g_assert(callback != NULL);
278 editor = HILDON_TIME_EDITOR(container);
279 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
281 if (!include_internals)
284 /* widget that are always shown */
285 (*callback) (priv->iconbutton, callback_data);
286 (*callback) (priv->frame, callback_data);
289 static void hildon_time_editor_destroy(GtkObject * self)
291 HildonTimeEditorPrivate *priv;
293 priv = HILDON_TIME_EDITOR_GET_PRIVATE(self);
295 if (priv->iconbutton) {
296 gtk_widget_unparent(priv->iconbutton);
297 priv->iconbutton = NULL;
300 gtk_widget_unparent(priv->frame);
304 if (GTK_OBJECT_CLASS(parent_class)->destroy)
305 GTK_OBJECT_CLASS(parent_class)->destroy(self);
310 hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
312 GObjectClass *object_class = G_OBJECT_CLASS(editor_class);
313 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(editor_class);
314 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(editor_class);
316 parent_class = g_type_class_peek_parent(editor_class);
318 g_type_class_add_private(editor_class,
319 sizeof(HildonTimeEditorPrivate));
321 object_class->get_property = hildon_time_editor_get_property;
322 object_class->set_property = hildon_time_editor_set_property;
323 widget_class->size_request = hildon_time_editor_size_request;
324 widget_class->size_allocate = hildon_time_editor_size_allocate;
325 widget_class->tap_and_hold_setup =
326 hildon_time_editor_tap_and_hold_setup;
327 widget_class->focus = hildon_composite_widget_focus;
329 container_class->forall = hildon_time_editor_forall;
330 GTK_OBJECT_CLASS(editor_class)->destroy = hildon_time_editor_destroy;
332 object_class->finalize = hildon_time_editor_finalize;
335 * HildonTimeEditor:ticks:
337 * If editor is in duration mode, contains the duration seconds.
338 * If not, contains seconds since midnight.
340 g_object_class_install_property( object_class, PROP_TICKS,
341 g_param_spec_uint("ticks",
343 "Current value of duration",
345 HILDON_TIME_EDITOR_TICKS_VALUE,
346 G_PARAM_READABLE | G_PARAM_WRITABLE) );
349 * HildonTimeEditor:show_seconds:
351 * Controls whether seconds are shown in the editor
353 g_object_class_install_property( object_class, PROP_SHOW_SECONDS,
354 g_param_spec_boolean("show_seconds",
355 "Show seconds property",
356 "Controls whether the seconds are shown in the editor",
358 G_PARAM_READABLE | G_PARAM_WRITABLE) );
361 * HildonTimeEditor:show_hours:
363 * Controls whether hours are shown in the editor
365 g_object_class_install_property( object_class, PROP_SHOW_HOURS,
366 g_param_spec_boolean("show_hours",
368 "Controls whether the hours field is shown in the editor",
370 G_PARAM_READABLE | G_PARAM_WRITABLE) );
373 * HildonTimeEditor:duration_mode:
375 * Controls whether the TimeEditor is in duration mode
377 g_object_class_install_property( object_class, PROP_DURATION_MODE,
378 g_param_spec_boolean("duration_mode",
380 "Controls whether the TimeEditor is in duration mode",
381 HILDON_TIME_EDITOR_DURATION_MODE,
382 G_PARAM_READABLE | G_PARAM_WRITABLE) );
385 * HildonTimeEditor:duration_min:
387 * Minimum allowed duration value.
389 g_object_class_install_property( object_class, PROP_DURATION_MIN,
390 g_param_spec_uint("duration_min",
391 "Minumum duration value",
392 "Smallest possible duration value",
393 MIN_DURATION, MAX_DURATION,
394 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
395 G_PARAM_READABLE | G_PARAM_WRITABLE) );
398 * HildonTimeEditor:duration_max:
400 * Maximum allowed duration value.
402 g_object_class_install_property( object_class, PROP_DURATION_MAX,
403 g_param_spec_uint("duration_max",
404 "Maximum duration value",
405 "Largest possible duration value",
407 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
408 G_PARAM_READABLE | G_PARAM_WRITABLE) );
412 void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
415 GtkWidgetTapAndHoldFlags flags)
417 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
420 /* Forward this tap_and_hold_setup signal to all our child widgets */
421 for (i = 0; i < ENTRY_COUNT; i++)
423 gtk_widget_tap_and_hold_setup(priv->entries[i], menu, func,
424 GTK_TAP_AND_HOLD_NO_SIGNALS);
426 gtk_widget_tap_and_hold_setup(priv->eventbox, menu, func,
427 GTK_TAP_AND_HOLD_NO_SIGNALS);
428 gtk_widget_tap_and_hold_setup(priv->iconbutton, menu, func,
429 GTK_TAP_AND_HOLD_NONE);
432 static void hildon_time_editor_entry_changed(GtkWidget *widget, gpointer data)
434 g_assert(HILDON_IS_TIME_EDITOR(data));
435 hildon_time_editor_validate(HILDON_TIME_EDITOR(data), TRUE);
438 static void hildon_time_editor_init(HildonTimeEditor * editor)
440 HildonTimeEditorPrivate *priv;
441 GtkWidget *hbox, *icon;
444 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
446 gtk_widget_push_composite_child();
448 /* Setup defaults and create widgets */
450 priv->show_seconds = FALSE;
451 priv->show_hours = TRUE;
452 priv->ampm_pos_after = TRUE;
453 priv->clock_24h = TRUE;
454 priv->duration_mode = FALSE;
455 priv->iconbutton = gtk_button_new();
456 priv->ampm_label = gtk_label_new(NULL);
457 priv->hm_label = gtk_label_new(NULL);
458 priv->sec_label = gtk_label_new(NULL);
459 priv->frame = gtk_frame_new(NULL);
460 priv->eventbox = gtk_event_box_new();
462 icon = gtk_image_new_from_icon_name(ICON_NAME, HILDON_ICON_SIZE_WIDG);
463 hbox = gtk_hbox_new(FALSE, 0);
465 GTK_WIDGET_SET_FLAGS(editor, GTK_NO_WINDOW);
466 GTK_WIDGET_UNSET_FLAGS(priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
468 gtk_event_box_set_visible_window(GTK_EVENT_BOX(priv->eventbox), FALSE);
470 gtk_container_set_border_width(GTK_CONTAINER(priv->frame), 0);
472 gtk_container_add(GTK_CONTAINER(priv->iconbutton), icon);
473 gtk_container_add(GTK_CONTAINER(priv->eventbox), priv->ampm_label);
475 /* Create hour, minute and second entries */
476 for (i = 0; i < ENTRY_COUNT; i++)
478 priv->entries[i] = gtk_entry_new();
480 /* No frames for entries, so that they all appear to be inside one long entry */
481 gtk_entry_set_has_frame(GTK_ENTRY(priv->entries[i]), FALSE);
483 /* Set the entries to accept only numeric characters */
484 g_object_set (priv->entries[i], "input-mode",
485 HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
487 /* The entry fields all take exactly two characters */
488 gtk_entry_set_max_length (GTK_ENTRY(priv->entries[i]), 2);
489 gtk_entry_set_width_chars (GTK_ENTRY(priv->entries[i]), 2);
491 /* Connect signals */
492 g_signal_connect(priv->entries[i], "button-release-event",
493 G_CALLBACK(hildon_time_editor_entry_clicked), editor);
494 g_signal_connect(priv->entries[i], "focus-in-event",
495 G_CALLBACK(hildon_time_editor_entry_focusin), editor);
496 g_signal_connect(priv->entries[i], "focus-out-event",
497 G_CALLBACK(hildon_time_editor_entry_focusout), editor);
498 g_signal_connect(priv->entries[i], "key-press-event",
499 G_CALLBACK(hildon_time_editor_entry_keypress), editor);
500 g_signal_connect(priv->entries[i], "changed",
501 G_CALLBACK(hildon_time_editor_entry_changed), editor);
503 /* inserted signal sets time */
504 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
505 G_CALLBACK (hildon_time_editor_inserted_text),
509 /* clicked signal for am/pm label */
510 g_signal_connect(G_OBJECT(priv->eventbox), "button_press_event",
511 G_CALLBACK(hildon_time_editor_ampm_clicked), editor);
513 /* clicked signal for icon */
514 g_signal_connect(G_OBJECT(priv->iconbutton), "clicked",
515 G_CALLBACK(hildon_time_editor_icon_clicked), editor);
517 /* Set ourself as the parent of all the widgets we created */
518 gtk_widget_set_parent(priv->iconbutton, GTK_WIDGET(editor));
519 gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
520 gtk_box_pack_start(GTK_BOX(hbox), priv->hm_label, FALSE, FALSE, 0);
521 gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
522 gtk_box_pack_start(GTK_BOX(hbox), priv->sec_label, FALSE, FALSE, 0);
523 gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
524 gtk_box_pack_start(GTK_BOX(hbox), priv->eventbox, FALSE, FALSE, 0);
526 gtk_container_add(GTK_CONTAINER(priv->frame), hbox);
528 /* Show created widgets */
529 gtk_widget_set_parent(priv->frame, GTK_WIDGET(editor));
530 gtk_widget_show_all(priv->frame);
531 gtk_widget_show_all(priv->iconbutton);
533 /* Update AM/PM and time separators settings from locale */
534 if (!hildon_time_editor_check_locale(editor)) {
535 /* Using 12h clock */
536 priv->clock_24h = FALSE;
538 gtk_widget_hide(priv->eventbox);
541 /* Set time separators labels */
542 gtk_label_set_label(GTK_LABEL(priv->hm_label), priv->hm_sep_symbol); /* priv-> set by ..._chech_locale()*/
543 gtk_label_set_label(GTK_LABEL(priv->sec_label), priv->ms_sep_symbol);
545 if (!priv->show_seconds) {
546 gtk_widget_hide(priv->sec_label);
547 gtk_widget_hide(priv->entries[ENTRY_SECS]);
550 /* set the default time to current time. */
551 hildon_time_editor_set_to_current_time (editor);
553 gtk_widget_pop_composite_child();
556 static void hildon_time_editor_set_property (GObject *object,
561 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR(object);
565 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
568 case PROP_SHOW_SECONDS:
569 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
572 case PROP_SHOW_HOURS:
573 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
576 case PROP_DURATION_MODE:
577 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
580 case PROP_DURATION_MIN:
581 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
584 case PROP_DURATION_MAX:
585 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
589 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
594 static void hildon_time_editor_get_property (GObject *object,
599 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR(object);
604 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
607 case PROP_SHOW_SECONDS:
608 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
611 case PROP_SHOW_HOURS:
612 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
615 case PROP_DURATION_MODE:
616 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
619 case PROP_DURATION_MIN:
620 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
623 case PROP_DURATION_MAX:
624 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
628 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
634 * hildon_time_editor_new:
636 * This function creates a new time editor.
638 * Returns: pointer to a new #HildonTimeEditor widget
641 GtkWidget *hildon_time_editor_new(void)
643 return GTK_WIDGET(g_object_new(HILDON_TYPE_TIME_EDITOR, NULL));
646 static void hildon_time_editor_finalize(GObject * obj_self)
648 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(obj_self);
650 g_free(priv->am_symbol);
651 g_free(priv->pm_symbol);
653 if (priv->hm_sep_symbol)
654 g_free(priv->hm_sep_symbol);
656 if (priv->ms_sep_symbol)
657 g_free(priv->ms_sep_symbol);
659 if (priv->highlight_idle)
660 g_source_remove(priv->highlight_idle);
662 if (G_OBJECT_CLASS(parent_class)->finalize)
663 G_OBJECT_CLASS(parent_class)->finalize(obj_self);
666 /* Gets hour-minute separator and minute-second separator
667 * from current locale
669 static void get_time_separators(HildonTimeEditorPrivate *priv)
672 GDate locale_test_date;
675 /* Get localized time string */
676 g_date_set_dmy(&locale_test_date, 1, 2, 1970);
677 (void) g_date_strftime(buffer, sizeof(buffer), "%X", &locale_test_date);
679 /* Find h-m separator */
681 while (*iter && g_ascii_isdigit(*iter)) iter++;
683 /* Extract h-m separator*/
685 while (*endp && !g_ascii_isdigit(*endp)) endp++;
686 priv->hm_sep_symbol = g_strndup(iter, endp - iter);
688 /* Find m-s separator */
690 while (*iter && g_ascii_isdigit(*iter)) iter++;
692 /* Extract m-s separator*/
694 while (*endp && !g_ascii_isdigit(*endp)) endp++;
695 priv->ms_sep_symbol = g_strndup(iter, endp - iter);
698 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
699 static void ticks_to_time (guint ticks,
706 *hours = ticks / 3600;
708 *minutes = left / 60;
709 *seconds = left % 60;
713 * hildon_time_editor_set_ticks:
714 * @editor: the #HildonTimeEditor widget
715 * @ticks: the duration to set, in seconds
717 * Sets the current duration in seconds. This means seconds from
718 * midnight, if not in duration mode. In case of any errors, it tries
722 void hildon_time_editor_set_ticks (HildonTimeEditor * editor,
725 HildonTimeEditorPrivate *priv;
729 g_assert(HILDON_IS_TIME_EDITOR(editor));
731 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
733 /* Validate ticks. If it's too low or too high, set it to
734 min/max value for the current mode. */
735 if (priv->duration_mode)
736 priv->ticks = CLAMP(ticks, priv->duration_min, priv->duration_max);
738 /* Check that ticks value is valid. We only need to check that hours
740 ticks_to_time (ticks, &h, &m, &s);
741 if (h > HOURS_MAX_24)
742 ticks = TICKS(HOURS_MAX_24, m, s);
747 /* Get the time in H:M:S. */
748 ticks_to_time (priv->ticks, &h, &m, &s);
750 if (!priv->clock_24h && !priv->duration_mode)
752 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
753 convert_to_12h (&h, &priv->am);
756 /* Set H:M:S values to entries. We do not want to invoke validation
757 callbacks (since they can cause new call to this function), so we
758 block signals while setting values. */
759 for (i = 0; i < ENTRY_COUNT; i++)
761 g_signal_handlers_block_by_func(priv->entries[i],
762 (gpointer) hildon_time_editor_entry_changed, editor);
765 g_snprintf(str, sizeof(str), "%02u", h);
766 gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_HOURS]), str);
768 g_snprintf(str, sizeof(str), "%02u", m);
769 gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_MINS]), str);
771 g_snprintf(str, sizeof(str), "%02u", s);
772 gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_SECS]), str);
774 for (i = 0; i < ENTRY_COUNT; i++)
776 g_signal_handlers_unblock_by_func(priv->entries[i],
777 (gpointer) hildon_time_editor_entry_changed, editor);
780 /* Update AM/PM label in case we're in 12h mode */
781 gtk_label_set_label(GTK_LABEL(priv->ampm_label),
782 priv->am ? priv->am_symbol : priv->pm_symbol);
784 g_object_notify (G_OBJECT (editor), "ticks");
788 hildon_time_editor_set_to_current_time (HildonTimeEditor * editor)
794 tm = localtime(&now);
797 hildon_time_editor_set_time(editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
801 * hildon_time_editor_get_ticks:
802 * @editor: the #HildonTimeEditor widget
804 * This function returns the current duration, in seconds.
805 * This means seconds from midnight, if not in duration mode.
807 * Returns: current duration in seconds
810 guint hildon_time_editor_get_ticks (HildonTimeEditor * editor)
812 HildonTimeEditorPrivate *priv;
814 g_return_val_if_fail(editor, 0);
815 g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
817 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
819 return (priv->ticks);
823 * hildon_time_editor_set_show_seconds:
824 * @editor: the #HildonTimeEditor
825 * @show_seconds: enable or disable showing of seconds
827 * This function shows or hides the seconds field.
830 void hildon_time_editor_set_show_seconds (HildonTimeEditor * editor,
831 gboolean show_seconds)
833 HildonTimeEditorPrivate *priv;
835 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
837 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
839 if (show_seconds != priv->show_seconds) {
840 priv->show_seconds = show_seconds;
842 /* show/hide seconds field and its ':' label if the value changed. */
844 gtk_widget_show(priv->entries[ENTRY_SECS]);
845 gtk_widget_show(priv->sec_label);
847 gtk_widget_hide(priv->entries[ENTRY_SECS]);
848 gtk_widget_hide(priv->sec_label);
851 g_object_notify (G_OBJECT (editor), "show_seconds");
856 * hildon_time_editor_get_show_seconds:
857 * @editor: the #HildonTimeEditor widget
859 * This function returns a boolean indicating the visibility of
860 * seconds in the #HildonTimeEditor
862 * Returns: TRUE if the seconds are visible
865 gboolean hildon_time_editor_get_show_seconds (HildonTimeEditor * editor)
867 HildonTimeEditorPrivate *priv;
869 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
870 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
872 return (priv->show_seconds);
876 * hildon_time_editor_set_duration_mode:
877 * @editor: the #HildonTimeEditor
878 * @duration_mode: enable or disable duration editor mode
880 * This function sets the duration editor mode in which the maximum hours
884 void hildon_time_editor_set_duration_mode (HildonTimeEditor * editor,
885 gboolean duration_mode)
887 HildonTimeEditorPrivate *priv;
889 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
891 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
893 if (duration_mode != priv->duration_mode) {
894 priv->duration_mode = duration_mode;
897 /* FIXME: Why do we reset the duration range here?
898 Would change API, so won't touch this for now. */
899 hildon_time_editor_set_duration_range(editor, MIN_DURATION,
901 /* There's no AM/PM label or time picker icon in duration mode.
902 Make sure they're hidden. */
903 gtk_widget_hide(GTK_WIDGET(priv->ampm_label));
904 gtk_widget_hide(GTK_WIDGET(priv->eventbox));
905 gtk_widget_hide(GTK_WIDGET(priv->iconbutton));
906 /* Duration mode has seconds by default. */
907 hildon_time_editor_set_show_seconds(editor, TRUE);
909 /* Make sure AM/PM label and time picker icons are visible if needed */
910 if (!priv->clock_24h)
911 gtk_widget_show(GTK_WIDGET(priv->ampm_label));
913 gtk_widget_show(GTK_WIDGET(priv->eventbox));
914 gtk_widget_show(GTK_WIDGET(priv->iconbutton));
916 /* Reset the ticks to current time. Anything set in duration mode
917 * is bound to be invalid or useless in time mode.
919 hildon_time_editor_set_to_current_time (editor);
922 g_object_notify (G_OBJECT (editor), "duration_mode");
927 * hildon_time_editor_get_duration_mode:
928 * @editor: the #HildonTimeEditor widget
930 * This function returns a boolean indicating whether the #HildonTimeEditor
931 * is in the duration mode.
933 * Returns: TRUE if the #HildonTimeEditor is in duration mode
936 gboolean hildon_time_editor_get_duration_mode (HildonTimeEditor * editor)
938 HildonTimeEditorPrivate *priv;
940 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
941 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
943 return (priv->duration_mode);
947 * hildon_time_editor_set_duration_min:
948 * @editor: the #HildonTimeEditor widget
949 * @duration_min: mimimum allowed duration
951 * Sets the minimum allowed duration for the duration mode.
952 * Note: Has no effect in time mode
955 void hildon_time_editor_set_duration_min (HildonTimeEditor * editor,
958 HildonTimeEditorPrivate *priv;
960 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
961 g_return_if_fail(duration_min >= MIN_DURATION);
963 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
965 if( !priv->duration_mode )
968 priv->duration_min = duration_min;
970 /* Clamp the current value to the minimum if necessary */
971 if (priv->ticks < duration_min)
973 hildon_time_editor_set_ticks (editor, duration_min);
976 g_object_notify (G_OBJECT (editor), "duration_min");
980 * hildon_time_editor_get_duration_min:
981 * @editor: the #HildonTimeEditor widget
983 * This function returns the smallest duration the #HildonTimeEditor
984 * allows in the duration mode.
986 * Returns: minimum allowed duration in seconds
989 guint hildon_time_editor_get_duration_min (HildonTimeEditor * editor)
991 HildonTimeEditorPrivate *priv;
993 g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
995 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
997 if( !priv->duration_mode )
1000 return (priv->duration_min);
1004 * hildon_time_editor_set_duration_max:
1005 * @editor: the #HildonTimeEditor widget
1006 * @duration_max: maximum allowed duration in seconds
1008 * Sets the maximum allowed duration in seconds for the duration mode.
1009 * Note: Has no effect in time mode
1012 void hildon_time_editor_set_duration_max (HildonTimeEditor * editor,
1015 HildonTimeEditorPrivate *priv;
1017 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1018 g_return_if_fail(duration_max <= MAX_DURATION);
1020 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1022 if( !priv->duration_mode )
1025 priv->duration_max = duration_max;
1027 /* Clamp the current value to the maximum if necessary */
1028 if (priv->ticks > duration_max)
1030 hildon_time_editor_set_ticks (editor, duration_max);
1033 g_object_notify (G_OBJECT (editor), "duration_max");
1037 * hildon_time_editor_get_duration_max:
1038 * @editor: the #HildonTimeEditor widget
1040 * This function returns the longest duration the #HildonTimeEditor
1041 * allows in the duration mode.
1043 * Returns: maximum allowed duration in seconds
1046 guint hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1048 HildonTimeEditorPrivate *priv;
1050 g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
1052 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1054 if( !priv->duration_mode )
1057 return (priv->duration_max);
1062 * hildon_time_editor_set_time:
1063 * @editor: the #HildonTimeEditor widget
1068 * This function sets the time on an existing time editor. If the
1069 * time specified by the arguments is invalid, it's fixed.
1070 * The time is assumed to be in 24h format.
1073 void hildon_time_editor_set_time(HildonTimeEditor * editor, guint hours,
1074 guint minutes, guint seconds)
1076 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1078 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1082 * hildon_time_editor_get_time:
1083 * @editor: the #HildonTimeEditor widget
1088 * Gets the time of the #HildonTimeEditor widget. The time returned is
1089 * always in 24h format.
1092 void hildon_time_editor_get_time(HildonTimeEditor * editor,
1094 guint * minutes, guint * seconds)
1096 HildonTimeEditorPrivate *priv;
1098 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1100 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1102 ticks_to_time (hildon_time_editor_get_ticks (editor),
1103 hours, minutes, seconds);
1107 * hildon_time_editor_set_duration_range:
1108 * @editor: the #HildonTimeEditor widget
1109 * @min_seconds: minimum allowed time in seconds
1110 * @max_seconds: maximum allowed time in seconds
1112 * Sets the duration editor time range of the #HildonTimeEditor widget.
1115 void hildon_time_editor_set_duration_range(HildonTimeEditor * editor,
1119 HildonTimeEditorPrivate *priv;
1122 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1124 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1125 /* Swap values if reversed */
1126 if (min_seconds > max_seconds)
1129 max_seconds = min_seconds;
1133 hildon_time_editor_set_duration_max (editor, max_seconds);
1134 hildon_time_editor_set_duration_min (editor, min_seconds);
1136 if (priv->duration_mode) {
1137 /* Set minimum allowed value for duration editor.
1138 FIXME: Shouldn't it be changed only if it's not in range?
1139 Would change API, so won't touch this for now. */
1140 hildon_time_editor_set_ticks(editor, min_seconds);
1145 * hildon_time_editor_get_duration_range:
1146 * @editor: the #HildonTimeEditor widget
1147 * @min_seconds: pointer to guint
1148 * @max_seconds: pointer to guint
1150 * Gets the duration editor time range of the #HildonTimeEditor widget.
1153 void hildon_time_editor_get_duration_range(HildonTimeEditor * editor,
1154 guint * min_seconds,
1155 guint * max_seconds)
1157 HildonTimeEditorPrivate *priv;
1159 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1161 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1163 *min_seconds = priv->duration_min;
1164 *max_seconds = priv->duration_max;
1167 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor)
1169 HildonTimeEditorPrivate *priv;
1171 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1173 /* Update time separator symbols */
1174 get_time_separators(priv);
1176 /* Get AM/PM symbols. We want to show them in lowercase. */
1177 priv->am_symbol = g_ascii_strdown(nl_langinfo(AM_STR), -1);
1178 priv->pm_symbol = g_ascii_strdown(nl_langinfo(PM_STR), -1);
1180 if (priv->am_symbol[0] == '\0')
1183 /* 12h clock mode. Check if AM/PM should be before or after time.
1184 %p is the AM/PM string, so we assume that if the format string
1185 begins with %p it's in the beginning, and in any other case it's
1186 in the end (although that's not necessarily the case). */
1187 if (strncmp(nl_langinfo(T_FMT_AMPM), "%p", 2) == 0)
1188 priv->ampm_pos_after = FALSE;
1193 static gboolean hildon_time_editor_entry_focusin(GtkWidget * widget,
1194 GdkEventFocus * event,
1197 /* If we were trying to move away from a field with invalid value,
1198 we get moved back to it. Here we want to select the text in the field.
1199 The !button check checks that the entry wasn't focused with a mouse
1202 The selection happens temporarily if we got here with left/right
1203 keys, but it gets immediately unselected within same call due to some
1204 inner entry/clipboard magic. */
1205 if (!GTK_ENTRY(widget)->button)
1206 gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
1211 /* Returns negative if we didn't get value,
1212 * and should stop further validation
1214 static gint validated_conversion(HildonTimeEditorPrivate *priv,
1218 gboolean allow_intermediate,
1219 GString *error_string)
1225 text = gtk_entry_get_text(GTK_ENTRY(field));
1227 if (text && text[0])
1229 /* Try to convert entry text to number */
1230 value = strtol(text, &tail, 10);
1232 /* Check if conversion succeeded */
1236 g_string_printf(error_string, _("ckct_ib_maximum_value"), max);
1237 priv->error_widget = field;
1240 if (value < min && !allow_intermediate) {
1241 g_string_printf(error_string, _("ckct_ib_minimum_value"), min);
1242 priv->error_widget = field;
1248 /* We'll handle failed conversions soon */
1250 else if (allow_intermediate)
1251 return -1; /* Empty field while user is still editing. No error, but
1252 cannot validate either... */
1254 /* Empty field and not allowed intermediated OR failed conversion */
1255 g_string_printf(error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1256 priv->error_widget = field;
1261 hildon_time_editor_real_validate(HildonTimeEditor *editor,
1262 gboolean allow_intermediate, GString *error_string)
1264 HildonTimeEditorPrivate *priv;
1265 guint h, m, s, ticks;
1266 guint max_hours, min_hours, max_minutes, min_minutes, max_seconds, min_seconds;
1268 g_assert(HILDON_IS_TIME_EDITOR(editor));
1270 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1272 /* Find limits for field based validation. */
1273 if (priv->duration_mode)
1275 ticks_to_time(priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1276 ticks_to_time(priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1278 if (priv->clock_24h) {
1279 max_hours = HOURS_MAX_24;
1280 min_hours = HOURS_MIN_24;
1282 max_hours = HOURS_MAX_12;
1283 min_hours = HOURS_MIN_12;
1287 /* Get time components from fields and validate them... */
1288 if (priv->show_hours) {
1289 h = validated_conversion(priv, priv->entries[ENTRY_HOURS], min_hours, max_hours,
1290 allow_intermediate, error_string);
1291 if ((gint) h < 0) return;
1294 m = validated_conversion(priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX,
1295 allow_intermediate, error_string);
1296 if ((gint) m < 0) return;
1297 if (priv->show_seconds) {
1298 s = validated_conversion(priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX,
1299 allow_intermediate, error_string);
1300 if ((gint) s < 0) return;
1304 /* Ok, we now do separate check that tick count is valid for duration mode */
1305 if (priv->duration_mode)
1307 ticks = TICKS(h, m, s);
1309 if (ticks < priv->duration_min && !allow_intermediate)
1311 g_string_printf(error_string,
1312 _("ckct_ib_min_allowed_duration_hts"),
1313 min_hours, min_minutes, min_seconds);
1314 hildon_time_editor_set_ticks (editor, priv->duration_min);
1315 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1318 else if (ticks > priv->duration_max)
1320 g_string_printf(error_string,
1321 _("ckct_ib_max_allowed_duration_hts"),
1322 max_hours, max_minutes, max_seconds);
1323 hildon_time_editor_set_ticks (editor, priv->duration_max);
1324 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1328 else if (!priv->clock_24h)
1329 convert_to_24h (&h, priv->am);
1331 /* The only case when we do not want to refresh the
1332 time display, is when the user is editing a value
1333 (unless the value was out of bounds and we have to fix it) */
1334 if (!allow_intermediate || priv->error_widget)
1335 hildon_time_editor_set_time (editor, h, m, s);
1338 /* Setting text to entries causes entry to recompute itself
1339 in idle callback, which remove selection. Because of this
1340 we need to do selection in idle as well. */
1341 static gboolean highlight_callback(gpointer data)
1343 HildonTimeEditorPrivate *priv;
1346 GDK_THREADS_ENTER ();
1348 g_assert(HILDON_IS_TIME_EDITOR(data));
1350 priv = HILDON_TIME_EDITOR_GET_PRIVATE(data);
1351 widget = priv->error_widget;
1352 priv->error_widget = NULL;
1353 priv->highlight_idle = 0;
1355 g_assert(GTK_IS_ENTRY(widget));
1357 /* Grabbing focus can cause re-validation, priv->error widget
1358 can be set to something else, including NULL */
1359 gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
1360 gtk_widget_grab_focus(widget);
1362 GDK_THREADS_LEAVE ();
1367 /* Update ticks from current H:M:S entries. If they're invalid, show an
1368 infoprint and update the fields unless they're empty. */
1370 hildon_time_editor_validate (HildonTimeEditor *editor, gboolean allow_intermediate)
1372 HildonTimeEditorPrivate *priv;
1373 GString *error_message;
1375 g_assert(HILDON_IS_TIME_EDITOR(editor));
1377 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1378 priv->error_widget = NULL;
1380 error_message = g_string_new(NULL);
1381 hildon_time_editor_real_validate(editor,
1382 allow_intermediate, error_message);
1384 if (priv->error_widget) {
1385 hildon_banner_show_information(priv->error_widget, NULL,
1386 error_message->str);
1387 if (priv->highlight_idle == 0)
1388 priv->highlight_idle = g_idle_add(highlight_callback, editor);
1390 g_string_free(error_message, TRUE);
1393 /* on inserted text, if entry has two digits, jumps to the next field. */
1395 hildon_time_editor_inserted_text (GtkEditable * editable,
1397 gint new_text_length,
1401 HildonTimeEditor *editor;
1405 entry = GTK_ENTRY(editable);
1406 editor = HILDON_TIME_EDITOR(user_data);
1408 value = (gchar *) gtk_entry_get_text(entry);
1410 if (strlen(value) == 2)
1412 HildonTimeEditorPrivate *priv;
1414 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1416 if (GTK_WIDGET(editable) == priv->entries[ENTRY_HOURS])
1418 gtk_widget_grab_focus(priv->entries[ENTRY_MINS]);
1421 else if (GTK_WIDGET(editable) == priv->entries[ENTRY_MINS])
1423 gtk_widget_grab_focus(priv->entries[ENTRY_SECS]);
1429 static gboolean hildon_time_editor_entry_focusout(GtkWidget * widget,
1430 GdkEventFocus * event,
1433 g_assert(HILDON_IS_TIME_EDITOR(data));
1435 /* Validate the given time and update ticks. */
1436 hildon_time_editor_validate(HILDON_TIME_EDITOR(data), FALSE);
1442 hildon_time_editor_ampm_clicked(GtkWidget * widget,
1443 GdkEventButton * event, gpointer data)
1445 HildonTimeEditor *editor;
1446 HildonTimeEditorPrivate *priv;
1448 g_assert(GTK_IS_WIDGET(widget));
1449 g_assert(HILDON_IS_TIME_EDITOR(data));
1451 editor = HILDON_TIME_EDITOR(data);
1452 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1454 /* First validate the given time and update ticks. */
1455 hildon_time_editor_validate (editor, FALSE);
1457 /* Apply the AM/PM change by moving the current time by 12 hours */
1459 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1460 hildon_time_editor_set_ticks (editor, priv->ticks + 12*3600);
1462 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1463 hildon_time_editor_set_ticks (editor, priv->ticks - 12*3600);
1469 hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
1471 HildonTimeEditor *editor;
1474 guint h, m, s, result;
1476 g_assert(HILDON_IS_TIME_EDITOR(data));
1478 editor = HILDON_TIME_EDITOR(data);
1480 /* icon is passive in duration editor mode */
1481 if (hildon_time_editor_get_duration_mode(editor))
1484 /* Launch HildonTimePicker dialog */
1485 parent = gtk_widget_get_ancestor(GTK_WIDGET(editor), GTK_TYPE_WINDOW);
1486 picker = hildon_time_picker_new(GTK_WINDOW(parent));
1488 hildon_time_editor_get_time(editor, &h, &m, &s);
1489 hildon_time_picker_set_time(HILDON_TIME_PICKER(picker), h, m);
1491 result = gtk_dialog_run(GTK_DIALOG(picker));
1493 case GTK_RESPONSE_OK:
1494 case GTK_RESPONSE_ACCEPT:
1495 /* Use the selected time */
1496 hildon_time_picker_get_time(HILDON_TIME_PICKER(picker), &h, &m);
1497 hildon_time_editor_set_time(editor, h, m, 0);
1503 gtk_widget_destroy(picker);
1507 static gboolean hildon_time_editor_entry_clicked(GtkWidget * widget,
1508 GdkEventButton * event,
1511 HildonTimeEditor *editor;
1512 HildonTimeEditorPrivate *priv;
1514 editor = HILDON_TIME_EDITOR (data);
1515 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1517 /* If the focus has been grabbed back before the "clicked"
1518 * signal gets processed, don't highlight the text.
1519 * This happens when input in one H:M:S field is invalid and we're
1520 * trying to move to another field. The focus moves back to the invalid
1523 if (gtk_widget_is_focus (widget))
1524 gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
1529 static void hildon_time_editor_size_request(GtkWidget * widget,
1530 GtkRequisition * requisition)
1532 HildonTimeEditor *editor;
1533 HildonTimeEditorPrivate *priv;
1536 editor = HILDON_TIME_EDITOR(widget);
1537 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1539 /* Get frame's size */
1540 gtk_widget_size_request(priv->frame, requisition);
1542 if (GTK_WIDGET_VISIBLE(priv->iconbutton))
1544 gtk_widget_size_request(priv->iconbutton, &req);
1545 /* Reserve space for icon */
1546 requisition->width += req.width + ICON_PRESSED +
1547 HILDON_MARGIN_DEFAULT;
1550 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1551 want to force this since themes might have varying thickness values
1552 which cause the height to change. */
1553 requisition->height = TIME_EDITOR_HEIGHT;
1556 static void hildon_time_editor_size_allocate(GtkWidget * widget,
1557 GtkAllocation * allocation)
1559 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
1560 GtkAllocation alloc;
1561 GtkRequisition req, max_req;
1563 widget->allocation = *allocation;
1564 gtk_widget_get_child_requisition(widget, &max_req);
1566 /* Center horizontally */
1567 alloc.x = allocation->x + MAX(allocation->width - max_req.width, 0) / 2;
1568 /* Center vertically */
1569 alloc.y = allocation->y + MAX(allocation->height - max_req.height, 0) / 2;
1571 /* allocate frame */
1572 gtk_widget_get_child_requisition(priv->frame, &req);
1574 alloc.width = req.width;
1575 alloc.height = max_req.height;
1576 gtk_widget_size_allocate(priv->frame, &alloc);
1579 if (GTK_WIDGET_VISIBLE(priv->iconbutton)) {
1580 gtk_widget_get_child_requisition(priv->iconbutton, &req);
1582 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1583 alloc.width = req.width;
1584 gtk_widget_size_allocate(priv->iconbutton, &alloc);
1587 /* FIXME: ugly way to move labels up. They just don't seem move up
1588 otherwise. This is likely because we force the editor to be
1589 smaller than it otherwise would be. */
1590 alloc = priv->ampm_label->allocation;
1591 alloc.y = allocation->y - 2;
1592 alloc.height = max_req.height + 2;
1593 gtk_widget_size_allocate(priv->ampm_label, &alloc);
1595 alloc = priv->hm_label->allocation;
1596 alloc.y = allocation->y - 2;
1597 alloc.height = max_req.height + 2;
1598 gtk_widget_size_allocate(priv->hm_label, &alloc);
1600 alloc = priv->sec_label->allocation;
1601 alloc.y = allocation->y - 2;
1602 alloc.height = max_req.height + 2;
1603 gtk_widget_size_allocate(priv->sec_label, &alloc);
1606 static gboolean hildon_time_editor_entry_keypress(GtkWidget * widget,
1607 GdkEventKey * event,
1610 HildonTimeEditor *editor;
1611 HildonTimeEditorPrivate *priv;
1614 g_assert(GTK_IS_ENTRY(widget));
1615 g_assert(event != NULL);
1616 g_assert(HILDON_IS_TIME_EDITOR(data));
1618 editor = HILDON_TIME_EDITOR(data);
1619 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1620 cursor_pos = gtk_editable_get_position(GTK_EDITABLE(widget));
1622 switch (event->keyval)
1625 /* Return key popups up time picker dialog. Visually it looks as if
1626 the time picker icon was clicked. Before opening the time picker
1627 the fields are first validated and fixed. */
1628 hildon_time_editor_validate (editor, FALSE);
1629 hildon_gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), TRUE);
1630 hildon_time_editor_icon_clicked(widget, data);
1631 hildon_gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), FALSE);
1635 /* left arrow pressed in the entry. If we are on first position, try to
1636 move to the previous field. */
1637 if (cursor_pos == 0) {
1638 (void) gtk_widget_child_focus(GTK_WIDGET(editor), GTK_DIR_LEFT);
1644 /* right arrow pressed in the entry. If we are on last position, try to
1645 move to the next field. */
1646 if (cursor_pos >= g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(widget)), -1)) {
1647 (void) gtk_widget_child_focus(GTK_WIDGET(editor), GTK_DIR_RIGHT);
1664 convert_to_12h (guint *h, gboolean *am)
1666 g_assert(0 <= *h && *h < 24);
1668 /* 00:00 to 00:59 add 12 hours */
1669 /* 01:00 to 11:59 straight to am */
1670 /* 12:00 to 12:59 straight to pm */
1671 /* 13:00 to 23:59 subtract 12 hours */
1673 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1674 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1675 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1676 else { *am = FALSE; *h -= 12;}
1680 convert_to_24h (guint *h, gboolean am)
1682 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1686 else if (!am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1693 * hildon_time_editor_set_show_hours:
1694 * @editor: The #HildonTimeEditor.
1695 * @enable: Enable or disable showing of hours.
1697 * This function shows or hides the hours field.
1701 void hildon_time_editor_set_show_hours(HildonTimeEditor * editor,
1702 gboolean show_hours)
1704 HildonTimeEditorPrivate *priv;
1706 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1708 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1710 if (show_hours != priv->show_hours) {
1711 priv->show_hours = show_hours;
1713 /* show/hide hours field and its ':' label if the value changed. */
1715 gtk_widget_show(priv->entries[ENTRY_HOURS]);
1716 gtk_widget_show(priv->hm_label);
1718 gtk_widget_hide(priv->entries[ENTRY_HOURS]);
1719 gtk_widget_hide(priv->hm_label);
1722 g_object_notify (G_OBJECT (editor), "show_hours");
1727 * hildon_time_editor_get_show_hours:
1728 * @self: the @HildonTimeEditor widget.
1730 * This function returns a boolean indicating the visibility of
1731 * hours in the @HildonTimeEditor
1733 * Return value: TRUE if hours are visible.
1737 gboolean hildon_time_editor_get_show_hours(HildonTimeEditor *editor)
1739 HildonTimeEditorPrivate *priv;
1741 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1742 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1744 return priv->show_hours;
1748 * Deprecated functions
1752 * hildon_time_editor_show_seconds:
1753 * @editor: the #HildonTimeEditor
1754 * @enable: enable or disable showing of seconds
1756 * This function is deprecated,
1757 * use #hildon_time_editor_set_show_seconds instead.
1759 void hildon_time_editor_show_seconds(HildonTimeEditor * editor,
1762 hildon_time_editor_set_show_seconds (editor, enable);
1765 * hildon_time_editor_enable_duration_mode:
1766 * @editor: the #HildonTimeEditor
1767 * @enable: enable or disable duration editor mode
1769 * This function is deprecated,
1770 * use #hildon_time_editor_set_duration_mode instead.
1772 void hildon_time_editor_enable_duration_mode(HildonTimeEditor * editor,
1775 hildon_time_editor_set_duration_mode (editor, enable);