2006-09-19 Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
[hildon] / hildon-widgets / hildon-time-editor.c
index e2af240..f030b29 100644 (file)
@@ -1,14 +1,14 @@
 /*
  * This file is part of hildon-libs
  *
- * Copyright (C) 2005, 2006 Nokia Corporation.
+ * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
  *
  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
  * as published by the Free Software Foundation; version 2.1 of
- * the License.
+ * the License or any later version.
  *
  * This library is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -40,7 +40,6 @@
 #endif
 
 #include <gtk/gtkhbox.h>
-#include <gtk/gtkeventbox.h>
 #include <gtk/gtkentry.h>
 #include <gtk/gtkbutton.h>
 #include <gtk/gtklabel.h>
@@ -141,7 +140,6 @@ struct _HildonTimeEditorPrivate {
     gchar     *am_symbol;
     gchar     *pm_symbol;
 
-    GtkWidget *eventbox;             /* hold entries                 */
     GtkWidget *iconbutton;           /* button for icon              */
 
     GtkWidget *frame;                /* frame around the entries     */
@@ -151,6 +149,7 @@ struct _HildonTimeEditorPrivate {
     GtkWidget *ampm_label;           /* label for showing am or pm   */
 
     GtkWidget *error_widget;         /* field to highlight in idle   */
+  GtkWidget *ampm_button;            /* am/pm change button */
 
 
     gboolean   duration_mode;        /* In HildonDurationEditor mode */
@@ -209,16 +208,11 @@ static gboolean hildon_time_editor_time_error(HildonTimeEditor *editor,
                                              HildonTimeEditorErrorType type);
 
 static gboolean hildon_time_editor_ampm_clicked(GtkWidget       *widget,
-                                                GdkEventButton  *event,
                                                 gpointer         data);
 
 static gboolean hildon_time_editor_icon_clicked(GtkWidget       *widget,
                                                 gpointer         data);
 
-static gboolean hildon_time_editor_entry_clicked(GtkWidget      *widget,
-                                                 GdkEventButton *event,
-                                                 gpointer        data);
-
 static void     hildon_time_editor_size_request(GtkWidget       *widget,
                                                 GtkRequisition  *requisition);
 
@@ -245,6 +239,10 @@ hildon_time_editor_validate (HildonTimeEditor *editor, gboolean allow_intermedia
 
 static void hildon_time_editor_set_to_current_time (HildonTimeEditor * editor);
 
+static gboolean
+_hildon_time_editor_entry_select_all(GtkWidget *widget);
+
+
 /***
  * Utility functions
  */
@@ -457,7 +455,7 @@ void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
       gtk_widget_tap_and_hold_setup(priv->entries[i], menu, func,
                                     GTK_TAP_AND_HOLD_NO_SIGNALS);
     }
-    gtk_widget_tap_and_hold_setup(priv->eventbox, menu, func,
+    gtk_widget_tap_and_hold_setup(priv->ampm_button, menu, func,
                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
     gtk_widget_tap_and_hold_setup(priv->iconbutton, menu, func,
                                   GTK_TAP_AND_HOLD_NONE);
@@ -491,7 +489,7 @@ static void hildon_time_editor_init(HildonTimeEditor * editor)
     priv->hm_label       = gtk_label_new(NULL);
     priv->sec_label      = gtk_label_new(NULL);
     priv->frame          = gtk_frame_new(NULL);
-    priv->eventbox       = gtk_event_box_new();
+    priv->ampm_button    = gtk_button_new();
 
     icon = gtk_image_new_from_icon_name(ICON_NAME, HILDON_ICON_SIZE_WIDG);
     hbox = gtk_hbox_new(FALSE, 0);
@@ -499,12 +497,12 @@ static void hildon_time_editor_init(HildonTimeEditor * editor)
     GTK_WIDGET_SET_FLAGS(editor, GTK_NO_WINDOW);
     GTK_WIDGET_UNSET_FLAGS(priv->iconbutton, GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
     
-    gtk_event_box_set_visible_window(GTK_EVENT_BOX(priv->eventbox), FALSE);
-
     gtk_container_set_border_width(GTK_CONTAINER(priv->frame), 0);
 
     gtk_container_add(GTK_CONTAINER(priv->iconbutton), icon);
-    gtk_container_add(GTK_CONTAINER(priv->eventbox), priv->ampm_label);
+    gtk_container_add(GTK_CONTAINER(priv->ampm_button), priv->ampm_label);
+    gtk_button_set_relief(GTK_BUTTON(priv->ampm_button), GTK_RELIEF_NONE);
+    gtk_button_set_focus_on_click(GTK_BUTTON(priv->ampm_button), FALSE);
 
     /* Create hour, minute and second entries */
     for (i = 0; i < ENTRY_COUNT; i++)
@@ -522,9 +520,6 @@ static void hildon_time_editor_init(HildonTimeEditor * editor)
       gtk_entry_set_max_length  (GTK_ENTRY(priv->entries[i]), 2);
       gtk_entry_set_width_chars (GTK_ENTRY(priv->entries[i]), 2);
 
-      /* Connect signals */
-      g_signal_connect(priv->entries[i], "button-release-event",
-                       G_CALLBACK(hildon_time_editor_entry_clicked), editor);
       g_signal_connect(priv->entries[i], "focus-in-event",
                        G_CALLBACK(hildon_time_editor_entry_focusin), editor);
       g_signal_connect(priv->entries[i], "focus-out-event",
@@ -541,7 +536,7 @@ static void hildon_time_editor_init(HildonTimeEditor * editor)
     }
     
     /* clicked signal for am/pm label */
-    g_signal_connect(G_OBJECT(priv->eventbox), "button_press_event",
+    g_signal_connect(G_OBJECT(priv->ampm_button), "clicked",
                      G_CALLBACK(hildon_time_editor_ampm_clicked), editor);
 
     /* clicked signal for icon */
@@ -555,7 +550,8 @@ static void hildon_time_editor_init(HildonTimeEditor * editor)
     gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_MINS],  FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox), priv->sec_label,            FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox), priv->entries[ENTRY_SECS],  FALSE, FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(hbox), priv->eventbox,             FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), priv->ampm_button,          FALSE, FALSE, 0);
