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
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * SECTION:hildon-time-editor
27 * @short_description: A widget used to enter time or duration in hours, minutes,
28 * and optional seconds.
29 * @see_also: #HildonTimePicker
31 * HildonTimeEditor is used to edit time or duration. Time mode is
32 * restricted to normal 24 hour cycle, but Duration mode can select any
33 * amount of time up to 99 hours. It consists of entries for hours,
34 * minutes and seconds, and pm/am indicator as well as a button which
35 * popups a #HildonTimePicker dialog.
38 * <title>HildonTimePicker example</title>
41 * editor = hildon_time_editor_new ();
42 * hildon_time_editor_set_time (editor, h, m, s);
44 * gtk_box_pack_start (..., editor)
46 * hildon_time_editor_get_time (editor, &h, &m, &s);
57 #include "hildon-time-editor.h"
58 #include <gtk/gtkhbox.h>
59 #include <gtk/gtkentry.h>
60 #include <gtk/gtkbutton.h>
61 #include <gtk/gtklabel.h>
62 #include <gtk/gtkframe.h>
63 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkenums.h>
70 #include "hildon-defines.h"
71 #include "hildon-time-picker.h"
72 #include "hildon-banner.h"
73 #include "hildon-private.h"
74 #include "hildon-marshalers.h"
75 #include "hildon-enum-types.h"
76 #include "hildon-time-editor-private.h"
78 #define _(String) dgettext("hildon-libs", String)
80 #define c_(String) dgettext("hildon-common-strings", String)
82 #define TICKS(h,m,s) \
83 ((h) * 3600 + (m) * 60 + (s))
85 #define TIME_EDITOR_HEIGHT 30
87 #define ICON_PRESSED 4
89 #define ICON_NAME "qgn_widg_timedit"
91 #define ICON_SIZE "timepicker-size"
93 #define MIN_DURATION 0
95 #define MAX_DURATION TICKS(99, 59, 59)
97 /* Default values for properties */
99 #define HILDON_TIME_EDITOR_TICKS_VALUE 0
101 #define HILDON_TIME_EDITOR_DURATION_MODE FALSE
103 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE 0
105 #define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE TICKS(99, 59, 59)
107 #define HOURS_MAX_24 23
109 #define HOURS_MAX_12 12
111 #define HOURS_MIN_24 0
113 #define HOURS_MIN_12 1
115 #define MINUTES_MAX 59
117 #define SECONDS_MAX 59
119 #define MINUTES_MIN 0
121 #define SECONDS_MIN 0
123 static GtkContainerClass* parent_class;
142 /* Error codes categories */
150 static guint time_editor_signals[LAST_SIGNAL] = { 0 };
152 static guint hour_errors[NUM_ERROR_CODES] = {
153 HILDON_DATE_TIME_ERROR_MAX_HOURS,
154 HILDON_DATE_TIME_ERROR_MIN_HOURS,
155 HILDON_DATE_TIME_ERROR_EMPTY_HOURS };
157 static guint min_errors[NUM_ERROR_CODES] = {
158 HILDON_DATE_TIME_ERROR_MAX_MINS,
159 HILDON_DATE_TIME_ERROR_MIN_MINS,
160 HILDON_DATE_TIME_ERROR_EMPTY_MINS };
162 static guint sec_errors[NUM_ERROR_CODES] = {
163 HILDON_DATE_TIME_ERROR_MAX_SECS,
164 HILDON_DATE_TIME_ERROR_MIN_SECS,
165 HILDON_DATE_TIME_ERROR_EMPTY_SECS };
168 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class);
171 hildon_time_editor_init (HildonTimeEditor *editor);
174 hildon_time_editor_finalize (GObject *obj_self);
177 hildon_time_editor_set_property (GObject *object,
183 hildon_time_editor_get_property (GObject *object,
189 hildon_time_editor_forall (GtkContainer *container,
190 gboolean include_internals,
191 GtkCallback callback,
192 gpointer callback_data);
195 hildon_time_editor_destroy (GtkObject *self);
198 hildon_time_editor_entry_focus_out (GtkWidget *widget,
199 GdkEventFocus *event,
203 hildon_time_editor_entry_focus_in (GtkWidget *widget,
204 GdkEventFocus *event,
208 hildon_time_editor_time_error (HildonTimeEditor *editor,
209 HildonDateTimeError type);
212 hildon_time_editor_ampm_clicked (GtkWidget *widget,
216 hildon_time_editor_icon_clicked (GtkWidget *widget,
220 hildon_time_editor_size_request (GtkWidget *widget,
221 GtkRequisition *requisition);
224 hildon_time_editor_size_allocate (GtkWidget *widget,
225 GtkAllocation *allocation);
228 hildon_time_editor_entry_keypress (GtkWidget *widget,
233 hildon_time_editor_check_locale (HildonTimeEditor *editor);
236 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
239 GtkWidgetTapAndHoldFlags flags);
241 hildon_time_editor_validate (HildonTimeEditor *editor,
242 gboolean allow_intermediate);
245 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor);
248 hildon_time_editor_entry_select_all (GtkWidget *widget);
251 convert_to_12h (guint *h,
255 convert_to_24h (guint *h,
259 ticks_to_time (guint ticks,
265 hildon_time_editor_inserted_text (GtkEditable *editable,
267 gint new_text_length,
272 * hildon_time_editor_get_type:
274 * Initializes and returns the type of a hildon time editor.
276 * @Returns: GType of #HildonTimeEditor
279 hildon_time_editor_get_type (void)
281 static GType editor_type = 0;
284 static const GTypeInfo editor_info = {
285 sizeof(HildonTimeEditorClass),
286 NULL, /* base_init */
287 NULL, /* base_finalize */
288 (GClassInitFunc) hildon_time_editor_class_init,
289 NULL, /* class_finalize */
290 NULL, /* class_data */
291 sizeof(HildonTimeEditor),
293 (GInstanceInitFunc) hildon_time_editor_init,
295 editor_type = g_type_register_static (GTK_TYPE_CONTAINER,
304 hildon_time_editor_forall (GtkContainer *container,
305 gboolean include_internals,
306 GtkCallback callback,
307 gpointer callback_data)
309 HildonTimeEditorPrivate *priv;
311 g_assert (HILDON_IS_TIME_EDITOR (container));
312 g_assert (callback != NULL);
314 priv = HILDON_TIME_EDITOR_GET_PRIVATE (container);
318 if (! include_internals)
321 /* widget that are always shown */
322 (*callback) (priv->iconbutton, callback_data);
323 (*callback) (priv->frame, callback_data);
327 hildon_time_editor_destroy (GtkObject *self)
329 HildonTimeEditorPrivate *priv;
331 priv = HILDON_TIME_EDITOR_GET_PRIVATE (self);
334 if (priv->iconbutton) {
335 gtk_widget_unparent (priv->iconbutton);
336 priv->iconbutton = NULL;
339 gtk_widget_unparent (priv->frame);
343 if (GTK_OBJECT_CLASS (parent_class)->destroy)
344 GTK_OBJECT_CLASS (parent_class)->destroy (self);
348 hildon_time_editor_class_init (HildonTimeEditorClass *editor_class)
350 GObjectClass *object_class = G_OBJECT_CLASS (editor_class);
351 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (editor_class);
352 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (editor_class);
354 parent_class = g_type_class_peek_parent (editor_class);
356 g_type_class_add_private (editor_class, sizeof (HildonTimeEditorPrivate));
358 object_class->get_property = hildon_time_editor_get_property;
359 object_class->set_property = hildon_time_editor_set_property;
360 widget_class->size_request = hildon_time_editor_size_request;
361 widget_class->size_allocate = hildon_time_editor_size_allocate;
362 widget_class->tap_and_hold_setup = hildon_time_editor_tap_and_hold_setup;
363 widget_class->focus = hildon_private_composite_focus;
365 container_class->forall = hildon_time_editor_forall;
366 GTK_OBJECT_CLASS (editor_class)->destroy = hildon_time_editor_destroy;
368 object_class->finalize = hildon_time_editor_finalize;
370 editor_class->time_error = hildon_time_editor_time_error;
372 time_editor_signals[TIME_ERROR] =
373 g_signal_new ("time-error",
374 G_OBJECT_CLASS_TYPE (object_class),
376 G_STRUCT_OFFSET (HildonTimeEditorClass, time_error),
377 g_signal_accumulator_true_handled, NULL,
378 _hildon_marshal_BOOLEAN__ENUM,
379 G_TYPE_BOOLEAN, 1, HILDON_TYPE_DATE_TIME_ERROR);
382 * HildonTimeEditor:ticks:
384 * If editor is in duration mode, contains the duration seconds.
385 * If not, contains seconds since midnight.
387 g_object_class_install_property (object_class, PROP_TICKS,
388 g_param_spec_uint ("ticks",
390 "Current value of duration",
392 HILDON_TIME_EDITOR_TICKS_VALUE,
393 G_PARAM_READABLE | G_PARAM_WRITABLE) );
396 * HildonTimeEditor:show_seconds:
398 * Controls whether seconds are shown in the editor
400 g_object_class_install_property (object_class, PROP_SHOW_SECONDS,
401 g_param_spec_boolean ("show_seconds",
402 "Show seconds property",
403 "Controls whether the seconds are shown in the editor",
405 G_PARAM_READABLE | G_PARAM_WRITABLE) );
408 * HildonTimeEditor:show_hours:
410 * Controls whether hours are shown in the editor
412 g_object_class_install_property (object_class, PROP_SHOW_HOURS,
413 g_param_spec_boolean ("show_hours",
415 "Controls whether the hours field is shown in the editor",
417 G_PARAM_READABLE | G_PARAM_WRITABLE) );
420 * HildonTimeEditor:duration_mode:
422 * Controls whether the TimeEditor is in duration mode
424 g_object_class_install_property (object_class, PROP_DURATION_MODE,
425 g_param_spec_boolean ("duration_mode",
427 "Controls whether the TimeEditor is in duration mode",
428 HILDON_TIME_EDITOR_DURATION_MODE,
429 G_PARAM_READABLE | G_PARAM_WRITABLE) );
432 * HildonTimeEditor:duration_min:
434 * Minimum allowed duration value.
436 g_object_class_install_property (object_class, PROP_DURATION_MIN,
437 g_param_spec_uint ("duration_min",
438 "Minumum duration value",
439 "Smallest possible duration value",
440 MIN_DURATION, MAX_DURATION,
441 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
442 G_PARAM_READABLE | G_PARAM_WRITABLE) );
445 * HildonTimeEditor:duration_max:
447 * Maximum allowed duration value.
449 g_object_class_install_property (object_class, PROP_DURATION_MAX,
450 g_param_spec_uint ("duration_max",
451 "Maximum duration value",
452 "Largest possible duration value",
454 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
455 G_PARAM_READABLE | G_PARAM_WRITABLE) );
459 hildon_time_editor_tap_and_hold_setup (GtkWidget *widget,
462 GtkWidgetTapAndHoldFlags flags)
464 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
467 /* Forward this tap_and_hold_setup signal to all our child widgets */
468 for (i = 0; i < ENTRY_COUNT; i++)
470 gtk_widget_tap_and_hold_setup (priv->entries[i], menu, func,
471 GTK_TAP_AND_HOLD_NO_SIGNALS);
473 gtk_widget_tap_and_hold_setup (priv->ampm_button, menu, func,
474 GTK_TAP_AND_HOLD_NO_SIGNALS);
475 gtk_widget_tap_and_hold_setup (priv->iconbutton, menu, func,
476 GTK_TAP_AND_HOLD_NONE);
480 hildon_time_editor_entry_changed (GtkWidget *widget,
483 g_assert (HILDON_IS_TIME_EDITOR (data));
484 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), TRUE);
488 hildon_time_editor_init (HildonTimeEditor *editor)
490 HildonTimeEditorPrivate *priv;
491 GtkWidget *hbox, *icon;
494 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
497 gtk_widget_push_composite_child ();
499 /* Setup defaults and create widgets */
501 priv->show_seconds = FALSE;
502 priv->show_hours = TRUE;
503 priv->ampm_pos_after = TRUE;
504 priv->clock_24h = TRUE;
505 priv->duration_mode = FALSE;
506 priv->iconbutton = gtk_button_new();
507 priv->ampm_label = gtk_label_new(NULL);
508 priv->hm_label = gtk_label_new(NULL);
509 priv->sec_label = gtk_label_new(NULL);
510 priv->frame = gtk_frame_new(NULL);
511 priv->ampm_button = gtk_button_new();
512 priv->skipper = FALSE;
514 icon = gtk_image_new_from_icon_name (ICON_NAME, HILDON_ICON_SIZE_SMALL);
515 hbox = gtk_hbox_new (FALSE, 0);
517 GTK_WIDGET_SET_FLAGS (editor, GTK_NO_WINDOW);
518 GTK_WIDGET_UNSET_FLAGS (priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
520 gtk_container_set_border_width (GTK_CONTAINER(priv->frame), 0);
522 gtk_container_add (GTK_CONTAINER (priv->iconbutton), icon);
523 gtk_container_add (GTK_CONTAINER (priv->ampm_button), priv->ampm_label);
524 gtk_button_set_relief(GTK_BUTTON (priv->ampm_button), GTK_RELIEF_NONE);
525 gtk_button_set_focus_on_click (GTK_BUTTON (priv->ampm_button), FALSE);
527 /* Create hour, minute and second entries */
528 for (i = 0; i < ENTRY_COUNT; i++)
530 priv->entries[i] = gtk_entry_new ();
532 /* No frames for entries, so that they all appear to be inside one long entry */
533 gtk_entry_set_has_frame (GTK_ENTRY (priv->entries[i]), FALSE);
535 /* Set the entries to accept only numeric characters */
536 g_object_set (priv->entries[i], "input-mode", HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
538 /* The entry fields all take exactly two characters */
539 gtk_entry_set_max_length (GTK_ENTRY (priv->entries[i]), 2);
540 gtk_entry_set_width_chars (GTK_ENTRY (priv->entries[i]), 2);
542 g_signal_connect (priv->entries[i], "focus-in-event",
543 G_CALLBACK (hildon_time_editor_entry_focus_in), editor);
544 g_signal_connect (priv->entries[i], "focus-out-event",
545 G_CALLBACK (hildon_time_editor_entry_focus_out), editor);
546 g_signal_connect (priv->entries[i], "key-press-event",
547 G_CALLBACK (hildon_time_editor_entry_keypress), editor);
548 g_signal_connect (priv->entries[i], "changed",
549 G_CALLBACK (hildon_time_editor_entry_changed), editor);
551 /* inserted signal sets time */
552 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
553 G_CALLBACK (hildon_time_editor_inserted_text),
557 /* clicked signal for am/pm label */
558 g_signal_connect (G_OBJECT (priv->ampm_button), "clicked",
559 G_CALLBACK (hildon_time_editor_ampm_clicked), editor);
561 /* clicked signal for icon */
562 g_signal_connect (G_OBJECT (priv->iconbutton), "clicked",
563 G_CALLBACK (hildon_time_editor_icon_clicked), editor);
565 /* Set ourself as the parent of all the widgets we created */
566 gtk_widget_set_parent (priv->iconbutton, GTK_WIDGET(editor));
567 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
568 gtk_box_pack_start (GTK_BOX (hbox), priv->hm_label, FALSE, FALSE, 0);
569 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
570 gtk_box_pack_start (GTK_BOX (hbox), priv->sec_label, FALSE, FALSE, 0);
571 gtk_box_pack_start (GTK_BOX (hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
572 gtk_box_pack_start (GTK_BOX (hbox), priv->ampm_button, FALSE, FALSE, 0);
573 gtk_misc_set_padding (GTK_MISC (priv->ampm_label), 0, 0);
575 gtk_container_add (GTK_CONTAINER (priv->frame), hbox);
577 /* Show created widgets */
578 gtk_widget_set_parent (priv->frame, GTK_WIDGET(editor));
579 gtk_widget_show_all (priv->frame);
580 gtk_widget_show_all (priv->iconbutton);
582 /* Update AM/PM and time separators settings from locale */
583 if (! hildon_time_editor_check_locale (editor)) {
584 /* Using 12h clock */
585 priv->clock_24h = FALSE;
587 gtk_widget_hide (priv->ampm_button);
590 if (! priv->show_seconds) {
591 gtk_widget_hide (priv->sec_label);
592 gtk_widget_hide (priv->entries[ENTRY_SECS]);
595 /* set the default time to current time. */
596 hildon_time_editor_set_to_current_time (editor);
598 gtk_widget_pop_composite_child ();
602 hildon_time_editor_set_property (GObject *object,
607 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
612 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
615 case PROP_SHOW_SECONDS:
616 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
619 case PROP_SHOW_HOURS:
620 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
623 case PROP_DURATION_MODE:
624 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
627 case PROP_DURATION_MIN:
628 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
631 case PROP_DURATION_MAX:
632 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
636 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
642 hildon_time_editor_get_property (GObject *object,
647 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR (object);
653 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
656 case PROP_SHOW_SECONDS:
657 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
660 case PROP_SHOW_HOURS:
661 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
664 case PROP_DURATION_MODE:
665 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
668 case PROP_DURATION_MIN:
669 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
672 case PROP_DURATION_MAX:
673 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
677 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
683 * hildon_time_editor_new:
685 * This function creates a new time editor.
687 * Returns: pointer to a new #HildonTimeEditor widget
690 hildon_time_editor_new (void)
692 return GTK_WIDGET (g_object_new (HILDON_TYPE_TIME_EDITOR, NULL));
696 hildon_time_editor_finalize (GObject *obj_self)
698 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (obj_self);
702 g_free (priv->am_symbol);
705 g_free (priv->pm_symbol);
707 if (priv->highlight_idle)
708 g_source_remove (priv->highlight_idle);
710 if (G_OBJECT_CLASS (parent_class)->finalize)
711 G_OBJECT_CLASS (parent_class)->finalize (obj_self);
715 * hildon_time_editor_get_time_separators:
716 * @hm_sep_label: the label that will show the hour:minutes separator
717 * @ms_sep_label: the label that will show the minutes:seconds separator
719 * Gets hour-minute separator and minute-second separator from current
720 * locale and sets then to the labels we set as parameters. Both
721 * parameters can be NULL if you just want to assing one separator.
725 hildon_time_editor_get_time_separators (GtkLabel *hm_sep_label,
726 GtkLabel *ms_sep_label)
730 GDate locale_test_date;
731 gchar *iter, *endp = NULL;
733 /* Get localized time string */
734 g_date_set_dmy (&locale_test_date, 1, 2, 1970);
735 (void) g_date_strftime (buffer, sizeof (buffer), "%X", &locale_test_date);
737 if (hm_sep_label != NULL)
739 /* Find h-m separator */
741 while (*iter && g_ascii_isdigit (*iter)) iter++;
743 /* Extract h-m separator*/
745 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
746 separator = g_strndup (iter, endp - iter);
747 gtk_label_set_label (hm_sep_label, separator);
751 if (ms_sep_label != NULL)
753 /* Find m-s separator */
755 while (*iter && g_ascii_isdigit (*iter)) iter++;
757 /* Extract m-s separator*/
759 while (*endp && ! g_ascii_isdigit (*endp)) endp++;
760 separator = g_strndup (iter, endp - iter);
761 gtk_label_set_label (ms_sep_label, separator);
766 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
768 ticks_to_time (guint ticks,
775 *hours = ticks / 3600;
777 *minutes = left / 60;
778 *seconds = left % 60;
782 * hildon_time_editor_set_ticks:
783 * @editor: the #HildonTimeEditor widget
784 * @ticks: the duration to set, in seconds
786 * Sets the current duration in seconds. This means seconds from
787 * midnight, if not in duration mode. In case of any errors, it tries
792 hildon_time_editor_set_ticks (HildonTimeEditor *editor,
795 HildonTimeEditorPrivate *priv;
799 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
801 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
804 /* Validate ticks. If it's too low or too high, set it to
805 min/max value for the current mode. */
806 if (priv->duration_mode)
807 priv->ticks = CLAMP (ticks, priv->duration_min, priv->duration_max);
809 /* Check that ticks value is valid. We only need to check that hours
811 ticks_to_time (ticks, &h, &m, &s);
812 if (h > HOURS_MAX_24)
813 ticks = TICKS(HOURS_MAX_24, m, s);
818 /* Get the time in H:M:S. */
819 ticks_to_time (priv->ticks, &h, &m, &s);
821 if (!priv->clock_24h && ! priv->duration_mode)
823 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
824 convert_to_12h (&h, &priv->am);
827 /* Set H:M:S values to entries. We do not want to invoke validation
828 callbacks (since they can cause new call to this function), so we
829 block signals while setting values. */
830 for (i = 0; i < ENTRY_COUNT; i++)
832 g_signal_handlers_block_by_func(priv->entries[i],
833 (gpointer) hildon_time_editor_entry_changed, editor);
835 g_signal_handlers_block_by_func(priv->entries[i],
836 (gpointer) hildon_time_editor_inserted_text, editor);
838 g_signal_handlers_block_by_func(priv->entries[i],
839 (gpointer) hildon_time_editor_entry_focus_out, editor);
842 g_snprintf (str, sizeof (str), "%02u", h);
843 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_HOURS]), str);
845 g_snprintf(str, sizeof (str), "%02u", m);
846 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_MINS]), str);
848 g_snprintf(str, sizeof (str), "%02u", s);
849 gtk_entry_set_text (GTK_ENTRY (priv->entries[ENTRY_SECS]), str);
851 for (i = 0; i < ENTRY_COUNT; i++)
853 g_signal_handlers_unblock_by_func (priv->entries[i],
854 (gpointer) hildon_time_editor_entry_changed, editor);
856 g_signal_handlers_unblock_by_func (priv->entries[i],
857 (gpointer) hildon_time_editor_inserted_text, editor);
859 g_signal_handlers_unblock_by_func (priv->entries[i],
860 (gpointer) hildon_time_editor_entry_focus_out, editor);
863 /* Update AM/PM label in case we're in 12h mode */
864 gtk_label_set_label( GTK_LABEL (priv->ampm_label),
865 priv->am ? priv->am_symbol : priv->pm_symbol);
867 g_object_notify (G_OBJECT (editor), "ticks");
871 hildon_time_editor_set_to_current_time (HildonTimeEditor *editor)
877 tm = localtime (&now);
880 hildon_time_editor_set_time (editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
884 * hildon_time_editor_get_ticks:
885 * @editor: the #HildonTimeEditor widget
887 * This function returns the current duration, in seconds.
888 * This means seconds from midnight, if not in duration mode.
890 * Returns: current duration in seconds
893 hildon_time_editor_get_ticks (HildonTimeEditor *editor)
895 HildonTimeEditorPrivate *priv;
897 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
899 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
902 return (priv->ticks);
906 * hildon_time_editor_set_show_seconds:
907 * @editor: the #HildonTimeEditor
908 * @show_seconds: enable or disable showing of seconds
910 * This function shows or hides the seconds field.
913 hildon_time_editor_set_show_seconds (HildonTimeEditor *editor,
914 gboolean show_seconds)
916 HildonTimeEditorPrivate *priv;
918 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
920 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
923 if (show_seconds != priv->show_seconds) {
924 priv->show_seconds = show_seconds;
926 /* show/hide seconds field and its ':' label if the value changed. */
928 gtk_widget_show (priv->entries[ENTRY_SECS]);
929 gtk_widget_show (priv->sec_label);
931 gtk_widget_hide (priv->entries[ENTRY_SECS]);
932 gtk_widget_hide (priv->sec_label);
935 g_object_notify (G_OBJECT (editor), "show_seconds");
940 * hildon_time_editor_get_show_seconds:
941 * @editor: the #HildonTimeEditor widget
943 * This function returns a boolean indicating the visibility of
944 * seconds in the #HildonTimeEditor
946 * Returns: TRUE if the seconds are visible
949 hildon_time_editor_get_show_seconds (HildonTimeEditor *editor)
951 HildonTimeEditorPrivate *priv;
953 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
954 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
957 return (priv->show_seconds);
961 * hildon_time_editor_set_duration_mode:
962 * @editor: the #HildonTimeEditor
963 * @duration_mode: enable or disable duration editor mode
965 * This function sets the duration editor mode in which the maximum hours
969 hildon_time_editor_set_duration_mode (HildonTimeEditor *editor,
970 gboolean duration_mode)
972 HildonTimeEditorPrivate *priv;
974 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
976 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
979 if (duration_mode != priv->duration_mode) {
980 priv->duration_mode = duration_mode;
983 /* FIXME: Why do we reset the duration range here?
984 Would change API, so won't touch this for now. */
985 hildon_time_editor_set_duration_range (editor, MIN_DURATION, MAX_DURATION);
986 /* There's no AM/PM label or time picker icon in duration mode.
987 Make sure they're hidden. */
988 gtk_widget_hide (GTK_WIDGET (priv->ampm_label));
989 gtk_widget_hide (GTK_WIDGET (priv->ampm_button));
990 gtk_widget_hide (GTK_WIDGET (priv->iconbutton));
991 /* Duration mode has seconds by default. */
992 hildon_time_editor_set_show_seconds (editor, TRUE);
994 /* Make sure AM/PM label and time picker icons are visible if needed */
995 if (! priv->clock_24h)
996 gtk_widget_show (GTK_WIDGET (priv->ampm_label));
998 gtk_widget_show (GTK_WIDGET (priv->ampm_button));
999 gtk_widget_show (GTK_WIDGET (priv->iconbutton));
1001 /* Reset the ticks to current time. Anything set in duration mode
1002 * is bound to be invalid or useless in time mode.
1004 hildon_time_editor_set_to_current_time (editor);
1007 g_object_notify (G_OBJECT (editor), "duration_mode");
1012 * hildon_time_editor_get_duration_mode:
1013 * @editor: the #HildonTimeEditor widget
1015 * This function returns a boolean indicating whether the #HildonTimeEditor
1016 * is in the duration mode.
1018 * Returns: TRUE if the #HildonTimeEditor is in duration mode
1021 hildon_time_editor_get_duration_mode (HildonTimeEditor *editor)
1023 HildonTimeEditorPrivate *priv;
1025 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1026 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1029 return (priv->duration_mode);
1033 * hildon_time_editor_set_duration_min:
1034 * @editor: the #HildonTimeEditor widget
1035 * @duration_min: mimimum allowed duration
1037 * Sets the minimum allowed duration for the duration mode.
1038 * Note: Has no effect in time mode
1041 hildon_time_editor_set_duration_min (HildonTimeEditor *editor,
1044 HildonTimeEditorPrivate *priv;
1046 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1047 g_return_if_fail (duration_min >= MIN_DURATION);
1049 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1052 if (! priv->duration_mode )
1055 priv->duration_min = duration_min;
1057 /* Clamp the current value to the minimum if necessary */
1058 if (priv->ticks < duration_min)
1060 hildon_time_editor_set_ticks (editor, duration_min);
1063 g_object_notify (G_OBJECT (editor), "duration_min");
1067 * hildon_time_editor_get_duration_min:
1068 * @editor: the #HildonTimeEditor widget
1070 * This function returns the smallest duration the #HildonTimeEditor
1071 * allows in the duration mode.
1073 * Returns: minimum allowed duration in seconds
1076 hildon_time_editor_get_duration_min (HildonTimeEditor *editor)
1078 HildonTimeEditorPrivate *priv;
1080 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1082 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1085 if(! priv->duration_mode )
1088 return (priv->duration_min);
1092 * hildon_time_editor_set_duration_max:
1093 * @editor: the #HildonTimeEditor widget
1094 * @duration_max: maximum allowed duration in seconds
1096 * Sets the maximum allowed duration in seconds for the duration mode.
1097 * Note: Has no effect in time mode
1100 hildon_time_editor_set_duration_max (HildonTimeEditor *editor,
1103 HildonTimeEditorPrivate *priv;
1105 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1106 g_return_if_fail (duration_max <= MAX_DURATION);
1108 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1111 if (! priv->duration_mode)
1114 priv->duration_max = duration_max;
1116 /* Clamp the current value to the maximum if necessary */
1117 if (priv->ticks > duration_max)
1119 hildon_time_editor_set_ticks (editor, duration_max);
1122 g_object_notify (G_OBJECT (editor), "duration_max");
1126 * hildon_time_editor_get_duration_max:
1127 * @editor: the #HildonTimeEditor widget
1129 * This function returns the longest duration the #HildonTimeEditor
1130 * allows in the duration mode.
1132 * Returns: maximum allowed duration in seconds
1135 hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1137 HildonTimeEditorPrivate *priv;
1139 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), 0);
1141 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1144 if (! priv->duration_mode)
1147 return (priv->duration_max);
1151 * hildon_time_editor_set_time:
1152 * @editor: the #HildonTimeEditor widget
1157 * This function sets the time on an existing time editor. If the
1158 * time specified by the arguments is invalid, it's fixed.
1159 * The time is assumed to be in 24h format.
1162 hildon_time_editor_set_time (HildonTimeEditor *editor,
1167 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1169 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1173 * hildon_time_editor_get_time:
1174 * @editor: the #HildonTimeEditor widget
1179 * Gets the time of the #HildonTimeEditor widget. The time returned is
1180 * always in 24h format.
1183 hildon_time_editor_get_time (HildonTimeEditor *editor,
1188 HildonTimeEditorPrivate *priv;
1190 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1192 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1195 ticks_to_time (hildon_time_editor_get_ticks (editor), hours, minutes, seconds);
1199 * hildon_time_editor_set_duration_range:
1200 * @editor: the #HildonTimeEditor widget
1201 * @min_seconds: minimum allowed time in seconds
1202 * @max_seconds: maximum allowed time in seconds
1204 * Sets the duration editor time range of the #HildonTimeEditor widget.
1207 hildon_time_editor_set_duration_range (HildonTimeEditor *editor,
1211 HildonTimeEditorPrivate *priv;
1214 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1216 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1219 /* Swap values if reversed */
1220 if (min_seconds > max_seconds)
1223 max_seconds = min_seconds;
1227 hildon_time_editor_set_duration_max (editor, max_seconds);
1228 hildon_time_editor_set_duration_min (editor, min_seconds);
1230 if (priv->duration_mode) {
1231 /* Set minimum allowed value for duration editor.
1232 FIXME: Shouldn't it be changed only if it's not in range?
1233 Would change API, so won't touch this for now. */
1234 hildon_time_editor_set_ticks (editor, min_seconds);
1239 * hildon_time_editor_get_duration_range:
1240 * @editor: the #HildonTimeEditor widget
1241 * @min_seconds: pointer to guint
1242 * @max_seconds: pointer to guint
1244 * Gets the duration editor time range of the #HildonTimeEditor widget.
1247 hildon_time_editor_get_duration_range (HildonTimeEditor *editor,
1251 HildonTimeEditorPrivate *priv;
1253 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1255 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1258 *min_seconds = priv->duration_min;
1259 *max_seconds = priv->duration_max;
1263 hildon_time_editor_check_locale (HildonTimeEditor *editor)
1265 HildonTimeEditorPrivate *priv;
1267 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1270 /* Update time separator symbols */
1271 hildon_time_editor_get_time_separators (GTK_LABEL (priv->hm_label), GTK_LABEL (priv->sec_label));
1273 /* Get AM/PM symbols. */
1274 priv->am_symbol = g_strdup (nl_langinfo (AM_STR));
1275 priv->pm_symbol = g_strdup (nl_langinfo (PM_STR));
1277 if (priv->am_symbol[0] == '\0')
1280 /* 12h clock mode. Check if AM/PM should be before or after time.
1281 %p is the AM/PM string, so we assume that if the format string
1282 begins with %p it's in the beginning, and in any other case it's
1283 in the end (although that's not necessarily the case). */
1284 if (strncmp (nl_langinfo (T_FMT_AMPM), "%p", 2) == 0)
1285 priv->ampm_pos_after = FALSE;
1291 hildon_time_editor_entry_focus_in (GtkWidget *widget,
1292 GdkEventFocus *event,
1295 g_idle_add ((GSourceFunc) hildon_time_editor_entry_select_all,
1296 GTK_ENTRY (widget));
1302 hildon_time_editor_time_error (HildonTimeEditor *editor,
1303 HildonDateTimeError type)
1308 /* Returns negative if we didn't get value,
1309 * and should stop further validation
1312 validated_conversion (HildonTimeEditorPrivate *priv,
1317 gboolean allow_intermediate,
1319 GString *error_string)
1325 text = gtk_entry_get_text (GTK_ENTRY (field));
1327 if (text && text[0])
1329 /* Try to convert entry text to number */
1330 value = strtol (text, &tail, 10);
1332 /* Check if conversion succeeded */
1333 if ((tail[0] == 0) && !(text[0] == '-'))
1336 g_string_printf (error_string, _("ckct_ib_maximum_value"), max);
1337 priv->error_widget = field;
1338 *error_code = MAX_VALUE;
1342 if (value < min && !allow_intermediate) {
1343 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1344 priv->error_widget = field;
1345 *error_code = MIN_VALUE;
1352 /* We'll handle failed conversions soon */
1355 if ((tail[0] == '-') || (text[0] == '-'))
1357 g_string_printf (error_string, _("ckct_ib_minimum_value"), min);
1358 priv->error_widget = field;
1359 *error_code = MIN_VALUE;
1364 else if (allow_intermediate)
1365 return -1; /* Empty field while user is still editing. No error, but
1366 cannot validate either... */
1367 else /* Empty field: show error and set value to minimum allowed */
1369 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1370 priv->error_widget = field;
1371 *error_code = WITHIN_RANGE;
1375 /* Empty field and not allowed intermediated OR failed conversion */
1376 g_string_printf (error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1377 priv->error_widget = field;
1378 *error_code = WITHIN_RANGE;
1383 hildon_time_editor_real_validate (HildonTimeEditor *editor,
1384 gboolean allow_intermediate,
1385 GString *error_string)
1387 HildonTimeEditorPrivate *priv;
1388 guint h, m, s, ticks;
1390 guint max_hours, min_hours, def_hours;
1391 guint max_minutes, min_minutes, def_minutes;
1392 guint max_seconds, min_seconds, def_seconds;
1395 g_assert (HILDON_IS_TIME_EDITOR (editor));
1397 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1400 /* Find limits for field based validation. */
1401 if (priv->duration_mode)
1403 ticks_to_time (priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1404 ticks_to_time (priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1406 if (priv->clock_24h) {
1407 max_hours = HOURS_MAX_24;
1408 min_hours = HOURS_MIN_24;
1410 max_hours = HOURS_MAX_12;
1411 min_hours = HOURS_MIN_12;
1415 hildon_time_editor_get_time (editor, &def_hours, &def_minutes, &def_seconds);
1417 /* Get time components from fields and validate them... */
1418 if (priv->show_hours) {
1419 h = validated_conversion (priv, priv->entries[ENTRY_HOURS], min_hours, max_hours, def_hours,
1420 allow_intermediate, &error_code, error_string);
1421 if (priv->error_widget == priv->entries[ENTRY_HOURS])
1422 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, hour_errors[error_code], &r);
1423 if ((gint) h < 0) return;
1426 m = validated_conversion (priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX, def_minutes,
1427 allow_intermediate, &error_code, error_string);
1428 if (priv->error_widget == priv->entries[ENTRY_MINS])
1429 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, min_errors[error_code], &r);
1430 if ((gint) m < 0) return;
1431 if (priv->show_seconds) {
1432 s = validated_conversion (priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX, def_seconds,
1433 allow_intermediate, &error_code, error_string);
1434 if (priv->error_widget == priv->entries[ENTRY_SECS])
1435 g_signal_emit (editor, time_editor_signals [TIME_ERROR], 0, sec_errors[error_code], &r);
1436 if ((gint) s < 0) return;
1440 /* Ok, we now do separate check that tick count is valid for duration mode */
1441 if (priv->duration_mode)
1443 ticks = TICKS(h, m, s);
1445 if (ticks < priv->duration_min && !allow_intermediate)
1447 g_string_printf (error_string,
1448 _("ckct_ib_min_allowed_duration_hts"),
1449 min_hours, min_minutes, min_seconds);
1450 hildon_time_editor_set_ticks (editor, priv->duration_min);
1451 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1452 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MIN_DURATION, &r);
1455 else if (ticks > priv->duration_max)
1457 g_string_printf (error_string,
1458 _("ckct_ib_max_allowed_duration_hts"),
1459 max_hours, max_minutes, max_seconds);
1460 hildon_time_editor_set_ticks (editor, priv->duration_max);
1461 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1462 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_MAX_DURATION, &r);
1466 else if (! priv->clock_24h)
1467 convert_to_24h (&h, priv->am);
1469 /* The only case when we do not want to refresh the
1470 time display, is when the user is editing a value
1471 (unless the value was out of bounds and we have to fix it) */
1472 if (! allow_intermediate || priv->error_widget)
1473 hildon_time_editor_set_time (editor, h, m, s);
1476 /* Setting text to entries causes entry to recompute itself
1477 in idle callback, which remove selection. Because of this
1478 we need to do selection in idle as well. */
1480 highlight_callback (gpointer data)
1482 HildonTimeEditorPrivate *priv;
1486 g_assert (HILDON_IS_TIME_EDITOR (data));
1487 priv = HILDON_TIME_EDITOR_GET_PRIVATE (data);
1490 GDK_THREADS_ENTER ();
1492 widget = priv->error_widget;
1493 priv->error_widget = NULL;
1495 if (GTK_IS_WIDGET (widget) == FALSE)
1498 /* Avoid revalidation because it will issue the date_error signal
1499 twice when there is an empty field. We must block the signal
1500 for all the entries because we do not know where the focus
1502 for (i = 0; i < ENTRY_COUNT; i++)
1503 g_signal_handlers_block_by_func (priv->entries[i],
1504 (gpointer) hildon_time_editor_entry_focus_out, data);
1505 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1506 gtk_widget_grab_focus (widget);
1507 for (i = 0; i < ENTRY_COUNT; i++)
1508 g_signal_handlers_unblock_by_func (priv->entries[i],
1509 (gpointer) hildon_time_editor_entry_focus_out, data);
1512 priv->highlight_idle = 0;
1513 GDK_THREADS_LEAVE ();
1518 /* Update ticks from current H:M:S entries. If they're invalid, show an
1519 infoprint and update the fields unless they're empty. */
1521 hildon_time_editor_validate (HildonTimeEditor *editor,
1522 gboolean allow_intermediate)
1524 HildonTimeEditorPrivate *priv;
1525 GString *error_message;
1527 g_assert (HILDON_IS_TIME_EDITOR(editor));
1528 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1531 /* if there is already an error we do nothing until it will be managed by the idle */
1532 if (priv->highlight_idle == 0 && priv->skipper == FALSE)
1534 priv->skipper = TRUE;
1535 error_message = g_string_new (NULL);
1536 hildon_time_editor_real_validate (editor,
1537 allow_intermediate, error_message);
1539 if (priv->error_widget)
1541 hildon_banner_show_information (priv->error_widget, NULL,
1542 error_message->str);
1544 priv->highlight_idle = g_idle_add (highlight_callback, editor);
1547 priv->skipper = FALSE;
1548 g_string_free (error_message, TRUE);
1552 /* on inserted text, if entry has two digits, jumps to the next field. */
1554 hildon_time_editor_inserted_text (GtkEditable *editable,
1556 gint new_text_length,
1560 HildonTimeEditor *editor;
1563 HildonTimeEditorPrivate *priv;
1565 entry = GTK_ENTRY (editable);
1566 editor = HILDON_TIME_EDITOR (user_data);
1568 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1571 /* if there is already an error we don't have to do anything */
1572 if (! priv->error_widget)
1574 value = (gchar *) gtk_entry_get_text (entry);
1576 if (strlen (value) == 2)
1578 if (GTK_WIDGET (editable) == priv->entries[ENTRY_HOURS])
1580 /* We already checked the input in changed signal, but
1581 * now we will re-check it again in focus-out we
1582 * intermediate flag set to FALSE */
1583 gtk_widget_grab_focus (priv->entries[ENTRY_MINS]);
1586 else if (GTK_WIDGET (editable) == priv->entries[ENTRY_MINS] &&
1587 GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS]))
1590 gtk_widget_grab_focus (priv->entries[ENTRY_SECS]);
1598 hildon_time_editor_entry_focus_out (GtkWidget *widget,
1599 GdkEventFocus *event,
1602 g_assert (HILDON_IS_TIME_EDITOR (data));
1604 /* Validate the given time and update ticks. */
1605 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1611 hildon_time_editor_ampm_clicked (GtkWidget *widget,
1614 HildonTimeEditor *editor;
1615 HildonTimeEditorPrivate *priv;
1617 g_assert (GTK_IS_WIDGET (widget));
1618 g_assert (HILDON_IS_TIME_EDITOR (data));
1620 editor = HILDON_TIME_EDITOR (data);
1621 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1624 /* First validate the given time and update ticks. */
1625 hildon_time_editor_validate (editor, FALSE);
1627 /* Apply the AM/PM change by moving the current time by 12 hours */
1629 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1630 hildon_time_editor_set_ticks (editor, priv->ticks + 12 * 3600);
1632 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1633 hildon_time_editor_set_ticks (editor, priv->ticks - 12 * 3600);
1640 hildon_time_editor_icon_clicked (GtkWidget *widget,
1643 HildonTimeEditor *editor;
1646 guint h, m, s, result;
1647 HildonTimeEditorPrivate *priv;
1649 g_assert (HILDON_IS_TIME_EDITOR (data));
1651 editor = HILDON_TIME_EDITOR (data);
1652 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1655 /* icon is passive in duration editor mode */
1656 if (hildon_time_editor_get_duration_mode (editor))
1659 /* Validate and do not launch if broken */
1660 hildon_time_editor_validate (HILDON_TIME_EDITOR (data), FALSE);
1661 if (priv->error_widget != NULL)
1664 /* Launch HildonTimePicker dialog */
1665 parent = gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW);
1666 picker = hildon_time_picker_new (GTK_WINDOW (parent));
1668 hildon_time_editor_get_time (editor, &h, &m, &s);
1669 hildon_time_picker_set_time (HILDON_TIME_PICKER (picker), h, m);
1671 result = gtk_dialog_run (GTK_DIALOG (picker));
1674 case GTK_RESPONSE_OK:
1675 case GTK_RESPONSE_ACCEPT:
1676 /* Use the selected time */
1677 hildon_time_picker_get_time (HILDON_TIME_PICKER (picker), &h, &m);
1678 hildon_time_editor_set_time (editor, h, m, 0);
1685 gtk_widget_destroy (picker);
1690 hildon_time_editor_size_request (GtkWidget *widget,
1691 GtkRequisition *requisition)
1693 HildonTimeEditor *editor;
1694 HildonTimeEditorPrivate *priv;
1697 editor = HILDON_TIME_EDITOR (widget);
1698 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1700 /* Get frame's size */
1701 gtk_widget_size_request (priv->frame, requisition);
1703 if (GTK_WIDGET_VISIBLE (priv->iconbutton))
1705 gtk_widget_size_request (priv->iconbutton, &req);
1706 /* Reserve space for icon */
1707 requisition->width += req.width + ICON_PRESSED +
1708 HILDON_MARGIN_DEFAULT;
1711 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1712 want to force this since themes might have varying thickness values
1713 which cause the height to change. */
1714 requisition->height = TIME_EDITOR_HEIGHT;
1718 hildon_time_editor_size_allocate (GtkWidget *widget,
1719 GtkAllocation *allocation)
1721 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE (widget);
1722 GtkAllocation alloc;
1723 GtkRequisition req, max_req;
1727 widget->allocation = *allocation;
1728 gtk_widget_get_child_requisition (widget, &max_req);
1730 /* Center horizontally */
1731 alloc.x = allocation->x + MAX (allocation->width - max_req.width, 0) / 2;
1732 /* Center vertically */
1733 alloc.y = allocation->y + MAX (allocation->height - max_req.height, 0) / 2;
1735 /* allocate frame */
1736 gtk_widget_get_child_requisition (priv->frame, &req);
1738 alloc.width = req.width;
1739 alloc.height = max_req.height;
1740 gtk_widget_size_allocate (priv->frame, &alloc);
1743 if (GTK_WIDGET_VISIBLE (priv->iconbutton)) {
1744 gtk_widget_get_child_requisition (priv->iconbutton, &req);
1746 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1747 alloc.width = req.width;
1748 gtk_widget_size_allocate (priv->iconbutton, &alloc);
1751 /* FIXME: ugly way to move labels up. They just don't seem move up
1752 otherwise. This is likely because we force the editor to be
1753 smaller than it otherwise would be. */
1754 alloc = priv->ampm_label->allocation;
1755 alloc.y = allocation->y - 2;
1756 alloc.height = max_req.height + 2;
1757 gtk_widget_size_allocate (priv->ampm_label, &alloc);
1759 alloc = priv->hm_label->allocation;
1760 alloc.y = allocation->y - 2;
1761 alloc.height = max_req.height + 2;
1762 gtk_widget_size_allocate (priv->hm_label, &alloc);
1764 alloc = priv->sec_label->allocation;
1765 alloc.y = allocation->y - 2;
1766 alloc.height = max_req.height + 2;
1767 gtk_widget_size_allocate (priv->sec_label, &alloc);
1771 hildon_time_editor_entry_keypress (GtkWidget *widget,
1775 HildonTimeEditor *editor;
1776 HildonTimeEditorPrivate *priv;
1780 g_assert (GTK_IS_ENTRY (widget));
1781 g_assert (event != NULL);
1782 g_assert (HILDON_IS_TIME_EDITOR (data));
1784 editor = HILDON_TIME_EDITOR (data);
1785 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1787 cursor_pos = gtk_editable_get_position (GTK_EDITABLE (widget));
1789 /* Show error message in case the key pressed is not allowed
1790 (only digits and control characters are allowed )*/
1791 if (!g_unichar_isdigit (event->keyval) && ! (event->keyval & 0xF000)) {
1792 g_signal_emit (editor, time_editor_signals[TIME_ERROR], 0, HILDON_DATE_TIME_ERROR_INVALID_CHAR, &r);
1793 hildon_banner_show_information (widget, NULL, c_("ckct_ib_illegal_character"));
1797 switch (event->keyval)
1800 /* Return key popups up time picker dialog. Visually it looks as if
1801 the time picker icon was clicked. Before opening the time picker
1802 the fields are first validated and fixed. */
1804 /* hildon_time_editor_validate (editor, FALSE);
1805 hildon_gtk_button_set_depressed (GTK_BUTTON (priv->iconbutton), TRUE);
1806 hildon_time_editor_icon_clicked (widget, data);
1807 hildon_gtk_button_set_depressed (GTK_BUTTON (priv->iconbutton), FALSE);
1809 FIXME The above code used to be here before the consolidation that removed the
1810 _set_depressed crap. However, I think this code had NO EFFECT anyways, since
1811 there is no expose event after the _set functions. So I'm just cutting it out.
1812 Another story would be to actually fix it... */
1814 hildon_time_editor_icon_clicked (widget, data);
1818 /* left arrow pressed in the entry. If we are on first position, try to
1819 move to the previous field. */
1820 if (cursor_pos == 0) {
1821 (void) gtk_widget_child_focus (GTK_WIDGET (editor), GTK_DIR_LEFT);
1827 /* right arrow pressed in the entry. If we are on last position, try to
1828 move to the next field. */
1829 if (cursor_pos >= g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (widget)), -1)) {
1830 (void) gtk_widget_child_focus (GTK_WIDGET (editor), GTK_DIR_RIGHT);
1843 convert_to_12h (guint *h,
1846 g_assert (0 <= *h && *h < 24);
1848 /* 00:00 to 00:59 add 12 hours */
1849 /* 01:00 to 11:59 straight to am */
1850 /* 12:00 to 12:59 straight to pm */
1851 /* 13:00 to 23:59 subtract 12 hours */
1853 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1854 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1855 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1856 else { *am = FALSE; *h -= 12;}
1860 convert_to_24h (guint *h,
1863 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1868 else if (! am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1875 * hildon_time_editor_set_show_hours:
1876 * @editor: The #HildonTimeEditor.
1877 * @show_hours: Enable or disable showing of hours.
1879 * This function shows or hides the hours field.
1883 hildon_time_editor_set_show_hours (HildonTimeEditor *editor,
1884 gboolean show_hours)
1886 HildonTimeEditorPrivate *priv;
1888 g_return_if_fail (HILDON_IS_TIME_EDITOR (editor));
1890 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1893 if (show_hours != priv->show_hours) {
1894 priv->show_hours = show_hours;
1896 /* show/hide hours field and its ':' label if the value changed. */
1898 gtk_widget_show (priv->entries[ENTRY_HOURS]);
1899 gtk_widget_show (priv->hm_label);
1901 gtk_widget_hide (priv->entries[ENTRY_HOURS]);
1902 gtk_widget_hide (priv->hm_label);
1905 g_object_notify (G_OBJECT (editor), "show_hours");
1910 * hildon_time_editor_get_show_hours:
1911 * @editor: the @HildonTimeEditor widget.
1913 * This function returns a boolean indicating the visibility of
1914 * hours in the @HildonTimeEditor
1916 * Return value: TRUE if hours are visible.
1920 hildon_time_editor_get_show_hours (HildonTimeEditor *editor)
1922 HildonTimeEditorPrivate *priv;
1924 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1925 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1928 return priv->show_hours;
1933 hildon_time_editor_entry_select_all (GtkWidget *widget)
1935 GDK_THREADS_ENTER ();
1936 gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
1937 GDK_THREADS_LEAVE ();