[gimp] Bug 789764 - Please add Paste In Place feature



commit f12d0d8c29fc73bb439d2a9f1aee9c45538a60d0
Author: Michael Natterer <mitch gimp org>
Date:   Sun Nov 12 18:41:05 2017 +0100

    Bug 789764 - Please add Paste In Place feature
    
    Add "In Place" variants for all sorts of pasting:
    
    - extend the GimpPasteType enum with IN_PLACE values
    - add the needed actions and menu items
    - merge the action callbacks into one, taking an enum value as parameter
    - refactor the pasting code in gimp-edit.c into smaller functions
    
    We probably have too menu items in the "Edit" menu now, needs to be
    sorted out.

 app/actions/buffers-actions.c  |   69 ++++++---
 app/actions/buffers-commands.c |  110 +++++---------
 app/actions/buffers-commands.h |    5 +-
 app/actions/edit-actions.c     |   82 +++++++---
 app/actions/edit-commands.c    |   52 ++++----
 app/actions/edit-commands.h    |    5 +-
 app/core/core-enums.c          |    6 +
 app/core/core-enums.h          |    5 +-
 app/core/gimp-edit.c           |  321 +++++++++++++++++++++++++---------------
 app/core/gimp-edit.h           |   10 --
 app/widgets/gimpbufferview.c   |   16 ++-
 app/widgets/gimphelp-ids.h     |    6 +
 menus/buffers-menu.xml         |    3 +
 menus/image-menu.xml.in        |    3 +
 14 files changed, 417 insertions(+), 276 deletions(-)
---
diff --git a/app/actions/buffers-actions.c b/app/actions/buffers-actions.c
index 1321d80..18d1f5f 100644
--- a/app/actions/buffers-actions.c
+++ b/app/actions/buffers-actions.c
@@ -42,35 +42,58 @@ static const GimpActionEntry buffers_actions[] =
     NC_("buffers-action", "Buffers Menu"), NULL, NULL, NULL,
     GIMP_HELP_BUFFER_DIALOG },
 
+  { "buffers-paste-as-new-image", GIMP_ICON_EDIT_PASTE_AS_NEW,
+    NC_("buffers-action", "Paste Buffer as _New Image"), NULL,
+    NC_("buffers-action", "Paste the selected buffer as a new image"),
+    G_CALLBACK (buffers_paste_as_new_image_cmd_callback),
+    GIMP_HELP_BUFFER_PASTE_AS_NEW_IMAGE },
+
+  { "buffers-delete", GIMP_ICON_EDIT_DELETE,
+    NC_("buffers-action", "_Delete Buffer"), NULL,
+    NC_("buffers-action", "Delete the selected buffer"),
+    G_CALLBACK (buffers_delete_cmd_callback),
+    GIMP_HELP_BUFFER_DELETE }
+};
+
+static const GimpEnumActionEntry buffers_paste_actions[] =
+{
   { "buffers-paste", GIMP_ICON_EDIT_PASTE,
     NC_("buffers-action", "_Paste Buffer"), NULL,
     NC_("buffers-action", "Paste the selected buffer"),
-    G_CALLBACK (buffers_paste_cmd_callback),
+    GIMP_PASTE_TYPE_FLOATING, FALSE,
     GIMP_HELP_BUFFER_PASTE },
 
+  { "buffers-paste-in-place", GIMP_ICON_EDIT_PASTE,
+    NC_("buffers-action", "Paste Buffer In Pl_ace"), NULL,
+    NC_("buffers-action", "Paste the selected buffer at its original position"),
+    GIMP_PASTE_TYPE_FLOATING_IN_PLACE, FALSE,
+    GIMP_HELP_BUFFER_PASTE_IN_PLACE },
+
   { "buffers-paste-into", GIMP_ICON_EDIT_PASTE_INTO,
     NC_("buffers-action", "Paste Buffer _Into"), NULL,
     NC_("buffers-action", "Paste the selected buffer into the selection"),
-    G_CALLBACK (buffers_paste_into_cmd_callback),
+    GIMP_PASTE_TYPE_FLOATING_INTO, FALSE,
     GIMP_HELP_BUFFER_PASTE_INTO },
 
+  { "buffers-paste-into-in-place", GIMP_ICON_EDIT_PASTE_INTO,
+    NC_("buffers-action", "Paste Buffer Into In Place"), NULL,
+    NC_("buffers-action",
+        "Paste the selected buffer into the selection at its original position"),
+    GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE, FALSE,
+    GIMP_HELP_BUFFER_PASTE_INTO_IN_PLACE },
+
   { "buffers-paste-as-new-layer", GIMP_ICON_EDIT_PASTE_AS_NEW,
     NC_("buffers-action", "Paste Buffer as New _Layer"), NULL,
     NC_("buffers-action", "Paste the selected buffer as a new layer"),
-    G_CALLBACK (buffers_paste_as_new_layer_cmd_callback),
+    GIMP_PASTE_TYPE_NEW_LAYER, FALSE,
     GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER },
 
-  { "buffers-paste-as-new-image", GIMP_ICON_EDIT_PASTE_AS_NEW,
-    NC_("buffers-action", "Paste Buffer as _New Image"), NULL,
-    NC_("buffers-action", "Paste the selected buffer as a new image"),
-    G_CALLBACK (buffers_paste_as_new_image_cmd_callback),
-    GIMP_HELP_BUFFER_PASTE_AS_NEW_IMAGE },
-
-  { "buffers-delete", GIMP_ICON_EDIT_DELETE,
-    NC_("buffers-action", "_Delete Buffer"), NULL,
-    NC_("buffers-action", "Delete the selected buffer"),
-    G_CALLBACK (buffers_delete_cmd_callback),
-    GIMP_HELP_BUFFER_DELETE }
+  { "buffers-paste-as-new-layer-in-place", GIMP_ICON_EDIT_PASTE_AS_NEW,
+    NC_("buffers-action", "Paste Buffer as New Layer in Place"), NULL,
+    NC_("buffers-action",
+        "Paste the selected buffer as a new layer at its original position"),
+    GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, FALSE,
+    GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER_IN_PLACE },
 };
 
 
