[gimp] app, pdb: layers-merge-down action now multi-layer aware.



commit 955aecab922b8ca96010d92723f0e40f76033fed
Author: Jehan <jehan girinstud io>
Date:   Tue Jun 30 23:29:05 2020 +0200

    app, pdb: layers-merge-down action now multi-layer aware.
    
    When several layers are selected, each layer will merge down with the
    layer below it. This is similar to running Merge Down several times, one
    for each selected layer.

 app/actions/layers-actions.c  |  83 +++++++++++++-------------
 app/actions/layers-commands.c |  24 ++++++--
 app/core/gimpimage-merge.c    | 132 ++++++++++++++++++++++++------------------
 app/core/gimpimage-merge.h    |   4 +-
 app/pdb/image-cmds.c          |  14 ++++-
 pdb/groups/image.pdb          |  14 ++++-
 6 files changed, 159 insertions(+), 112 deletions(-)
---
diff --git a/app/actions/layers-actions.c b/app/actions/layers-actions.c
index d655f80d77..f44463f7d7 100644
--- a/app/actions/layers-actions.c
+++ b/app/actions/layers-actions.c
@@ -173,7 +173,7 @@ static const GimpActionEntry layers_actions[] =
 
   { "layers-merge-down", GIMP_ICON_LAYER_MERGE_DOWN,
     NC_("layers-action", "Merge Do_wn"), NULL,
-    NC_("layers-action", "Merge this layer with the first visible layer below it"),
+    NC_("layers-action", "Merge these layers with the first visible layer below each"),
     layers_merge_down_cmd_callback,
     GIMP_HELP_LAYER_MERGE_DOWN },
 
@@ -182,7 +182,7 @@ static const GimpActionEntry layers_actions[] =
    */
   { "layers-merge-down-button", GIMP_ICON_LAYER_MERGE_DOWN,
     NC_("layers-action", "Merge Do_wn"), NULL,
-    NC_("layers-action", "Merge this layer with the first visible layer below it"),
+    NC_("layers-action", "Merge these layers with the first visible layer below each"),
     layers_merge_down_cmd_callback,
     GIMP_HELP_LAYER_MERGE_DOWN },
 
