[gimp] Bug 51112 - Support layer masks on layer groups
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] Bug 51112 - Support layer masks on layer groups
- Date: Mon, 5 Feb 2018 17:09:38 +0000 (UTC)
commit 36dec4e6b077851a3ced62e18149d68e4081c060
Author: Ell <ell_se yahoo com>
Date: Mon Feb 5 11:19:18 2018 -0500
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
app/actions/layers-actions.c | 6 +-
app/core/core-enums.c | 12 ++-
app/core/core-enums.h | 6 +-
app/core/gimpgrouplayer.c | 274 ++++++++++++++++++++++++++++++++++++++--
app/core/gimpgrouplayer.h | 26 +++-
app/core/gimpgrouplayerundo.c | 102 +++++++++++++--
app/core/gimpgrouplayerundo.h | 3 +
app/core/gimpimage-undo-push.c | 48 ++++++--
app/core/gimpimage-undo-push.h | 14 ++-
app/core/gimplayer.c | 35 +++++
10 files changed, 477 insertions(+), 49 deletions(-)
---
diff --git a/app/actions/layers-actions.c b/app/actions/layers-actions.c
index 34c1f15..a6369a7 100644
--- a/app/actions/layers-actions.c
+++ b/app/actions/layers-actions.c
@@ -975,9 +975,9 @@ layers_actions_update (GimpActionGroup *group,
SET_SENSITIVE ("layers-composite-mode-src-in", layer && cm_mutable);
SET_SENSITIVE ("layers-composite-mode-dst-atop", layer && cm_mutable);
- SET_SENSITIVE ("layers-mask-add", layer && !fs && !ac && !mask && !children);
- SET_SENSITIVE ("layers-mask-add-button", layer && !fs && !ac && !children);
- SET_SENSITIVE ("layers-mask-add-last-values", layer && !fs && !ac && !mask && !children);
+ SET_SENSITIVE ("layers-mask-add", layer && !fs && !ac && !mask);
+ SET_SENSITIVE ("layers-mask-add-button", layer && !fs && !ac);
+ SET_SENSITIVE ("layers-mask-add-last-values", layer && !fs && !ac && !mask);
SET_SENSITIVE ("layers-mask-apply", writable && !fs && !ac && mask && !children);
SET_SENSITIVE ("layers-mask-delete", layer && !fs && !ac && mask);
diff --git a/app/core/core-enums.c b/app/core/core-enums.c
index 20c3a32..83076d5 100644
--- a/app/core/core-enums.c
+++ b/app/core/core-enums.c
@@ -793,8 +793,10 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_LAYER_MODE, "GIMP_UNDO_LAYER_MODE", "layer-mode" },
{ GIMP_UNDO_LAYER_OPACITY, "GIMP_UNDO_LAYER_OPACITY", "layer-opacity" },
{ GIMP_UNDO_LAYER_LOCK_ALPHA, "GIMP_UNDO_LAYER_LOCK_ALPHA", "layer-lock-alpha" },
- { GIMP_UNDO_GROUP_LAYER_SUSPEND, "GIMP_UNDO_GROUP_LAYER_SUSPEND", "group-layer-suspend" },
- { GIMP_UNDO_GROUP_LAYER_RESUME, "GIMP_UNDO_GROUP_LAYER_RESUME", "group-layer-resume" },
+ { GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE, "GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE",
"group-layer-suspend-resize" },
+ { GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE, "GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE",
"group-layer-resume-resize" },
+ { GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK, "GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK", "group-layer-suspend-mask" },
+ { GIMP_UNDO_GROUP_LAYER_RESUME_MASK, "GIMP_UNDO_GROUP_LAYER_RESUME_MASK", "group-layer-resume-mask" },
{ GIMP_UNDO_GROUP_LAYER_CONVERT, "GIMP_UNDO_GROUP_LAYER_CONVERT", "group-layer-convert" },
{ GIMP_UNDO_TEXT_LAYER, "GIMP_UNDO_TEXT_LAYER", "text-layer" },
{ GIMP_UNDO_TEXT_LAYER_MODIFIED, "GIMP_UNDO_TEXT_LAYER_MODIFIED", "text-layer-modified" },
@@ -886,8 +888,10 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_LAYER_MODE, NC_("undo-type", "Set layer mode"), NULL },
{ GIMP_UNDO_LAYER_OPACITY, NC_("undo-type", "Set layer opacity"), NULL },
{ GIMP_UNDO_LAYER_LOCK_ALPHA, NC_("undo-type", "Lock/Unlock alpha channel"), NULL },
- { GIMP_UNDO_GROUP_LAYER_SUSPEND, NC_("undo-type", "Suspend group layer resize"), NULL },
- { GIMP_UNDO_GROUP_LAYER_RESUME, NC_("undo-type", "Resume group layer resize"), NULL },
+ { GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE, NC_("undo-type", "Suspend group layer resize"), NULL },
+ { GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE, NC_("undo-type", "Resume group layer resize"), NULL },
+ { GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK, NC_("undo-type", "Suspend group layer mask"), NULL },
+ { GIMP_UNDO_GROUP_LAYER_RESUME_MASK, NC_("undo-type", "Resume group layer mask"), NULL },
{ GIMP_UNDO_GROUP_LAYER_CONVERT, NC_("undo-type", "Convert group layer"), NULL },
{ GIMP_UNDO_TEXT_LAYER, NC_("undo-type", "Text layer"), NULL },
{ GIMP_UNDO_TEXT_LAYER_MODIFIED, NC_("undo-type", "Text layer modification"), NULL },
diff --git a/app/core/core-enums.h b/app/core/core-enums.h
index 51db731..9cd2cdb 100644
--- a/app/core/core-enums.h
+++ b/app/core/core-enums.h
@@ -410,8 +410,10 @@ typedef enum /*< pdb-skip >*/
GIMP_UNDO_LAYER_MODE, /*< desc="Set layer mode" >*/
GIMP_UNDO_LAYER_OPACITY, /*< desc="Set layer opacity" >*/
GIMP_UNDO_LAYER_LOCK_ALPHA, /*< desc="Lock/Unlock alpha channel" >*/
- GIMP_UNDO_GROUP_LAYER_SUSPEND, /*< desc="Suspend group layer resize" >*/
- GIMP_UNDO_GROUP_LAYER_RESUME, /*< desc="Resume group layer resize" >*/
+ GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE,/*< desc="Suspend group layer resize" >*/
+ GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE,/*< desc="Resume group layer resize" >*/
+ GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK, /*< desc="Suspend group layer mask" >*/
+ GIMP_UNDO_GROUP_LAYER_RESUME_MASK, /*< desc="Resume group layer mask" >*/
GIMP_UNDO_GROUP_LAYER_CONVERT, /*< desc="Convert group layer" >*/
GIMP_UNDO_TEXT_LAYER, /*< desc="Text layer" >*/
GIMP_UNDO_TEXT_LAYER_MODIFIED, /*< desc="Text layer modification" >*/
diff --git a/app/core/gimpgrouplayer.c b/app/core/gimpgrouplayer.c
index a7746f8..0a045c6 100644
--- a/app/core/gimpgrouplayer.c
+++ b/app/core/gimpgrouplayer.c
@@ -34,6 +34,7 @@
#include "gimpgrouplayer.h"
#include "gimpimage.h"
+#include "gimpimage-undo.h"
#include "gimpimage-undo-push.h"
#include "gimplayerstack.h"
#include "gimppickable.h"
@@ -54,6 +55,10 @@ struct _GimpGroupLayerPrivate
GeglNode *graph;
GeglNode *offset_node;
gint suspend_resize;
+ gint suspend_mask;
+ GeglBuffer *suspended_mask_buffer;
+ GeglRectangle suspended_mask_bounds;
+ gint moving;
gboolean expanded;
gboolean pass_through;
@@ -100,6 +105,10 @@ static GimpItem * gimp_group_layer_duplicate (GimpItem *item,
static void gimp_group_layer_convert (GimpItem *item,
GimpImage *dest_image,
GType old_type);
+static void gimp_group_layer_start_move (GimpItem *item,
+ gboolean push_undo);
+static void gimp_group_layer_end_move (GimpItem *item,
+ gboolean push_undo);
static gint64 gimp_group_layer_estimate_memsize (GimpDrawable *drawable,
GimpComponentType component_type,
@@ -257,6 +266,8 @@ gimp_group_layer_class_init (GimpGroupLayerClass *klass)
item_class->is_position_locked = gimp_group_layer_is_position_locked;
item_class->duplicate = gimp_group_layer_duplicate;
item_class->convert = gimp_group_layer_convert;
+ item_class->start_move = gimp_group_layer_start_move;
+ item_class->end_move = gimp_group_layer_end_move;
item_class->default_name = _("Layer Group");
item_class->rename_desc = C_("undo-type", "Rename Layer Group");
@@ -590,6 +601,30 @@ gimp_group_layer_convert (GimpItem *item,
GIMP_ITEM_CLASS (parent_class)->convert (item, dest_image, old_type);
}
+static void
+gimp_group_layer_start_move (GimpItem *item,
+ gboolean push_undo)
+{
+ GimpGroupLayerPrivate *private = GET_PRIVATE (item);
+
+ private->moving++;
+
+ if (GIMP_ITEM_CLASS (parent_class)->start_move)
+ GIMP_ITEM_CLASS (parent_class)->start_move (item, push_undo);
+}
+
+static void
+gimp_group_layer_end_move (GimpItem *item,
+ gboolean push_undo)
+{
+ GimpGroupLayerPrivate *private = GET_PRIVATE (item);
+
+ if (GIMP_ITEM_CLASS (parent_class)->end_move)
+ GIMP_ITEM_CLASS (parent_class)->end_move (item, push_undo);
+
+ private->moving--;
+}
+
static gint64
gimp_group_layer_estimate_memsize (GimpDrawable *drawable,
GimpComponentType component_type,
@@ -1041,6 +1076,8 @@ gimp_group_layer_excludes_backdrop_changed (GimpLayer *layer)
static void
gimp_group_layer_mask_changed (GimpLayer *layer)
{
+ g_warn_if_fail (GET_PRIVATE (layer)->suspend_mask == 0);
+
gimp_layer_update_effective_mode (layer);
if (GIMP_LAYER_CLASS (parent_class)->mask_changed)
@@ -1341,8 +1378,8 @@ gimp_group_layer_suspend_resize (GimpGroupLayer *group,
push_undo = FALSE;
if (push_undo)
- gimp_image_undo_push_group_layer_suspend (gimp_item_get_image (item),
- NULL, group);
+ gimp_image_undo_push_group_layer_suspend_resize (gimp_item_get_image (item),
+ NULL, group);
GET_PRIVATE (group)->suspend_resize++;
}
@@ -1366,8 +1403,8 @@ gimp_group_layer_resume_resize (GimpGroupLayer *group,
push_undo = FALSE;
if (push_undo)
- gimp_image_undo_push_group_layer_resume (gimp_item_get_image (item),
- NULL, group);
+ gimp_image_undo_push_group_layer_resume_resize (gimp_item_get_image (item),
+ NULL, group);
private->suspend_resize--;
@@ -1377,6 +1414,129 @@ gimp_group_layer_resume_resize (GimpGroupLayer *group,
}
}
+void
+gimp_group_layer_suspend_mask (GimpGroupLayer *group,
+ gboolean push_undo)
+{
+ GimpGroupLayerPrivate *private;
+ GimpItem *item;
+
+ g_return_if_fail (GIMP_IS_GROUP_LAYER (group));
+
+ private = GET_PRIVATE (group);
+ item = GIMP_ITEM (group);
+
+ if (! gimp_item_is_attached (item))
+ push_undo = FALSE;
+
+ if (push_undo)
+ gimp_image_undo_push_group_layer_suspend_mask (gimp_item_get_image (item),
+ NULL, group);
+
+ if (private->suspend_mask == 0)
+ {
+ if (gimp_layer_get_mask (GIMP_LAYER (group)))
+ {
+ GimpItem *mask = GIMP_ITEM (gimp_layer_get_mask (GIMP_LAYER (group)));
+
+ private->suspended_mask_buffer =
+ g_object_ref (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)));
+
+ private->suspended_mask_bounds.x = gimp_item_get_offset_x (mask);
+ private->suspended_mask_bounds.y = gimp_item_get_offset_y (mask);
+ private->suspended_mask_bounds.width = gimp_item_get_width (mask);
+ private->suspended_mask_bounds.height = gimp_item_get_height (mask);
+ }
+ else
+ {
+ private->suspended_mask_buffer = NULL;
+ }
+ }
+
+ private->suspend_mask++;
+}
+
+void
+gimp_group_layer_resume_mask (GimpGroupLayer *group,
+ gboolean push_undo)
+{
+ GimpGroupLayerPrivate *private;
+ GimpItem *item;
+
+ g_return_if_fail (GIMP_IS_GROUP_LAYER (group));
+
+ private = GET_PRIVATE (group);
+
+ g_return_if_fail (private->suspend_mask > 0);
+
+ item = GIMP_ITEM (group);
+
+ if (! gimp_item_is_attached (item))
+ push_undo = FALSE;
+
+ if (push_undo)
+ gimp_image_undo_push_group_layer_resume_mask (gimp_item_get_image (item),
+ NULL, group);
+
+ private->suspend_mask--;
+
+ if (private->suspend_mask == 0)
+ g_clear_object (&private->suspended_mask_buffer);
+}
+
+
+/* protected functions */
+
+void
+_gimp_group_layer_set_suspended_mask (GimpGroupLayer *group,
+ GeglBuffer *buffer,
+ const GeglRectangle *bounds)
+{
+ GimpGroupLayerPrivate *private;
+
+ g_return_if_fail (GIMP_IS_GROUP_LAYER (group));
+ g_return_if_fail (buffer != NULL);
+ g_return_if_fail (bounds != NULL);
+
+ private = GET_PRIVATE (group);
+
+ g_return_if_fail (private->suspend_mask > 0);
+
+ g_object_ref (buffer);
+
+ g_clear_object (&private->suspended_mask_buffer);
+
+ private->suspended_mask_buffer = buffer;
+ private->suspended_mask_bounds = *bounds;
+}
+
+GeglBuffer *
+_gimp_group_layer_get_suspended_mask (GimpGroupLayer *group,
+ GeglRectangle *bounds)
+{
+ GimpGroupLayerPrivate *private;
+ GimpLayerMask *mask;
+
+ g_return_val_if_fail (GIMP_IS_GROUP_LAYER (group), NULL);
+ g_return_val_if_fail (bounds != NULL, NULL);
+
+ private = GET_PRIVATE (group);
+ mask = gimp_layer_get_mask (GIMP_LAYER (group));
+
+ g_return_val_if_fail (private->suspend_mask > 0, NULL);
+
+ if (mask &&
+ gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)) !=
+ private->suspended_mask_buffer)
+ {
+ *bounds = private->suspended_mask_bounds;
+
+ return private->suspended_mask_buffer;
+ }
+
+ return NULL;
+}
+
/* private functions */
@@ -1501,6 +1661,8 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
gint width = 1;
gint height = 1;
gboolean first = TRUE;
+ gboolean size_changed;
+ gboolean resize_mask ;
GList *list;
for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (private->children));
@@ -1540,11 +1702,93 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
}
}
- if (private->reallocate_projection ||
- x != old_x ||
- y != old_y ||
- width != old_width ||
- height != old_height)
+ size_changed = (x != old_x ||
+ y != old_y ||
+ width != old_width ||
+ height != old_height);
+
+ resize_mask = gimp_layer_get_mask (GIMP_LAYER (group)) && size_changed;
+
+ /* if we show the mask, invalidate the old mask area */
+ if (resize_mask && gimp_layer_get_show_mask (GIMP_LAYER (group)))
+ {
+ 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,
+ gimp_item_get_width (mask),
+ 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,
+ ©_bounds.x,
+ ©_bounds.y,
+ ©_bounds.width,
+ ©_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
* coordinates first, so the graph is in the right state when
@@ -1603,6 +1847,18 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
gimp_group_layer_flush (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)));
+
+ gimp_drawable_update (GIMP_DRAWABLE (group),
+ gimp_item_get_offset_x (mask) - x,
+ gimp_item_get_offset_y (mask) - y,
+ gimp_item_get_width (mask),
+ gimp_item_get_height (mask));
+ }
}
static void
diff --git a/app/core/gimpgrouplayer.h b/app/core/gimpgrouplayer.h
index db0169f..6603fe6 100644
--- a/app/core/gimpgrouplayer.h
+++ b/app/core/gimpgrouplayer.h
@@ -46,16 +46,28 @@ struct _GimpGroupLayerClass
};
-GType gimp_group_layer_get_type (void) G_GNUC_CONST;
+GType gimp_group_layer_get_type (void) G_GNUC_CONST;
-GimpLayer * gimp_group_layer_new (GimpImage *image);
+GimpLayer * gimp_group_layer_new (GimpImage *image);
-GimpProjection * gimp_group_layer_get_projection (GimpGroupLayer *group);
+GimpProjection * gimp_group_layer_get_projection (GimpGroupLayer *group);
-void gimp_group_layer_suspend_resize (GimpGroupLayer *group,
- gboolean push_undo);
-void gimp_group_layer_resume_resize (GimpGroupLayer *group,
- gboolean push_undo);
+void gimp_group_layer_suspend_resize (GimpGroupLayer *group,
+ gboolean push_undo);
+void gimp_group_layer_resume_resize (GimpGroupLayer *group,
+ gboolean push_undo);
+
+void gimp_group_layer_suspend_mask (GimpGroupLayer *group,
+ gboolean push_undo);
+void gimp_group_layer_resume_mask (GimpGroupLayer *group,
+ gboolean push_undo);
+
+
+void _gimp_group_layer_set_suspended_mask (GimpGroupLayer *group,
+ GeglBuffer *buffer,
+ const GeglRectangle *bounds);
+GeglBuffer * _gimp_group_layer_get_suspended_mask (GimpGroupLayer *group,
+ GeglRectangle *bounds);
#endif /* __GIMP_GROUP_LAYER_H__ */
diff --git a/app/core/gimpgrouplayerundo.c b/app/core/gimpgrouplayerundo.c
index 6c30c04..63aa02c 100644
--- a/app/core/gimpgrouplayerundo.c
+++ b/app/core/gimpgrouplayerundo.c
@@ -22,16 +22,22 @@
#include "core-types.h"
+#include "gimp-memsize.h"
#include "gimpimage.h"
#include "gimpgrouplayer.h"
#include "gimpgrouplayerundo.h"
-static void gimp_group_layer_undo_constructed (GObject *object);
+static void gimp_group_layer_undo_constructed (GObject *object);
-static void gimp_group_layer_undo_pop (GimpUndo *undo,
- GimpUndoMode undo_mode,
- GimpUndoAccumulator *accum);
+static gint64 gimp_group_layer_undo_get_memsize (GimpObject *object,
+ gint64 *gui_size);
+
+static void gimp_group_layer_undo_pop (GimpUndo *undo,
+ GimpUndoMode undo_mode,
+ GimpUndoAccumulator *accum);
+static void gimp_group_layer_undo_free (GimpUndo *undo,
+ GimpUndoMode undo_mode);
G_DEFINE_TYPE (GimpGroupLayerUndo, gimp_group_layer_undo, GIMP_TYPE_ITEM_UNDO)
@@ -42,12 +48,16 @@ G_DEFINE_TYPE (GimpGroupLayerUndo, gimp_group_layer_undo, GIMP_TYPE_ITEM_UNDO)
static void
gimp_group_layer_undo_class_init (GimpGroupLayerUndoClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
+ GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass);
+
+ object_class->constructed = gimp_group_layer_undo_constructed;
- object_class->constructed = gimp_group_layer_undo_constructed;
+ gimp_object_class->get_memsize = gimp_group_layer_undo_get_memsize;
- undo_class->pop = gimp_group_layer_undo_pop;
+ undo_class->pop = gimp_group_layer_undo_pop;
+ undo_class->free = gimp_group_layer_undo_free;
}
static void
@@ -69,8 +79,19 @@ gimp_group_layer_undo_constructed (GObject *object)
switch (GIMP_UNDO (object)->undo_type)
{
- case GIMP_UNDO_GROUP_LAYER_SUSPEND:
- case GIMP_UNDO_GROUP_LAYER_RESUME:
+ case GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE:
+ case GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE:
+ case GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK:
+ break;
+
+ case GIMP_UNDO_GROUP_LAYER_RESUME_MASK:
+ group_layer_undo->prev_suspended_mask_buffer =
+ _gimp_group_layer_get_suspended_mask(
+ group,
+ &group_layer_undo->prev_suspended_mask_bounds);
+
+ if (group_layer_undo->prev_suspended_mask_buffer)
+ g_object_ref (group_layer_undo->prev_suspended_mask_buffer);
break;
case GIMP_UNDO_GROUP_LAYER_CONVERT:
@@ -84,6 +105,20 @@ gimp_group_layer_undo_constructed (GObject *object)
}
}
+static gint64
+gimp_group_layer_undo_get_memsize (GimpObject *object,
+ gint64 *gui_size)
+{
+ GimpGroupLayerUndo *group_layer_undo = GIMP_GROUP_LAYER_UNDO (object);
+ gint64 memsize = 0;
+
+ memsize +=
+ gimp_gegl_buffer_get_memsize (group_layer_undo->prev_suspended_mask_buffer);
+
+ return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
+ gui_size);
+}
+
static void
gimp_group_layer_undo_pop (GimpUndo *undo,
GimpUndoMode undo_mode,
@@ -98,12 +133,12 @@ gimp_group_layer_undo_pop (GimpUndo *undo,
switch (undo->undo_type)
{
- case GIMP_UNDO_GROUP_LAYER_SUSPEND:
- case GIMP_UNDO_GROUP_LAYER_RESUME:
+ case GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE:
+ case GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE:
if ((undo_mode == GIMP_UNDO_MODE_UNDO &&
- undo->undo_type == GIMP_UNDO_GROUP_LAYER_SUSPEND) ||
+ undo->undo_type == GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE) ||
(undo_mode == GIMP_UNDO_MODE_REDO &&
- undo->undo_type == GIMP_UNDO_GROUP_LAYER_RESUME))
+ undo->undo_type == GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE))
{
/* resume group layer auto-resizing */
@@ -117,6 +152,34 @@ gimp_group_layer_undo_pop (GimpUndo *undo,
}
break;
+ case GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK:
+ case GIMP_UNDO_GROUP_LAYER_RESUME_MASK:
+ if ((undo_mode == GIMP_UNDO_MODE_UNDO &&
+ undo->undo_type == GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK) ||
+ (undo_mode == GIMP_UNDO_MODE_REDO &&
+ undo->undo_type == GIMP_UNDO_GROUP_LAYER_RESUME_MASK))
+ {
+ /* resume group layer mask auto-resizing */
+
+ gimp_group_layer_resume_mask (group, FALSE);
+ }
+ else
+ {
+ /* suspend group layer mask auto-resizing */
+
+ gimp_group_layer_suspend_mask (group, FALSE);
+
+ if (undo->undo_type == GIMP_UNDO_GROUP_LAYER_RESUME_MASK &&
+ group_layer_undo->prev_suspended_mask_buffer)
+ {
+ _gimp_group_layer_set_suspended_mask (
+ group,
+ group_layer_undo->prev_suspended_mask_buffer,
+ &group_layer_undo->prev_suspended_mask_bounds);
+ }
+ }
+ break;
+
case GIMP_UNDO_GROUP_LAYER_CONVERT:
{
GimpImageBaseType type;
@@ -146,3 +209,14 @@ gimp_group_layer_undo_pop (GimpUndo *undo,
g_return_if_reached ();
}
}
+
+static void
+gimp_group_layer_undo_free (GimpUndo *undo,
+ GimpUndoMode undo_mode)
+{
+ GimpGroupLayerUndo *group_layer_undo = GIMP_GROUP_LAYER_UNDO (undo);
+
+ g_clear_object (&group_layer_undo->prev_suspended_mask_buffer);
+
+ GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode);
+}
diff --git a/app/core/gimpgrouplayerundo.h b/app/core/gimpgrouplayerundo.h
index 61502b2..f4dd039 100644
--- a/app/core/gimpgrouplayerundo.h
+++ b/app/core/gimpgrouplayerundo.h
@@ -37,6 +37,9 @@ struct _GimpGroupLayerUndo
{
GimpItemUndo parent_instance;
+ GeglBuffer *prev_suspended_mask_buffer;
+ GeglRectangle prev_suspended_mask_bounds;
+
GimpImageBaseType prev_type;
GimpPrecision prev_precision;
gboolean prev_has_alpha;
diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c
index 670cc42..77c55fd 100644
--- a/app/core/gimpimage-undo-push.c
+++ b/app/core/gimpimage-undo-push.c
@@ -608,32 +608,64 @@ gimp_image_undo_push_layer_lock_alpha (GimpImage *image,
/***********************/
GimpUndo *
-gimp_image_undo_push_group_layer_suspend (GimpImage *image,
- const gchar *undo_desc,
- GimpGroupLayer *group)
+gimp_image_undo_push_group_layer_suspend_resize (GimpImage *image,
+ const gchar *undo_desc,
+ GimpGroupLayer *group)
+{
+ g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+ g_return_val_if_fail (GIMP_IS_GROUP_LAYER (group), NULL);
+ g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (group)), NULL);
+
+ return gimp_image_undo_push (image, GIMP_TYPE_GROUP_LAYER_UNDO,
+ GIMP_UNDO_GROUP_LAYER_SUSPEND_RESIZE, undo_desc,
+ GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE,
+ "item", group,
+ NULL);
+}
+
+GimpUndo *
+gimp_image_undo_push_group_layer_resume_resize (GimpImage *image,
+ const gchar *undo_desc,
+ GimpGroupLayer *group)
+{
+ g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+ g_return_val_if_fail (GIMP_IS_GROUP_LAYER (group), NULL);
+ g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (group)), NULL);
+
+ return gimp_image_undo_push (image, GIMP_TYPE_GROUP_LAYER_UNDO,
+ GIMP_UNDO_GROUP_LAYER_RESUME_RESIZE, undo_desc,
+ GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE,
+ "item", group,
+ NULL);
+}
+
+GimpUndo *
+gimp_image_undo_push_group_layer_suspend_mask (GimpImage *image,
+ const gchar *undo_desc,
+ GimpGroupLayer *group)
{
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
g_return_val_if_fail (GIMP_IS_GROUP_LAYER (group), NULL);
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (group)), NULL);
return gimp_image_undo_push (image, GIMP_TYPE_GROUP_LAYER_UNDO,
- GIMP_UNDO_GROUP_LAYER_SUSPEND, undo_desc,
+ GIMP_UNDO_GROUP_LAYER_SUSPEND_MASK, undo_desc,
GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE,
"item", group,
NULL);
}
GimpUndo *
-gimp_image_undo_push_group_layer_resume (GimpImage *image,
- const gchar *undo_desc,
- GimpGroupLayer *group)
+gimp_image_undo_push_group_layer_resume_mask (GimpImage *image,
+ const gchar *undo_desc,
+ GimpGroupLayer *group)
{
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
g_return_val_if_fail (GIMP_IS_GROUP_LAYER (group), NULL);
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (group)), NULL);
return gimp_image_undo_push (image, GIMP_TYPE_GROUP_LAYER_UNDO,
- GIMP_UNDO_GROUP_LAYER_RESUME, undo_desc,
+ GIMP_UNDO_GROUP_LAYER_RESUME_MASK, undo_desc,
GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE,
"item", group,
NULL);
diff --git a/app/core/gimpimage-undo-push.h b/app/core/gimpimage-undo-push.h
index 57bc970..d2c1530 100644
--- a/app/core/gimpimage-undo-push.h
+++ b/app/core/gimpimage-undo-push.h
@@ -145,10 +145,20 @@ GimpUndo * gimp_image_undo_push_layer_lock_alpha (GimpImage *image,
/* group layer undos */
-GimpUndo * gimp_image_undo_push_group_layer_suspend (GimpImage *image,
+GimpUndo *
+ gimp_image_undo_push_group_layer_suspend_resize (GimpImage *image,
const gchar *undo_desc,
GimpGroupLayer *group);
-GimpUndo * gimp_image_undo_push_group_layer_resume (GimpImage *image,
+GimpUndo *
+ gimp_image_undo_push_group_layer_resume_resize (GimpImage *image,
+ const gchar *undo_desc,
+ GimpGroupLayer *group);
+GimpUndo *
+ gimp_image_undo_push_group_layer_suspend_mask (GimpImage *image,
+ const gchar *undo_desc,
+ GimpGroupLayer *group);
+GimpUndo *
+ gimp_image_undo_push_group_layer_resume_mask (GimpImage *image,
const gchar *undo_desc,
GimpGroupLayer *group);
GimpUndo * gimp_image_undo_push_group_layer_convert (GimpImage *image,
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index fe33e92..ed971be 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -44,6 +44,7 @@
#include "gimpcontainer.h"
#include "gimpdrawable-floating-selection.h"
#include "gimperror.h"
+#include "gimpgrouplayer.h"
#include "gimpimage-undo-push.h"
#include "gimpimage-undo.h"
#include "gimpimage.h"
@@ -128,6 +129,10 @@ static gboolean gimp_layer_rename (GimpItem *item,
const gchar *new_name,
const gchar *undo_desc,
GError **error);
+static void gimp_layer_start_move (GimpItem *item,
+ gboolean push_undo);
+static void gimp_layer_end_move (GimpItem *item,
+ gboolean push_undo);
static void gimp_layer_translate (GimpItem *item,
gint offset_x,
gint offset_y,
@@ -421,6 +426,8 @@ gimp_layer_class_init (GimpLayerClass *klass)
item_class->duplicate = gimp_layer_duplicate;
item_class->convert = gimp_layer_convert;
item_class->rename = gimp_layer_rename;
+ item_class->start_move = gimp_layer_start_move;
+ item_class->end_move = gimp_layer_end_move;
item_class->translate = gimp_layer_translate;
item_class->scale = gimp_layer_scale;
item_class->resize = gimp_layer_resize;
@@ -1050,6 +1057,34 @@ gimp_layer_rename (GimpItem *item,
}
static void
+gimp_layer_start_move (GimpItem *item,
+ gboolean push_undo)
+{
+ GimpLayer *layer = GIMP_LAYER (item);
+
+ /* suspend mask cropping for all of the layer's ancestors */
+ while ((layer = gimp_layer_get_parent (layer)))
+ gimp_group_layer_suspend_mask (GIMP_GROUP_LAYER (layer), push_undo);
+
+ if (GIMP_ITEM_CLASS (parent_class)->start_move)
+ GIMP_ITEM_CLASS (parent_class)->start_move (item, push_undo);
+}
+
+static void
+gimp_layer_end_move (GimpItem *item,
+ gboolean push_undo)
+{
+ GimpLayer *layer = GIMP_LAYER (item);
+
+ if (GIMP_ITEM_CLASS (parent_class)->end_move)
+ GIMP_ITEM_CLASS (parent_class)->end_move (item, push_undo);
+
+ /* resume mask cropping for all of the layer's ancestors */
+ while ((layer = gimp_layer_get_parent (layer)))
+ gimp_group_layer_resume_mask (GIMP_GROUP_LAYER (layer), push_undo);
+}
+
+static void
gimp_layer_translate (GimpItem *item,
gint offset_x,
gint offset_y,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]