@@ -80,6 +103,11 @@ buffers_actions_setup (GimpActionGroup *group)
   gimp_action_group_add_actions (group, "buffers-action",
                                  buffers_actions,
                                  G_N_ELEMENTS (buffers_actions));
+
+  gimp_action_group_add_enum_actions (group, "buffers-action",
+                                      buffers_paste_actions,
+                                      G_N_ELEMENTS (buffers_paste_actions),
+                                      G_CALLBACK (buffers_paste_cmd_callback));
 }
 
 void
@@ -95,11 +123,14 @@ buffers_actions_update (GimpActionGroup *group,
 #define SET_SENSITIVE(action,condition) \
         gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
 
-  SET_SENSITIVE ("buffers-paste",              buffer);
-  SET_SENSITIVE ("buffers-paste-into",         buffer);
-  SET_SENSITIVE ("buffers-paste-as-new-layer", buffer);
-  SET_SENSITIVE ("buffers-paste-as-new-image", buffer);
-  SET_SENSITIVE ("buffers-delete",             buffer);
+  SET_SENSITIVE ("buffers-paste",                       buffer);
+  SET_SENSITIVE ("buffers-paste-in-place",              buffer);
+  SET_SENSITIVE ("buffers-paste-into",                  buffer);
+  SET_SENSITIVE ("buffers-paste-into-in-place",         buffer);
+  SET_SENSITIVE ("buffers-paste-as-new-layer",          buffer);
+  SET_SENSITIVE ("buffers-paste-as-new-layer-in-place", buffer);
+  SET_SENSITIVE ("buffers-paste-as-new-image",          buffer);
+  SET_SENSITIVE ("buffers-delete",                      buffer);
 
 #undef SET_SENSITIVE
 }
diff --git a/app/actions/buffers-commands.c b/app/actions/buffers-commands.c
index a0fe7c8..454429e 100644
--- a/app/actions/buffers-commands.c
+++ b/app/actions/buffers-commands.c
@@ -30,7 +30,7 @@
 #include "core/gimpcontext.h"
 #include "core/gimpimage.h"
 
-#include "widgets/gimpbufferview.h"
+#include "widgets/gimpcontainereditor.h"
 #include "widgets/gimpcontainerview.h"
 #include "widgets/gimpcontainerview-utils.h"
 
@@ -43,84 +43,18 @@
 #include "gimp-intl.h"
 
 
-/*  local function prototypes  */
-
-static void   buffers_paste (GimpBufferView *view,
-                             GimpPasteType   paste_type);
-
-
 /*  public functionss */
 
 void
 buffers_paste_cmd_callback (GtkAction *action,
+                            gint       value,
                             gpointer   data)
 {
-  buffers_paste (GIMP_BUFFER_VIEW (data), GIMP_PASTE_TYPE_FLOATING);
-}
-
-void
-buffers_paste_into_cmd_callback (GtkAction *action,
-                                 gpointer   data)
-{
-  buffers_paste (GIMP_BUFFER_VIEW (data), GIMP_PASTE_TYPE_FLOATING_INTO);
-}
-
-void
-buffers_paste_as_new_layer_cmd_callback (GtkAction *action,
-                                         gpointer   data)
-{
-  buffers_paste (GIMP_BUFFER_VIEW (data), GIMP_PASTE_TYPE_NEW_LAYER);
-}
-
-void
-buffers_paste_as_new_image_cmd_callback (GtkAction *action,
-                                         gpointer   data)
-{
-  GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
-  GimpContainer       *container;
-  GimpContext         *context;
-  GimpBuffer          *buffer;
-
-  container = gimp_container_view_get_container (editor->view);
-  context   = gimp_container_view_get_context (editor->view);
-
-  buffer = gimp_context_get_buffer (context);
-
-  if (buffer && gimp_container_have (container, GIMP_OBJECT (buffer)))
-    {
-      GtkWidget *widget = GTK_WIDGET (editor);
-      GimpImage *new_image;
-
-      new_image = gimp_edit_paste_as_new_image (context->gimp,
-                                                GIMP_OBJECT (buffer));
-      gimp_create_display (context->gimp, new_image,
-                           GIMP_UNIT_PIXEL, 1.0,
-                           G_OBJECT (gtk_widget_get_screen (widget)),
-                           gimp_widget_get_monitor (widget));
-      g_object_unref (new_image);
-    }
-}
-
-void
-buffers_delete_cmd_callback (GtkAction *action,
-                             gpointer   data)
-{
   GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
-
-  gimp_container_view_remove_active (editor->view);
-}
-
-
-/*  private functions  */
-
-static void
-buffers_paste (GimpBufferView *view,
-               GimpPasteType   paste_type)
-{
-  GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (view);
   GimpContainer       *container;
   GimpContext         *context;
   GimpBuffer          *buffer;
+  GimpPasteType        paste_type = (GimpPasteType) value;
 
   container = gimp_container_view_get_container (editor->view);
   context   = gimp_container_view_get_context (editor->view);
@@ -160,3 +94,41 @@ buffers_paste (GimpBufferView *view,
         }
     }
 }
