[ekiga/ds-gtk-application] GmEntry: Added a activate_icon property and an activated signal.



commit d27b482cec2b5ae9d57301ca2c655b6fe9f235dc
Author: Damien Sandras <dsandras seconix com>
Date:   Sun Oct 26 15:57:56 2014 +0100

    GmEntry: Added a activate_icon property and an activated signal.
    
    The activate icon is an icon that appears when the GmEntry content is
    both valid and non-empty (even if allow-empty is set to true). It emits
    the activate signal when being clicked. (this is the reason why it can
    not be empty).
    
    The activated signal is emitted when the GtkEntry activate signal is
    emitted and the GmEntry content is valid (and not empty).

 lib/gui/gm-entry.c |  151 ++++++++++++++++++++++++++++++++++++++++++++++++----
 lib/gui/gm-entry.h |   34 +++++++++++-
 2 files changed, 172 insertions(+), 13 deletions(-)
---
diff --git a/lib/gui/gm-entry.c b/lib/gui/gm-entry.c
index 887258c..71ac7d9 100644
--- a/lib/gui/gm-entry.c
+++ b/lib/gui/gm-entry.c
@@ -46,6 +46,7 @@ struct _GmEntryPrivate {
 
   GRegex *regex;
   gchar *regex_string;
+  gchar *activate_icon;
   gboolean is_valid;
   gboolean allow_empty;
 };
@@ -53,10 +54,12 @@ struct _GmEntryPrivate {
 enum {
   GM_ENTRY_REGEX = 1,
   GM_ENTRY_ALLOW_EMPTY = 2,
+  GM_ENTRY_ACTIVATE_ICON = 3,
 };
 
 enum {
   VALIDITY_CHANGED_SIGNAL,
+  ACTIVATED_SIGNAL,
   LAST_SIGNAL
 };
 
@@ -69,10 +72,21 @@ G_DEFINE_TYPE (GmEntry, gm_entry, GTK_TYPE_ENTRY);
 static void gm_entry_changed_cb (GmEntry *self,
                                  G_GNUC_UNUSED gpointer data);
 
+static void gm_entry_activated_cb (GmEntry *self,
+                                   G_GNUC_UNUSED gpointer data);
+
 static void gm_entry_icon_release_cb (GtkEntry *self,
+                                      GtkEntryIconPosition icon_pos,
+                                      G_GNUC_UNUSED GdkEvent *event,
                                       G_GNUC_UNUSED gpointer data);
 
 
+/* Helpers */
+static void gm_entry_update_clear_icon (GmEntry *self);
+
+static void gm_entry_update_activate_icon (GmEntry *self);
+
+
 /* Static GObject functions and declarations */
 static void gm_entry_class_init (GmEntryClass *);
 
@@ -96,29 +110,46 @@ static void
 gm_entry_changed_cb (GmEntry *self,
                      G_GNUC_UNUSED gpointer data)
 {
-  gboolean empty = (gtk_entry_get_text_length (GTK_ENTRY (self)) == 0);
-  gboolean rtl = (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL);
+  g_return_if_fail (GM_IS_ENTRY (self));
   gboolean is_valid = gm_entry_text_is_valid (self);
 
-  g_object_set (self,
-                "secondary-icon-name", !empty ? (rtl ? "edit-clear-rtl-symbolic" : "edit-clear-symbolic") : 
NULL,
-                "secondary-icon-activatable", !empty,
-                "secondary-icon-sensitive", !empty,
-                NULL);
-
   if (is_valid != self->priv->is_valid) {
     self->priv->is_valid = is_valid;
     g_signal_emit (self, signals[VALIDITY_CHANGED_SIGNAL], 0);
   }
+
+  gm_entry_update_clear_icon (self);
+  gm_entry_update_activate_icon (self);
+}
+
+
+static void
+gm_entry_activated_cb (GmEntry *self,
+                       G_GNUC_UNUSED gpointer data)
+{
+  g_return_if_fail (GM_IS_ENTRY (self));
+  if (self->priv->is_valid)
+    g_signal_emit (self, signals[ACTIVATED_SIGNAL], 0);
 }
 
 
 static void
 gm_entry_icon_release_cb (GtkEntry *self,
+                          GtkEntryIconPosition icon_pos,
+                          G_GNUC_UNUSED GdkEvent *event,
                           G_GNUC_UNUSED gpointer data)
 {
-  gtk_entry_set_text (self, "");
-  gtk_widget_grab_focus (GTK_WIDGET (self));
+  switch (icon_pos) {
+  case GTK_ENTRY_ICON_SECONDARY:
+    gtk_entry_set_text (self, "");
+    gtk_widget_grab_focus (GTK_WIDGET (self));
+    break;
+
+  default:
+  case GTK_ENTRY_ICON_PRIMARY:
+    g_signal_emit_by_name (G_OBJECT (self), "activate");
+    break;
+  }
 }
 
 
@@ -136,6 +167,10 @@ gm_entry_dispose (GObject* obj)
     g_free (priv->regex_string);
     priv->regex_string = NULL;
   }
