[gimp] app: improve source tool options GUI.



commit 6ad00cdbba7226a2062af956edf86df14ab08324
Author: Jehan <jehan girinstud io>
Date:   Fri Sep 3 23:39:03 2021 +0200

    app: improve source tool options GUI.
    
    The "Source" dropdown to choose an image or pattern, and to check
    "Sample merged" seem important enough that I moved them up the source
    tool options. I also added a label giving information about the image
    source being currently set, i.e. in particular which image (when the
    source is another image), how many composited layers (or all of them
    with "Sample merged" checked), or if each layer is its own source.
    
    For this to happen, I moved src-drawables property from GimpSourceCore
    to GimpSourceOptions (though without making it a config property,
    because we don't want this option to be saved in config files). It
    actually makes sense, it is a kind of "option" of how the tool will
    behave, and then it is also visible by the options GUI.

 app/paint/gimpperspectiveclone.c     |  10 +--
 app/paint/gimpsourcecore.c           | 143 ++-----------------------------
 app/paint/gimpsourcecore.h           |   5 --
 app/paint/gimpsourceoptions.c        | 159 ++++++++++++++++++++++++++++++++--
 app/paint/gimpsourceoptions.h        |   6 ++
 app/tools/gimpcloneoptions-gui.c     | 162 ++++++++++++++++++++++++++++++++---
 app/tools/gimpperspectiveclonetool.c |  15 ++--
 app/tools/gimpsourcetool.c           |  11 +--
 8 files changed, 334 insertions(+), 177 deletions(-)
---
diff --git a/app/paint/gimpperspectiveclone.c b/app/paint/gimpperspectiveclone.c
index 32491b3840..aa1b49c51b 100644
--- a/app/paint/gimpperspectiveclone.c
+++ b/app/paint/gimpperspectiveclone.c
@@ -146,7 +146,7 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
     case GIMP_PAINT_STATE_INIT:
       if (source_core->set_source)
         {
-          g_object_set (source_core, "src-drawables", drawables, NULL);
+          g_object_set (options, "src-drawables", drawables, NULL);
 
           source_core->src_x = floor (coords->x);
           source_core->src_y = floor (coords->y);
@@ -194,7 +194,7 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                  *  Otherwise, we need a call to get_orig_image to make sure
                  *  we get a copy of the unblemished (offset) image
                  */
-                src_image = gimp_pickable_get_image (source_core->src_drawables->data);
+                src_image = gimp_pickable_get_image (options->src_drawables->data);
 
                 if (sample_merged)
                   src_pickable = GIMP_PICKABLE (src_image);
@@ -204,12 +204,12 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                 if ((sample_merged &&
                      (src_image != dest_image)) ||
                     (! sample_merged                                 &&
-                     g_list_length (source_core->src_drawables) == 1 &&
+                     g_list_length (options->src_drawables) == 1 &&
                      g_list_length (drawables) == 1                  &&
-                     (source_core->src_drawables != drawables->data)))
+                     (options->src_drawables != drawables->data)))
                   {
                     if (! sample_merged)
-                      src_pickable = GIMP_PICKABLE (source_core->src_drawables->data);
+                      src_pickable = GIMP_PICKABLE (options->src_drawables->data);
 
                     orig_buffer = gimp_pickable_get_buffer (src_pickable);
                   }
diff --git a/app/paint/gimpsourcecore.c b/app/paint/gimpsourcecore.c
index 4f6c58c192..4d07e0a1d9 100644
--- a/app/paint/gimpsourcecore.c
+++ b/app/paint/gimpsourcecore.c
@@ -46,13 +46,11 @@
 enum
 {
   PROP_0,
-  PROP_SRC_DRAWABLES,
   PROP_SRC_X,
   PROP_SRC_Y
 };
 
 
-static void     gimp_source_core_finalize        (GObject           *object);
 static void     gimp_source_core_set_property    (GObject           *object,
                                                   guint              property_id,
                                                   const GValue      *value,
@@ -101,10 +99,6 @@ static GeglBuffer *
                                                   gint              *paint_area_height,
                                                   GeglRectangle     *src_rect);
 
-static void    gimp_source_core_set_src_drawable (GimpSourceCore    *source_core,
-                                                  GList             *drawables);
-static void    gimp_source_core_make_pickable    (GimpSourceCore    *source_core);
-
 
 G_DEFINE_TYPE (GimpSourceCore, gimp_source_core, GIMP_TYPE_BRUSH_CORE)
 
@@ -118,7 +112,6 @@ gimp_source_core_class_init (GimpSourceCoreClass *klass)
   GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
   GimpBrushCoreClass *brush_core_class = GIMP_BRUSH_CORE_CLASS (klass);
 
