2 * This file is a part of hildon
4 * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
6 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@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; version 2.1 of
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 "hildon-time-editor.h"
43 #include <gtk/gtkhbox.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>
54 #include "hildon-defines.h"
55 #include "hildon-time-picker.h"
56 #include "hildon-banner.h"
57 #include "hildon-input-mode-hint.h"
58 #include "hildon-private.h"
59 #include "hildon-marshalers.h"
60 #include "hildon-enum-types.h"
61 #include "hildon-time-editor-private.h"
63 #define _(String) dgettext(PACKAGE, String)
65 #define TICKS(h,m,s) \
66 ((h) * 3600 + (m) * 60 + (s))
68 #define TIME_EDITOR_HEIGHT 30
70 #define ICON_PRESSED 4
72 #define ICON_NAME "qgn_widg_timedit"
74 #define ICON_SIZE "timepicker-size"
76 #define MIN_DURATION 0
78 #define MAX_DURATION TICKS(99, 59, 59)
80 /* Default values for properties */
82 #define HILDON_TIME_EDITOR_TICKS_VALUE 0
84 #define HILDON_TIME_EDITOR_DURATION_MODE FALSE
86 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE 0
88 #define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE TICKS(99, 59, 59)
90 #define HOURS_MAX_24 23
92 #define HOURS_MAX_12 12
94 #define HOURS_MIN_24 0
96 #define HOURS_MIN_12 1
98 #define MINUTES_MAX 59
100 #define SECONDS_MAX 59
102 #define MINUTES_MIN 0
104 #define SECONDS_MIN 0
106 static GtkContainerClass* parent_class;
125 /* Error codes categories */
133 static guint time_editor_signals[LAST_SIGNAL] = { 0 };
135 static guint hour_errors[NUM_ERROR_CODES] = {
136 HILDON_DATE_TIME_ERROR_MAX_HOURS,
137 HILDON_DATE_TIME_ERROR_MIN_HOURS,
138 HILDON_DATE_TIME_ERROR_EMPTY_HOURS };
140 static guint min_errors[NUM_ERROR_CODES] = {
141 HILDON_DATE_TIME_ERROR_MAX_MINS,
142 HILDON_DATE_TIME_ERROR_MIN_MINS,
143 HILDON_DATE_TIME_ERROR_EMPTY_MINS };
145 static guint sec_errors[NUM_ERROR_CODES] = {
146 HILDON_DATE_TIME_ERROR_MAX_SECS,
147 HILDON_DATE_TIME_ERROR_MIN_SECS,
148 HILDON_DATE_TIME_ERROR_EMPTY_SECS };
151 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class);
154 hildon_time_editor_init (HildonTimeEditor *editor);
157 hildon_time_editor_finalize (GObject *obj_self);
160 hildon_time_editor_set_property (GObject *object,
166 hildon_time_editor_get_property (GObject *object,
172 hildon_time_editor_forall (GtkContainer *container,
173 gboolean include_internals,
174 GtkCallback callback,
175 gpointer callback_data);
178 hildon_time_editor_destroy (GtkObject *self);
181 hildon_time_editor_entry_focus_out (GtkWidget *widget,
182 GdkEventFocus *event,
186 hildon_time_editor_entry_focus_in (GtkWidget *widget,
187 GdkEventFocus *event,
191 hildon_time_editor_time_error (HildonTimeEditor *editor,
192 HildonDateTimeError type);
195 hildon_time_editor_ampm_clicked (GtkWidget *widget,
199 hildon_time_editor_icon_clicked (GtkWidget *widget,
203 hildon_time_editor_size_request (GtkWidget *widget,
204 GtkRequisition *requisition);
207 hildon_time_editor_size_allocate (GtkWidget *widget,
208 GtkAllocation *allocation);
211 hildon_time_editor_entry_keypress (GtkWidget *widget,
216 hildon_time_editor_check_locale (HildonTimeEditor *editor);
219 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
222 GtkWidgetTapAndHoldFlags flags);
224 hildon_time_editor_validate (HildonTimeEditor *editor,
225 gboolean allow_intermediate);
228 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor);
231 hildon_time_editor_entry_select_all (GtkWidget *widget);
234 convert_to_12h (guint *h,
238 convert_to_24h (guint *h,
242 ticks_to_time (guint ticks,
248 hildon_time_editor_inserted_text (GtkEditable *editable,
250 gint new_text_length,
255 hildon_time_editor_get_type (void)
257 static GType editor_type = 0;
260 static const GTypeInfo editor_info = {
261 sizeof(HildonTimeEditorClass),
262 NULL, /* base_init */
263 NULL, /* base_finalize */
264 (GClassInitFunc) hildon_time_editor_class_init,
265 NULL, /* class_finalize */
266 NULL, /* class_data */
267 sizeof(HildonTimeEditor),
269 (GInstanceInitFunc) hildon_time_editor_init,
271 editor_type = g_type_register_static (GTK_TYPE_CONTAINER,
280 hildon_time_editor_forall (GtkContainer *container,
281 gboolean include_internals,
282 GtkCallback callback,
283 gpointer callback_data)
285 HildonTimeEditorPrivate *priv;
287 g_assert (HILDON_IS_TIME_EDITOR (container));
288 g_assert (callback != NULL);
290 priv = HILDON_TIME_EDITOR_GET_PRIVATE (container);
294 if (! include_internals)
297 /* widget that are always shown */
298 (*callback) (priv->iconbutton, callback_data);
299 (*callback) (priv->frame, callback_data);
303 hildon_time_editor_destroy (GtkObject *self)
305 HildonTimeEditorPrivate *priv;
307 priv = HILDON_TIME_EDITOR_GET_PRIVATE (self);
310 if (priv->iconbutton) {
311 gtk_widget_unparent (priv->iconbutton);
312 priv->iconbutton = NULL;
315 gtk_widget_unparent (priv->frame);
319 if (GTK_OBJECT_CLASS (parent_class)->destroy)
320 GTK_OBJECT_CLASS (parent_class)->destroy (self);
324 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class)
326 GObjectClass *object_class = G_OBJECT_CLASS (editor_class);
327 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (editor_class);
328 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (editor_class);
330 parent_class = g_type_class_peek_parent (editor_class);
332 g_type_class_add_private (editor_class, sizeof (HildonTimeEditorPrivate));
334 object_class->get_property = hildon_time_editor_get_property;
335 object_class->set_property = hildon_time_editor_set_property;
336 widget_class->size_request = hildon_time_editor_size_request;
337 widget_class->size_allocate = hildon_time_editor_size_allocate;
338 widget_class->tap_and_hold_setup = hildon_time_editor_tap_and_hold_setup;
339 widget_class->focus = hildon_private_composite_focus;
341 container_class->forall = hildon_time_editor_forall;
342 GTK_OBJECT_CLASS (editor_class)->destroy = hildon_time_editor_destroy;
344 object_class->finalize = hildon_time_editor_finalize;
346 editor_class->time_error = hildon_time_editor_time_error;
348 time_editor_signals[TIME_ERROR] =
349 g_signal_new ("time-error",
350 G_OBJECT_CLASS_TYPE (object_class),
352 G_STRUCT_OFFSET (HildonTimeEditorClass, time_error),
353 g_signal_accumulator_true_handled, NULL,
354 _hildon_marshal_BOOLEAN__ENUM,
355 G_TYPE_BOOLEAN, 1, HILDON_TYPE_DATE_TIME_ERROR);
358 * HildonTimeEditor:ticks:
360 * If editor is in duration mode, contains the duration seconds.
361 * If not, contains seconds since midnight.
363 g_object_class_install_property (object_class, PROP_TICKS,
364 g_param_spec_uint ("ticks",
366 "Current value of duration",
368 HILDON_TIME_EDITOR_TICKS_VALUE,
369 G_PARAM_READABLE | G_PARAM_WRITABLE) );
372 * HildonTimeEditor:show_seconds:
374 * Controls whether seconds are shown in the editor
376 g_object_class_install_property (object_class, PROP_SHOW_SECONDS,
377 g_param_spec_boolean ("show_seconds",
378 "Show seconds property",
379 "Controls whether the seconds are shown in the editor",
381 G_PARAM_READABLE | G_PARAM_WRITABLE) );
384 * HildonTimeEditor:show_hours:
386 * Controls whether hours are shown in the editor
388 g_object_class_install_property (object_class, PROP_SHOW_HOURS,
389 g_param_spec_boolean ("show_hours",
391 "Controls whether the hours field is shown in the editor",
393 G_PARAM_READABLE | G_PARAM_WRITABLE) );
396 * HildonTimeEditor:duration_mode:
398 * Controls whether the TimeEditor is in duration mode
400 g_object_class_install_property (object_class, PROP_DURATION_MODE,
401 g_param_spec_boolean ("duration_mode",
403 "Controls whether the TimeEditor is in duration mode",
404 HILDON_TIME_EDITOR_DURATION_MODE,
405 G_PARAM_READABLE | G_PARAM_WRITABLE) );
408 * HildonTimeEditor:duration_min:
410 * Minimum allowed duration value.
412 g_object_class_install_property (object_class, PROP_DURATION_MIN,
413 g_param_spec_uint ("duration_min",
414 "Minumum duration value",
415 "Smallest possible duration value",
416 MIN_DURATION, MAX_DURATION,
417 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
418 G_PARAM_READABLE | G_PARAM_WRITABLE) );
421 * HildonTimeEditor:duration_max:
423 * Maximum allowed duration value.
425 g_object_class_install_property (object_class, PROP_DURATION_MAX,
426 g_param_spec_uint ("duration_max",
427 "Maximum duration value",
428 "Largest possible duration value",
430 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
431 G_PARAM_READABLE | G_PARAM_WRITABLE) );
435 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
438 GtkWidgetTapAndHoldFlags flags)
440 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
443 /* Forward this tap_and_hold_setup signal to all our child widgets */
444 for (i = 0; i < ENTRY_COUNT; i++)
446 gtk_widget_tap_and_hold_setup (priv->entries[i], menu, func,
447 GTK_TAP_AND_HOLD_NO_SIGNALS);
449 gtk_widget_tap_and_hold_setup (priv->ampm_button, menu, func,
450 GTK_TAP_AND_HOLD_NO_SIGNALS);
451 gtk_widget_tap_and_hold_setup (priv->iconbutton, menu, func,
452 GTK_TAP_AND_HOLD_NONE);
456 hildon_time_editor_entry_changed (GtkWidget *widget,
459 g_assert (HILDON_IS_TIME_EDITOR (data));
460 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), TRUE);
464 hildon_time_editor_init (HildonTimeEditor *editor)
466 HildonTimeEditorPrivate *priv;
467 GtkWidget *hbox, *icon;
470 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
473 gtk_widget_push_composite_child ();
475 /* Setup defaults and create widgets */
477 priv->show_seconds = FALSE;
478 priv->show_hours = TRUE;
479 priv->ampm_pos_after = TRUE;
480 priv->clock_24h = TRUE;
481 priv->duration_mode = FALSE;
482 priv->iconbutton = gtk_button_new();
483 priv->ampm_label = gtk_label_new(NULL);
484 priv->hm_label = gtk_label_new(NULL);
485 priv->sec_label = gtk_label_new(NULL);
486 priv->frame = gtk_frame_new(NULL);
487 priv->ampm_button = gtk_button_new();
488 priv->skipper = FALSE;
490 icon = gtk_image_new_from_icon_name (ICON_NAME, HILDON_ICON_SIZE_WIDG);
491 hbox = gtk_hbox_new (FALSE, 0);
493 GTK_WIDGET_SET_FLAGS (editor, GTK_NO_WINDOW);
494 GTK_WIDGET_UNSET_FLAGS (priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
496 gtk_container_set_border_width (GTK_CONTAINER(priv->frame), 0);
498 gtk_container_add (GTK_CONTAINER (priv->iconbutton), icon);
499 gtk_container_add (GTK_CONTAINER (priv->ampm_button), priv->ampm_label);
500 gtk_button_set_relief(GTK_BUTTON (priv->ampm_button), GTK_RELIEF_NONE);
501 gtk_button_set_focus_on_click (GTK_BUTTON (priv->ampm_button), FALSE);
503 /* Create hour, minute and second entries */
504 for (i = 0; i < ENTRY_COUNT; i++)
506 priv->entries[i] = gtk_entry_new ();
508 /* No frames for entries, so that they all appear to be inside one long entry */
509 gtk_entry_set_has_frame (GTK_ENTRY (priv->entries[i]), FALSE);
511 /* Set the entries to accept only numeric characters */
512 g_object_set (priv->entries[i], "input-mode", HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
514 /* The entry fields all take exactly two characters */
515 gtk_entry_set_max_length (GTK_ENTRY (priv->entries[i]), 2);
516 gtk_entry_set_width_chars (GTK_ENTRY (priv->entries[i]), 2);
518 g_signal_connect (priv->entries[i], "focus-in-event",
519 G_CALLBACK (hildon_time_editor_entry_focus_in), editor);
520 g_signal_connect (priv->entries[i], "focus-out-event",
521 G_CALLBACK (hildon_time_editor_entry_focus_out), editor);
522 g_signal_connect (priv->entries[i], "key-press-event",
523 G_CALLBACK (hildon_time_editor_entry_keypress), editor);
524 g_signal_connect (priv->entries[i], "changed",
525 G_CALLBACK (hildon_time_editor_entry_changed), editor);
527 /* inserted signal sets time */
528 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
529 G_CALLBACK (hildon_time_editor_inserted_text),
533 /* clicked signal for am/pm label */
534 g_signal_connect (G_OBJECT (priv->ampm_button), "clicked",
535 G_CALLBACK (hildon_time_editor_ampm_clicked), editor);
537 /* clicked signal for icon */
538 g_signal_connect (G_OBJECT (priv->iconbutton), "clicked",
539 G_CALLBACK (hildon_time_editor_icon_clicked), editor);
541 /* Set ourself as the parent of all the widgets we created */
542 gtk_widget_set_parent (priv->iconbutton, GTK_WIDGET(editor));
543 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
544 gtk_box_pack_start (GTK_BOX (hbox), priv->hm_label, FALSE, FALSE, 0);
545 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
546 gtk_box_pack_start (GTK_BOX (hbox), priv->sec_label, FALSE, FALSE, 0);
547 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
548 gtk_box_pack_start (GTK_BOX (hbox), priv->ampm_button, FALSE, FALSE, 0);
549 gtk_misc_set_padding (GTK_MISC (priv->ampm_label), 0, 0);
551 gtk_container_add (GTK_CONTAINER (priv->frame), hbox);
553 /* Show created widgets */
554 gtk_widget_set_parent (priv->frame, GTK_WIDGET(editor));
555 gtk_widget_show_all (priv->frame);
556 gtk_widget_show_all (priv->iconbutton);
558 /* Update AM/PM and time separators settings from locale */
559 if (! hildon_time_editor_check_locale (editor)) {
560 /* Using 12h clock */
561 priv->clock_24h = FALSE;
563 gtk_widget_hide (priv->ampm_button);
566 if (! priv->show_seconds) {
567 gtk_widget_hide (priv->sec_label);
568 gtk_widget_hide (priv->entries[ENTRY_SECS]);
571 /* set the default time to current time. */
572 hildon_time_editor_set_to_current_time (editor);
574 gtk_widget_pop_composite_child ();
578 hildon_time_editor_set_property (GObject *object,
583 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
588 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
591 case PROP_SHOW_SECONDS:
592 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
595 case PROP_SHOW_HOURS:
596 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
599 case PROP_DURATION_MODE:
600 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
603 case PROP_DURATION_MIN:
604 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
607 case PROP_DURATION_MAX:
608 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
612 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
618 hildon_time_editor_get_property (GObject *object,
623 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
629 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
632 case PROP_SHOW_SECONDS:
633 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
636 case PROP_SHOW_HOURS:
637 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
640 case PROP_DURATION_MODE:
641 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
644 case PROP_DURATION_MIN:
645 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
648 case PROP_DURATION_MAX:
649 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
653 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
659 * hildon_time_editor_new:
661 * This function creates a new time editor.
663 * Returns: pointer to a new #HildonTimeEditor widget
666 hildon_time_editor_new (void)
668 return GTK_WIDGET (g_object_new (HILDON_TYPE_TIME_EDITOR, NULL));
672 hildon_time_editor_finalize (GObject *obj_self)
674 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (obj_self);
677 g_free (priv->am_symbol);
678 g_free (priv->pm_symbol);
680 if (priv->highlight_idle)
681 g_source_remove (priv->highlight_idle);
683 if (G_OBJECT_CLASS (parent_class)->finalize)
684 G_OBJECT_CLASS (parent_class)->finalize (obj_self);
688 * hildon_time_editor_get_time_separators:
689 * @editor: the #HildonTimeEditor
690 * @hm_sep_label: the label that will show the hour:minutes separator
691 * @ms_sep_label: the label that will show the minutes:seconds separator
693 * Gets hour-minute separator and minute-second separator from current
694 * locale and sets then to the labels we set as parameters. Both
695 * parameters can be NULL if you just want to assing one separator.
699 hildon_time_editor_get_time_separators (GtkLabel *hm_sep_label,
700 GtkLabel *ms_sep_label)
704 GDate locale_test_date;
705 gchar *iter, *endp = NULL;
707 /* Get localized time string */
708 g_date_set_dmy (&locale_test_date, 1, 2, 1970);
709 (void) g_date_strftime (buffer, sizeof (buffer), "%X", &locale_test_date);
711 if (hm_sep_label != NULL)
713 /* Find h-m separator */
715 while (*iter && g_ascii_isdigit (*iter)) iter++;
717 /* Extract h-m separator*/
719 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
720 separator = g_strndup (iter, endp - iter);
721 gtk_label_set_label (hm_sep_label, separator);
725 if (ms_sep_label != NULL)
727 /* Find m-s separator */
729 while (*iter && g_ascii_isdigit (*iter)) iter++;
731 /* Extract m-s separator*/
733 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
734 separator = g_strndup (iter, endp - iter);
735 gtk_label_set_label (ms_sep_label, separator);
740 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
742 ticks_to_time (guint ticks,
749 *hours = ticks / 3600;
751 *minutes = left / 60;
752 *seconds = left % 60;
756 * hildon_time_editor_set_ticks:
757 * @editor: the #HildonTimeEditor widget
758 * @ticks: the duration to set, in seconds
760 * Sets the current duration in seconds. This means seconds from
761 * midnight, if not in duration mode. In case of any errors, it tries
766 hildon_time_editor_set_ticks (HildonTimeEditor *editor,
769 HildonTimeEditorPrivate *priv;
773 g_assert (HILDON_IS_TIME_EDITOR (editor));
775 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
778 /* Validate ticks. If it's too low or too high, set it to
779 min/max value for the current mode. */
780 if (priv->duration_mode)
781 priv->ticks = CLAMP (ticks, priv->duration_min, priv->duration_max);
783 /* Check that ticks value is valid. We only need to check that hours
785 ticks_to_time (ticks, &h, &m, &s);
786 if (h > HOURS_MAX_24)
787 ticks = TICKS(HOURS_MAX_24, m, s);
792 /* Get the time in H:M:S. */
793 ticks_to_time (priv->ticks, &h, &m, &s);
795 if (!priv->clock_24h && ! priv->duration_mode)
797 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
798 convert_to_12h (&h, &priv->am);
801 /* Set H:M:S values to entries. We do not want to invoke validation
802 callbacks (since they can cause new call to this function), so we
803 block signals while setting values. */
804 for (i = 0; i < ENTRY_COUNT; i++)
806 g_signal_handlers_block_by_func(priv->entries[i],
807 (gpointer) hildon_time_editor_entry_changed, editor);
809 g_signal_handlers_block_by_func(priv->entries[i],
810 (gpointer) hildon_time_editor_inserted_text, editor);
812 g_signal_handlers_block_by_func(priv->entries[i],
813 (gpointer) hildon_time_editor_entry_focus_out, editor);
816 g_snprintf (str, sizeof (str), "%02u", h);
817 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_HOURS]), str);
819 g_snprintf(str, sizeof (str), "%02u", m);
820 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_MINS]), str);
822 g_snprintf(str, sizeof (str), "%02u", s);
823 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_SECS]), str);
825 for (i = 0; i < ENTRY_COUNT; i++)
827 g_signal_handlers_unblock_by_func (priv->entries[i],
828 (gpointer) hildon_time_editor_entry_changed, editor);
830 g_signal_handlers_unblock_by_func (priv->entries[i],
831 (gpointer) hildon_time_editor_inserted_text, editor);
833 g_signal_handlers_unblock_by_func (priv->entries[i],
834 (gpointer) hildon_time_editor_entry_focus_out, editor);
837 /* Update AM/PM label in case we're in 12h mode */
838 gtk_label_set_label( GTK_LABEL (priv->ampm_label),
839 priv->am ? priv->am_symbol : priv->pm_symbol);
841 g_object_notify (G_OBJECT (editor), "ticks");
845 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor)
851 tm = localtime (&now);
854 hildon_time_editor_set_time (editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
858 * hildon_time_editor_get_ticks:
859 * @editor: the #HildonTimeEditor widget
861 * This function returns the current duration, in seconds.
862 * This means seconds from midnight, if not in duration mode.
864 * Returns: current duration in seconds
867 hildon_time_editor_get_ticks (HildonTimeEditor *editor)
869 HildonTimeEditorPrivate *priv;
871 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
873 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
876 return (priv->ticks);
880 * hildon_time_editor_set_show_seconds:
881 * @editor: the #HildonTimeEditor
882 * @show_seconds: enable or disable showing of seconds
884 * This function shows or hides the seconds field.
887 hildon_time_editor_set_show_seconds (HildonTimeEditor *editor,
888 gboolean show_seconds)
890 HildonTimeEditorPrivate *priv;
892 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
894 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
897 if (show_seconds != priv->show_seconds) {
898 priv->show_seconds = show_seconds;
900 /* show/hide seconds field and its ':' label if the value changed. */
902 gtk_widget_show (priv->entries[ENTRY_SECS]);
903 gtk_widget_show (priv->sec_label);
905 gtk_widget_hide (priv->entries[ENTRY_SECS]);
906 gtk_widget_hide (priv->sec_label);
909 g_object_notify (G_OBJECT (editor), "show_seconds");
914 * hildon_time_editor_get_show_seconds:
915 * @editor: the #HildonTimeEditor widget
917 * This function returns a boolean indicating the visibility of
918 * seconds in the #HildonTimeEditor
920 * Returns: TRUE if the seconds are visible
923 hildon_time_editor_get_show_seconds (HildonTimeEditor *editor)
925 HildonTimeEditorPrivate *priv;
927 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
928 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
931 return (priv->show_seconds);
935 * hildon_time_editor_set_duration_mode:
936 * @editor: the #HildonTimeEditor
937 * @duration_mode: enable or disable duration editor mode
939 * This function sets the duration editor mode in which the maximum hours
943 hildon_time_editor_set_duration_mode (HildonTimeEditor *editor,
944 gboolean duration_mode)
946 HildonTimeEditorPrivate *priv;
948 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
950 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
953 if (duration_mode != priv->duration_mode) {
954 priv->duration_mode = duration_mode;
957 /* FIXME: Why do we reset the duration range here?
958 Would change API, so won't touch this for now. */
959 hildon_time_editor_set_duration_range (editor, MIN_DURATION, MAX_DURATION);
960 /* There's no AM/PM label or time picker icon in duration mode.
961 Make sure they're hidden. */
962 gtk_widget_hide (GTK_WIDGET (priv->ampm_label));
963 gtk_widget_hide (GTK_WIDGET (priv->ampm_button));
964 gtk_widget_hide (GTK_WIDGET (priv->iconbutton));
965 /* Duration mode has seconds by default. */
966 hildon_time_editor_set_show_seconds (editor, TRUE);
968 /* Make sure AM/PM label and time picker icons are visible if needed */
969 if (! priv->clock_24h)
970 gtk_widget_show (GTK_WIDGET (priv->ampm_label));
972 gtk_widget_show (GTK_WIDGET (priv->ampm_button));
973 gtk_widget_show (GTK_WIDGET (priv->iconbutton));
975 /* Reset the ticks to current time. Anything set in duration mode
976 * is bound to be invalid or useless in time mode.
978 hildon_time_editor_set_to_current_time (editor);
981 g_object_notify (G_OBJECT (editor), "duration_mode");
986 * hildon_time_editor_get_duration_mode:
987 * @editor: the #HildonTimeEditor widget
989 * This function returns a boolean indicating whether the #HildonTimeEditor
990 * is in the duration mode.
992 * Returns: TRUE if the #HildonTimeEditor is in duration mode
995 hildon_time_editor_get_duration_mode (HildonTimeEditor *editor)
997 HildonTimeEditorPrivate *priv;
999 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1000 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1003 return (priv->duration_mode);
1007 * hildon_time_editor_set_duration_min:
1008 * @editor: the #HildonTimeEditor widget
1009 * @duration_min: mimimum allowed duration
1011 * Sets the minimum allowed duration for the duration mode.
1012 * Note: Has no effect in time mode
1015 hildon_time_editor_set_duration_min (HildonTimeEditor *editor,
1018 HildonTimeEditorPrivate *priv;
1020 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1021 g_return_if_fail (duration_min >= MIN_DURATION);
1023 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1026 if (! priv->duration_mode )
1029 priv->duration_min = duration_min;
1031 /* Clamp the current value to the minimum if necessary */
1032 if (priv->ticks < duration_min)
1034 hildon_time_editor_set_ticks (editor, duration_min);
1037 g_object_notify (G_OBJECT (editor), "duration_min");
1041 * hildon_time_editor_get_duration_min:
1042 * @editor: the #HildonTimeEditor widget
1044 * This function returns the smallest duration the #HildonTimeEditor
1045 * allows in the duration mode.
1047 * Returns: minimum allowed duration in seconds
1050 hildon_time_editor_get_duration_min (HildonTimeEditor *editor)
1052 HildonTimeEditorPrivate *priv;
1054 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1056 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1059 if(! priv->duration_mode )
1062 return (priv->duration_min);
1066 * hildon_time_editor_set_duration_max:
1067 * @editor: the #HildonTimeEditor widget
1068 * @duration_max: maximum allowed duration in seconds
1070 * Sets the maximum allowed duration in seconds for the duration mode.
1071 * Note: Has no effect in time mode
1074 hildon_time_editor_set_duration_max (HildonTimeEditor *editor,
1077 HildonTimeEditorPrivate *priv;
1079 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1080 g_return_if_fail (duration_max <= MAX_DURATION);
1082 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1085 if (! priv->duration_mode)
1088 priv->duration_max = duration_max;
1090 /* Clamp the current value to the maximum if necessary */
1091 if (priv->ticks > duration_max)
1093 hildon_time_editor_set_ticks (editor, duration_max);
1096 g_object_notify (G_OBJECT (editor), "duration_max");
1100 * hildon_time_editor_get_duration_max:
1101 * @editor: the #HildonTimeEditor widget
1103 * This function returns the longest duration the #HildonTimeEditor
1104 * allows in the duration mode.
1106 * Returns: maximum allowed duration in seconds
1109 hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1111 HildonTimeEditorPrivate *priv;
1113 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1115 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1118 if (! priv->duration_mode)
1121 return (priv->duration_max);
1125 * hildon_time_editor_set_time:
1126 * @editor: the #HildonTimeEditor widget
1131 * This function sets the time on an existing time editor. If the
1132 * time specified by the arguments is invalid, it's fixed.
1133 * The time is assumed to be in 24h format.
1136 hildon_time_editor_set_time (HildonTimeEditor *editor,
1141 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1143 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1147 * hildon_time_editor_get_time:
1148 * @editor: the #HildonTimeEditor widget
1153 * Gets the time of the #HildonTimeEditor widget. The time returned is
1154 * always in 24h format.
1157 hildon_time_editor_get_time (HildonTimeEditor *editor,
1162 HildonTimeEditorPrivate *priv;
1164 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1166 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1169 ticks_to_time (hildon_time_editor_get_ticks (editor), hours, minutes, seconds);
1173 * hildon_time_editor_set_duration_range:
1174 * @editor: the #HildonTimeEditor widget
1175 * @min_seconds: minimum allowed time in seconds
1176 * @max_seconds: maximum allowed time in seconds
1178 * Sets the duration editor time range of the #HildonTimeEditor widget.
1181 hildon_time_editor_set_duration_range (HildonTimeEditor *editor,
1185 HildonTimeEditorPrivate *priv;
1188 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1190 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1193 /* Swap values if reversed */
1194 if (min_seconds > max_seconds)
1197 max_seconds = min_seconds;
1201 hildon_time_editor_set_duration_max (editor, max_seconds);
1202 hildon_time_editor_set_duration_min (editor, min_seconds);
1204 if (priv->duration_mode) {
1205 /* Set minimum allowed value for duration editor.
1206 FIXME: Shouldn't it be changed only if it's not in range?
1207 Would change API, so won't touch this for now. */
1208 hildon_time_editor_set_ticks (editor, min_seconds);
1213 * hildon_time_editor_get_duration_range:
1214 * @editor: the #HildonTimeEditor widget
1215 * @min_seconds: pointer to guint
1216 * @max_seconds: pointer to guint
1218 * Gets the duration editor time range of the #HildonTimeEditor widget.
1221 hildon_time_editor_get_duration_range (HildonTimeEditor *editor,
1225 HildonTimeEditorPrivate *priv;
1227 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1229 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1232 *min_seconds = priv->duration_min;
1233 *max_seconds = priv->duration_max;
1237 hildon_time_editor_check_locale (HildonTimeEditor *editor)
1239 HildonTimeEditorPrivate *priv;
1241 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1244 /* Update time separator symbols */
1245 hildon_time_editor_get_time_separators (GTK_LABEL (priv->hm_label), GTK_LABEL (priv->sec_label));
1247 /* Get AM/PM symbols. */
1248 priv->am_symbol = g_strdup (nl_langinfo (AM_STR));
1249 priv->pm_symbol = g_strdup (nl_langinfo (PM_STR));
1251 if (priv->am_symbol[0] == '\0')
1254 /* 12h clock mode. Check if AM/PM should be before or after time.
1255 %p is the AM/PM string, so we assume that if the format string
1256 begins with %p it's in the beginning, and in any other case it's
1257 in the end (although that's not necessarily the case). */
1258 if (strncmp (nl_langinfo (T_FMT_AMPM), "%p", 2) == 0)
1259 priv->ampm_pos_after = FALSE;
1265 hildon_time_editor_entry_focus_in (GtkWidget *widget,
1266 GdkEventFocus *event,
1269 g_idle_add ((GSourceFunc) hildon_time_editor_entry_select_all,
1270 GTK_ENTRY (widget));
1276 hildon_time_editor_time_error (HildonTimeEditor *editor,
1277 HildonDateTimeError type)
1282 /* Returns negative if we didn't get value,
1283 * and should stop further validation
1286 validated_conversion (HildonTimeEditorPrivate *priv,
1291 gboolean allow_intermediate,
1293 GString *error_string)
1299 text = gtk_entry_get_text (GTK_ENTRY (field));
1301 if (text && text[0])
1303 /* Try to convert entry text to number */
1304 value = strtol (text, &tail, 10);
1306 /* Check if conversion succeeded */
1307 if ((tail[0] == 0) && !(text[0] == '-'))
1310 g_string_printf (error_string, _("ckct_ib_maximum_value"), max);
1311 priv->error_widget = field;
1312 *error_code = MAX_VALUE;
1316 if (value < min && !allow_intermediate) {
1317 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1318 priv->error_widget = field;
1319 *error_code = MIN_VALUE;
1326 /* We'll handle failed conversions soon */
1329 if ((tail[0] == '-') || (text[0] == '-'))
1331 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1332 priv->error_widget = field;
1333 *error_code = MIN_VALUE;
1338 else if (allow_intermediate)
1339 return -1; /* Empty field while user is still editing. No error, but
1340 cannot validate either... */
1341 else /* Empty field: show error and set value to minimum allowed */
1343 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1344 priv->error_widget = field;
1345 *error_code = WITHIN_RANGE;
1349 /* Empty field and not allowed intermediated OR failed conversion */
1350 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1351 priv->error_widget = field;
1352 *error_code = WITHIN_RANGE;
1357 hildon_time_editor_real_validate (HildonTimeEditor *editor,
1358 gboolean allow_intermediate,
1359 GString *error_string)
1361 HildonTimeEditorPrivate *priv;
1362 guint h, m, s, ticks;
1364 guint max_hours, min_hours, def_hours;
1365 guint max_minutes, min_minutes, def_minutes;
1366 guint max_seconds, min_seconds, def_seconds;
1369 g_assert (HILDON_IS_TIME_EDITOR (editor));
1371 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1374 /* Find limits for field based validation. */
1375 if (priv->duration_mode)
1377 ticks_to_time (priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1378 ticks_to_time (priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1380 if (priv->clock_24h) {
1381 max_hours = HOURS_MAX_24;
1382 min_hours = HOURS_MIN_24;
1384 max_hours = HOURS_MAX_12;
1385 min_hours = HOURS_MIN_12;
1389 hildon_time_editor_get_time (editor, &def_hours, &def_minutes, &def_seconds);
1391 /* Get time components from fields and validate them... */
1392 if (priv->show_hours) {
1393 h = validated_conversion (priv, priv->entries[ENTRY_HOURS], min_hours, max_hours, def_hours,
1394 allow_intermediate, &error_code, error_string);
1395 if (priv->error_widget == priv->entries[ENTRY_HOURS])
1396 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, hour_errors[error_code], &r);
1397 if ((gint) h < 0) return;
1400 m = validated_conversion (priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX, def_minutes,
1401 allow_intermediate, &error_code, error_string);
1402 if (priv->error_widget == priv->entries[ENTRY_MINS])
1403 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, min_errors[error_code], &r);
1404 if ((gint) m < 0) return;
1405 if (priv->show_seconds) {
1406 s = validated_conversion (priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX, def_seconds,
1407 allow_intermediate, &error_code, error_string);
1408 if (priv->error_widget == priv->entries[ENTRY_SECS])
1409 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, sec_errors[error_code], &r);
1410 if ((gint) s < 0) return;
1414 /* Ok, we now do separate check that tick count is valid for duration mode */
1415 if (priv->duration_mode)
1417 ticks = TICKS(h, m, s);
1419 if (ticks < priv->duration_min && !allow_intermediate)
1421 g_string_printf (error_string,
1422 _("ckct_ib_min_allowed_duration_hts"),
1423 min_hours, min_minutes, min_seconds);
1424 hildon_time_editor_set_ticks (editor, priv->duration_min);
1425 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1426 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MIN_DURATION, &r);
1429 else if (ticks > priv->duration_max)
1431 g_string_printf (error_string,
1432 _("ckct_ib_max_allowed_duration_hts"),
1433 max_hours, max_minutes, max_seconds);
1434 hildon_time_editor_set_ticks (editor, priv->duration_max);
1435 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1436 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MAX_DURATION, &r);
1440 else if (! priv->clock_24h)
1441 convert_to_24h (&h, priv->am);
1443 /* The only case when we do not want to refresh the
1444 time display, is when the user is editing a value
1445 (unless the value was out of bounds and we have to fix it) */
1446 if (! allow_intermediate || priv->error_widget)
1447 hildon_time_editor_set_time (editor, h, m, s);
1450 /* Setting text to entries causes entry to recompute itself
1451 in idle callback, which remove selection. Because of this
1452 we need to do selection in idle as well. */
1454 highlight_callback (gpointer data)
1456 HildonTimeEditorPrivate *priv;
1460 g_assert (HILDON_IS_TIME_EDITOR (data));
1461 priv = HILDON_TIME_EDITOR_GET_PRIVATE (data);
1464 GDK_THREADS_ENTER ();
1466 widget = priv->error_widget;
1467 priv->error_widget = NULL;
1469 if (GTK_IS_WIDGET (widget) == FALSE)
1472 /* Avoid revalidation because it will issue the date_error signal
1473 twice when there is an empty field. We must block the signal
1474 for all the entries because we do not know where the focus
1476 for (i = 0; i < ENTRY_COUNT; i++)
1477 g_signal_handlers_block_by_func (priv->entries[i],
1478 (gpointer) hildon_time_editor_entry_focus_out, data);
1479 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1480 gtk_widget_grab_focus (widget);
1481 for (i = 0; i < ENTRY_COUNT; i++)
1482 g_signal_handlers_unblock_by_func (priv->entries[i],
1483 (gpointer) hildon_time_editor_entry_focus_out, data);
1486 priv->highlight_idle = 0;
1487 GDK_THREADS_LEAVE ();
1492 /* Update ticks from current H:M:S entries. If they're invalid, show an
1493 infoprint and update the fields unless they're empty. */
1495 hildon_time_editor_validate (HildonTimeEditor *editor,
1496 gboolean allow_intermediate)
1498 HildonTimeEditorPrivate *priv;
1499 GString *error_message;
1501 g_assert (HILDON_IS_TIME_EDITOR(editor));
1502 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1505 /* if there is already an error we do nothing until it will be managed by the idle */
1506 if (priv->highlight_idle == 0 && priv->skipper == FALSE)
1508 priv->skipper = TRUE;
1509 error_message = g_string_new (NULL);
1510 hildon_time_editor_real_validate (editor,
1511 allow_intermediate, error_message);
1513 if (priv->error_widget)
1515 hildon_banner_show_information (priv->error_widget, NULL,
1516 error_message->str);
1518 priv->highlight_idle = g_idle_add (highlight_callback, editor);
1521 priv->skipper = FALSE;
1522 g_string_free (error_message, TRUE);
1526 /* on inserted text, if entry has two digits, jumps to the next field. */
1528 hildon_time_editor_inserted_text (GtkEditable *editable,
1530 gint new_text_length,
1534 HildonTimeEditor *editor;
1537 HildonTimeEditorPrivate *priv;
1539 entry = GTK_ENTRY (editable);
1540 editor = HILDON_TIME_EDITOR (user_data);
1542 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1545 /* if there is already an error we don't have to do anything */
1546 if (! priv->error_widget)
1548 value = (gchar *) gtk_entry_get_text (entry);
1550 if (strlen (value) == 2)
1552 if (GTK_WIDGET (editable) == priv->entries[ENTRY_HOURS])
1554 /* We already checked the input in changed signal, but
1555 * now we will re-check it again in focus-out we
1556 * intermediate flag set to FALSE */
1557 gtk_widget_grab_focus (priv->entries[ENTRY_MINS]);
1560 else if (GTK_WIDGET (editable) == priv->entries[ENTRY_MINS] &&
1561 GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS]))
1564 gtk_widget_grab_focus (priv->entries[ENTRY_SECS]);
1572 hildon_time_editor_entry_focus_out (GtkWidget *widget,
1573 GdkEventFocus *event,
1576 g_assert (HILDON_IS_TIME_EDITOR (data));
1578 /* Validate the given time and update ticks. */
1579 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1585 hildon_time_editor_ampm_clicked (GtkWidget *widget,
1588 HildonTimeEditor *editor;
1589 HildonTimeEditorPrivate *priv;
1591 g_assert (GTK_IS_WIDGET (widget));
1592 g_assert (HILDON_IS_TIME_EDITOR (data));
1594 editor = HILDON_TIME_EDITOR (data);
1595 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1598 /* First validate the given time and update ticks. */
1599 hildon_time_editor_validate (editor, FALSE);
1601 /* Apply the AM/PM change by moving the current time by 12 hours */
1603 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1604 hildon_time_editor_set_ticks (editor, priv->ticks + 12 * 3600);
1606 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1607 hildon_time_editor_set_ticks (editor, priv->ticks - 12 * 3600);
1614 hildon_time_editor_icon_clicked (GtkWidget *widget,
1617 HildonTimeEditor *editor;
1620 guint h, m, s, result;
1621 HildonTimeEditorPrivate *priv;
1623 g_assert (HILDON_IS_TIME_EDITOR (data));
1625 editor = HILDON_TIME_EDITOR (data);
1626 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1629 /* icon is passive in duration editor mode */
1630 if (hildon_time_editor_get_duration_mode (editor))
1633 /* Validate and do not launch if broken */
1634 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1635 if (priv->error_widget != NULL)
1638 /* Launch HildonTimePicker dialog */
1639 parent = gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW);
1640 picker = hildon_time_picker_new (GTK_WINDOW (parent));
1642 hildon_time_editor_get_time (editor, &h, &m, &s);
1643 hildon_time_picker_set_time (HILDON_TIME_PICKER (picker), h, m);
1645 result = gtk_dialog_run (GTK_DIALOG (picker));
1648 case GTK_RESPONSE_OK:
1649 case GTK_RESPONSE_ACCEPT:
1650 /* Use the selected time */
1651 hildon_time_picker_get_time (HILDON_TIME_PICKER (picker), &h, &m);
1652 hildon_time_editor_set_time (editor, h, m, 0);
1659 gtk_widget_destroy (picker);
1664 hildon_time_editor_size_request (GtkWidget *widget,
1665 GtkRequisition *requisition)
1667 HildonTimeEditor *editor;
1668 HildonTimeEditorPrivate *priv;
1671 editor = HILDON_TIME_EDITOR (widget);
1672 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1674 /* Get frame's size */
1675 gtk_widget_size_request (priv->frame, requisition);
1677 if (GTK_WIDGET_VISIBLE (priv->iconbutton))
1679 gtk_widget_size_request (priv->iconbutton, &req);
1680 /* Reserve space for icon */
1681 requisition->width += req.width + ICON_PRESSED +
1682 HILDON_MARGIN_DEFAULT;
1685 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1686 want to force this since themes might have varying thickness values
1687 which cause the height to change. */
1688 requisition->height = TIME_EDITOR_HEIGHT;
1692 hildon_time_editor_size_allocate (GtkWidget *widget,
1693 GtkAllocation *allocation)
1695 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
1696 GtkAllocation alloc;
1697 GtkRequisition req, max_req;
1701 widget->allocation = *allocation;
1702 gtk_widget_get_child_requisition (widget, &max_req);
1704 /* Center horizontally */
1705 alloc.x = allocation->x + MAX (allocation->width - max_req.width, 0) / 2;
1706 /* Center vertically */
1707 alloc.y = allocation->y + MAX (allocation->height - max_req.height, 0) / 2;
1709 /* allocate frame */
1710 gtk_widget_get_child_requisition (priv->frame, &req);
1712 alloc.width = req.width;
1713 alloc.height = max_req.height;
1714 gtk_widget_size_allocate (priv->frame, &alloc);
1717 if (GTK_WIDGET_VISIBLE (priv->iconbutton)) {
1718 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1720 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1721 alloc.width = req.width;
1722 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1725 /* FIXME: ugly way to move labels up. They just don't seem move up
1726 otherwise. This is likely because we force the editor to be
1727 smaller than it otherwise would be. */
1728 alloc = priv->ampm_label->allocation;
1729 alloc.y = allocation->y - 2;
1730 alloc.height = max_req.height + 2;
1731 gtk_widget_size_allocate (priv->ampm_label, &alloc);
1733 alloc = priv->hm_label->allocation;
1734 alloc.y = allocation->y - 2;
1735 alloc.height = max_req.height + 2;
1736 gtk_widget_size_allocate (priv->hm_label, &alloc);
1738 alloc = priv->sec_label->allocation;
1739 alloc.y = allocation->y - 2;
1740 alloc.height = max_req.height + 2;
1741 gtk_widget_size_allocate (priv->sec_label, &alloc);
1745 hildon_time_editor_entry_keypress (GtkWidget *widget,
1749 HildonTimeEditor *editor;
1750 HildonTimeEditorPrivate *priv;
1754 g_assert (GTK_IS_ENTRY (widget));
1755 g_assert (event != NULL);
1756 g_assert (HILDON_IS_TIME_EDITOR (data));
1758 editor = HILDON_TIME_EDITOR (data);
1759 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1761 cursor_pos = gtk_editable_get_position (GTK_EDITABLE (widget));
1763 /* Show error message in case the key pressed is not allowed
1764 (only digits and control characters are allowed )*/
1765 if (!g_unichar_isdigit (event->keyval) && ! (event->keyval & 0xF000)) {
1766 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_INVALID_CHAR, &r);
1767 hildon_banner_show_information (widget, NULL, _("ckct_ib_illegal_character"));
1771 switch (event->keyval)
1774 /* Return key popups up time picker dialog. Visually it looks as if
1775 the time picker icon was clicked. Before opening the time picker
1776 the fields are first validated and fixed. */
1778 /* hildon_time_editor_validate (editor, FALSE);
1779 hildon_gtk_button_set_depressed (GTK_BUTTON (priv->iconbutton), TRUE);
1780 hildon_time_editor_icon_clicked (widget, data);
1781 hildon_gtk_button_set_depressed (GTK_BUTTON (priv->iconbutton), FALSE);
1783 FIXME The above code used to be here before the consolidation that removed the
1784 _set_depressed crap. However, I think this code had NO EFFECT anyways, since
1785 there is no expose event after the _set functions. So I'm just cutting it out.
1786 Another story would be to actually fix it... */
1788 hildon_time_editor_icon_clicked (widget, data);
1792 /* left arrow pressed in the entry. If we are on first position, try to
1793 move to the previous field. */
1794 if (cursor_pos == 0) {
1795 (void) gtk_widget_child_focus (GTK_WIDGET (editor), GTK_DIR_LEFT);
1801 /* right arrow pressed in the entry. If we are on last position, try to
1802 move to the next field. */
1803 if (cursor_pos >= g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (widget)), -1)) {
1804 (void) gtk_widget_child_focus (GTK_WIDGET (editor), GTK_DIR_RIGHT);
1817 convert_to_12h (guint *h,
1820 g_assert (0 <= *h && *h < 24);
1822 /* 00:00 to 00:59 add 12 hours */
1823 /* 01:00 to 11:59 straight to am */
1824 /* 12:00 to 12:59 straight to pm */
1825 /* 13:00 to 23:59 subtract 12 hours */
1827 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1828 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1829 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1830 else { *am = FALSE; *h -= 12;}
1834 convert_to_24h (guint *h,
1837 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1842 else if (! am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1849 * hildon_time_editor_set_show_hours:
1850 * @editor: The #HildonTimeEditor.
1851 * @enable: Enable or disable showing of hours.
1853 * This function shows or hides the hours field.
1857 hildon_time_editor_set_show_hours (HildonTimeEditor *editor,
1858 gboolean show_hours)
1860 HildonTimeEditorPrivate *priv;
1862 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1864 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1867 if (show_hours != priv->show_hours) {
1868 priv->show_hours = show_hours;
1870 /* show/hide hours field and its ':' label if the value changed. */
1872 gtk_widget_show (priv->entries[ENTRY_HOURS]);
1873 gtk_widget_show (priv->hm_label);
1875 gtk_widget_hide (priv->entries[ENTRY_HOURS]);
1876 gtk_widget_hide (priv->hm_label);
1879 g_object_notify (G_OBJECT (editor), "show_hours");
1884 * hildon_time_editor_get_show_hours:
1885 * @self: the @HildonTimeEditor widget.
1887 * This function returns a boolean indicating the visibility of
1888 * hours in the @HildonTimeEditor
1890 * Return value: TRUE if hours are visible.
1894 hildon_time_editor_get_show_hours (HildonTimeEditor *editor)
1896 HildonTimeEditorPrivate *priv;
1898 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1899 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1902 return priv->show_hours;
1907 hildon_time_editor_entry_select_all (GtkWidget *widget)
1909 GDK_THREADS_ENTER ();
1910 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1911 GDK_THREADS_LEAVE ();