@@ -774,14 +774,12 @@ layers_actions_update (GimpActionGroup *group,
   gboolean       lock_alpha     = TRUE;
   gboolean       can_lock_alpha = FALSE;
   gboolean       text_layer     = FALSE;
-  gboolean       visible        = FALSE;
   gboolean       writable       = FALSE;
   gboolean       movable        = FALSE;
   gboolean       children       = FALSE;
   gboolean       bs_mutable     = FALSE; /* At least 1 selected layers' blend space is mutable.     */
   gboolean       cs_mutable     = FALSE; /* At least 1 selected layers' composite space is mutable. */
   gboolean       cm_mutable     = FALSE; /* At least 1 selected layers' composite mode is mutable.  */
-  GList         *next_visible   = NULL;
   gboolean       next_mode      = TRUE;
   gboolean       prev_mode      = TRUE;
   gboolean       last_mode      = FALSE;
@@ -795,6 +793,8 @@ layers_actions_update (GimpActionGroup *group,
   gboolean       have_prev      = FALSE; /* At least 1 selected layer has a previous sibling. */
   gboolean       have_next      = FALSE; /* At least 1 selected layer has a next sibling.     */
 
+  gboolean       all_visible        = TRUE;
+  gboolean       all_next_visible   = TRUE;
   gboolean       all_masks_shown    = TRUE;
   gboolean       all_masks_disabled = TRUE;
 
@@ -872,11 +872,33 @@ layers_actions_update (GimpActionGroup *group,
 
           if (iter2)
             {
+              GList *next_visible;
+
               if (g_list_previous (iter2))
                 have_prev = TRUE;
 
               if (g_list_next (iter2))
                 have_next = TRUE;
+
+              for (next_visible = g_list_next (iter2);
+                   next_visible;
+                   next_visible = g_list_next (next_visible))
+                {
+                  if (gimp_item_get_visible (next_visible->data))
+                    {
+                      /*  "next_visible" is actually "next_visible" and
+                       *  "writable" and "not group"
+                       */
+                      if (gimp_item_is_content_locked (next_visible->data) ||
+                          gimp_viewable_get_children (next_visible->data))
+                        next_visible = NULL;
+
+                      break;
+                    }
+                }
+
+              if (! next_visible)
+                all_next_visible = FALSE;
             }
 
           if (gimp_layer_mode_is_blend_space_mutable (mode))
@@ -886,23 +908,25 @@ layers_actions_update (GimpActionGroup *group,
           if (gimp_layer_mode_is_composite_mode_mutable (mode))
             cm_mutable = TRUE;
 
-          if (have_masks && have_no_masks        &&
-              have_groups && have_no_groups      &&
-              have_writable && ! all_masks_shown &&
-              ! all_masks_disabled               &&
-              ! lock_alpha && can_lock_alpha     &&
-              ! prev_mode && ! next_mode         &&
-              have_prev && have_next             &&
-              bs_mutable && cs_mutable && cm_mutable)
+          if (! gimp_item_get_visible (iter->data))
+            all_visible = FALSE;
+
+          if (have_masks && have_no_masks            &&
+              have_groups && have_no_groups          &&
+              have_writable && ! all_masks_shown     &&
+              ! all_masks_disabled                   &&
+              ! lock_alpha && can_lock_alpha         &&
+              ! prev_mode && ! next_mode             &&
+              have_prev && have_next                 &&
+              bs_mutable && cs_mutable && cm_mutable &&
+              ! all_visible && ! all_next_visible)
             break;
         }
 
       if (n_layers == 1)
         {
           /* Special unique layer case. */
-          const gchar   *action = NULL;
-          GList         *layer_list;
-          GList         *list;
+          const gchar *action = NULL;
 
           layer  = layers->data;
           switch (gimp_layer_get_blend_space (layer))
@@ -953,37 +977,12 @@ layers_actions_update (GimpActionGroup *group,
 
           mask           = gimp_layer_get_mask (layer);
           alpha          = gimp_drawable_has_alpha (GIMP_DRAWABLE (layer));
-          visible        = gimp_item_get_visible (GIMP_ITEM (layer));
           writable       = ! gimp_item_is_content_locked (GIMP_ITEM (layer));
           movable        = ! gimp_item_is_position_locked (GIMP_ITEM (layer));
 
           if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
             children = TRUE;
 
-          layer_list = gimp_item_get_container_iter (GIMP_ITEM (layer));
-
-          list = g_list_find (layer_list, layer);
-
-          if (list)
-            {
-              for (next_visible = g_list_next (list);
-                   next_visible;
-                   next_visible = g_list_next (next_visible))
-                {
-                  if (gimp_item_get_visible (next_visible->data))
-                    {
-                      /*  "next_visible" is actually "next_visible" and
-                       *  "writable" and "not group"
-                       */
-                      if (gimp_item_is_content_locked (next_visible->data) ||
-                          gimp_viewable_get_children (next_visible->data))
-                        next_visible = NULL;
-
-                      break;
-                    }
-                }
-            }
-
           text_layer = gimp_item_is_text_layer (GIMP_ITEM (layer));
         }
     }
@@ -1037,9 +1036,9 @@ layers_actions_update (GimpActionGroup *group,
 
   SET_VISIBLE   ("layers-anchor",            fs && !ac);
   SET_VISIBLE   ("layers-merge-down",        !fs);
-  SET_SENSITIVE ("layers-merge-down",        layer && !fs && !ac && visible && next_visible);
+  SET_SENSITIVE ("layers-merge-down",        n_layers > 0 && !fs && !ac && all_visible && all_next_visible);
   SET_VISIBLE   ("layers-merge-down-button", !fs);
-  SET_SENSITIVE ("layers-merge-down-button", layer && !fs && !ac);
+  SET_SENSITIVE ("layers-merge-down-button", n_layers > 0 && !fs && !ac);
   SET_VISIBLE   ("layers-merge-group",       have_groups);
   SET_SENSITIVE ("layers-merge-group",       n_layers && !fs && !ac && have_groups);
   SET_SENSITIVE ("layers-merge-layers",      n_layers > 0 && !fs && !ac);
diff --git a/app/actions/layers-commands.c b/app/actions/layers-commands.c
index d6a107b3ff..0df6cec1e9 100644
--- a/app/actions/layers-commands.c
+++ b/app/actions/layers-commands.c
@@ -822,14 +822,28 @@ layers_merge_down_cmd_callback (GimpAction *action,
                                 gpointer    data)
 {
   GimpImage   *image;
-  GimpLayer   *layer;
+  GList       *layers;
   GimpDisplay *display;
-  return_if_no_layer (image, layer, data);
+  GError      *error = NULL;
+
+  return_if_no_layers (image, layers, data);
   return_if_no_display (display, data);
 
-  gimp_image_merge_down (image, layer, action_data_get_context (data),
-                         GIMP_EXPAND_AS_NECESSARY,
-                         GIMP_PROGRESS (display), NULL);
+  layers = gimp_image_merge_down (image, layers, action_data_get_context (data),
+                                  GIMP_EXPAND_AS_NECESSARY,
+                                  GIMP_PROGRESS (display), &error);
+
+  if (error)
+    {
+      gimp_message_literal (image->gimp,
+                            G_OBJECT (display), GIMP_MESSAGE_WARNING,
+                            error->message);
+      g_clear_error (&error);
+      return;
+    }
+  gimp_image_set_selected_layers (image, layers);
+  g_list_free (layers);
+
   gimp_image_flush (image);
 }
 
diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c
index a39e0c1421..75fa60b158 100644
--- a/app/core/gimpimage-merge.c
+++ b/app/core/gimpimage-merge.c
@@ -264,86 +264,98 @@ gimp_image_flatten (GimpImage     *image,
   return NULL;
 }
 
-GimpLayer *
+GList *
 gimp_image_merge_down (GimpImage      *image,
-                       GimpLayer      *current_layer,
+                       GList          *layers,
                        GimpContext    *context,
                        GimpMergeType   merge_type,
                        GimpProgress   *progress,
                        GError        **error)
 {
   GimpLayer   *layer;
+  GList       *merged_layers = NULL;
   GList       *list;
-  GList       *layer_list = NULL;
-  GSList      *merge_list = NULL;
+  GList       *merge_lists   = NULL;
+  GSList      *merge_list;
   const gchar *undo_desc;
 
   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
-  g_return_val_if_fail (GIMP_IS_LAYER (current_layer), NULL);
-  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (current_layer)), NULL);
   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
   g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-  if (gimp_layer_is_floating_sel (current_layer))
+  for (list = layers; list; list = list->next)
     {
-      g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
-                           _("Cannot merge down a floating selection."));
-      return NULL;
-    }
+      GList  *list2;
+      GList  *layer_list = NULL;
 
-  if (! gimp_item_get_visible (GIMP_ITEM (current_layer)))
-    {
-      g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
-                           _("Cannot merge down an invisible layer."));
-      return NULL;
-    }
+      g_return_val_if_fail (GIMP_IS_LAYER (list->data), NULL);
+      g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (list->data)), NULL);
 