+
+void
+buffers_paste_as_new_image_cmd_callback (GtkAction *action,
+                                         gpointer   data)
+{
+  GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
+  GimpContainer       *container;
+  GimpContext         *context;
+  GimpBuffer          *buffer;
+
+  container = gimp_container_view_get_container (editor->view);
+  context   = gimp_container_view_get_context (editor->view);
+
+  buffer = gimp_context_get_buffer (context);
+
+  if (buffer && gimp_container_have (container, GIMP_OBJECT (buffer)))
+    {
+      GtkWidget *widget = GTK_WIDGET (editor);
+      GimpImage *new_image;
+
+      new_image = gimp_edit_paste_as_new_image (context->gimp,
+                                                GIMP_OBJECT (buffer));
+      gimp_create_display (context->gimp, new_image,
+                           GIMP_UNIT_PIXEL, 1.0,
+                           G_OBJECT (gtk_widget_get_screen (widget)),
+                           gimp_widget_get_monitor (widget));
+      g_object_unref (new_image);
+    }
+}
+
+void
+buffers_delete_cmd_callback (GtkAction *action,
+                             gpointer   data)
+{
+  GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (data);
+
+  gimp_container_view_remove_active (editor->view);
+}
diff --git a/app/actions/buffers-commands.h b/app/actions/buffers-commands.h
index 8c4dcf5..3af7413 100644
--- a/app/actions/buffers-commands.h
+++ b/app/actions/buffers-commands.h
@@ -20,10 +20,7 @@
 
 
 void   buffers_paste_cmd_callback              (GtkAction *action,
-                                                gpointer   data);
-void   buffers_paste_into_cmd_callback         (GtkAction *action,
-                                                gpointer   data);
-void   buffers_paste_as_new_layer_cmd_callback (GtkAction *action,
+                                                gint       value,
                                                 gpointer   data);
 void   buffers_paste_as_new_image_cmd_callback (GtkAction *action,
                                                 gpointer   data);
diff --git a/app/actions/edit-actions.c b/app/actions/edit-actions.c
index fef6980..d2f6a46 100644
--- a/app/actions/edit-actions.c
+++ b/app/actions/edit-actions.c
@@ -126,25 +126,6 @@ static const GimpActionEntry edit_actions[] =
     G_CALLBACK (edit_copy_visible_cmd_callback),
     GIMP_HELP_EDIT_COPY_VISIBLE },
 
-  { "edit-paste", GIMP_ICON_EDIT_PASTE,
-    NC_("edit-action", "_Paste"), "<primary>V",
-    NC_("edit-action", "Paste the content of the clipboard"),
-    G_CALLBACK (edit_paste_cmd_callback),
-    GIMP_HELP_EDIT_PASTE },
-
-  { "edit-paste-into", GIMP_ICON_EDIT_PASTE_INTO,
-    NC_("edit-action", "Paste _Into"), NULL,
-    NC_("edit-action",
-        "Paste the content of the clipboard into the current selection"),
-    G_CALLBACK (edit_paste_into_cmd_callback),
-    GIMP_HELP_EDIT_PASTE_INTO },
-
-  { "edit-paste-as-new-layer", NULL,
-    NC_("edit-action", "New _Layer"), NULL,
-    NC_("edit-action", "Create a new layer from the content of the clipboard"),
-    G_CALLBACK (edit_paste_as_new_layer_cmd_callback),
-    GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER },
-
   { "edit-paste-as-new-image", GIMP_ICON_EDIT_PASTE_AS_NEW,
     NC_("edit-action", "From _Clipboard"), "<primary><shift>V",
     NC_("edit-action", "Create a new image from the content of the clipboard"),
@@ -189,6 +170,51 @@ static const GimpActionEntry edit_actions[] =
     GIMP_HELP_EDIT_CLEAR }
 };
 
