[gimp] app, pdb: properly save the list of source drawables.



commit 3a9462b219420c4fcb4d91e40ca4baf29289c3ad
Author: Jehan <jehan girinstud io>
Date:   Wed Aug 18 23:04:11 2021 +0200

    app, pdb: properly save the list of source drawables.
    
    By doing this, I also add the ability to use a composited projection of
    the selected drawables as source. This is similar to "Sample merged"
    except that instead of using the whole visible image, we use what would
    have been visible if only the selected layers existed.
    
    Note that this doesn't work together with the previously added ability
    of multi-cloning from each layer to itself. This ability works for
    cloning from multiple layers to one.

 app/paint/gimpperspectiveclone.c     |   4 +-
 app/paint/gimpsourcecore.c           | 179 ++++++++++++++++++++++++-----------
 app/paint/gimpsourcecore.h           |   6 +-
 app/pdb/paint-tools-cmds.c           |  24 +++--
 app/tools/gimpperspectiveclonetool.c |   8 +-
 app/tools/gimpsourcetool.c           |  16 ++--
 pdb/groups/paint_tools.pdb           |  24 +++--
 7 files changed, 175 insertions(+), 86 deletions(-)
---
diff --git a/app/paint/gimpperspectiveclone.c b/app/paint/gimpperspectiveclone.c
index 1759e87240..29bf79d91a 100644
--- a/app/paint/gimpperspectiveclone.c
+++ b/app/paint/gimpperspectiveclone.c
@@ -144,7 +144,7 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
     case GIMP_PAINT_STATE_INIT:
       if (source_core->set_source)
         {
-          g_object_set (source_core, "src-drawable", drawables->data, NULL);
+          g_object_set (source_core, "src-drawables", drawables, NULL);
 
           source_core->src_x = floor (coords->x);
           source_core->src_y = floor (coords->y);
@@ -192,7 +192,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_pickable = GIMP_PICKABLE (source_core->src_drawable);
+                src_pickable = GIMP_PICKABLE (source_core->src_drawables->data);
                 src_image    = gimp_pickable_get_image (src_pickable);
 
                 if (sample_merged)
diff --git a/app/paint/gimpsourcecore.c b/app/paint/gimpsourcecore.c
index 9a6e705599..151a3beb31 100644
--- a/app/paint/gimpsourcecore.c
+++ b/app/paint/gimpsourcecore.c
@@ -28,10 +28,12 @@
 #include "gegl/gimp-gegl-utils.h"
 
 #include "core/gimp.h"
+#include "core/gimpcontainer.h"
 #include "core/gimpdrawable.h"
 #include "core/gimpdynamics.h"
 #include "core/gimperror.h"
 #include "core/gimpimage.h"
+#include "core/gimpimage-new.h"
 #include "core/gimppickable.h"
 #include "core/gimpsymmetry.h"
 
@@ -44,12 +46,13 @@
 enum
 {
   PROP_0,
-  PROP_SRC_DRAWABLE,
+  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,
@@ -99,7 +102,8 @@ static GeglBuffer *
                                                   GeglRectangle     *src_rect);
 
 static void    gimp_source_core_set_src_drawable (GimpSourceCore    *source_core,
-                                                  GimpDrawable      *drawable);
+                                                  GList             *drawables);
+static void    gimp_source_core_make_pickable    (GimpSourceCore    *source_core);
 
 
 G_DEFINE_TYPE (GimpSourceCore, gimp_source_core, GIMP_TYPE_BRUSH_CORE)
@@ -114,6 +118,7 @@ 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;
 
