Add facility to compress multiple group layer resizings into one

* app/core/gimpgrouplayer.[ch]: add gimp_group_layer_suspend_resize()
  and gimp_group_layer_resume_resize() and call them around functions
  where all a group's children are transformed (translated, resized
  etc).  This way we go from the worst case of reallocating the
  group's projection tiles once for each child down to exactly one
  reallocation.

* app/core/Makefile.am
* app/core/core-enums.[ch]
* app/core/core-types.h
* app/core/gimpimage-undo-push.[ch]
* app/core/gimpgrouplayerundo.[ch]: add new undo class
  GimpGroupLayerUndo which implements undos for suspend/resume of
  group layers and calls them in reverse order when undoing.
This commit is contained in:
Michael Natterer 2009-09-07 13:04:55 +02:00
parent 6a10485f6b
commit 4df9b25217
10 changed files with 305 additions and 11 deletions

View File

@ -185,6 +185,8 @@ libappcore_a_sources = \
gimpgrid.h \
gimpgrouplayer.c \
gimpgrouplayer.h \
gimpgrouplayerundo.c \
gimpgrouplayerundo.h \
gimpguide.c \
gimpguide.h \
gimpguideundo.c \

View File

@ -839,6 +839,8 @@ 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_TEXT_LAYER, "GIMP_UNDO_TEXT_LAYER", "text-layer" },
{ GIMP_UNDO_TEXT_LAYER_MODIFIED, "GIMP_UNDO_TEXT_LAYER_MODIFIED", "text-layer-modified" },
{ GIMP_UNDO_LAYER_MASK_ADD, "GIMP_UNDO_LAYER_MASK_ADD", "layer-mask-add" },
@ -924,6 +926,8 @@ 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_TEXT_LAYER, NC_("undo-type", "Text layer"), NULL },
{ GIMP_UNDO_TEXT_LAYER_MODIFIED, NC_("undo-type", "Text layer modification"), NULL },
{ GIMP_UNDO_LAYER_MASK_ADD, NC_("undo-type", "Add layer mask"), NULL },

View File

@ -420,6 +420,8 @@ 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_TEXT_LAYER, /*< desc="Text layer" >*/
GIMP_UNDO_TEXT_LAYER_MODIFIED, /*< desc="Text layer modification" >*/
GIMP_UNDO_LAYER_MASK_ADD, /*< desc="Add layer mask" >*/

View File

@ -129,6 +129,7 @@ typedef struct _GimpLayerMaskUndo GimpLayerMaskUndo;
typedef struct _GimpLayerMaskPropUndo GimpLayerMaskPropUndo;
typedef struct _GimpLayerUndo GimpLayerUndo;
typedef struct _GimpLayerPropUndo GimpLayerPropUndo;
typedef struct _GimpGroupLayerUndo GimpGroupLayerUndo;
typedef struct _GimpMaskUndo GimpMaskUndo;
typedef struct _GimpGuideUndo GimpGuideUndo;
typedef struct _GimpSamplePointUndo GimpSamplePointUndo;

View File