+static const GimpEnumActionEntry edit_paste_actions[] =
+{
+  { "edit-paste", GIMP_ICON_EDIT_PASTE,
+    NC_("edit-action", "_Paste"), "<primary>V",
+    NC_("edit-action", "Paste the content of the clipboard"),
+    GIMP_PASTE_TYPE_FLOATING, FALSE,
+    GIMP_HELP_EDIT_PASTE },
+
+  { "edit-paste-in-place", GIMP_ICON_EDIT_PASTE,
+    NC_("edit-action", "Paste In Place"), NULL,
+    NC_("edit-action",
+        "Paste the content of the clipboard at its original position"),
+    GIMP_PASTE_TYPE_FLOATING_IN_PLACE, FALSE,
+    GIMP_HELP_EDIT_PASTE_IN_PLACE },
+
+  { "edit-paste-into", GIMP_ICON_EDIT_PASTE_INTO,
+    NC_("edit-action", "Paste _Into Selection"), NULL,
+    NC_("edit-action",
+        "Paste the content of the clipboard into the current selection"),
+    GIMP_PASTE_TYPE_FLOATING_INTO, FALSE,
+    GIMP_HELP_EDIT_PASTE_INTO },
+
+  { "edit-paste-into-in-place", GIMP_ICON_EDIT_PASTE_INTO,
+    NC_("edit-action", "Paste Into Selection In Place"), NULL,
+    NC_("edit-action",
+        "Paste the content of the clipboard into the current selection "
+        "at its original position"),
+    GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE, FALSE,
+    GIMP_HELP_EDIT_PASTE_INTO_IN_PLACE },
+
+  { "edit-paste-as-new-layer", GIMP_ICON_EDIT_PASTE_AS_NEW,
+    NC_("edit-action", "New _Layer"), NULL,
+    NC_("edit-action", "Create a new layer from the content of the clipboard"),
+    GIMP_PASTE_TYPE_NEW_LAYER, FALSE,
+    GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER },
+
+  { "edit-paste-as-new-layer-in-place", GIMP_ICON_EDIT_PASTE_AS_NEW,
+    NC_("edit-action", "New Layer In _Place"), NULL,
+    NC_("edit-action",
+        "Create a new layer from the content of the clipboard"
+        "and place it at its original position"),
+    GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, FALSE,
+    GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER_IN_PLACE }
+};
+
 static const GimpEnumActionEntry edit_fill_actions[] =
 {
   { "edit-fill-fg", GIMP_ICON_TOOL_BUCKET_FILL,
@@ -224,6 +250,11 @@ edit_actions_setup (GimpActionGroup *group)
                                  G_N_ELEMENTS (edit_actions));
 
   gimp_action_group_add_enum_actions (group, "edit-action",
+                                      edit_paste_actions,
+                                      G_N_ELEMENTS (edit_paste_actions),
+                                      G_CALLBACK (edit_paste_cmd_callback));
+
+  gimp_action_group_add_enum_actions (group, "edit-action",
                                       edit_fill_actions,
                                       G_N_ELEMENTS (edit_fill_actions),
                                       G_CALLBACK (edit_fill_cmd_callback));
@@ -359,12 +390,15 @@ edit_actions_update (GimpActionGroup *group,
   g_free (redo_name);
   g_free (fade_name);
 
-  SET_SENSITIVE ("edit-cut",                writable && !children);
-  SET_SENSITIVE ("edit-copy",               drawable);
-  SET_SENSITIVE ("edit-copy-visible",       image);
+  SET_SENSITIVE ("edit-cut",                         writable && !children);
+  SET_SENSITIVE ("edit-copy",                        drawable);
+  SET_SENSITIVE ("edit-copy-visible",                image);
   /*             "edit-paste" is always active */
-  SET_SENSITIVE ("edit-paste-into",         image);
-  SET_SENSITIVE ("edit-paste-as-new-layer", image);
+  SET_SENSITIVE ("edit-paste-in-place",              image);
+  SET_SENSITIVE ("edit-paste-into",                  image);
+  SET_SENSITIVE ("edit-paste-into-in-place",         image);
+  SET_SENSITIVE ("edit-paste-as-new-layer",          image);
+  SET_SENSITIVE ("edit-paste-as-new-layer-in-place", image);
 
   SET_SENSITIVE ("edit-named-cut",          writable && !children);
   SET_SENSITIVE ("edit-named-copy",         drawable);
diff --git a/app/actions/edit-commands.c b/app/actions/edit-commands.c
index ef2a9a0..9959c63 100644
--- a/app/actions/edit-commands.c
+++ b/app/actions/edit-commands.c
@@ -65,7 +65,7 @@
 /*  local function prototypes  */
 
 static void   edit_paste                         (GimpDisplay   *display,
-                                                  GimpPasteType  paste_into,
+                                                  GimpPasteType  paste_type,
                                                   gboolean       try_svg);
 static void   cut_named_buffer_callback          (GtkWidget     *widget,
                                                   const gchar   *name,
@@ -327,38 +327,38 @@ edit_copy_visible_cmd_callback (GtkAction *action,
 
 void
 edit_paste_cmd_callback (GtkAction *action,
+                         gint       value,
                          gpointer   data)
 {
-  GimpDisplay *display = action_data_get_display (data);
+  GimpDisplay   *display    = action_data_get_display (data);
+  GimpPasteType  paste_type = (GimpPasteType) value;
 
-  if (display && gimp_display_get_image (display))
+  if (paste_type == GIMP_PASTE_TYPE_FLOATING)
     {
-      edit_paste (display, GIMP_PASTE_TYPE_FLOATING, TRUE);
-    }
-  else
-    {
-      edit_paste_as_new_image_cmd_callback (action, data);
+      if (! display || ! gimp_display_get_image (display))
+        {
+          edit_paste_as_new_image_cmd_callback (action, data);
+          return;
+        }
     }
-}
-
-void
-edit_paste_into_cmd_callback (GtkAction *action,
-                              gpointer   data)
-{
-  GimpDisplay *display;
-  return_if_no_display (display, data);
 
-  edit_paste (display, GIMP_PASTE_TYPE_FLOATING_INTO, TRUE);
-}
+  if (! display)
+    return;
 
-void
-edit_paste_as_new_layer_cmd_callback (GtkAction *action,
-                                      gpointer   data)
-{
-  GimpDisplay *display;
-  return_if_no_display (display, data);
-
-  edit_paste (display, GIMP_PASTE_TYPE_NEW_LAYER, FALSE);
+  switch (paste_type)
+    {
+    case GIMP_PASTE_TYPE_FLOATING:
+    case GIMP_PASTE_TYPE_FLOATING_IN_PLACE:
+    case GIMP_PASTE_TYPE_FLOATING_INTO:
+    case GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE:
+      edit_paste (display, paste_type, TRUE);
+      break;
+
+    case GIMP_PASTE_TYPE_NEW_LAYER:
+    case GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE:
+      edit_paste (display, paste_type, FALSE);
+      break;
+    }
 }
 
 void
diff --git a/app/actions/edit-commands.h b/app/actions/edit-commands.h
index 940dcc7..bb91675 100644
--- a/app/actions/edit-commands.h
+++ b/app/actions/edit-commands.h
@@ -41,10 +41,7 @@ void   edit_copy_visible_cmd_callback       (GtkAction *action,
                                              gpointer   data);
 
 void   edit_paste_cmd_callback              (GtkAction *action,
-                                             gpointer   data);
-void   edit_paste_into_cmd_callback         (GtkAction *action,
-                                             gpointer   data);
-void   edit_paste_as_new_layer_cmd_callback (GtkAction *action,
+                                             gint       value,
                                              gpointer   data);
 void   edit_paste_as_new_image_cmd_callback (GtkAction *action,
                                              gpointer   data);
diff --git a/app/core/core-enums.c b/app/core/core-enums.c
index 1e1570e..645c022 100644
--- a/app/core/core-enums.c
+++ b/app/core/core-enums.c
@@ -319,16 +319,22 @@ gimp_paste_type_get_type (void)
   static const GEnumValue values[] =
   {
     { GIMP_PASTE_TYPE_FLOATING, "GIMP_PASTE_TYPE_FLOATING", "floating" },
+    { GIMP_PASTE_TYPE_FLOATING_IN_PLACE, "GIMP_PASTE_TYPE_FLOATING_IN_PLACE", "floating-in-place" },
     { GIMP_PASTE_TYPE_FLOATING_INTO, "GIMP_PASTE_TYPE_FLOATING_INTO", "floating-into" },
+    { GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE, "GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE", 
"floating-into-in-place" },
     { GIMP_PASTE_TYPE_NEW_LAYER, "GIMP_PASTE_TYPE_NEW_LAYER", "new-layer" },
+    { GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, "GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE", "new-layer-in-place" },
     { 0, NULL, NULL }
   };
 
   static const GimpEnumDesc descs[] =
   {
     { GIMP_PASTE_TYPE_FLOATING, "GIMP_PASTE_TYPE_FLOATING", NULL },
+    { GIMP_PASTE_TYPE_FLOATING_IN_PLACE, "GIMP_PASTE_TYPE_FLOATING_IN_PLACE", NULL },
     { GIMP_PASTE_TYPE_FLOATING_INTO, "GIMP_PASTE_TYPE_FLOATING_INTO", NULL },
+    { GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE, "GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE", NULL },
     { GIMP_PASTE_TYPE_NEW_LAYER, "GIMP_PASTE_TYPE_NEW_LAYER", NULL },
+    { GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, "GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE", NULL },
     { 0, NULL, NULL }
   };
 
diff --git a/app/core/core-enums.h b/app/core/core-enums.h
index 429de3a..eb7a2ad 100644
--- a/app/core/core-enums.h
+++ b/app/core/core-enums.h
@@ -169,8 +169,11 @@ GType gimp_paste_type_get_type (void) G_GNUC_CONST;
 typedef enum  /*< pdb-skip >*/
 {
   GIMP_PASTE_TYPE_FLOATING,
+  GIMP_PASTE_TYPE_FLOATING_IN_PLACE,
   GIMP_PASTE_TYPE_FLOATING_INTO,
-  GIMP_PASTE_TYPE_NEW_LAYER
+  GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE,
+  GIMP_PASTE_TYPE_NEW_LAYER,
+  GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE
 } GimpPasteType;
 
 
diff --git a/app/core/gimp-edit.c b/app/core/gimp-edit.c
index 4ecbe13..5d2fa96 100644
--- a/app/core/gimp-edit.c
+++ b/app/core/gimp-edit.c
@@ -80,8 +80,15 @@ gimp_edit_cut (GimpImage     *image,
       gimp_channel_is_empty (gimp_image_get_mask (image)))
     {
       GimpImage *clip_image;
+      gint       off_x, off_y;
+
+      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
 
       clip_image = gimp_image_new_from_drawable (image->gimp, drawable);
+      g_object_set_data (G_OBJECT (clip_image), "offset-x",
+                         GINT_TO_POINTER (off_x));
+      g_object_set_data (G_OBJECT (clip_image), "offset-y",
+                         GINT_TO_POINTER (off_y));
       gimp_container_remove (image->gimp->images, GIMP_OBJECT (clip_image));
       gimp_set_clipboard_image (image->gimp, clip_image);
       g_object_unref (clip_image);
@@ -131,8 +138,15 @@ gimp_edit_copy (GimpImage     *image,
       gimp_channel_is_empty (gimp_image_get_mask (image)))
     {
       GimpImage *clip_image;
+      gint       off_x, off_y;
+
+      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
 
       clip_image = gimp_image_new_from_drawable (image->gimp, drawable);
+      g_object_set_data (G_OBJECT (clip_image), "offset-x",
+                         GINT_TO_POINTER (off_x));
+      g_object_set_data (G_OBJECT (clip_image), "offset-y",
+                         GINT_TO_POINTER (off_y));
       gimp_container_remove (image->gimp->images, GIMP_OBJECT (clip_image));
       gimp_set_clipboard_image (image->gimp, clip_image);
       g_object_unref (clip_image);
@@ -183,16 +197,110 @@ gimp_edit_copy_visible (GimpImage    *image,
   return NULL;
 }
 
-void
-gimp_edit_get_paste_offset (GimpImage    *image,
-                            GimpDrawable *drawable,
-                            GimpObject   *paste,
-                            gint          viewport_x,
-                            gint          viewport_y,
-                            gint          viewport_width,
-                            gint          viewport_height,
-                            gint         *offset_x,
-                            gint         *offset_y)
+static GimpLayer *
+gimp_edit_paste_get_layer (GimpImage     *image,
+                           GimpDrawable  *drawable,
+                           GimpObject    *paste,
+                           GimpPasteType *paste_type)
+{
+  GimpLayer  *layer = NULL;
+  const Babl *floating_format;
+
+  /*  change paste type to NEW_LAYER for cases where we can't attach a
+   *  floating selection
+   */
+  if (! drawable                                            ||
+      gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) ||
+      gimp_item_is_content_locked (GIMP_ITEM (drawable)))
+    {
+      *paste_type = GIMP_PASTE_TYPE_NEW_LAYER;
+    }
+
+  /*  floating pastes always have the pasted-to drawable's format with
+   *  alpha; if drawable == NULL, user is pasting into an empty image
+   */
+  if (drawable)
+    floating_format = gimp_drawable_get_format_with_alpha (drawable);
+  else
+    floating_format = gimp_image_get_layer_format (image, TRUE);
+
+  if (GIMP_IS_IMAGE (paste))
+    {
+      GType layer_type;
+
+      layer = gimp_image_get_layer_iter (GIMP_IMAGE (paste))->data;
+
+      switch (*paste_type)
+        {
+        case GIMP_PASTE_TYPE_FLOATING:
+        case GIMP_PASTE_TYPE_FLOATING_INTO:
+          /*  when pasting as floating selection, force creation of a
+           *  plain layer, so gimp_item_convert() will collapse a
+           *  group layer
+           */
+          layer_type = GIMP_TYPE_LAYER;
+          break;
+
+        case GIMP_PASTE_TYPE_NEW_LAYER:
+          layer_type = G_TYPE_FROM_INSTANCE (layer);
+          break;
+
+        default:
+          g_return_val_if_reached (NULL);
+        }
+
+      layer = GIMP_LAYER (gimp_item_convert (GIMP_ITEM (layer),
+                                             image, layer_type));
+
+      switch (*paste_type)
+        {
+        case GIMP_PASTE_TYPE_FLOATING:
+        case GIMP_PASTE_TYPE_FLOATING_INTO:
+          /*  when pasting as floating selection, get rid of the layer mask,
+           *  and make sure the layer has the right format
+           */
+          if (gimp_layer_get_mask (layer))
+            gimp_layer_apply_mask (layer, GIMP_MASK_DISCARD, FALSE);
+
+          if (gimp_drawable_get_format (GIMP_DRAWABLE (layer)) !=
+              floating_format)
+            {
+              gimp_drawable_convert_type (GIMP_DRAWABLE (layer), image,
+                                          gimp_drawable_get_base_type (drawable),
+                                          gimp_drawable_get_precision (drawable),
+                                          TRUE,
+                                          NULL,
+                                          GEGL_DITHER_NONE, GEGL_DITHER_NONE,
+                                          FALSE, NULL);
+            }
+          break;
+
+        default:
+          break;
+        }
+    }
+  else if (GIMP_IS_BUFFER (paste))
+    {
+      layer = gimp_layer_new_from_buffer (GIMP_BUFFER (paste), image,
+                                          floating_format,
+                                          _("Pasted Layer"),
+                                          GIMP_OPACITY_OPAQUE,
+                                          gimp_image_get_default_new_layer_mode (image));
+    }
+
+  return layer;
+}
+
+static void
+gimp_edit_paste_get_viewport_offset (GimpImage    *image,
+                                     GimpDrawable *drawable,
+                                     GimpObject   *paste,
+                                     gint          viewport_x,
+                                     gint          viewport_y,
+                                     gint          viewport_width,
+                                     gint          viewport_height,
+                                     gint         *offset_x,
+                                     gint         *offset_y)
 {
   gint     image_width;
   gint     image_height;
@@ -321,119 +429,45 @@ gimp_edit_get_paste_offset (GimpImage    *image,
     }
 }
 
-GimpLayer *
-gimp_edit_paste (GimpImage     *image,
-                 GimpDrawable  *drawable,
-                 GimpObject    *paste,
-                 GimpPasteType  paste_type,
-                 gint           viewport_x,
-                 gint           viewport_y,
-                 gint           viewport_width,
-                 gint           viewport_height)
+static void
+gimp_edit_paste_get_paste_offset (GimpImage    *image,
+                                  GimpDrawable *drawable,
+                                  GimpObject   *paste,
+                                  gint         *offset_x,
+                                  gint         *offset_y)
 {
-  GimpLayer  *layer = NULL;
-  const Babl *floating_format;
-  gint        offset_x;
-  gint        offset_y;
-
-  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
-  g_return_val_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable), NULL);
-  g_return_val_if_fail (drawable == NULL ||
-                        gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
-  g_return_val_if_fail (GIMP_IS_IMAGE (paste) || GIMP_IS_BUFFER (paste), NULL);
-
-  /*  change paste type to NEW_LAYER for cases where we can't attach a
-   *  floating selection
-   */
-  if (! drawable                                            ||
-      gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) ||
-      gimp_item_is_content_locked (GIMP_ITEM (drawable)))
-    {
-      paste_type = GIMP_PASTE_TYPE_NEW_LAYER;
-    }
-
-  /*  floating pastes always have the pasted-to drawable's format with
-   *  alpha; if drawable == NULL, user is pasting into an empty image
-   */
-  if (drawable)
-    floating_format = gimp_drawable_get_format_with_alpha (drawable);
-  else
-    floating_format = gimp_image_get_layer_format (image, TRUE);
+  g_return_if_fail (GIMP_IS_IMAGE (image));
+  g_return_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable));
+  g_return_if_fail (drawable == NULL ||
+                    gimp_item_is_attached (GIMP_ITEM (drawable)));
+  g_return_if_fail (GIMP_IS_VIEWABLE (paste));
+  g_return_if_fail (offset_x != NULL);
+  g_return_if_fail (offset_y != NULL);
 
   if (GIMP_IS_IMAGE (paste))
     {
-      GType layer_type;
-
-      layer = gimp_image_get_layer_iter (GIMP_IMAGE (paste))->data;
-
-      switch (paste_type)
-        {
-        case GIMP_PASTE_TYPE_FLOATING:
-        case GIMP_PASTE_TYPE_FLOATING_INTO:
-          /*  when pasting as floating selection, force creation of a
-           *  plain layer, so gimp_item_convert() will collapse a
-           *  group layer
-           */
-          layer_type = GIMP_TYPE_LAYER;
-          break;
-
-        case GIMP_PASTE_TYPE_NEW_LAYER:
-          layer_type = G_TYPE_FROM_INSTANCE (layer);
-          break;
-
-        default:
-          g_return_val_if_reached (NULL);
-        }
-
-      layer = GIMP_LAYER (gimp_item_convert (GIMP_ITEM (layer),
-                                             image, layer_type));
-
-      switch (paste_type)
-        {
-        case GIMP_PASTE_TYPE_FLOATING:
-        case GIMP_PASTE_TYPE_FLOATING_INTO:
-          /*  when pasting as floating selection, get rid of the layer mask,
-           *  and make sure the layer has the right format
-           */
-          if (gimp_layer_get_mask (layer))
-            gimp_layer_apply_mask (layer, GIMP_MASK_DISCARD, FALSE);
-
-          if (gimp_drawable_get_format (GIMP_DRAWABLE (layer)) !=
-              floating_format)
-            {
-              gimp_drawable_convert_type (GIMP_DRAWABLE (layer), image,
-                                          gimp_drawable_get_base_type (drawable),
-                                          gimp_drawable_get_precision (drawable),
-                                          TRUE,
-                                          NULL,
-                                          GEGL_DITHER_NONE, GEGL_DITHER_NONE,
-                                          FALSE, NULL);
-            }
-          break;
-
-        default:
-          break;
-        }
+      *offset_x = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (paste),
+                                                      "offset-x"));
+      *offset_y = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (paste),
+                                                      "offset-y"));
     }
   else if (GIMP_IS_BUFFER (paste))
     {
-      layer = gimp_layer_new_from_buffer (GIMP_BUFFER (paste), image,
-                                          floating_format,
-                                          _("Pasted Layer"),
-                                          GIMP_OPACITY_OPAQUE,
-                                          gimp_image_get_default_new_layer_mode (image));
-    }
+      GimpBuffer *buffer = GIMP_BUFFER (paste);
 