+    gtk_misc_set_padding(GTK_MISC(priv->ampm_label), 0, 0);
 
     gtk_container_add(GTK_CONTAINER(priv->frame), hbox);
 
@@ -569,7 +565,7 @@ static void hildon_time_editor_init(HildonTimeEditor * editor)
         /* Using 12h clock */
         priv->clock_24h = FALSE;
     } else {
-        gtk_widget_hide(priv->eventbox);
+        gtk_widget_hide(priv->ampm_button);
     }
  
     if (!priv->show_seconds) {
@@ -705,7 +701,7 @@ _hildon_time_editor_get_time_separators(GtkLabel *hm_sep_label,
     gchar buffer[256];
     gchar *separator;
     GDate locale_test_date;
-    gchar *iter, *endp;
+    gchar *iter, *endp = NULL;
 
     /* Get localized time string */
     g_date_set_dmy(&locale_test_date, 1, 2, 1970);
@@ -961,7 +957,7 @@ void hildon_time_editor_set_duration_mode (HildonTimeEditor * editor,
             /* There's no AM/PM label or time picker icon in duration mode.
                Make sure they're hidden. */
             gtk_widget_hide(GTK_WIDGET(priv->ampm_label));
-            gtk_widget_hide(GTK_WIDGET(priv->eventbox));
+            gtk_widget_hide(GTK_WIDGET(priv->ampm_button));
             gtk_widget_hide(GTK_WIDGET(priv->iconbutton));
             /* Duration mode has seconds by default. */
             hildon_time_editor_set_show_seconds(editor, TRUE);
@@ -970,7 +966,7 @@ void hildon_time_editor_set_duration_mode (HildonTimeEditor * editor,
             if (!priv->clock_24h)
                 gtk_widget_show(GTK_WIDGET(priv->ampm_label));
 
-            gtk_widget_show(GTK_WIDGET(priv->eventbox));
+            gtk_widget_show(GTK_WIDGET(priv->ampm_button));
             gtk_widget_show(GTK_WIDGET(priv->iconbutton));        
 
                /* Reset the ticks to current time. Anything set in duration mode
@@ -1254,16 +1250,8 @@ static gboolean hildon_time_editor_entry_focusin(GtkWidget * widget,
                                                  GdkEventFocus * event, 
                                                  gpointer data)
 {
-    /* If we were trying to move away from a field with invalid value,
-       we get moved back to it. Here we want to select the text in the field.
-       The !button check checks that the entry wasn't focused with a mouse
-       click.
-
-       The selection happens temporarily if we got here with left/right
-       keys, but it gets immediately unselected within same call due to some
-       inner entry/clipboard magic. */
-    if (!GTK_ENTRY(widget)->button)
-        gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
+    g_idle_add((GSourceFunc) _hildon_time_editor_entry_select_all,
+               GTK_ENTRY(widget));
 
     return FALSE;
 }
@@ -1518,37 +1506,20 @@ hildon_time_editor_inserted_text  (GtkEditable * editable,
   
       if (strlen(value) == 2)
         {
-          HildonTimeEditorPrivate *priv;
-      
-          priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
-      
           if (GTK_WIDGET(editable) == priv->entries[ENTRY_HOURS]) 
-            { 
-              /* we don't want a focusout signal with this grab_focus
-                 because the validation was already done during the
-                 changed signal */
-              g_signal_handlers_block_by_func(priv->entries[ENTRY_HOURS],
-                                              (gpointer) hildon_time_editor_entry_focusout, editor);
-              
+            {
+              /* We already checked the input in changed signal, but 
+               * now we will re-check it again in focus-out we 
+               * intermediate flag set to FALSE */
               gtk_widget_grab_focus(priv->entries[ENTRY_MINS]);
               *position = -1;
-
-              g_signal_handlers_unblock_by_func(priv->entries[ENTRY_HOURS],
-                                                (gpointer) hildon_time_editor_entry_focusout, editor);
-              
             }
           else if (GTK_WIDGET(editable) == priv->entries[ENTRY_MINS] &&
                    GTK_WIDGET_VISIBLE (priv->entries[ENTRY_SECS])) 
             {
-              g_signal_handlers_block_by_func(priv->entries[ENTRY_MINS],
-                                              (gpointer) hildon_time_editor_entry_focusout, editor);
-
+              /* See above */
               gtk_widget_grab_focus(priv->entries[ENTRY_SECS]);
               *position = -1;
-
-              g_signal_handlers_unblock_by_func(priv->entries[ENTRY_MINS],
-                                                (gpointer) hildon_time_editor_entry_focusout, editor);
-              
             }
         }
     }   
@@ -1568,7 +1539,7 @@ static gboolean hildon_time_editor_entry_focusout(GtkWidget * widget,
 
 static gboolean
 hildon_time_editor_ampm_clicked(GtkWidget * widget,
-                                GdkEventButton * event, gpointer data)
+                                gpointer data)
 {
     HildonTimeEditor *editor;
     HildonTimeEditorPrivate *priv;
@@ -1600,15 +1571,22 @@ hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
     GtkWidget *picker;
     GtkWidget *parent;
     guint h, m, s, result;
+    HildonTimeEditorPrivate *priv;
 
     g_assert(HILDON_IS_TIME_EDITOR(data));
 
     editor = HILDON_TIME_EDITOR(data);
+    priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
 
     /* icon is passive in duration editor mode */
     if (hildon_time_editor_get_duration_mode(editor))
         return FALSE;
 
+    /* Validate and do not launch if broken */
+    hildon_time_editor_validate(HILDON_TIME_EDITOR(data), FALSE);
+    if (priv->error_widget != NULL)
+        return FALSE;
+
     /* Launch HildonTimePicker dialog */
     parent = gtk_widget_get_ancestor(GTK_WIDGET(editor), GTK_TYPE_WINDOW);
     picker = hildon_time_picker_new(GTK_WINDOW(parent));
@@ -1623,6 +1601,7 @@ hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
         /* Use the selected time */
         hildon_time_picker_get_time(HILDON_TIME_PICKER(picker), &h, &m);
         hildon_time_editor_set_time(editor, h, m, 0);
+        gtk_widget_grab_focus (editor);
         break;
     default:
         break;
@@ -1632,28 +1611,6 @@ hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
     return FALSE;
 }
 
-static gboolean hildon_time_editor_entry_clicked(GtkWidget * widget,
-                                                 GdkEventButton * event,
-                                                 gpointer data)
-{
-    HildonTimeEditor *editor;
-    HildonTimeEditorPrivate *priv;
-
-    editor = HILDON_TIME_EDITOR (data);
-    priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
-
-    /* If the focus has been grabbed back before the "clicked"
-     * signal gets processed, don't highlight the text.
-     * This happens when input in one H:M:S field is invalid and we're
-     * trying to move to another field. The focus moves back to the invalid
-     * field.
-     */
-    if (gtk_widget_is_focus (widget))
-        gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
-
-    return FALSE;
-}
-
 static void hildon_time_editor_size_request(GtkWidget * widget,
                                             GtkRequisition * requisition)
 {
@@ -1902,3 +1859,13 @@ void hildon_time_editor_enable_duration_mode(HildonTimeEditor * editor,
 {
     hildon_time_editor_set_duration_mode (editor, enable);
 }
+
+/* Idle callback */
+static gboolean
+_hildon_time_editor_entry_select_all (GtkWidget *widget)
+{
+       GDK_THREADS_ENTER ();
+       gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
+       GDK_THREADS_LEAVE ();
+       return FALSE;
+}