@ -33,6 +33,7 @@
#include "gimpgrouplayer.h"
#include "gimpimage.h"
#include "gimpimage-undo-push.h"
#include "gimpdrawablestack.h"
#include "gimppickable.h"
#include "gimpprojectable.h"
@ -118,7 +119,8 @@ static void gimp_group_layer_child_move (GimpLayer *child,
static void gimp_group_layer_child_resize (GimpLayer *child,
GimpGroupLayer *group);
static void gimp_group_layer_update_size (GimpGroupLayer *group);
static void gimp_group_layer_update (GimpGroupLayer *group);
static void gimp_group_layer_update_size (GimpGroupLayer *group);
static void gimp_group_layer_stack_update (GimpDrawableStack *stack,
gint x,
@ -395,6 +397,9 @@ gimp_group_layer_translate (GimpItem *item,
GimpLayerMask *mask;
GList *list;
/* don't push an undo here because undo will call us again */
gimp_group_layer_suspend_resize (group, FALSE);
for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (group->children));
list;
list = g_list_next (list))
@ -415,6 +420,9 @@ gimp_group_layer_translate (GimpItem *item,
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (mask));
}
/* don't push an undo here because undo will call us again */
gimp_group_layer_resume_resize (group, FALSE);
}
static void
@ -440,6 +448,8 @@ gimp_group_layer_scale (GimpItem *item,
old_offset_x = gimp_item_get_offset_x (item);
old_offset_y = gimp_item_get_offset_y (item);
gimp_group_layer_suspend_resize (group, TRUE);
list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (group->children));
while (list)
@ -488,6 +498,8 @@ gimp_group_layer_scale (GimpItem *item,
new_width, new_height,
new_offset_x, new_offset_y,
interpolation_type, progress);
gimp_group_layer_resume_resize (group, TRUE);
}
static void
@ -506,6 +518,8 @@ gimp_group_layer_resize (GimpItem *item,
x = gimp_item_get_offset_x (item) - offset_x;
y = gimp_item_get_offset_y (item) - offset_y;
gimp_group_layer_suspend_resize (group, TRUE);
list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (group->children));
while (list)
@ -555,6 +569,8 @@ gimp_group_layer_resize (GimpItem *item,
if (mask)
gimp_item_resize (GIMP_ITEM (mask), context,
new_width, new_height, offset_x, offset_y);
gimp_group_layer_resume_resize (group, TRUE);
}
static void
@ -568,6 +584,8 @@ gimp_group_layer_flip (GimpItem *item,
GimpLayerMask *mask;
GList *list;
gimp_group_layer_suspend_resize (group, TRUE);
for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (group->children));
list;
list = g_list_next (list))
@ -583,6 +601,8 @@ gimp_group_layer_flip (GimpItem *item,
if (mask)
gimp_item_flip (GIMP_ITEM (mask), context,
flip_type, axis, clip_result);
gimp_group_layer_resume_resize (group, TRUE);
}
static void
@ -597,6 +617,8 @@ gimp_group_layer_rotate (GimpItem *item,
GimpLayerMask *mask;
GList *list;
gimp_group_layer_suspend_resize (group, TRUE);
for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (group->children));
list;
list = g_list_next (list))
@ -612,6 +634,8 @@ gimp_group_layer_rotate (GimpItem *item,
if (mask)
gimp_item_rotate (GIMP_ITEM (mask), context,
rotate_type, center_x, center_y, clip_result);
gimp_group_layer_resume_resize (group, TRUE);
}
static void
@ -628,6 +652,8 @@ gimp_group_layer_transform (GimpItem *item,
GimpLayerMask *mask;
GList *list;
gimp_group_layer_suspend_resize (group, TRUE);
for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (group->children));
list;
list = g_list_next (list))
@ -647,6 +673,8 @@ gimp_group_layer_transform (GimpItem *item,
matrix, direction,
interpolation_type, recursion_level,
clip_result, progress);
gimp_group_layer_resume_resize (group, TRUE);
}
static gint64
@ -758,6 +786,52 @@ gimp_group_layer_new (GimpImage *image)
return GIMP_LAYER (group);
}
void
gimp_group_layer_suspend_resize (GimpGroupLayer *group,
gboolean push_undo)
{
GimpItem *item;
g_return_if_fail (GIMP_IS_GROUP_LAYER (group));
item = GIMP_ITEM (group);
if (! gimp_item_is_attached (item))
push_undo = FALSE;
if (push_undo)
gimp_image_undo_push_group_layer_suspend (gimp_item_get_image (item),
NULL, group);
group->suspend_resize++;
}
void
gimp_group_layer_resume_resize (GimpGroupLayer *group,
gboolean push_undo)
{
GimpItem *item;
g_return_if_fail (GIMP_IS_GROUP_LAYER (group));
g_return_if_fail (group->suspend_resize > 0);
item = GIMP_ITEM (group);
if (! gimp_item_is_attached (item))
push_undo = FALSE;
if (push_undo)
gimp_image_undo_push_group_layer_resume (gimp_item_get_image (item),
NULL, group);
group->suspend_resize--;
if (group->suspend_resize == 0)
{
gimp_group_layer_update_size (group);
}
}
/* private functions */
@ -766,7 +840,7 @@ gimp_group_layer_child_add (GimpContainer *container,
GimpLayer *child,
GimpGroupLayer *group)
{
gimp_group_layer_update_size (group);
gimp_group_layer_update (group);
}
static void
@ -774,7 +848,7 @@ gimp_group_layer_child_remove (GimpContainer *container,
GimpLayer *child,
GimpGroupLayer *group)
{
gimp_group_layer_update_size (group);
gimp_group_layer_update (group);
}
static void
@ -782,20 +856,31 @@ gimp_group_layer_child_move (GimpLayer *child,
GParamSpec *pspec,
GimpGroupLayer *group)
{
gimp_group_layer_update_size (group);
gimp_group_layer_update (group);
}
static void
gimp_group_layer_child_resize (GimpLayer *child,
GimpGroupLayer *group)
{
gimp_group_layer_update_size (group);
gimp_group_layer_update (group);
}
static void
gimp_group_layer_update (GimpGroupLayer *group)
{
if (group->suspend_resize == 0)
{
gimp_group_layer_update_size (group);
}
}
static void
gimp_group_layer_update_size (GimpGroupLayer *group)
{
GimpItem *item = GIMP_ITEM (group);
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);
gint old_height = gimp_item_get_height (item);
gint x = 0;
@ -831,9 +916,9 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
}
}
if (x != gimp_item_get_offset_x (item) ||
y != gimp_item_get_offset_y (item) ||
width != old_width ||
if (x != old_x ||
y != old_y ||
width != old_width ||
height != old_height)
{
if (width != old_width ||

View File

@ -43,6 +43,7 @@ struct _GimpGroupLayer
GimpProjection *projection;
GeglNode *graph;
GeglNode *offset_node;
gint suspend_resize;
};
struct _GimpGroupLayerClass
@ -51,9 +52,14 @@ 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);
void gimp_group_layer_suspend_resize (GimpGroupLayer *group,
gboolean push_undo);
void gimp_group_layer_resume_resize (GimpGroupLayer *group,
gboolean push_undo);
#endif /* __GIMP_GROUP_LAYER_H__ */

View File

@ -0,0 +1,97 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include "core-types.h"
#include "gimpimage.h"
#include "gimpgrouplayer.h"
#include "gimpgrouplayerundo.h"
static GObject * gimp_group_layer_undo_constructor (GType type,
guint n_params,
GObjectConstructParam *params);
static void gimp_group_layer_undo_pop (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
G_DEFINE_TYPE (GimpGroupLayerUndo, gimp_group_layer_undo, GIMP_TYPE_ITEM_UNDO)
#define parent_class gimp_group_layer_undo_parent_class
static void
gimp_group_layer_undo_class_init (GimpGroupLayerUndoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass);
object_class->constructor = gimp_group_layer_undo_constructor;
undo_class->pop = gimp_group_layer_undo_pop;
}
static void
gimp_group_layer_undo_init (GimpGroupLayerUndo *undo)
{
}
static GObject *
gimp_group_layer_undo_constructor (GType type,
guint n_params,
GObjectConstructParam *params)
{
GObject *object;
object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
g_assert (GIMP_IS_GROUP_LAYER (GIMP_ITEM_UNDO (object)->item));
return object;
}
static void
gimp_group_layer_undo_pop (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
GimpGroupLayer *group = GIMP_GROUP_LAYER (GIMP_ITEM_UNDO (undo)->item);
GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum);
if ((undo_mode == GIMP_UNDO_MODE_UNDO &&
undo->undo_type == GIMP_UNDO_GROUP_LAYER_SUSPEND) ||
(undo_mode == GIMP_UNDO_MODE_REDO &&
undo->undo_type == GIMP_UNDO_GROUP_LAYER_RESUME))
{
/* resume group layer auto-resizing */
gimp_group_layer_resume_resize (group, FALSE);
}
else
{
/* suspend group layer auto-resizing */
gimp_group_layer_suspend_resize (group, FALSE);
}
}

