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
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.
38 * <title>HildonTimePicker example</title>
41 * editor = hildon_time_editor_new ();
42 * hildon_time_editor_set_time (editor, h, m, s);
44 * gtk_box_pack_start (..., editor)
46 * hildon_time_editor_get_time (editor, &h, &m, &s);
62 #include <gdk/gdkkeysyms.h>
64 #include "hildon-time-editor.h"
65 #include "hildon-defines.h"
66 #include "hildon-time-picker.h"
67 #include "hildon-banner.h"
68 #include "hildon-private.h"
69 #include "hildon-marshalers.h"
70 #include "hildon-enum-types.h"
71 #include "hildon-time-editor-private.h"
73 #define _(String) dgettext("hildon-libs", String)
75 #define c_(String) dgettext("hildon-common-strings", String)
77 #define TICKS(h,m,s) \
78 ((h) * 3600 + (m) * 60 + (s))
80 #define TIME_EDITOR_HEIGHT 30
82 #define ICON_PRESSED 4
84 #define ICON_NAME "qgn_widg_timedit"
86 #define ICON_SIZE "timepicker-size"
88 #define MIN_DURATION 0
90 #define MAX_DURATION TICKS(99, 59, 59)
92 /* Default values for properties */
94 #define HILDON_TIME_EDITOR_TICKS_VALUE 0
96 #define HILDON_TIME_EDITOR_DURATION_MODE FALSE
98 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE 0
100 #define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE TICKS(99, 59, 59)
102 #define HOURS_MAX_24 23
104 #define HOURS_MAX_12 12
106 #define HOURS_MIN_24 0
108 #define HOURS_MIN_12 1
110 #define MINUTES_MAX 59
112 #define SECONDS_MAX 59
114 #define MINUTES_MIN 0
116 #define SECONDS_MIN 0
118 static GtkContainerClass* parent_class;
137 /* Error codes categories */
145 static guint time_editor_signals[LAST_SIGNAL] = { 0 };
147 static guint hour_errors[NUM_ERROR_CODES] = {
148 HILDON_DATE_TIME_ERROR_MAX_HOURS,
149 HILDON_DATE_TIME_ERROR_MIN_HOURS,
150 HILDON_DATE_TIME_ERROR_EMPTY_HOURS };
152 static guint min_errors[NUM_ERROR_CODES] = {
153 HILDON_DATE_TIME_ERROR_MAX_MINS,
154 HILDON_DATE_TIME_ERROR_MIN_MINS,
155 HILDON_DATE_TIME_ERROR_EMPTY_MINS };
157 static guint sec_errors[NUM_ERROR_CODES] = {
158 HILDON_DATE_TIME_ERROR_MAX_SECS,
159 HILDON_DATE_TIME_ERROR_MIN_SECS,
160 HILDON_DATE_TIME_ERROR_EMPTY_SECS };
163 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class);
166 hildon_time_editor_init (HildonTimeEditor *editor);
169 hildon_time_editor_finalize (GObject *obj_self);
172 hildon_time_editor_set_property (GObject *object,
178 hildon_time_editor_get_property (GObject *object,
184 hildon_time_editor_forall (GtkContainer *container,
185 gboolean include_internals,
186 GtkCallback callback,
187 gpointer callback_data);
190 hildon_time_editor_destroy (GtkObject *self);
193 hildon_time_editor_entry_focus_out (GtkWidget *widget,
194 GdkEventFocus *event,
198 hildon_time_editor_entry_focus_in (GtkWidget *widget,
199 GdkEventFocus *event,
203 hildon_time_editor_time_error (HildonTimeEditor *editor,
204 HildonDateTimeError type);
207 hildon_time_editor_ampm_clicked (GtkWidget *widget,
211 hildon_time_editor_icon_clicked (GtkWidget *widget,
215 hildon_time_editor_size_request (GtkWidget *widget,
216 GtkRequisition *requisition);
219 hildon_time_editor_size_allocate (GtkWidget *widget,
220 GtkAllocation *allocation);
223 hildon_time_editor_focus (GtkWidget *widget,
224 GtkDirectionType direction);
227 hildon_time_editor_entry_keypress (GtkEntry *entry,
232 hildon_time_editor_check_locale (HildonTimeEditor *editor);
236 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
239 GtkWidgetTapAndHoldFlags flags);
243 hildon_time_editor_validate (HildonTimeEditor *editor,
244 gboolean allow_intermediate);
247 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor);
250 hildon_time_editor_entry_select_all (GtkWidget *widget);
253 convert_to_12h (guint *h,
257 convert_to_24h (guint *h,
261 ticks_to_time (guint ticks,
267 hildon_time_editor_inserted_text (GtkEditable *editable,
269 gint new_text_length,
274 * hildon_time_editor_get_type:
276 * Initializes and returns the type of a hildon time editor.
278 * @Returns: GType of #HildonTimeEditor
281 hildon_time_editor_get_type (void)
283 static GType editor_type = 0;
286 static const GTypeInfo editor_info = {
287 sizeof(HildonTimeEditorClass),
288 NULL, /* base_init */
289 NULL, /* base_finalize */
290 (GClassInitFunc) hildon_time_editor_class_init,
291 NULL, /* class_finalize */
292 NULL, /* class_data */
293 sizeof(HildonTimeEditor),
295 (GInstanceInitFunc) hildon_time_editor_init,
297 editor_type = g_type_register_static (GTK_TYPE_CONTAINER,
306 hildon_time_editor_forall (GtkContainer *container,
307 gboolean include_internals,
308 GtkCallback callback,
309 gpointer callback_data)
311 HildonTimeEditorPrivate *priv;
313 g_assert (HILDON_IS_TIME_EDITOR (container));
314 g_assert (callback != NULL);
316 priv = HILDON_TIME_EDITOR_GET_PRIVATE (container);
320 if (! include_internals)
323 /* widget that are always shown */
324 (*callback) (priv->iconbutton, callback_data);
325 (*callback) (priv->frame, callback_data);
329 hildon_time_editor_destroy (GtkObject *self)
331 HildonTimeEditorPrivate *priv;
333 priv = HILDON_TIME_EDITOR_GET_PRIVATE (self);
336 if (priv->iconbutton) {
337 gtk_widget_unparent (priv->iconbutton);
338 priv->iconbutton = NULL;
341 gtk_widget_unparent (priv->frame);
345 if (GTK_OBJECT_CLASS (parent_class)->destroy)
346 GTK_OBJECT_CLASS (parent_class)->destroy (self);
350 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class)
352 GObjectClass *object_class = G_OBJECT_CLASS (editor_class);
353 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (editor_class);
354 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (editor_class);
356 parent_class = g_type_class_peek_parent (editor_class);
358 g_type_class_add_private (editor_class, sizeof (HildonTimeEditorPrivate));
360 object_class->get_property = hildon_time_editor_get_property;
361 object_class->set_property = hildon_time_editor_set_property;
362 widget_class->size_request = hildon_time_editor_size_request;
363 widget_class->size_allocate = hildon_time_editor_size_allocate;
364 widget_class->focus = hildon_time_editor_focus;
366 container_class->forall = hildon_time_editor_forall;
367 GTK_OBJECT_CLASS (editor_class)->destroy = hildon_time_editor_destroy;
369 object_class->finalize = hildon_time_editor_finalize;
371 editor_class->time_error = hildon_time_editor_time_error;
373 time_editor_signals[TIME_ERROR] =
374 g_signal_new ("time-error",
375 G_OBJECT_CLASS_TYPE (object_class),
377 G_STRUCT_OFFSET (HildonTimeEditorClass, time_error),
378 g_signal_accumulator_true_handled, NULL,
379 _hildon_marshal_BOOLEAN__ENUM,
380 G_TYPE_BOOLEAN, 1, HILDON_TYPE_DATE_TIME_ERROR);
383 * HildonTimeEditor:ticks:
385 * If editor is in duration mode, contains the duration seconds.
386 * If not, contains seconds since midnight.
388 g_object_class_install_property (object_class, PROP_TICKS,
389 g_param_spec_uint ("ticks",
391 "Current value of duration",
393 HILDON_TIME_EDITOR_TICKS_VALUE,
394 G_PARAM_READABLE | G_PARAM_WRITABLE) );
397 * HildonTimeEditor:show_seconds:
399 * Controls whether seconds are shown in the editor
401 g_object_class_install_property (object_class, PROP_SHOW_SECONDS,
402 g_param_spec_boolean ("show_seconds",
403 "Show seconds property",
404 "Controls whether the seconds are shown in the editor",
406 G_PARAM_READABLE | G_PARAM_WRITABLE) );
409 * HildonTimeEditor:show_hours:
411 * Controls whether hours are shown in the editor
413 g_object_class_install_property (object_class, PROP_SHOW_HOURS,
414 g_param_spec_boolean ("show_hours",
416 "Controls whether the hours field is shown in the editor",
418 G_PARAM_READABLE | G_PARAM_WRITABLE) );
421 * HildonTimeEditor:duration_mode:
423 * Controls whether the TimeEditor is in duration mode
425 g_object_class_install_property (object_class, PROP_DURATION_MODE,
426 g_param_spec_boolean ("duration_mode",
428 "Controls whether the TimeEditor is in duration mode",
429 HILDON_TIME_EDITOR_DURATION_MODE,
430 G_PARAM_READABLE | G_PARAM_WRITABLE) );
433 * HildonTimeEditor:duration_min:
435 * Minimum allowed duration value.
437 g_object_class_install_property (object_class, PROP_DURATION_MIN,
438 g_param_spec_uint ("duration_min",
439 "Minumum duration value",
440 "Smallest possible duration value",
441 MIN_DURATION, MAX_DURATION,
442 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
443 G_PARAM_READABLE | G_PARAM_WRITABLE) );
446 * HildonTimeEditor:duration_max:
448 * Maximum allowed duration value.
450 g_object_class_install_property (object_class, PROP_DURATION_MAX,
451 g_param_spec_uint ("duration_max",
452 "Maximum duration value",
453 "Largest possible duration value",
455 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
456 G_PARAM_READABLE | G_PARAM_WRITABLE) );
461 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
464 GtkWidgetTapAndHoldFlags flags)
466 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
469 /* Forward this tap_and_hold_setup signal to all our child widgets */
470 for (i = 0; i < ENTRY_COUNT; i++)
472 gtk_widget_tap_and_hold_setup (priv->entries[i], menu, func,
473 GTK_TAP_AND_HOLD_NO_SIGNALS);
475 gtk_widget_tap_and_hold_setup (priv->ampm_button, menu, func,
476 GTK_TAP_AND_HOLD_NO_SIGNALS);
477 gtk_widget_tap_and_hold_setup (priv->iconbutton, menu, func,
478 GTK_TAP_AND_HOLD_NONE);
483 hildon_time_editor_entry_changed (GtkWidget *widget,
486 g_assert (HILDON_IS_TIME_EDITOR (data));
487 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), TRUE);
491 hildon_time_editor_init (HildonTimeEditor *editor)
493 HildonTimeEditorPrivate *priv;
494 GtkWidget *hbox, *icon;
497 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
500 gtk_widget_push_composite_child ();
502 /* Setup defaults and create widgets */
504 priv->show_seconds = FALSE;
505 priv->show_hours = TRUE;
506 priv->ampm_pos_after = TRUE;
507 priv->clock_24h = TRUE;
508 priv->duration_mode = FALSE;
509 priv->iconbutton = gtk_button_new();
510 priv->ampm_label = gtk_label_new(NULL);
511 priv->hm_label = gtk_label_new(NULL);
512 priv->sec_label = gtk_label_new(NULL);
513 priv->frame = gtk_frame_new(NULL);
514 priv->ampm_button = gtk_button_new();
515 priv->skipper = FALSE;
517 icon = gtk_image_new_from_icon_name (ICON_NAME, HILDON_ICON_SIZE_SMALL);
518 hbox = gtk_hbox_new (FALSE, 0);
520 GTK_WIDGET_SET_FLAGS (editor, GTK_NO_WINDOW);
521 GTK_WIDGET_UNSET_FLAGS (priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
523 gtk_container_set_border_width (GTK_CONTAINER(priv->frame), 0);
525 gtk_container_add (GTK_CONTAINER (priv->iconbutton), icon);
526 gtk_container_add (GTK_CONTAINER (priv->ampm_button), priv->ampm_label);
527 gtk_button_set_relief(GTK_BUTTON (priv->ampm_button), GTK_RELIEF_NONE);
528 gtk_button_set_focus_on_click (GTK_BUTTON (priv->ampm_button), FALSE);
530 /* Create hour, minute and second entries */
531 for (i = 0; i < ENTRY_COUNT; i++)
533 priv->entries[i] = gtk_entry_new ();
535 /* No frames for entries, so that they all appear to be inside one long entry */
536 gtk_entry_set_has_frame (GTK_ENTRY (priv->entries[i]), FALSE);
539 /* Set the entries to accept only numeric characters */
540 g_object_set (priv->entries[i], "hildon-input-mode", HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
543 /* The entry fields all take exactly two characters */
544 gtk_entry_set_max_length (GTK_ENTRY (priv->entries[i]), 2);
545 gtk_entry_set_width_chars (GTK_ENTRY (priv->entries[i]), 2);
547 g_signal_connect (priv->entries[i], "focus-in-event",
548 G_CALLBACK (hildon_time_editor_entry_focus_in), editor);
549 g_signal_connect (priv->entries[i], "focus-out-event",
550 G_CALLBACK (hildon_time_editor_entry_focus_out), editor);
551 g_signal_connect (priv->entries[i], "key-press-event",
552 G_CALLBACK (hildon_time_editor_entry_keypress), editor);
553 g_signal_connect (priv->entries[i], "changed",
554 G_CALLBACK (hildon_time_editor_entry_changed), editor);
556 /* inserted signal sets time */
557 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
558 G_CALLBACK (hildon_time_editor_inserted_text),
562 /* clicked signal for am/pm label */
563 g_signal_connect (G_OBJECT (priv->ampm_button), "clicked",
564 G_CALLBACK (hildon_time_editor_ampm_clicked), editor);
566 /* clicked signal for icon */
567 g_signal_connect (G_OBJECT (priv->iconbutton), "clicked",
568 G_CALLBACK (hildon_time_editor_icon_clicked), editor);
570 /* Set ourself as the parent of all the widgets we created */
571 gtk_widget_set_parent (priv->iconbutton, GTK_WIDGET(editor));
572 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
573 gtk_box_pack_start (GTK_BOX (hbox), priv->hm_label, FALSE, FALSE, 0);
574 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
575 gtk_box_pack_start (GTK_BOX (hbox), priv->sec_label, FALSE, FALSE, 0);
576 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
577 gtk_box_pack_start (GTK_BOX (hbox), priv->ampm_button, FALSE, FALSE, 0);
578 gtk_misc_set_padding (GTK_MISC (priv->ampm_label), 0, 0);
580 gtk_container_add (GTK_CONTAINER (priv->frame), hbox);
582 /* Show created widgets */
583 gtk_widget_set_parent (priv->frame, GTK_WIDGET(editor));
584 gtk_widget_show_all (priv->frame);
585 gtk_widget_show_all (priv->iconbutton);
587 /* Update AM/PM and time separators settings from locale */
588 if (! hildon_time_editor_check_locale (editor)) {
589 /* Using 12h clock */
590 priv->clock_24h = FALSE;
592 gtk_widget_hide (priv->ampm_button);
595 if (! priv->show_seconds) {
596 gtk_widget_hide (priv->sec_label);
597 gtk_widget_hide (priv->entries[ENTRY_SECS]);
600 /* set the default time to current time. */
601 hildon_time_editor_set_to_current_time (editor);
603 gtk_widget_pop_composite_child ();
606 g_signal_connect (editor, "tap-and-hold-setup",
607 G_CALLBACK (hildon_time_editor_tap_and_hold_setup),
614 hildon_time_editor_set_property (GObject *object,
619 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
624 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
627 case PROP_SHOW_SECONDS:
628 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
631 case PROP_SHOW_HOURS:
632 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
635 case PROP_DURATION_MODE:
636 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
639 case PROP_DURATION_MIN:
640 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
643 case PROP_DURATION_MAX:
644 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
648 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
654 hildon_time_editor_get_property (GObject *object,
659 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
665 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
668 case PROP_SHOW_SECONDS:
669 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
672 case PROP_SHOW_HOURS:
673 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
676 case PROP_DURATION_MODE:
677 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
680 case PROP_DURATION_MIN:
681 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
684 case PROP_DURATION_MAX:
685 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
689 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
695 * hildon_time_editor_new:
697 * This function creates a new time editor.
699 * Returns: pointer to a new #HildonTimeEditor widget
702 hildon_time_editor_new (void)
704 return GTK_WIDGET (g_object_new (HILDON_TYPE_TIME_EDITOR, NULL));
708 hildon_time_editor_finalize (GObject *obj_self)
710 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (obj_self);
714 g_free (priv->am_symbol);
717 g_free (priv->pm_symbol);
719 if (priv->highlight_idle)
720 g_source_remove (priv->highlight_idle);
722 if (G_OBJECT_CLASS (parent_class)->finalize)
723 G_OBJECT_CLASS (parent_class)->finalize (obj_self);
727 * hildon_time_editor_get_time_separators:
728 * @hm_sep_label: the label that will show the hour:minutes separator
729 * @ms_sep_label: the label that will show the minutes:seconds separator
731 * Gets hour-minute separator and minute-second separator from current
732 * locale and sets then to the labels we set as parameters. Both
733 * parameters can be NULL if you just want to assing one separator.
737 hildon_time_editor_get_time_separators (GtkLabel *hm_sep_label,
738 GtkLabel *ms_sep_label)
742 GDate locale_test_date;
743 gchar *iter, *endp = NULL;
745 /* Get localized time string */
746 g_date_set_dmy (&locale_test_date, 1, 2, 1970);
747 (void) g_date_strftime (buffer, sizeof (buffer), "%X", &locale_test_date);
749 if (hm_sep_label != NULL)
751 /* Find h-m separator */
753 while (*iter && g_ascii_isdigit (*iter)) iter++;
755 /* Extract h-m separator*/
757 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
758 separator = g_strndup (iter, endp - iter);
759 gtk_label_set_label (hm_sep_label, separator);
763 if (ms_sep_label != NULL)
765 /* Find m-s separator */
767 while (*iter && g_ascii_isdigit (*iter)) iter++;
769 /* Extract m-s separator*/
771 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
772 separator = g_strndup (iter, endp - iter);
773 gtk_label_set_label (ms_sep_label, separator);
778 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
780 ticks_to_time (guint ticks,
787 *hours = ticks / 3600;
789 *minutes = left / 60;
790 *seconds = left % 60;
794 * hildon_time_editor_set_ticks:
795 * @editor: the #HildonTimeEditor widget
796 * @ticks: the duration to set, in seconds
798 * Sets the current duration in seconds. This means seconds from
799 * midnight, if not in duration mode. In case of any errors, it tries
804 hildon_time_editor_set_ticks (HildonTimeEditor *editor,
807 HildonTimeEditorPrivate *priv;
811 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
813 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
816 /* Validate ticks. If it's too low or too high, set it to
817 min/max value for the current mode. */
818 if (priv->duration_mode)
819 priv->ticks = CLAMP (ticks, priv->duration_min, priv->duration_max);
821 /* Check that ticks value is valid. We only need to check that hours
823 ticks_to_time (ticks, &h, &m, &s);
824 if (h > HOURS_MAX_24)
825 ticks = TICKS(HOURS_MAX_24, m, s);
830 /* Get the time in H:M:S. */
831 ticks_to_time (priv->ticks, &h, &m, &s);
833 if (!priv->clock_24h && ! priv->duration_mode)
835 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
836 convert_to_12h (&h, &priv->am);
839 /* Set H:M:S values to entries. We do not want to invoke validation
840 callbacks (since they can cause new call to this function), so we
841 block signals while setting values. */
842 for (i = 0; i < ENTRY_COUNT; i++)
844 g_signal_handlers_block_by_func(priv->entries[i],
845 (gpointer) hildon_time_editor_entry_changed, editor);
847 g_signal_handlers_block_by_func(priv->entries[i],
848 (gpointer) hildon_time_editor_inserted_text, editor);
850 g_signal_handlers_block_by_func(priv->entries[i],
851 (gpointer) hildon_time_editor_entry_focus_out, editor);
854 g_snprintf (str, sizeof (str), "%02u", h);
855 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_HOURS]), str);
857 g_snprintf(str, sizeof (str), "%02u", m);
858 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_MINS]), str);
860 g_snprintf(str, sizeof (str), "%02u", s);
861 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_SECS]), str);
863 for (i = 0; i < ENTRY_COUNT; i++)
865 g_signal_handlers_unblock_by_func (priv->entries[i],
866 (gpointer) hildon_time_editor_entry_changed, editor);
868 g_signal_handlers_unblock_by_func (priv->entries[i],
869 (gpointer) hildon_time_editor_inserted_text, editor);
871 g_signal_handlers_unblock_by_func (priv->entries[i],
872 (gpointer) hildon_time_editor_entry_focus_out, editor);
875 /* Update AM/PM label in case we're in 12h mode */
876 gtk_label_set_label( GTK_LABEL (priv->ampm_label),
877 priv->am ? priv->am_symbol : priv->pm_symbol);
879 g_object_notify (G_OBJECT (editor), "ticks");
883 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor)
889 tm = localtime (&now);
892 hildon_time_editor_set_time (editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
896 * hildon_time_editor_get_ticks:
897 * @editor: the #HildonTimeEditor widget
899 * This function returns the current duration, in seconds.
900 * This means seconds from midnight, if not in duration mode.
902 * Returns: current duration in seconds
905 hildon_time_editor_get_ticks (HildonTimeEditor *editor)
907 HildonTimeEditorPrivate *priv;
909 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
911 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
914 return (priv->ticks);
918 * hildon_time_editor_set_show_seconds:
919 * @editor: the #HildonTimeEditor
920 * @show_seconds: enable or disable showing of seconds
922 * This function shows or hides the seconds field.
925 hildon_time_editor_set_show_seconds (HildonTimeEditor *editor,
926 gboolean show_seconds)
928 HildonTimeEditorPrivate *priv;
930 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
932 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
935 if (show_seconds != priv->show_seconds) {
936 priv->show_seconds = show_seconds;
938 /* show/hide seconds field and its ':' label if the value changed. */
940 gtk_widget_show (priv->entries[ENTRY_SECS]);
941 gtk_widget_show (priv->sec_label);
943 gtk_widget_hide (priv->entries[ENTRY_SECS]);
944 gtk_widget_hide (priv->sec_label);
947 g_object_notify (G_OBJECT (editor), "show_seconds");
952 * hildon_time_editor_get_show_seconds:
953 * @editor: the #HildonTimeEditor widget
955 * This function returns a boolean indicating the visibility of
956 * seconds in the #HildonTimeEditor
958 * Returns: TRUE if the seconds are visible
961 hildon_time_editor_get_show_seconds (HildonTimeEditor *editor)
963 HildonTimeEditorPrivate *priv;
965 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
966 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
969 return (priv->show_seconds);
973 * hildon_time_editor_set_duration_mode:
974 * @editor: the #HildonTimeEditor
975 * @duration_mode: enable or disable duration editor mode
977 * This function sets the duration editor mode in which the maximum hours
981 hildon_time_editor_set_duration_mode (HildonTimeEditor *editor,
982 gboolean duration_mode)
984 HildonTimeEditorPrivate *priv;
986 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
988 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
991 if (duration_mode != priv->duration_mode) {
992 priv->duration_mode = duration_mode;
995 /* FIXME: Why do we reset the duration range here?
996 Would change API, so won't touch this for now. */
997 hildon_time_editor_set_duration_range (editor, MIN_DURATION, MAX_DURATION);
998 /* There's no AM/PM label or time picker icon in duration mode.
999 Make sure they're hidden. */
1000 gtk_widget_hide (GTK_WIDGET (priv->ampm_label));
1001 gtk_widget_hide (GTK_WIDGET (priv->ampm_button));
1002 gtk_widget_hide (GTK_WIDGET (priv->iconbutton));
1003 /* Duration mode has seconds by default. */
1004 hildon_time_editor_set_show_seconds (editor, TRUE);
1006 /* Make sure AM/PM label and time picker icons are visible if needed */
1007 if (! priv->clock_24h)
1008 gtk_widget_show (GTK_WIDGET (priv->ampm_label));
1010 gtk_widget_show (GTK_WIDGET (priv->ampm_button));
1011 gtk_widget_show (GTK_WIDGET (priv->iconbutton));
1013 /* Reset the ticks to current time. Anything set in duration mode
1014 * is bound to be invalid or useless in time mode.
1016 hildon_time_editor_set_to_current_time (editor);
1019 g_object_notify (G_OBJECT (editor), "duration_mode");
1024 * hildon_time_editor_get_duration_mode:
1025 * @editor: the #HildonTimeEditor widget
1027 * This function returns a boolean indicating whether the #HildonTimeEditor
1028 * is in the duration mode.
1030 * Returns: TRUE if the #HildonTimeEditor is in duration mode
1033 hildon_time_editor_get_duration_mode (HildonTimeEditor *editor)
1035 HildonTimeEditorPrivate *priv;
1037 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1038 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1041 return (priv->duration_mode);
1045 * hildon_time_editor_set_duration_min:
1046 * @editor: the #HildonTimeEditor widget
1047 * @duration_min: mimimum allowed duration
1049 * Sets the minimum allowed duration for the duration mode.
1050 * Note: Has no effect in time mode
1053 hildon_time_editor_set_duration_min (HildonTimeEditor *editor,
1056 HildonTimeEditorPrivate *priv;
1058 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1059 g_return_if_fail (duration_min >= MIN_DURATION);
1061 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1064 if (! priv->duration_mode )
1067 priv->duration_min = duration_min;
1069 /* Clamp the current value to the minimum if necessary */
1070 if (priv->ticks < duration_min)
1072 hildon_time_editor_set_ticks (editor, duration_min);
1075 g_object_notify (G_OBJECT (editor), "duration_min");
1079 * hildon_time_editor_get_duration_min:
1080 * @editor: the #HildonTimeEditor widget
1082 * This function returns the smallest duration the #HildonTimeEditor
1083 * allows in the duration mode.
1085 * Returns: minimum allowed duration in seconds
1088 hildon_time_editor_get_duration_min (HildonTimeEditor *editor)
1090 HildonTimeEditorPrivate *priv;
1092 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1094 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1097 if(! priv->duration_mode )
1100 return (priv->duration_min);
1104 * hildon_time_editor_set_duration_max:
1105 * @editor: the #HildonTimeEditor widget
1106 * @duration_max: maximum allowed duration in seconds
1108 * Sets the maximum allowed duration in seconds for the duration mode.
1109 * Note: Has no effect in time mode
1112 hildon_time_editor_set_duration_max (HildonTimeEditor *editor,
1115 HildonTimeEditorPrivate *priv;
1117 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1118 g_return_if_fail (duration_max <= MAX_DURATION);
1120 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1123 if (! priv->duration_mode)
1126 priv->duration_max = duration_max;
1128 /* Clamp the current value to the maximum if necessary */
1129 if (priv->ticks > duration_max)
1131 hildon_time_editor_set_ticks (editor, duration_max);
1134 g_object_notify (G_OBJECT (editor), "duration_max");
1138 * hildon_time_editor_get_duration_max:
1139 * @editor: the #HildonTimeEditor widget
1141 * This function returns the longest duration the #HildonTimeEditor
1142 * allows in the duration mode.
1144 * Returns: maximum allowed duration in seconds
1147 hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1149 HildonTimeEditorPrivate *priv;
1151 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1153 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1156 if (! priv->duration_mode)
1159 return (priv->duration_max);
1163 * hildon_time_editor_set_time:
1164 * @editor: the #HildonTimeEditor widget
1169 * This function sets the time on an existing time editor. If the
1170 * time specified by the arguments is invalid, it's fixed.
1171 * The time is assumed to be in 24h format.
1174 hildon_time_editor_set_time (HildonTimeEditor *editor,
1179 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1181 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1185 * hildon_time_editor_get_time:
1186 * @editor: the #HildonTimeEditor widget
1191 * Gets the time of the #HildonTimeEditor widget. The time returned is
1192 * always in 24h format.
1195 hildon_time_editor_get_time (HildonTimeEditor *editor,
1200 HildonTimeEditorPrivate *priv;
1202 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1204 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1207 ticks_to_time (hildon_time_editor_get_ticks (editor), hours, minutes, seconds);
1211 * hildon_time_editor_set_duration_range:
1212 * @editor: the #HildonTimeEditor widget
1213 * @min_seconds: minimum allowed time in seconds
1214 * @max_seconds: maximum allowed time in seconds
1216 * Sets the duration editor time range of the #HildonTimeEditor widget.
1219 hildon_time_editor_set_duration_range (HildonTimeEditor *editor,
1223 HildonTimeEditorPrivate *priv;
1226 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1228 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1231 /* Swap values if reversed */
1232 if (min_seconds > max_seconds)
1235 max_seconds = min_seconds;
1239 hildon_time_editor_set_duration_max (editor, max_seconds);
1240 hildon_time_editor_set_duration_min (editor, min_seconds);
1242 if (priv->duration_mode) {
1243 /* Set minimum allowed value for duration editor.
1244 FIXME: Shouldn't it be changed only if it's not in range?
1245 Would change API, so won't touch this for now. */
1246 hildon_time_editor_set_ticks (editor, min_seconds);
1251 * hildon_time_editor_get_duration_range:
1252 * @editor: the #HildonTimeEditor widget
1253 * @min_seconds: pointer to guint
1254 * @max_seconds: pointer to guint
1256 * Gets the duration editor time range of the #HildonTimeEditor widget.
1259 hildon_time_editor_get_duration_range (HildonTimeEditor *editor,
1263 HildonTimeEditorPrivate *priv;
1265 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1267 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1270 *min_seconds = priv->duration_min;
1271 *max_seconds = priv->duration_max;
1275 hildon_time_editor_check_locale (HildonTimeEditor *editor)
1277 HildonTimeEditorPrivate *priv;
1279 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1282 /* Update time separator symbols */
1283 hildon_time_editor_get_time_separators (GTK_LABEL (priv->hm_label), GTK_LABEL (priv->sec_label));
1285 /* Get AM/PM symbols. */
1286 priv->am_symbol = g_strdup (nl_langinfo (AM_STR));
1287 priv->pm_symbol = g_strdup (nl_langinfo (PM_STR));
1289 if (priv->am_symbol[0] == '\0')
1292 /* 12h clock mode. Check if AM/PM should be before or after time.
1293 %p is the AM/PM string, so we assume that if the format string
1294 begins with %p it's in the beginning, and in any other case it's
1295 in the end (although that's not necessarily the case). */
1296 if (strncmp (nl_langinfo (T_FMT_AMPM), "%p", 2) == 0)
1297 priv->ampm_pos_after = FALSE;
1303 hildon_time_editor_entry_focus_in (GtkWidget *widget,
1304 GdkEventFocus *event,
1307 g_idle_add ((GSourceFunc) hildon_time_editor_entry_select_all,
1308 GTK_ENTRY (widget));
1314 hildon_time_editor_time_error (HildonTimeEditor *editor,
1315 HildonDateTimeError type)
1320 /* Returns negative if we didn't get value,
1321 * and should stop further validation
1324 validated_conversion (HildonTimeEditorPrivate *priv,
1329 gboolean allow_intermediate,
1331 GString *error_string)
1337 text = gtk_entry_get_text (GTK_ENTRY (field));
1339 if (text && text[0])
1341 /* Try to convert entry text to number */
1342 value = strtol (text, &tail, 10);
1344 /* Check if conversion succeeded */
1345 if ((tail[0] == 0) && !(text[0] == '-'))
1348 g_string_printf (error_string, _("ckct_ib_maximum_value"), max);
1349 priv->error_widget = field;
1350 *error_code = MAX_VALUE;
1354 if (value < min && !allow_intermediate) {
1355 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1356 priv->error_widget = field;
1357 *error_code = MIN_VALUE;
1364 /* We'll handle failed conversions soon */
1367 if ((tail[0] == '-') || (text[0] == '-'))
1369 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1370 priv->error_widget = field;
1371 *error_code = MIN_VALUE;
1376 else if (allow_intermediate)
1377 return -1; /* Empty field while user is still editing. No error, but
1378 cannot validate either... */
1379 else /* Empty field: show error and set value to minimum allowed */
1381 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1382 priv->error_widget = field;
1383 *error_code = WITHIN_RANGE;
1387 /* Empty field and not allowed intermediated OR failed conversion */
1388 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1389 priv->error_widget = field;
1390 *error_code = WITHIN_RANGE;
1395 hildon_time_editor_real_validate (HildonTimeEditor *editor,
1396 gboolean allow_intermediate,
1397 GString *error_string)
1399 HildonTimeEditorPrivate *priv;
1400 guint h, m, s, ticks;
1402 guint max_hours, min_hours, def_hours;
1403 guint max_minutes, min_minutes, def_minutes;
1404 guint max_seconds, min_seconds, def_seconds;
1407 g_assert (HILDON_IS_TIME_EDITOR (editor));
1409 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1412 /* Find limits for field based validation. */
1413 if (priv->duration_mode)
1415 ticks_to_time (priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1416 ticks_to_time (priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1418 if (priv->clock_24h) {
1419 max_hours = HOURS_MAX_24;
1420 min_hours = HOURS_MIN_24;
1422 max_hours = HOURS_MAX_12;
1423 min_hours = HOURS_MIN_12;
1427 hildon_time_editor_get_time (editor, &def_hours, &def_minutes, &def_seconds);
1429 /* Get time components from fields and validate them... */
1430 if (priv->show_hours) {
1431 h = validated_conversion (priv, priv->entries[ENTRY_HOURS], min_hours, max_hours, def_hours,
1432 allow_intermediate, &error_code, error_string);
1433 if (priv->error_widget == priv->entries[ENTRY_HOURS])
1434 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, hour_errors[error_code], &r);
1435 if ((gint) h < 0) return;
1438 m = validated_conversion (priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX, def_minutes,
1439 allow_intermediate, &error_code, error_string);
1440 if (priv->error_widget == priv->entries[ENTRY_MINS])
1441 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, min_errors[error_code], &r);
1442 if ((gint) m < 0) return;
1443 if (priv->show_seconds) {
1444 s = validated_conversion (priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX, def_seconds,
1445 allow_intermediate, &error_code, error_string);
1446 if (priv->error_widget == priv->entries[ENTRY_SECS])
1447 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, sec_errors[error_code], &r);
1448 if ((gint) s < 0) return;
1452 /* Ok, we now do separate check that tick count is valid for duration mode */
1453 if (priv->duration_mode)
1455 ticks = TICKS(h, m, s);
1457 if (ticks < priv->duration_min && !allow_intermediate)
1459 g_string_printf (error_string,
1460 _("ckct_ib_min_allowed_duration_hts"),
1461 min_hours, min_minutes, min_seconds);
1462 hildon_time_editor_set_ticks (editor, priv->duration_min);
1463 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1464 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MIN_DURATION, &r);
1467 else if (ticks > priv->duration_max)
1469 g_string_printf (error_string,
1470 _("ckct_ib_max_allowed_duration_hts"),
1471 max_hours, max_minutes, max_seconds);
1472 hildon_time_editor_set_ticks (editor, priv->duration_max);
1473 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1474 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MAX_DURATION, &r);
1478 else if (! priv->clock_24h)
1479 convert_to_24h (&h, priv->am);
1481 /* The only case when we do not want to refresh the
1482 time display, is when the user is editing a value
1483 (unless the value was out of bounds and we have to fix it) */
1484 if (! allow_intermediate || priv->error_widget)
1485 hildon_time_editor_set_time (editor, h, m, s);
1488 /* Setting text to entries causes entry to recompute itself
1489 in idle callback, which remove selection. Because of this
1490 we need to do selection in idle as well. */
1492 highlight_callback (gpointer data)
1494 HildonTimeEditorPrivate *priv;
1498 g_assert (HILDON_IS_TIME_EDITOR (data));
1499 priv = HILDON_TIME_EDITOR_GET_PRIVATE (data);
1502 GDK_THREADS_ENTER ();
1504 widget = priv->error_widget;
1505 priv->error_widget = NULL;
1507 if (GTK_IS_WIDGET (widget) == FALSE)
1510 /* Avoid revalidation because it will issue the date_error signal
1511 twice when there is an empty field. We must block the signal
1512 for all the entries because we do not know where the focus
1514 for (i = 0; i < ENTRY_COUNT; i++)
1515 g_signal_handlers_block_by_func (priv->entries[i],
1516 (gpointer) hildon_time_editor_entry_focus_out, data);
1517 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1518 gtk_widget_grab_focus (widget);
1519 for (i = 0; i < ENTRY_COUNT; i++)
1520 g_signal_handlers_unblock_by_func (priv->entries[i],
1521 (gpointer) hildon_time_editor_entry_focus_out, data);
1524 priv->highlight_idle = 0;
1525 GDK_THREADS_LEAVE ();
1530 /* Update ticks from current H:M:S entries. If they're invalid, show an
1531 infoprint and update the fields unless they're empty. */
1533 hildon_time_editor_validate (HildonTimeEditor *editor,
1534 gboolean allow_intermediate)
1536 HildonTimeEditorPrivate *priv;
1537 GString *error_message;
1539 g_assert (HILDON_IS_TIME_EDITOR(editor));
1540 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1543 /* if there is already an error we do nothing until it will be managed by the idle */
1544 if (priv->highlight_idle == 0 && priv->skipper == FALSE)
1546 priv->skipper = TRUE;
1547 error_message = g_string_new (NULL);
1548 hildon_time_editor_real_validate (editor,
1549 allow_intermediate, error_message);
1551 if (priv->error_widget)
1553 hildon_banner_show_information (priv->error_widget, NULL,
1554 error_message->str);
1556 priv->highlight_idle = g_idle_add (highlight_callback, editor);
1559 priv->skipper = FALSE;
1560 g_string_free (error_message, TRUE);
1564 /* on inserted text, if entry has two digits, jumps to the next field. */
1566 hildon_time_editor_inserted_text (GtkEditable *editable,
1568 gint new_text_length,
1572 HildonTimeEditor *editor;
1575 HildonTimeEditorPrivate *priv;
1577 entry = GTK_ENTRY (editable);
1578 editor = HILDON_TIME_EDITOR (user_data);
1580 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1583 /* if there is already an error we don't have to do anything */
1584 if (! priv->error_widget)
1586 value = (gchar *) gtk_entry_get_text (entry);
1588 if (strlen (value) == 2)
1590 if (GTK_WIDGET (editable) == priv->entries[ENTRY_HOURS])
1592 /* We already checked the input in changed signal, but
1593 * now we will re-check it again in focus-out we
1594 * intermediate flag set to FALSE */
1595 gtk_widget_grab_focus (priv->entries[ENTRY_MINS]);
1598 else if (GTK_WIDGET (editable) == priv->entries[ENTRY_MINS] &&
1599 GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS]))
1602 gtk_widget_grab_focus (priv->entries[ENTRY_SECS]);
1610 hildon_time_editor_entry_focus_out (GtkWidget *widget,
1611 GdkEventFocus *event,
1614 g_assert (HILDON_IS_TIME_EDITOR (data));
1616 /* Validate the given time and update ticks. */
1617 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1623 hildon_time_editor_ampm_clicked (GtkWidget *widget,
1626 HildonTimeEditor *editor;
1627 HildonTimeEditorPrivate *priv;
1629 g_assert (GTK_IS_WIDGET (widget));
1630 g_assert (HILDON_IS_TIME_EDITOR (data));
1632 editor = HILDON_TIME_EDITOR (data);
1633 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1636 /* First validate the given time and update ticks. */
1637 hildon_time_editor_validate (editor, FALSE);
1639 /* Apply the AM/PM change by moving the current time by 12 hours */
1641 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1642 hildon_time_editor_set_ticks (editor, priv->ticks + 12 * 3600);
1644 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1645 hildon_time_editor_set_ticks (editor, priv->ticks - 12 * 3600);
1652 hildon_time_editor_icon_clicked (GtkWidget *widget,
1655 HildonTimeEditor *editor;
1658 guint h, m, s, result;
1659 HildonTimeEditorPrivate *priv;
1661 g_assert (HILDON_IS_TIME_EDITOR (data));
1663 editor = HILDON_TIME_EDITOR (data);
1664 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1667 /* icon is passive in duration editor mode */
1668 if (hildon_time_editor_get_duration_mode (editor))
1671 /* Validate and do not launch if broken */
1672 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1673 if (priv->error_widget != NULL)
1676 /* Launch HildonTimePicker dialog */
1677 parent = gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW);
1678 picker = hildon_time_picker_new (GTK_WINDOW (parent));
1680 hildon_time_editor_get_time (editor, &h, &m, &s);
1681 hildon_time_picker_set_time (HILDON_TIME_PICKER (picker), h, m);
1683 result = gtk_dialog_run (GTK_DIALOG (picker));
1686 case GTK_RESPONSE_OK:
1687 case GTK_RESPONSE_ACCEPT:
1688 /* Use the selected time */
1689 hildon_time_picker_get_time (HILDON_TIME_PICKER (picker), &h, &m);
1690 hildon_time_editor_set_time (editor, h, m, 0);
1697 gtk_widget_destroy (picker);
1702 hildon_time_editor_size_request (GtkWidget *widget,
1703 GtkRequisition *requisition)
1705 HildonTimeEditor *editor;
1706 HildonTimeEditorPrivate *priv;
1709 editor = HILDON_TIME_EDITOR (widget);
1710 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1712 /* Get frame's size */
1713 gtk_widget_size_request (priv->frame, requisition);
1715 if (GTK_WIDGET_VISIBLE (priv->iconbutton))
1717 gtk_widget_size_request (priv->iconbutton, &req);
1718 /* Reserve space for icon */
1719 requisition->width += req.width + ICON_PRESSED +
1720 HILDON_MARGIN_DEFAULT;
1723 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1724 want to force this since themes might have varying thickness values
1725 which cause the height to change. */
1726 requisition->height = TIME_EDITOR_HEIGHT;
1730 hildon_time_editor_size_allocate (GtkWidget *widget,
1731 GtkAllocation *allocation)
1733 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
1734 GtkAllocation alloc;
1735 GtkRequisition req, max_req;
1740 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1741 widget->allocation = *allocation;
1742 gtk_widget_get_child_requisition (widget, &max_req);
1744 /* Center horizontally */
1745 alloc.x = allocation->x + MAX (allocation->width - max_req.width, 0) / 2;
1746 /* Center vertically */
1747 alloc.y = allocation->y + MAX (allocation->height - max_req.height, 0) / 2;
1749 /* allocate frame */
1751 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1753 gtk_widget_get_child_requisition (priv->frame, &req);
1755 alloc.width = req.width;
1756 alloc.height = max_req.height;
1758 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1760 gtk_widget_size_allocate (priv->frame, &alloc);
1763 if (GTK_WIDGET_VISIBLE (priv->iconbutton)) {
1765 gtk_widget_get_child_requisition (priv->frame, &req);
1767 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1769 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1770 alloc.width = req.width;
1773 gtk_widget_size_allocate (priv->frame, &alloc);
1775 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1778 /* FIXME: ugly way to move labels up. They just don't seem move up
1779 otherwise. This is likely because we force the editor to be
1780 smaller than it otherwise would be. */
1781 alloc = priv->ampm_label->allocation;
1782 alloc.y = allocation->y - 2;
1783 alloc.height = max_req.height + 2;
1784 gtk_widget_size_allocate (priv->ampm_label, &alloc);
1786 alloc = priv->hm_label->allocation;
1787 alloc.y = allocation->y - 2;
1788 alloc.height = max_req.height + 2;
1789 gtk_widget_size_allocate (priv->hm_label, &alloc);
1791 alloc = priv->sec_label->allocation;
1792 alloc.y = allocation->y - 2;
1793 alloc.height = max_req.height + 2;
1794 gtk_widget_size_allocate (priv->sec_label, &alloc);
1798 hildon_time_editor_focus (GtkWidget *widget,
1799 GtkDirectionType direction)
1802 GtkDirectionType effective_direction;
1804 g_assert (HILDON_IS_TIME_EDITOR (widget));
1806 retval = hildon_private_composite_focus (widget, direction, &effective_direction);
1809 return GTK_WIDGET_CLASS (parent_class)->focus (widget, effective_direction);
1815 hildon_time_editor_entry_keypress (GtkEntry *entry,
1819 switch (event->keyval)
1823 hildon_time_editor_icon_clicked (GTK_WIDGET (entry), data);
1829 g_assert_not_reached ();
1833 convert_to_12h (guint *h,
1836 g_assert (0 <= *h && *h < 24);
1838 /* 00:00 to 00:59 add 12 hours */
1839 /* 01:00 to 11:59 straight to am */
1840 /* 12:00 to 12:59 straight to pm */
1841 /* 13:00 to 23:59 subtract 12 hours */
1843 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1844 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1845 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1846 else { *am = FALSE; *h -= 12;}
1850 convert_to_24h (guint *h,
1853 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1858 else if (! am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1865 * hildon_time_editor_set_show_hours:
1866 * @editor: The #HildonTimeEditor.
1867 * @show_hours: Enable or disable showing of hours.
1869 * This function shows or hides the hours field.
1873 hildon_time_editor_set_show_hours (HildonTimeEditor *editor,
1874 gboolean show_hours)
1876 HildonTimeEditorPrivate *priv;
1878 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1880 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1883 if (show_hours != priv->show_hours) {
1884 priv->show_hours = show_hours;
1886 /* show/hide hours field and its ':' label if the value changed. */
1888 gtk_widget_show (priv->entries[ENTRY_HOURS]);
1889 gtk_widget_show (priv->hm_label);
1891 gtk_widget_hide (priv->entries[ENTRY_HOURS]);
1892 gtk_widget_hide (priv->hm_label);
1895 g_object_notify (G_OBJECT (editor), "show_hours");
1900 * hildon_time_editor_get_show_hours:
1901 * @editor: the @HildonTimeEditor widget.
1903 * This function returns a boolean indicating the visibility of
1904 * hours in the @HildonTimeEditor
1906 * Return value: TRUE if hours are visible.
1910 hildon_time_editor_get_show_hours (HildonTimeEditor *editor)
1912 HildonTimeEditorPrivate *priv;
1914 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1915 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1918 return priv->show_hours;
1923 hildon_time_editor_entry_select_all (GtkWidget *widget)
1925 GDK_THREADS_ENTER ();
1926 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1927 GDK_THREADS_LEAVE ();