diff --git a/app/actions/buffers-commands.c b/app/actions/buffers-commands.c index 367aba7ff9..98bac107ed 100644 --- a/app/actions/buffers-commands.c +++ b/app/actions/buffers-commands.c @@ -93,6 +93,7 @@ buffers_paste_cmd_callback (GimpAction *action, g_list_free (gimp_edit_paste (image, g_list_length (drawables) == 1 ? drawables->data : NULL, GIMP_OBJECT (buffer), paste_type, + context, FALSE, x, y, width, height)); gimp_image_flush (image); diff --git a/app/actions/edit-actions.c b/app/actions/edit-actions.c index 0cb8a07417..f7fb41446c 100644 --- a/app/actions/edit-actions.c +++ b/app/actions/edit-actions.c @@ -178,6 +178,19 @@ static const GimpEnumActionEntry edit_paste_actions[] = GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE, FALSE, GIMP_HELP_EDIT_PASTE_IN_PLACE }, + { "edit-paste-merged", GIMP_ICON_EDIT_PASTE, + NC_("edit-action", "_Paste as Single Layer"), NULL, + NC_("edit-action", "Paste the content of the clipboard as a single layer"), + GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING, FALSE, + GIMP_HELP_EDIT_PASTE }, + + { "edit-paste-merged-in-place", GIMP_ICON_EDIT_PASTE, + NC_("edit-action", "Paste as Single Layer In P_lace"), NULL, + NC_("edit-action", + "Paste the content of the clipboard at its original position as a single layer"), + GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_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", diff --git a/app/actions/edit-commands.c b/app/actions/edit-commands.c index d358b3cd0e..81b9385c70 100644 --- a/app/actions/edit-commands.c +++ b/app/actions/edit-commands.c @@ -69,6 +69,7 @@ static gboolean check_drawable_alpha (GimpDrawable *drawable, gpointer data); static void edit_paste (GimpDisplay *display, GimpPasteType paste_type, + gboolean merged, gboolean try_svg); static void cut_named_buffer_callback (GtkWidget *widget, const gchar *name, @@ -346,6 +347,7 @@ edit_paste_cmd_callback (GimpAction *action, GimpPasteType paste_type = (GimpPasteType) g_variant_get_int32 (value); GimpPasteType converted_type; GList *drawables; + gboolean merged = FALSE; return_if_no_image (image, data); @@ -367,14 +369,17 @@ edit_paste_cmd_callback (GimpAction *action, 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); + edit_paste (display, paste_type, merged, TRUE); break; case GIMP_PASTE_TYPE_NEW_LAYER: case GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE: - edit_paste (display, paste_type, FALSE); + edit_paste (display, paste_type, merged, FALSE); break; + case GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING: + case GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE: + merged = TRUE; case GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING: case GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE: drawables = gimp_image_get_selected_drawables (image); @@ -383,19 +388,21 @@ edit_paste_cmd_callback (GimpAction *action, (g_list_length (drawables) == 1) && GIMP_IS_LAYER_MASK (drawables->data)) { - converted_type = (paste_type == GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING) ? + converted_type = (paste_type == GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING || + paste_type == GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING) ? GIMP_PASTE_TYPE_FLOATING : GIMP_PASTE_TYPE_FLOATING_IN_PLACE; - edit_paste (display, converted_type, TRUE); + edit_paste (display, converted_type, merged, TRUE); } else { - converted_type = (paste_type == GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING) ? + converted_type = (paste_type == GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING || + paste_type == GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING) ? GIMP_PASTE_TYPE_NEW_LAYER : GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE; - edit_paste (display, converted_type, FALSE); + edit_paste (display, converted_type, merged, FALSE); } g_list_free (drawables); @@ -627,13 +634,16 @@ check_drawable_alpha (GimpDrawable *drawable, static void edit_paste (GimpDisplay *display, GimpPasteType paste_type, + gboolean merged, gboolean try_svg) { GimpImage *image = gimp_display_get_image (display); GimpObject *paste; - g_return_if_fail (paste_type != GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING && - paste_type != GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE); + g_return_if_fail (paste_type != GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING && + paste_type != GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE && + paste_type != GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING && + paste_type != GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE); if (try_svg) { @@ -702,8 +712,9 @@ edit_paste (GimpDisplay *display, ! gimp_display_shell_get_infinite_canvas (shell), &x, &y, &width, &height); - if ((pasted_layers = gimp_edit_paste (image, drawables, paste, - paste_type, x, y, width, height))) + if ((pasted_layers = gimp_edit_paste (image, drawables, paste, paste_type, + gimp_get_user_context (display->gimp), + merged, x, y, width, height))) { gimp_image_set_selected_layers (image, pasted_layers); g_list_free (pasted_layers); diff --git a/app/core/core-enums.c b/app/core/core-enums.c index 57fc28c764..6811c6ad37 100644 --- a/app/core/core-enums.c +++ b/app/core/core-enums.c @@ -950,6 +950,8 @@ gimp_paste_type_get_type (void) { GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, "GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE", "new-layer-in-place" }, { GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING, "GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING", "new-layer-or-floating" }, { GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE, "GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE", "new-layer-or-floating-in-place" }, + { GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING, "GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING", "new-merged-layer-or-floating" }, + { GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE, "GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE", "new-merged-layer-or-floating-in-place" }, { 0, NULL, NULL } }; @@ -963,6 +965,8 @@ gimp_paste_type_get_type (void) { GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, "GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE", NULL }, { GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING, "GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING", NULL }, { GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE, "GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE", NULL }, + { GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING, "GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING", NULL }, + { GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE, "GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE", NULL }, { 0, NULL, NULL } }; diff --git a/app/core/core-enums.h b/app/core/core-enums.h index 3db5ad7238..a50b087cae 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -437,7 +437,9 @@ typedef enum /*< pdb-skip >*/ GIMP_PASTE_TYPE_NEW_LAYER, GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE, GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING, - GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE + GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE, + GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING, + GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE, } GimpPasteType; diff --git a/app/core/gimp-edit.c b/app/core/gimp-edit.c index 313ff04611..8a41fce775 100644 --- a/app/core/gimp-edit.c +++ b/app/core/gimp-edit.c @@ -34,6 +34,7 @@ #include "gimpgrouplayer.h" #include "gimpimage.h" #include "gimpimage-duplicate.h" +#include "gimpimage-merge.h" #include "gimpimage-new.h" #include "gimpimage-undo.h" #include "gimplayer-floating-selection.h" @@ -296,12 +297,14 @@ gimp_edit_paste_is_in_place (GimpPasteType paste_type) case GIMP_PASTE_TYPE_FLOATING_INTO: case GIMP_PASTE_TYPE_NEW_LAYER: case GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING: + case GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING: return FALSE; case GIMP_PASTE_TYPE_FLOATING_IN_PLACE: case GIMP_PASTE_TYPE_FLOATING_INTO_IN_PLACE: case GIMP_PASTE_TYPE_NEW_LAYER_IN_PLACE: case GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE: + case GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE: return TRUE; } @@ -326,6 +329,8 @@ gimp_edit_paste_is_floating (GimpPasteType paste_type, case GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING: case GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE: + case GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING: + case GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE: if (GIMP_IS_LAYER_MASK (drawable)) return TRUE; else @@ -775,6 +780,10 @@ gimp_edit_paste_paste (GimpImage *image, gimp_image_add_layer (image, iter->data, parent, position, TRUE); } break; + + case GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING: + case GIMP_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE: + g_return_val_if_reached (NULL); } } @@ -788,6 +797,8 @@ gimp_edit_paste (GimpImage *image, GList *drawables, GimpObject *paste, GimpPasteType paste_type, + GimpContext *context, + gboolean merged, gint viewport_x, gint viewport_y, gint viewport_width, @@ -809,7 +820,51 @@ gimp_edit_paste (GimpImage *image, g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (iter->data)), NULL); } - layers = gimp_edit_paste_get_layers (image, drawables, paste, &paste_type); + if (merged && GIMP_IS_IMAGE (paste)) + { + GimpImage *tmp_image; + + tmp_image = gimp_image_duplicate (GIMP_IMAGE (paste)); + gimp_container_remove (image->gimp->images, GIMP_OBJECT (tmp_image)); + gimp_image_merge_visible_layers (tmp_image, context, GIMP_EXPAND_AS_NECESSARY, + FALSE, FALSE, NULL); + layers = g_list_copy (gimp_image_get_layer_iter (tmp_image)); + + /* The merge process should ensure that we get a single non-group and + * no-mask layer. + */ + g_return_val_if_fail (g_list_length (layers) == 1, NULL); + + layers->data = gimp_item_convert (GIMP_ITEM (layers->data), image, + G_TYPE_FROM_INSTANCE (layers->data)); + + 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: + if (gimp_drawable_get_format (GIMP_DRAWABLE (layers->data)) != + gimp_drawable_get_format_with_alpha (GIMP_DRAWABLE (layers->data))) + { + gimp_drawable_convert_type (GIMP_DRAWABLE (layers->data), image, + gimp_drawable_get_base_type (layers->data), + gimp_drawable_get_precision (layers->data), + TRUE, NULL, NULL, + GEGL_DITHER_NONE, GEGL_DITHER_NONE, + FALSE, NULL); + } + break; + + default: + break; + } + g_object_unref (tmp_image); + } + else + { + layers = gimp_edit_paste_get_layers (image, drawables, paste, &paste_type); + } if (! layers) return NULL; diff --git a/app/core/gimp-edit.h b/app/core/gimp-edit.h index b37a083978..501c07c3f2 100644 --- a/app/core/gimp-edit.h +++ b/app/core/gimp-edit.h @@ -35,6 +35,8 @@ GList * gimp_edit_paste (GimpImage *image, GList *drawables, GimpObject *paste, GimpPasteType paste_type, + GimpContext *context, + gboolean merged, gint viewport_x, gint viewport_y, gint viewport_width, diff --git a/app/display/gimpdisplayshell-dnd.c b/app/display/gimpdisplayshell-dnd.c index ce8a2bed91..e22f681a46 100644 --- a/app/display/gimpdisplayshell-dnd.c +++ b/app/display/gimpdisplayshell-dnd.c @@ -459,6 +459,7 @@ gimp_display_shell_drop_buffer (GtkWidget *widget, { GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (data); GimpImage *image = gimp_display_get_image (shell->display); + GimpContext *context; GList *drawables; GimpBuffer *buffer; GimpPasteType paste_type; @@ -482,8 +483,8 @@ gimp_display_shell_drop_buffer (GtkWidget *widget, paste_type = GIMP_PASTE_TYPE_NEW_LAYER_OR_FLOATING; drawables = gimp_image_get_selected_drawables (image); - - buffer = GIMP_BUFFER (viewable); + context = gimp_get_user_context (shell->display->gimp); + buffer = GIMP_BUFFER (viewable); gimp_display_shell_untransform_viewport ( shell, @@ -493,7 +494,8 @@ gimp_display_shell_drop_buffer (GtkWidget *widget, /* FIXME: popup a menu for selecting "Paste Into" */ g_list_free (gimp_edit_paste (image, drawables, GIMP_OBJECT (buffer), - paste_type, x, y, width, height)); + paste_type, context, FALSE, + x, y, width, height)); g_list_free (drawables); gimp_display_shell_dnd_flush (shell, image); diff --git a/app/pdb/edit-cmds.c b/app/pdb/edit-cmds.c index f027e5076e..7b460e0877 100644 --- a/app/pdb/edit-cmds.c +++ b/app/pdb/edit-cmds.c @@ -278,6 +278,7 @@ edit_paste_invoker (GimpProcedure *procedure, paste_into ? GIMP_PASTE_TYPE_FLOATING_INTO : GIMP_PASTE_TYPE_FLOATING, + context, FALSE, -1, -1, -1, -1); g_list_free (drawables); @@ -595,6 +596,7 @@ edit_named_paste_invoker (GimpProcedure *procedure, paste_into ? GIMP_PASTE_TYPE_FLOATING_INTO : GIMP_PASTE_TYPE_FLOATING, + context, FALSE, -1, -1, -1, -1); g_list_free (drawables); diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in index b6043974ed..81ef18ae87 100644 --- a/menus/image-menu.xml.in +++ b/menus/image-menu.xml.in @@ -197,6 +197,8 @@