View File

@ -0,0 +1,49 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_GROUP_LAYER_UNDO_H__
#define __GIMP_GROUP_LAYER_UNDO_H__
#include "gimpitemundo.h"
#define GIMP_TYPE_GROUP_LAYER_UNDO (gimp_group_layer_undo_get_type ())
#define GIMP_GROUP_LAYER_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_GROUP_LAYER_UNDO, GimpGroupLayerUndo))
#define GIMP_GROUP_LAYER_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_GROUP_LAYER_UNDO, GimpGroupLayerUndoClass))
#define GIMP_IS_GROUP_LAYER_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_GROUP_LAYER_UNDO))
#define GIMP_IS_GROUP_LAYER_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_GROUP_LAYER_UNDO))
#define GIMP_GROUP_LAYER_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_GROUP_LAYER_UNDO, GimpGroupLayerUndoClass))
typedef struct _GimpGroupLayerUndoClass GimpGroupLayerUndoClass;
struct _GimpGroupLayerUndo
{
GimpItemUndo parent_instance;
};
struct _GimpGroupLayerUndoClass
{
GimpItemUndoClass parent_class;
};
GType gimp_group_layer_undo_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_GROUP_LAYER_UNDO_H__ */

View File

@ -32,6 +32,8 @@
#include "gimpdrawableundo.h"
#include "gimpfloatingselundo.h"
#include "gimpgrid.h"
#include "gimpgrouplayer.h"
#include "gimpgrouplayerundo.h"
#include "gimpguide.h"
#include "gimpguideundo.h"
#include "gimpimage.h"
@ -39,7 +41,6 @@
#include "gimpimage-undo-push.h"
#include "gimpimageundo.h"
#include "gimpitempropundo.h"
#include "gimplayer.h"
#include "gimplayermask.h"
#include "gimplayermaskpropundo.h"
#include "gimplayermaskundo.h"
@ -514,6 +515,43 @@ gimp_image_undo_push_layer_lock_alpha (GimpImage *image,
}
/***********************/
/* Group Layer Undos */
/***********************/
GimpUndo *
gimp_image_undo_push_group_layer_suspend (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_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE,
"item", group,
NULL);
}
GimpUndo *
gimp_image_undo_push_group_layer_resume (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_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE,
"item", group,
NULL);
}
/**********************/
/* Text Layer Undos */
/**********************/

View File

@ -128,6 +128,16 @@ GimpUndo * gimp_image_undo_push_layer_lock_alpha (GimpImage *image,
GimpLayer *layer);
/* group layer undos */
GimpUndo * gimp_image_undo_push_group_layer_suspend (GimpImage *image,
const gchar *undo_desc,
GimpGroupLayer *group);
GimpUndo * gimp_image_undo_push_group_layer_resume (GimpImage *image,
const gchar *undo_desc,
GimpGroupLayer *group);
/* text layer undos */
GimpUndo * gimp_image_undo_push_text_layer (GimpImage *image,