2 * This file is part of hildon-libs
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@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; either 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.
42 #include <gtk/gtkhbox.h>
43 #include <gtk/gtkeventbox.h>
44 #include <gtk/gtkentry.h>
45 #include <gtk/gtkbutton.h>
46 #include <gtk/gtklabel.h>
47 #include <gtk/gtkframe.h>
48 #include <gdk/gdkkeysyms.h>
56 #include <hildon-widgets/hildon-defines.h>
57 #include <hildon-widgets/hildon-time-editor.h>
58 #include <hildon-widgets/hildon-time-picker.h>
59 #include <hildon-widgets/hildon-banner.h>
60 #include <hildon-widgets/hildon-input-mode-hint.h>
61 #include <hildon-widgets/hildon-private.h>
62 #include "hildon-composite-widget.h"
64 #define _(String) dgettext(PACKAGE, String)
66 #define HILDON_TIME_EDITOR_GET_PRIVATE(obj) \
67 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
68 HILDON_TYPE_TIME_EDITOR, HildonTimeEditorPrivate));
70 #define TICKS(h,m,s) ((h) * 3600 + (m) * 60 + (s))
72 #define TIME_EDITOR_HEIGHT 30
73 #define ICON_PRESSED 4
74 #define ICON_NAME "qgn_widg_timedit"
75 #define ICON_SIZE "timepicker-size"
76 #define MIN_DURATION 0
77 #define MAX_DURATION TICKS(99, 59, 59)
79 /* Default values for properties */
80 #define HILDON_TIME_EDITOR_TICKS_VALUE 0
81 #define HILDON_TIME_EDITOR_DURATION_MODE FALSE
82 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE 0
83 #define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE TICKS(99, 59, 59)
85 #define HOURS_MAX_24 23
86 #define HOURS_MAX_12 12
87 #define HOURS_MIN_24 0
88 #define HOURS_MIN_12 1
89 #define MINUTES_MAX 59
90 #define SECONDS_MAX 59
94 static GtkContainerClass *parent_class;
96 typedef struct _HildonTimeEditorPrivate HildonTimeEditorPrivate;
108 /* Indices for h/m/s entries in priv->entries */
117 struct _HildonTimeEditorPrivate {
118 guint ticks; /* Current duration in seconds */
123 GtkWidget *eventbox; /* hold entries */
124 GtkWidget *iconbutton; /* button for icon */
126 GtkWidget *frame; /* frame around the entries */
127 GtkWidget *entries[ENTRY_COUNT]; /* h, m, s entries */
128 GtkWidget *hm_label; /* between hour and minute */
129 GtkWidget *sec_label; /* between minute and second */
130 GtkWidget *ampm_label; /* label for showing am or pm */
132 GtkWidget *error_widget; /* field to highlight in idle */
135 gboolean duration_mode; /* In HildonDurationEditor mode */
136 gboolean show_seconds; /* show seconds */
137 gboolean show_hours; /* show hours */
139 gboolean ampm_pos_after; /* is am/pm shown after others */
140 gboolean clock_24h; /* whether to show a 24h clock */
141 gboolean am; /* TRUE == am, FALSE == pm */
143 guint duration_min; /* duration editor ranges */
144 guint duration_max; /* duration editor ranges */
146 guint highlight_idle;
153 static void hildon_time_editor_class_init (HildonTimeEditorClass *editor_class);
154 static void hildon_time_editor_init (HildonTimeEditor *editor);
156 static void hildon_time_editor_finalize (GObject *obj_self);
158 static void hildon_time_editor_set_property(GObject *object,
163 static void hildon_time_editor_get_property(GObject *object,
168 static void hildon_time_editor_forall(GtkContainer *container,
169 gboolean include_internals,
170 GtkCallback callback,
171 gpointer callback_data);
173 static void hildon_time_editor_destroy(GtkObject * self);
179 static gboolean hildon_time_editor_entry_focusout(GtkWidget *widget,
180 GdkEventFocus *event,
183 static gboolean hildon_time_editor_entry_focusin(GtkWidget *widget,
184 GdkEventFocus *event,
187 static gboolean hildon_time_editor_ampm_clicked(GtkWidget *widget,
188 GdkEventButton *event,
191 static gboolean hildon_time_editor_icon_clicked(GtkWidget *widget,
194 static gboolean hildon_time_editor_entry_clicked(GtkWidget *widget,
195 GdkEventButton *event,
198 static void hildon_time_editor_size_request(GtkWidget *widget,
199 GtkRequisition *requisition);
201 static void hildon_time_editor_size_allocate(GtkWidget *widget,
202 GtkAllocation *allocation);
204 static gboolean hildon_time_editor_entry_keypress(GtkWidget *widget,
212 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor);
215 void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
218 GtkWidgetTapAndHoldFlags flags);
220 hildon_time_editor_validate (HildonTimeEditor *editor, gboolean allow_intermediate);
222 static void hildon_time_editor_set_to_current_time (HildonTimeEditor * editor);
228 static void convert_to_12h (guint *h, gboolean *am);
229 static void convert_to_24h (guint *h, gboolean am);
231 static void ticks_to_time (guint ticks,
237 hildon_time_editor_inserted_text (GtkEditable * editable,
239 gint new_text_length,
243 GType hildon_time_editor_get_type(void)
245 static GType editor_type = 0;
248 static const GTypeInfo editor_info = {
249 sizeof(HildonTimeEditorClass),
250 NULL, /* base_init */
251 NULL, /* base_finalize */
252 (GClassInitFunc) hildon_time_editor_class_init,
253 NULL, /* class_finalize */
254 NULL, /* class_data */
255 sizeof(HildonTimeEditor),
257 (GInstanceInitFunc) hildon_time_editor_init,
259 editor_type = g_type_register_static(GTK_TYPE_CONTAINER,
266 static void hildon_time_editor_forall(GtkContainer * container,
267 gboolean include_internals,
268 GtkCallback callback,
269 gpointer callback_data)
271 HildonTimeEditor *editor;
272 HildonTimeEditorPrivate *priv;
274 g_assert(HILDON_IS_TIME_EDITOR(container));
275 g_assert(callback != NULL);
277 editor = HILDON_TIME_EDITOR(container);
278 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
280 if (!include_internals)
283 /* widget that are always shown */
284 (*callback) (priv->iconbutton, callback_data);
285 (*callback) (priv->frame, callback_data);
288 static void hildon_time_editor_destroy(GtkObject * self)
290 HildonTimeEditorPrivate *priv;
292 priv = HILDON_TIME_EDITOR_GET_PRIVATE(self);
294 if (priv->iconbutton) {
295 gtk_widget_unparent(priv->iconbutton);
296 priv->iconbutton = NULL;
299 gtk_widget_unparent(priv->frame);
303 if (GTK_OBJECT_CLASS(parent_class)->destroy)
304 GTK_OBJECT_CLASS(parent_class)->destroy(self);
309 hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
311 GObjectClass *object_class = G_OBJECT_CLASS(editor_class);
312 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(editor_class);
313 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(editor_class);
315 parent_class = g_type_class_peek_parent(editor_class);
317 g_type_class_add_private(editor_class,
318 sizeof(HildonTimeEditorPrivate));
320 object_class->get_property = hildon_time_editor_get_property;
321 object_class->set_property = hildon_time_editor_set_property;
322 widget_class->size_request = hildon_time_editor_size_request;
323 widget_class->size_allocate = hildon_time_editor_size_allocate;
324 widget_class->tap_and_hold_setup =
325 hildon_time_editor_tap_and_hold_setup;
326 widget_class->focus = hildon_composite_widget_focus;
328 container_class->forall = hildon_time_editor_forall;
329 GTK_OBJECT_CLASS(editor_class)->destroy = hildon_time_editor_destroy;
331 object_class->finalize = hildon_time_editor_finalize;
334 * HildonTimeEditor:ticks:
336 * If editor is in duration mode, contains the duration seconds.
337 * If not, contains seconds since midnight.
339 g_object_class_install_property( object_class, PROP_TICKS,
340 g_param_spec_uint("ticks",
342 "Current value of duration",
344 HILDON_TIME_EDITOR_TICKS_VALUE,
345 G_PARAM_READABLE | G_PARAM_WRITABLE) );
348 * HildonTimeEditor:show_seconds:
350 * Controls whether seconds are shown in the editor
352 g_object_class_install_property( object_class, PROP_SHOW_SECONDS,
353 g_param_spec_boolean("show_seconds",
354 "Show seconds property",
355 "Controls whether the seconds are shown in the editor",
357 G_PARAM_READABLE | G_PARAM_WRITABLE) );
360 * HildonTimeEditor:show_hours:
362 * Controls whether hours are shown in the editor
364 g_object_class_install_property( object_class, PROP_SHOW_HOURS,
365 g_param_spec_boolean("show_hours",
367 "Controls whether the hours field is shown in the editor",
369 G_PARAM_READABLE | G_PARAM_WRITABLE) );
372 * HildonTimeEditor:duration_mode:
374 * Controls whether the TimeEditor is in duration mode
376 g_object_class_install_property( object_class, PROP_DURATION_MODE,
377 g_param_spec_boolean("duration_mode",
379 "Controls whether the TimeEditor is in duration mode",
380 HILDON_TIME_EDITOR_DURATION_MODE,
381 G_PARAM_READABLE | G_PARAM_WRITABLE) );
384 * HildonTimeEditor:duration_min:
386 * Minimum allowed duration value.
388 g_object_class_install_property( object_class, PROP_DURATION_MIN,
389 g_param_spec_uint("duration_min",
390 "Minumum duration value",
391 "Smallest possible duration value",
392 MIN_DURATION, MAX_DURATION,
393 HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
394 G_PARAM_READABLE | G_PARAM_WRITABLE) );
397 * HildonTimeEditor:duration_max:
399 * Maximum allowed duration value.
401 g_object_class_install_property( object_class, PROP_DURATION_MAX,
402 g_param_spec_uint("duration_max",
403 "Maximum duration value",
404 "Largest possible duration value",
406 HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
407 G_PARAM_READABLE | G_PARAM_WRITABLE) );
411 void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
414 GtkWidgetTapAndHoldFlags flags)
416 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
419 /* Forward this tap_and_hold_setup signal to all our child widgets */
420 for (i = 0; i < ENTRY_COUNT; i++)
422 gtk_widget_tap_and_hold_setup(priv->entries[i], menu, func,
423 GTK_TAP_AND_HOLD_NO_SIGNALS);
425 gtk_widget_tap_and_hold_setup(priv->eventbox, menu, func,
426 GTK_TAP_AND_HOLD_NO_SIGNALS);
427 gtk_widget_tap_and_hold_setup(priv->iconbutton, menu, func,
428 GTK_TAP_AND_HOLD_NONE);
431 static void hildon_time_editor_entry_changed(GtkWidget *widget, gpointer data)
433 g_assert(HILDON_IS_TIME_EDITOR(data));
434 hildon_time_editor_validate(HILDON_TIME_EDITOR(data), TRUE);
437 static void hildon_time_editor_init(HildonTimeEditor * editor)
439 HildonTimeEditorPrivate *priv;
440 GtkWidget *hbox, *icon;
443 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
445 gtk_widget_push_composite_child();
447 /* Setup defaults and create widgets */
449 priv->show_seconds = FALSE;
450 priv->show_hours = TRUE;
451 priv->ampm_pos_after = TRUE;
452 priv->clock_24h = TRUE;
453 priv->duration_mode = FALSE;
454 priv->iconbutton = gtk_button_new();
455 priv->ampm_label = gtk_label_new(NULL);
456 priv->hm_label = gtk_label_new(NULL);
457 priv->sec_label = gtk_label_new(NULL);
458 priv->frame = gtk_frame_new(NULL);
459 priv->eventbox = gtk_event_box_new();
461 icon = gtk_image_new_from_icon_name(ICON_NAME, HILDON_ICON_SIZE_WIDG);
462 hbox = gtk_hbox_new(FALSE, 0);
464 GTK_WIDGET_SET_FLAGS(editor, GTK_NO_WINDOW);
465 GTK_WIDGET_UNSET_FLAGS(priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
467 gtk_event_box_set_visible_window(GTK_EVENT_BOX(priv->eventbox), FALSE);
469 gtk_container_set_border_width(GTK_CONTAINER(priv->frame), 0);
471 gtk_container_add(GTK_CONTAINER(priv->iconbutton), icon);
472 gtk_container_add(GTK_CONTAINER(priv->eventbox), priv->ampm_label);
474 /* Create hour, minute and second entries */
475 for (i = 0; i < ENTRY_COUNT; i++)
477 priv->entries[i] = gtk_entry_new();
479 /* No frames for entries, so that they all appear to be inside one long entry */
480 gtk_entry_set_has_frame(GTK_ENTRY(priv->entries[i]), FALSE);
482 /* Set the entries to accept only numeric characters */
483 g_object_set (priv->entries[i], "input-mode",
484 HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
486 /* The entry fields all take exactly two characters */
487 gtk_entry_set_max_length (GTK_ENTRY(priv->entries[i]), 2);
488 gtk_entry_set_width_chars (GTK_ENTRY(priv->entries[i]), 2);
490 /* Connect signals */
491 g_signal_connect(priv->entries[i], "button-release-event",
492 G_CALLBACK(hildon_time_editor_entry_clicked), editor);
493 g_signal_connect(priv->entries[i], "focus-in-event",
494 G_CALLBACK(hildon_time_editor_entry_focusin), editor);
495 g_signal_connect(priv->entries[i], "focus-out-event",
496 G_CALLBACK(hildon_time_editor_entry_focusout), editor);
497 g_signal_connect(priv->entries[i], "key-press-event",
498 G_CALLBACK(hildon_time_editor_entry_keypress), editor);
499 g_signal_connect(priv->entries[i], "changed",
500 G_CALLBACK(hildon_time_editor_entry_changed), editor);
502 /* inserted signal sets time */
503 g_signal_connect_after (G_OBJECT(priv->entries[i]), "insert_text",
504 G_CALLBACK (hildon_time_editor_inserted_text),
508 /* clicked signal for am/pm label */
509 g_signal_connect(G_OBJECT(priv->eventbox), "button_press_event",
510 G_CALLBACK(hildon_time_editor_ampm_clicked), editor);
512 /* clicked signal for icon */
513 g_signal_connect(G_OBJECT(priv->iconbutton), "clicked",
514 G_CALLBACK(hildon_time_editor_icon_clicked), editor);
516 /* Set ourself as the parent of all the widgets we created */
517 gtk_widget_set_parent(priv->iconbutton, GTK_WIDGET(editor));
518 gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_HOURS], FALSE, FALSE, 0);
519 gtk_box_pack_start(GTK_BOX(hbox), priv->hm_label, FALSE, FALSE, 0);
520 gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_MINS], FALSE, FALSE, 0);
521 gtk_box_pack_start(GTK_BOX(hbox), priv->sec_label, FALSE, FALSE, 0);
522 gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_SECS], FALSE, FALSE, 0);
523 gtk_box_pack_start(GTK_BOX(hbox), priv->eventbox, FALSE, FALSE, 0);
525 gtk_container_add(GTK_CONTAINER(priv->frame), hbox);
527 /* Show created widgets */
528 gtk_widget_set_parent(priv->frame, GTK_WIDGET(editor));
529 gtk_widget_show_all(priv->frame);
530 gtk_widget_show_all(priv->iconbutton);
532 /* Update AM/PM and time separators settings from locale */
533 if (!hildon_time_editor_check_locale(editor)) {
534 /* Using 12h clock */
535 priv->clock_24h = FALSE;
537 gtk_widget_hide(priv->eventbox);
540 if (!priv->show_seconds) {
541 gtk_widget_hide(priv->sec_label);
542 gtk_widget_hide(priv->entries[ENTRY_SECS]);
545 /* set the default time to current time. */
546 hildon_time_editor_set_to_current_time (editor);
548 gtk_widget_pop_composite_child();
551 static void hildon_time_editor_set_property (GObject *object,
556 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR(object);
560 hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
563 case PROP_SHOW_SECONDS:
564 hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
567 case PROP_SHOW_HOURS:
568 hildon_time_editor_set_show_hours (time_editor, g_value_get_boolean(value));
571 case PROP_DURATION_MODE:
572 hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
575 case PROP_DURATION_MIN:
576 hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
579 case PROP_DURATION_MAX:
580 hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
584 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
589 static void hildon_time_editor_get_property (GObject *object,
594 HildonTimeEditor *time_editor = HILDON_TIME_EDITOR(object);
599 g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
602 case PROP_SHOW_SECONDS:
603 g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
606 case PROP_SHOW_HOURS:
607 g_value_set_boolean (value, hildon_time_editor_get_show_hours (time_editor));
610 case PROP_DURATION_MODE:
611 g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
614 case PROP_DURATION_MIN:
615 g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
618 case PROP_DURATION_MAX:
619 g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
623 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
629 * hildon_time_editor_new:
631 * This function creates a new time editor.
633 * Returns: pointer to a new #HildonTimeEditor widget
636 GtkWidget *hildon_time_editor_new(void)
638 return GTK_WIDGET(g_object_new(HILDON_TYPE_TIME_EDITOR, NULL));
641 static void hildon_time_editor_finalize(GObject * obj_self)
643 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(obj_self);
645 g_free(priv->am_symbol);
646 g_free(priv->pm_symbol);
648 if (priv->highlight_idle)
649 g_source_remove(priv->highlight_idle);
651 if (G_OBJECT_CLASS(parent_class)->finalize)
652 G_OBJECT_CLASS(parent_class)->finalize(obj_self);
656 * _hildon_time_editor_get_time_separators:
657 * @editor: the #HildonTimeEditor
658 * @hm_sep_label: the label that will show the hour:minutes separator
659 * @ms_sep_label: the label that will show the minutes:seconds separator
661 * Gets hour-minute separator and minute-second separator from current
662 * locale and sets then to the labels we set as parameters. Both
663 * parameters can be NULL if you just want to assing one separator.
667 _hildon_time_editor_get_time_separators(GtkLabel *hm_sep_label,
668 GtkLabel *ms_sep_label)
672 GDate locale_test_date;
675 /* Get localized time string */
676 g_date_set_dmy(&locale_test_date, 1, 2, 1970);
677 (void) g_date_strftime(buffer, sizeof(buffer), "%X", &locale_test_date);
679 if (hm_sep_label != NULL)
681 /* Find h-m separator */
683 while (*iter && g_ascii_isdigit(*iter)) iter++;
685 /* Extract h-m separator*/
687 while (*endp && !g_ascii_isdigit(*endp)) endp++;
688 separator = g_strndup(iter, endp - iter);
689 gtk_label_set_label(hm_sep_label, separator);
693 if (ms_sep_label != NULL)
695 /* Find m-s separator */
697 while (*iter && g_ascii_isdigit(*iter)) iter++;
699 /* Extract m-s separator*/
701 while (*endp && !g_ascii_isdigit(*endp)) endp++;
702 separator = g_strndup(iter, endp - iter);
703 gtk_label_set_label(ms_sep_label, separator);
709 /* Convert ticks to H:M:S. Ticks = seconds since 00:00:00. */
710 static void ticks_to_time (guint ticks,
717 *hours = ticks / 3600;
719 *minutes = left / 60;
720 *seconds = left % 60;
724 * hildon_time_editor_set_ticks:
725 * @editor: the #HildonTimeEditor widget
726 * @ticks: the duration to set, in seconds
728 * Sets the current duration in seconds. This means seconds from
729 * midnight, if not in duration mode. In case of any errors, it tries
733 void hildon_time_editor_set_ticks (HildonTimeEditor * editor,
736 HildonTimeEditorPrivate *priv;
740 g_assert(HILDON_IS_TIME_EDITOR(editor));
742 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
744 /* Validate ticks. If it's too low or too high, set it to
745 min/max value for the current mode. */
746 if (priv->duration_mode)
747 priv->ticks = CLAMP(ticks, priv->duration_min, priv->duration_max);
749 /* Check that ticks value is valid. We only need to check that hours
751 ticks_to_time (ticks, &h, &m, &s);
752 if (h > HOURS_MAX_24)
753 ticks = TICKS(HOURS_MAX_24, m, s);
758 /* Get the time in H:M:S. */
759 ticks_to_time (priv->ticks, &h, &m, &s);
761 if (!priv->clock_24h && !priv->duration_mode)
763 /* Convert 24h H:M:S values to 12h mode, and update AM/PM state */
764 convert_to_12h (&h, &priv->am);
767 /* Set H:M:S values to entries. We do not want to invoke validation
768 callbacks (since they can cause new call to this function), so we
769 block signals while setting values. */
770 for (i = 0; i < ENTRY_COUNT; i++)
772 g_signal_handlers_block_by_func(priv->entries[i],
773 (gpointer) hildon_time_editor_entry_changed, editor);
776 g_snprintf(str, sizeof(str), "%02u", h);
777 gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_HOURS]), str);
779 g_snprintf(str, sizeof(str), "%02u", m);
780 gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_MINS]), str);
782 g_snprintf(str, sizeof(str), "%02u", s);
783 gtk_entry_set_text(GTK_ENTRY(priv->entries[ENTRY_SECS]), str);
785 for (i = 0; i < ENTRY_COUNT; i++)
787 g_signal_handlers_unblock_by_func(priv->entries[i],
788 (gpointer) hildon_time_editor_entry_changed, editor);
791 /* Update AM/PM label in case we're in 12h mode */
792 gtk_label_set_label(GTK_LABEL(priv->ampm_label),
793 priv->am ? priv->am_symbol : priv->pm_symbol);
795 g_object_notify (G_OBJECT (editor), "ticks");
799 hildon_time_editor_set_to_current_time (HildonTimeEditor * editor)
805 tm = localtime(&now);
808 hildon_time_editor_set_time(editor, tm->tm_hour, tm->tm_min, tm->tm_sec);
812 * hildon_time_editor_get_ticks:
813 * @editor: the #HildonTimeEditor widget
815 * This function returns the current duration, in seconds.
816 * This means seconds from midnight, if not in duration mode.
818 * Returns: current duration in seconds
821 guint hildon_time_editor_get_ticks (HildonTimeEditor * editor)
823 HildonTimeEditorPrivate *priv;
825 g_return_val_if_fail(editor, 0);
826 g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
828 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
830 return (priv->ticks);
834 * hildon_time_editor_set_show_seconds:
835 * @editor: the #HildonTimeEditor
836 * @show_seconds: enable or disable showing of seconds
838 * This function shows or hides the seconds field.
841 void hildon_time_editor_set_show_seconds (HildonTimeEditor * editor,
842 gboolean show_seconds)
844 HildonTimeEditorPrivate *priv;
846 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
848 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
850 if (show_seconds != priv->show_seconds) {
851 priv->show_seconds = show_seconds;
853 /* show/hide seconds field and its ':' label if the value changed. */
855 gtk_widget_show(priv->entries[ENTRY_SECS]);
856 gtk_widget_show(priv->sec_label);
858 gtk_widget_hide(priv->entries[ENTRY_SECS]);
859 gtk_widget_hide(priv->sec_label);
862 g_object_notify (G_OBJECT (editor), "show_seconds");
867 * hildon_time_editor_get_show_seconds:
868 * @editor: the #HildonTimeEditor widget
870 * This function returns a boolean indicating the visibility of
871 * seconds in the #HildonTimeEditor
873 * Returns: TRUE if the seconds are visible
876 gboolean hildon_time_editor_get_show_seconds (HildonTimeEditor * editor)
878 HildonTimeEditorPrivate *priv;
880 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
881 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
883 return (priv->show_seconds);
887 * hildon_time_editor_set_duration_mode:
888 * @editor: the #HildonTimeEditor
889 * @duration_mode: enable or disable duration editor mode
891 * This function sets the duration editor mode in which the maximum hours
895 void hildon_time_editor_set_duration_mode (HildonTimeEditor * editor,
896 gboolean duration_mode)
898 HildonTimeEditorPrivate *priv;
900 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
902 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
904 if (duration_mode != priv->duration_mode) {
905 priv->duration_mode = duration_mode;
908 /* FIXME: Why do we reset the duration range here?
909 Would change API, so won't touch this for now. */
910 hildon_time_editor_set_duration_range(editor, MIN_DURATION,
912 /* There's no AM/PM label or time picker icon in duration mode.
913 Make sure they're hidden. */
914 gtk_widget_hide(GTK_WIDGET(priv->ampm_label));
915 gtk_widget_hide(GTK_WIDGET(priv->eventbox));
916 gtk_widget_hide(GTK_WIDGET(priv->iconbutton));
917 /* Duration mode has seconds by default. */
918 hildon_time_editor_set_show_seconds(editor, TRUE);
920 /* Make sure AM/PM label and time picker icons are visible if needed */
921 if (!priv->clock_24h)
922 gtk_widget_show(GTK_WIDGET(priv->ampm_label));
924 gtk_widget_show(GTK_WIDGET(priv->eventbox));
925 gtk_widget_show(GTK_WIDGET(priv->iconbutton));
927 /* Reset the ticks to current time. Anything set in duration mode
928 * is bound to be invalid or useless in time mode.
930 hildon_time_editor_set_to_current_time (editor);
933 g_object_notify (G_OBJECT (editor), "duration_mode");
938 * hildon_time_editor_get_duration_mode:
939 * @editor: the #HildonTimeEditor widget
941 * This function returns a boolean indicating whether the #HildonTimeEditor
942 * is in the duration mode.
944 * Returns: TRUE if the #HildonTimeEditor is in duration mode
947 gboolean hildon_time_editor_get_duration_mode (HildonTimeEditor * editor)
949 HildonTimeEditorPrivate *priv;
951 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
952 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
954 return (priv->duration_mode);
958 * hildon_time_editor_set_duration_min:
959 * @editor: the #HildonTimeEditor widget
960 * @duration_min: mimimum allowed duration
962 * Sets the minimum allowed duration for the duration mode.
963 * Note: Has no effect in time mode
966 void hildon_time_editor_set_duration_min (HildonTimeEditor * editor,
969 HildonTimeEditorPrivate *priv;
971 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
972 g_return_if_fail(duration_min >= MIN_DURATION);
974 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
976 if( !priv->duration_mode )
979 priv->duration_min = duration_min;
981 /* Clamp the current value to the minimum if necessary */
982 if (priv->ticks < duration_min)
984 hildon_time_editor_set_ticks (editor, duration_min);
987 g_object_notify (G_OBJECT (editor), "duration_min");
991 * hildon_time_editor_get_duration_min:
992 * @editor: the #HildonTimeEditor widget
994 * This function returns the smallest duration the #HildonTimeEditor
995 * allows in the duration mode.
997 * Returns: minimum allowed duration in seconds
1000 guint hildon_time_editor_get_duration_min (HildonTimeEditor * editor)
1002 HildonTimeEditorPrivate *priv;
1004 g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
1006 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1008 if( !priv->duration_mode )
1011 return (priv->duration_min);
1015 * hildon_time_editor_set_duration_max:
1016 * @editor: the #HildonTimeEditor widget
1017 * @duration_max: maximum allowed duration in seconds
1019 * Sets the maximum allowed duration in seconds for the duration mode.
1020 * Note: Has no effect in time mode
1023 void hildon_time_editor_set_duration_max (HildonTimeEditor * editor,
1026 HildonTimeEditorPrivate *priv;
1028 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1029 g_return_if_fail(duration_max <= MAX_DURATION);
1031 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1033 if( !priv->duration_mode )
1036 priv->duration_max = duration_max;
1038 /* Clamp the current value to the maximum if necessary */
1039 if (priv->ticks > duration_max)
1041 hildon_time_editor_set_ticks (editor, duration_max);
1044 g_object_notify (G_OBJECT (editor), "duration_max");
1048 * hildon_time_editor_get_duration_max:
1049 * @editor: the #HildonTimeEditor widget
1051 * This function returns the longest duration the #HildonTimeEditor
1052 * allows in the duration mode.
1054 * Returns: maximum allowed duration in seconds
1057 guint hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1059 HildonTimeEditorPrivate *priv;
1061 g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
1063 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1065 if( !priv->duration_mode )
1068 return (priv->duration_max);
1073 * hildon_time_editor_set_time:
1074 * @editor: the #HildonTimeEditor widget
1079 * This function sets the time on an existing time editor. If the
1080 * time specified by the arguments is invalid, it's fixed.
1081 * The time is assumed to be in 24h format.
1084 void hildon_time_editor_set_time(HildonTimeEditor * editor, guint hours,
1085 guint minutes, guint seconds)
1087 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1089 hildon_time_editor_set_ticks (editor, TICKS(hours, minutes, seconds));
1093 * hildon_time_editor_get_time:
1094 * @editor: the #HildonTimeEditor widget
1099 * Gets the time of the #HildonTimeEditor widget. The time returned is
1100 * always in 24h format.
1103 void hildon_time_editor_get_time(HildonTimeEditor * editor,
1105 guint * minutes, guint * seconds)
1107 HildonTimeEditorPrivate *priv;
1109 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1111 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1113 ticks_to_time (hildon_time_editor_get_ticks (editor),
1114 hours, minutes, seconds);
1118 * hildon_time_editor_set_duration_range:
1119 * @editor: the #HildonTimeEditor widget
1120 * @min_seconds: minimum allowed time in seconds
1121 * @max_seconds: maximum allowed time in seconds
1123 * Sets the duration editor time range of the #HildonTimeEditor widget.
1126 void hildon_time_editor_set_duration_range(HildonTimeEditor * editor,
1130 HildonTimeEditorPrivate *priv;
1133 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1135 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1136 /* Swap values if reversed */
1137 if (min_seconds > max_seconds)
1140 max_seconds = min_seconds;
1144 hildon_time_editor_set_duration_max (editor, max_seconds);
1145 hildon_time_editor_set_duration_min (editor, min_seconds);
1147 if (priv->duration_mode) {
1148 /* Set minimum allowed value for duration editor.
1149 FIXME: Shouldn't it be changed only if it's not in range?
1150 Would change API, so won't touch this for now. */
1151 hildon_time_editor_set_ticks(editor, min_seconds);
1156 * hildon_time_editor_get_duration_range:
1157 * @editor: the #HildonTimeEditor widget
1158 * @min_seconds: pointer to guint
1159 * @max_seconds: pointer to guint
1161 * Gets the duration editor time range of the #HildonTimeEditor widget.
1164 void hildon_time_editor_get_duration_range(HildonTimeEditor * editor,
1165 guint * min_seconds,
1166 guint * max_seconds)
1168 HildonTimeEditorPrivate *priv;
1170 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1172 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1174 *min_seconds = priv->duration_min;
1175 *max_seconds = priv->duration_max;
1178 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor)
1180 HildonTimeEditorPrivate *priv;
1182 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1184 /* Update time separator symbols */
1185 _hildon_time_editor_get_time_separators(GTK_LABEL(priv->hm_label), GTK_LABEL(priv->sec_label));
1187 /* Get AM/PM symbols. */
1188 priv->am_symbol = g_strdup(nl_langinfo(AM_STR));
1189 priv->pm_symbol = g_strdup(nl_langinfo(PM_STR));
1191 if (priv->am_symbol[0] == '\0')
1194 /* 12h clock mode. Check if AM/PM should be before or after time.
1195 %p is the AM/PM string, so we assume that if the format string
1196 begins with %p it's in the beginning, and in any other case it's
1197 in the end (although that's not necessarily the case). */
1198 if (strncmp(nl_langinfo(T_FMT_AMPM), "%p", 2) == 0)
1199 priv->ampm_pos_after = FALSE;
1204 static gboolean hildon_time_editor_entry_focusin(GtkWidget * widget,
1205 GdkEventFocus * event,
1208 /* If we were trying to move away from a field with invalid value,
1209 we get moved back to it. Here we want to select the text in the field.
1210 The !button check checks that the entry wasn't focused with a mouse
1213 The selection happens temporarily if we got here with left/right
1214 keys, but it gets immediately unselected within same call due to some
1215 inner entry/clipboard magic. */
1216 if (!GTK_ENTRY(widget)->button)
1217 gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
1222 /* Returns negative if we didn't get value,
1223 * and should stop further validation
1225 static gint validated_conversion(HildonTimeEditorPrivate *priv,
1229 gboolean allow_intermediate,
1230 GString *error_string)
1236 text = gtk_entry_get_text(GTK_ENTRY(field));
1238 if (text && text[0])
1240 /* Try to convert entry text to number */
1241 value = strtol(text, &tail, 10);
1243 /* Check if conversion succeeded */
1247 g_string_printf(error_string, _("ckct_ib_maximum_value"), max);
1248 priv->error_widget = field;
1251 if (value < min && !allow_intermediate) {
1252 g_string_printf(error_string, _("ckct_ib_minimum_value"), min);
1253 priv->error_widget = field;
1259 /* We'll handle failed conversions soon */
1261 else if (allow_intermediate)
1262 return -1; /* Empty field while user is still editing. No error, but
1263 cannot validate either... */
1265 /* Empty field and not allowed intermediated OR failed conversion */
1266 g_string_printf(error_string, _("ckct_ib_set_a_value_within_range"), min, max);
1267 priv->error_widget = field;
1272 hildon_time_editor_real_validate(HildonTimeEditor *editor,
1273 gboolean allow_intermediate, GString *error_string)
1275 HildonTimeEditorPrivate *priv;
1276 guint h, m, s, ticks;
1277 guint max_hours, min_hours, max_minutes, min_minutes, max_seconds, min_seconds;
1279 g_assert(HILDON_IS_TIME_EDITOR(editor));
1281 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1283 /* Find limits for field based validation. */
1284 if (priv->duration_mode)
1286 ticks_to_time(priv->duration_min, &min_hours, &min_minutes, &min_seconds);
1287 ticks_to_time(priv->duration_max, &max_hours, &max_minutes, &max_seconds);
1289 if (priv->clock_24h) {
1290 max_hours = HOURS_MAX_24;
1291 min_hours = HOURS_MIN_24;
1293 max_hours = HOURS_MAX_12;
1294 min_hours = HOURS_MIN_12;
1298 /* Get time components from fields and validate them... */
1299 if (priv->show_hours) {
1300 h = validated_conversion(priv, priv->entries[ENTRY_HOURS], min_hours, max_hours,
1301 allow_intermediate, error_string);
1302 if ((gint) h < 0) return;
1305 m = validated_conversion(priv, priv->entries[ENTRY_MINS], MINUTES_MIN, MINUTES_MAX,
1306 allow_intermediate, error_string);
1307 if ((gint) m < 0) return;
1308 if (priv->show_seconds) {
1309 s = validated_conversion(priv, priv->entries[ENTRY_SECS], SECONDS_MIN, SECONDS_MAX,
1310 allow_intermediate, error_string);
1311 if ((gint) s < 0) return;
1315 /* Ok, we now do separate check that tick count is valid for duration mode */
1316 if (priv->duration_mode)
1318 ticks = TICKS(h, m, s);
1320 if (ticks < priv->duration_min && !allow_intermediate)
1322 g_string_printf(error_string,
1323 _("ckct_ib_min_allowed_duration_hts"),
1324 min_hours, min_minutes, min_seconds);
1325 hildon_time_editor_set_ticks (editor, priv->duration_min);
1326 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1329 else if (ticks > priv->duration_max)
1331 g_string_printf(error_string,
1332 _("ckct_ib_max_allowed_duration_hts"),
1333 max_hours, max_minutes, max_seconds);
1334 hildon_time_editor_set_ticks (editor, priv->duration_max);
1335 priv->error_widget = priv->show_hours ? priv->entries[ENTRY_HOURS] : priv->entries[ENTRY_MINS];
1339 else if (!priv->clock_24h)
1340 convert_to_24h (&h, priv->am);
1342 /* The only case when we do not want to refresh the
1343 time display, is when the user is editing a value
1344 (unless the value was out of bounds and we have to fix it) */
1345 if (!allow_intermediate || priv->error_widget)
1346 hildon_time_editor_set_time (editor, h, m, s);
1349 /* Setting text to entries causes entry to recompute itself
1350 in idle callback, which remove selection. Because of this
1351 we need to do selection in idle as well. */
1352 static gboolean highlight_callback(gpointer data)
1354 HildonTimeEditorPrivate *priv;
1357 GDK_THREADS_ENTER ();
1359 g_assert(HILDON_IS_TIME_EDITOR(data));
1361 priv = HILDON_TIME_EDITOR_GET_PRIVATE(data);
1362 widget = priv->error_widget;
1363 priv->error_widget = NULL;
1364 priv->highlight_idle = 0;
1366 g_assert(GTK_IS_ENTRY(widget));
1368 /* Grabbing focus can cause re-validation, priv->error widget
1369 can be set to something else, including NULL */
1370 gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
1371 gtk_widget_grab_focus(widget);
1373 GDK_THREADS_LEAVE ();
1378 /* Update ticks from current H:M:S entries. If they're invalid, show an
1379 infoprint and update the fields unless they're empty. */
1381 hildon_time_editor_validate (HildonTimeEditor *editor, gboolean allow_intermediate)
1383 HildonTimeEditorPrivate *priv;
1384 GString *error_message;
1386 g_assert(HILDON_IS_TIME_EDITOR(editor));
1388 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1389 priv->error_widget = NULL;
1391 error_message = g_string_new(NULL);
1392 hildon_time_editor_real_validate(editor,
1393 allow_intermediate, error_message);
1395 if (priv->error_widget) {
1396 hildon_banner_show_information(priv->error_widget, NULL,
1397 error_message->str);
1398 if (priv->highlight_idle == 0)
1399 priv->highlight_idle = g_idle_add(highlight_callback, editor);
1401 g_string_free(error_message, TRUE);
1404 /* on inserted text, if entry has two digits, jumps to the next field. */
1406 hildon_time_editor_inserted_text (GtkEditable * editable,
1408 gint new_text_length,
1412 HildonTimeEditor *editor;
1416 entry = GTK_ENTRY(editable);
1417 editor = HILDON_TIME_EDITOR(user_data);
1419 value = (gchar *) gtk_entry_get_text(entry);
1421 if (strlen(value) == 2)
1423 HildonTimeEditorPrivate *priv;
1425 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1427 if (GTK_WIDGET(editable) == priv->entries[ENTRY_HOURS])
1429 gtk_widget_grab_focus(priv->entries[ENTRY_MINS]);
1432 else if (GTK_WIDGET(editable) == priv->entries[ENTRY_MINS])
1434 gtk_widget_grab_focus(priv->entries[ENTRY_SECS]);
1440 static gboolean hildon_time_editor_entry_focusout(GtkWidget * widget,
1441 GdkEventFocus * event,
1444 g_assert(HILDON_IS_TIME_EDITOR(data));
1446 /* Validate the given time and update ticks. */
1447 hildon_time_editor_validate(HILDON_TIME_EDITOR(data), FALSE);
1453 hildon_time_editor_ampm_clicked(GtkWidget * widget,
1454 GdkEventButton * event, gpointer data)
1456 HildonTimeEditor *editor;
1457 HildonTimeEditorPrivate *priv;
1459 g_assert(GTK_IS_WIDGET(widget));
1460 g_assert(HILDON_IS_TIME_EDITOR(data));
1462 editor = HILDON_TIME_EDITOR(data);
1463 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1465 /* First validate the given time and update ticks. */
1466 hildon_time_editor_validate (editor, FALSE);
1468 /* Apply the AM/PM change by moving the current time by 12 hours */
1470 /* 00:00 .. 11:59 -> 12:00 .. 23:59 */
1471 hildon_time_editor_set_ticks (editor, priv->ticks + 12*3600);
1473 /* 12:00 .. 23:59 -> 00:00 .. 11:59 */
1474 hildon_time_editor_set_ticks (editor, priv->ticks - 12*3600);
1480 hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
1482 HildonTimeEditor *editor;
1485 guint h, m, s, result;
1487 g_assert(HILDON_IS_TIME_EDITOR(data));
1489 editor = HILDON_TIME_EDITOR(data);
1491 /* icon is passive in duration editor mode */
1492 if (hildon_time_editor_get_duration_mode(editor))
1495 /* Launch HildonTimePicker dialog */
1496 parent = gtk_widget_get_ancestor(GTK_WIDGET(editor), GTK_TYPE_WINDOW);
1497 picker = hildon_time_picker_new(GTK_WINDOW(parent));
1499 hildon_time_editor_get_time(editor, &h, &m, &s);
1500 hildon_time_picker_set_time(HILDON_TIME_PICKER(picker), h, m);
1502 result = gtk_dialog_run(GTK_DIALOG(picker));
1504 case GTK_RESPONSE_OK:
1505 case GTK_RESPONSE_ACCEPT:
1506 /* Use the selected time */
1507 hildon_time_picker_get_time(HILDON_TIME_PICKER(picker), &h, &m);
1508 hildon_time_editor_set_time(editor, h, m, 0);
1514 gtk_widget_destroy(picker);
1518 static gboolean hildon_time_editor_entry_clicked(GtkWidget * widget,
1519 GdkEventButton * event,
1522 HildonTimeEditor *editor;
1523 HildonTimeEditorPrivate *priv;
1525 editor = HILDON_TIME_EDITOR (data);
1526 priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1528 /* If the focus has been grabbed back before the "clicked"
1529 * signal gets processed, don't highlight the text.
1530 * This happens when input in one H:M:S field is invalid and we're
1531 * trying to move to another field. The focus moves back to the invalid
1534 if (gtk_widget_is_focus (widget))
1535 gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
1540 static void hildon_time_editor_size_request(GtkWidget * widget,
1541 GtkRequisition * requisition)
1543 HildonTimeEditor *editor;
1544 HildonTimeEditorPrivate *priv;
1547 editor = HILDON_TIME_EDITOR(widget);
1548 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1550 /* Get frame's size */
1551 gtk_widget_size_request(priv->frame, requisition);
1553 if (GTK_WIDGET_VISIBLE(priv->iconbutton))
1555 gtk_widget_size_request(priv->iconbutton, &req);
1556 /* Reserve space for icon */
1557 requisition->width += req.width + ICON_PRESSED +
1558 HILDON_MARGIN_DEFAULT;
1561 /* FIXME: It's evil to use hardcoded TIME_EDITOR_HEIGHT. For now we'll
1562 want to force this since themes might have varying thickness values
1563 which cause the height to change. */
1564 requisition->height = TIME_EDITOR_HEIGHT;
1567 static void hildon_time_editor_size_allocate(GtkWidget * widget,
1568 GtkAllocation * allocation)
1570 HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
1571 GtkAllocation alloc;
1572 GtkRequisition req, max_req;
1574 widget->allocation = *allocation;
1575 gtk_widget_get_child_requisition(widget, &max_req);
1577 /* Center horizontally */
1578 alloc.x = allocation->x + MAX(allocation->width - max_req.width, 0) / 2;
1579 /* Center vertically */
1580 alloc.y = allocation->y + MAX(allocation->height - max_req.height, 0) / 2;
1582 /* allocate frame */
1583 gtk_widget_get_child_requisition(priv->frame, &req);
1585 alloc.width = req.width;
1586 alloc.height = max_req.height;
1587 gtk_widget_size_allocate(priv->frame, &alloc);
1590 if (GTK_WIDGET_VISIBLE(priv->iconbutton)) {
1591 gtk_widget_get_child_requisition(priv->iconbutton, &req);
1593 alloc.x += alloc.width + HILDON_MARGIN_DEFAULT;
1594 alloc.width = req.width;
1595 gtk_widget_size_allocate(priv->iconbutton, &alloc);
1598 /* FIXME: ugly way to move labels up. They just don't seem move up
1599 otherwise. This is likely because we force the editor to be
1600 smaller than it otherwise would be. */
1601 alloc = priv->ampm_label->allocation;
1602 alloc.y = allocation->y - 2;
1603 alloc.height = max_req.height + 2;
1604 gtk_widget_size_allocate(priv->ampm_label, &alloc);
1606 alloc = priv->hm_label->allocation;
1607 alloc.y = allocation->y - 2;
1608 alloc.height = max_req.height + 2;
1609 gtk_widget_size_allocate(priv->hm_label, &alloc);
1611 alloc = priv->sec_label->allocation;
1612 alloc.y = allocation->y - 2;
1613 alloc.height = max_req.height + 2;
1614 gtk_widget_size_allocate(priv->sec_label, &alloc);
1617 static gboolean hildon_time_editor_entry_keypress(GtkWidget * widget,
1618 GdkEventKey * event,
1621 HildonTimeEditor *editor;
1622 HildonTimeEditorPrivate *priv;
1625 g_assert(GTK_IS_ENTRY(widget));
1626 g_assert(event != NULL);
1627 g_assert(HILDON_IS_TIME_EDITOR(data));
1629 editor = HILDON_TIME_EDITOR(data);
1630 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1631 cursor_pos = gtk_editable_get_position(GTK_EDITABLE(widget));
1633 switch (event->keyval)
1636 /* Return key popups up time picker dialog. Visually it looks as if
1637 the time picker icon was clicked. Before opening the time picker
1638 the fields are first validated and fixed. */
1639 hildon_time_editor_validate (editor, FALSE);
1640 hildon_gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), TRUE);
1641 hildon_time_editor_icon_clicked(widget, data);
1642 hildon_gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), FALSE);
1646 /* left arrow pressed in the entry. If we are on first position, try to
1647 move to the previous field. */
1648 if (cursor_pos == 0) {
1649 (void) gtk_widget_child_focus(GTK_WIDGET(editor), GTK_DIR_LEFT);
1655 /* right arrow pressed in the entry. If we are on last position, try to
1656 move to the next field. */
1657 if (cursor_pos >= g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(widget)), -1)) {
1658 (void) gtk_widget_child_focus(GTK_WIDGET(editor), GTK_DIR_RIGHT);
1675 convert_to_12h (guint *h, gboolean *am)
1677 g_assert(0 <= *h && *h < 24);
1679 /* 00:00 to 00:59 add 12 hours */
1680 /* 01:00 to 11:59 straight to am */
1681 /* 12:00 to 12:59 straight to pm */
1682 /* 13:00 to 23:59 subtract 12 hours */
1684 if ( *h == 0 ) { *am = TRUE; *h += 12;}
1685 else if ( 1 <= *h && *h < 12 ) { *am = TRUE; }
1686 else if ( 12 <= *h && *h < 13 ) { *am = FALSE; }
1687 else { *am = FALSE; *h -= 12;}
1691 convert_to_24h (guint *h, gboolean am)
1693 if (*h == 12 && am) /* 12 midnight - 12:59 AM subtract 12 hours */
1697 else if (!am && 1 <= *h && *h < 12) /* 1:00 PM - 11:59 AM add 12 hours */
1704 * hildon_time_editor_set_show_hours:
1705 * @editor: The #HildonTimeEditor.
1706 * @enable: Enable or disable showing of hours.
1708 * This function shows or hides the hours field.
1712 void hildon_time_editor_set_show_hours(HildonTimeEditor * editor,
1713 gboolean show_hours)
1715 HildonTimeEditorPrivate *priv;
1717 g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1719 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1721 if (show_hours != priv->show_hours) {
1722 priv->show_hours = show_hours;
1724 /* show/hide hours field and its ':' label if the value changed. */
1726 gtk_widget_show(priv->entries[ENTRY_HOURS]);
1727 gtk_widget_show(priv->hm_label);
1729 gtk_widget_hide(priv->entries[ENTRY_HOURS]);
1730 gtk_widget_hide(priv->hm_label);
1733 g_object_notify (G_OBJECT (editor), "show_hours");
1738 * hildon_time_editor_get_show_hours:
1739 * @self: the @HildonTimeEditor widget.
1741 * This function returns a boolean indicating the visibility of
1742 * hours in the @HildonTimeEditor
1744 * Return value: TRUE if hours are visible.
1748 gboolean hildon_time_editor_get_show_hours(HildonTimeEditor *editor)
1750 HildonTimeEditorPrivate *priv;
1752 g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1753 priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1755 return priv->show_hours;
1759 * Deprecated functions
1763 * hildon_time_editor_show_seconds:
1764 * @editor: the #HildonTimeEditor
1765 * @enable: enable or disable showing of seconds
1767 * This function is deprecated,
1768 * use #hildon_time_editor_set_show_seconds instead.
1770 void hildon_time_editor_show_seconds(HildonTimeEditor * editor,
1773 hildon_time_editor_set_show_seconds (editor, enable);
1776 * hildon_time_editor_enable_duration_mode:
1777 * @editor: the #HildonTimeEditor
1778 * @enable: enable or disable duration editor mode
1780 * This function is deprecated,
1781 * use #hildon_time_editor_set_duration_mode instead.
1783 void hildon_time_editor_enable_duration_mode(HildonTimeEditor * editor,
1786 hildon_time_editor_set_duration_mode (editor, enable);