From dfb26f37e7f63f3ed74d1bf53afed06dcb41ce5d Mon Sep 17 00:00:00 2001 From: Alx Sa Date: Tue, 12 Mar 2024 13:29:36 +0000 Subject: [PATCH] core: Allow copy/pasting NDE filters Previously, filters were lost when copying individual layers. This patch copies them to the clipboard image on cut or copy, then copies them back to the pasted image. It also fixes an issue where filters would be merged down if a selection was copied instead of the entire layer. --- app/actions/edit-commands.c | 50 ++++++++++++++++++++++++++++++++++++ app/core/gimpdrawable-edit.c | 9 +++++++ app/core/gimpimage-new.c | 44 +++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/app/actions/edit-commands.c b/app/actions/edit-commands.c index 9e0157428d..b73de4159b 100644 --- a/app/actions/edit-commands.c +++ b/app/actions/edit-commands.c @@ -33,10 +33,13 @@ #include "core/gimpcontainer.h" #include "core/gimpdrawable.h" #include "core/gimpdrawable-edit.h" +#include "core/gimpdrawable-filters.h" +#include "core/gimpdrawablefilter.h" #include "core/gimpfilloptions.h" #include "core/gimplayer.h" #include "core/gimplayer-new.h" #include "core/gimplayermask.h" +#include "core/gimplist.h" #include "core/gimpimage.h" #include "core/gimpimage-undo.h" @@ -718,6 +721,53 @@ edit_paste (GimpDisplay *display, merged, x, y, width, height))) { gimp_image_set_selected_layers (image, pasted_layers); + + /* Copy over layer effects */ + if (GIMP_IS_IMAGE (paste)) + { + GList *old_layers_list; + GList *new_layers_list; + + old_layers_list = gimp_image_get_layer_iter (GIMP_IMAGE (paste)); + for (new_layers_list = pasted_layers; new_layers_list; + new_layers_list = g_list_next (new_layers_list)) + { + GimpLayer *layer = old_layers_list->data; + GimpLayer *new_layer = new_layers_list->data; + + if (gimp_drawable_has_filters (GIMP_DRAWABLE (layer))) + { + GList *filter_list; + GimpContainer *filters; + + filters = gimp_drawable_get_filters (GIMP_DRAWABLE (layer)); + + for (filter_list = GIMP_LIST (filters)->queue->tail; + filter_list; + filter_list = g_list_previous (filter_list)) + { + if (GIMP_IS_DRAWABLE_FILTER (filter_list->data)) + { + GimpDrawableFilter *old_filter = filter_list->data; + GimpDrawableFilter *filter; + + filter = + gimp_drawable_filter_duplicate (GIMP_DRAWABLE (new_layer), + old_filter); + + gimp_drawable_filter_apply (filter, NULL); + gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE); + + gimp_drawable_filter_layer_mask_freeze (filter); + g_object_unref (filter); + } + } + } + + old_layers_list = g_list_next (old_layers_list); + } + } + g_list_free (pasted_layers); gimp_image_flush (image); } diff --git a/app/core/gimpdrawable-edit.c b/app/core/gimpdrawable-edit.c index 848d69bcde..217a0cadc2 100644 --- a/app/core/gimpdrawable-edit.c +++ b/app/core/gimpdrawable-edit.c @@ -27,8 +27,10 @@ #include "gegl/gimp-gegl-loops.h" #include "gimpchannel.h" +#include "core/gimpcontainer.h" #include "gimpdrawable.h" #include "gimpdrawable-edit.h" +#include "core/gimpdrawable-filters.h" #include "gimpdrawablefilter.h" #include "gimpcontext.h" #include "gimpfilloptions.h" @@ -201,6 +203,7 @@ gimp_drawable_edit_fill (GimpDrawable *drawable, gdouble opacity; GimpLayerMode mode; GimpLayerCompositeMode composite_mode; + GimpContainer *filter_stack; opacity = gimp_context_get_opacity (context); mode = gimp_context_get_paint_mode (context); @@ -224,6 +227,12 @@ gimp_drawable_edit_fill (GimpDrawable *drawable, composite_mode); gimp_drawable_filter_apply (filter, NULL); + /* Move to bottom of filter stack */ + filter_stack = gimp_drawable_get_filters (drawable); + if (filter_stack) + gimp_container_reorder (filter_stack, GIMP_OBJECT (filter), + gimp_container_get_n_children (filter_stack) - 1); + gimp_drawable_filter_commit (filter, FALSE, NULL, FALSE); g_object_unref (filter); diff --git a/app/core/gimpimage-new.c b/app/core/gimpimage-new.c index 89f63ec601..e706249805 100644 --- a/app/core/gimpimage-new.c +++ b/app/core/gimpimage-new.c @@ -37,6 +37,8 @@ #include "gimpchannel.h" #include "gimpcontext.h" #include "gimpdrawable-fill.h" +#include "gimpdrawable-filters.h" +#include "gimpdrawablefilter.h" #include "gimpgrouplayer.h" #include "gimpimage.h" #include "gimpimage-color-profile.h" @@ -406,6 +408,8 @@ gimp_image_new_from_drawables (Gimp *gimp, gdouble xres; gdouble yres; GimpColorProfile *profile = NULL; + GList *old_layers_list; + GList *new_layers_list; g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); g_return_val_if_fail (drawables != NULL, NULL); @@ -462,6 +466,46 @@ gimp_image_new_from_drawables (Gimp *gimp, } gimp_image_new_copy_drawables (image, drawables, new_image, tag_copies, NULL, NULL, NULL, NULL); + + /* Copy any attached layer effects */ + old_layers_list = gimp_image_get_layer_iter (image); + for (new_layers_list = gimp_image_get_layer_iter (new_image); + new_layers_list; new_layers_list = g_list_next (new_layers_list)) + { + GimpLayer *layer = old_layers_list->data; + GimpLayer *new_layer = new_layers_list->data; + + if (gimp_drawable_has_filters (GIMP_DRAWABLE (layer))) + { + GList *filter_list; + GimpContainer *filters; + + filters = gimp_drawable_get_filters (GIMP_DRAWABLE (layer)); + + for (filter_list = GIMP_LIST (filters)->queue->tail; filter_list; + filter_list = g_list_previous (filter_list)) + { + if (GIMP_IS_DRAWABLE_FILTER (filter_list->data)) + { + GimpDrawableFilter *old_filter = filter_list->data; + GimpDrawableFilter *filter; + + filter = + gimp_drawable_filter_duplicate (GIMP_DRAWABLE (new_layer), + old_filter); + + gimp_drawable_filter_apply (filter, NULL); + gimp_drawable_filter_commit (filter, TRUE, NULL, FALSE); + + gimp_drawable_filter_layer_mask_freeze (filter); + g_object_unref (filter); + } + } + } + + old_layers_list = g_list_next (old_layers_list); + } + gimp_image_undo_enable (new_image); return new_image;