@@ -126,11 +131,10 @@ 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_DRAWABLE,
-                                   g_param_spec_object ("src-drawable",
-                                                        NULL, NULL,
-                                                        GIMP_TYPE_DRAWABLE,
-                                                        GIMP_PARAM_READWRITE));
+  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,
@@ -148,18 +152,29 @@ gimp_source_core_class_init (GimpSourceCoreClass *klass)
 static void
 gimp_source_core_init (GimpSourceCore *source_core)
 {
-  source_core->set_source   = FALSE;
+  source_core->set_source    = FALSE;
 
-  source_core->src_drawable = NULL;
-  source_core->src_x        = 0;
-  source_core->src_y        = 0;
+  source_core->src_drawables = NULL;
+  source_core->src_x         = 0;
+  source_core->src_y         = 0;
 
-  source_core->orig_src_x   = 0;
-  source_core->orig_src_y   = 0;
+  source_core->orig_src_x    = 0;
+  source_core->orig_src_y    = 0;
 
-  source_core->offset_x     = 0;
-  source_core->offset_y     = 0;
-  source_core->first_stroke = TRUE;
+  source_core->offset_x      = 0;
+  source_core->offset_y      = 0;
+  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
@@ -172,9 +187,9 @@ gimp_source_core_set_property (GObject      *object,
 
   switch (property_id)
     {
-    case PROP_SRC_DRAWABLE:
+    case PROP_SRC_DRAWABLES:
       gimp_source_core_set_src_drawable (source_core,
-                                         g_value_get_object (value));
+                                         g_value_get_pointer (value));
       break;
     case PROP_SRC_X:
       source_core->src_x = g_value_get_int (value);
@@ -198,8 +213,8 @@ gimp_source_core_get_property (GObject    *object,
 
   switch (property_id)
     {
-    case PROP_SRC_DRAWABLE:
-      g_value_set_object (value, source_core->src_drawable);
+    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);
@@ -235,7 +250,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_drawable)
+      if (! source_core->src_drawables)
         {
           g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
                                _("Set a source image first."));
@@ -244,7 +259,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_drawable)) ==
+          gimp_item_get_image (GIMP_ITEM (source_core->src_drawables->data)) ==
           gimp_item_get_image (GIMP_ITEM (drawables->data)))
         {
           paint_core->use_saved_proj = TRUE;
@@ -274,7 +289,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->data);
+          gimp_source_core_set_src_drawable (source_core, drawables);
 
           /* FIXME(?): subpixel source sampling */
           source_core->src_x = floor (coords->x);
@@ -289,6 +304,8 @@ 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:
@@ -411,16 +428,15 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
 
   if (gimp_source_core_use_source (source_core, options))
     {
-      src_pickable = GIMP_PICKABLE (source_core->src_drawable);
-
       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;
+          GimpImage *src_image;
+
+          src_image = gimp_pickable_get_image (source_core->src_drawables->data);
 
           if (! gimp_paint_core_get_show_all (paint_core))
             {
@@ -428,15 +444,12 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
             }
           else
             {
-              src_pickable = GIMP_PICKABLE (
-                gimp_image_get_projection (src_image));
+              src_pickable = GIMP_PICKABLE (gimp_image_get_projection (src_image));
             }
-
-          gimp_item_get_offset (GIMP_ITEM (source_core->src_drawable),
-                                &off_x, &off_y);
-
-          base_src_offset_x += off_x;
-          base_src_offset_y += off_y;
+        }
+      else
+        {
+          src_pickable = source_core->src_pickable;
         }
     }
 
@@ -638,7 +651,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 && (source_core->src_drawable != drawable)))
+      (! sample_merged && (g_list_length (source_core->src_drawables) != 1 ||
+                           source_core->src_drawables->data != drawable)))
     {
       dest_buffer = src_buffer;
     }
@@ -666,10 +680,7 @@ static void
 gimp_source_core_src_drawable_removed (GimpDrawable   *drawable,
                                        GimpSourceCore *source_core)
 {
-  if (drawable == source_core->src_drawable)
-    {
-      source_core->src_drawable = NULL;
-    }
+  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,
@@ -678,22 +689,84 @@ gimp_source_core_src_drawable_removed (GimpDrawable   *drawable,
 
 static void
 gimp_source_core_set_src_drawable (GimpSourceCore *source_core,
-                                   GimpDrawable   *drawable)
+                                   GList          *drawables)
 {
-  if (source_core->src_drawable == drawable)
-    return;
+  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);
 
-  if (source_core->src_drawable)
-    g_signal_handlers_disconnect_by_func (source_core->src_drawable,
-                                          gimp_source_core_src_drawable_removed,
-                                          source_core);
+      g_list_free (source_core->src_drawables);
+    }
+
+  source_core->src_drawables = g_list_copy (drawables);
 
-  source_core->src_drawable = drawable;
+  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);
+    }
 
-  if (source_core->src_drawable)
-    g_signal_connect (source_core->src_drawable, "removed",
-                      G_CALLBACK (gimp_source_core_src_drawable_removed),
-                      source_core);
+  g_object_notify (G_OBJECT (source_core), "src-drawables");
+}
 