+  if (priv->activate_icon) {
+    g_free (priv->activate_icon);
+    priv->activate_icon = NULL;
+  }
 
   G_OBJECT_CLASS (gm_entry_parent_class)->dispose (obj);
 }
@@ -162,6 +197,10 @@ gm_entry_get_property (GObject *obj,
     g_value_set_boolean (value, self->priv->allow_empty);
     break;
 
+  case GM_ENTRY_ACTIVATE_ICON:
+    g_value_set_string (value, self->priv->activate_icon);
+    break;
+
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, spec);
     break;
@@ -208,6 +247,19 @@ gm_entry_set_property (GObject *obj,
     self->priv->allow_empty = g_value_get_boolean (value);
     break;
 
+  case GM_ENTRY_ACTIVATE_ICON:
+    if (self->priv->activate_icon)
+      g_free (self->priv->activate_icon);
+    self->priv->activate_icon = NULL;
+
+    str = g_value_get_string (value);
+    if (g_strcmp0 (str, "")) {
+      self->priv->activate_icon = g_strdup (str);
+      gm_entry_update_activate_icon (self);
+    }
+    break;
+
+
   default:
     G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, spec);
     break;
@@ -232,11 +284,14 @@ gm_entry_class_init (GmEntryClass *klass)
                               NULL, (GParamFlags) G_PARAM_READWRITE);
   g_object_class_install_property (gobject_class, GM_ENTRY_REGEX, spec);
 
-
   spec = g_param_spec_boolean ("allow-empty", "Allow Empty", "Allow empty GmEntry",
                                TRUE, (GParamFlags) G_PARAM_READWRITE);
   g_object_class_install_property (gobject_class, GM_ENTRY_ALLOW_EMPTY, spec);
 
+  spec = g_param_spec_string ("activate-icon", "Activate Icon", "Icon triggering the activate signal",
+                              NULL, (GParamFlags) G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, GM_ENTRY_ACTIVATE_ICON, spec);
+
 
   signals[VALIDITY_CHANGED_SIGNAL] =
     g_signal_new ("validity-changed",
@@ -245,6 +300,14 @@ gm_entry_class_init (GmEntryClass *klass)
                  0, NULL, NULL,
                  g_cclosure_marshal_generic,
                  G_TYPE_NONE, 0);
+
+  signals[ACTIVATED_SIGNAL] =
+    g_signal_new ("activated",
+                 G_OBJECT_CLASS_TYPE (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 0, NULL, NULL,
+                 g_cclosure_marshal_generic,
+                 G_TYPE_NONE, 0);
 }
 
 
@@ -257,15 +320,62 @@ gm_entry_init (GmEntry* self)
 
   self->priv->regex = NULL;
   self->priv->regex_string = NULL;
+  self->priv->activate_icon = NULL;
   self->priv->is_valid = gm_entry_text_is_valid (self);
 
+  gm_entry_update_activate_icon (self);
+  gm_entry_update_clear_icon (self);
+
   g_signal_connect (self, "changed",
                     G_CALLBACK (gm_entry_changed_cb), NULL);
+  g_signal_connect (self, "activate",
+                    G_CALLBACK (gm_entry_activated_cb), NULL);
   g_signal_connect (self, "icon-release",
                     G_CALLBACK (gm_entry_icon_release_cb), NULL);
 }
 
 
