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);
53 #undef HILDON_DISABLE_DEPRECATED
64 #include <gdk/gdkkeysyms.h>
66 #include "hildon-time-editor.h"
67 #include "hildon-defines.h"
68 #include "hildon-time-picker.h"
69 #include "hildon-banner.h"
70 #include "hildon-private.h"
71 #include "hildon-marshalers.h"
72 #include "hildon-enum-types.h"
73 #include "hildon-time-editor-private.h"
75 #define _(String) dgettext("hildon-libs", String)
77 #define c_(String) dgettext("hildon-common-strings", String)
79 #define TICKS(h,m,s) \
80 ((h) * 3600 + (m) * 60 + (s))
82 #define TIME_EDITOR_HEIGHT 30
84 #define ICON_PRESSED 4
86 #define ICON_NAME "qgn_widg_timedit"
88 #define ICON_SIZE "timepicker-size"
90 #define MIN_DURATION 0
92 #define MAX_DURATION TICKS(99, 59, 59)
94 /* Default values for properties */
96 #define HILDON_TIME_EDITOR_TICKS_VALUE 0
98 #define HILDON_TIME_EDITOR_DURATION_MODE FALSE
100 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE 0
102 #define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE TICKS(99, 59, 59)
104 #define HOURS_MAX_24 23
106 #define HOURS_MAX_12 12
108 #define HOURS_MIN_24 0
110 #define HOURS_MIN_12 1
112 #define MINUTES_MAX 59
114 #define SECONDS_MAX 59
116 #define MINUTES_MIN 0
118 #define SECONDS_MIN 0
120 static GtkContainerClass* parent_class;
139 /* Error codes categories */
147 static guint time_editor_signals[LAST_SIGNAL] = { 0 };
149 static guint hour_errors[NUM_ERROR_CODES] = {
150 HILDON_DATE_TIME_ERROR_MAX_HOURS,
151 HILDON_DATE_TIME_ERROR_MIN_HOURS,
152 HILDON_DATE_TIME_ERROR_EMPTY_HOURS };
154 static guint min_errors[NUM_ERROR_CODES] = {
155 HILDON_DATE_TIME_ERROR_MAX_MINS,
156 HILDON_DATE_TIME_ERROR_MIN_MINS,
157 HILDON_DATE_TIME_ERROR_EMPTY_MINS };
159 static guint sec_errors[NUM_ERROR_CODES] = {
160 HILDON_DATE_TIME_ERROR_MAX_SECS,
161 HILDON_DATE_TIME_ERROR_MIN_SECS,
162 HILDON_DATE_TIME_ERROR_EMPTY_SECS };
165 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class);
168 hildon_time_editor_init (HildonTimeEditor *editor);
171 hildon_time_editor_finalize (GObject *obj_self);
174 hildon_time_editor_set_property (GObject *object,
180 hildon_time_editor_get_property (GObject *object,
186 hildon_time_editor_forall (GtkContainer *container,
187 gboolean include_internals,
188 GtkCallback callback,
189 gpointer callback_data);
192 hildon_time_editor_destroy (GtkObject *self);
195 hildon_time_editor_entry_focus_out (GtkWidget *widget,
196 GdkEventFocus *event,
200 hildon_time_editor_entry_focus_in (GtkWidget *widget,
201 GdkEventFocus *event,
205 hildon_time_editor_time_error (HildonTimeEditor *editor,
206 HildonDateTimeError type);
209 hildon_time_editor_ampm_clicked (GtkWidget *widget,
213 hildon_time_editor_icon_clicked (GtkWidget *widget,
217 hildon_time_editor_size_request (GtkWidget *widget,
218 GtkRequisition *requisition);
221 hildon_time_editor_size_allocate (GtkWidget *widget,
222 GtkAllocation *allocation);
225 hildon_time_editor_focus (GtkWidget *widget,
226 GtkDirectionType direction);
229 hildon_time_editor_entry_keypress (GtkEntry *entry,
234 hildon_time_editor_check_locale (HildonTimeEditor *editor);
238 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
241 GtkWidgetTapAndHoldFlags flags);
245 hildon_time_editor_validate (HildonTimeEditor *editor,
246 gboolean allow_intermediate);
249 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor);
252 hildon_time_editor_entry_select_all (GtkWidget *widget);
255 convert_to_12h (guint *h,
259 convert_to_24h (guint *h,
263 ticks_to_time (guint ticks,
269 hildon_time_editor_inserted_text (GtkEditable *editable,
271 gint new_text_length,
276 * hildon_time_editor_get_type:
278 * Initializes and returns the type of a hildon time editor.
280 * @Returns: GType of #HildonTimeEditor
283 hildon_time_editor_get_type (void)
285 static GType editor_type = 0;
288 static const GTypeInfo editor_info = {
289 sizeof(HildonTimeEditorClass),
290 NULL, /* base_init */
291 NULL, /* base_finalize */
292 (GClassInitFunc) hildon_time_editor_class_init,
293 NULL, /* class_finalize */
294 NULL, /* class_data */
295 sizeof(HildonTimeEditor),
297 (GInstanceInitFunc) hildon_time_editor_init,
299 editor_type = g_type_register_static (GTK_TYPE_CONTAINER,
308 hildon_time_editor_forall (GtkContainer *container,
309 gboolean include_internals,
310 GtkCallback callback,
311 gpointer callback_data)
313 HildonTimeEditorPrivate *priv;
315 g_assert (HILDON_IS_TIME_EDITOR (container));
316 g_assert (callback != NULL);
318 priv = HILDON_TIME_EDITOR_GET_PRIVATE (container);
322 if (! include_internals)
325 /* widget that are always shown */
326 (*callback) (priv->iconbutton, callback_data);
327 (*callback) (priv->frame, callback_data);
331 hildon_time_editor_destroy (GtkObject *self)
333 HildonTimeEditorPrivate *priv;
335 priv = HILDON_TIME_EDITOR_GET_PRIVATE (self);
338 if (priv->iconbutton) {
339 gtk_widget_unparent (priv->iconbutton);
340 priv->iconbutton = NULL;
343 gtk_widget_unparent (priv->frame);
347 if (GTK_OBJECT_CLASS (parent_class)->destroy)
348 GTK_OBJECT_CLASS (parent_class)->destroy (self);
352 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class)
354 GObjectClass *object_class = G_OBJECT_CLASS (editor_class);
355 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (editor_class);
356 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (editor_class);
358 parent_class = g_type_class_peek_parent (editor_class);
360 g_type_class_add_private (editor_class, sizeof (HildonTimeEditorPrivate));
362 object_class->get_property = hildon_time_editor_get_property;
363 object_class->set_property = hildon_time_editor_set_property;
364 widget_class->size_request = hildon_time_editor_size_request;
365 widget_class->size_allocate = hildon_time_editor_size_allocate;
366 widget_class->focus = hildon_time_editor_focus;
368 container_class->forall = hildon_time_editor_forall;
369 GTK_OBJECT_CLASS (editor_class)->destroy = hildon_time_editor_destroy;
371 object_class->finalize = hildon_time_editor_finalize;
373 editor_class->time_error = hildon_time_editor_time_error;
375 time_editor_signals[TIME_ERROR] =
376 g_signal_new ("time-error",
377 G_OBJECT_CLASS_TYPE (object_class),
379 G_STRUCT_OFFSET (HildonTimeEditorClass, time_error),
380 g_signal_accumulator_true_handled, NULL,
381 _hildon_marshal_BOOLEAN__ENUM,
382 G_TYPE_BOOLEAN, 1, HILDON_TYPE_DATE_TIME_ERROR);
385 * HildonTimeEditor:ticks:
387 * If editor is in duration mode, contains the duration seconds.
388 * If not, contains seconds since midnight.
390 g_object_class_install_property (object_class, PROP_TICKS,
391 g_param_spec_uint ("ticks",
393 "Current value of duration",
395 HILDON_TIME_EDITOR_TICKS_VALUE,
396 G_PARAM_READABLE | G_PARAM_WRITABLE) );
399 * HildonTimeEditor:show_seconds:
401 * Controls whether seconds are shown in the editor
403 g_object_class_install_property (object_class, PROP_SHOW_SECONDS,
404 g_param_spec_boolean ("show_seconds",
405 "Show seconds property",
406 "Controls whether the seconds are shown in the editor",
408 G_PARAM_READABLE | G_PARAM_WRITABLE) );
411 * HildonTimeEditor:show_hours:
413 * Controls whether hours are shown in the editor
415 g_object_class_install_property (object_class, PROP_SHOW_HOURS,
416 g_param_spec_boolean ("show_hours",
418 "Controls whether the hours field is shown in the editor",
420 G_PARAM_READABLE | G_PARAM_WRITABLE) );
423 * HildonTimeEditor:duration_mode:
425 * Controls whether the TimeEditor is in duration mode
427 g_object_class_install_property (object_class, PROP_DURATION_MODE,
428 g_param_spec_boolean ("duration_mode",
430 "Controls whether the TimeEditor is in duration mode",
431 HILDON_TIME_EDITOR_DURATION_MODE,
432 G_PARAM_READABLE | G_PARAM_WRITABLE) );
435 * HildonTimeEditor:duration_min:
437 * Minimum allowed duration value.
439 g_object_class_install_property (object_class, PROP_DURATION_MIN,
440 g_param_spec_uint ("duration_min",
441 "Minumum duration value",
442 "Smallest possible duration value",
443 MIN_DURATION, MAX_DURATION,
444 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
445 G_PARAM_READABLE | G_PARAM_WRITABLE) );
448 * HildonTimeEditor:duration_max:
450 * Maximum allowed duration value.
452 g_object_class_install_property (object_class, PROP_DURATION_MAX,
453 g_param_spec_uint ("duration_max",
454 "Maximum duration value",
455 "Largest possible duration value",
457 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
458 G_PARAM_READABLE | G_PARAM_WRITABLE) );
463 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
466 GtkWidgetTapAndHoldFlags flags)
468 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
471 /* Forward this tap_and_hold_setup signal to all our child widgets */
472 for (i = 0; i < ENTRY_COUNT; i++)
474 gtk_widget_tap_and_hold_setup (priv->entries[i], menu, func,
475 GTK_TAP_AND_HOLD_NO_SIGNALS);
477 gtk_widget_tap_and_hold_setup (priv->ampm_button, menu, func,
478 GTK_TAP_AND_HOLD_NO_SIGNALS);
479 gtk_widget_tap_and_hold_setup (priv->iconbutton, menu, func,
480 GTK_TAP_AND_HOLD_NONE);
485 hildon_time_editor_entry_changed (GtkWidget *widget,
488 g_assert (HILDON_IS_TIME_EDITOR (data));
489 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), TRUE);
493 hildon_time_editor_init (HildonTimeEditor *editor)
495 HildonTimeEditorPrivate *priv;
496 GtkWidget *hbox, *icon;
499 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
502 gtk_widget_push_composite_child ();
504 /* Setup defaults and create widgets */
506 priv->show_seconds = FALSE;
507 priv->show_hours = TRUE;
508 priv->ampm_pos_after = TRUE;
509 priv->clock_24h = TRUE;
510 priv->duration_mode = FALSE;
511 priv->iconbutton = gtk_button_new();
512 priv->ampm_label = gtk_label_new(NULL);
513 priv->hm_label = gtk_label_new(NULL);
514 priv->sec_label = gtk_label_new(NULL);
515 priv->frame = gtk_frame_new(NULL);
516 priv->ampm_button = gtk_button_new();
517 priv->skipper = FALSE;
519 icon = gtk_image_new_from_icon_name (ICON_NAME, HILDON_ICON_SIZE_SMALL);
520 hbox = gtk_hbox_new (FALSE, 0);
522 GTK_WIDGET_SET_FLAGS (editor, GTK_NO_WINDOW);
523 GTK_WIDGET_UNSET_FLAGS (priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
525 gtk_container_set_border_width (GTK_CONTAINER(priv->frame), 0);
527 gtk_container_add (GTK_CONTAINER (priv->iconbutton), icon);
528 gtk_container_add (GTK_CONTAINER (priv->ampm_button), priv->ampm_label);
529 gtk_button_set_relief(GTK_BUTTON (priv->ampm_button), GTK_RELIEF_NONE);
530 gtk_button_set_focus_on_click (GTK_BUTTON (priv->ampm_button), FALSE);
532 /* Create hour, minute and second entries */
533 for (i = 0; i < ENTRY_COUNT; i++)
535 priv->entries[i] = gtk_entry_new ();
537 /* No frames for entries, so that they all appear to be inside one long entry */
538 gtk_entry_set_has_frame (GTK_ENTRY (priv->entries[i]), FALSE);
541 /* Set the entries to accept only numeric characters */
542 g_object_set (priv->entries[i], "hildon-input-mode", HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
545 /* The entry fields all take exactly two characters */
546 gtk_entry_set_max_length (GTK_ENTRY (priv->entries[i]), 2);
547 gtk_entry_set_width_chars (GTK_ENTRY (priv->entries[i]), 2);
549 g_signal_connect (priv->entries[i], "focus-in-event",
550 G_CALLBACK (hildon_time_editor_entry_focus_in), editor);
551 g_signal_connect (priv->entries[i], "focus-out-event",
552 G_CALLBACK (hildon_time_editor_entry_focus_out), editor);
553 g_signal_connect (priv->entries[i], "key-press-event",
554 G_CALLBACK (hildon_time_editor_entry_keypress), editor);
555 g_signal_connect (priv->entries[i], "changed",
556 G_CALLBACK (hildon_time_editor_entry_changed), editor);
558 /* inserted signal sets time */
559 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
560 G_CALLBACK (hildon_time_editor_inserted_text),
564 /* clicked signal for am/pm label */
565 g_signal_connect (G_OBJECT (priv->ampm_button), "clicked",
566 G_CALLBACK (hildon_time_editor_ampm_clicked), editor);
568 /* clicked signal for icon */
569 g_signal_connect (G_OBJECT (priv->iconbutton), "clicked",
570 G_CALLBACK (hildon_time_editor_icon_clicked), editor);
572 /* Set ourself as the parent of all the widgets we created */
573 gtk_widget_set_parent (priv->iconbutton, GTK_WIDGET(editor));
574 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
575 gtk_box_pack_start (GTK_BOX (hbox), priv->hm_label, FALSE, FALSE, 0);
576 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
577 gtk_box_pack_start (GTK_BOX (hbox), priv->sec_label, FALSE, FALSE, 0);
578 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
579 gtk_box_pack_start (GTK_BOX (hbox), priv->ampm_button, FALSE, FALSE, 0);
580 gtk_misc_set_padding (GTK_MISC (priv->ampm_label), 0, 0);
582 gtk_container_add (GTK_CONTAINER (priv->frame), hbox);
584 /* Show created widgets */
585 gtk_widget_set_parent (priv->frame, GTK_WIDGET(editor));
586 gtk_widget_show_all (priv->frame);
587 gtk_widget_show_all (priv->iconbutton);
589 /* Update AM/PM and time separators settings from locale */
590 if (! hildon_time_editor_check_locale (editor)) {
591 /* Using 12h clock */
592 priv->clock_24h = FALSE;
594 gtk_widget_hide (priv->ampm_button);
597 if (! priv->show_seconds) {
598 gtk_widget_hide (priv->sec_label);
599 gtk_widget_hide (priv->entries[ENTRY_SECS]);
602 /* set the default time to current time. */
603 hildon_time_editor_set_to_current_time (editor);
605 gtk_widget_pop_composite_child ();
608 g_signal_connect (editor, "tap-and-hold-setup",
609 G_CALLBACK (hildon_time_editor_tap_and_hold_setup),
616 hildon_time_editor_set_property (GObject *object,
621 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
626 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
629 case PROP_SHOW_SECONDS:
630 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
633 case PROP_SHOW_HOURS:
634 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
637 case PROP_DURATION_MODE:
638 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
641 case PROP_DURATION_MIN:
642 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
645 case PROP_DURATION_MAX:
646 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
650 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
656 hildon_time_editor_get_property (GObject *object,
661 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
667 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
670 case PROP_SHOW_SECONDS:
671 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
674 case PROP_SHOW_HOURS:
675 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
678 case PROP_DURATION_MODE:
679 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
682 case PROP_DURATION_MIN:
683 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
686 case PROP_DURATION_MAX:
687 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
691 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
697 * hildon_time_editor_new:
699 * This function creates a new time editor.
701 * Returns: pointer to a new #HildonTimeEditor widget
704 hildon_time_editor_new (void)
706 return GTK_WIDGET (g_object_new (HILDON_TYPE_TIME_EDITOR, NULL));
710 hildon_time_editor_finalize (GObject *obj_self)
712 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (obj_self);
716 g_free (priv->am_symbol);
719 g_free (priv->pm_symbol);
721 if (priv->highlight_idle)
722 g_source_remove (priv->highlight_idle);
724 if (G_OBJECT_CLASS (parent_class)->finalize)
725 G_OBJECT_CLASS (parent_class)->finalize (obj_self);
729 * hildon_time_editor_get_time_separators:
730 * @hm_sep_label: the label that will show the hour:minutes separator
731 * @ms_sep_label: the label that will show the minutes:seconds separator
733 * Gets hour-minute separator and minute-second separator from current
734 * locale and sets then to the labels we set as parameters. Both
735 * parameters can be NULL if you just want to assing one separator.
739 hildon_time_editor_get_time_separators (GtkLabel *hm_sep_label,
740 GtkLabel *ms_sep_label)
744 GDate locale_test_date;
745 gchar *iter, *endp = NULL;
747 /* Get localized time string */
748 g_date_set_dmy (&locale_test_date, 1, 2, 1970);
749 (void) g_date_strftime (buffer, sizeof (buffer), "%X", &locale_test_date);
751 if (hm_sep_label != NULL)
753 /* Find h-m separator */
755 while (*iter && g_ascii_isdigit (*iter)) iter++;
757 /* Extract h-m separator*/
759 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
760 separator = g_strndup (iter, endp - iter);
761 gtk_label_set_label (hm_sep_label, separator);
765 if (ms_sep_label != NULL)
767 /* Find m-s separator */
769 while (*iter && g_ascii_isdigit (*iter)) iter++;
771 /* Extract m-s separator*/
773 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
774 separator = g_strndup (iter, endp - iter);
775 gtk_label_set_label (ms_sep_label, separator);
780 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
782 ticks_to_time (guint ticks,
789 *hours = ticks / 3600;
791 *minutes = left / 60;
792 *seconds = left % 60;
796 * hildon_time_editor_set_ticks:
797 * @editor: the #HildonTimeEditor widget
798 * @ticks: the duration to set, in seconds
800 * Sets the current duration in seconds. This means seconds from
801 * midnight, if not in duration mode. In case of any errors, it tries
806 hildon_time_editor_set_ticks (HildonTimeEditor *editor,
809 HildonTimeEditorPrivate *priv;
813 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
815 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
818 /* Validate ticks. If it's too low or too high, set it to
819 min/max value for the current mode. */
820 if (priv->duration_mode)
821 priv->ticks = CLAMP (ticks, priv->duration_min, priv->duration_max);
823 /* Check that ticks value is valid. We only need to check that hours
825 ticks_to_time (ticks, &h, &m, &s);
826 if (h > HOURS_MAX_24)
827 ticks = TICKS(HOURS_MAX_24, m, s);
832 /* Get the time in H:M:S. */
833 ticks_to_time (priv->ticks, &h, &m, &s);
835 if (!priv->clock_24h && ! priv->duration_mode)
837 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
838 convert_to_12h (&h, &priv->am);
841 /* Set H:M:S values to entries. We do not want to invoke validation
842 callbacks (since they can cause new call to this function), so we
843 block signals while setting values. */
844 for (i = 0; i < ENTRY_COUNT; i++)
846 g_signal_handlers_block_by_func(priv->entries[i],
847 (gpointer) hildon_time_editor_entry_changed, editor);
849 g_signal_handlers_block_by_func(priv->entries[i],
850 (gpointer) hildon_time_editor_inserted_text, editor);
852 g_signal_handlers_block_by_func(priv->entries[i],
853 (gpointer) hildon_time_editor_entry_focus_out, editor);
856 g_snprintf (str, sizeof (str), "%02u", h);
857 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_HOURS]), str);
859 g_snprintf(str, sizeof (str), "%02u", m);
860 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_MINS]), str);
862 g_snprintf(str, sizeof (str), "%02u", s);
863 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_SECS]), str);
865 for (i = 0; i < ENTRY_COUNT; i++)
867 g_signal_handlers_unblock_by_func (priv->entries[i],
868 (gpointer) hildon_time_editor_entry_changed, editor);
870 g_signal_handlers_unblock_by_func (priv->entries[i],
871 (gpointer) hildon_time_editor_inserted_text, editor);
873 g_signal_handlers_unblock_by_func (priv->entries[i],
874 (gpointer) hildon_time_editor_entry_focus_out, editor);
877 /* Update AM/PM label in case we're in 12h mode */
878 gtk_label_set_label( GTK_LABEL (priv->ampm_label),
879 priv->am ? priv->am_symbol : priv->pm_symbol);
881 g_object_notify (G_OBJECT (editor), "ticks");
885 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor)
891 tm = localtime (&now);
894 hildon_time_editor_set_time (editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
898 * hildon_time_editor_get_ticks:
899 * @editor: the #HildonTimeEditor widget
901 * This function returns the current duration, in seconds.
902 * This means seconds from midnight, if not in duration mode.
904 * Returns: current duration in seconds
907 hildon_time_editor_get_ticks (HildonTimeEditor *editor)
909 HildonTimeEditorPrivate *priv;
911 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
913 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
916 return (priv->ticks);
920 * hildon_time_editor_set_show_seconds:
921 * @editor: the #HildonTimeEditor
922 * @show_seconds: enable or disable showing of seconds
924 * This function shows or hides the seconds field.
927 hildon_time_editor_set_show_seconds (HildonTimeEditor *editor,
928 gboolean show_seconds)
930 HildonTimeEditorPrivate *priv;
932 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
934 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
937 if (show_seconds != priv->show_seconds) {
938 priv->show_seconds = show_seconds;
940 /* show/hide seconds field and its ':' label if the value changed. */
942 gtk_widget_show (priv->entries[ENTRY_SECS]);
943 gtk_widget_show (priv->sec_label);
945 gtk_widget_hide (priv->entries[ENTRY_SECS]);
946 gtk_widget_hide (priv->sec_label);
949 g_object_notify (G_OBJECT (editor), "show_seconds");
954 * hildon_time_editor_get_show_seconds:
955 * @editor: the #HildonTimeEditor widget
957 * This function returns a boolean indicating the visibility of
958 * seconds in the #HildonTimeEditor
960 * Returns: TRUE if the seconds are visible
963 hildon_time_editor_get_show_seconds (HildonTimeEditor *editor)
965 HildonTimeEditorPrivate *priv;
967 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
968 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
971 return (priv->show_seconds);
975 * hildon_time_editor_set_duration_mode:
976 * @editor: the #HildonTimeEditor
977 * @duration_mode: enable or disable duration editor mode
979 * This function sets the duration editor mode in which the maximum hours
983 hildon_time_editor_set_duration_mode (HildonTimeEditor *editor,
984 gboolean duration_mode)
986 HildonTimeEditorPrivate *priv;
988 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
990 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
993 if (duration_mode != priv->duration_mode) {
994 priv->duration_mode = duration_mode;
997 /* FIXME: Why do we reset the duration range here?
998 Would change API, so won't touch this for now. */
999 hildon_time_editor_set_duration_range (editor, MIN_DURATION, MAX_DURATION);
1000 /* There's no AM/PM label or time picker icon in duration mode.
1001 Make sure they're hidden. */
1002 gtk_widget_hide (GTK_WIDGET (priv->ampm_label));
1003 gtk_widget_hide (GTK_WIDGET (priv->ampm_button));
1004 gtk_widget_hide (GTK_WIDGET (priv->iconbutton));
1005 /* Duration mode has seconds by default. */
1006 hildon_time_editor_set_show_seconds (editor, TRUE);
1008 /* Make sure AM/PM label and time picker icons are visible if needed */
1009 if (! priv->clock_24h)
1010 gtk_widget_show (GTK_WIDGET (priv->ampm_label));
1012 gtk_widget_show (GTK_WIDGET (priv->ampm_button));
1013 gtk_widget_show (GTK_WIDGET (priv->iconbutton));
1015 /* Reset the ticks to current time. Anything set in duration mode
1016 * is bound to be invalid or useless in time mode.
1018 hildon_time_editor_set_to_current_time (editor);
1021 g_object_notify (G_OBJECT (editor), "duration_mode");
1026 * hildon_time_editor_get_duration_mode:
1027 * @editor: the #HildonTimeEditor widget
1029 * This function returns a boolean indicating whether the #HildonTimeEditor
1030 * is in the duration mode.
1032 * Returns: TRUE if the #HildonTimeEditor is in duration mode
1035 hildon_time_editor_get_duration_mode (HildonTimeEditor *editor)
1037 HildonTimeEditorPrivate *priv;
1039 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1040 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1043 return (priv->duration_mode);
1047 * hildon_time_editor_set_duration_min:
1048 * @editor: the #HildonTimeEditor widget
1049 * @duration_min: mimimum allowed duration
1051 * Sets the minimum allowed duration for the duration mode.
1052 * Note: Has no effect in time mode
1055 hildon_time_editor_set_duration_min (HildonTimeEditor *editor,
1058 HildonTimeEditorPrivate *priv;
1060 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1061 g_return_if_fail (duration_min >= MIN_DURATION);
1063 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1066 if (! priv->duration_mode )
1069 priv->duration_min = duration_min;
1071 /* Clamp the current value to the minimum if necessary */
1072 if (priv->ticks < duration_min)
1074 hildon_time_editor_set_ticks (editor, duration_min);
1077 g_object_notify (G_OBJECT (editor), "duration_min");
1081 * hildon_time_editor_get_duration_min:
1082 * @editor: the #HildonTimeEditor widget
1084 * This function returns the smallest duration the #HildonTimeEditor
1085 * allows in the duration mode.
1087 * Returns: minimum allowed duration in seconds
1090 hildon_time_editor_get_duration_min (HildonTimeEditor *editor)
1092 HildonTimeEditorPrivate *priv;
1094 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1096 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1099 if(! priv->duration_mode )
1102 return (priv->duration_min);
1106 * hildon_time_editor_set_duration_max:
1107 * @editor: the #HildonTimeEditor widget
1108 * @duration_max: maximum allowed duration in seconds
1110 * Sets the maximum allowed duration in seconds for the duration mode.
1111 * Note: Has no effect in time mode
1114 hildon_time_editor_set_duration_max (HildonTimeEditor *editor,
1117 HildonTimeEditorPrivate *priv;
1119 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1120 g_return_if_fail (duration_max <= MAX_DURATION);
1122 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1125 if (! priv->duration_mode)
1128 priv->duration_max = duration_max;
1130 /* Clamp the current value to the maximum if necessary */
1131 if (priv->ticks > duration_max)
1133 hildon_time_editor_set_ticks (editor, duration_max);
1136 g_object_notify (G_OBJECT (editor), "duration_max");
1140 * hildon_time_editor_get_duration_max:
1141 * @editor: the #HildonTimeEditor widget
1143 * This function returns the longest duration the #HildonTimeEditor
1144 * allows in the duration mode.
1146 * Returns: maximum allowed duration in seconds
1149 hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1151 HildonTimeEditorPrivate *priv;
1153 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1155 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1158 if (! priv->duration_mode)
1161 return (priv->duration_max);
1165 * hildon_time_editor_set_time:
1166 * @editor: the #HildonTimeEditor widget
1171 * This function sets the time on an existing time editor. If the
1172 * time specified by the arguments is invalid, it's fixed.
1173 * The time is assumed to be in 24h format.
1176 hildon_time_editor_set_time (HildonTimeEditor *editor,
1181 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1183 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1187 * hildon_time_editor_get_time:
1188 * @editor: the #HildonTimeEditor widget
1193 * Gets the time of the #HildonTimeEditor widget. The time returned is
1194 * always in 24h format.
1197 hildon_time_editor_get_time (HildonTimeEditor *editor,
1202 HildonTimeEditorPrivate *priv;
1204 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1206 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1209 ticks_to_time (hildon_time_editor_get_ticks (editor), hours, minutes, seconds);
1213 * hildon_time_editor_set_duration_range:
1214 * @editor: the #HildonTimeEditor widget
1215 * @min_seconds: minimum allowed time in seconds
1216 * @max_seconds: maximum allowed time in seconds
1218 * Sets the duration editor time range of the #HildonTimeEditor widget.
1221 hildon_time_editor_set_duration_range (HildonTimeEditor *editor,
1225 HildonTimeEditorPrivate *priv;
1228 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1230 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1233 /* Swap values if reversed */
1234 if (min_seconds > max_seconds)
1237 max_seconds = min_seconds;
1241 hildon_time_editor_set_duration_max (editor, max_seconds);
1242 hildon_time_editor_set_duration_min (editor, min_seconds);
1244 if (priv->duration_mode) {
1245 /* Set minimum allowed value for duration editor.
1246 FIXME: Shouldn't it be changed only if it's not in range?
1247 Would change API, so won't touch this for now. */
1248 hildon_time_editor_set_ticks (editor, min_seconds);
1253 * hildon_time_editor_get_duration_range:
1254 * @editor: the #HildonTimeEditor widget
1255 * @min_seconds: pointer to guint
1256 * @max_seconds: pointer to guint
1258 * Gets the duration editor time range of the #HildonTimeEditor widget.
1261 hildon_time_editor_get_duration_range (HildonTimeEditor *editor,
1265 HildonTimeEditorPrivate *priv;
1267 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1269 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1272 *min_seconds = priv->duration_min;
1273 *max_seconds = priv->duration_max;
1277 hildon_time_editor_check_locale (HildonTimeEditor *editor)
1279 HildonTimeEditorPrivate *priv;
1281 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1284 /* Update time separator symbols */
1285 hildon_time_editor_get_time_separators (GTK_LABEL (priv->hm_label), GTK_LABEL (priv->sec_label));
1287 /* Get AM/PM symbols. */
1288 priv->am_symbol = g_strdup (nl_langinfo (AM_STR));
1289 priv->pm_symbol = g_strdup (nl_langinfo (PM_STR));
1291 if (priv->am_symbol[0] == '\0')
1294 /* 12h clock mode. Check if AM/PM should be before or after time.
1295 %p is the AM/PM string, so we assume that if the format string
1296 begins with %p it's in the beginning, and in any other case it's
1297 in the end (although that's not necessarily the case). */
1298 if (strncmp (nl_langinfo (T_FMT_AMPM), "%p", 2) == 0)
1299 priv->ampm_pos_after = FALSE;
1305 hildon_time_editor_entry_focus_in (GtkWidget *widget,
1306 GdkEventFocus *event,
1309 g_idle_add ((GSourceFunc) hildon_time_editor_entry_select_all,
1310 GTK_ENTRY (widget));
1316 hildon_time_editor_time_error (HildonTimeEditor *editor,
1317 HildonDateTimeError type)
1322 /* Returns negative if we didn't get value,
1323 * and should stop further validation
1326 validated_conversion (HildonTimeEditorPrivate *priv,
1331 gboolean allow_intermediate,
1333 GString *error_string)
1339 text = gtk_entry_get_text (GTK_ENTRY (field));
1341 if (text && text[0])
1343 /* Try to convert entry text to number */
1344 value = strtol (text, &tail, 10);
1346 /* Check if conversion succeeded */
1347 if ((tail[0] == 0) && !(text[0] == '-'))
1350 g_string_printf (error_string, _("ckct_ib_maximum_value"), max);
1351 priv->error_widget = field;
1352 *error_code = MAX_VALUE;
1356 if (value < min && !allow_intermediate) {
1357 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1358 priv->error_widget = field;
1359 *error_code = MIN_VALUE;
1366 /* We'll handle failed conversions soon */
1369 if ((tail[0] == '-') || (text[0] == '-'))
1371 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1372 priv->error_widget = field;
1373 *error_code = MIN_VALUE;
1378 else if (allow_intermediate)
1379 return -1; /* Empty field while user is still editing. No error, but
1380 cannot validate either... */
1381 else /* Empty field: show error and set value to minimum allowed */
1383 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1384 priv->error_widget = field;
1385 *error_code = WITHIN_RANGE;
1389 /* Empty field and not allowed intermediated OR failed conversion */
1390 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1391 priv->error_widget = field;
1392 *error_code = WITHIN_RANGE;
1397 hildon_time_editor_real_validate (HildonTimeEditor *editor,
1398 gboolean allow_intermediate,
1399 GString *error_string)
1401 HildonTimeEditorPrivate *priv;
1402 guint h, m, s, ticks;
1404 guint max_hours, min_hours, def_hours;
1405 guint max_minutes, min_minutes, def_minutes;
1406 guint max_seconds, min_seconds, def_seconds;
1409 g_assert (HILDON_IS_TIME_EDITOR (editor));
1411 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1414 /* Find limits for field based validation. */
1415 if (priv->duration_mode)
1417 ticks_to_time (priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1418 ticks_to_time (priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1420 if (priv->clock_24h) {
1421 max_hours = HOURS_MAX_24;
1422 min_hours = HOURS_MIN_24;
1424 max_hours = HOURS_MAX_12;
1425 min_hours = HOURS_MIN_12;
1429 hildon_time_editor_get_time (editor, &def_hours, &def_minutes, &def_seconds);
1431 /* Get time components from fields and validate them... */
1432 if (priv->show_hours) {
1433 h = validated_conversion (priv, priv->entries[ENTRY_HOURS], min_hours, max_hours, def_hours,
1434 allow_intermediate, &error_code, error_string);
1435 if (priv->error_widget == priv->entries[ENTRY_HOURS])
1436 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, hour_errors[error_code], &r);
1437 if ((gint) h < 0) return;
1440 m = validated_conversion (priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX, def_minutes,
1441 allow_intermediate, &error_code, error_string);
1442 if (priv->error_widget == priv->entries[ENTRY_MINS])
1443 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, min_errors[error_code], &r);
1444 if ((gint) m < 0) return;
1445 if (priv->show_seconds) {
1446 s = validated_conversion (priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX, def_seconds,
1447 allow_intermediate, &error_code, error_string);
1448 if (priv->error_widget == priv->entries[ENTRY_SECS])
1449 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, sec_errors[error_code], &r);
1450 if ((gint) s < 0) return;
1454 /* Ok, we now do separate check that tick count is valid for duration mode */
1455 if (priv->duration_mode)
1457 ticks = TICKS(h, m, s);
1459 if (ticks < priv->duration_min && !allow_intermediate)
1461 g_string_printf (error_string,
1462 _("ckct_ib_min_allowed_duration_hts"),
1463 min_hours, min_minutes, min_seconds);
1464 hildon_time_editor_set_ticks (editor, priv->duration_min);
1465 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1466 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MIN_DURATION, &r);
1469 else if (ticks > priv->duration_max)
1471 g_string_printf (error_string,
1472 _("ckct_ib_max_allowed_duration_hts"),
1473 max_hours, max_minutes, max_seconds);
1474 hildon_time_editor_set_ticks (editor, priv->duration_max);
1475 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1476 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MAX_DURATION, &r);
1480 else if (! priv->clock_24h)
1481 convert_to_24h (&h, priv->am);
1483 /* The only case when we do not want to refresh the
1484 time display, is when the user is editing a value
1485 (unless the value was out of bounds and we have to fix it) */
1486 if (! allow_intermediate || priv->error_widget)
1487 hildon_time_editor_set_time (editor, h, m, s);
1490 /* Setting text to entries causes entry to recompute itself
1491 in idle callback, which remove selection. Because of this
1492 we need to do selection in idle as well. */
1494 highlight_callback (gpointer data)
1496 HildonTimeEditorPrivate *priv;
1500 g_assert (HILDON_IS_TIME_EDITOR (data));
1501 priv = HILDON_TIME_EDITOR_GET_PRIVATE (data);
1504 GDK_THREADS_ENTER ();
1506 widget = priv->error_widget;
1507 priv->error_widget = NULL;
1509 if (GTK_IS_WIDGET (widget) == FALSE)
1512 /* Avoid revalidation because it will issue the date_error signal
1513 twice when there is an empty field. We must block the signal
1514 for all the entries because we do not know where the focus
1516 for (i = 0; i < ENTRY_COUNT; i++)
1517 g_signal_handlers_block_by_func (priv->entries[i],
1518 (gpointer) hildon_time_editor_entry_focus_out, data);
1519 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1520 gtk_widget_grab_focus (widget);
1521 for (i = 0; i < ENTRY_COUNT; i++)
1522 g_signal_handlers_unblock_by_func (priv->entries[i],
1523 (gpointer) hildon_time_editor_entry_focus_out, data);
1526 priv->highlight_idle = 0;
1527 GDK_THREADS_LEAVE ();
1532 /* Update ticks from current H:M:S entries. If they're invalid, show an
1533 infoprint and update the fields unless they're empty. */
1535 hildon_time_editor_validate (HildonTimeEditor *editor,
1536 gboolean allow_intermediate)
1538 HildonTimeEditorPrivate *priv;
1539 GString *error_message;
1541 g_assert (HILDON_IS_TIME_EDITOR(editor));
1542 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1545 /* if there is already an error we do nothing until it will be managed by the idle */
1546 if (priv->highlight_idle == 0 && priv->skipper == FALSE)
1548 priv->skipper = TRUE;
1549 error_message = g_string_new (NULL);
1550 hildon_time_editor_real_validate (editor,
1551 allow_intermediate, error_message);
1553 if (priv->error_widget)
1555 hildon_banner_show_information (priv->error_widget, NULL,
1556 error_message->str);
1558 priv->highlight_idle = g_idle_add (highlight_callback, editor);
1561 priv->skipper = FALSE;
1562 g_string_free (error_message, TRUE);
1566 /* on inserted text, if entry has two digits, jumps to the next field. */
1568 hildon_time_editor_inserted_text (GtkEditable *editable,
1570 gint new_text_length,
1574 HildonTimeEditor *editor;
1577 HildonTimeEditorPrivate *priv;
1579 entry = GTK_ENTRY (editable);
1580 editor = HILDON_TIME_EDITOR (user_data);
1582 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1585 /* if there is already an error we don't have to do anything */
1586 if (! priv->error_widget)
1588 value = (gchar *) gtk_entry_get_text (entry);
1590 if (strlen (value) == 2)
1592 if (GTK_WIDGET (editable) == priv->entries[ENTRY_HOURS])
1594 /* We already checked the input in changed signal, but
1595 * now we will re-check it again in focus-out we
1596 * intermediate flag set to FALSE */
1597 gtk_widget_grab_focus (priv->entries[ENTRY_MINS]);
1600 else if (GTK_WIDGET (editable) == priv->entries[ENTRY_MINS] &&
1601 GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS]))
1604 gtk_widget_grab_focus (priv->entries[ENTRY_SECS]);
1612 hildon_time_editor_entry_focus_out (GtkWidget *widget,
1613 GdkEventFocus *event,
1616 g_assert (HILDON_IS_TIME_EDITOR (data));
1618 /* Validate the given time and update ticks. */
1619 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1625 hildon_time_editor_ampm_clicked (GtkWidget *widget,
1628 HildonTimeEditor *editor;
1629 HildonTimeEditorPrivate *priv;
1631 g_assert (GTK_IS_WIDGET (widget));
1632 g_assert (HILDON_IS_TIME_EDITOR (data));
1634 editor = HILDON_TIME_EDITOR (data);
1635 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1638 /* First validate the given time and update ticks. */
1639 hildon_time_editor_validate (editor, FALSE);
1641 /* Apply the AM/PM change by moving the current time by 12 hours */
1643 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1644 hildon_time_editor_set_ticks (editor, priv->ticks + 12 * 3600);
1646 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1647 hildon_time_editor_set_ticks (editor, priv->ticks - 12 * 3600);
1654 hildon_time_editor_icon_clicked (GtkWidget *widget,
1657 HildonTimeEditor *editor;
1660 guint h, m, s, result;
1661 HildonTimeEditorPrivate *priv;
1663 g_assert (HILDON_IS_TIME_EDITOR (data));
1665 editor = HILDON_TIME_EDITOR (data);
1666 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1669 /* icon is passive in duration editor mode */
1670 if (hildon_time_editor_get_duration_mode (editor))
1673 /* Validate and do not launch if broken */
1674 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1675 if (priv->error_widget != NULL)
1678 /* Launch HildonTimePicker dialog */
1679 parent = gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW);
1680 picker = hildon_time_picker_new (GTK_WINDOW (parent));
1682 hildon_time_editor_get_time (editor, &h, &m, &s);
1683 hildon_time_picker_set_time (HILDON_TIME_PICKER (picker), h, m);
1685 result = gtk_dialog_run (GTK_DIALOG (picker));
1688 case GTK_RESPONSE_OK:
1689 case GTK_RESPONSE_ACCEPT:
1690 /* Use the selected time */
1691 hildon_time_picker_get_time (HILDON_TIME_PICKER (picker), &h, &m);
1692 hildon_time_editor_set_time (editor, h, m, 0);
1699 gtk_widget_destroy (picker);
1704 hildon_time_editor_size_request (GtkWidget *widget,
1705 GtkRequisition *requisition)
1707 HildonTimeEditor *editor;
1708 HildonTimeEditorPrivate *priv;
1711 editor = HILDON_TIME_EDITOR (widget);
1712 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1714 /* Get frame's size */
1715 gtk_widget_size_request (priv->frame, requisition);
1717 if (GTK_WIDGET_VISIBLE (priv->iconbutton))
1719 gtk_widget_size_request (priv->iconbutton, &req);
1720 /* Reserve space for icon */
1721 requisition->width += req.width + ICON_PRESSED +
1722 HILDON_MARGIN_DEFAULT;
1725 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1726 want to force this since themes might have varying thickness values
1727 which cause the height to change. */
1728 requisition->height = TIME_EDITOR_HEIGHT;
1732 hildon_time_editor_size_allocate (GtkWidget *widget,
1733 GtkAllocation *allocation)
1735 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
1736 GtkAllocation alloc;
1737 GtkRequisition req, max_req;
1742 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1743 widget->allocation = *allocation;
1744 gtk_widget_get_child_requisition (widget, &max_req);
1746 /* Center horizontally */
1747 alloc.x = allocation->x + MAX (allocation->width - max_req.width, 0) / 2;
1748 /* Center vertically */
1749 alloc.y = allocation->y + MAX (allocation->height - max_req.height, 0) / 2;
1751 /* allocate frame */
1753 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1755 gtk_widget_get_child_requisition (priv->frame, &req);
1757 alloc.width = req.width;
1758 alloc.height = max_req.height;
1760 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1762 gtk_widget_size_allocate (priv->frame, &alloc);
1765 if (GTK_WIDGET_VISIBLE (priv->iconbutton)) {
1767 gtk_widget_get_child_requisition (priv->frame, &req);
1769 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1771 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1772 alloc.width = req.width;
1775 gtk_widget_size_allocate (priv->frame, &alloc);
1777 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1780 /* FIXME: ugly way to move labels up. They just don't seem move up
1781 otherwise. This is likely because we force the editor to be
1782 smaller than it otherwise would be. */
1783 alloc = priv->ampm_label->allocation;
1784 alloc.y = allocation->y - 2;
1785 alloc.height = max_req.height + 2;
1786 gtk_widget_size_allocate (priv->ampm_label, &alloc);
1788 alloc = priv->hm_label->allocation;
1789 alloc.y = allocation->y - 2;
1790 alloc.height = max_req.height + 2;
1791 gtk_widget_size_allocate (priv->hm_label, &alloc);
1793 alloc = priv->sec_label->allocation;
1794 alloc.y = allocation->y - 2;
1795 alloc.height = max_req.height + 2;
1796 gtk_widget_size_allocate (priv->sec_label, &alloc);
1800 hildon_time_editor_focus (GtkWidget *widget,
1801 GtkDirectionType direction)
1804 GtkDirectionType effective_direction;
1806 g_assert (HILDON_IS_TIME_EDITOR (widget));
1808 retval = hildon_private_composite_focus (widget, direction, &effective_direction);
1811 return GTK_WIDGET_CLASS (parent_class)->focus (widget, effective_direction);
1817 hildon_time_editor_entry_keypress (GtkEntry *entry,
1821 switch (event->keyval)
1825 hildon_time_editor_icon_clicked (GTK_WIDGET (entry), data);
1831 g_assert_not_reached ();
1835 convert_to_12h (guint *h,
1838 g_assert (0 <= *h && *h < 24);
1840 /* 00:00 to 00:59 add 12 hours */
1841 /* 01:00 to 11:59 straight to am */
1842 /* 12:00 to 12:59 straight to pm */
1843 /* 13:00 to 23:59 subtract 12 hours */
1845 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1846 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1847 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1848 else { *am = FALSE; *h -= 12;}
1852 convert_to_24h (guint *h,
1855 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1860 else if (! am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1867 * hildon_time_editor_set_show_hours:
1868 * @editor: The #HildonTimeEditor.
1869 * @show_hours: Enable or disable showing of hours.
1871 * This function shows or hides the hours field.
1875 hildon_time_editor_set_show_hours (HildonTimeEditor *editor,
1876 gboolean show_hours)
1878 HildonTimeEditorPrivate *priv;
1880 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1882 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1885 if (show_hours != priv->show_hours) {
1886 priv->show_hours = show_hours;
1888 /* show/hide hours field and its ':' label if the value changed. */
1890 gtk_widget_show (priv->entries[ENTRY_HOURS]);
1891 gtk_widget_show (priv->hm_label);
1893 gtk_widget_hide (priv->entries[ENTRY_HOURS]);
1894 gtk_widget_hide (priv->hm_label);
1897 g_object_notify (G_OBJECT (editor), "show_hours");
1902 * hildon_time_editor_get_show_hours:
1903 * @editor: the @HildonTimeEditor widget.
1905 * This function returns a boolean indicating the visibility of
1906 * hours in the @HildonTimeEditor
1908 * Return value: TRUE if hours are visible.
1912 hildon_time_editor_get_show_hours (HildonTimeEditor *editor)
1914 HildonTimeEditorPrivate *priv;
1916 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1917 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1920 return priv->show_hours;
1925 hildon_time_editor_entry_select_all (GtkWidget *widget)
1927 GDK_THREADS_ENTER ();
1928 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1929 GDK_THREADS_LEAVE ();