-  g_object_notify (G_OBJECT (source_core), "src-drawable");
+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 6954e44a86..f662216ada 100644
--- a/app/paint/gimpsourcecore.h
+++ b/app/paint/gimpsourcecore.h
@@ -38,10 +38,14 @@ struct _GimpSourceCore
 
   gboolean       set_source;
 
-  GimpDrawable  *src_drawable;
+  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/pdb/paint-tools-cmds.c b/app/pdb/paint-tools-cmds.c
index f37a72e737..c8a1ae7ba2 100644
--- a/app/pdb/paint-tools-cmds.c
+++ b/app/pdb/paint-tools-cmds.c
@@ -228,7 +228,10 @@ clone_invoker (GimpProcedure         *procedure,
                                      GIMP_PDB_ITEM_CONTENT, error) &&
           gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
         {
+          GList *src_drawables;
+
           options = gimp_config_duplicate (GIMP_CONFIG (options));
+          src_drawables = g_list_prepend (NULL, src_drawable);
 
           g_object_set (options,
                         "clone-type", clone_type,
@@ -236,11 +239,12 @@ clone_invoker (GimpProcedure         *procedure,
 
           success = paint_tools_stroke (gimp, context, options, drawable,
                                         num_strokes, strokes, error,
-                                        "undo-desc",    options->paint_info->blurb,
-                                        "src-drawable", src_drawable,
-                                        "src-x",        (gint) floor (src_x),
-                                        "src-y",        (gint) floor (src_y),
+                                        "undo-desc",     options->paint_info->blurb,
+                                        "src-drawables", src_drawables,
+                                        "src-x",         (gint) floor (src_x),
+                                        "src-y",         (gint) floor (src_y),
                                         NULL);
+          g_list_free (src_drawables);
         }
       else
         success = FALSE;
@@ -615,15 +619,19 @@ heal_invoker (GimpProcedure         *procedure,
                                      GIMP_PDB_ITEM_CONTENT, error) &&
           gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
         {
+          GList *src_drawables;
+
           options = gimp_config_duplicate (GIMP_CONFIG (options));
+          src_drawables = g_list_prepend (NULL, src_drawable);
 
           success = paint_tools_stroke (gimp, context, options, drawable,
                                         num_strokes, strokes, error,
-                                        "undo-desc",    options->paint_info->blurb,
-                                        "src-drawable", src_drawable,
-                                        "src-x",        (gint) floor (src_x),
-                                        "src-y",        (gint) floor (src_y),
+                                        "undo-desc",     options->paint_info->blurb,
+                                        "src-drawables", src_drawables,
+                                        "src-x",         (gint) floor (src_x),
+                                        "src-y",         (gint) floor (src_y),
                                         NULL);
+          g_list_free (src_drawables);
         }
       else
         success = FALSE;
diff --git a/app/tools/gimpperspectiveclonetool.c b/app/tools/gimpperspectiveclonetool.c
index b59d3a9869..f1567eadaa 100644
--- a/app/tools/gimpperspectiveclonetool.c
+++ b/app/tools/gimpperspectiveclonetool.c
@@ -566,7 +566,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_drawable)
+      else if (! GIMP_SOURCE_CORE (GIMP_PAINT_TOOL (tool)->core)->src_drawables)
         {
           modifier = GIMP_CURSOR_MODIFIER_BAD;
         }
@@ -624,7 +624,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_drawable == NULL)
+          if (source_core->src_drawables == NULL)
             {
               gimp_tool_replace_status (tool, display,
                                         _("Ctrl-Click to set a clone source"));
@@ -759,7 +759,7 @@ gimp_perspective_clone_tool_draw (GimpDrawTool *draw_tool)
       gimp_draw_tool_pop_group (draw_tool);
     }
 
-  if (source_core->src_drawable && clone_tool->src_display)
+  if (source_core->src_drawables && clone_tool->src_display)
     {
       GimpDisplay *tmp_display;
 
@@ -788,7 +788,7 @@ gimp_perspective_clone_tool_halt (GimpPerspectiveCloneTool *clone_tool)
   clone_tool->src_display = NULL;
 
   g_object_set (GIMP_PAINT_TOOL (tool)->core,
-                "src-drawable", NULL,
+                "src-drawables", NULL,
                 NULL);
 
   if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tool)))
