app: resize group-layer mask after moving the group

We avoid resizing the mask as a result of changes in the group's
bounding box while the group is being moved (i.e., translated,
rotated, etc.), so that GimpLayer transforms the original mask,
rather than a cropped mask.  We still need to crop the mask after
we're finished moving the group, however.  This commit takes care
of that.
This commit is contained in:
Ell 2018-02-07 09:48:00 -05:00
parent 88c5eb6318
commit 94554fcc0c
1 changed files with 103 additions and 76 deletions

View File

@ -207,6 +207,7 @@ static void
static void gimp_group_layer_flush (GimpGroupLayer *group);
static void gimp_group_layer_update (GimpGroupLayer *group);
static void gimp_group_layer_update_size (GimpGroupLayer *group);
static void gimp_group_layer_update_mask_size (GimpGroupLayer *group);
static void gimp_group_layer_update_source_node (GimpGroupLayer *group);
static void gimp_group_layer_update_mode_node (GimpGroupLayer *group);
@ -608,6 +609,8 @@ gimp_group_layer_start_move (GimpItem *item,
{
GimpGroupLayerPrivate *private = GET_PRIVATE (item);
g_return_if_fail (private->suspend_mask == 0);
private->moving++;
if (GIMP_ITEM_CLASS (parent_class)->start_move)
@ -620,10 +623,16 @@ gimp_group_layer_end_move (GimpItem *item,
{
GimpGroupLayerPrivate *private = GET_PRIVATE (item);
g_return_if_fail (private->suspend_mask == 0);
g_return_if_fail (private->moving > 0);
if (GIMP_ITEM_CLASS (parent_class)->end_move)
GIMP_ITEM_CLASS (parent_class)->end_move (item, push_undo);
private->moving--;
if (private->moving == 0)
gimp_group_layer_update_mask_size (GIMP_GROUP_LAYER (item));
}
static void
@ -1715,6 +1724,8 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
{
GimpGroupLayerPrivate *private = GET_PRIVATE (group);
GimpItem *item = GIMP_ITEM (group);
GimpLayer *layer = GIMP_LAYER (group);
GimpItem *mask = GIMP_ITEM (gimp_layer_get_mask (layer));
gint old_x = gimp_item_get_offset_x (item);
gint old_y = gimp_item_get_offset_y (item);
gint old_width = gimp_item_get_width (item);
@ -1725,7 +1736,7 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
gint height = 1;
gboolean first = TRUE;
gboolean size_changed;
gboolean resize_mask ;
gboolean resize_mask;
GList *list;
for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (private->children));
@ -1770,13 +1781,11 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
width != old_width ||
height != old_height);
resize_mask = gimp_layer_get_mask (GIMP_LAYER (group)) && size_changed;
resize_mask = mask && size_changed;
/* if we show the mask, invalidate the old mask area */
if (resize_mask && gimp_layer_get_show_mask (GIMP_LAYER (group)))
if (resize_mask && gimp_layer_get_show_mask (layer))
{
GimpItem *mask = GIMP_ITEM (gimp_layer_get_mask (GIMP_LAYER (group)));
gimp_drawable_update (GIMP_DRAWABLE (group),
gimp_item_get_offset_x (mask) - old_x,
gimp_item_get_offset_y (mask) - old_y,
@ -1784,73 +1793,6 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
gimp_item_get_height (mask));
}
/* resize the mask if not moving (in which case, GimpLayer takes care of the
* mask)
*/
if (resize_mask && ! private->moving)
{
GimpItem *mask = GIMP_ITEM (gimp_layer_get_mask (GIMP_LAYER (group)));
GeglBuffer *buffer;
GeglBuffer *mask_buffer;
GeglRectangle mask_bounds;
GeglRectangle copy_bounds;
gboolean intersect;
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
gimp_drawable_get_format (GIMP_DRAWABLE (mask)));
if (private->suspended_mask_buffer)
{
/* copy the suspended mask into the new mask */
mask_buffer = private->suspended_mask_buffer;
mask_bounds = private->suspended_mask_bounds;
}
else
{
/* copy the old mask into the new mask */
mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
mask_bounds.x = gimp_item_get_offset_x (mask);
mask_bounds.y = gimp_item_get_offset_y (mask);
mask_bounds.width = gimp_item_get_width (mask);
mask_bounds.height = gimp_item_get_height (mask);
}
intersect = gimp_rectangle_intersect (mask_bounds.x,
mask_bounds.y,
mask_bounds.width,
mask_bounds.height,
x,
y,
width,
height,
&copy_bounds.x,
&copy_bounds.y,
&copy_bounds.width,
&copy_bounds.height);
if (intersect)
{
gegl_buffer_copy (mask_buffer,
GEGL_RECTANGLE (copy_bounds.x - mask_bounds.x,
copy_bounds.y - mask_bounds.y,
copy_bounds.width,
copy_bounds.height),
GEGL_ABYSS_NONE,
buffer,
GEGL_RECTANGLE (copy_bounds.x - x,
copy_bounds.y - y,
copy_bounds.width,
copy_bounds.height));
}
gimp_drawable_set_buffer_full (GIMP_DRAWABLE (mask),
FALSE, NULL,
buffer, x, y);
g_object_unref (buffer);
}
if (private->reallocate_projection || size_changed)
{
/* if the graph is already constructed, set the offset node's
@ -1911,11 +1853,15 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
}
}
/* if we show the mask, invalidate the new mask area */
if (resize_mask && gimp_layer_get_show_mask (GIMP_LAYER (group)))
{
GimpItem *mask = GIMP_ITEM (gimp_layer_get_mask (GIMP_LAYER (group)));
/* resize the mask if not moving (in which case, GimpLayer takes care of the
* mask)
*/
if (resize_mask && ! private->moving)
gimp_group_layer_update_mask_size (group);
/* if we show the mask, invalidate the new mask area */
if (resize_mask && gimp_layer_get_show_mask (layer))
{
gimp_drawable_update (GIMP_DRAWABLE (group),
gimp_item_get_offset_x (mask) - x,
gimp_item_get_offset_y (mask) - y,
@ -1924,6 +1870,87 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
}
}
static void
gimp_group_layer_update_mask_size (GimpGroupLayer *group)
{
GimpGroupLayerPrivate *private = GET_PRIVATE (group);
GimpItem *item = GIMP_ITEM (group);
GimpItem *mask;
GeglBuffer *buffer;
GeglBuffer *mask_buffer;
GeglRectangle bounds;
GeglRectangle mask_bounds;
GeglRectangle copy_bounds;
gboolean intersect;
mask = GIMP_ITEM (gimp_layer_get_mask (GIMP_LAYER (group)));
if (! mask)
return;
bounds.x = gimp_item_get_offset_x (item);
bounds.y = gimp_item_get_offset_y (item);
bounds.width = gimp_item_get_width (item);
bounds.height = gimp_item_get_height (item);
mask_bounds.x = gimp_item_get_offset_x (mask);
mask_bounds.y = gimp_item_get_offset_y (mask);
mask_bounds.width = gimp_item_get_width (mask);
mask_bounds.height = gimp_item_get_height (mask);
if (gegl_rectangle_equal (&bounds, &mask_bounds))
return;
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, bounds.width, bounds.height),
gimp_drawable_get_format (GIMP_DRAWABLE (mask)));
if (private->suspended_mask_buffer)
{
/* copy the suspended mask into the new mask */
mask_buffer = private->suspended_mask_buffer;
mask_bounds = private->suspended_mask_bounds;
}
else
{
/* copy the old mask into the new mask */
mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
}
intersect = gimp_rectangle_intersect (bounds.x,
bounds.y,
bounds.width,
bounds.height,
mask_bounds.x,
mask_bounds.y,
mask_bounds.width,
mask_bounds.height,
&copy_bounds.x,
&copy_bounds.y,
&copy_bounds.width,
&copy_bounds.height);
if (intersect)
{
gegl_buffer_copy (mask_buffer,
GEGL_RECTANGLE (copy_bounds.x - mask_bounds.x,
copy_bounds.y - mask_bounds.y,
copy_bounds.width,
copy_bounds.height),
GEGL_ABYSS_NONE,
buffer,
GEGL_RECTANGLE (copy_bounds.x - bounds.x,
copy_bounds.y - bounds.y,
copy_bounds.width,
copy_bounds.height));
}
gimp_drawable_set_buffer_full (GIMP_DRAWABLE (mask),
FALSE, NULL,
buffer, bounds.x, bounds.y);
g_object_unref (buffer);
}
static void
gimp_group_layer_update_source_node (GimpGroupLayer *group)
{