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_focus (GtkWidget *widget,
229 GtkDirectionType direction);
232 hildon_time_editor_entry_keypress (GtkEntry *entry,
237 hildon_time_editor_check_locale (HildonTimeEditor *editor);
241 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
244 GtkWidgetTapAndHoldFlags flags);
248 hildon_time_editor_validate (HildonTimeEditor *editor,
249 gboolean allow_intermediate);
252 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor);
255 hildon_time_editor_entry_select_all (GtkWidget *widget);
258 convert_to_12h (guint *h,
262 convert_to_24h (guint *h,
266 ticks_to_time (guint ticks,
272 hildon_time_editor_inserted_text (GtkEditable *editable,
274 gint new_text_length,
279 * hildon_time_editor_get_type:
281 * Initializes and returns the type of a hildon time editor.
283 * @Returns: GType of #HildonTimeEditor
286 hildon_time_editor_get_type (void)
288 static GType editor_type = 0;
291 static const GTypeInfo editor_info = {
292 sizeof(HildonTimeEditorClass),
293 NULL, /* base_init */
294 NULL, /* base_finalize */
295 (GClassInitFunc) hildon_time_editor_class_init,
296 NULL, /* class_finalize */
297 NULL, /* class_data */
298 sizeof(HildonTimeEditor),
300 (GInstanceInitFunc) hildon_time_editor_init,
302 editor_type = g_type_register_static (GTK_TYPE_CONTAINER,
311 hildon_time_editor_forall (GtkContainer *container,
312 gboolean include_internals,
313 GtkCallback callback,
314 gpointer callback_data)
316 HildonTimeEditorPrivate *priv;
318 g_assert (HILDON_IS_TIME_EDITOR (container));
319 g_assert (callback != NULL);
321 priv = HILDON_TIME_EDITOR_GET_PRIVATE (container);
325 if (! include_internals)
328 /* widget that are always shown */
329 (*callback) (priv->iconbutton, callback_data);
330 (*callback) (priv->frame, callback_data);
334 hildon_time_editor_destroy (GtkObject *self)
336 HildonTimeEditorPrivate *priv;
338 priv = HILDON_TIME_EDITOR_GET_PRIVATE (self);
341 if (priv->iconbutton) {
342 gtk_widget_unparent (priv->iconbutton);
343 priv->iconbutton = NULL;
346 gtk_widget_unparent (priv->frame);
350 if (GTK_OBJECT_CLASS (parent_class)->destroy)
351 GTK_OBJECT_CLASS (parent_class)->destroy (self);
355 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class)
357 GObjectClass *object_class = G_OBJECT_CLASS (editor_class);
358 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (editor_class);
359 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (editor_class);
361 parent_class = g_type_class_peek_parent (editor_class);
363 g_type_class_add_private (editor_class, sizeof (HildonTimeEditorPrivate));
365 object_class->get_property = hildon_time_editor_get_property;
366 object_class->set_property = hildon_time_editor_set_property;
367 widget_class->size_request = hildon_time_editor_size_request;
368 widget_class->size_allocate = hildon_time_editor_size_allocate;
369 widget_class->focus = hildon_time_editor_focus;
371 container_class->forall = hildon_time_editor_forall;
372 GTK_OBJECT_CLASS (editor_class)->destroy = hildon_time_editor_destroy;
374 object_class->finalize = hildon_time_editor_finalize;
376 editor_class->time_error = hildon_time_editor_time_error;
378 time_editor_signals[TIME_ERROR] =
379 g_signal_new ("time-error",
380 G_OBJECT_CLASS_TYPE (object_class),
382 G_STRUCT_OFFSET (HildonTimeEditorClass, time_error),
383 g_signal_accumulator_true_handled, NULL,
384 _hildon_marshal_BOOLEAN__ENUM,
385 G_TYPE_BOOLEAN, 1, HILDON_TYPE_DATE_TIME_ERROR);
388 * HildonTimeEditor:ticks:
390 * If editor is in duration mode, contains the duration seconds.
391 * If not, contains seconds since midnight.
393 g_object_class_install_property (object_class, PROP_TICKS,
394 g_param_spec_uint ("ticks",
396 "Current value of duration",
398 HILDON_TIME_EDITOR_TICKS_VALUE,
399 G_PARAM_READABLE | G_PARAM_WRITABLE) );
402 * HildonTimeEditor:show_seconds:
404 * Controls whether seconds are shown in the editor
406 g_object_class_install_property (object_class, PROP_SHOW_SECONDS,
407 g_param_spec_boolean ("show_seconds",
408 "Show seconds property",
409 "Controls whether the seconds are shown in the editor",
411 G_PARAM_READABLE | G_PARAM_WRITABLE) );
414 * HildonTimeEditor:show_hours:
416 * Controls whether hours are shown in the editor
418 g_object_class_install_property (object_class, PROP_SHOW_HOURS,
419 g_param_spec_boolean ("show_hours",
421 "Controls whether the hours field is shown in the editor",
423 G_PARAM_READABLE | G_PARAM_WRITABLE) );
426 * HildonTimeEditor:duration_mode:
428 * Controls whether the TimeEditor is in duration mode
430 g_object_class_install_property (object_class, PROP_DURATION_MODE,
431 g_param_spec_boolean ("duration_mode",
433 "Controls whether the TimeEditor is in duration mode",
434 HILDON_TIME_EDITOR_DURATION_MODE,
435 G_PARAM_READABLE | G_PARAM_WRITABLE) );
438 * HildonTimeEditor:duration_min:
440 * Minimum allowed duration value.
442 g_object_class_install_property (object_class, PROP_DURATION_MIN,
443 g_param_spec_uint ("duration_min",
444 "Minumum duration value",
445 "Smallest possible duration value",
446 MIN_DURATION, MAX_DURATION,
447 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
448 G_PARAM_READABLE | G_PARAM_WRITABLE) );
451 * HildonTimeEditor:duration_max:
453 * Maximum allowed duration value.
455 g_object_class_install_property (object_class, PROP_DURATION_MAX,
456 g_param_spec_uint ("duration_max",
457 "Maximum duration value",
458 "Largest possible duration value",
460 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
461 G_PARAM_READABLE | G_PARAM_WRITABLE) );
466 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
469 GtkWidgetTapAndHoldFlags flags)
471 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
474 /* Forward this tap_and_hold_setup signal to all our child widgets */
475 for (i = 0; i < ENTRY_COUNT; i++)
477 gtk_widget_tap_and_hold_setup (priv->entries[i], menu, func,
478 GTK_TAP_AND_HOLD_NO_SIGNALS);
480 gtk_widget_tap_and_hold_setup (priv->ampm_button, menu, func,
481 GTK_TAP_AND_HOLD_NO_SIGNALS);
482 gtk_widget_tap_and_hold_setup (priv->iconbutton, menu, func,
483 GTK_TAP_AND_HOLD_NONE);
488 hildon_time_editor_entry_changed (GtkWidget *widget,
491 g_assert (HILDON_IS_TIME_EDITOR (data));
492 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), TRUE);
496 hildon_time_editor_init (HildonTimeEditor *editor)
498 HildonTimeEditorPrivate *priv;
499 GtkWidget *hbox, *icon;
502 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
505 gtk_widget_push_composite_child ();
507 /* Setup defaults and create widgets */
509 priv->show_seconds = FALSE;
510 priv->show_hours = TRUE;
511 priv->ampm_pos_after = TRUE;
512 priv->clock_24h = TRUE;
513 priv->duration_mode = FALSE;
514 priv->iconbutton = gtk_button_new();
515 priv->ampm_label = gtk_label_new(NULL);
516 priv->hm_label = gtk_label_new(NULL);
517 priv->sec_label = gtk_label_new(NULL);
518 priv->frame = gtk_frame_new(NULL);
519 priv->ampm_button = gtk_button_new();
520 priv->skipper = FALSE;
522 icon = gtk_image_new_from_icon_name (ICON_NAME, HILDON_ICON_SIZE_SMALL);
523 hbox = gtk_hbox_new (FALSE, 0);
525 GTK_WIDGET_SET_FLAGS (editor, GTK_NO_WINDOW);
526 GTK_WIDGET_UNSET_FLAGS (priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
528 gtk_container_set_border_width (GTK_CONTAINER(priv->frame), 0);
530 gtk_container_add (GTK_CONTAINER (priv->iconbutton), icon);
531 gtk_container_add (GTK_CONTAINER (priv->ampm_button), priv->ampm_label);
532 gtk_button_set_relief(GTK_BUTTON (priv->ampm_button), GTK_RELIEF_NONE);
533 gtk_button_set_focus_on_click (GTK_BUTTON (priv->ampm_button), FALSE);
535 /* Create hour, minute and second entries */
536 for (i = 0; i < ENTRY_COUNT; i++)
538 priv->entries[i] = gtk_entry_new ();
540 /* No frames for entries, so that they all appear to be inside one long entry */
541 gtk_entry_set_has_frame (GTK_ENTRY (priv->entries[i]), FALSE);
544 /* Set the entries to accept only numeric characters */
545 g_object_set (priv->entries[i], "hildon-input-mode", HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
548 /* The entry fields all take exactly two characters */
549 gtk_entry_set_max_length (GTK_ENTRY (priv->entries[i]), 2);
550 gtk_entry_set_width_chars (GTK_ENTRY (priv->entries[i]), 2);
552 g_signal_connect (priv->entries[i], "focus-in-event",
553 G_CALLBACK (hildon_time_editor_entry_focus_in), editor);
554 g_signal_connect (priv->entries[i], "focus-out-event",
555 G_CALLBACK (hildon_time_editor_entry_focus_out), editor);
556 g_signal_connect (priv->entries[i], "key-press-event",
557 G_CALLBACK (hildon_time_editor_entry_keypress), editor);
558 g_signal_connect (priv->entries[i], "changed",
559 G_CALLBACK (hildon_time_editor_entry_changed), editor);
561 /* inserted signal sets time */
562 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
563 G_CALLBACK (hildon_time_editor_inserted_text),
567 /* clicked signal for am/pm label */
568 g_signal_connect (G_OBJECT (priv->ampm_button), "clicked",
569 G_CALLBACK (hildon_time_editor_ampm_clicked), editor);
571 /* clicked signal for icon */
572 g_signal_connect (G_OBJECT (priv->iconbutton), "clicked",
573 G_CALLBACK (hildon_time_editor_icon_clicked), editor);
575 /* Set ourself as the parent of all the widgets we created */
576 gtk_widget_set_parent (priv->iconbutton, GTK_WIDGET(editor));
577 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
578 gtk_box_pack_start (GTK_BOX (hbox), priv->hm_label, FALSE, FALSE, 0);
579 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
580 gtk_box_pack_start (GTK_BOX (hbox), priv->sec_label, FALSE, FALSE, 0);
581 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
582 gtk_box_pack_start (GTK_BOX (hbox), priv->ampm_button, FALSE, FALSE, 0);
583 gtk_misc_set_padding (GTK_MISC (priv->ampm_label), 0, 0);
585 gtk_container_add (GTK_CONTAINER (priv->frame), hbox);
587 /* Show created widgets */
588 gtk_widget_set_parent (priv->frame, GTK_WIDGET(editor));
589 gtk_widget_show_all (priv->frame);
590 gtk_widget_show_all (priv->iconbutton);
592 /* Update AM/PM and time separators settings from locale */
593 if (! hildon_time_editor_check_locale (editor)) {
594 /* Using 12h clock */
595 priv->clock_24h = FALSE;
597 gtk_widget_hide (priv->ampm_button);
600 if (! priv->show_seconds) {
601 gtk_widget_hide (priv->sec_label);
602 gtk_widget_hide (priv->entries[ENTRY_SECS]);
605 /* set the default time to current time. */
606 hildon_time_editor_set_to_current_time (editor);
608 gtk_widget_pop_composite_child ();
611 g_signal_connect (editor, "tap-and-hold-setup",
612 G_CALLBACK (hildon_time_editor_tap_and_hold_setup),
619 hildon_time_editor_set_property (GObject *object,
624 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
629 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
632 case PROP_SHOW_SECONDS:
633 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
636 case PROP_SHOW_HOURS:
637 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
640 case PROP_DURATION_MODE:
641 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
644 case PROP_DURATION_MIN:
645 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
648 case PROP_DURATION_MAX:
649 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
653 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
659 hildon_time_editor_get_property (GObject *object,
664 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
670 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
673 case PROP_SHOW_SECONDS:
674 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
677 case PROP_SHOW_HOURS:
678 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
681 case PROP_DURATION_MODE:
682 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
685 case PROP_DURATION_MIN:
686 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
689 case PROP_DURATION_MAX:
690 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
694 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
700 * hildon_time_editor_new:
702 * This function creates a new time editor.
704 * Returns: pointer to a new #HildonTimeEditor widget
707 hildon_time_editor_new (void)
709 return GTK_WIDGET (g_object_new (HILDON_TYPE_TIME_EDITOR, NULL));
713 hildon_time_editor_finalize (GObject *obj_self)
715 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (obj_self);
719 g_free (priv->am_symbol);
722 g_free (priv->pm_symbol);
724 if (priv->highlight_idle)
725 g_source_remove (priv->highlight_idle);
727 if (G_OBJECT_CLASS (parent_class)->finalize)
728 G_OBJECT_CLASS (parent_class)->finalize (obj_self);
732 * hildon_time_editor_get_time_separators:
733 * @hm_sep_label: the label that will show the hour:minutes separator
734 * @ms_sep_label: the label that will show the minutes:seconds separator
736 * Gets hour-minute separator and minute-second separator from current
737 * locale and sets then to the labels we set as parameters. Both
738 * parameters can be NULL if you just want to assing one separator.
742 hildon_time_editor_get_time_separators (GtkLabel *hm_sep_label,
743 GtkLabel *ms_sep_label)
747 GDate locale_test_date;
748 gchar *iter, *endp = NULL;
750 /* Get localized time string */
751 g_date_set_dmy (&locale_test_date, 1, 2, 1970);
752 (void) g_date_strftime (buffer, sizeof (buffer), "%X", &locale_test_date);
754 if (hm_sep_label != NULL)
756 /* Find h-m separator */
758 while (*iter && g_ascii_isdigit (*iter)) iter++;
760 /* Extract h-m separator*/
762 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
763 separator = g_strndup (iter, endp - iter);
764 gtk_label_set_label (hm_sep_label, separator);
768 if (ms_sep_label != NULL)
770 /* Find m-s separator */
772 while (*iter && g_ascii_isdigit (*iter)) iter++;
774 /* Extract m-s separator*/
776 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
777 separator = g_strndup (iter, endp - iter);
778 gtk_label_set_label (ms_sep_label, separator);
783 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
785 ticks_to_time (guint ticks,
792 *hours = ticks / 3600;
794 *minutes = left / 60;
795 *seconds = left % 60;
799 * hildon_time_editor_set_ticks:
800 * @editor: the #HildonTimeEditor widget
801 * @ticks: the duration to set, in seconds
803 * Sets the current duration in seconds. This means seconds from
804 * midnight, if not in duration mode. In case of any errors, it tries
809 hildon_time_editor_set_ticks (HildonTimeEditor *editor,
812 HildonTimeEditorPrivate *priv;
816 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
818 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
821 /* Validate ticks. If it's too low or too high, set it to
822 min/max value for the current mode. */
823 if (priv->duration_mode)
824 priv->ticks = CLAMP (ticks, priv->duration_min, priv->duration_max);
826 /* Check that ticks value is valid. We only need to check that hours
828 ticks_to_time (ticks, &h, &m, &s);
829 if (h > HOURS_MAX_24)
830 ticks = TICKS(HOURS_MAX_24, m, s);
835 /* Get the time in H:M:S. */
836 ticks_to_time (priv->ticks, &h, &m, &s);
838 if (!priv->clock_24h && ! priv->duration_mode)
840 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
841 convert_to_12h (&h, &priv->am);
844 /* Set H:M:S values to entries. We do not want to invoke validation
845 callbacks (since they can cause new call to this function), so we
846 block signals while setting values. */
847 for (i = 0; i < ENTRY_COUNT; i++)
849 g_signal_handlers_block_by_func(priv->entries[i],
850 (gpointer) hildon_time_editor_entry_changed, editor);
852 g_signal_handlers_block_by_func(priv->entries[i],
853 (gpointer) hildon_time_editor_inserted_text, editor);
855 g_signal_handlers_block_by_func(priv->entries[i],
856 (gpointer) hildon_time_editor_entry_focus_out, editor);
859 g_snprintf (str, sizeof (str), "%02u", h);
860 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_HOURS]), str);
862 g_snprintf(str, sizeof (str), "%02u", m);
863 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_MINS]), str);
865 g_snprintf(str, sizeof (str), "%02u", s);
866 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_SECS]), str);
868 for (i = 0; i < ENTRY_COUNT; i++)
870 g_signal_handlers_unblock_by_func (priv->entries[i],
871 (gpointer) hildon_time_editor_entry_changed, editor);
873 g_signal_handlers_unblock_by_func (priv->entries[i],
874 (gpointer) hildon_time_editor_inserted_text, editor);
876 g_signal_handlers_unblock_by_func (priv->entries[i],
877 (gpointer) hildon_time_editor_entry_focus_out, editor);
880 /* Update AM/PM label in case we're in 12h mode */
881 gtk_label_set_label( GTK_LABEL (priv->ampm_label),
882 priv->am ? priv->am_symbol : priv->pm_symbol);
884 g_object_notify (G_OBJECT (editor), "ticks");
888 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor)
894 tm = localtime (&now);
897 hildon_time_editor_set_time (editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
901 * hildon_time_editor_get_ticks:
902 * @editor: the #HildonTimeEditor widget
904 * This function returns the current duration, in seconds.
905 * This means seconds from midnight, if not in duration mode.
907 * Returns: current duration in seconds
910 hildon_time_editor_get_ticks (HildonTimeEditor *editor)
912 HildonTimeEditorPrivate *priv;
914 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
916 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
919 return (priv->ticks);
923 * hildon_time_editor_set_show_seconds:
924 * @editor: the #HildonTimeEditor
925 * @show_seconds: enable or disable showing of seconds
927 * This function shows or hides the seconds field.
930 hildon_time_editor_set_show_seconds (HildonTimeEditor *editor,
931 gboolean show_seconds)
933 HildonTimeEditorPrivate *priv;
935 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
937 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
940 if (show_seconds != priv->show_seconds) {
941 priv->show_seconds = show_seconds;
943 /* show/hide seconds field and its ':' label if the value changed. */
945 gtk_widget_show (priv->entries[ENTRY_SECS]);
946 gtk_widget_show (priv->sec_label);
948 gtk_widget_hide (priv->entries[ENTRY_SECS]);
949 gtk_widget_hide (priv->sec_label);
952 g_object_notify (G_OBJECT (editor), "show_seconds");
957 * hildon_time_editor_get_show_seconds:
958 * @editor: the #HildonTimeEditor widget
960 * This function returns a boolean indicating the visibility of
961 * seconds in the #HildonTimeEditor
963 * Returns: TRUE if the seconds are visible
966 hildon_time_editor_get_show_seconds (HildonTimeEditor *editor)
968 HildonTimeEditorPrivate *priv;
970 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
971 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
974 return (priv->show_seconds);
978 * hildon_time_editor_set_duration_mode:
979 * @editor: the #HildonTimeEditor
980 * @duration_mode: enable or disable duration editor mode
982 * This function sets the duration editor mode in which the maximum hours
986 hildon_time_editor_set_duration_mode (HildonTimeEditor *editor,
987 gboolean duration_mode)
989 HildonTimeEditorPrivate *priv;
991 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
993 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
996 if (duration_mode != priv->duration_mode) {
997 priv->duration_mode = duration_mode;
1000 /* FIXME: Why do we reset the duration range here?
1001 Would change API, so won't touch this for now. */
1002 hildon_time_editor_set_duration_range (editor, MIN_DURATION, MAX_DURATION);
1003 /* There's no AM/PM label or time picker icon in duration mode.
1004 Make sure they're hidden. */
1005 gtk_widget_hide (GTK_WIDGET (priv->ampm_label));
1006 gtk_widget_hide (GTK_WIDGET (priv->ampm_button));
1007 gtk_widget_hide (GTK_WIDGET (priv->iconbutton));
1008 /* Duration mode has seconds by default. */
1009 hildon_time_editor_set_show_seconds (editor, TRUE);
1011 /* Make sure AM/PM label and time picker icons are visible if needed */
1012 if (! priv->clock_24h)
1013 gtk_widget_show (GTK_WIDGET (priv->ampm_label));
1015 gtk_widget_show (GTK_WIDGET (priv->ampm_button));
1016 gtk_widget_show (GTK_WIDGET (priv->iconbutton));
1018 /* Reset the ticks to current time. Anything set in duration mode
1019 * is bound to be invalid or useless in time mode.
1021 hildon_time_editor_set_to_current_time (editor);
1024 g_object_notify (G_OBJECT (editor), "duration_mode");
1029 * hildon_time_editor_get_duration_mode:
1030 * @editor: the #HildonTimeEditor widget
1032 * This function returns a boolean indicating whether the #HildonTimeEditor
1033 * is in the duration mode.
1035 * Returns: TRUE if the #HildonTimeEditor is in duration mode
1038 hildon_time_editor_get_duration_mode (HildonTimeEditor *editor)
1040 HildonTimeEditorPrivate *priv;
1042 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1043 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1046 return (priv->duration_mode);
1050 * hildon_time_editor_set_duration_min:
1051 * @editor: the #HildonTimeEditor widget
1052 * @duration_min: mimimum allowed duration
1054 * Sets the minimum allowed duration for the duration mode.
1055 * Note: Has no effect in time mode
1058 hildon_time_editor_set_duration_min (HildonTimeEditor *editor,
1061 HildonTimeEditorPrivate *priv;
1063 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1064 g_return_if_fail (duration_min >= MIN_DURATION);
1066 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1069 if (! priv->duration_mode )
1072 priv->duration_min = duration_min;
1074 /* Clamp the current value to the minimum if necessary */
1075 if (priv->ticks < duration_min)
1077 hildon_time_editor_set_ticks (editor, duration_min);
1080 g_object_notify (G_OBJECT (editor), "duration_min");
1084 * hildon_time_editor_get_duration_min:
1085 * @editor: the #HildonTimeEditor widget
1087 * This function returns the smallest duration the #HildonTimeEditor
1088 * allows in the duration mode.
1090 * Returns: minimum allowed duration in seconds
1093 hildon_time_editor_get_duration_min (HildonTimeEditor *editor)
1095 HildonTimeEditorPrivate *priv;
1097 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1099 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1102 if(! priv->duration_mode )
1105 return (priv->duration_min);
1109 * hildon_time_editor_set_duration_max:
1110 * @editor: the #HildonTimeEditor widget
1111 * @duration_max: maximum allowed duration in seconds
1113 * Sets the maximum allowed duration in seconds for the duration mode.
1114 * Note: Has no effect in time mode
1117 hildon_time_editor_set_duration_max (HildonTimeEditor *editor,
1120 HildonTimeEditorPrivate *priv;
1122 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1123 g_return_if_fail (duration_max <= MAX_DURATION);
1125 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1128 if (! priv->duration_mode)
1131 priv->duration_max = duration_max;
1133 /* Clamp the current value to the maximum if necessary */
1134 if (priv->ticks > duration_max)
1136 hildon_time_editor_set_ticks (editor, duration_max);
1139 g_object_notify (G_OBJECT (editor), "duration_max");
1143 * hildon_time_editor_get_duration_max:
1144 * @editor: the #HildonTimeEditor widget
1146 * This function returns the longest duration the #HildonTimeEditor
1147 * allows in the duration mode.
1149 * Returns: maximum allowed duration in seconds
1152 hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1154 HildonTimeEditorPrivate *priv;
1156 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1158 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1161 if (! priv->duration_mode)
1164 return (priv->duration_max);
1168 * hildon_time_editor_set_time:
1169 * @editor: the #HildonTimeEditor widget
1174 * This function sets the time on an existing time editor. If the
1175 * time specified by the arguments is invalid, it's fixed.
1176 * The time is assumed to be in 24h format.
1179 hildon_time_editor_set_time (HildonTimeEditor *editor,
1184 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1186 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1190 * hildon_time_editor_get_time:
1191 * @editor: the #HildonTimeEditor widget
1196 * Gets the time of the #HildonTimeEditor widget. The time returned is
1197 * always in 24h format.
1200 hildon_time_editor_get_time (HildonTimeEditor *editor,
1205 HildonTimeEditorPrivate *priv;
1207 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1209 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1212 ticks_to_time (hildon_time_editor_get_ticks (editor), hours, minutes, seconds);
1216 * hildon_time_editor_set_duration_range:
1217 * @editor: the #HildonTimeEditor widget
1218 * @min_seconds: minimum allowed time in seconds
1219 * @max_seconds: maximum allowed time in seconds
1221 * Sets the duration editor time range of the #HildonTimeEditor widget.
1224 hildon_time_editor_set_duration_range (HildonTimeEditor *editor,
1228 HildonTimeEditorPrivate *priv;
1231 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1233 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1236 /* Swap values if reversed */
1237 if (min_seconds > max_seconds)
1240 max_seconds = min_seconds;
1244 hildon_time_editor_set_duration_max (editor, max_seconds);
1245 hildon_time_editor_set_duration_min (editor, min_seconds);
1247 if (priv->duration_mode) {
1248 /* Set minimum allowed value for duration editor.
1249 FIXME: Shouldn't it be changed only if it's not in range?
1250 Would change API, so won't touch this for now. */
1251 hildon_time_editor_set_ticks (editor, min_seconds);
1256 * hildon_time_editor_get_duration_range:
1257 * @editor: the #HildonTimeEditor widget
1258 * @min_seconds: pointer to guint
1259 * @max_seconds: pointer to guint
1261 * Gets the duration editor time range of the #HildonTimeEditor widget.
1264 hildon_time_editor_get_duration_range (HildonTimeEditor *editor,
1268 HildonTimeEditorPrivate *priv;
1270 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1272 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1275 *min_seconds = priv->duration_min;
1276 *max_seconds = priv->duration_max;
1280 hildon_time_editor_check_locale (HildonTimeEditor *editor)
1282 HildonTimeEditorPrivate *priv;
1284 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1287 /* Update time separator symbols */
1288 hildon_time_editor_get_time_separators (GTK_LABEL (priv->hm_label), GTK_LABEL (priv->sec_label));
1290 /* Get AM/PM symbols. */
1291 priv->am_symbol = g_strdup (nl_langinfo (AM_STR));
1292 priv->pm_symbol = g_strdup (nl_langinfo (PM_STR));
1294 if (priv->am_symbol[0] == '\0')
1297 /* 12h clock mode. Check if AM/PM should be before or after time.
1298 %p is the AM/PM string, so we assume that if the format string
1299 begins with %p it's in the beginning, and in any other case it's
1300 in the end (although that's not necessarily the case). */
1301 if (strncmp (nl_langinfo (T_FMT_AMPM), "%p", 2) == 0)
1302 priv->ampm_pos_after = FALSE;
1308 hildon_time_editor_entry_focus_in (GtkWidget *widget,
1309 GdkEventFocus *event,
1312 g_idle_add ((GSourceFunc) hildon_time_editor_entry_select_all,
1313 GTK_ENTRY (widget));
1319 hildon_time_editor_time_error (HildonTimeEditor *editor,
1320 HildonDateTimeError type)
1325 /* Returns negative if we didn't get value,
1326 * and should stop further validation
1329 validated_conversion (HildonTimeEditorPrivate *priv,
1334 gboolean allow_intermediate,
1336 GString *error_string)
1342 text = gtk_entry_get_text (GTK_ENTRY (field));
1344 if (text && text[0])
1346 /* Try to convert entry text to number */
1347 value = strtol (text, &tail, 10);
1349 /* Check if conversion succeeded */
1350 if ((tail[0] == 0) && !(text[0] == '-'))
1353 g_string_printf (error_string, _("ckct_ib_maximum_value"), max);
1354 priv->error_widget = field;
1355 *error_code = MAX_VALUE;
1359 if (value < min && !allow_intermediate) {
1360 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1361 priv->error_widget = field;
1362 *error_code = MIN_VALUE;
1369 /* We'll handle failed conversions soon */
1372 if ((tail[0] == '-') || (text[0] == '-'))
1374 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1375 priv->error_widget = field;
1376 *error_code = MIN_VALUE;
1381 else if (allow_intermediate)
1382 return -1; /* Empty field while user is still editing. No error, but
1383 cannot validate either... */
1384 else /* Empty field: show error and set value to minimum allowed */
1386 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1387 priv->error_widget = field;
1388 *error_code = WITHIN_RANGE;
1392 /* Empty field and not allowed intermediated OR failed conversion */
1393 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1394 priv->error_widget = field;
1395 *error_code = WITHIN_RANGE;
1400 hildon_time_editor_real_validate (HildonTimeEditor *editor,
1401 gboolean allow_intermediate,
1402 GString *error_string)
1404 HildonTimeEditorPrivate *priv;
1405 guint h, m, s, ticks;
1407 guint max_hours, min_hours, def_hours;
1408 guint max_minutes, min_minutes, def_minutes;
1409 guint max_seconds, min_seconds, def_seconds;
1412 g_assert (HILDON_IS_TIME_EDITOR (editor));
1414 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1417 /* Find limits for field based validation. */
1418 if (priv->duration_mode)
1420 ticks_to_time (priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1421 ticks_to_time (priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1423 if (priv->clock_24h) {
1424 max_hours = HOURS_MAX_24;
1425 min_hours = HOURS_MIN_24;
1427 max_hours = HOURS_MAX_12;
1428 min_hours = HOURS_MIN_12;
1432 hildon_time_editor_get_time (editor, &def_hours, &def_minutes, &def_seconds);
1434 /* Get time components from fields and validate them... */
1435 if (priv->show_hours) {
1436 h = validated_conversion (priv, priv->entries[ENTRY_HOURS], min_hours, max_hours, def_hours,
1437 allow_intermediate, &error_code, error_string);
1438 if (priv->error_widget == priv->entries[ENTRY_HOURS])
1439 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, hour_errors[error_code], &r);
1440 if ((gint) h < 0) return;
1443 m = validated_conversion (priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX, def_minutes,
1444 allow_intermediate, &error_code, error_string);
1445 if (priv->error_widget == priv->entries[ENTRY_MINS])
1446 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, min_errors[error_code], &r);
1447 if ((gint) m < 0) return;
1448 if (priv->show_seconds) {
1449 s = validated_conversion (priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX, def_seconds,
1450 allow_intermediate, &error_code, error_string);
1451 if (priv->error_widget == priv->entries[ENTRY_SECS])
1452 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, sec_errors[error_code], &r);
1453 if ((gint) s < 0) return;
1457 /* Ok, we now do separate check that tick count is valid for duration mode */
1458 if (priv->duration_mode)
1460 ticks = TICKS(h, m, s);
1462 if (ticks < priv->duration_min && !allow_intermediate)
1464 g_string_printf (error_string,
1465 _("ckct_ib_min_allowed_duration_hts"),
1466 min_hours, min_minutes, min_seconds);
1467 hildon_time_editor_set_ticks (editor, priv->duration_min);
1468 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1469 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MIN_DURATION, &r);
1472 else if (ticks > priv->duration_max)
1474 g_string_printf (error_string,
1475 _("ckct_ib_max_allowed_duration_hts"),
1476 max_hours, max_minutes, max_seconds);
1477 hildon_time_editor_set_ticks (editor, priv->duration_max);
1478 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1479 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MAX_DURATION, &r);
1483 else if (! priv->clock_24h)
1484 convert_to_24h (&h, priv->am);
1486 /* The only case when we do not want to refresh the
1487 time display, is when the user is editing a value
1488 (unless the value was out of bounds and we have to fix it) */
1489 if (! allow_intermediate || priv->error_widget)
1490 hildon_time_editor_set_time (editor, h, m, s);
1493 /* Setting text to entries causes entry to recompute itself
1494 in idle callback, which remove selection. Because of this
1495 we need to do selection in idle as well. */
1497 highlight_callback (gpointer data)
1499 HildonTimeEditorPrivate *priv;
1503 g_assert (HILDON_IS_TIME_EDITOR (data));
1504 priv = HILDON_TIME_EDITOR_GET_PRIVATE (data);
1507 GDK_THREADS_ENTER ();
1509 widget = priv->error_widget;
1510 priv->error_widget = NULL;
1512 if (GTK_IS_WIDGET (widget) == FALSE)
1515 /* Avoid revalidation because it will issue the date_error signal
1516 twice when there is an empty field. We must block the signal
1517 for all the entries because we do not know where the focus
1519 for (i = 0; i < ENTRY_COUNT; i++)
1520 g_signal_handlers_block_by_func (priv->entries[i],
1521 (gpointer) hildon_time_editor_entry_focus_out, data);
1522 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1523 gtk_widget_grab_focus (widget);
1524 for (i = 0; i < ENTRY_COUNT; i++)
1525 g_signal_handlers_unblock_by_func (priv->entries[i],
1526 (gpointer) hildon_time_editor_entry_focus_out, data);
1529 priv->highlight_idle = 0;
1530 GDK_THREADS_LEAVE ();
1535 /* Update ticks from current H:M:S entries. If they're invalid, show an
1536 infoprint and update the fields unless they're empty. */
1538 hildon_time_editor_validate (HildonTimeEditor *editor,
1539 gboolean allow_intermediate)
1541 HildonTimeEditorPrivate *priv;
1542 GString *error_message;
1544 g_assert (HILDON_IS_TIME_EDITOR(editor));
1545 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1548 /* if there is already an error we do nothing until it will be managed by the idle */
1549 if (priv->highlight_idle == 0 && priv->skipper == FALSE)
1551 priv->skipper = TRUE;
1552 error_message = g_string_new (NULL);
1553 hildon_time_editor_real_validate (editor,
1554 allow_intermediate, error_message);
1556 if (priv->error_widget)
1558 hildon_banner_show_information (priv->error_widget, NULL,
1559 error_message->str);
1561 priv->highlight_idle = g_idle_add (highlight_callback, editor);
1564 priv->skipper = FALSE;
1565 g_string_free (error_message, TRUE);
1569 /* on inserted text, if entry has two digits, jumps to the next field. */
1571 hildon_time_editor_inserted_text (GtkEditable *editable,
1573 gint new_text_length,
1577 HildonTimeEditor *editor;
1580 HildonTimeEditorPrivate *priv;
1582 entry = GTK_ENTRY (editable);
1583 editor = HILDON_TIME_EDITOR (user_data);
1585 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1588 /* if there is already an error we don't have to do anything */
1589 if (! priv->error_widget)
1591 value = (gchar *) gtk_entry_get_text (entry);
1593 if (strlen (value) == 2)
1595 if (GTK_WIDGET (editable) == priv->entries[ENTRY_HOURS])
1597 /* We already checked the input in changed signal, but
1598 * now we will re-check it again in focus-out we
1599 * intermediate flag set to FALSE */
1600 gtk_widget_grab_focus (priv->entries[ENTRY_MINS]);
1603 else if (GTK_WIDGET (editable) == priv->entries[ENTRY_MINS] &&
1604 GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS]))
1607 gtk_widget_grab_focus (priv->entries[ENTRY_SECS]);
1615 hildon_time_editor_entry_focus_out (GtkWidget *widget,
1616 GdkEventFocus *event,
1619 g_assert (HILDON_IS_TIME_EDITOR (data));
1621 /* Validate the given time and update ticks. */
1622 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1628 hildon_time_editor_ampm_clicked (GtkWidget *widget,
1631 HildonTimeEditor *editor;
1632 HildonTimeEditorPrivate *priv;
1634 g_assert (GTK_IS_WIDGET (widget));
1635 g_assert (HILDON_IS_TIME_EDITOR (data));
1637 editor = HILDON_TIME_EDITOR (data);
1638 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1641 /* First validate the given time and update ticks. */
1642 hildon_time_editor_validate (editor, FALSE);
1644 /* Apply the AM/PM change by moving the current time by 12 hours */
1646 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1647 hildon_time_editor_set_ticks (editor, priv->ticks + 12 * 3600);
1649 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1650 hildon_time_editor_set_ticks (editor, priv->ticks - 12 * 3600);
1657 hildon_time_editor_icon_clicked (GtkWidget *widget,
1660 HildonTimeEditor *editor;
1663 guint h, m, s, result;
1664 HildonTimeEditorPrivate *priv;
1666 g_assert (HILDON_IS_TIME_EDITOR (data));
1668 editor = HILDON_TIME_EDITOR (data);
1669 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1672 /* icon is passive in duration editor mode */
1673 if (hildon_time_editor_get_duration_mode (editor))
1676 /* Validate and do not launch if broken */
1677 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1678 if (priv->error_widget != NULL)
1681 /* Launch HildonTimePicker dialog */
1682 parent = gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW);
1683 picker = hildon_time_picker_new (GTK_WINDOW (parent));
1685 hildon_time_editor_get_time (editor, &h, &m, &s);
1686 hildon_time_picker_set_time (HILDON_TIME_PICKER (picker), h, m);
1688 result = gtk_dialog_run (GTK_DIALOG (picker));
1691 case GTK_RESPONSE_OK:
1692 case GTK_RESPONSE_ACCEPT:
1693 /* Use the selected time */
1694 hildon_time_picker_get_time (HILDON_TIME_PICKER (picker), &h, &m);
1695 hildon_time_editor_set_time (editor, h, m, 0);
1702 gtk_widget_destroy (picker);
1707 hildon_time_editor_size_request (GtkWidget *widget,
1708 GtkRequisition *requisition)
1710 HildonTimeEditor *editor;
1711 HildonTimeEditorPrivate *priv;
1714 editor = HILDON_TIME_EDITOR (widget);
1715 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1717 /* Get frame's size */
1718 gtk_widget_size_request (priv->frame, requisition);
1720 if (GTK_WIDGET_VISIBLE (priv->iconbutton))
1722 gtk_widget_size_request (priv->iconbutton, &req);
1723 /* Reserve space for icon */
1724 requisition->width += req.width + ICON_PRESSED +
1725 HILDON_MARGIN_DEFAULT;
1728 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1729 want to force this since themes might have varying thickness values
1730 which cause the height to change. */
1731 requisition->height = TIME_EDITOR_HEIGHT;
1735 hildon_time_editor_size_allocate (GtkWidget *widget,
1736 GtkAllocation *allocation)
1738 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
1739 GtkAllocation alloc;
1740 GtkRequisition req, max_req;
1745 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1746 widget->allocation = *allocation;
1747 gtk_widget_get_child_requisition (widget, &max_req);
1749 /* Center horizontally */
1750 alloc.x = allocation->x + MAX (allocation->width - max_req.width, 0) / 2;
1751 /* Center vertically */
1752 alloc.y = allocation->y + MAX (allocation->height - max_req.height, 0) / 2;
1754 /* allocate frame */
1756 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1758 gtk_widget_get_child_requisition (priv->frame, &req);
1760 alloc.width = req.width;
1761 alloc.height = max_req.height;
1763 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1765 gtk_widget_size_allocate (priv->frame, &alloc);
1768 if (GTK_WIDGET_VISIBLE (priv->iconbutton)) {
1770 gtk_widget_get_child_requisition (priv->frame, &req);
1772 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1774 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1775 alloc.width = req.width;
1778 gtk_widget_size_allocate (priv->frame, &alloc);
1780 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1783 /* FIXME: ugly way to move labels up. They just don't seem move up
1784 otherwise. This is likely because we force the editor to be
1785 smaller than it otherwise would be. */
1786 alloc = priv->ampm_label->allocation;
1787 alloc.y = allocation->y - 2;
1788 alloc.height = max_req.height + 2;
1789 gtk_widget_size_allocate (priv->ampm_label, &alloc);
1791 alloc = priv->hm_label->allocation;
1792 alloc.y = allocation->y - 2;
1793 alloc.height = max_req.height + 2;
1794 gtk_widget_size_allocate (priv->hm_label, &alloc);
1796 alloc = priv->sec_label->allocation;
1797 alloc.y = allocation->y - 2;
1798 alloc.height = max_req.height + 2;
1799 gtk_widget_size_allocate (priv->sec_label, &alloc);
1803 hildon_time_editor_focus (GtkWidget *widget,
1804 GtkDirectionType direction)
1807 GtkDirectionType effective_direction;
1809 g_assert (HILDON_IS_TIME_EDITOR (widget));
1811 retval = hildon_private_composite_focus (widget, direction, &effective_direction);
1814 return GTK_WIDGET_CLASS (parent_class)->focus (widget, effective_direction);
1820 hildon_time_editor_entry_keypress (GtkEntry *entry,
1824 switch (event->keyval)
1828 hildon_time_editor_icon_clicked (GTK_WIDGET (entry), data);
1834 g_assert_not_reached ();
1838 convert_to_12h (guint *h,
1841 g_assert (0 <= *h && *h < 24);
1843 /* 00:00 to 00:59 add 12 hours */
1844 /* 01:00 to 11:59 straight to am */
1845 /* 12:00 to 12:59 straight to pm */
1846 /* 13:00 to 23:59 subtract 12 hours */
1848 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1849 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1850 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1851 else { *am = FALSE; *h -= 12;}
1855 convert_to_24h (guint *h,
1858 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1863 else if (! am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1870 * hildon_time_editor_set_show_hours:
1871 * @editor: The #HildonTimeEditor.
1872 * @show_hours: Enable or disable showing of hours.
1874 * This function shows or hides the hours field.
1878 hildon_time_editor_set_show_hours (HildonTimeEditor *editor,
1879 gboolean show_hours)
1881 HildonTimeEditorPrivate *priv;
1883 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1885 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1888 if (show_hours != priv->show_hours) {
1889 priv->show_hours = show_hours;
1891 /* show/hide hours field and its ':' label if the value changed. */
1893 gtk_widget_show (priv->entries[ENTRY_HOURS]);
1894 gtk_widget_show (priv->hm_label);
1896 gtk_widget_hide (priv->entries[ENTRY_HOURS]);
1897 gtk_widget_hide (priv->hm_label);
1900 g_object_notify (G_OBJECT (editor), "show_hours");
1905 * hildon_time_editor_get_show_hours:
1906 * @editor: the @HildonTimeEditor widget.
1908 * This function returns a boolean indicating the visibility of
1909 * hours in the @HildonTimeEditor
1911 * Return value: TRUE if hours are visible.
1915 hildon_time_editor_get_show_hours (HildonTimeEditor *editor)
1917 HildonTimeEditorPrivate *priv;
1919 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1920 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1923 return priv->show_hours;
1928 hildon_time_editor_entry_select_all (GtkWidget *widget)
1930 GDK_THREADS_ENTER ();
1931 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1932 GDK_THREADS_LEAVE ();