-  object_class->finalize                   = gimp_source_core_finalize;
   object_class->set_property               = gimp_source_core_set_property;
   object_class->get_property               = gimp_source_core_get_property;
 
@@ -131,11 +124,6 @@ gimp_source_core_class_init (GimpSourceCoreClass *klass)
   klass->get_source                        = gimp_source_core_real_get_source;
   klass->motion                            = NULL;
 
-  g_object_class_install_property (object_class, PROP_SRC_DRAWABLES,
-                                   g_param_spec_pointer ("src-drawables",
-                                                         NULL, NULL,
-                                                         GIMP_PARAM_READWRITE));
-
   g_object_class_install_property (object_class, PROP_SRC_X,
                                    g_param_spec_int ("src-x", NULL, NULL,
                                                      0, GIMP_MAX_IMAGE_SIZE,
@@ -154,7 +142,6 @@ gimp_source_core_init (GimpSourceCore *source_core)
 {
   source_core->set_source    = FALSE;
 
-  source_core->src_drawables = NULL;
   source_core->src_x         = 0;
   source_core->src_y         = 0;
 
@@ -166,17 +153,6 @@ gimp_source_core_init (GimpSourceCore *source_core)
   source_core->first_stroke  = TRUE;
 }
 
-static void
-gimp_source_core_finalize (GObject *object)
-{
-  GimpSourceCore *source_core = GIMP_SOURCE_CORE (object);
-
-  g_clear_object (&source_core->src_image);
-  g_clear_pointer (&source_core->src_drawables, g_list_free);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
 static void
 gimp_source_core_set_property (GObject      *object,
                                guint         property_id,
@@ -187,11 +163,6 @@ gimp_source_core_set_property (GObject      *object,
 
   switch (property_id)
     {
-    case PROP_SRC_DRAWABLES:
-      gimp_source_core_set_src_drawable (source_core,
-                                         g_value_get_pointer (value));
-      gimp_source_core_make_pickable (source_core);
-      break;
     case PROP_SRC_X:
       source_core->src_x = g_value_get_int (value);
       break;
@@ -214,9 +185,6 @@ gimp_source_core_get_property (GObject    *object,
 
   switch (property_id)
     {
-    case PROP_SRC_DRAWABLES:
-      g_value_set_pointer (value, source_core->src_drawables);
-      break;
     case PROP_SRC_X:
       g_value_set_int (value, source_core->src_x);
       break;
@@ -251,7 +219,7 @@ gimp_source_core_start (GimpPaintCore     *paint_core,
   if (! source_core->set_source &&
       gimp_source_core_use_source (source_core, options))
     {
-      if (! source_core->src_drawables)
+      if (! options->src_drawables)
         {
           g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
                                _("Set a source image first."));
@@ -267,7 +235,7 @@ gimp_source_core_start (GimpPaintCore     *paint_core,
 
       if (options->sample_merged         &&
           g_list_length (drawables) == 1 &&
-          gimp_item_get_image (GIMP_ITEM (source_core->src_drawables->data)) ==
+          gimp_item_get_image (GIMP_ITEM (options->src_drawables->data)) ==
           gimp_item_get_image (GIMP_ITEM (drawables->data)))
         {
           paint_core->use_saved_proj = TRUE;
@@ -297,7 +265,7 @@ gimp_source_core_paint (GimpPaintCore    *paint_core,
     case GIMP_PAINT_STATE_INIT:
       if (source_core->set_source)
         {
-          gimp_source_core_set_src_drawable (source_core, drawables);
+          g_object_set (options, "src-drawables", drawables, NULL);
 
           /* FIXME(?): subpixel source sampling */
           source_core->src_x = floor (coords->x);
@@ -312,8 +280,6 @@ gimp_source_core_paint (GimpPaintCore    *paint_core,
 
           source_core->first_stroke = TRUE;
         }
-
-      gimp_source_core_make_pickable (source_core);
       break;
 
     case GIMP_PAINT_STATE_MOTION:
@@ -450,7 +416,7 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
         {
           GimpImage *src_image;
 
-          src_image = gimp_pickable_get_image (source_core->src_drawables->data);
+          src_image = gimp_pickable_get_image (options->src_drawables->data);
 
           if (! gimp_paint_core_get_show_all (paint_core))
             {
@@ -463,7 +429,7 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
         }
       else
         {
-          src_pickable = source_core->src_pickable;
+          src_pickable = options->src_pickable;
         }
 
       if (GIMP_IS_ITEM (src_pickable))
@@ -671,8 +637,8 @@ gimp_source_core_real_get_source (GimpSourceCore   *source_core,
    *  we get a copy of the unblemished (offset) image
    */
   if ((  sample_merged && (src_image                 != image)) ||
-      (! sample_merged && (g_list_length (source_core->src_drawables) != 1 ||
-                           source_core->src_drawables->data != drawable)))
+      (! sample_merged && (g_list_length (options->src_drawables) != 1 ||
+                           options->src_drawables->data != drawable)))
     {
       dest_buffer = src_buffer;
     }
@@ -695,98 +661,3 @@ gimp_source_core_real_get_source (GimpSourceCore   *source_core,
 
   return g_object_ref (dest_buffer);
 }
-
-static void
-gimp_source_core_src_drawable_removed (GimpDrawable   *drawable,
-                                       GimpSourceCore *source_core)
-{
-  source_core->src_drawables = g_list_remove (source_core->src_drawables, drawable);
-
-  g_signal_handlers_disconnect_by_func (drawable,
-                                        gimp_source_core_src_drawable_removed,
-                                        source_core);
-}
-
-static void
-gimp_source_core_set_src_drawable (GimpSourceCore *source_core,
-                                   GList          *drawables)
-{
-  GimpImage *image = NULL;
-  GList     *iter;
-
-  if (g_list_length (source_core->src_drawables) == g_list_length (drawables))
-    {
-      GList *iter2;
-
-      for (iter = source_core->src_drawables, iter2 = drawables;
-           iter; iter = iter->next, iter2 = iter2->next)
-        {
-          if (iter->data != iter2->data)
-            break;
-        }
-      if (iter == NULL)
-        return;
-    }
-  for (GList *iter = drawables; iter; iter = iter->next)
-    {
-      /* Make sure all drawables are from the same image. */
-      if (image == NULL)
-        image = gimp_item_get_image (GIMP_ITEM (iter->data));
-      else
-        g_return_if_fail (image == gimp_item_get_image (GIMP_ITEM (iter->data)));
-    }
-
-  if (source_core->src_drawables)
-    {
-      for (GList *iter = source_core->src_drawables; iter; iter = iter->next)
-        g_signal_handlers_disconnect_by_func (iter->data,
-                                              gimp_source_core_src_drawable_removed,
-                                              source_core);
-
-      g_list_free (source_core->src_drawables);
-    }
-
-  source_core->src_drawables = g_list_copy (drawables);
-
-  if (source_core->src_drawables)
-    {
-      for (GList *iter = source_core->src_drawables; iter; iter = iter->next)
-        g_signal_connect (iter->data, "removed",
-                          G_CALLBACK (gimp_source_core_src_drawable_removed),
-                          source_core);
-    }
-
-  g_object_notify (G_OBJECT (source_core), "src-drawables");
-}
-
-static void
-gimp_source_core_make_pickable (GimpSourceCore *source_core)
-{
-  g_clear_object (&source_core->src_image);
-  source_core->src_pickable = NULL;
-
-  if (source_core->src_drawables)
-    {
-      GimpImage *image;
-
-      image = gimp_item_get_image (GIMP_ITEM (source_core->src_drawables->data));
-
-      if (g_list_length (source_core->src_drawables) > 1)
-        {
-          /* A composited projection of src_drawables as if they were on
-           * their own in the image. Some kind of sample_merged limited
-           * to these drawables.
-           */
-          source_core->src_image = gimp_image_new_from_drawables (image->gimp, source_core->src_drawables,
-                                                                  FALSE);
-          gimp_container_remove (image->gimp->images, GIMP_OBJECT (source_core->src_image));
-
-          source_core->src_pickable = GIMP_PICKABLE (source_core->src_image);
-          gimp_pickable_flush (source_core->src_pickable);
-        }
-      else
-        {
-          source_core->src_pickable = GIMP_PICKABLE (source_core->src_drawables->data);
-        }
-    }
-}
diff --git a/app/paint/gimpsourcecore.h b/app/paint/gimpsourcecore.h
index f662216ada..9db8032dfe 100644
--- a/app/paint/gimpsourcecore.h
+++ b/app/paint/gimpsourcecore.h
@@ -38,14 +38,9 @@ struct _GimpSourceCore
 
   gboolean       set_source;
 
-  GList         *src_drawables;
   gint           src_x;
   gint           src_y;
 
-  /* The pickable to use when not in sample merged mode. */
-  GimpPickable  *src_pickable;
-  GimpImage     *src_image;
-
   gint           orig_src_x;
   gint           orig_src_y;
 
diff --git a/app/paint/gimpsourceoptions.c b/app/paint/gimpsourceoptions.c
index ba6323491a..db119156ae 100644
--- a/app/paint/gimpsourceoptions.c
+++ b/app/paint/gimpsourceoptions.c
@@ -25,6 +25,13 @@
 
 #include "paint-types.h"
 
+#include "core/gimp.h"
+#include "core/gimpcontainer.h"
+#include "core/gimpimage.h"
+#include "core/gimpimage-new.h"
+#include "core/gimpitem.h"
+#include "core/gimppickable.h"
+
 #include "gimpsourceoptions.h"
 
 #include "gimp-intl.h"
@@ -33,32 +40,50 @@
 enum
 {
   PROP_0,
+  PROP_SRC_DRAWABLES,
   PROP_ALIGN_MODE,
   PROP_SAMPLE_MERGED
 };
 
 
-static void   gimp_source_options_set_property (GObject      *object,
-                                                guint         property_id,
-                                                const GValue *value,
-                                                GParamSpec   *pspec);
-static void   gimp_source_options_get_property (GObject      *object,
-                                                guint         property_id,
-                                                GValue       *value,
-                                                GParamSpec   *pspec);
+static void   gimp_source_options_finalize     (GObject           *object);
+static void   gimp_source_options_set_property (GObject           *object,
+                                                guint              property_id,
+                                                const GValue      *value,
+                                                GParamSpec        *pspec);
+static void   gimp_source_options_get_property (GObject           *object,
+                                                guint              property_id,
+                                                GValue            *value,
+                                                GParamSpec        *pspec);
+
+static void
+         gimp_source_options_set_src_drawables (GimpSourceOptions *options,
+                                                GList             *drawables);
+static void
+      gimp_source_options_src_drawable_removed (GimpDrawable      *drawable,
+                                                GimpSourceOptions *options);
+static void  gimp_source_options_make_pickable (GimpSourceOptions *options);
 
 
 G_DEFINE_TYPE (GimpSourceOptions, gimp_source_options, GIMP_TYPE_PAINT_OPTIONS)
 
+#define parent_class gimp_source_options_parent_class
+
 
 static void
 gimp_source_options_class_init (GimpSourceOptionsClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  object_class->finalize     = gimp_source_options_finalize;
   object_class->set_property = gimp_source_options_set_property;
   object_class->get_property = gimp_source_options_get_property;
 
+  g_object_class_install_property (object_class, PROP_SRC_DRAWABLES,
+                                   g_param_spec_pointer ("src-drawables",
+                                                         NULL, NULL,
+                                                         GIMP_PARAM_READWRITE));
+
   GIMP_CONFIG_PROP_ENUM (object_class, PROP_ALIGN_MODE,
                          "align-mode",
                          _("Alignment"),
@@ -78,6 +103,18 @@ gimp_source_options_class_init (GimpSourceOptionsClass *klass)
 static void
 gimp_source_options_init (GimpSourceOptions *options)
 {
+  options->src_drawables = NULL;
+}
+
+static void
+gimp_source_options_finalize (GObject *object)
+{
+  GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (object);
+
+  gimp_source_options_set_src_drawables (options, NULL);
+  g_clear_object (&options->src_image);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static void
@@ -90,6 +127,10 @@ gimp_source_options_set_property (GObject      *object,
 
   switch (property_id)
     {
+    case PROP_SRC_DRAWABLES:
+      gimp_source_options_set_src_drawables (options,
+                                             g_value_get_pointer (value));
+      break;
     case PROP_ALIGN_MODE:
       options->align_mode = g_value_get_enum (value);
       break;
@@ -112,6 +153,9 @@ gimp_source_options_get_property (GObject    *object,
 
   switch (property_id)
     {
+    case PROP_SRC_DRAWABLES:
+      g_value_set_pointer (value, options->src_drawables);
+      break;
     case PROP_ALIGN_MODE:
       g_value_set_enum (value, options->align_mode);
       break;
@@ -123,3 +167,102 @@ gimp_source_options_get_property (GObject    *object,
       break;
     }
 }
+
+static void
+gimp_source_options_set_src_drawables (GimpSourceOptions *options,
+                                       GList             *drawables)
+{
+  GimpImage *image = NULL;
+  GList     *iter;
+
+  if (g_list_length (options->src_drawables) == g_list_length (drawables))
+    {
+      GList *iter2;
+
+      for (iter = options->src_drawables, iter2 = drawables;
+           iter; iter = iter->next, iter2 = iter2->next)
+        {
+          if (iter->data != iter2->data)
+            break;
+        }
+      if (iter == NULL)
+        return;
+    }
+  for (GList *iter = drawables; iter; iter = iter->next)
+    {
+      /* Make sure all drawables are from the same image. */
+      if (image == NULL)
+        image = gimp_item_get_image (GIMP_ITEM (iter->data));
+      else
+        g_return_if_fail (image == gimp_item_get_image (GIMP_ITEM (iter->data)));
+    }
+
+  if (options->src_drawables)
+    {
+      for (GList *iter = options->src_drawables; iter; iter = iter->next)
+        g_signal_handlers_disconnect_by_func (iter->data,
+                                              gimp_source_options_src_drawable_removed,
+                                              options);
+
+      g_list_free (options->src_drawables);
+    }
+
+  options->src_drawables = g_list_copy (drawables);
+
+  if (options->src_drawables)
+    {
+      for (GList *iter = options->src_drawables; iter; iter = iter->next)
+        g_signal_connect (iter->data, "removed",
+                          G_CALLBACK (gimp_source_options_src_drawable_removed),
+                          options);
+    }
+
+  gimp_source_options_make_pickable (options);
+  g_object_notify (G_OBJECT (options), "src-drawables");
+}
+
+static void
+gimp_source_options_src_drawable_removed (GimpDrawable      *drawable,
+                                          GimpSourceOptions *options)
+{
+  options->src_drawables = g_list_remove (options->src_drawables, drawable);
+
+  g_signal_handlers_disconnect_by_func (drawable,
+                                        gimp_source_options_src_drawable_removed,
+                                        options);
+
+  gimp_source_options_make_pickable (options);
+  g_object_notify (G_OBJECT (options), "src-drawables");
+}
+
+static void
+gimp_source_options_make_pickable (GimpSourceOptions *options)
+{
+  g_clear_object (&options->src_image);
+  options->src_pickable = NULL;
+
+  if (options->src_drawables)
+    {
+      GimpImage *image;
+
+      image = gimp_item_get_image (GIMP_ITEM (options->src_drawables->data));
+
+      if (g_list_length (options->src_drawables) > 1)
+        {
+          /* A composited projection of src_drawables as if they were on
+           * their own in the image. Some kind of sample_merged limited
+           * to these drawables.
+           */
+          options->src_image = gimp_image_new_from_drawables (image->gimp, options->src_drawables,
+                                                                  FALSE);
+          gimp_container_remove (image->gimp->images, GIMP_OBJECT (options->src_image));
+
+          options->src_pickable = GIMP_PICKABLE (options->src_image);
+          gimp_pickable_flush (options->src_pickable);
+        }
+      else
+        {
+          options->src_pickable = GIMP_PICKABLE (options->src_drawables->data);
+        }
+    }
+}
diff --git a/app/paint/gimpsourceoptions.h b/app/paint/gimpsourceoptions.h
index e4e2e2e2c5..a5417b9663 100644
--- a/app/paint/gimpsourceoptions.h
+++ b/app/paint/gimpsourceoptions.h
@@ -36,6 +36,12 @@ struct _GimpSourceOptions
 {
   GimpPaintOptions     parent_instance;
 
+  GList               *src_drawables;
+
+  /* The pickable to use when not in sample merged mode. */
+  GimpPickable        *src_pickable;
+  GimpImage           *src_image;
+
   GimpSourceAlignMode  align_mode;
   gboolean             sample_merged;
 };
diff --git a/app/tools/gimpcloneoptions-gui.c b/app/tools/gimpcloneoptions-gui.c
index fa4fa095ea..0375b7c813 100644
--- a/app/tools/gimpcloneoptions-gui.c
+++ b/app/tools/gimpcloneoptions-gui.c
@@ -26,6 +26,7 @@
 
 #include "core/gimp.h"
 #include "core/gimpimage.h"
+#include "core/gimpitem.h"
 
 #include "paint/gimpcloneoptions.h"
 
@@ -38,6 +39,24 @@
 #include "gimp-intl.h"
 
 
+static gboolean gimp_clone_options_sync_source           (GBinding     *binding,
+                                                          const GValue *source_value,
+                                                          GValue       *target_value,
+                                                          gpointer      user_data);
+
+static void gimp_clone_options_gui_drawables_changed     (GimpImage         *image,
+                                                          GimpSourceOptions *options);
+static void gimp_clone_options_gui_src_changed           (GimpSourceOptions *options,
+                                                          GParamSpec        *pspec,
+                                                          GtkWidget         *label);
+static void gimp_clone_options_gui_context_image_changed (GimpContext       *context,
+                                                          GimpImage         *image,
+                                                          GimpSourceOptions *options);
+
+static void gimp_clone_options_gui_update_src_label       (GimpSourceOptions *options,
+                                                           GtkWidget         *label);
+
+
 static gboolean
 gimp_clone_options_sync_source (GBinding     *binding,
                                 const GValue *source_value,
@@ -53,39 +72,55 @@ gimp_clone_options_sync_source (GBinding     *binding,
 }
 
 static void
-gimp_clone_options_gui_drawables_changed (GimpImage *image,
-                                          GtkWidget *button)
+gimp_clone_options_gui_drawables_changed (GimpImage         *image,
+                                          GimpSourceOptions *options)
 {
-  GList *drawables;
+  GList     *drawables;
+  GtkWidget *button;
 
   drawables = gimp_image_get_selected_drawables (image);
+  button    = g_object_get_data (G_OBJECT (options), "sample-merged-checkbox");
+
   gtk_widget_set_sensitive (button, (g_list_length (drawables) < 2));
   g_list_free (drawables);
+
+  gimp_clone_options_gui_update_src_label (options, NULL);
+}
+
+static void
+gimp_clone_options_gui_src_changed (GimpSourceOptions *options,
+                                    GParamSpec        *pspec,
+                                    GtkWidget         *label)
+{
+  gimp_clone_options_gui_update_src_label (options, label);
 }
 
 static void
-gimp_clone_options_gui_context_image_changed (GimpContext *context,
-                                              GimpImage   *image,
-                                              GtkWidget   *button)
+gimp_clone_options_gui_context_image_changed (GimpContext       *context,
+                                              GimpImage         *image,
+                                              GimpSourceOptions *options)
 {
   GimpImage *prev_image;
+  GtkWidget *button;
 
+  button     = g_object_get_data (G_OBJECT (options), "sample-merged-checkbox");
   prev_image = g_object_get_data (G_OBJECT (button), "gimp-clone-options-gui-image");
+
   if (image != prev_image)
     {
       if (prev_image)
         g_signal_handlers_disconnect_by_func (prev_image,
                                               G_CALLBACK (gimp_clone_options_gui_drawables_changed),
-                                              button);
+                                              options);
       if (image)
         {
           g_signal_connect_object (image, "selected-channels-changed",
                                    G_CALLBACK (gimp_clone_options_gui_drawables_changed),
-                                   button, 0);
+                                   options, 0);
           g_signal_connect_object (image, "selected-layers-changed",
                                    G_CALLBACK (gimp_clone_options_gui_drawables_changed),
-                                   button, 0);
-          gimp_clone_options_gui_drawables_changed (image, button);
+                                   options, 0);
+          gimp_clone_options_gui_drawables_changed (image, options);
         }
       else
         {
@@ -96,20 +131,98 @@ gimp_clone_options_gui_context_image_changed (GimpContext *context,
     }
 }
 
+static void
+gimp_clone_options_gui_update_src_label (GimpSourceOptions *options,
+                                         GtkWidget         *label)
+{
+  gchar *markup = NULL;
+
+  if (! label)
+    label = g_object_get_data (G_OBJECT (options), "src-label");
+
+  if (options->src_drawables == NULL)
+    {
+      markup = g_strdup_printf ("<i>%s</i>", _("No source selected"));
+    }
+  else
+    {
+      GimpImage *image;
+      GList     *drawables;
+      gchar     *str = NULL;
+      gboolean   sample_merged;
+
+      image = gimp_context_get_image (gimp_get_user_context (GIMP_CONTEXT (options)->gimp));
+      drawables = gimp_image_get_selected_drawables (image);
+
+      sample_merged = options->sample_merged && g_list_length (drawables) == 1;
+
+      if (g_list_length (drawables) > 1)
+        {
+          str = g_strdup_printf (ngettext ("Source: %d item to itself",
+                                           "Source: %d items to themselves",
+                                           g_list_length (drawables)),
+                                 g_list_length (drawables));
+        }
+      else
+        {
+          GimpImage *src_image = NULL;
+
+          src_image = gimp_item_get_image (options->src_drawables->data);
+
+          if (sample_merged)
+            {
+              if (image == src_image)
+                str = g_strdup (_("All composited visible layers"));
+              else
+                str = g_strdup_printf (_("All composited visible layers from '%s'"),
+                                       gimp_image_get_display_name (src_image));
+            }
+          else
+            {
+              if (image == src_image)
+                str = g_strdup_printf (ngettext ("Source: %d item",
+                                                 "Source: %d items",
+                                                 g_list_length (options->src_drawables)),
+                                       g_list_length (options->src_drawables));
+              else
+                str = g_strdup_printf (ngettext ("Source: %d item from '%s'",
+                                                 "Source: %d items from '%s'",
+                                                 g_list_length (options->src_drawables)),
+                                       g_list_length (options->src_drawables),
+                                       gimp_image_get_display_name (src_image));
+            }
+        }
+      markup = g_strdup_printf ("<i>%s</i>", str);
+
+      g_list_free (drawables);
+      g_free (str);
+    }
+
+  gtk_label_set_markup (GTK_LABEL (label), markup);
+  g_free (markup);
+}
+
+
+/* Public functions. */
+
+
 GtkWidget *
 gimp_clone_options_gui (GimpToolOptions *tool_options)
 {
   GObject   *config = G_OBJECT (tool_options);
   GtkWidget *vbox   = gimp_paint_options_gui (tool_options);
   GtkWidget *frame;
+  GtkWidget *label;
   GtkWidget *combo;
   GtkWidget *source_vbox;
   GtkWidget *button;
   GtkWidget *hbox;
+  gchar     *str;
 
   /*  the source frame  */
   frame = gimp_frame_new (NULL);
   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  gtk_box_reorder_child (GTK_BOX (vbox), frame, 2);
   gtk_widget_show (frame);
 
   /*  the source type menu  */
@@ -123,6 +236,7 @@ gimp_clone_options_gui (GimpToolOptions *tool_options)
   gtk_widget_show (source_vbox);
 
   button = gimp_prop_check_button_new (config, "sample-merged", NULL);
+  g_object_set_data (G_OBJECT (tool_options), "sample-merged-checkbox", button);
   gtk_box_pack_start (GTK_BOX (source_vbox), button, FALSE, FALSE, 0);
 
   g_object_bind_property_full (config, "clone-type",
@@ -132,10 +246,26 @@ gimp_clone_options_gui (GimpToolOptions *tool_options)
                                NULL,
                                GINT_TO_POINTER (GIMP_CLONE_IMAGE), NULL);
 
+  label = gtk_label_new (NULL);
+  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+  str = g_strdup_printf ("<i>%s</i>", _("No source selected"));
+  gtk_label_set_markup (GTK_LABEL (label), str);
+  g_object_set_data (G_OBJECT (tool_options), "src-label", label);
+  g_free (str);
+
+  gtk_box_pack_start (GTK_BOX (source_vbox), label, FALSE, FALSE, 0);
+
+  g_object_bind_property_full (config, "clone-type",
+                               label,  "visible",
+                               G_BINDING_SYNC_CREATE,
+                               gimp_clone_options_sync_source,
+                               NULL,
+                               GINT_TO_POINTER (GIMP_CLONE_IMAGE), NULL);
+
   g_signal_connect (gimp_get_user_context (GIMP_CONTEXT (tool_options)->gimp),
                     "image-changed",
                     G_CALLBACK (gimp_clone_options_gui_context_image_changed),
-                    button);
+                    tool_options);
 
   hbox = gimp_prop_pattern_box_new (NULL, GIMP_CONTEXT (tool_options),
                                     NULL, 2,
@@ -153,6 +283,16 @@ gimp_clone_options_gui (GimpToolOptions *tool_options)
   gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (combo), _("Alignment"));
   g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
   gtk_box_pack_start (GTK_BOX (vbox), combo, TRUE, TRUE, 0);
+  gtk_box_reorder_child (GTK_BOX (vbox), combo, 3);
+
+  /* A few options which can trigger a change in the source label. */
+  g_signal_connect (config, "notify::src-drawables",
+                    G_CALLBACK (gimp_clone_options_gui_src_changed),
+                    label);
+  g_signal_connect (config, "notify::sample-merged",
+                    G_CALLBACK (gimp_clone_options_gui_src_changed),
+                    label);
+  gimp_clone_options_gui_src_changed (GIMP_SOURCE_OPTIONS (config), NULL, label);
 
   return vbox;
 }
diff --git a/app/tools/gimpperspectiveclonetool.c b/app/tools/gimpperspectiveclonetool.c
index 14ecbd086e..00c6132b0f 100644
--- a/app/tools/gimpperspectiveclonetool.c
+++ b/app/tools/gimpperspectiveclonetool.c
@@ -563,7 +563,7 @@ gimp_perspective_clone_tool_cursor_update (GimpTool         *tool,
         {
           cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
         }
-      else if (! GIMP_SOURCE_CORE (GIMP_PAINT_TOOL (tool)->core)->src_drawables)
+      else if (! GIMP_SOURCE_OPTIONS (options)->src_drawables)
         {
           modifier = GIMP_CURSOR_MODIFIER_BAD;
         }
@@ -621,7 +621,7 @@ gimp_perspective_clone_tool_oper_update (GimpTool         *tool,
           GimpPerspectiveClone *clone       = GIMP_PERSPECTIVE_CLONE (core);
           GimpSourceCore       *source_core = GIMP_SOURCE_CORE (core);
 
-          if (source_core->src_drawables == NULL)
+          if (GIMP_SOURCE_OPTIONS (options)->src_drawables == NULL)
             {
               gimp_tool_replace_status (tool, display,
                                         _("Ctrl-Click to set a clone source"));
@@ -708,8 +708,6 @@ gimp_perspective_clone_tool_draw (GimpDrawTool *draw_tool)
 {
   GimpTool                    *tool        = GIMP_TOOL (draw_tool);
   GimpPerspectiveCloneTool    *clone_tool  = GIMP_PERSPECTIVE_CLONE_TOOL (draw_tool);
-  GimpPerspectiveClone        *clone       = GIMP_PERSPECTIVE_CLONE (GIMP_PAINT_TOOL (tool)->core);
-  GimpSourceCore              *source_core = GIMP_SOURCE_CORE (clone);
   GimpPerspectiveCloneOptions *options;
 
   options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
@@ -756,7 +754,7 @@ gimp_perspective_clone_tool_draw (GimpDrawTool *draw_tool)
       gimp_draw_tool_pop_group (draw_tool);
     }
 
-  if (source_core->src_drawables && clone_tool->src_display)
+  if (GIMP_SOURCE_OPTIONS (options)->src_drawables && clone_tool->src_display)
     {
       GimpDisplay *tmp_display;
 
@@ -780,11 +778,14 @@ gimp_perspective_clone_tool_draw (GimpDrawTool *draw_tool)
 static void
 gimp_perspective_clone_tool_halt (GimpPerspectiveCloneTool *clone_tool)
 {
-  GimpTool *tool = GIMP_TOOL (clone_tool);
+  GimpTool                    *tool = GIMP_TOOL (clone_tool);
+  GimpPerspectiveCloneOptions *options;
+
+  options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
 
   clone_tool->src_display = NULL;
 
-  g_object_set (GIMP_PAINT_TOOL (tool)->core,
+  g_object_set (options,
                 "src-drawables", NULL,
                 NULL);
 
diff --git a/app/tools/gimpsourcetool.c b/app/tools/gimpsourcetool.c
index 34f505e627..d27252462c 100644
--- a/app/tools/gimpsourcetool.c
+++ b/app/tools/gimpsourcetool.c
@@ -157,7 +157,8 @@ gimp_source_tool_control (GimpTool       *tool,
                           GimpToolAction  action,
                           GimpDisplay    *display)
 {
-  GimpSourceTool *source_tool = GIMP_SOURCE_TOOL (tool);
+  GimpSourceTool    *source_tool = GIMP_SOURCE_TOOL (tool);
+  GimpSourceOptions *options     = GIMP_SOURCE_TOOL_GET_OPTIONS (tool);
 
   switch (action)
     {
@@ -167,7 +168,7 @@ gimp_source_tool_control (GimpTool       *tool,
 
     case GIMP_TOOL_ACTION_HALT:
       gimp_source_tool_set_src_display (source_tool, NULL);
-      g_object_set (GIMP_PAINT_TOOL (tool)->core,
+      g_object_set (options,
                     "src-drawables", NULL,
                     NULL);
       break;
@@ -302,7 +303,7 @@ gimp_source_tool_cursor_update (GimpTool         *tool,
         {
           cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
         }
-      else if (! GIMP_SOURCE_CORE (GIMP_PAINT_TOOL (tool)->core)->src_drawables)
+      else if (! options->src_drawables)
         {
           modifier = GIMP_CURSOR_MODIFIER_BAD;
         }
@@ -341,7 +342,7 @@ gimp_source_tool_oper_update (GimpTool         *tool,
 
   if (gimp_source_core_use_source (source, options))
     {
-      if (source->src_drawables == NULL)
+      if (options->src_drawables == NULL)
         {
           GdkModifierType toggle_mask = gimp_get_toggle_behavior_mask ();
 
@@ -400,7 +401,7 @@ gimp_source_tool_draw (GimpDrawTool *draw_tool)
   GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
 
   if (gimp_source_core_use_source (source, options) &&
-      source->src_drawables && source_tool->src_display)
+      options->src_drawables && source_tool->src_display)
     {
       GimpDisplayShell *src_shell;
       gdouble           src_x;


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