+/* Helpers */
+static void
+gm_entry_update_clear_icon (GmEntry *self)
+{
+  g_return_if_fail (GM_IS_ENTRY (self));
+
+  gboolean empty = (gtk_entry_get_text_length (GTK_ENTRY (self)) == 0);
+  gboolean rtl = (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL);
+
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+                                            GM_TYPE_ENTRY,
+                                           GmEntryPrivate);
+
+  g_object_set (self,
+                "secondary-icon-name", !empty ? (rtl ? "edit-clear-rtl-symbolic" : "edit-clear-symbolic") : 
NULL,
+                "secondary-icon-activatable", !empty,
+                "secondary-icon-sensitive", !empty,
+                NULL);
+}
+
+
+static void
+gm_entry_update_activate_icon (GmEntry *self)
+{
+  const gchar *content = gtk_entry_get_text (GTK_ENTRY (self));
+  gchar *value = g_strdup (content);
+  value = g_strstrip (value);
+
+  gboolean empty = (!g_strcmp0 (value, ""));
+  gboolean ok = (!empty && self->priv->is_valid);
+
+  g_object_set (self,
+                "primary-icon-name", ok ? self->priv->activate_icon : NULL,
+                "primary-icon-activatable", ok,
+                "primary-icon-sensitive", ok,
+                NULL);
+
+  g_free (value);
+}
+
+
 /* public api */
 GtkWidget *
 gm_entry_new (const gchar *regex)
@@ -327,3 +437,22 @@ gm_entry_get_allow_empty (GmEntry *self)
 
   return self->priv->allow_empty;
 }
+
+
+void
+gm_entry_set_activate_icon (GmEntry *self,
+                            const gchar *activate_icon)
+{
+  g_return_if_fail (GM_IS_ENTRY (self));
+
+  g_object_set (self, "activate-icon", activate_icon, NULL);
+}
+
+
+const gchar *
+gm_entry_get_activate_icon (GmEntry *self)
+{
+  g_return_val_if_fail (GM_IS_ENTRY (self), TRUE);
+
+  return self->priv->activate_icon;
+}
diff --git a/lib/gui/gm-entry.h b/lib/gui/gm-entry.h
index 762261e..9229c6b 100644
--- a/lib/gui/gm-entry.h
+++ b/lib/gui/gm-entry.h
@@ -46,6 +46,11 @@
 
 G_BEGIN_DECLS
 
+#define URI_SCHEME "([A-Za-z]+:)?"
+#define BASIC_URI_PART "[A-Za-z0-9_\\-\\.]+"
+#define BASIC_URI_REGEX "^" URI_SCHEME BASIC_URI_PART "@" BASIC_URI_PART "$"
+#define PHONE_NUMBER_REGEX "\\+?[0-9]+"
+
 typedef struct _GmEntry GmEntry;
 typedef struct _GmEntryPrivate GmEntryPrivate;
 typedef struct _GmEntryClass GmEntryClass;
@@ -84,15 +89,40 @@ void gm_entry_set_allow_empty (GmEntry *self,
 gboolean gm_entry_get_allow_empty (GmEntry *self);
 
 
+/** Set the activate icon.
+ * The activate icon is displayed when the GmEntry content is considered as
+ * valid.
+ *
+ * @param The GmEntry.
+ * @param The activate icon name.
+ */
+void gm_entry_set_activate_icon (GmEntry *self,
+                                 const gchar *activate_icon);
+
+
+/** Return the GmEntry activate icon name.
+ * @param The GmEntry
+ * @return The current activate icon.
+ */
+const gchar *gm_entry_get_activate_icon (GmEntry *self);
+
+
 /* Signals emitted by that widget :
  *
- * - "validity-changed"
+ * - "validity-changed": Emitted when the GmEntry validity changes.
+ * - "activated"       : Emitted when the entry is activated and its content is
+ *                       valid. This is similar to the native "activate" signal.
+ *                       However, the native signal will be emitted even if the
+ *                       GmEntry content is invalid.
  *
  */
 
 /* Properties of that widget :
  *
- * - "allow-empty": Defaults to TRUE.
+ * - "allow-empty"  :   Defaults to TRUE.
+ * - "activate-icon":   Icon that appears when the entry content is not empty
+ *                      and valid. Clicking on it emits the activated signal.
+ * - "regex"        :  Set the regex string to use for validity checking.
  *
  */
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]