[gimp] app: add ability to clone/heal from/on multiple layers.



commit b4d189f8efadb58aa12ddd0f698f429869acc6be
Author: Jehan <jehan girinstud io>
Date:   Wed Aug 18 14:23:30 2021 +0200

    app: add ability to clone/heal from/on multiple layers.
    
    When multiple layers are selected, the "sample merged" button won't
    work. In such a context, each selected layer will pick from itself into
    itself.

 app/paint/gimpperspectiveclone.c | 18 +++++++++-----
 app/paint/gimpsourcecore.c       | 30 ++++++++++++++++++-----
 app/paint/gimpsourcecore.h       |  2 ++
 app/tools/gimpcloneoptions-gui.c | 52 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 90 insertions(+), 12 deletions(-)
---
diff --git a/app/paint/gimpperspectiveclone.c b/app/paint/gimpperspectiveclone.c
index 17fb600d88..1759e87240 100644
--- a/app/paint/gimpperspectiveclone.c
+++ b/app/paint/gimpperspectiveclone.c
@@ -58,6 +58,7 @@ static gboolean     gimp_perspective_clone_use_source (GimpSourceCore    *source
 static GeglBuffer * gimp_perspective_clone_get_source (GimpSourceCore    *source_core,
                                                        GimpDrawable      *drawable,
                                                        GimpPaintOptions  *paint_options,
+                                                       gboolean           self_drawable,
                                                        GimpPickable      *src_pickable,
                                                        gint               src_offset_x,
                                                        gint               src_offset_y,
@@ -131,9 +132,12 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
   GimpCloneOptions     *clone_options = GIMP_CLONE_OPTIONS (paint_options);
   GimpSourceOptions    *options       = GIMP_SOURCE_OPTIONS (paint_options);
   const GimpCoords     *coords;
+  gboolean              sample_merged;
 
   /* The source is based on the original stroke */
-  coords = gimp_symmetry_get_origin (sym);
+  coords        = gimp_symmetry_get_origin (sym);
+
+  sample_merged = options->sample_merged && (g_list_length (drawables) > 1);
 
   switch (paint_state)
     {
@@ -191,21 +195,21 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                 src_pickable = GIMP_PICKABLE (source_core->src_drawable);
                 src_image    = gimp_pickable_get_image (src_pickable);
 
-                if (options->sample_merged)
+                if (sample_merged)
                   src_pickable = GIMP_PICKABLE (src_image);
 
                 dest_image = gimp_item_get_image (GIMP_ITEM (drawables->data));
 
-                if ((options->sample_merged &&
+                if ((sample_merged &&
                      (src_image != dest_image)) ||
-                    (! options->sample_merged &&
+                    (! sample_merged &&
                      (source_core->src_drawable != drawables->data)))
                   {
                     orig_buffer = gimp_pickable_get_buffer (src_pickable);
                   }
                 else
                   {
-                    if (options->sample_merged)
+                    if (sample_merged)
                       orig_buffer = gimp_paint_core_get_orig_proj (paint_core);
                     else
                       orig_buffer = gimp_paint_core_get_orig_image (paint_core, drawables->data);
@@ -327,7 +331,8 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
             }
 
           for (GList *iter = drawables; iter; iter = iter->next)
-            gimp_source_core_motion (source_core, iter->data, paint_options, sym);
+            gimp_source_core_motion (source_core, iter->data, paint_options,
+                                     (g_list_length (drawables) > 1), sym);
         }
       break;
 
@@ -357,6 +362,7 @@ static GeglBuffer *
 gimp_perspective_clone_get_source (GimpSourceCore   *source_core,
                                    GimpDrawable     *drawable,
                                    GimpPaintOptions *paint_options,
+                                   gboolean          self_drawable,
                                    GimpPickable     *src_pickable,
                                    gint              src_offset_x,
                                    gint              src_offset_y,
diff --git a/app/paint/gimpsourcecore.c b/app/paint/gimpsourcecore.c
index 1f891a55be..9a6e705599 100644
--- a/app/paint/gimpsourcecore.c
+++ b/app/paint/gimpsourcecore.c
@@ -75,6 +75,7 @@ static void     gimp_source_core_paint           (GimpPaintCore     *paint_core,
 static void     gimp_source_core_motion          (GimpSourceCore    *source_core,
                                                   GimpDrawable      *drawable,
                                                   GimpPaintOptions  *paint_options,
+                                                  gboolean           self_drawable,
                                                   GimpSymmetry      *sym);
 #endif
 
@@ -84,6 +85,7 @@ static GeglBuffer *
                 gimp_source_core_real_get_source (GimpSourceCore    *source_core,
                                                   GimpDrawable      *drawable,
                                                   GimpPaintOptions  *paint_options,
+                                                  gboolean           self_drawable,
                                                   GimpPickable      *src_pickable,
                                                   gint               src_offset_x,
                                                   gint               src_offset_y,
@@ -240,7 +242,8 @@ gimp_source_core_start (GimpPaintCore     *paint_core,
           return FALSE;
         }
 
-      if (options->sample_merged &&
+      if (options->sample_merged         &&
+          g_list_length (drawables) == 1 &&
           gimp_item_get_image (GIMP_ITEM (source_core->src_drawable)) ==
           gimp_item_get_image (GIMP_ITEM (drawables->data)))
         {
@@ -331,7 +334,9 @@ gimp_source_core_paint (GimpPaintCore    *paint_core,
 
           for (GList *iter = drawables; iter; iter = iter->next)
             gimp_source_core_motion (source_core, iter->data,
-                                     paint_options, sym);
+                                     paint_options,
+                                     (g_list_length (drawables) > 1),
+                                     sym);
         }
       break;
 
@@ -356,6 +361,7 @@ void
 gimp_source_core_motion (GimpSourceCore   *source_core,
                          GimpDrawable     *drawable,
                          GimpPaintOptions *paint_options,
+                         gboolean          self_drawable,
                          GimpSymmetry     *sym)
 
 {
@@ -407,7 +413,11 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
     {
       src_pickable = GIMP_PICKABLE (source_core->src_drawable);
 
-      if (options->sample_merged)
+      if (self_drawable)
+        {
+          src_pickable = GIMP_PICKABLE (drawable);
+        }
+      else if (options->sample_merged)
         {
           GimpImage *src_image = gimp_pickable_get_image (src_pickable);
           gint       off_x, off_y;
@@ -470,6 +480,7 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
             GIMP_SOURCE_CORE_GET_CLASS (source_core)->get_source (source_core,
                                                                   drawable,
                                                                   paint_options,
+                                                                  self_drawable,
                                                                   src_pickable,
                                                                   src_offset_x,
                                                                   src_offset_y,
@@ -579,6 +590,7 @@ static GeglBuffer *
 gimp_source_core_real_get_source (GimpSourceCore   *source_core,
                                   GimpDrawable     *drawable,
                                   GimpPaintOptions *paint_options,
+                                  gboolean          self_drawable,
                                   GimpPickable     *src_pickable,
                                   gint              src_offset_x,
                                   gint              src_offset_y,
@@ -596,9 +608,15 @@ gimp_source_core_real_get_source (GimpSourceCore   *source_core,
   GimpImage         *src_image  = gimp_pickable_get_image (src_pickable);
   GeglBuffer        *src_buffer = gimp_pickable_get_buffer (src_pickable);
   GeglBuffer        *dest_buffer;
+  gboolean           sample_merged;
   gint               x, y;
   gint               width, height;
 
+  /* As a special case, we bypass sample merged value when we request
+   * each drawable to be its own source.
+   */
+  sample_merged = options->sample_merged && (! self_drawable);
+
   if (! gimp_rectangle_intersect (paint_buffer_x + src_offset_x,
                                   paint_buffer_y + src_offset_y,
                                   gegl_buffer_get_width  (paint_buffer),
@@ -619,15 +637,15 @@ gimp_source_core_real_get_source (GimpSourceCore   *source_core,
    *  Otherwise, we need a call to get_orig_image to make sure
    *  we get a copy of the unblemished (offset) image
    */
-  if ((  options->sample_merged && (src_image                 != image)) ||
-      (! options->sample_merged && (source_core->src_drawable != drawable)))
+  if ((  sample_merged && (src_image                 != image)) ||
+      (! sample_merged && (source_core->src_drawable != drawable)))
     {
       dest_buffer = src_buffer;
     }
   else
     {
       /*  get the original image  */
-      if (options->sample_merged)
+      if (sample_merged)
         dest_buffer = gimp_paint_core_get_orig_proj (GIMP_PAINT_CORE (source_core));
       else
         dest_buffer = gimp_paint_core_get_orig_image (GIMP_PAINT_CORE (source_core),
diff --git a/app/paint/gimpsourcecore.h b/app/paint/gimpsourcecore.h
index 158920b61d..6954e44a86 100644
--- a/app/paint/gimpsourcecore.h
+++ b/app/paint/gimpsourcecore.h
@@ -60,6 +60,7 @@ struct _GimpSourceCoreClass
   GeglBuffer * (* get_source) (GimpSourceCore    *source_core,
                                GimpDrawable      *drawable,
                                GimpPaintOptions  *paint_options,
+                               gboolean           self_drawable,
                                GimpPickable      *src_pickable,
                                gint               src_offset_x,
                                gint               src_offset_y,
@@ -104,6 +105,7 @@ gboolean gimp_source_core_use_source (GimpSourceCore    *source_core,
 void     gimp_source_core_motion     (GimpSourceCore    *source_core,
                                       GimpDrawable      *drawable,
                                       GimpPaintOptions  *paint_options,
+                                      gboolean           self_drawable,
                                       GimpSymmetry      *sym);
 
 
diff --git a/app/tools/gimpcloneoptions-gui.c b/app/tools/gimpcloneoptions-gui.c
index 4299aeea5b..fa4fa095ea 100644
--- a/app/tools/gimpcloneoptions-gui.c
+++ b/app/tools/gimpcloneoptions-gui.c
@@ -24,6 +24,9 @@
 
 #include "tools-types.h"
 
+#include "core/gimp.h"
+#include "core/gimpimage.h"
+
 #include "paint/gimpcloneoptions.h"
 
 #include "widgets/gimpviewablebox.h"
@@ -49,6 +52,50 @@ gimp_clone_options_sync_source (GBinding     *binding,
   return TRUE;
 }
 
+static void
+gimp_clone_options_gui_drawables_changed (GimpImage *image,
+                                          GtkWidget *button)
+{
+  GList *drawables;
+
+  drawables = gimp_image_get_selected_drawables (image);
+  gtk_widget_set_sensitive (button, (g_list_length (drawables) < 2));
+  g_list_free (drawables);
+}
+
+static void
+gimp_clone_options_gui_context_image_changed (GimpContext *context,
+                                              GimpImage   *image,
+                                              GtkWidget   *button)
+{
+  GimpImage *prev_image;
+
+  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);
+      if (image)
+        {
+          g_signal_connect_object (image, "selected-channels-changed",
+                                   G_CALLBACK (gimp_clone_options_gui_drawables_changed),
+                                   button, 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);
+        }
+      else
+        {
+          gtk_widget_set_sensitive (button, TRUE);
+        }
+
+      g_object_set_data (G_OBJECT (button), "gimp-clone-options-gui-image", image);
+    }
+}
+
 GtkWidget *
 gimp_clone_options_gui (GimpToolOptions *tool_options)
 {
@@ -85,6 +132,11 @@ gimp_clone_options_gui (GimpToolOptions *tool_options)
                                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);
+
   hbox = gimp_prop_pattern_box_new (NULL, GIMP_CONTEXT (tool_options),
                                     NULL, 2,
                                     "pattern-view-type", "pattern-view-size");


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