-  for (list = gimp_item_get_container_iter (GIMP_ITEM (current_layer));
-       list;
-       list = g_list_next (list))
-    {
-      layer = list->data;
+      if (gimp_layer_is_floating_sel (list->data))
+        {
+          g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
+                               _("Cannot merge down a floating selection."));
+          return NULL;
+        }
 
-      if (layer == current_layer)
-        break;
-    }
+      if (! gimp_item_get_visible (GIMP_ITEM (list->data)))
+        {
+          g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
+                               _("Cannot merge down an invisible layer."));
+          return NULL;
+        }
 
-  for (layer_list = g_list_next (list);
-       layer_list;
-       layer_list = g_list_next (layer_list))
-    {
-      layer = layer_list->data;
+      for (list2 = gimp_item_get_container_iter (GIMP_ITEM (list->data));
+           list2;
+           list2 = g_list_next (list2))
+        {
+          layer = list2->data;
 
-      if (gimp_item_get_visible (GIMP_ITEM (layer)))
+          if (layer == list->data)
+            break;
+        }
+
+      merge_list = NULL;
+
+      for (layer_list = g_list_next (list2);
+           layer_list;
+           layer_list = g_list_next (layer_list))
         {
-          if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
-            {
-              g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
-                                   _("Cannot merge down to a layer group."));
-              return NULL;
-            }
+          layer = layer_list->data;
 
-          if (gimp_item_is_content_locked (GIMP_ITEM (layer)))
+          if (gimp_item_get_visible (GIMP_ITEM (layer)))
             {
-              g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
-                                   _("The layer to merge down to is locked."));
-              return NULL;
+              if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
+                {
+                  g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
+                                       _("Cannot merge down to a layer group."));
+                  return NULL;
+                }
+
+              if (gimp_item_is_content_locked (GIMP_ITEM (layer)))
+                {
+                  g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
+                                       _("The layer to merge down to is locked."));
+                  return NULL;
+                }
+
+              merge_list = g_slist_append (NULL, layer);
+              break;
             }