diff --git a/app/tools/gimpsourcetool.c b/app/tools/gimpsourcetool.c
index b2c5f6d44d..34f505e627 100644
--- a/app/tools/gimpsourcetool.c
+++ b/app/tools/gimpsourcetool.c
@@ -168,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,
-                    "src-drawable", NULL,
+                    "src-drawables", NULL,
                     NULL);
       break;
 
@@ -302,7 +302,7 @@ gimp_source_tool_cursor_update (GimpTool         *tool,
         {
           cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
         }
-      else if (! GIMP_SOURCE_CORE (GIMP_PAINT_TOOL (tool)->core)->src_drawable)
+      else if (! GIMP_SOURCE_CORE (GIMP_PAINT_TOOL (tool)->core)->src_drawables)
         {
           modifier = GIMP_CURSOR_MODIFIER_BAD;
         }
@@ -341,7 +341,7 @@ gimp_source_tool_oper_update (GimpTool         *tool,
 
   if (gimp_source_core_use_source (source, options))
     {
-      if (source->src_drawable == NULL)
+      if (source->src_drawables == NULL)
         {
           GdkModifierType toggle_mask = gimp_get_toggle_behavior_mask ();
 
@@ -400,20 +400,16 @@ 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_drawable && source_tool->src_display)
+      source->src_drawables && source_tool->src_display)
     {
       GimpDisplayShell *src_shell;
-      gint              off_x;
-      gint              off_y;
       gdouble           src_x;
       gdouble           src_y;
 
       src_shell = gimp_display_get_shell (source_tool->src_display);
 
-      gimp_item_get_offset (GIMP_ITEM (source->src_drawable), &off_x, &off_y);
-
-      src_x = source_tool->src_x + off_x + 0.5;
-      src_y = source_tool->src_y + off_y + 0.5;
+      src_x = source_tool->src_x + 0.5;
+      src_y = source_tool->src_y + 0.5;
 
       if (source_tool->src_outline)
         {
diff --git a/pdb/groups/paint_tools.pdb b/pdb/groups/paint_tools.pdb
index 227ea80c4e..52ad2d5b27 100644
--- a/pdb/groups/paint_tools.pdb
+++ b/pdb/groups/paint_tools.pdb
@@ -172,7 +172,10 @@ HELP
                                  GIMP_PDB_ITEM_CONTENT, error) &&
       gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
     {
+      GList *src_drawables;
+
       options = gimp_config_duplicate (GIMP_CONFIG (options));
+      src_drawables = g_list_prepend (NULL, src_drawable);
 
       g_object_set (options,
                     "clone-type", clone_type,
@@ -180,11 +183,12 @@ HELP
 
       success = paint_tools_stroke (gimp, context, options, drawable,
                                     num_strokes, strokes, error,
-                                    "undo-desc",    options->paint_info->blurb,
-                                    "src-drawable", src_drawable,
-                                    "src-x",        (gint) floor (src_x),
-                                    "src-y",        (gint) floor (src_y),
+                                    "undo-desc",     options->paint_info->blurb,
+                                    "src-drawables", src_drawables,
+                                    "src-x",         (gint) floor (src_x),
+                                    "src-y",         (gint) floor (src_y),
                                     NULL);
+      g_list_free (src_drawables);
     }
   else
     success = FALSE;
@@ -531,15 +535,19 @@ HELP
                                  GIMP_PDB_ITEM_CONTENT, error) &&
       gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
     {
+      GList *src_drawables;
+
       options = gimp_config_duplicate (GIMP_CONFIG (options));
+      src_drawables = g_list_prepend (NULL, src_drawable);
 
       success = paint_tools_stroke (gimp, context, options, drawable,
                                     num_strokes, strokes, error,
-                                   "undo-desc",    options->paint_info->blurb,
-                                    "src-drawable", src_drawable,
-                                    "src-x",        (gint) floor (src_x),
-                                    "src-y",        (gint) floor (src_y),
+                                    "undo-desc",     options->paint_info->blurb,
+                                    "src-drawables", src_drawables,
+                                    "src-x",         (gint) floor (src_x),
+                                    "src-y",         (gint) floor (src_y),
                                     NULL);
+      g_list_free (src_drawables);
     }
   else
     success = FALSE;


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