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);
57 #include "hildon-time-editor.h"
58 #include <gtk/gtkhbox.h>
59 #include <gtk/gtkentry.h>
60 #include <gtk/gtkbutton.h>
61 #include <gtk/gtklabel.h>
62 #include <gtk/gtkframe.h>
63 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkenums.h>
70 #include "hildon-defines.h"
71 #include "hildon-time-picker.h"
72 #include "hildon-banner.h"
73 #include "hildon-private.h"
74 #include "hildon-marshalers.h"
75 #include "hildon-enum-types.h"
76 #include "hildon-time-editor-private.h"
78 #define _(String) dgettext("hildon-libs", String)
80 #define c_(String) dgettext("hildon-common-strings", String)
82 #define TICKS(h,m,s) \
83 ((h) * 3600 + (m) * 60 + (s))
85 #define TIME_EDITOR_HEIGHT 30
87 #define ICON_PRESSED 4
89 #define ICON_NAME "qgn_widg_timedit"
91 #define ICON_SIZE "timepicker-size"
93 #define MIN_DURATION 0
95 #define MAX_DURATION TICKS(99, 59, 59)
97 /* Default values for properties */
99 #define HILDON_TIME_EDITOR_TICKS_VALUE 0
101 #define HILDON_TIME_EDITOR_DURATION_MODE FALSE
103 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE 0
105 #define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE TICKS(99, 59, 59)
107 #define HOURS_MAX_24 23
109 #define HOURS_MAX_12 12
111 #define HOURS_MIN_24 0
113 #define HOURS_MIN_12 1
115 #define MINUTES_MAX 59
117 #define SECONDS_MAX 59
119 #define MINUTES_MIN 0
121 #define SECONDS_MIN 0
123 static GtkContainerClass* parent_class;
142 /* Error codes categories */
150 static guint time_editor_signals[LAST_SIGNAL] = { 0 };
152 static guint hour_errors[NUM_ERROR_CODES] = {
153 HILDON_DATE_TIME_ERROR_MAX_HOURS,
154 HILDON_DATE_TIME_ERROR_MIN_HOURS,
155 HILDON_DATE_TIME_ERROR_EMPTY_HOURS };
157 static guint min_errors[NUM_ERROR_CODES] = {
158 HILDON_DATE_TIME_ERROR_MAX_MINS,
159 HILDON_DATE_TIME_ERROR_MIN_MINS,
160 HILDON_DATE_TIME_ERROR_EMPTY_MINS };
162 static guint sec_errors[NUM_ERROR_CODES] = {
163 HILDON_DATE_TIME_ERROR_MAX_SECS,
164 HILDON_DATE_TIME_ERROR_MIN_SECS,
165 HILDON_DATE_TIME_ERROR_EMPTY_SECS };
168 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class);
171 hildon_time_editor_init (HildonTimeEditor *editor);
174 hildon_time_editor_finalize (GObject *obj_self);
177 hildon_time_editor_set_property (GObject *object,
183 hildon_time_editor_get_property (GObject *object,
189 hildon_time_editor_forall (GtkContainer *container,
190 gboolean include_internals,
191 GtkCallback callback,
192 gpointer callback_data);
195 hildon_time_editor_destroy (GtkObject *self);
198 hildon_time_editor_entry_focus_out (GtkWidget *widget,
199 GdkEventFocus *event,
203 hildon_time_editor_entry_focus_in (GtkWidget *widget,
204 GdkEventFocus *event,
208 hildon_time_editor_time_error (HildonTimeEditor *editor,
209 HildonDateTimeError type);
212 hildon_time_editor_ampm_clicked (GtkWidget *widget,
216 hildon_time_editor_icon_clicked (GtkWidget *widget,
220 hildon_time_editor_size_request (GtkWidget *widget,
221 GtkRequisition *requisition);
224 hildon_time_editor_size_allocate (GtkWidget *widget,
225 GtkAllocation *allocation);
228 hildon_time_editor_entry_keypress (GtkEntry *entry,
233 hildon_time_editor_check_locale (HildonTimeEditor *editor);
237 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
240 GtkWidgetTapAndHoldFlags flags);
244 hildon_time_editor_validate (HildonTimeEditor *editor,
245 gboolean allow_intermediate);
248 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor);
251 hildon_time_editor_entry_select_all (GtkWidget *widget);
254 convert_to_12h (guint *h,
258 convert_to_24h (guint *h,
262 ticks_to_time (guint ticks,
268 hildon_time_editor_inserted_text (GtkEditable *editable,
270 gint new_text_length,
275 * hildon_time_editor_get_type:
277 * Initializes and returns the type of a hildon time editor.
279 * @Returns: GType of #HildonTimeEditor
282 hildon_time_editor_get_type (void)
284 static GType editor_type = 0;
287 static const GTypeInfo editor_info = {
288 sizeof(HildonTimeEditorClass),
289 NULL, /* base_init */
290 NULL, /* base_finalize */
291 (GClassInitFunc) hildon_time_editor_class_init,
292 NULL, /* class_finalize */
293 NULL, /* class_data */
294 sizeof(HildonTimeEditor),
296 (GInstanceInitFunc) hildon_time_editor_init,
298 editor_type = g_type_register_static (GTK_TYPE_CONTAINER,
307 hildon_time_editor_forall (GtkContainer *container,
308 gboolean include_internals,
309 GtkCallback callback,
310 gpointer callback_data)
312 HildonTimeEditorPrivate *priv;
314 g_assert (HILDON_IS_TIME_EDITOR (container));
315 g_assert (callback != NULL);
317 priv = HILDON_TIME_EDITOR_GET_PRIVATE (container);
321 if (! include_internals)
324 /* widget that are always shown */
325 (*callback) (priv->iconbutton, callback_data);
326 (*callback) (priv->frame, callback_data);
330 hildon_time_editor_destroy (GtkObject *self)
332 HildonTimeEditorPrivate *priv;
334 priv = HILDON_TIME_EDITOR_GET_PRIVATE (self);
337 if (priv->iconbutton) {
338 gtk_widget_unparent (priv->iconbutton);
339 priv->iconbutton = NULL;
342 gtk_widget_unparent (priv->frame);
346 if (GTK_OBJECT_CLASS (parent_class)->destroy)
347 GTK_OBJECT_CLASS (parent_class)->destroy (self);
351 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class)
353 GObjectClass *object_class = G_OBJECT_CLASS (editor_class);
354 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (editor_class);
355 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (editor_class);
357 parent_class = g_type_class_peek_parent (editor_class);
359 g_type_class_add_private (editor_class, sizeof (HildonTimeEditorPrivate));
361 object_class->get_property = hildon_time_editor_get_property;
362 object_class->set_property = hildon_time_editor_set_property;
363 widget_class->size_request = hildon_time_editor_size_request;
364 widget_class->size_allocate = hildon_time_editor_size_allocate;
366 widget_class->tap_and_hold_setup = hildon_time_editor_tap_and_hold_setup;
368 widget_class->focus = hildon_private_composite_focus;
370 container_class->forall = hildon_time_editor_forall;
371 GTK_OBJECT_CLASS (editor_class)->destroy = hildon_time_editor_destroy;
373 object_class->finalize = hildon_time_editor_finalize;
375 editor_class->time_error = hildon_time_editor_time_error;
377 time_editor_signals[TIME_ERROR] =
378 g_signal_new ("time-error",
379 G_OBJECT_CLASS_TYPE (object_class),
381 G_STRUCT_OFFSET (HildonTimeEditorClass, time_error),
382 g_signal_accumulator_true_handled, NULL,
383 _hildon_marshal_BOOLEAN__ENUM,
384 G_TYPE_BOOLEAN, 1, HILDON_TYPE_DATE_TIME_ERROR);
387 * HildonTimeEditor:ticks:
389 * If editor is in duration mode, contains the duration seconds.
390 * If not, contains seconds since midnight.
392 g_object_class_install_property (object_class, PROP_TICKS,
393 g_param_spec_uint ("ticks",
395 "Current value of duration",
397 HILDON_TIME_EDITOR_TICKS_VALUE,
398 G_PARAM_READABLE | G_PARAM_WRITABLE) );
401 * HildonTimeEditor:show_seconds:
403 * Controls whether seconds are shown in the editor
405 g_object_class_install_property (object_class, PROP_SHOW_SECONDS,
406 g_param_spec_boolean ("show_seconds",
407 "Show seconds property",
408 "Controls whether the seconds are shown in the editor",
410 G_PARAM_READABLE | G_PARAM_WRITABLE) );
413 * HildonTimeEditor:show_hours:
415 * Controls whether hours are shown in the editor
417 g_object_class_install_property (object_class, PROP_SHOW_HOURS,
418 g_param_spec_boolean ("show_hours",
420 "Controls whether the hours field is shown in the editor",
422 G_PARAM_READABLE | G_PARAM_WRITABLE) );
425 * HildonTimeEditor:duration_mode:
427 * Controls whether the TimeEditor is in duration mode
429 g_object_class_install_property (object_class, PROP_DURATION_MODE,
430 g_param_spec_boolean ("duration_mode",
432 "Controls whether the TimeEditor is in duration mode",
433 HILDON_TIME_EDITOR_DURATION_MODE,
434 G_PARAM_READABLE | G_PARAM_WRITABLE) );
437 * HildonTimeEditor:duration_min:
439 * Minimum allowed duration value.
441 g_object_class_install_property (object_class, PROP_DURATION_MIN,
442 g_param_spec_uint ("duration_min",
443 "Minumum duration value",
444 "Smallest possible duration value",
445 MIN_DURATION, MAX_DURATION,
446 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
447 G_PARAM_READABLE | G_PARAM_WRITABLE) );
450 * HildonTimeEditor:duration_max:
452 * Maximum allowed duration value.
454 g_object_class_install_property (object_class, PROP_DURATION_MAX,
455 g_param_spec_uint ("duration_max",
456 "Maximum duration value",
457 "Largest possible duration value",
459 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
460 G_PARAM_READABLE | G_PARAM_WRITABLE) );
465 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
468 GtkWidgetTapAndHoldFlags flags)
470 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
473 /* Forward this tap_and_hold_setup signal to all our child widgets */
474 for (i = 0; i < ENTRY_COUNT; i++)
476 gtk_widget_tap_and_hold_setup (priv->entries[i], menu, func,
477 GTK_TAP_AND_HOLD_NO_SIGNALS);
479 gtk_widget_tap_and_hold_setup (priv->ampm_button, menu, func,
480 GTK_TAP_AND_HOLD_NO_SIGNALS);
481 gtk_widget_tap_and_hold_setup (priv->iconbutton, menu, func,
482 GTK_TAP_AND_HOLD_NONE);
487 hildon_time_editor_entry_changed (GtkWidget *widget,
490 g_assert (HILDON_IS_TIME_EDITOR (data));
491 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), TRUE);
495 hildon_time_editor_init (HildonTimeEditor *editor)
497 HildonTimeEditorPrivate *priv;
498 GtkWidget *hbox, *icon;
501 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
504 gtk_widget_push_composite_child ();
506 /* Setup defaults and create widgets */
508 priv->show_seconds = FALSE;
509 priv->show_hours = TRUE;
510 priv->ampm_pos_after = TRUE;
511 priv->clock_24h = TRUE;
512 priv->duration_mode = FALSE;
513 priv->iconbutton = gtk_button_new();
514 priv->ampm_label = gtk_label_new(NULL);
515 priv->hm_label = gtk_label_new(NULL);
516 priv->sec_label = gtk_label_new(NULL);
517 priv->frame = gtk_frame_new(NULL);
518 priv->ampm_button = gtk_button_new();
519 priv->skipper = FALSE;
521 icon = gtk_image_new_from_icon_name (ICON_NAME, HILDON_ICON_SIZE_SMALL);
522 hbox = gtk_hbox_new (FALSE, 0);
524 GTK_WIDGET_SET_FLAGS (editor, GTK_NO_WINDOW);
525 GTK_WIDGET_UNSET_FLAGS (priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
527 gtk_container_set_border_width (GTK_CONTAINER(priv->frame), 0);
529 gtk_container_add (GTK_CONTAINER (priv->iconbutton), icon);
530 gtk_container_add (GTK_CONTAINER (priv->ampm_button), priv->ampm_label);
531 gtk_button_set_relief(GTK_BUTTON (priv->ampm_button), GTK_RELIEF_NONE);
532 gtk_button_set_focus_on_click (GTK_BUTTON (priv->ampm_button), FALSE);
534 /* Create hour, minute and second entries */
535 for (i = 0; i < ENTRY_COUNT; i++)
537 priv->entries[i] = gtk_entry_new ();
539 /* No frames for entries, so that they all appear to be inside one long entry */
540 gtk_entry_set_has_frame (GTK_ENTRY (priv->entries[i]), FALSE);
543 /* Set the entries to accept only numeric characters */
544 g_object_set (priv->entries[i], "hildon-input-mode", HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
547 /* The entry fields all take exactly two characters */
548 gtk_entry_set_max_length (GTK_ENTRY (priv->entries[i]), 2);
549 gtk_entry_set_width_chars (GTK_ENTRY (priv->entries[i]), 2);
551 g_signal_connect (priv->entries[i], "focus-in-event",
552 G_CALLBACK (hildon_time_editor_entry_focus_in), editor);
553 g_signal_connect (priv->entries[i], "focus-out-event",
554 G_CALLBACK (hildon_time_editor_entry_focus_out), editor);
555 g_signal_connect (priv->entries[i], "key-press-event",
556 G_CALLBACK (hildon_time_editor_entry_keypress), editor);
557 g_signal_connect (priv->entries[i], "changed",
558 G_CALLBACK (hildon_time_editor_entry_changed), editor);
560 /* inserted signal sets time */
561 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
562 G_CALLBACK (hildon_time_editor_inserted_text),
566 /* clicked signal for am/pm label */
567 g_signal_connect (G_OBJECT (priv->ampm_button), "clicked",
568 G_CALLBACK (hildon_time_editor_ampm_clicked), editor);
570 /* clicked signal for icon */
571 g_signal_connect (G_OBJECT (priv->iconbutton), "clicked",
572 G_CALLBACK (hildon_time_editor_icon_clicked), editor);
574 /* Set ourself as the parent of all the widgets we created */
575 gtk_widget_set_parent (priv->iconbutton, GTK_WIDGET(editor));
576 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
577 gtk_box_pack_start (GTK_BOX (hbox), priv->hm_label, FALSE, FALSE, 0);
578 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
579 gtk_box_pack_start (GTK_BOX (hbox), priv->sec_label, FALSE, FALSE, 0);
580 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
581 gtk_box_pack_start (GTK_BOX (hbox), priv->ampm_button, FALSE, FALSE, 0);
582 gtk_misc_set_padding (GTK_MISC (priv->ampm_label), 0, 0);
584 gtk_container_add (GTK_CONTAINER (priv->frame), hbox);
586 /* Show created widgets */
587 gtk_widget_set_parent (priv->frame, GTK_WIDGET(editor));
588 gtk_widget_show_all (priv->frame);
589 gtk_widget_show_all (priv->iconbutton);
591 /* Update AM/PM and time separators settings from locale */
592 if (! hildon_time_editor_check_locale (editor)) {
593 /* Using 12h clock */
594 priv->clock_24h = FALSE;
596 gtk_widget_hide (priv->ampm_button);
599 if (! priv->show_seconds) {
600 gtk_widget_hide (priv->sec_label);
601 gtk_widget_hide (priv->entries[ENTRY_SECS]);
604 /* set the default time to current time. */
605 hildon_time_editor_set_to_current_time (editor);
607 gtk_widget_pop_composite_child ();
611 hildon_time_editor_set_property (GObject *object,
616 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
621 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
624 case PROP_SHOW_SECONDS:
625 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
628 case PROP_SHOW_HOURS:
629 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
632 case PROP_DURATION_MODE:
633 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
636 case PROP_DURATION_MIN:
637 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
640 case PROP_DURATION_MAX:
641 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
645 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
651 hildon_time_editor_get_property (GObject *object,
656 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
662 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
665 case PROP_SHOW_SECONDS:
666 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
669 case PROP_SHOW_HOURS:
670 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
673 case PROP_DURATION_MODE:
674 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
677 case PROP_DURATION_MIN:
678 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
681 case PROP_DURATION_MAX:
682 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
686 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
692 * hildon_time_editor_new:
694 * This function creates a new time editor.
696 * Returns: pointer to a new #HildonTimeEditor widget
699 hildon_time_editor_new (void)
701 return GTK_WIDGET (g_object_new (HILDON_TYPE_TIME_EDITOR, NULL));
705 hildon_time_editor_finalize (GObject *obj_self)
707 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (obj_self);
711 g_free (priv->am_symbol);
714 g_free (priv->pm_symbol);
716 if (priv->highlight_idle)
717 g_source_remove (priv->highlight_idle);
719 if (G_OBJECT_CLASS (parent_class)->finalize)
720 G_OBJECT_CLASS (parent_class)->finalize (obj_self);
724 * hildon_time_editor_get_time_separators:
725 * @hm_sep_label: the label that will show the hour:minutes separator
726 * @ms_sep_label: the label that will show the minutes:seconds separator
728 * Gets hour-minute separator and minute-second separator from current
729 * locale and sets then to the labels we set as parameters. Both
730 * parameters can be NULL if you just want to assing one separator.
734 hildon_time_editor_get_time_separators (GtkLabel *hm_sep_label,
735 GtkLabel *ms_sep_label)
739 GDate locale_test_date;
740 gchar *iter, *endp = NULL;
742 /* Get localized time string */
743 g_date_set_dmy (&locale_test_date, 1, 2, 1970);
744 (void) g_date_strftime (buffer, sizeof (buffer), "%X", &locale_test_date);
746 if (hm_sep_label != NULL)
748 /* Find h-m separator */
750 while (*iter && g_ascii_isdigit (*iter)) iter++;
752 /* Extract h-m separator*/
754 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
755 separator = g_strndup (iter, endp - iter);
756 gtk_label_set_label (hm_sep_label, separator);
760 if (ms_sep_label != NULL)
762 /* Find m-s separator */
764 while (*iter && g_ascii_isdigit (*iter)) iter++;
766 /* Extract m-s separator*/
768 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
769 separator = g_strndup (iter, endp - iter);
770 gtk_label_set_label (ms_sep_label, separator);
775 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
777 ticks_to_time (guint ticks,
784 *hours = ticks / 3600;
786 *minutes = left / 60;
787 *seconds = left % 60;
791 * hildon_time_editor_set_ticks:
792 * @editor: the #HildonTimeEditor widget
793 * @ticks: the duration to set, in seconds
795 * Sets the current duration in seconds. This means seconds from
796 * midnight, if not in duration mode. In case of any errors, it tries
801 hildon_time_editor_set_ticks (HildonTimeEditor *editor,
804 HildonTimeEditorPrivate *priv;
808 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
810 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
813 /* Validate ticks. If it's too low or too high, set it to
814 min/max value for the current mode. */
815 if (priv->duration_mode)
816 priv->ticks = CLAMP (ticks, priv->duration_min, priv->duration_max);
818 /* Check that ticks value is valid. We only need to check that hours
820 ticks_to_time (ticks, &h, &m, &s);
821 if (h > HOURS_MAX_24)
822 ticks = TICKS(HOURS_MAX_24, m, s);
827 /* Get the time in H:M:S. */
828 ticks_to_time (priv->ticks, &h, &m, &s);
830 if (!priv->clock_24h && ! priv->duration_mode)
832 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
833 convert_to_12h (&h, &priv->am);
836 /* Set H:M:S values to entries. We do not want to invoke validation
837 callbacks (since they can cause new call to this function), so we
838 block signals while setting values. */
839 for (i = 0; i < ENTRY_COUNT; i++)
841 g_signal_handlers_block_by_func(priv->entries[i],
842 (gpointer) hildon_time_editor_entry_changed, editor);
844 g_signal_handlers_block_by_func(priv->entries[i],
845 (gpointer) hildon_time_editor_inserted_text, editor);
847 g_signal_handlers_block_by_func(priv->entries[i],
848 (gpointer) hildon_time_editor_entry_focus_out, editor);
851 g_snprintf (str, sizeof (str), "%02u", h);
852 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_HOURS]), str);
854 g_snprintf(str, sizeof (str), "%02u", m);
855 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_MINS]), str);
857 g_snprintf(str, sizeof (str), "%02u", s);
858 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_SECS]), str);
860 for (i = 0; i < ENTRY_COUNT; i++)
862 g_signal_handlers_unblock_by_func (priv->entries[i],
863 (gpointer) hildon_time_editor_entry_changed, editor);
865 g_signal_handlers_unblock_by_func (priv->entries[i],
866 (gpointer) hildon_time_editor_inserted_text, editor);
868 g_signal_handlers_unblock_by_func (priv->entries[i],
869 (gpointer) hildon_time_editor_entry_focus_out, editor);
872 /* Update AM/PM label in case we're in 12h mode */
873 gtk_label_set_label( GTK_LABEL (priv->ampm_label),
874 priv->am ? priv->am_symbol : priv->pm_symbol);
876 g_object_notify (G_OBJECT (editor), "ticks");
880 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor)
886 tm = localtime (&now);
889 hildon_time_editor_set_time (editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
893 * hildon_time_editor_get_ticks:
894 * @editor: the #HildonTimeEditor widget
896 * This function returns the current duration, in seconds.
897 * This means seconds from midnight, if not in duration mode.
899 * Returns: current duration in seconds
902 hildon_time_editor_get_ticks (HildonTimeEditor *editor)
904 HildonTimeEditorPrivate *priv;
906 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
908 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
911 return (priv->ticks);
915 * hildon_time_editor_set_show_seconds:
916 * @editor: the #HildonTimeEditor
917 * @show_seconds: enable or disable showing of seconds
919 * This function shows or hides the seconds field.
922 hildon_time_editor_set_show_seconds (HildonTimeEditor *editor,
923 gboolean show_seconds)
925 HildonTimeEditorPrivate *priv;
927 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
929 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
932 if (show_seconds != priv->show_seconds) {
933 priv->show_seconds = show_seconds;
935 /* show/hide seconds field and its ':' label if the value changed. */
937 gtk_widget_show (priv->entries[ENTRY_SECS]);
938 gtk_widget_show (priv->sec_label);
940 gtk_widget_hide (priv->entries[ENTRY_SECS]);
941 gtk_widget_hide (priv->sec_label);
944 g_object_notify (G_OBJECT (editor), "show_seconds");
949 * hildon_time_editor_get_show_seconds:
950 * @editor: the #HildonTimeEditor widget
952 * This function returns a boolean indicating the visibility of
953 * seconds in the #HildonTimeEditor
955 * Returns: TRUE if the seconds are visible
958 hildon_time_editor_get_show_seconds (HildonTimeEditor *editor)
960 HildonTimeEditorPrivate *priv;
962 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
963 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
966 return (priv->show_seconds);
970 * hildon_time_editor_set_duration_mode:
971 * @editor: the #HildonTimeEditor
972 * @duration_mode: enable or disable duration editor mode
974 * This function sets the duration editor mode in which the maximum hours
978 hildon_time_editor_set_duration_mode (HildonTimeEditor *editor,
979 gboolean duration_mode)
981 HildonTimeEditorPrivate *priv;
983 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
985 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
988 if (duration_mode != priv->duration_mode) {
989 priv->duration_mode = duration_mode;
992 /* FIXME: Why do we reset the duration range here?
993 Would change API, so won't touch this for now. */
994 hildon_time_editor_set_duration_range (editor, MIN_DURATION, MAX_DURATION);
995 /* There's no AM/PM label or time picker icon in duration mode.
996 Make sure they're hidden. */
997 gtk_widget_hide (GTK_WIDGET (priv->ampm_label));
998 gtk_widget_hide (GTK_WIDGET (priv->ampm_button));
999 gtk_widget_hide (GTK_WIDGET (priv->iconbutton));
1000 /* Duration mode has seconds by default. */
1001 hildon_time_editor_set_show_seconds (editor, TRUE);
1003 /* Make sure AM/PM label and time picker icons are visible if needed */
1004 if (! priv->clock_24h)
1005 gtk_widget_show (GTK_WIDGET (priv->ampm_label));
1007 gtk_widget_show (GTK_WIDGET (priv->ampm_button));
1008 gtk_widget_show (GTK_WIDGET (priv->iconbutton));
1010 /* Reset the ticks to current time. Anything set in duration mode
1011 * is bound to be invalid or useless in time mode.
1013 hildon_time_editor_set_to_current_time (editor);
1016 g_object_notify (G_OBJECT (editor), "duration_mode");
1021 * hildon_time_editor_get_duration_mode:
1022 * @editor: the #HildonTimeEditor widget
1024 * This function returns a boolean indicating whether the #HildonTimeEditor
1025 * is in the duration mode.
1027 * Returns: TRUE if the #HildonTimeEditor is in duration mode
1030 hildon_time_editor_get_duration_mode (HildonTimeEditor *editor)
1032 HildonTimeEditorPrivate *priv;
1034 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1035 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1038 return (priv->duration_mode);
1042 * hildon_time_editor_set_duration_min:
1043 * @editor: the #HildonTimeEditor widget
1044 * @duration_min: mimimum allowed duration
1046 * Sets the minimum allowed duration for the duration mode.
1047 * Note: Has no effect in time mode
1050 hildon_time_editor_set_duration_min (HildonTimeEditor *editor,
1053 HildonTimeEditorPrivate *priv;
1055 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1056 g_return_if_fail (duration_min >= MIN_DURATION);
1058 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1061 if (! priv->duration_mode )
1064 priv->duration_min = duration_min;
1066 /* Clamp the current value to the minimum if necessary */
1067 if (priv->ticks < duration_min)
1069 hildon_time_editor_set_ticks (editor, duration_min);
1072 g_object_notify (G_OBJECT (editor), "duration_min");
1076 * hildon_time_editor_get_duration_min:
1077 * @editor: the #HildonTimeEditor widget
1079 * This function returns the smallest duration the #HildonTimeEditor
1080 * allows in the duration mode.
1082 * Returns: minimum allowed duration in seconds
1085 hildon_time_editor_get_duration_min (HildonTimeEditor *editor)
1087 HildonTimeEditorPrivate *priv;
1089 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1091 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1094 if(! priv->duration_mode )
1097 return (priv->duration_min);
1101 * hildon_time_editor_set_duration_max:
1102 * @editor: the #HildonTimeEditor widget
1103 * @duration_max: maximum allowed duration in seconds
1105 * Sets the maximum allowed duration in seconds for the duration mode.
1106 * Note: Has no effect in time mode
1109 hildon_time_editor_set_duration_max (HildonTimeEditor *editor,
1112 HildonTimeEditorPrivate *priv;
1114 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1115 g_return_if_fail (duration_max <= MAX_DURATION);
1117 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1120 if (! priv->duration_mode)
1123 priv->duration_max = duration_max;
1125 /* Clamp the current value to the maximum if necessary */
1126 if (priv->ticks > duration_max)
1128 hildon_time_editor_set_ticks (editor, duration_max);
1131 g_object_notify (G_OBJECT (editor), "duration_max");
1135 * hildon_time_editor_get_duration_max:
1136 * @editor: the #HildonTimeEditor widget
1138 * This function returns the longest duration the #HildonTimeEditor
1139 * allows in the duration mode.
1141 * Returns: maximum allowed duration in seconds
1144 hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1146 HildonTimeEditorPrivate *priv;
1148 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1150 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1153 if (! priv->duration_mode)
1156 return (priv->duration_max);
1160 * hildon_time_editor_set_time:
1161 * @editor: the #HildonTimeEditor widget
1166 * This function sets the time on an existing time editor. If the
1167 * time specified by the arguments is invalid, it's fixed.
1168 * The time is assumed to be in 24h format.
1171 hildon_time_editor_set_time (HildonTimeEditor *editor,
1176 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1178 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1182 * hildon_time_editor_get_time:
1183 * @editor: the #HildonTimeEditor widget
1188 * Gets the time of the #HildonTimeEditor widget. The time returned is
1189 * always in 24h format.
1192 hildon_time_editor_get_time (HildonTimeEditor *editor,
1197 HildonTimeEditorPrivate *priv;
1199 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1201 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1204 ticks_to_time (hildon_time_editor_get_ticks (editor), hours, minutes, seconds);
1208 * hildon_time_editor_set_duration_range:
1209 * @editor: the #HildonTimeEditor widget
1210 * @min_seconds: minimum allowed time in seconds
1211 * @max_seconds: maximum allowed time in seconds
1213 * Sets the duration editor time range of the #HildonTimeEditor widget.
1216 hildon_time_editor_set_duration_range (HildonTimeEditor *editor,
1220 HildonTimeEditorPrivate *priv;
1223 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1225 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1228 /* Swap values if reversed */
1229 if (min_seconds > max_seconds)
1232 max_seconds = min_seconds;
1236 hildon_time_editor_set_duration_max (editor, max_seconds);
1237 hildon_time_editor_set_duration_min (editor, min_seconds);
1239 if (priv->duration_mode) {
1240 /* Set minimum allowed value for duration editor.
1241 FIXME: Shouldn't it be changed only if it's not in range?
1242 Would change API, so won't touch this for now. */
1243 hildon_time_editor_set_ticks (editor, min_seconds);
1248 * hildon_time_editor_get_duration_range:
1249 * @editor: the #HildonTimeEditor widget
1250 * @min_seconds: pointer to guint
1251 * @max_seconds: pointer to guint
1253 * Gets the duration editor time range of the #HildonTimeEditor widget.
1256 hildon_time_editor_get_duration_range (HildonTimeEditor *editor,
1260 HildonTimeEditorPrivate *priv;
1262 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1264 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1267 *min_seconds = priv->duration_min;
1268 *max_seconds = priv->duration_max;
1272 hildon_time_editor_check_locale (HildonTimeEditor *editor)
1274 HildonTimeEditorPrivate *priv;
1276 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1279 /* Update time separator symbols */
1280 hildon_time_editor_get_time_separators (GTK_LABEL (priv->hm_label), GTK_LABEL (priv->sec_label));
1282 /* Get AM/PM symbols. */
1283 priv->am_symbol = g_strdup (nl_langinfo (AM_STR));
1284 priv->pm_symbol = g_strdup (nl_langinfo (PM_STR));
1286 if (priv->am_symbol[0] == '\0')
1289 /* 12h clock mode. Check if AM/PM should be before or after time.
1290 %p is the AM/PM string, so we assume that if the format string
1291 begins with %p it's in the beginning, and in any other case it's
1292 in the end (although that's not necessarily the case). */
1293 if (strncmp (nl_langinfo (T_FMT_AMPM), "%p", 2) == 0)
1294 priv->ampm_pos_after = FALSE;
1300 hildon_time_editor_entry_focus_in (GtkWidget *widget,
1301 GdkEventFocus *event,
1304 g_idle_add ((GSourceFunc) hildon_time_editor_entry_select_all,
1305 GTK_ENTRY (widget));
1311 hildon_time_editor_time_error (HildonTimeEditor *editor,
1312 HildonDateTimeError type)
1317 /* Returns negative if we didn't get value,
1318 * and should stop further validation
1321 validated_conversion (HildonTimeEditorPrivate *priv,
1326 gboolean allow_intermediate,
1328 GString *error_string)
1334 text = gtk_entry_get_text (GTK_ENTRY (field));
1336 if (text && text[0])
1338 /* Try to convert entry text to number */
1339 value = strtol (text, &tail, 10);
1341 /* Check if conversion succeeded */
1342 if ((tail[0] == 0) && !(text[0] == '-'))
1345 g_string_printf (error_string, _("ckct_ib_maximum_value"), max);
1346 priv->error_widget = field;
1347 *error_code = MAX_VALUE;
1351 if (value < min && !allow_intermediate) {
1352 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1353 priv->error_widget = field;
1354 *error_code = MIN_VALUE;
1361 /* We'll handle failed conversions soon */
1364 if ((tail[0] == '-') || (text[0] == '-'))
1366 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1367 priv->error_widget = field;
1368 *error_code = MIN_VALUE;
1373 else if (allow_intermediate)
1374 return -1; /* Empty field while user is still editing. No error, but
1375 cannot validate either... */
1376 else /* Empty field: show error and set value to minimum allowed */
1378 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1379 priv->error_widget = field;
1380 *error_code = WITHIN_RANGE;
1384 /* Empty field and not allowed intermediated OR failed conversion */
1385 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1386 priv->error_widget = field;
1387 *error_code = WITHIN_RANGE;
1392 hildon_time_editor_real_validate (HildonTimeEditor *editor,
1393 gboolean allow_intermediate,
1394 GString *error_string)
1396 HildonTimeEditorPrivate *priv;
1397 guint h, m, s, ticks;
1399 guint max_hours, min_hours, def_hours;
1400 guint max_minutes, min_minutes, def_minutes;
1401 guint max_seconds, min_seconds, def_seconds;
1404 g_assert (HILDON_IS_TIME_EDITOR (editor));
1406 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1409 /* Find limits for field based validation. */
1410 if (priv->duration_mode)
1412 ticks_to_time (priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1413 ticks_to_time (priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1415 if (priv->clock_24h) {
1416 max_hours = HOURS_MAX_24;
1417 min_hours = HOURS_MIN_24;
1419 max_hours = HOURS_MAX_12;
1420 min_hours = HOURS_MIN_12;
1424 hildon_time_editor_get_time (editor, &def_hours, &def_minutes, &def_seconds);
1426 /* Get time components from fields and validate them... */
1427 if (priv->show_hours) {
1428 h = validated_conversion (priv, priv->entries[ENTRY_HOURS], min_hours, max_hours, def_hours,
1429 allow_intermediate, &error_code, error_string);
1430 if (priv->error_widget == priv->entries[ENTRY_HOURS])
1431 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, hour_errors[error_code], &r);
1432 if ((gint) h < 0) return;
1435 m = validated_conversion (priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX, def_minutes,
1436 allow_intermediate, &error_code, error_string);
1437 if (priv->error_widget == priv->entries[ENTRY_MINS])
1438 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, min_errors[error_code], &r);
1439 if ((gint) m < 0) return;
1440 if (priv->show_seconds) {
1441 s = validated_conversion (priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX, def_seconds,
1442 allow_intermediate, &error_code, error_string);
1443 if (priv->error_widget == priv->entries[ENTRY_SECS])
1444 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, sec_errors[error_code], &r);
1445 if ((gint) s < 0) return;
1449 /* Ok, we now do separate check that tick count is valid for duration mode */
1450 if (priv->duration_mode)
1452 ticks = TICKS(h, m, s);
1454 if (ticks < priv->duration_min && !allow_intermediate)
1456 g_string_printf (error_string,
1457 _("ckct_ib_min_allowed_duration_hts"),
1458 min_hours, min_minutes, min_seconds);
1459 hildon_time_editor_set_ticks (editor, priv->duration_min);
1460 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1461 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MIN_DURATION, &r);
1464 else if (ticks > priv->duration_max)
1466 g_string_printf (error_string,
1467 _("ckct_ib_max_allowed_duration_hts"),
1468 max_hours, max_minutes, max_seconds);
1469 hildon_time_editor_set_ticks (editor, priv->duration_max);
1470 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1471 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MAX_DURATION, &r);
1475 else if (! priv->clock_24h)
1476 convert_to_24h (&h, priv->am);
1478 /* The only case when we do not want to refresh the
1479 time display, is when the user is editing a value
1480 (unless the value was out of bounds and we have to fix it) */
1481 if (! allow_intermediate || priv->error_widget)
1482 hildon_time_editor_set_time (editor, h, m, s);
1485 /* Setting text to entries causes entry to recompute itself
1486 in idle callback, which remove selection. Because of this
1487 we need to do selection in idle as well. */
1489 highlight_callback (gpointer data)
1491 HildonTimeEditorPrivate *priv;
1495 g_assert (HILDON_IS_TIME_EDITOR (data));
1496 priv = HILDON_TIME_EDITOR_GET_PRIVATE (data);
1499 GDK_THREADS_ENTER ();
1501 widget = priv->error_widget;
1502 priv->error_widget = NULL;
1504 if (GTK_IS_WIDGET (widget) == FALSE)
1507 /* Avoid revalidation because it will issue the date_error signal
1508 twice when there is an empty field. We must block the signal
1509 for all the entries because we do not know where the focus
1511 for (i = 0; i < ENTRY_COUNT; i++)
1512 g_signal_handlers_block_by_func (priv->entries[i],
1513 (gpointer) hildon_time_editor_entry_focus_out, data);
1514 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1515 gtk_widget_grab_focus (widget);
1516 for (i = 0; i < ENTRY_COUNT; i++)
1517 g_signal_handlers_unblock_by_func (priv->entries[i],
1518 (gpointer) hildon_time_editor_entry_focus_out, data);
1521 priv->highlight_idle = 0;
1522 GDK_THREADS_LEAVE ();
1527 /* Update ticks from current H:M:S entries. If they're invalid, show an
1528 infoprint and update the fields unless they're empty. */
1530 hildon_time_editor_validate (HildonTimeEditor *editor,
1531 gboolean allow_intermediate)
1533 HildonTimeEditorPrivate *priv;
1534 GString *error_message;
1536 g_assert (HILDON_IS_TIME_EDITOR(editor));
1537 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1540 /* if there is already an error we do nothing until it will be managed by the idle */
1541 if (priv->highlight_idle == 0 && priv->skipper == FALSE)
1543 priv->skipper = TRUE;
1544 error_message = g_string_new (NULL);
1545 hildon_time_editor_real_validate (editor,
1546 allow_intermediate, error_message);
1548 if (priv->error_widget)
1550 hildon_banner_show_information (priv->error_widget, NULL,
1551 error_message->str);
1553 priv->highlight_idle = g_idle_add (highlight_callback, editor);
1556 priv->skipper = FALSE;
1557 g_string_free (error_message, TRUE);
1561 /* on inserted text, if entry has two digits, jumps to the next field. */
1563 hildon_time_editor_inserted_text (GtkEditable *editable,
1565 gint new_text_length,
1569 HildonTimeEditor *editor;
1572 HildonTimeEditorPrivate *priv;
1574 entry = GTK_ENTRY (editable);
1575 editor = HILDON_TIME_EDITOR (user_data);
1577 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1580 /* if there is already an error we don't have to do anything */
1581 if (! priv->error_widget)
1583 value = (gchar *) gtk_entry_get_text (entry);
1585 if (strlen (value) == 2)
1587 if (GTK_WIDGET (editable) == priv->entries[ENTRY_HOURS])
1589 /* We already checked the input in changed signal, but
1590 * now we will re-check it again in focus-out we
1591 * intermediate flag set to FALSE */
1592 gtk_widget_grab_focus (priv->entries[ENTRY_MINS]);
1595 else if (GTK_WIDGET (editable) == priv->entries[ENTRY_MINS] &&
1596 GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS]))
1599 gtk_widget_grab_focus (priv->entries[ENTRY_SECS]);
1607 hildon_time_editor_entry_focus_out (GtkWidget *widget,
1608 GdkEventFocus *event,
1611 g_assert (HILDON_IS_TIME_EDITOR (data));
1613 /* Validate the given time and update ticks. */
1614 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1620 hildon_time_editor_ampm_clicked (GtkWidget *widget,
1623 HildonTimeEditor *editor;
1624 HildonTimeEditorPrivate *priv;
1626 g_assert (GTK_IS_WIDGET (widget));
1627 g_assert (HILDON_IS_TIME_EDITOR (data));
1629 editor = HILDON_TIME_EDITOR (data);
1630 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1633 /* First validate the given time and update ticks. */
1634 hildon_time_editor_validate (editor, FALSE);
1636 /* Apply the AM/PM change by moving the current time by 12 hours */
1638 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1639 hildon_time_editor_set_ticks (editor, priv->ticks + 12 * 3600);
1641 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1642 hildon_time_editor_set_ticks (editor, priv->ticks - 12 * 3600);
1649 hildon_time_editor_icon_clicked (GtkWidget *widget,
1652 HildonTimeEditor *editor;
1655 guint h, m, s, result;
1656 HildonTimeEditorPrivate *priv;
1658 g_assert (HILDON_IS_TIME_EDITOR (data));
1660 editor = HILDON_TIME_EDITOR (data);
1661 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1664 /* icon is passive in duration editor mode */
1665 if (hildon_time_editor_get_duration_mode (editor))
1668 /* Validate and do not launch if broken */
1669 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1670 if (priv->error_widget != NULL)
1673 /* Launch HildonTimePicker dialog */
1674 parent = gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW);
1675 picker = hildon_time_picker_new (GTK_WINDOW (parent));
1677 hildon_time_editor_get_time (editor, &h, &m, &s);
1678 hildon_time_picker_set_time (HILDON_TIME_PICKER (picker), h, m);
1680 result = gtk_dialog_run (GTK_DIALOG (picker));
1683 case GTK_RESPONSE_OK:
1684 case GTK_RESPONSE_ACCEPT:
1685 /* Use the selected time */
1686 hildon_time_picker_get_time (HILDON_TIME_PICKER (picker), &h, &m);
1687 hildon_time_editor_set_time (editor, h, m, 0);
1694 gtk_widget_destroy (picker);
1699 hildon_time_editor_size_request (GtkWidget *widget,
1700 GtkRequisition *requisition)
1702 HildonTimeEditor *editor;
1703 HildonTimeEditorPrivate *priv;
1706 editor = HILDON_TIME_EDITOR (widget);
1707 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1709 /* Get frame's size */
1710 gtk_widget_size_request (priv->frame, requisition);
1712 if (GTK_WIDGET_VISIBLE (priv->iconbutton))
1714 gtk_widget_size_request (priv->iconbutton, &req);
1715 /* Reserve space for icon */
1716 requisition->width += req.width + ICON_PRESSED +
1717 HILDON_MARGIN_DEFAULT;
1720 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1721 want to force this since themes might have varying thickness values
1722 which cause the height to change. */
1723 requisition->height = TIME_EDITOR_HEIGHT;
1727 hildon_time_editor_size_allocate (GtkWidget *widget,
1728 GtkAllocation *allocation)
1730 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
1731 GtkAllocation alloc;
1732 GtkRequisition req, max_req;
1736 widget->allocation = *allocation;
1737 gtk_widget_get_child_requisition (widget, &max_req);
1739 /* Center horizontally */
1740 alloc.x = allocation->x + MAX (allocation->width - max_req.width, 0) / 2;
1741 /* Center vertically */
1742 alloc.y = allocation->y + MAX (allocation->height - max_req.height, 0) / 2;
1744 /* allocate frame */
1745 gtk_widget_get_child_requisition (priv->frame, &req);
1747 alloc.width = req.width;
1748 alloc.height = max_req.height;
1749 gtk_widget_size_allocate (priv->frame, &alloc);
1752 if (GTK_WIDGET_VISIBLE (priv->iconbutton)) {
1753 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1755 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1756 alloc.width = req.width;
1757 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1760 /* FIXME: ugly way to move labels up. They just don't seem move up
1761 otherwise. This is likely because we force the editor to be
1762 smaller than it otherwise would be. */
1763 alloc = priv->ampm_label->allocation;
1764 alloc.y = allocation->y - 2;
1765 alloc.height = max_req.height + 2;
1766 gtk_widget_size_allocate (priv->ampm_label, &alloc);
1768 alloc = priv->hm_label->allocation;
1769 alloc.y = allocation->y - 2;
1770 alloc.height = max_req.height + 2;
1771 gtk_widget_size_allocate (priv->hm_label, &alloc);
1773 alloc = priv->sec_label->allocation;
1774 alloc.y = allocation->y - 2;
1775 alloc.height = max_req.height + 2;
1776 gtk_widget_size_allocate (priv->sec_label, &alloc);
1780 hildon_time_editor_entry_keypress (GtkEntry *entry,
1784 switch (event->keyval)
1788 hildon_time_editor_icon_clicked (entry, data);
1794 g_assert_not_reached ();
1798 convert_to_12h (guint *h,
1801 g_assert (0 <= *h && *h < 24);
1803 /* 00:00 to 00:59 add 12 hours */
1804 /* 01:00 to 11:59 straight to am */
1805 /* 12:00 to 12:59 straight to pm */
1806 /* 13:00 to 23:59 subtract 12 hours */
1808 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1809 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1810 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1811 else { *am = FALSE; *h -= 12;}
1815 convert_to_24h (guint *h,
1818 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1823 else if (! am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1830 * hildon_time_editor_set_show_hours:
1831 * @editor: The #HildonTimeEditor.
1832 * @show_hours: Enable or disable showing of hours.
1834 * This function shows or hides the hours field.
1838 hildon_time_editor_set_show_hours (HildonTimeEditor *editor,
1839 gboolean show_hours)
1841 HildonTimeEditorPrivate *priv;
1843 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1845 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1848 if (show_hours != priv->show_hours) {
1849 priv->show_hours = show_hours;
1851 /* show/hide hours field and its ':' label if the value changed. */
1853 gtk_widget_show (priv->entries[ENTRY_HOURS]);
1854 gtk_widget_show (priv->hm_label);
1856 gtk_widget_hide (priv->entries[ENTRY_HOURS]);
1857 gtk_widget_hide (priv->hm_label);
1860 g_object_notify (G_OBJECT (editor), "show_hours");
1865 * hildon_time_editor_get_show_hours:
1866 * @editor: the @HildonTimeEditor widget.
1868 * This function returns a boolean indicating the visibility of
1869 * hours in the @HildonTimeEditor
1871 * Return value: TRUE if hours are visible.
1875 hildon_time_editor_get_show_hours (HildonTimeEditor *editor)
1877 HildonTimeEditorPrivate *priv;
1879 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1880 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1883 return priv->show_hours;
1888 hildon_time_editor_entry_select_all (GtkWidget *widget)
1890 GDK_THREADS_ENTER ();
1891 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1892 GDK_THREADS_LEAVE ();