[gimp] Bug 648776 - fixes symmetry painting after Massimo and Mitch's reviews.



commit 1f4839288e8463138ec98f19478e2999f221dbdd
Author: Jehan <jehan girinstud io>
Date:   Thu Jan 21 21:43:15 2016 +0100

    Bug 648776 - fixes symmetry painting after Massimo and Mitch's reviews.
    
    Use a GType for the PROP_SYMMETRY property of GimpImage, and create
    a default "identity" symmetry for an image.
    I still use a GimpIntComboBox but store the property value in the
    user-data column because gpointer isn't a subset of gint.
    Adds in libgimpwidgets:
    - gimp_int_combo_box_set_active_by_user_data()
    - gimp_int_combo_box_get_active_user_data()
    - gimp_int_store_lookup_by_user_data()
    - gimp_prop_pointer_combo_box_new() to create a GimpIntComboBox and
      attach it to a gpointer property.
    Thanks Massimo and Mitch for reviewing my code.

 app/core/gimpimage-symmetry.c    |   18 ++----
 app/core/gimpimage.c             |   56 ++++++++---------
 app/widgets/gimpsymmetryeditor.c |   10 ++--
 libgimpwidgets/gimpintcombobox.c |   66 ++++++++++++++++++++
 libgimpwidgets/gimpintcombobox.h |    7 ++
 libgimpwidgets/gimpintstore.c    |   39 ++++++++++++
 libgimpwidgets/gimpintstore.h    |    3 +
 libgimpwidgets/gimppropwidgets.c |  124 ++++++++++++++++++++++++++++++++++++--
 libgimpwidgets/gimppropwidgets.h |    5 ++
 9 files changed, 277 insertions(+), 51 deletions(-)
---
diff --git a/app/core/gimpimage-symmetry.c b/app/core/gimpimage-symmetry.c
index 1fc300f..b6c6dff 100644
--- a/app/core/gimpimage-symmetry.c
+++ b/app/core/gimpimage-symmetry.c
@@ -55,6 +55,9 @@ gimp_image_symmetry_list (void)
  * @type:  the #GType of the symmetry
  *
  * Creates a new #GimpSymmetry of @type attached to @image.
+ * @type must be a subtype of `GIMP_TYPE_SYMMETRY`.
+ * Note that using the base @type `GIMP_TYPE_SYMMETRY` creates an
+ * identity transformation.
  *
  * Returns: the new #GimpSymmetry.
  **/