+        }
 
-          merge_list = g_slist_append (NULL, layer);
-          break;
+      if (! merge_list)
+        {
+          g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
+                               _("There is no visible layer to merge down to."));
+          return NULL;
         }
-    }
 
-  if (! merge_list)
-    {
-      g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
-                           _("There is no visible layer to merge down to."));
-      return NULL;
-    }
+      merge_list = g_slist_prepend (merge_list, list->data);
 
-  merge_list = g_slist_prepend (merge_list, current_layer);
+      merge_lists = g_list_prepend (merge_lists, merge_list);
+    }
 
   undo_desc = C_("undo-type", "Merge Down");
 
@@ -353,17 +365,23 @@ gimp_image_merge_down (GimpImage      *image,
                                GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE,
                                undo_desc);
 
-  layer = gimp_image_merge_layers (image,
-                                   gimp_item_get_container (GIMP_ITEM (current_layer)),
-                                   merge_list, context, merge_type,
-                                   undo_desc, progress);
-  g_slist_free (merge_list);
+  for (list = merge_lists; list; list = list->next)
+    {
+      merge_list = list->data;
+      layer = gimp_image_merge_layers (image,
+                                       gimp_item_get_container (merge_list->data),
+                                       merge_list, context, merge_type,
+                                       undo_desc, progress);
+      merged_layers = g_list_prepend (merged_layers, layer);
+    }
+
+  g_list_free_full (merge_lists, (GDestroyNotify) g_slist_free);
 
   gimp_image_undo_group_end (image);
 
   gimp_unset_busy (image->gimp);
 
-  return layer;
+  return merged_layers;
 }
 
 GimpLayer *
diff --git a/app/core/gimpimage-merge.h b/app/core/gimpimage-merge.h
index de8e9297b6..f298ad54eb 100644
--- a/app/core/gimpimage-merge.h
+++ b/app/core/gimpimage-merge.h
@@ -25,8 +25,8 @@ GList       * gimp_image_merge_visible_layers  (GimpImage      *image,
                                                 gboolean        merge_active_group,
                                                 gboolean        discard_invisible,
                                                 GimpProgress   *progress);
-GimpLayer   * gimp_image_merge_down            (GimpImage      *image,
-                                                GimpLayer      *current_layer,
+GList       * gimp_image_merge_down            (GimpImage      *image,
+                                                GList          *layers,
                                                 GimpContext    *context,
                                                 GimpMergeType   merge_type,
                                                 GimpProgress   *progress,
diff --git a/app/pdb/image-cmds.c b/app/pdb/image-cmds.c
index 37b3fba3bc..44fcf02093 100644
--- a/app/pdb/image-cmds.c
+++ b/app/pdb/image-cmds.c
@@ -1468,11 +1468,19 @@ image_merge_down_invoker (GimpProcedure         *procedure,
     {
       if (gimp_pdb_item_is_attached (GIMP_ITEM (merge_layer), image, 0, error))
         {
-          layer = gimp_image_merge_down (image, merge_layer, context, merge_type,
-                                         progress, error);
+          GList *merge_layers = g_list_prepend (NULL, merge_layer);
+          GList *layers;
 
-          if (! layer)
+          layers = gimp_image_merge_down (image, merge_layers, context,
+                                          merge_type, progress, error);
+          g_list_free (merge_layers);
+
+          if (! layers)
             success = FALSE;
+          else
+            layer = layers->data;
+
+          g_list_free (layers);
         }
       else
         success = FALSE;
diff --git a/pdb/groups/image.pdb b/pdb/groups/image.pdb
index 64d269ee25..59d90b84ae 100644
--- a/pdb/groups/image.pdb
+++ b/pdb/groups/image.pdb
@@ -826,11 +826,19 @@ HELP
 {
   if (gimp_pdb_item_is_attached (GIMP_ITEM (merge_layer), image, 0, error))
     {
-      layer = gimp_image_merge_down (image, merge_layer, context, merge_type,
-                                     progress, error);
+      GList *merge_layers = g_list_prepend (NULL, merge_layer);
+      GList *layers;
 
-      if (! layer)
+      layers = gimp_image_merge_down (image, merge_layers, context,
+                                      merge_type, progress, error);
+      g_list_free (merge_layers);
+
+      if (! layers)
         success = FALSE;
+      else
+        layer = layers->data;
+
+      g_list_free (layers);
     }
   else
     success = FALSE;


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