app, menus, pdb: new "Paste as Single Layer( in Place)?" actions.

When the clipboard contains raw image data or single layers, it's the same as
the normal "Paste" (and "Paste In Place" respectively). These actions are useful
if you want to copy a bunch of layers and paste them "merged" into a single
layers (since now the copy-paste of multiple layers will create multiple
layers).
It is somehow similar to the "Copy Visible" action except that it works on
selected layers only and work at paste time, making the action more versatile.
This commit is contained in:
Jehan 2022-11-12 22:17:00 +01:00
parent fc050914ab
commit 143496af22
11 changed files with 111 additions and 15 deletions

View File

@ -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);

View File

@ -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",

View File

@ -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);

View File

@ -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 }
};

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -197,6 +197,8 @@
<menuitem action="edit-paste-in-place" />
</placeholder>
<menu action="edit-paste-as-menu" name="Paste as">
<menuitem action="edit-paste-merged" />
<menuitem action="edit-paste-merged-in-place" />
<menuitem action="edit-paste-into" />
<menuitem action="edit-paste-into-in-place" />
<menuitem action="edit-paste-as-new-image-short" />

View File

@ -287,6 +287,7 @@ HELP
paste_into ?
GIMP_PASTE_TYPE_FLOATING_INTO :
GIMP_PASTE_TYPE_FLOATING,
context, FALSE,
-1, -1, -1, -1);
g_list_free (drawables);
@ -614,6 +615,7 @@ HELP
paste_into ?
GIMP_PASTE_TYPE_FLOATING_INTO :
GIMP_PASTE_TYPE_FLOATING,
context, FALSE,
-1, -1, -1, -1);
g_list_free (drawables);