@@ -63,6 +66,7 @@ gimp_image_symmetry_new (GimpImage *image,
                          GType      type)
 {
   GimpSymmetry *sym = NULL;
+  g_return_val_if_fail (g_type_is_a (type, GIMP_TYPE_SYMMETRY), NULL);
 
   if (type != G_TYPE_NONE)
     {
@@ -176,21 +180,11 @@ gimp_image_symmetry_select (GimpImage *image,
 GimpSymmetry *
 gimp_image_symmetry_selected (GimpImage *image)
 {
-  static GimpImage    *last_image = NULL;
-  static GimpSymmetry *identity = NULL;
-  GimpImagePrivate    *private;
+  GimpImagePrivate *private;
 
   g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
 
-  if (last_image != image)
-    {
-      if (identity)
-        g_object_unref (identity);
-      identity = gimp_image_symmetry_new (image,
-                                          GIMP_TYPE_SYMMETRY);
-    }
-
   private = GIMP_IMAGE_GET_PRIVATE (image);
 
-  return private->selected_symmetry ? private->selected_symmetry : identity;
+  return private->selected_symmetry;
 }
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index 5900715..6e762ec 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -628,10 +628,11 @@ gimp_image_class_init (GimpImageClass *klass)
   g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
 
   g_object_class_install_property (object_class, PROP_SYMMETRY,
-                                   g_param_spec_int ("symmetry",
-                                                     NULL, _("Symmetry"),
-                                                     G_TYPE_NONE, G_MAXINT, G_TYPE_NONE,
-                                                     GIMP_PARAM_READWRITE));
+                                   g_param_spec_gtype ("symmetry",
+                                                       NULL, _("Symmetry"),
+                                                       GIMP_TYPE_SYMMETRY,
+                                                       GIMP_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT));
   g_type_class_add_private (klass, sizeof (GimpImagePrivate));
 }
 
@@ -873,7 +874,8 @@ gimp_image_set_property (GObject      *object,
       break;
     case PROP_SYMMETRY:
       {
-        GType type = g_value_get_int (value);
+        GList *iter;
+        GType  type = g_value_get_gtype (value);
 
         if (private->selected_symmetry)
           g_object_set (private->selected_symmetry,
@@ -881,29 +883,25 @@ gimp_image_set_property (GObject      *object,
                         NULL);
         private->selected_symmetry = NULL;
 
-        if (type != G_TYPE_NONE)
+
+        for (iter = private->symmetries; iter; iter = g_list_next (iter))
           {
-            GList *iter;
-
-            for (iter = private->symmetries; iter; iter = g_list_next (iter))
-              {
-                GimpSymmetry *sym = iter->data;
-                if (g_type_is_a (sym->type, type))
-                  private->selected_symmetry = iter->data;
-              }
-
-            if (private->selected_symmetry == NULL)
-              {
-                GimpSymmetry *sym;
-
-                sym = gimp_image_symmetry_new (image, type);
-                gimp_image_symmetry_add (image, sym);
-                private->selected_symmetry = sym;
-              }
-            g_object_set (private->selected_symmetry,
-                          "active", TRUE,
-                          NULL);
+            GimpSymmetry *sym = iter->data;
+            if (type == sym->type)
+              private->selected_symmetry = iter->data;
+          }
+
+        if (private->selected_symmetry == NULL)
+          {
+            GimpSymmetry *sym;
+
+            sym = gimp_image_symmetry_new (image, type);
+            gimp_image_symmetry_add (image, sym);
+            private->selected_symmetry = sym;
           }
+        g_object_set (private->selected_symmetry,
+                      "active", TRUE,
+                      NULL);
       }
       break;
     default:
@@ -948,9 +946,9 @@ gimp_image_get_property (GObject    *object,
       g_value_set_object (value, gimp_image_get_buffer (GIMP_PICKABLE (image)));
       break;
     case PROP_SYMMETRY:
-      g_value_set_int (value,
-                       private->selected_symmetry ?
-                       private->selected_symmetry->type : G_TYPE_NONE);
+      g_value_set_gtype (value,
+                         private->selected_symmetry ?
+                         private->selected_symmetry->type : GIMP_TYPE_SYMMETRY);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
diff --git a/app/widgets/gimpsymmetryeditor.c b/app/widgets/gimpsymmetryeditor.c
index eb5169d..9674aef 100644
--- a/app/widgets/gimpsymmetryeditor.c
+++ b/app/widgets/gimpsymmetryeditor.c
@@ -274,7 +274,7 @@ gimp_symmetry_editor_image_changed (GimpContext        *context,
           gtk_list_store_set (store, &iter,
                               GIMP_INT_STORE_LABEL,
                               klass->label,
-                              GIMP_INT_STORE_VALUE,
+                              GIMP_INT_STORE_USER_DATA,
                               sym_iter->data,
                               -1);
           g_type_class_unref (klass);
@@ -284,11 +284,11 @@ gimp_symmetry_editor_image_changed (GimpContext        *context,
       gtk_list_store_prepend (store, &iter);
       gtk_list_store_set (store, &iter,
                           GIMP_INT_STORE_LABEL, _("None"),
-                          GIMP_INT_STORE_VALUE, G_TYPE_NONE,
+                          GIMP_INT_STORE_USER_DATA, GIMP_TYPE_SYMMETRY,
                           -1);
-      editor->p->menu = gimp_prop_int_combo_box_new (G_OBJECT (image),
-                                                     "symmetry",
-                                                     GIMP_INT_STORE (store));
+      editor->p->menu = gimp_prop_pointer_combo_box_new (G_OBJECT (image),
+                                                         "symmetry",
+                                                         GIMP_INT_STORE (store));
       g_object_unref (store);
 
       gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (editor->p->menu),
diff --git a/libgimpwidgets/gimpintcombobox.c b/libgimpwidgets/gimpintcombobox.c
index c32062f..a270dcd 100644
--- a/libgimpwidgets/gimpintcombobox.c
+++ b/libgimpwidgets/gimpintcombobox.c
@@ -471,6 +471,72 @@ gimp_int_combo_box_get_active (GimpIntComboBox *combo_box,
 }
 
 /**
+ * gimp_int_combo_box_set_active_by_user_data:
+ * @combo_box: a #GimpIntComboBox
+ * @user_data: an integer value
+ *
+ * Looks up the item that has the given @user_data and makes it the
+ * selected item in the @combo_box.
+ *
+ * Return value: %TRUE on success or %FALSE if there was no item for
+ *               this user-data.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_int_combo_box_set_active_by_user_data (GimpIntComboBox *combo_box,
+                                            gpointer         user_data)
+{
+  GtkTreeModel *model;
+  GtkTreeIter   iter;
+
+  g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box), FALSE);
+
+  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
+
+  if (gimp_int_store_lookup_by_user_data (model, user_data, &iter))
+    {
+      gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * gimp_int_combo_box_get_active_user_data:
+ * @combo_box: a #GimpIntComboBox
+ * @user_data: return location for the gpointer value
+ *
+ * Retrieves the user-data of the selected (active) item in the @combo_box.
+ *
+ * Return value: %TRUE if @user_data has been set or %FALSE if no item was
+ *               active.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_int_combo_box_get_active_user_data (GimpIntComboBox *combo_box,
+                                         gpointer        *user_data)
+{
+  GtkTreeIter  iter;
+
+  g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box), FALSE);
+  g_return_val_if_fail (user_data != NULL, FALSE);
+
+  if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter))
+    {
+      gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)),
+                          &iter,
+                          GIMP_INT_STORE_USER_DATA, user_data,
+                          -1);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
  * gimp_int_combo_box_connect:
  * @combo_box: a #GimpIntComboBox
  * @value:     the value to set
diff --git a/libgimpwidgets/gimpintcombobox.h b/libgimpwidgets/gimpintcombobox.h
index 4652742..809f57d 100644
--- a/libgimpwidgets/gimpintcombobox.h
+++ b/libgimpwidgets/gimpintcombobox.h
@@ -85,6 +85,13 @@ gboolean      gimp_int_combo_box_set_active      (GimpIntComboBox *combo_box,
 gboolean      gimp_int_combo_box_get_active      (GimpIntComboBox *combo_box,
                                                   gint            *value);
 
+gboolean
+      gimp_int_combo_box_set_active_by_user_data (GimpIntComboBox *combo_box,
+                                                  gpointer         user_data);
+gboolean
+      gimp_int_combo_box_get_active_user_data    (GimpIntComboBox *combo_box,
+                                                  gpointer        *user_data);
+
 gulong        gimp_int_combo_box_connect         (GimpIntComboBox *combo_box,
                                                   gint             value,
                                                   GCallback        callback,
diff --git a/libgimpwidgets/gimpintstore.c b/libgimpwidgets/gimpintstore.c
index dbd6ac2..dc74ac2 100644
--- a/libgimpwidgets/gimpintstore.c
+++ b/libgimpwidgets/gimpintstore.c
@@ -309,3 +309,42 @@ gimp_int_store_lookup_by_value (GtkTreeModel *model,
 
   return iter_valid;
 }
+
+/**
+ * gimp_int_store_lookup_by_user_data:
+ * @model: a #GimpIntStore
+ * @user_data: a gpointer "user-data" to lookup in the @model
+ * @iter:  return location for the iter of the given @user_data
+ *
+ * Iterate over the @model looking for @user_data.
+ *
+ * Return value: %TRUE if the user-data has been located and @iter is
+ *               valid, %FALSE otherwise.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_int_store_lookup_by_user_data (GtkTreeModel *model,
+                                    gpointer      user_data,
+                                    GtkTreeIter  *iter)
+{
+  gboolean iter_valid = FALSE;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  for (iter_valid = gtk_tree_model_get_iter_first (model, iter);
+       iter_valid;
+       iter_valid = gtk_tree_model_iter_next (model, iter))
+    {
+      gpointer this;
+
+      gtk_tree_model_get (model, iter,
+                          GIMP_INT_STORE_USER_DATA, &this,
+                          -1);
+      if (this == user_data)
+        break;
+    }
+
+  return (gboolean) iter_valid;
+}
diff --git a/libgimpwidgets/gimpintstore.h b/libgimpwidgets/gimpintstore.h
index d819893..f77d0de 100644
--- a/libgimpwidgets/gimpintstore.h
+++ b/libgimpwidgets/gimpintstore.h
@@ -92,6 +92,9 @@ GtkListStore * gimp_int_store_new             (void);
 gboolean       gimp_int_store_lookup_by_value (GtkTreeModel  *model,
                                                gint           value,
                                                GtkTreeIter   *iter);
+gboolean   gimp_int_store_lookup_by_user_data (GtkTreeModel  *model,
+                                               gpointer       user_data,
+                                               GtkTreeIter   *iter);
 
 
 G_END_DECLS
diff --git a/libgimpwidgets/gimppropwidgets.c b/libgimpwidgets/gimppropwidgets.c
index 37e91ce..96f9a11 100644
--- a/libgimpwidgets/gimppropwidgets.c
+++ b/libgimpwidgets/gimppropwidgets.c
@@ -337,11 +337,17 @@ gimp_prop_enum_check_button_notify (GObject    *config,
 /*  int/enum combo box   */
 /*************************/
 
-static void   gimp_prop_int_combo_box_callback (GtkWidget   *widget,
-                                                GObject     *config);
-static void   gimp_prop_int_combo_box_notify   (GObject     *config,
-                                                GParamSpec  *param_spec,
-                                                GtkWidget   *widget);
+static void gimp_prop_int_combo_box_callback     (GtkWidget  *widget,
+                                                  GObject    *config);
+static void gimp_prop_int_combo_box_notify       (GObject    *config,
+                                                  GParamSpec *param_spec,
+                                                  GtkWidget  *widget);
+
+static void gimp_prop_pointer_combo_box_callback (GtkWidget  *widget,
+                                                  GObject    *config);
+static void gimp_prop_pointer_combo_box_notify   (GObject    *config,
+                                                  GParamSpec *param_spec,
+                                                  GtkWidget  *combo_box);
 
 /**
  * gimp_prop_int_combo_box_new:
@@ -398,6 +404,72 @@ gimp_prop_int_combo_box_new (GObject      *config,
 }
 
 /**
+ * gimp_prop_pointer_combo_box_new:
+ * @config:        Object to which property is attached.
+ * @property_name: Name of GType/gpointer property controlled by combo box.
+ * @store:         #GimpIntStore holding list of labels, values, etc.
+ *
+ * Creates a #GimpIntComboBox widget to display and set the specified
+ * property.  The contents of the widget are determined by @store,
+ * which should be created using gimp_int_store_new().
+ * Values are GType/gpointer data, and therefore must be stored in the
+ * "user-data" column, instead of the usual "value" column.
+ *
+ * Return value: The newly created #GimpIntComboBox widget.
+ *
+ * Since GIMP 2.10
+ */
+GtkWidget *
+gimp_prop_pointer_combo_box_new (GObject      *config,
+                                 const gchar  *property_name,
+                                 GimpIntStore *store)
+{
+  GParamSpec *param_spec;
+  GtkWidget  *combo_box;
+  gpointer    property_value;
+
+  g_return_val_if_fail (G_IS_OBJECT (config), NULL);
+  g_return_val_if_fail (property_name != NULL, NULL);
+
+  param_spec = check_param_spec_w (config, property_name,
+                                   G_TYPE_PARAM_GTYPE, G_STRFUNC);
+  if (! param_spec)
+    {
+      param_spec = check_param_spec_w (config, property_name,
+                                       G_TYPE_PARAM_POINTER, G_STRFUNC);
+      if (! param_spec)
+        return NULL;
+    }
+
+  g_object_get (config,
+                property_name, &property_value,
+                NULL);
+
+  /* We use a GimpIntComboBox but we cannot store gpointer in the
+   * "value" column, because gpointer is not a subset of gint. Instead
+   * we store the value in the "user-data" column which is a gpointer.
+   */
+  combo_box = g_object_new (GIMP_TYPE_INT_COMBO_BOX,
+                            "model", store,
+                            NULL);
+
+  gimp_int_combo_box_set_active_by_user_data (GIMP_INT_COMBO_BOX (combo_box),
+                                              property_value);
+
+  g_signal_connect (combo_box, "changed",
+                    G_CALLBACK (gimp_prop_pointer_combo_box_callback),
+                    config);
+
+  set_param_spec (G_OBJECT (combo_box), combo_box, param_spec);
+
+  connect_notify (config, property_name,
+                  G_CALLBACK (gimp_prop_pointer_combo_box_notify),
+                  combo_box);
+
+  return combo_box;
+}
+
+/**
  * gimp_prop_enum_combo_box_new:
  * @config:        Object to which property is attached.
  * @property_name: Name of enum property controlled by combo box.
@@ -510,6 +582,48 @@ gimp_prop_int_combo_box_notify (GObject    *config,
                                      config);
 }
 
+static void
+gimp_prop_pointer_combo_box_callback (GtkWidget *widget,
+                                      GObject   *config)
+{
+  GParamSpec *param_spec;
+  gpointer    value;
+
+  param_spec = get_param_spec (G_OBJECT (widget));
+  if (! param_spec)
+    return;
+
+  if (gimp_int_combo_box_get_active_user_data (GIMP_INT_COMBO_BOX (widget),
+                                               &value))
+    {
+      g_object_set (config,
+                    param_spec->name, value,
+                    NULL);
+    }
+}
+
+static void
+gimp_prop_pointer_combo_box_notify (GObject    *config,
+                                    GParamSpec *param_spec,
+                                    GtkWidget  *combo_box)
+{
+  gpointer value;
+
+  g_object_get (config,
+                param_spec->name, &value,
+                NULL);
+
+  g_signal_handlers_block_by_func (combo_box,
+                                   gimp_prop_pointer_combo_box_callback,
+                                   config);
+
+  gimp_int_combo_box_set_active_by_user_data (GIMP_INT_COMBO_BOX (combo_box),
+                                              value);
+
+  g_signal_handlers_unblock_by_func (combo_box,
+                                     gimp_prop_pointer_combo_box_callback,
+                                     config);
+}
 
 /************************/
 /*  boolean combo box   */
diff --git a/libgimpwidgets/gimppropwidgets.h b/libgimpwidgets/gimppropwidgets.h
index 469e667..19dca84 100644
--- a/libgimpwidgets/gimppropwidgets.h
+++ b/libgimpwidgets/gimppropwidgets.h
@@ -55,6 +55,11 @@ GtkWidget     * gimp_prop_int_combo_box_new       (GObject      *config,
                                                    const gchar  *property_name,
                                                    GimpIntStore *store);
 
+/*  GParamGType  */
+
+GtkWidget     * gimp_prop_pointer_combo_box_new   (GObject      *config,
+                                                   const gchar  *property_name,
+                                                   GimpIntStore *store);
 
 /*  GParamEnum  */
 


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