From 5964f72cea9aacb4f1061d14979b03bd1ce49ab1 Mon Sep 17 00:00:00 2001 From: Jehan Date: Thu, 7 May 2020 14:30:21 +0200 Subject: [PATCH] app, pdb: layers-merge-layers* and image-merge-layers multi-layer aware. Multi selection actually only really matter when "Merge within active groups only" option is checked, in which case we are able to merge layers within several layer groups simultaneously, and end up with multi-selected merged layers. Also not sure why both layers-merge-layers and image-merge-layers exist, as they are exactly the same (exact same callback called when activated). --- app/actions/layers-actions.c | 2 +- app/config/gimpdialogconfig.c | 2 +- app/core/gimpimage-merge.c | 169 ++++++++++++++---------- app/core/gimpimage-merge.h | 2 +- app/dialogs/image-merge-layers-dialog.c | 2 +- app/dialogs/preferences-dialog.c | 2 +- app/file/file-open.c | 13 +- app/pdb/image-cmds.c | 13 +- pdb/groups/image.pdb | 13 +- 9 files changed, 130 insertions(+), 88 deletions(-) diff --git a/app/actions/layers-actions.c b/app/actions/layers-actions.c index 0b67608292..57f3bbbfa5 100644 --- a/app/actions/layers-actions.c +++ b/app/actions/layers-actions.c @@ -1040,7 +1040,7 @@ layers_actions_update (GimpActionGroup *group, SET_SENSITIVE ("layers-merge-down-button", layer && !fs && !ac); SET_VISIBLE ("layers-merge-group", children); SET_SENSITIVE ("layers-merge-group", layer && !fs && !ac && children); - SET_SENSITIVE ("layers-merge-layers", layer && !fs && !ac); + SET_SENSITIVE ("layers-merge-layers", n_layers > 0 && !fs && !ac); SET_SENSITIVE ("layers-flatten-image", layer && !fs && !ac); SET_VISIBLE ("layers-text-discard", text_layer && !ac); diff --git a/app/config/gimpdialogconfig.c b/app/config/gimpdialogconfig.c index f81d778d86..ca13737784 100644 --- a/app/config/gimpdialogconfig.c +++ b/app/config/gimpdialogconfig.c @@ -388,7 +388,7 @@ gimp_dialog_config_class_init (GimpDialogConfigClass *klass) GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_LAYER_MERGE_ACTIVE_GROUP_ONLY, "layer-merge-active-group-only", - "Default layer merge active group only", + "Default layer merge active groups only", LAYER_MERGE_ACTIVE_GROUP_ONLY_BLURB, TRUE, GIMP_PARAM_STATIC_STRINGS); diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c index b8dc8cc11b..a39e0c1421 100644 --- a/app/core/gimpimage-merge.c +++ b/app/core/gimpimage-merge.c @@ -66,7 +66,7 @@ static GimpLayer * gimp_image_merge_layers (GimpImage *image, /* public functions */ -GimpLayer * +GList * gimp_image_merge_visible_layers (GimpImage *image, GimpContext *context, GimpMergeType merge_type, @@ -74,10 +74,11 @@ gimp_image_merge_visible_layers (GimpImage *image, gboolean discard_invisible, GimpProgress *progress) { - GimpContainer *container; - GList *list; - GSList *merge_list = NULL; - GSList *invisible_list = NULL; + const gchar *undo_desc = C_("undo-type", "Merge Visible Layers"); + GList *containers = NULL; + GList *new_layers = NULL; + GList *iter; + GList *iter2; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); @@ -85,89 +86,119 @@ gimp_image_merge_visible_layers (GimpImage *image, if (merge_active_group) { - GimpLayer *active_layer = gimp_image_get_active_layer (image); + GList *selected_layers = gimp_image_get_selected_layers (image); /* if the active layer is the floating selection, get the * underlying drawable, but only if it is a layer */ - if (active_layer && gimp_layer_is_floating_sel (active_layer)) + if (g_list_length (selected_layers) == 1 && gimp_layer_is_floating_sel (selected_layers->data)) { GimpDrawable *fs_drawable; - fs_drawable = gimp_layer_get_floating_sel_drawable (active_layer); + fs_drawable = gimp_layer_get_floating_sel_drawable (selected_layers->data); if (GIMP_IS_LAYER (fs_drawable)) - active_layer = GIMP_LAYER (fs_drawable); + containers = g_list_prepend (containers, + gimp_item_get_container (GIMP_ITEM (fs_drawable))); } - - if (active_layer) - container = gimp_item_get_container (GIMP_ITEM (active_layer)); else - container = gimp_image_get_layers (image); - } - else - { - container = gimp_image_get_layers (image); - } - - for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (container)); - list; - list = g_list_next (list)) - { - GimpLayer *layer = list->data; - - if (gimp_layer_is_floating_sel (layer)) - continue; - - if (gimp_item_get_visible (GIMP_ITEM (layer))) { - merge_list = g_slist_append (merge_list, layer); + for (iter = selected_layers; iter; iter = iter->next) + if (! gimp_item_get_parent (iter->data)) + break; + + /* No need to list selected groups if any selected layer is + * to-level. + */ + if (iter == NULL) + { + for (iter = selected_layers; iter; iter = iter->next) + { + for (iter2 = selected_layers; iter2; iter2 = iter2->next) + { + /* Only retain a selected layer's container if no + * other selected layers are its parents. + */ + if (iter->data != iter2->data && + gimp_item_is_ancestor (iter->data, iter2->data)) + break; + } + if (iter2 == NULL && + ! g_list_find (containers, gimp_item_get_container (GIMP_ITEM (iter->data)))) + containers = g_list_prepend (containers, + gimp_item_get_container (GIMP_ITEM (iter->data))); + } + } } - else if (discard_invisible) + } + if (! containers) + containers = g_list_prepend (NULL, gimp_image_get_layers (image)); + + gimp_set_busy (image->gimp); + gimp_image_undo_group_start (image, + GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, + undo_desc); + + for (iter = containers; iter; iter = iter->next) + { + GimpContainer *container = iter->data; + GSList *merge_list = NULL; + GSList *invisible_list = NULL; + + for (iter2 = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (container)); + iter2; + iter2 = g_list_next (iter2)) { - invisible_list = g_slist_append (invisible_list, layer); + GimpLayer *layer = iter2->data; + + if (gimp_layer_is_floating_sel (layer)) + continue; + + if (gimp_item_get_visible (GIMP_ITEM (layer))) + { + merge_list = g_slist_append (merge_list, layer); + } + else if (discard_invisible) + { + invisible_list = g_slist_append (invisible_list, layer); + } + } + + if (merge_list) + { + GimpLayer *layer; + /* if there's a floating selection, anchor it */ + if (gimp_image_get_floating_selection (image)) + floating_sel_anchor (gimp_image_get_floating_selection (image)); + + layer = gimp_image_merge_layers (image, + container, + merge_list, context, merge_type, + undo_desc, progress); + g_slist_free (merge_list); + + if (invisible_list) + { + GSList *list; + + for (list = invisible_list; list; list = g_slist_next (list)) + gimp_image_remove_layer (image, list->data, TRUE, NULL); + + g_slist_free (invisible_list); + } + + new_layers = g_list_prepend (new_layers, layer); } } - if (merge_list) - { - GimpLayer *layer; - const gchar *undo_desc = C_("undo-type", "Merge Visible Layers"); + gimp_image_set_selected_layers (image, new_layers); + gimp_image_undo_group_end (image); + gimp_unset_busy (image->gimp); - gimp_set_busy (image->gimp); + g_list_free (new_layers); + g_list_free (containers); - gimp_image_undo_group_start (image, - GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, - undo_desc); - - /* if there's a floating selection, anchor it */ - if (gimp_image_get_floating_selection (image)) - floating_sel_anchor (gimp_image_get_floating_selection (image)); - - layer = gimp_image_merge_layers (image, - container, - merge_list, context, merge_type, - undo_desc, progress); - g_slist_free (merge_list); - - if (invisible_list) - { - GSList *list; - - for (list = invisible_list; list; list = g_slist_next (list)) - gimp_image_remove_layer (image, list->data, TRUE, NULL); - - g_slist_free (invisible_list); - } - - gimp_image_undo_group_end (image); - - gimp_unset_busy (image->gimp); - - return layer; - } - - return gimp_image_get_active_layer (image); + return gimp_image_get_selected_layers (image); } GimpLayer * diff --git a/app/core/gimpimage-merge.h b/app/core/gimpimage-merge.h index 93aab4e53a..de8e9297b6 100644 --- a/app/core/gimpimage-merge.h +++ b/app/core/gimpimage-merge.h @@ -19,7 +19,7 @@ #define __GIMP_IMAGE_MERGE_H__ -GimpLayer * gimp_image_merge_visible_layers (GimpImage *image, +GList * gimp_image_merge_visible_layers (GimpImage *image, GimpContext *context, GimpMergeType merge_type, gboolean merge_active_group, diff --git a/app/dialogs/image-merge-layers-dialog.c b/app/dialogs/image-merge-layers-dialog.c index 6ac115a44b..6426a9eee2 100644 --- a/app/dialogs/image-merge-layers-dialog.c +++ b/app/dialogs/image-merge-layers-dialog.c @@ -135,7 +135,7 @@ image_merge_layers_dialog_new (GimpImage *image, gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); - button = gtk_check_button_new_with_mnemonic (_("Merge within active _group only")); + button = gtk_check_button_new_with_mnemonic (_("Merge within active _groups only")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), private->merge_active_group); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c index 01d5305136..0fce63adc2 100644 --- a/app/dialogs/preferences-dialog.c +++ b/app/dialogs/preferences-dialog.c @@ -2353,7 +2353,7 @@ prefs_dialog_new (Gimp *gimp, GTK_GRID (grid), 0, size_group); prefs_check_button_add (object, "layer-merge-active-group-only", - _("Merge within active group only"), + _("Merge within active groups only"), GTK_BOX (vbox2)); prefs_check_button_add (object, "layer-merge-discard-invisible", _("Discard invisible layers"), diff --git a/app/file/file-open.c b/app/file/file-open.c index 86811673b0..5c3ba2b9a7 100644 --- a/app/file/file-open.c +++ b/app/file/file-open.c @@ -618,16 +618,13 @@ file_open_layers (Gimp *gimp, if (merge_visible && n_visible > 1) { - GimpLayer *layer; - g_list_free (layers); - layer = gimp_image_merge_visible_layers (new_image, context, - GIMP_CLIP_TO_IMAGE, - FALSE, FALSE, - NULL); - - layers = g_list_prepend (NULL, layer); + layers = gimp_image_merge_visible_layers (new_image, context, + GIMP_CLIP_TO_IMAGE, + FALSE, FALSE, + NULL); + layers = g_list_copy (layers); } if (layers) diff --git a/app/pdb/image-cmds.c b/app/pdb/image-cmds.c index aa4609af79..f64377aadc 100644 --- a/app/pdb/image-cmds.c +++ b/app/pdb/image-cmds.c @@ -1393,9 +1393,16 @@ image_merge_visible_layers_invoker (GimpProcedure *procedure, if (success) { - layer = gimp_image_merge_visible_layers (image, context, merge_type, - FALSE, FALSE, - progress); + GList *layers; + + layers = gimp_image_merge_visible_layers (image, context, merge_type, + FALSE, FALSE, progress); + + if (layers) + /* With merge_selected_groups set to FALSE, we always get only a + * single selected layer. + */ + layer = layers->data; if (! layer) success = FALSE; diff --git a/pdb/groups/image.pdb b/pdb/groups/image.pdb index 0d92af4ded..fa0064250e 100644 --- a/pdb/groups/image.pdb +++ b/pdb/groups/image.pdb @@ -737,9 +737,16 @@ HELP headers => [ qw("core/gimpimage-merge.h") ], code => <<'CODE' { - layer = gimp_image_merge_visible_layers (image, context, merge_type, - FALSE, FALSE, - progress); + GList *layers; + + layers = gimp_image_merge_visible_layers (image, context, merge_type, + FALSE, FALSE, progress); + + if (layers) + /* With merge_selected_groups set to FALSE, we always get only a + * single selected layer. + */ + layer = layers->data; if (! layer) success = FALSE;