app: merging a pass-through group should merge all visible layers below it.
Existing logic to merge a pass-through group layer was wrong because it was changing the global rendering of the image as though the group was in fact in Normal mode. Instead a pass-through group can be kinda considered as a Normal group which would contain not only its children, but also all visible sister layers below it. Therefore the new pass-through group merging will be taking the real pass-through group render into the new layer (we don't change the original group's mode before copying the render anymore), set to Normal mode, then we remove not only the pass-through group but all its big sister layers below it on same level. Organizational-wise, it may seem unexpected because "merging" this group leaks outside it (getting rid of not only the children but also the big sisters and cousins). Nevertheless this is exactly how this group mode works after all. So let's go full-in. After discussing on IRC with Wormnest and NikcDC, we decided that it was worth doing this specific merge the technically proper way, and we would just educate people through the docs on why this group mode is very particular this way. After all, if someone absolutely wants the old-style merge, they can always manually change the group to Normal mode first before merging. But if they let to "Pass-Through", we should assume this is the render they want.
This commit is contained in:
parent
db8be0c28c
commit
f3eb02b2f0
3 changed files with 112 additions and 32 deletions
|
|
@ -943,11 +943,47 @@ layers_merge_group_cmd_callback (GimpAction *action,
|
|||
|
||||
for (iter2 = layers; iter2; iter2 = iter2->next)
|
||||
{
|
||||
if (iter->data == iter2->data)
|
||||
continue;
|
||||
|
||||
/* Do not merge a layer when we already merge one of its
|
||||
* ancestors.
|
||||
*/
|
||||
if (gimp_viewable_is_ancestor (iter2->data, iter->data))
|
||||
break;
|
||||
|
||||
/* Do not merge a layer which has a little sister (same
|
||||
* parent and smaller index) or a little cousin (one of
|
||||
* its ancestors is a little sister) of a pass-through
|
||||
* group layer.
|
||||
* These will be rendered and merged through the
|
||||
* pass-through by definition.
|
||||
*/
|
||||
if (gimp_viewable_get_children (GIMP_VIEWABLE (iter2->data)) &&
|
||||
gimp_layer_get_mode (iter2->data) == GIMP_LAYER_MODE_PASS_THROUGH)
|
||||
{
|
||||
GimpLayer *pass_through_parent = gimp_layer_get_parent (iter2->data);
|
||||
GimpLayer *cousin = iter->data;
|
||||
gboolean ignore = FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
GimpLayer *cousin_parent = gimp_layer_get_parent (cousin);
|
||||
|
||||
if (pass_through_parent == cousin_parent &&
|
||||
gimp_item_get_index (GIMP_ITEM (iter2->data)) < gimp_item_get_index (GIMP_ITEM (cousin)))
|
||||
{
|
||||
ignore = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
cousin = cousin_parent;
|
||||
}
|
||||
while (cousin != NULL);
|
||||
|
||||
if (ignore)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter2 == NULL)
|
||||
|
|
|
|||
|
|
@ -412,6 +412,7 @@ gimp_image_merge_group_layer (GimpImage *image,
|
|||
{
|
||||
GimpLayer *parent;
|
||||
GimpLayer *layer;
|
||||
gboolean is_pass_through = FALSE;
|
||||
gint index;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
||||
|
|
@ -425,28 +426,8 @@ gimp_image_merge_group_layer (GimpImage *image,
|
|||
parent = gimp_layer_get_parent (GIMP_LAYER (group));
|
||||
index = gimp_item_get_index (GIMP_ITEM (group));
|
||||
|
||||
/* if this is a pass-through group, change its mode to NORMAL *before*
|
||||
* duplicating it, since PASS_THROUGH mode is invalid for regular layers.
|
||||
* see bug #793714.
|
||||
*/
|
||||
if (gimp_layer_get_mode (GIMP_LAYER (group)) == GIMP_LAYER_MODE_PASS_THROUGH)
|
||||
{
|
||||
GimpLayerColorSpace blend_space;
|
||||
GimpLayerColorSpace composite_space;
|
||||
GimpLayerCompositeMode composite_mode;
|
||||
|
||||
/* keep the group's current blend space, composite space, and composite
|
||||
* mode.
|
||||
*/
|
||||
blend_space = gimp_layer_get_blend_space (GIMP_LAYER (group));
|
||||
composite_space = gimp_layer_get_composite_space (GIMP_LAYER (group));
|
||||
composite_mode = gimp_layer_get_composite_mode (GIMP_LAYER (group));
|
||||
|
||||
gimp_layer_set_mode (GIMP_LAYER (group), GIMP_LAYER_MODE_NORMAL, TRUE);
|
||||
gimp_layer_set_blend_space (GIMP_LAYER (group), blend_space, TRUE);
|
||||
gimp_layer_set_composite_space (GIMP_LAYER (group), composite_space, TRUE);
|
||||
gimp_layer_set_composite_mode (GIMP_LAYER (group), composite_mode, TRUE);
|
||||
}
|
||||
is_pass_through = (gimp_layer_get_mode (GIMP_LAYER (group)) == GIMP_LAYER_MODE_PASS_THROUGH &&
|
||||
gimp_item_get_visible (GIMP_ITEM (group)));
|
||||
|
||||
/* Merge down filter effects */
|
||||
gimp_drawable_merge_filters (GIMP_DRAWABLE (group));
|
||||
|
|
@ -460,6 +441,39 @@ gimp_image_merge_group_layer (GimpImage *image,
|
|||
gimp_image_remove_layer (image, GIMP_LAYER (group), TRUE, NULL);
|
||||
gimp_image_add_layer (image, layer, parent, index, TRUE);
|
||||
|
||||
/* For pass-through group layers, we must remove all "big sister"
|
||||
* layers, i.e. all layers on the same level below the newly merged
|
||||
* layer, because their render is already integrated in the merged
|
||||
* layer. Therefore keeping them would change the whole image's
|
||||
* rendering.
|
||||
*/
|
||||
if (is_pass_through)
|
||||
{
|
||||
GimpContainer *stack;
|
||||
GList *iter;
|
||||
GList *new_selected = g_list_prepend (NULL, layer);
|
||||
GList *to_remove = NULL;
|
||||
gboolean remove = FALSE;
|
||||
|
||||
if (parent)
|
||||
stack = gimp_viewable_get_children (GIMP_VIEWABLE (parent));
|
||||
else
|
||||
stack = gimp_image_get_layers (image);
|
||||
|
||||
for (iter = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (stack)); iter; iter = iter->next)
|
||||
{
|
||||
if (iter->data == layer)
|
||||
remove = TRUE;
|
||||
else if (remove && gimp_item_get_visible (iter->data))
|
||||
to_remove = g_list_prepend (to_remove, iter->data);
|
||||
}
|
||||
|
||||
for (iter = to_remove; iter; iter = iter->next)
|
||||
gimp_image_remove_layer (image, GIMP_LAYER (iter->data), TRUE, new_selected);
|
||||
|
||||
g_list_free (new_selected);
|
||||
}
|
||||
|
||||
gimp_image_undo_group_end (image);
|
||||
|
||||
return layer;
|
||||
|
|
|
|||
|
|
@ -937,16 +937,46 @@ gimp_layer_duplicate (GimpItem *item,
|
|||
GimpLayer *layer = GIMP_LAYER (item);
|
||||
GimpLayer *new_layer = GIMP_LAYER (new_item);
|
||||
|
||||
gimp_layer_set_mode (new_layer,
|
||||
gimp_layer_get_mode (layer), FALSE);
|
||||
gimp_layer_set_blend_space (new_layer,
|
||||
gimp_layer_get_blend_space (layer), FALSE);
|
||||
gimp_layer_set_composite_space (new_layer,
|
||||
gimp_layer_get_composite_space (layer), FALSE);
|
||||
gimp_layer_set_composite_mode (new_layer,
|
||||
gimp_layer_get_composite_mode (layer), FALSE);
|
||||
gimp_layer_set_opacity (new_layer,
|
||||
gimp_layer_get_opacity (layer), FALSE);
|
||||
/* PASS_THROUGH mode is invalid for regular layers.
|
||||
* We used to change the mode to NORMAL *before* duplicating (see
|
||||
* #793714 on bugzilla) but it would change the image's render.
|
||||
* Instead we first duplicate so that the group's render is used
|
||||
* as-is for the non-group duplicate layer. Then we set NORMAL
|
||||
* mode.
|
||||
*/
|
||||
if (gimp_layer_get_mode (layer) == GIMP_LAYER_MODE_PASS_THROUGH &&
|
||||
! GIMP_IS_GROUP_LAYER (new_item))
|
||||
{
|
||||
GimpLayerColorSpace blend_space;
|
||||
GimpLayerColorSpace composite_space;
|
||||
GimpLayerCompositeMode composite_mode;
|
||||
|
||||
/* keep the group's current blend space, composite space, and composite
|
||||
* mode.
|
||||
*/
|
||||
blend_space = gimp_layer_get_blend_space (layer);
|
||||
composite_space = gimp_layer_get_composite_space (layer);
|
||||
composite_mode = gimp_layer_get_composite_mode (layer);
|
||||
|
||||
gimp_layer_set_mode (new_layer, GIMP_LAYER_MODE_NORMAL, FALSE);
|
||||
gimp_layer_set_blend_space (new_layer, blend_space, FALSE);
|
||||
gimp_layer_set_composite_space (new_layer, composite_space, FALSE);
|
||||
gimp_layer_set_composite_mode (new_layer, composite_mode, FALSE);
|
||||
gimp_layer_set_opacity (new_layer, 1.0, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_layer_set_mode (new_layer,
|
||||
gimp_layer_get_mode (layer), FALSE);
|
||||
gimp_layer_set_blend_space (new_layer,
|
||||
gimp_layer_get_blend_space (layer), FALSE);
|
||||
gimp_layer_set_composite_space (new_layer,
|
||||
gimp_layer_get_composite_space (layer), FALSE);
|
||||
gimp_layer_set_composite_mode (new_layer,
|
||||
gimp_layer_get_composite_mode (layer), FALSE);
|
||||
gimp_layer_set_opacity (new_layer,
|
||||
gimp_layer_get_opacity (layer), FALSE);
|
||||
}
|
||||
|
||||
if (gimp_layer_can_lock_alpha (new_layer))
|
||||
gimp_layer_set_lock_alpha (new_layer,
|
||||
|
|
|
|||
Loading…
Reference in a new issue