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;
370 widget_class->tap_and_hold_setup = hildon_time_editor_tap_and_hold_setup;
372 widget_class->focus = hildon_time_editor_focus;
374 container_class->forall = hildon_time_editor_forall;
375 GTK_OBJECT_CLASS (editor_class)->destroy = hildon_time_editor_destroy;
377 object_class->finalize = hildon_time_editor_finalize;
379 editor_class->time_error = hildon_time_editor_time_error;
381 time_editor_signals[TIME_ERROR] =
382 g_signal_new ("time-error",
383 G_OBJECT_CLASS_TYPE (object_class),
385 G_STRUCT_OFFSET (HildonTimeEditorClass, time_error),
386 g_signal_accumulator_true_handled, NULL,
387 _hildon_marshal_BOOLEAN__ENUM,
388 G_TYPE_BOOLEAN, 1, HILDON_TYPE_DATE_TIME_ERROR);
391 * HildonTimeEditor:ticks:
393 * If editor is in duration mode, contains the duration seconds.
394 * If not, contains seconds since midnight.
396 g_object_class_install_property (object_class, PROP_TICKS,
397 g_param_spec_uint ("ticks",
399 "Current value of duration",
401 HILDON_TIME_EDITOR_TICKS_VALUE,
402 G_PARAM_READABLE | G_PARAM_WRITABLE) );
405 * HildonTimeEditor:show_seconds:
407 * Controls whether seconds are shown in the editor
409 g_object_class_install_property (object_class, PROP_SHOW_SECONDS,
410 g_param_spec_boolean ("show_seconds",
411 "Show seconds property",
412 "Controls whether the seconds are shown in the editor",
414 G_PARAM_READABLE | G_PARAM_WRITABLE) );
417 * HildonTimeEditor:show_hours:
419 * Controls whether hours are shown in the editor
421 g_object_class_install_property (object_class, PROP_SHOW_HOURS,
422 g_param_spec_boolean ("show_hours",
424 "Controls whether the hours field is shown in the editor",
426 G_PARAM_READABLE | G_PARAM_WRITABLE) );
429 * HildonTimeEditor:duration_mode:
431 * Controls whether the TimeEditor is in duration mode
433 g_object_class_install_property (object_class, PROP_DURATION_MODE,
434 g_param_spec_boolean ("duration_mode",
436 "Controls whether the TimeEditor is in duration mode",
437 HILDON_TIME_EDITOR_DURATION_MODE,
438 G_PARAM_READABLE | G_PARAM_WRITABLE) );
441 * HildonTimeEditor:duration_min:
443 * Minimum allowed duration value.
445 g_object_class_install_property (object_class, PROP_DURATION_MIN,
446 g_param_spec_uint ("duration_min",
447 "Minumum duration value",
448 "Smallest possible duration value",
449 MIN_DURATION, MAX_DURATION,
450 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
451 G_PARAM_READABLE | G_PARAM_WRITABLE) );
454 * HildonTimeEditor:duration_max:
456 * Maximum allowed duration value.
458 g_object_class_install_property (object_class, PROP_DURATION_MAX,
459 g_param_spec_uint ("duration_max",
460 "Maximum duration value",
461 "Largest possible duration value",
463 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
464 G_PARAM_READABLE | G_PARAM_WRITABLE) );
469 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
472 GtkWidgetTapAndHoldFlags flags)
474 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
477 /* Forward this tap_and_hold_setup signal to all our child widgets */
478 for (i = 0; i < ENTRY_COUNT; i++)
480 gtk_widget_tap_and_hold_setup (priv->entries[i], menu, func,
481 GTK_TAP_AND_HOLD_NO_SIGNALS);
483 gtk_widget_tap_and_hold_setup (priv->ampm_button, menu, func,
484 GTK_TAP_AND_HOLD_NO_SIGNALS);
485 gtk_widget_tap_and_hold_setup (priv->iconbutton, menu, func,
486 GTK_TAP_AND_HOLD_NONE);
491 hildon_time_editor_entry_changed (GtkWidget *widget,
494 g_assert (HILDON_IS_TIME_EDITOR (data));
495 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), TRUE);
499 hildon_time_editor_init (HildonTimeEditor *editor)
501 HildonTimeEditorPrivate *priv;
502 GtkWidget *hbox, *icon;
505 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
508 gtk_widget_push_composite_child ();
510 /* Setup defaults and create widgets */
512 priv->show_seconds = FALSE;
513 priv->show_hours = TRUE;
514 priv->ampm_pos_after = TRUE;
515 priv->clock_24h = TRUE;
516 priv->duration_mode = FALSE;
517 priv->iconbutton = gtk_button_new();
518 priv->ampm_label = gtk_label_new(NULL);
519 priv->hm_label = gtk_label_new(NULL);
520 priv->sec_label = gtk_label_new(NULL);
521 priv->frame = gtk_frame_new(NULL);
522 priv->ampm_button = gtk_button_new();
523 priv->skipper = FALSE;
525 icon = gtk_image_new_from_icon_name (ICON_NAME, HILDON_ICON_SIZE_SMALL);
526 hbox = gtk_hbox_new (FALSE, 0);
528 GTK_WIDGET_SET_FLAGS (editor, GTK_NO_WINDOW);
529 GTK_WIDGET_UNSET_FLAGS (priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
531 gtk_container_set_border_width (GTK_CONTAINER(priv->frame), 0);
533 gtk_container_add (GTK_CONTAINER (priv->iconbutton), icon);
534 gtk_container_add (GTK_CONTAINER (priv->ampm_button), priv->ampm_label);
535 gtk_button_set_relief(GTK_BUTTON (priv->ampm_button), GTK_RELIEF_NONE);
536 gtk_button_set_focus_on_click (GTK_BUTTON (priv->ampm_button), FALSE);
538 /* Create hour, minute and second entries */
539 for (i = 0; i < ENTRY_COUNT; i++)
541 priv->entries[i] = gtk_entry_new ();
543 /* No frames for entries, so that they all appear to be inside one long entry */
544 gtk_entry_set_has_frame (GTK_ENTRY (priv->entries[i]), FALSE);
547 /* Set the entries to accept only numeric characters */
548 g_object_set (priv->entries[i], "hildon-input-mode", HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
551 /* The entry fields all take exactly two characters */
552 gtk_entry_set_max_length (GTK_ENTRY (priv->entries[i]), 2);
553 gtk_entry_set_width_chars (GTK_ENTRY (priv->entries[i]), 2);
555 g_signal_connect (priv->entries[i], "focus-in-event",
556 G_CALLBACK (hildon_time_editor_entry_focus_in), editor);
557 g_signal_connect (priv->entries[i], "focus-out-event",
558 G_CALLBACK (hildon_time_editor_entry_focus_out), editor);
559 g_signal_connect (priv->entries[i], "key-press-event",
560 G_CALLBACK (hildon_time_editor_entry_keypress), editor);
561 g_signal_connect (priv->entries[i], "changed",
562 G_CALLBACK (hildon_time_editor_entry_changed), editor);
564 /* inserted signal sets time */
565 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
566 G_CALLBACK (hildon_time_editor_inserted_text),
570 /* clicked signal for am/pm label */
571 g_signal_connect (G_OBJECT (priv->ampm_button), "clicked",
572 G_CALLBACK (hildon_time_editor_ampm_clicked), editor);
574 /* clicked signal for icon */
575 g_signal_connect (G_OBJECT (priv->iconbutton), "clicked",
576 G_CALLBACK (hildon_time_editor_icon_clicked), editor);
578 /* Set ourself as the parent of all the widgets we created */
579 gtk_widget_set_parent (priv->iconbutton, GTK_WIDGET(editor));
580 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
581 gtk_box_pack_start (GTK_BOX (hbox), priv->hm_label, FALSE, FALSE, 0);
582 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
583 gtk_box_pack_start (GTK_BOX (hbox), priv->sec_label, FALSE, FALSE, 0);
584 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
585 gtk_box_pack_start (GTK_BOX (hbox), priv->ampm_button, FALSE, FALSE, 0);
586 gtk_misc_set_padding (GTK_MISC (priv->ampm_label), 0, 0);
588 gtk_container_add (GTK_CONTAINER (priv->frame), hbox);
590 /* Show created widgets */
591 gtk_widget_set_parent (priv->frame, GTK_WIDGET(editor));
592 gtk_widget_show_all (priv->frame);
593 gtk_widget_show_all (priv->iconbutton);
595 /* Update AM/PM and time separators settings from locale */
596 if (! hildon_time_editor_check_locale (editor)) {
597 /* Using 12h clock */
598 priv->clock_24h = FALSE;
600 gtk_widget_hide (priv->ampm_button);
603 if (! priv->show_seconds) {
604 gtk_widget_hide (priv->sec_label);
605 gtk_widget_hide (priv->entries[ENTRY_SECS]);
608 /* set the default time to current time. */
609 hildon_time_editor_set_to_current_time (editor);
611 gtk_widget_pop_composite_child ();
615 hildon_time_editor_set_property (GObject *object,
620 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
625 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
628 case PROP_SHOW_SECONDS:
629 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
632 case PROP_SHOW_HOURS:
633 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
636 case PROP_DURATION_MODE:
637 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
640 case PROP_DURATION_MIN:
641 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
644 case PROP_DURATION_MAX:
645 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
649 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
655 hildon_time_editor_get_property (GObject *object,
660 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
666 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
669 case PROP_SHOW_SECONDS:
670 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
673 case PROP_SHOW_HOURS:
674 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
677 case PROP_DURATION_MODE:
678 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
681 case PROP_DURATION_MIN:
682 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
685 case PROP_DURATION_MAX:
686 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
690 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
696 * hildon_time_editor_new:
698 * This function creates a new time editor.
700 * Returns: pointer to a new #HildonTimeEditor widget
703 hildon_time_editor_new (void)
705 return GTK_WIDGET (g_object_new (HILDON_TYPE_TIME_EDITOR, NULL));
709 hildon_time_editor_finalize (GObject *obj_self)
711 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (obj_self);
715 g_free (priv->am_symbol);
718 g_free (priv->pm_symbol);
720 if (priv->highlight_idle)
721 g_source_remove (priv->highlight_idle);
723 if (G_OBJECT_CLASS (parent_class)->finalize)
724 G_OBJECT_CLASS (parent_class)->finalize (obj_self);
728 * hildon_time_editor_get_time_separators:
729 * @hm_sep_label: the label that will show the hour:minutes separator
730 * @ms_sep_label: the label that will show the minutes:seconds separator
732 * Gets hour-minute separator and minute-second separator from current
733 * locale and sets then to the labels we set as parameters. Both
734 * parameters can be NULL if you just want to assing one separator.
738 hildon_time_editor_get_time_separators (GtkLabel *hm_sep_label,
739 GtkLabel *ms_sep_label)
743 GDate locale_test_date;
744 gchar *iter, *endp = NULL;
746 /* Get localized time string */
747 g_date_set_dmy (&locale_test_date, 1, 2, 1970);
748 (void) g_date_strftime (buffer, sizeof (buffer), "%X", &locale_test_date);
750 if (hm_sep_label != NULL)
752 /* Find h-m separator */
754 while (*iter && g_ascii_isdigit (*iter)) iter++;
756 /* Extract h-m separator*/
758 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
759 separator = g_strndup (iter, endp - iter);
760 gtk_label_set_label (hm_sep_label, separator);
764 if (ms_sep_label != NULL)
766 /* Find m-s separator */
768 while (*iter && g_ascii_isdigit (*iter)) iter++;
770 /* Extract m-s separator*/
772 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
773 separator = g_strndup (iter, endp - iter);
774 gtk_label_set_label (ms_sep_label, separator);
779 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
781 ticks_to_time (guint ticks,
788 *hours = ticks / 3600;
790 *minutes = left / 60;
791 *seconds = left % 60;
795 * hildon_time_editor_set_ticks:
796 * @editor: the #HildonTimeEditor widget
797 * @ticks: the duration to set, in seconds
799 * Sets the current duration in seconds. This means seconds from
800 * midnight, if not in duration mode. In case of any errors, it tries
805 hildon_time_editor_set_ticks (HildonTimeEditor *editor,
808 HildonTimeEditorPrivate *priv;
812 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
814 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
817 /* Validate ticks. If it's too low or too high, set it to
818 min/max value for the current mode. */
819 if (priv->duration_mode)
820 priv->ticks = CLAMP (ticks, priv->duration_min, priv->duration_max);
822 /* Check that ticks value is valid. We only need to check that hours
824 ticks_to_time (ticks, &h, &m, &s);
825 if (h > HOURS_MAX_24)
826 ticks = TICKS(HOURS_MAX_24, m, s);
831 /* Get the time in H:M:S. */
832 ticks_to_time (priv->ticks, &h, &m, &s);
834 if (!priv->clock_24h && ! priv->duration_mode)
836 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
837 convert_to_12h (&h, &priv->am);
840 /* Set H:M:S values to entries. We do not want to invoke validation
841 callbacks (since they can cause new call to this function), so we
842 block signals while setting values. */
843 for (i = 0; i < ENTRY_COUNT; i++)
845 g_signal_handlers_block_by_func(priv->entries[i],
846 (gpointer) hildon_time_editor_entry_changed, editor);
848 g_signal_handlers_block_by_func(priv->entries[i],
849 (gpointer) hildon_time_editor_inserted_text, editor);
851 g_signal_handlers_block_by_func(priv->entries[i],
852 (gpointer) hildon_time_editor_entry_focus_out, editor);
855 g_snprintf (str, sizeof (str), "%02u", h);
856 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_HOURS]), str);
858 g_snprintf(str, sizeof (str), "%02u", m);
859 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_MINS]), str);
861 g_snprintf(str, sizeof (str), "%02u", s);
862 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_SECS]), str);
864 for (i = 0; i < ENTRY_COUNT; i++)
866 g_signal_handlers_unblock_by_func (priv->entries[i],
867 (gpointer) hildon_time_editor_entry_changed, editor);
869 g_signal_handlers_unblock_by_func (priv->entries[i],
870 (gpointer) hildon_time_editor_inserted_text, editor);
872 g_signal_handlers_unblock_by_func (priv->entries[i],
873 (gpointer) hildon_time_editor_entry_focus_out, editor);
876 /* Update AM/PM label in case we're in 12h mode */
877 gtk_label_set_label( GTK_LABEL (priv->ampm_label),
878 priv->am ? priv->am_symbol : priv->pm_symbol);
880 g_object_notify (G_OBJECT (editor), "ticks");
884 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor)
890 tm = localtime (&now);
893 hildon_time_editor_set_time (editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
897 * hildon_time_editor_get_ticks:
898 * @editor: the #HildonTimeEditor widget
900 * This function returns the current duration, in seconds.
901 * This means seconds from midnight, if not in duration mode.
903 * Returns: current duration in seconds
906 hildon_time_editor_get_ticks (HildonTimeEditor *editor)
908 HildonTimeEditorPrivate *priv;
910 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
912 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
915 return (priv->ticks);
919 * hildon_time_editor_set_show_seconds:
920 * @editor: the #HildonTimeEditor
921 * @show_seconds: enable or disable showing of seconds
923 * This function shows or hides the seconds field.
926 hildon_time_editor_set_show_seconds (HildonTimeEditor *editor,
927 gboolean show_seconds)
929 HildonTimeEditorPrivate *priv;
931 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
933 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
936 if (show_seconds != priv->show_seconds) {
937 priv->show_seconds = show_seconds;
939 /* show/hide seconds field and its ':' label if the value changed. */
941 gtk_widget_show (priv->entries[ENTRY_SECS]);
942 gtk_widget_show (priv->sec_label);
944 gtk_widget_hide (priv->entries[ENTRY_SECS]);
945 gtk_widget_hide (priv->sec_label);
948 g_object_notify (G_OBJECT (editor), "show_seconds");
953 * hildon_time_editor_get_show_seconds:
954 * @editor: the #HildonTimeEditor widget
956 * This function returns a boolean indicating the visibility of
957 * seconds in the #HildonTimeEditor
959 * Returns: TRUE if the seconds are visible
962 hildon_time_editor_get_show_seconds (HildonTimeEditor *editor)
964 HildonTimeEditorPrivate *priv;
966 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
967 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
970 return (priv->show_seconds);
974 * hildon_time_editor_set_duration_mode:
975 * @editor: the #HildonTimeEditor
976 * @duration_mode: enable or disable duration editor mode
978 * This function sets the duration editor mode in which the maximum hours
982 hildon_time_editor_set_duration_mode (HildonTimeEditor *editor,
983 gboolean duration_mode)
985 HildonTimeEditorPrivate *priv;
987 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
989 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
992 if (duration_mode != priv->duration_mode) {
993 priv->duration_mode = duration_mode;
996 /* FIXME: Why do we reset the duration range here?
997 Would change API, so won't touch this for now. */
998 hildon_time_editor_set_duration_range (editor, MIN_DURATION, MAX_DURATION);
999 /* There's no AM/PM label or time picker icon in duration mode.
1000 Make sure they're hidden. */
1001 gtk_widget_hide (GTK_WIDGET (priv->ampm_label));
1002 gtk_widget_hide (GTK_WIDGET (priv->ampm_button));
1003 gtk_widget_hide (GTK_WIDGET (priv->iconbutton));
1004 /* Duration mode has seconds by default. */
1005 hildon_time_editor_set_show_seconds (editor, TRUE);
1007 /* Make sure AM/PM label and time picker icons are visible if needed */
1008 if (! priv->clock_24h)
1009 gtk_widget_show (GTK_WIDGET (priv->ampm_label));
1011 gtk_widget_show (GTK_WIDGET (priv->ampm_button));
1012 gtk_widget_show (GTK_WIDGET (priv->iconbutton));
1014 /* Reset the ticks to current time. Anything set in duration mode
1015 * is bound to be invalid or useless in time mode.
1017 hildon_time_editor_set_to_current_time (editor);
1020 g_object_notify (G_OBJECT (editor), "duration_mode");
1025 * hildon_time_editor_get_duration_mode:
1026 * @editor: the #HildonTimeEditor widget
1028 * This function returns a boolean indicating whether the #HildonTimeEditor
1029 * is in the duration mode.
1031 * Returns: TRUE if the #HildonTimeEditor is in duration mode
1034 hildon_time_editor_get_duration_mode (HildonTimeEditor *editor)
1036 HildonTimeEditorPrivate *priv;
1038 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1039 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1042 return (priv->duration_mode);
1046 * hildon_time_editor_set_duration_min:
1047 * @editor: the #HildonTimeEditor widget
1048 * @duration_min: mimimum allowed duration
1050 * Sets the minimum allowed duration for the duration mode.
1051 * Note: Has no effect in time mode
1054 hildon_time_editor_set_duration_min (HildonTimeEditor *editor,
1057 HildonTimeEditorPrivate *priv;
1059 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1060 g_return_if_fail (duration_min >= MIN_DURATION);
1062 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1065 if (! priv->duration_mode )
1068 priv->duration_min = duration_min;
1070 /* Clamp the current value to the minimum if necessary */
1071 if (priv->ticks < duration_min)
1073 hildon_time_editor_set_ticks (editor, duration_min);
1076 g_object_notify (G_OBJECT (editor), "duration_min");
1080 * hildon_time_editor_get_duration_min:
1081 * @editor: the #HildonTimeEditor widget
1083 * This function returns the smallest duration the #HildonTimeEditor
1084 * allows in the duration mode.
1086 * Returns: minimum allowed duration in seconds
1089 hildon_time_editor_get_duration_min (HildonTimeEditor *editor)
1091 HildonTimeEditorPrivate *priv;
1093 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1095 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1098 if(! priv->duration_mode )
1101 return (priv->duration_min);
1105 * hildon_time_editor_set_duration_max:
1106 * @editor: the #HildonTimeEditor widget
1107 * @duration_max: maximum allowed duration in seconds
1109 * Sets the maximum allowed duration in seconds for the duration mode.
1110 * Note: Has no effect in time mode
1113 hildon_time_editor_set_duration_max (HildonTimeEditor *editor,
1116 HildonTimeEditorPrivate *priv;
1118 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1119 g_return_if_fail (duration_max <= MAX_DURATION);
1121 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1124 if (! priv->duration_mode)
1127 priv->duration_max = duration_max;
1129 /* Clamp the current value to the maximum if necessary */
1130 if (priv->ticks > duration_max)
1132 hildon_time_editor_set_ticks (editor, duration_max);
1135 g_object_notify (G_OBJECT (editor), "duration_max");
1139 * hildon_time_editor_get_duration_max:
1140 * @editor: the #HildonTimeEditor widget
1142 * This function returns the longest duration the #HildonTimeEditor
1143 * allows in the duration mode.
1145 * Returns: maximum allowed duration in seconds
1148 hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1150 HildonTimeEditorPrivate *priv;
1152 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1154 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1157 if (! priv->duration_mode)
1160 return (priv->duration_max);
1164 * hildon_time_editor_set_time:
1165 * @editor: the #HildonTimeEditor widget
1170 * This function sets the time on an existing time editor. If the
1171 * time specified by the arguments is invalid, it's fixed.
1172 * The time is assumed to be in 24h format.
1175 hildon_time_editor_set_time (HildonTimeEditor *editor,
1180 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1182 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1186 * hildon_time_editor_get_time:
1187 * @editor: the #HildonTimeEditor widget
1192 * Gets the time of the #HildonTimeEditor widget. The time returned is
1193 * always in 24h format.
1196 hildon_time_editor_get_time (HildonTimeEditor *editor,
1201 HildonTimeEditorPrivate *priv;
1203 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1205 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1208 ticks_to_time (hildon_time_editor_get_ticks (editor), hours, minutes, seconds);
1212 * hildon_time_editor_set_duration_range:
1213 * @editor: the #HildonTimeEditor widget
1214 * @min_seconds: minimum allowed time in seconds
1215 * @max_seconds: maximum allowed time in seconds
1217 * Sets the duration editor time range of the #HildonTimeEditor widget.
1220 hildon_time_editor_set_duration_range (HildonTimeEditor *editor,
1224 HildonTimeEditorPrivate *priv;
1227 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1229 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1232 /* Swap values if reversed */
1233 if (min_seconds > max_seconds)
1236 max_seconds = min_seconds;
1240 hildon_time_editor_set_duration_max (editor, max_seconds);
1241 hildon_time_editor_set_duration_min (editor, min_seconds);
1243 if (priv->duration_mode) {
1244 /* Set minimum allowed value for duration editor.
1245 FIXME: Shouldn't it be changed only if it's not in range?
1246 Would change API, so won't touch this for now. */
1247 hildon_time_editor_set_ticks (editor, min_seconds);
1252 * hildon_time_editor_get_duration_range:
1253 * @editor: the #HildonTimeEditor widget
1254 * @min_seconds: pointer to guint
1255 * @max_seconds: pointer to guint
1257 * Gets the duration editor time range of the #HildonTimeEditor widget.
1260 hildon_time_editor_get_duration_range (HildonTimeEditor *editor,
1264 HildonTimeEditorPrivate *priv;
1266 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1268 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1271 *min_seconds = priv->duration_min;
1272 *max_seconds = priv->duration_max;
1276 hildon_time_editor_check_locale (HildonTimeEditor *editor)
1278 HildonTimeEditorPrivate *priv;
1280 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1283 /* Update time separator symbols */
1284 hildon_time_editor_get_time_separators (GTK_LABEL (priv->hm_label), GTK_LABEL (priv->sec_label));
1286 /* Get AM/PM symbols. */
1287 priv->am_symbol = g_strdup (nl_langinfo (AM_STR));
1288 priv->pm_symbol = g_strdup (nl_langinfo (PM_STR));
1290 if (priv->am_symbol[0] == '\0')
1293 /* 12h clock mode. Check if AM/PM should be before or after time.
1294 %p is the AM/PM string, so we assume that if the format string
1295 begins with %p it's in the beginning, and in any other case it's
1296 in the end (although that's not necessarily the case). */
1297 if (strncmp (nl_langinfo (T_FMT_AMPM), "%p", 2) == 0)
1298 priv->ampm_pos_after = FALSE;
1304 hildon_time_editor_entry_focus_in (GtkWidget *widget,
1305 GdkEventFocus *event,
1308 g_idle_add ((GSourceFunc) hildon_time_editor_entry_select_all,
1309 GTK_ENTRY (widget));
1315 hildon_time_editor_time_error (HildonTimeEditor *editor,
1316 HildonDateTimeError type)
1321 /* Returns negative if we didn't get value,
1322 * and should stop further validation
1325 validated_conversion (HildonTimeEditorPrivate *priv,
1330 gboolean allow_intermediate,
1332 GString *error_string)
1338 text = gtk_entry_get_text (GTK_ENTRY (field));
1340 if (text && text[0])
1342 /* Try to convert entry text to number */
1343 value = strtol (text, &tail, 10);
1345 /* Check if conversion succeeded */
1346 if ((tail[0] == 0) && !(text[0] == '-'))
1349 g_string_printf (error_string, _("ckct_ib_maximum_value"), max);
1350 priv->error_widget = field;
1351 *error_code = MAX_VALUE;
1355 if (value < min && !allow_intermediate) {
1356 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1357 priv->error_widget = field;
1358 *error_code = MIN_VALUE;
1365 /* We'll handle failed conversions soon */
1368 if ((tail[0] == '-') || (text[0] == '-'))
1370 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1371 priv->error_widget = field;
1372 *error_code = MIN_VALUE;
1377 else if (allow_intermediate)
1378 return -1; /* Empty field while user is still editing. No error, but
1379 cannot validate either... */
1380 else /* Empty field: show error and set value to minimum allowed */
1382 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1383 priv->error_widget = field;
1384 *error_code = WITHIN_RANGE;
1388 /* Empty field and not allowed intermediated OR failed conversion */
1389 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1390 priv->error_widget = field;
1391 *error_code = WITHIN_RANGE;
1396 hildon_time_editor_real_validate (HildonTimeEditor *editor,
1397 gboolean allow_intermediate,
1398 GString *error_string)
1400 HildonTimeEditorPrivate *priv;
1401 guint h, m, s, ticks;
1403 guint max_hours, min_hours, def_hours;
1404 guint max_minutes, min_minutes, def_minutes;
1405 guint max_seconds, min_seconds, def_seconds;
1408 g_assert (HILDON_IS_TIME_EDITOR (editor));
1410 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1413 /* Find limits for field based validation. */
1414 if (priv->duration_mode)
1416 ticks_to_time (priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1417 ticks_to_time (priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1419 if (priv->clock_24h) {
1420 max_hours = HOURS_MAX_24;
1421 min_hours = HOURS_MIN_24;
1423 max_hours = HOURS_MAX_12;
1424 min_hours = HOURS_MIN_12;
1428 hildon_time_editor_get_time (editor, &def_hours, &def_minutes, &def_seconds);
1430 /* Get time components from fields and validate them... */
1431 if (priv->show_hours) {
1432 h = validated_conversion (priv, priv->entries[ENTRY_HOURS], min_hours, max_hours, def_hours,
1433 allow_intermediate, &error_code, error_string);
1434 if (priv->error_widget == priv->entries[ENTRY_HOURS])
1435 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, hour_errors[error_code], &r);
1436 if ((gint) h < 0) return;
1439 m = validated_conversion (priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX, def_minutes,
1440 allow_intermediate, &error_code, error_string);
1441 if (priv->error_widget == priv->entries[ENTRY_MINS])
1442 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, min_errors[error_code], &r);
1443 if ((gint) m < 0) return;
1444 if (priv->show_seconds) {
1445 s = validated_conversion (priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX, def_seconds,
1446 allow_intermediate, &error_code, error_string);
1447 if (priv->error_widget == priv->entries[ENTRY_SECS])
1448 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, sec_errors[error_code], &r);
1449 if ((gint) s < 0) return;
1453 /* Ok, we now do separate check that tick count is valid for duration mode */
1454 if (priv->duration_mode)
1456 ticks = TICKS(h, m, s);
1458 if (ticks < priv->duration_min && !allow_intermediate)
1460 g_string_printf (error_string,
1461 _("ckct_ib_min_allowed_duration_hts"),
1462 min_hours, min_minutes, min_seconds);
1463 hildon_time_editor_set_ticks (editor, priv->duration_min);
1464 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1465 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MIN_DURATION, &r);
1468 else if (ticks > priv->duration_max)
1470 g_string_printf (error_string,
1471 _("ckct_ib_max_allowed_duration_hts"),
1472 max_hours, max_minutes, max_seconds);
1473 hildon_time_editor_set_ticks (editor, priv->duration_max);
1474 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1475 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MAX_DURATION, &r);
1479 else if (! priv->clock_24h)
1480 convert_to_24h (&h, priv->am);
1482 /* The only case when we do not want to refresh the
1483 time display, is when the user is editing a value
1484 (unless the value was out of bounds and we have to fix it) */
1485 if (! allow_intermediate || priv->error_widget)
1486 hildon_time_editor_set_time (editor, h, m, s);
1489 /* Setting text to entries causes entry to recompute itself
1490 in idle callback, which remove selection. Because of this
1491 we need to do selection in idle as well. */
1493 highlight_callback (gpointer data)
1495 HildonTimeEditorPrivate *priv;
1499 g_assert (HILDON_IS_TIME_EDITOR (data));
1500 priv = HILDON_TIME_EDITOR_GET_PRIVATE (data);
1503 GDK_THREADS_ENTER ();
1505 widget = priv->error_widget;
1506 priv->error_widget = NULL;
1508 if (GTK_IS_WIDGET (widget) == FALSE)
1511 /* Avoid revalidation because it will issue the date_error signal
1512 twice when there is an empty field. We must block the signal
1513 for all the entries because we do not know where the focus
1515 for (i = 0; i < ENTRY_COUNT; i++)
1516 g_signal_handlers_block_by_func (priv->entries[i],
1517 (gpointer) hildon_time_editor_entry_focus_out, data);
1518 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1519 gtk_widget_grab_focus (widget);
1520 for (i = 0; i < ENTRY_COUNT; i++)
1521 g_signal_handlers_unblock_by_func (priv->entries[i],
1522 (gpointer) hildon_time_editor_entry_focus_out, data);
1525 priv->highlight_idle = 0;
1526 GDK_THREADS_LEAVE ();
1531 /* Update ticks from current H:M:S entries. If they're invalid, show an
1532 infoprint and update the fields unless they're empty. */
1534 hildon_time_editor_validate (HildonTimeEditor *editor,
1535 gboolean allow_intermediate)
1537 HildonTimeEditorPrivate *priv;
1538 GString *error_message;
1540 g_assert (HILDON_IS_TIME_EDITOR(editor));
1541 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1544 /* if there is already an error we do nothing until it will be managed by the idle */
1545 if (priv->highlight_idle == 0 && priv->skipper == FALSE)
1547 priv->skipper = TRUE;
1548 error_message = g_string_new (NULL);
1549 hildon_time_editor_real_validate (editor,
1550 allow_intermediate, error_message);
1552 if (priv->error_widget)
1554 hildon_banner_show_information (priv->error_widget, NULL,
1555 error_message->str);
1557 priv->highlight_idle = g_idle_add (highlight_callback, editor);
1560 priv->skipper = FALSE;
1561 g_string_free (error_message, TRUE);
1565 /* on inserted text, if entry has two digits, jumps to the next field. */
1567 hildon_time_editor_inserted_text (GtkEditable *editable,
1569 gint new_text_length,
1573 HildonTimeEditor *editor;
1576 HildonTimeEditorPrivate *priv;
1578 entry = GTK_ENTRY (editable);
1579 editor = HILDON_TIME_EDITOR (user_data);
1581 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1584 /* if there is already an error we don't have to do anything */
1585 if (! priv->error_widget)
1587 value = (gchar *) gtk_entry_get_text (entry);
1589 if (strlen (value) == 2)
1591 if (GTK_WIDGET (editable) == priv->entries[ENTRY_HOURS])
1593 /* We already checked the input in changed signal, but
1594 * now we will re-check it again in focus-out we
1595 * intermediate flag set to FALSE */
1596 gtk_widget_grab_focus (priv->entries[ENTRY_MINS]);
1599 else if (GTK_WIDGET (editable) == priv->entries[ENTRY_MINS] &&
1600 GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS]))
1603 gtk_widget_grab_focus (priv->entries[ENTRY_SECS]);
1611 hildon_time_editor_entry_focus_out (GtkWidget *widget,
1612 GdkEventFocus *event,
1615 g_assert (HILDON_IS_TIME_EDITOR (data));
1617 /* Validate the given time and update ticks. */
1618 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1624 hildon_time_editor_ampm_clicked (GtkWidget *widget,
1627 HildonTimeEditor *editor;
1628 HildonTimeEditorPrivate *priv;
1630 g_assert (GTK_IS_WIDGET (widget));
1631 g_assert (HILDON_IS_TIME_EDITOR (data));
1633 editor = HILDON_TIME_EDITOR (data);
1634 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1637 /* First validate the given time and update ticks. */
1638 hildon_time_editor_validate (editor, FALSE);
1640 /* Apply the AM/PM change by moving the current time by 12 hours */
1642 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1643 hildon_time_editor_set_ticks (editor, priv->ticks + 12 * 3600);
1645 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1646 hildon_time_editor_set_ticks (editor, priv->ticks - 12 * 3600);
1653 hildon_time_editor_icon_clicked (GtkWidget *widget,
1656 HildonTimeEditor *editor;
1659 guint h, m, s, result;
1660 HildonTimeEditorPrivate *priv;
1662 g_assert (HILDON_IS_TIME_EDITOR (data));
1664 editor = HILDON_TIME_EDITOR (data);
1665 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1668 /* icon is passive in duration editor mode */
1669 if (hildon_time_editor_get_duration_mode (editor))
1672 /* Validate and do not launch if broken */
1673 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1674 if (priv->error_widget != NULL)
1677 /* Launch HildonTimePicker dialog */
1678 parent = gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW);
1679 picker = hildon_time_picker_new (GTK_WINDOW (parent));
1681 hildon_time_editor_get_time (editor, &h, &m, &s);
1682 hildon_time_picker_set_time (HILDON_TIME_PICKER (picker), h, m);
1684 result = gtk_dialog_run (GTK_DIALOG (picker));
1687 case GTK_RESPONSE_OK:
1688 case GTK_RESPONSE_ACCEPT:
1689 /* Use the selected time */
1690 hildon_time_picker_get_time (HILDON_TIME_PICKER (picker), &h, &m);
1691 hildon_time_editor_set_time (editor, h, m, 0);
1698 gtk_widget_destroy (picker);
1703 hildon_time_editor_size_request (GtkWidget *widget,
1704 GtkRequisition *requisition)
1706 HildonTimeEditor *editor;
1707 HildonTimeEditorPrivate *priv;
1710 editor = HILDON_TIME_EDITOR (widget);
1711 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1713 /* Get frame's size */
1714 gtk_widget_size_request (priv->frame, requisition);
1716 if (GTK_WIDGET_VISIBLE (priv->iconbutton))
1718 gtk_widget_size_request (priv->iconbutton, &req);
1719 /* Reserve space for icon */
1720 requisition->width += req.width + ICON_PRESSED +
1721 HILDON_MARGIN_DEFAULT;
1724 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1725 want to force this since themes might have varying thickness values
1726 which cause the height to change. */
1727 requisition->height = TIME_EDITOR_HEIGHT;
1731 hildon_time_editor_size_allocate (GtkWidget *widget,
1732 GtkAllocation *allocation)
1734 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
1735 GtkAllocation alloc;
1736 GtkRequisition req, max_req;
1740 widget->allocation = *allocation;
1741 gtk_widget_get_child_requisition (widget, &max_req);
1743 /* Center horizontally */
1744 alloc.x = allocation->x + MAX (allocation->width - max_req.width, 0) / 2;
1745 /* Center vertically */
1746 alloc.y = allocation->y + MAX (allocation->height - max_req.height, 0) / 2;
1748 /* allocate frame */
1749 gtk_widget_get_child_requisition (priv->frame, &req);
1751 alloc.width = req.width;
1752 alloc.height = max_req.height;
1753 gtk_widget_size_allocate (priv->frame, &alloc);
1756 if (GTK_WIDGET_VISIBLE (priv->iconbutton)) {
1757 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1759 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1760 alloc.width = req.width;
1761 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1764 /* FIXME: ugly way to move labels up. They just don't seem move up
1765 otherwise. This is likely because we force the editor to be
1766 smaller than it otherwise would be. */
1767 alloc = priv->ampm_label->allocation;
1768 alloc.y = allocation->y - 2;
1769 alloc.height = max_req.height + 2;
1770 gtk_widget_size_allocate (priv->ampm_label, &alloc);
1772 alloc = priv->hm_label->allocation;
1773 alloc.y = allocation->y - 2;
1774 alloc.height = max_req.height + 2;
1775 gtk_widget_size_allocate (priv->hm_label, &alloc);
1777 alloc = priv->sec_label->allocation;
1778 alloc.y = allocation->y - 2;
1779 alloc.height = max_req.height + 2;
1780 gtk_widget_size_allocate (priv->sec_label, &alloc);
1784 hildon_time_editor_focus (GtkWidget *widget,
1785 GtkDirectionType direction)
1788 GtkDirectionType effective_direction;
1790 g_assert (HILDON_IS_TIME_EDITOR (widget));
1792 retval = hildon_private_composite_focus (widget, direction, &effective_direction);
1795 return GTK_WIDGET_CLASS (parent_class)->focus (widget, effective_direction);
1801 hildon_time_editor_entry_keypress (GtkEntry *entry,
1805 switch (event->keyval)
1809 hildon_time_editor_icon_clicked (entry, data);
1815 g_assert_not_reached ();
1819 convert_to_12h (guint *h,
1822 g_assert (0 <= *h && *h < 24);
1824 /* 00:00 to 00:59 add 12 hours */
1825 /* 01:00 to 11:59 straight to am */
1826 /* 12:00 to 12:59 straight to pm */
1827 /* 13:00 to 23:59 subtract 12 hours */
1829 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1830 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1831 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1832 else { *am = FALSE; *h -= 12;}
1836 convert_to_24h (guint *h,
1839 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1844 else if (! am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1851 * hildon_time_editor_set_show_hours:
1852 * @editor: The #HildonTimeEditor.
1853 * @show_hours: Enable or disable showing of hours.
1855 * This function shows or hides the hours field.
1859 hildon_time_editor_set_show_hours (HildonTimeEditor *editor,
1860 gboolean show_hours)
1862 HildonTimeEditorPrivate *priv;
1864 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1866 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1869 if (show_hours != priv->show_hours) {
1870 priv->show_hours = show_hours;
1872 /* show/hide hours field and its ':' label if the value changed. */
1874 gtk_widget_show (priv->entries[ENTRY_HOURS]);
1875 gtk_widget_show (priv->hm_label);
1877 gtk_widget_hide (priv->entries[ENTRY_HOURS]);
1878 gtk_widget_hide (priv->hm_label);
1881 g_object_notify (G_OBJECT (editor), "show_hours");
1886 * hildon_time_editor_get_show_hours:
1887 * @editor: the @HildonTimeEditor widget.
1889 * This function returns a boolean indicating the visibility of
1890 * hours in the @HildonTimeEditor
1892 * Return value: TRUE if hours are visible.
1896 hildon_time_editor_get_show_hours (HildonTimeEditor *editor)
1898 HildonTimeEditorPrivate *priv;
1900 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1901 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1904 return priv->show_hours;
1909 hildon_time_editor_entry_select_all (GtkWidget *widget)
1911 GDK_THREADS_ENTER ();
1912 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1913 GDK_THREADS_LEAVE ();