-  if (! layer)
-    return NULL;
+      *offset_x = buffer->offset_x;
+      *offset_y = buffer->offset_y;
+    }
+}
 
-  gimp_edit_get_paste_offset (image, drawable, GIMP_OBJECT (layer),
-                              viewport_x,
-                              viewport_y,
-                              viewport_width,
-                              viewport_height,
-                              &offset_x,
-                              &offset_y);
+static GimpLayer *
+gimp_edit_paste_paste (GimpImage     *image,
+                       GimpDrawable  *drawable,
+                       GimpLayer     *layer,
+                       GimpPasteType  paste_type,
+                       gint           offset_x,
+                       gint           offset_y)
+{
   gimp_item_translate (GIMP_ITEM (layer), offset_x, offset_y, FALSE);
 
   gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE,
@@ -442,6 +476,7 @@ gimp_edit_paste (GimpImage     *image,
   switch (paste_type)
     {
     case GIMP_PASTE_TYPE_FLOATING:
+    case GIMP_PASTE_TYPE_FLOATING_IN_PLACE:
       /*  if there is a selection mask clear it - this might not
        *  always be desired, but in general, it seems like the correct
        *  behavior
@@ -452,16 +487,18 @@ gimp_edit_paste (GimpImage     *image,
       /* fall thru */
 
     case GIMP_PASTE_TYPE_FLOATING_INTO:
+    case GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE:
       floating_sel_attach (layer, drawable);
       break;
 
     case GIMP_PASTE_TYPE_NEW_LAYER:
+    case GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE:
       {
         GimpLayer *parent   = NULL;
         gint       position = 0;
 
-        /* always add on top of the passed layer, where we would
-         * attach a floating selection
+        /*  always add on top of a passed layer, where we would attach
+         *  a floating selection
          */
         if (GIMP_IS_LAYER (drawable))
           {
@@ -479,6 +516,58 @@ gimp_edit_paste (GimpImage     *image,
   return layer;
 }
 
+GimpLayer *
+gimp_edit_paste (GimpImage     *image,
+                 GimpDrawable  *drawable,
+                 GimpObject    *paste,
+                 GimpPasteType  paste_type,
+                 gint           viewport_x,
+                 gint           viewport_y,
+                 gint           viewport_width,
+                 gint           viewport_height)
+{
+  GimpLayer *layer;
+  gint       offset_x = 0;
+  gint       offset_y = 0;
+
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+  g_return_val_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable), NULL);
+  g_return_val_if_fail (drawable == NULL ||
+                        gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
+  g_return_val_if_fail (GIMP_IS_IMAGE (paste) || GIMP_IS_BUFFER (paste), NULL);
+
+  layer = gimp_edit_paste_get_layer (image, drawable, paste, &paste_type);
+
+  if (! layer)
+    return NULL;
+
+  switch (paste_type)
+    {
+    case GIMP_PASTE_TYPE_FLOATING:
+    case GIMP_PASTE_TYPE_FLOATING_INTO:
+    case GIMP_PASTE_TYPE_NEW_LAYER:
+      gimp_edit_paste_get_viewport_offset (image, drawable, GIMP_OBJECT (layer),
+                                           viewport_x,
+                                           viewport_y,
+                                           viewport_width,
+                                           viewport_height,
+                                           &offset_x,
+                                           &offset_y);
+      break;
+
+    case GIMP_PASTE_TYPE_FLOATING_IN_PLACE:
+    case GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE:
+    case GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE:
+      gimp_edit_paste_get_paste_offset (image, drawable, paste,
+                                        &offset_x,
+                                        &offset_y);
+      break;
+    }
+
+  return gimp_edit_paste_paste (image, drawable, layer, paste_type,
+                                offset_x, offset_y);
+}
+
 GimpImage *
 gimp_edit_paste_as_new_image (Gimp       *gimp,
                               GimpObject *paste)
diff --git a/app/core/gimp-edit.h b/app/core/gimp-edit.h
index 1103841..dc8b6ac 100644
--- a/app/core/gimp-edit.h
+++ b/app/core/gimp-edit.h
@@ -31,16 +31,6 @@ GimpBuffer  * gimp_edit_copy_visible       (GimpImage       *image,
                                             GimpContext     *context,
                                             GError         **error);
 
-void          gimp_edit_get_paste_offset   (GimpImage       *image,
-                                            GimpDrawable    *drawable,
-                                            GimpObject      *paste,
-                                            gint             viewport_x,
-                                            gint             viewport_y,
-                                            gint             viewport_width,
-                                            gint             viewport_height,
-                                            gint            *offset_x,
-                                            gint            *offset_y);
-
 GimpLayer   * gimp_edit_paste              (GimpImage       *image,
                                             GimpDrawable    *drawable,
                                             GimpObject      *paste,
diff --git a/app/widgets/gimpbufferview.c b/app/widgets/gimpbufferview.c
index 73bf322..3eefb7c 100644
--- a/app/widgets/gimpbufferview.c
+++ b/app/widgets/gimpbufferview.c
@@ -42,6 +42,7 @@
 #include "gimpview.h"
 #include "gimpviewrendererbuffer.h"
 #include "gimpuimanager.h"
+#include "gimpwidgets-utils.h"
 
 #include "gimp-intl.h"
 
@@ -186,15 +187,24 @@ gimp_buffer_view_new (GimpViewType     view_type,
 
   buffer_view->paste_button =
     gimp_editor_add_action_button (GIMP_EDITOR (editor->view), "buffers",
-                                   "buffers-paste", NULL);
+                                   "buffers-paste",
+                                   "buffers-paste-in-place",
+                                   gimp_get_extend_selection_mask (),
+                                   NULL);
 
   buffer_view->paste_into_button =
     gimp_editor_add_action_button (GIMP_EDITOR (editor->view), "buffers",
-                                   "buffers-paste-into", NULL);
+                                   "buffers-paste-into",
+                                   "buffers-paste-into-in-place",
+                                   gimp_get_extend_selection_mask (),
+                                   NULL);
 
   buffer_view->paste_as_new_layer_button =
     gimp_editor_add_action_button (GIMP_EDITOR (editor->view), "buffers",
-                                   "buffers-paste-as-new-layer", NULL);
+                                   "buffers-paste-as-new-layer",
+                                   "buffers-paste-as-new-layer-in-place",
+                                   gimp_get_extend_selection_mask (),
+                                   NULL);
 
   buffer_view->paste_as_new_image_button =
     gimp_editor_add_action_button (GIMP_EDITOR (editor->view), "buffers",
diff --git a/app/widgets/gimphelp-ids.h b/app/widgets/gimphelp-ids.h
index b9d35a4..174546b 100644
--- a/app/widgets/gimphelp-ids.h
+++ b/app/widgets/gimphelp-ids.h
@@ -56,8 +56,11 @@
 #define GIMP_HELP_EDIT_COPY                       "gimp-edit-copy"
 #define GIMP_HELP_EDIT_COPY_VISIBLE               "gimp-edit-copy-visible"
 #define GIMP_HELP_EDIT_PASTE                      "gimp-edit-paste"
+#define GIMP_HELP_EDIT_PASTE_IN_PLACE             "gimp-edit-paste-in-place"
 #define GIMP_HELP_EDIT_PASTE_INTO                 "gimp-edit-paste-into"
+#define GIMP_HELP_EDIT_PASTE_INTO_IN_PLACE        "gimp-edit-paste-into-in-place"
 #define GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER         "gimp-edit-paste-as-new-layer"
+#define GIMP_HELP_EDIT_PASTE_AS_NEW_LAYER_IN_PLACE "gimp-edit-paste-as-new-layer-in-place"
 #define GIMP_HELP_EDIT_PASTE_AS_NEW_IMAGE         "gimp-edit-paste-as-new-image"
 #define GIMP_HELP_EDIT_CLEAR                      "gimp-edit-clear"
 #define GIMP_HELP_EDIT_FILL_FG                    "gimp-edit-fill-fg"
@@ -552,8 +555,11 @@
 #define GIMP_HELP_BUFFER_CUT                      "gimp-buffer-cut"
 #define GIMP_HELP_BUFFER_COPY                     "gimp-buffer-copy"
 #define GIMP_HELP_BUFFER_PASTE                    "gimp-buffer-paste"
+#define GIMP_HELP_BUFFER_PASTE_IN_PLACE           "gimp-buffer-paste-in-place"
 #define GIMP_HELP_BUFFER_PASTE_INTO               "gimp-buffer-paste-into"
+#define GIMP_HELP_BUFFER_PASTE_INTO_IN_PLACE      "gimp-buffer-paste-into-in-place"
 #define GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER       "gimp-buffer-paste-as-new-layer"
+#define GIMP_HELP_BUFFER_PASTE_AS_NEW_LAYER_IN_PLACE "gimp-buffer-paste-as-new-layer-in-place"
 #define GIMP_HELP_BUFFER_PASTE_AS_NEW_IMAGE       "gimp-buffer-paste-as-new-image"
 #define GIMP_HELP_BUFFER_DELETE                   "gimp-buffer-delete"
 
diff --git a/menus/buffers-menu.xml b/menus/buffers-menu.xml
index 840ef61..05b7745 100644
--- a/menus/buffers-menu.xml
+++ b/menus/buffers-menu.xml
@@ -4,8 +4,11 @@
 <ui>
   <popup action="buffers-popup">
     <menuitem action="buffers-paste" />
+    <menuitem action="buffers-paste-in-place" />
     <menuitem action="buffers-paste-into" />
+    <menuitem action="buffers-paste-into-in-place" />
     <menuitem action="buffers-paste-as-new-layer" />
+    <menuitem action="buffers-paste-as-new-layer-in-place" />
     <menuitem action="buffers-paste-as-new-image" />
     <menuitem action="buffers-delete" />
     <separator />
diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in
index e44e073..5a8e856 100644
--- a/menus/image-menu.xml.in
+++ b/menus/image-menu.xml.in
@@ -193,10 +193,13 @@
       </placeholder>
       <placeholder name="Paste">
         <menuitem action="edit-paste" />
+        <menuitem action="edit-paste-in-place" />
         <menuitem action="edit-paste-into" />
+        <menuitem action="edit-paste-into-in-place" />
       </placeholder>
       <menu action="edit-paste-as-menu" name="Paste as">
         <menuitem action="edit-paste-as-new-layer" />
+        <menuitem action="edit-paste-as-new-layer-in-place" />
         <menuitem action="edit-paste-as-new-image-short" />
       </menu>
       <menu action="edit-buffer-menu" name="Buffer">



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