diff --git a/ChangeLog b/ChangeLog index 9c840bb713..61cbff3216 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-01-28 Michael Natterer + + * app/core/Makefile.am + * app/core/core-types.h + * app/core/gimpchannelundo.[ch]: new GimpItemUndo subclass which + handles all the channel undo stuff itself. + + * app/core/gimpimage-undo-push.c: removed all channel undo code + here and simply create a GimpChannelUndo instance. + 2007-01-26 Tor Lillqvist Fix #398311 in GIMP until corresponding abstraction has been added diff --git a/app/core/Makefile.am b/app/core/Makefile.am index c2f9aa8990..600449ab64 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -76,6 +76,8 @@ libappcore_a_sources = \ gimpchannel-combine.h \ gimpchannel-select.c \ gimpchannel-select.h \ + gimpchannelundo.c \ + gimpchannelundo.h \ gimpcontainer.c \ gimpcontainer.h \ gimpcontainer-filter.c \ diff --git a/app/core/core-types.h b/app/core/core-types.h index 6368cd32d6..fc0c39776f 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -111,6 +111,7 @@ typedef struct _GimpLayerMask GimpLayerMask; typedef struct _GimpUndo GimpUndo; typedef struct _GimpItemUndo GimpItemUndo; +typedef struct _GimpChannelUndo GimpChannelUndo; typedef struct _GimpDrawableUndo GimpDrawableUndo; typedef struct _GimpUndoStack GimpUndoStack; typedef struct _GimpUndoAccumulator GimpUndoAccumulator; diff --git a/app/core/gimpchannelundo.c b/app/core/gimpchannelundo.c new file mode 100644 index 0000000000..f43f86cf38 --- /dev/null +++ b/app/core/gimpchannelundo.c @@ -0,0 +1,218 @@ +/* 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "libgimpbase/gimpbase.h" + +#include "core-types.h" + +#include "base/pixel-region.h" +#include "base/tile-manager.h" + +#include "paint-funcs/paint-funcs.h" + +#include "gimpimage.h" +#include "gimpchannel.h" +#include "gimpchannelundo.h" + + +static GObject * gimp_channel_undo_constructor (GType type, + guint n_params, + GObjectConstructParam *params); + +static void gimp_channel_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void gimp_channel_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode); + + +G_DEFINE_TYPE (GimpChannelUndo, gimp_channel_undo, GIMP_TYPE_ITEM_UNDO) + +#define parent_class gimp_channel_undo_parent_class + + +static void +gimp_channel_undo_class_init (GimpChannelUndoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass); + + object_class->constructor = gimp_channel_undo_constructor; + + undo_class->pop = gimp_channel_undo_pop; + undo_class->free = gimp_channel_undo_free; +} + +static void +gimp_channel_undo_init (GimpChannelUndo *undo) +{ +} + +static GObject * +gimp_channel_undo_constructor (GType type, + guint n_params, + GObjectConstructParam *params) +{ + GObject *object; + GimpChannelUndo *channel_undo; + GimpChannel *channel; + gint x1, y1, x2, y2; + + object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); + + channel_undo = GIMP_CHANNEL_UNDO (object); + + g_assert (GIMP_IS_CHANNEL (GIMP_ITEM_UNDO (object)->item)); + + channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (object)->item); + + if (gimp_channel_bounds (channel, &x1, &y1, &x2, &y2)) + { + GimpDrawable *drawable = GIMP_DRAWABLE (channel); + PixelRegion srcPR, destPR; + + channel_undo->tiles = tile_manager_new (x2 - x1, y2 - y1, + gimp_drawable_bytes (drawable)); + channel_undo->x = x1; + channel_undo->y = y1; + + pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable), + x1, y1, x2 - x1, y2 - y1, FALSE); + pixel_region_init (&destPR, channel_undo->tiles, + 0, 0, x2 - x1, y2 - y1, TRUE); + + copy_region (&srcPR, &destPR); + + GIMP_UNDO (object)->size += + tile_manager_get_memsize (channel_undo->tiles, FALSE); + } + + return object; +} + +static void +gimp_channel_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + GimpChannelUndo *channel_undo = GIMP_CHANNEL_UNDO (undo); + GimpChannel *channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (undo)->item); + TileManager *new_tiles; + PixelRegion srcPR, destPR; + gint x1, y1, x2, y2; + gint width = 0; + gint height = 0; + + GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); + + if (channel_undo->tiles) + undo->size -= tile_manager_get_memsize (channel_undo->tiles, FALSE); + + if (gimp_channel_bounds (channel, &x1, &y1, &x2, &y2)) + { + guchar empty = 0; + + new_tiles = tile_manager_new (x2 - x1, y2 - y1, 1); + + pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles, + x1, y1, x2 - x1, y2 - y1, FALSE); + pixel_region_init (&destPR, new_tiles, + 0, 0, x2 - x1, y2 - y1, TRUE); + + copy_region (&srcPR, &destPR); + + pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles, + x1, y1, x2 - x1, y2 - y1, TRUE); + + color_region (&srcPR, &empty); + } + else + { + new_tiles = NULL; + } + + if (channel_undo->tiles) + { + width = tile_manager_width (channel_undo->tiles); + height = tile_manager_height (channel_undo->tiles); + + pixel_region_init (&srcPR, channel_undo->tiles, + 0, 0, width, height, FALSE); + pixel_region_init (&destPR, GIMP_DRAWABLE (channel)->tiles, + channel_undo->x, channel_undo->y, width, height, TRUE); + + copy_region (&srcPR, &destPR); + + tile_manager_unref (channel_undo->tiles); + } + + /* invalidate the current bounds and boundary of the mask */ + gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (channel)); + + if (channel_undo->tiles) + { + channel->empty = FALSE; + channel->x1 = channel_undo->x; + channel->y1 = channel_undo->y; + channel->x2 = channel_undo->x + width; + channel->y2 = channel_undo->y + height; + } + else + { + channel->empty = TRUE; + channel->x1 = 0; + channel->y1 = 0; + channel->x2 = GIMP_ITEM (channel)->width; + channel->y2 = GIMP_ITEM (channel)->height; + } + + /* we know the bounds */ + channel->bounds_known = TRUE; + + /* set the new mask undo parameters */ + channel_undo->tiles = new_tiles; + channel_undo->x = x1; + channel_undo->y = y1; + + gimp_drawable_update (GIMP_DRAWABLE (channel), + 0, 0, + GIMP_ITEM (channel)->width, + GIMP_ITEM (channel)->height); + + if (channel_undo->tiles) + undo->size += tile_manager_get_memsize (channel_undo->tiles, FALSE); +} + +static void +gimp_channel_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + GimpChannelUndo *channel_undo = GIMP_CHANNEL_UNDO (undo); + + GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode); + + if (channel_undo->tiles) + { + tile_manager_unref (channel_undo->tiles); + channel_undo->tiles = NULL; + } +} diff --git a/app/core/gimpchannelundo.h b/app/core/gimpchannelundo.h new file mode 100644 index 0000000000..904b295660 --- /dev/null +++ b/app/core/gimpchannelundo.h @@ -0,0 +1,54 @@ +/* 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GIMP_CHANNEL_UNDO_H__ +#define __GIMP_CHANNEL_UNDO_H__ + + +#include "gimpitemundo.h" + + +#define GIMP_TYPE_CHANNEL_UNDO (gimp_channel_undo_get_type ()) +#define GIMP_CHANNEL_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CHANNEL_UNDO, GimpChannelUndo)) +#define GIMP_CHANNEL_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CHANNEL_UNDO, GimpChannelUndoClass)) +#define GIMP_IS_CHANNEL_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CHANNEL_UNDO)) +#define GIMP_IS_CHANNEL_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CHANNEL_UNDO)) +#define GIMP_CHANNEL_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CHANNEL_UNDO, GimpChannelUndoClass)) + + +typedef struct _GimpChannelUndoClass GimpChannelUndoClass; + +struct _GimpChannelUndo +{ + GimpItemUndo parent_instance; + + TileManager *tiles; + gint x; + gint y; +}; + +struct _GimpChannelUndoClass +{ + GimpItemUndoClass parent_class; +}; + + +GType gimp_channel_undo_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_CHANNEL_UNDO_H__ */ diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index 52ce1a4687..f8cc9b4612 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -34,6 +34,7 @@ #include "gimp.h" #include "gimp-parasites.h" +#include "gimpchannelundo.h" #include "gimpdrawableundo.h" #include "gimpgrid.h" #include "gimpguide.h" @@ -849,184 +850,34 @@ undo_free_drawable_mod (GimpUndo *undo, /* Mask Undo */ /***************/ -typedef struct _MaskUndo MaskUndo; - -struct _MaskUndo -{ - TileManager *tiles; /* the actual mask */ - gint x, y; /* offsets */ -}; - -static gboolean undo_pop_mask (GimpUndo *undo, - GimpUndoMode undo_mode, - GimpUndoAccumulator *accum); -static void undo_free_mask (GimpUndo *undo, - GimpUndoMode undo_mode); - gboolean gimp_image_undo_push_mask (GimpImage *image, const gchar *undo_desc, GimpChannel *mask) { - TileManager *undo_tiles = NULL; - gint x1, y1, x2, y2; - GimpUndo *new; - gint64 size; + GimpUndo *new; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (GIMP_IS_CHANNEL (mask), FALSE); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (mask)), FALSE); - size = sizeof (MaskUndo); - - if (gimp_channel_bounds (mask, &x1, &y1, &x2, &y2)) - { - GimpDrawable *drawable = GIMP_DRAWABLE (mask); - PixelRegion srcPR, destPR; - - undo_tiles = tile_manager_new (x2 - x1, y2 - y1, - gimp_drawable_bytes (drawable)); - - pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable), - x1, y1, x2 - x1, y2 - y1, FALSE); - pixel_region_init (&destPR, undo_tiles, - 0, 0, x2 - x1, y2 - y1, TRUE); - - copy_region (&srcPR, &destPR); - - size += tile_manager_get_memsize (undo_tiles, FALSE); - } - - if ((new = gimp_image_undo_push (image, GIMP_TYPE_ITEM_UNDO, - size, sizeof (MaskUndo), + if ((new = gimp_image_undo_push (image, GIMP_TYPE_CHANNEL_UNDO, + 0, 0, GIMP_UNDO_MASK, undo_desc, GIMP_IS_SELECTION (mask) ? GIMP_DIRTY_SELECTION : GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE, - undo_pop_mask, - undo_free_mask, + NULL, + NULL, "item", mask, NULL))) { - MaskUndo *mask_undo = new->data; - - mask_undo->tiles = undo_tiles; - mask_undo->x = x1; - mask_undo->y = y1; - return TRUE; } - if (undo_tiles) - tile_manager_unref (undo_tiles); - return FALSE; } -static gboolean -undo_pop_mask (GimpUndo *undo, - GimpUndoMode undo_mode, - GimpUndoAccumulator *accum) -{ - MaskUndo *mu = undo->data; - GimpChannel *channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (undo)->item); - TileManager *new_tiles; - PixelRegion srcPR, destPR; - gint x1, y1, x2, y2; - gint width = 0; - gint height = 0; - guchar empty = 0; - - if (mu->tiles) - undo->size -= tile_manager_get_memsize (mu->tiles, FALSE); - - if (gimp_channel_bounds (channel, &x1, &y1, &x2, &y2)) - { - new_tiles = tile_manager_new ((x2 - x1), (y2 - y1), 1); - - pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles, - x1, y1, (x2 - x1), (y2 - y1), FALSE); - pixel_region_init (&destPR, new_tiles, - 0, 0, (x2 - x1), (y2 - y1), TRUE); - - copy_region (&srcPR, &destPR); - - pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles, - x1, y1, (x2 - x1), (y2 - y1), TRUE); - - color_region (&srcPR, &empty); - } - else - { - new_tiles = NULL; - } - - if (mu->tiles) - { - width = tile_manager_width (mu->tiles); - height = tile_manager_height (mu->tiles); - - pixel_region_init (&srcPR, mu->tiles, - 0, 0, width, height, FALSE); - pixel_region_init (&destPR, GIMP_DRAWABLE (channel)->tiles, - mu->x, mu->y, width, height, TRUE); - - copy_region (&srcPR, &destPR); - - tile_manager_unref (mu->tiles); - } - - /* invalidate the current bounds and boundary of the mask */ - gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (channel)); - - if (mu->tiles) - { - channel->empty = FALSE; - channel->x1 = mu->x; - channel->y1 = mu->y; - channel->x2 = mu->x + width; - channel->y2 = mu->y + height; - } - else - { - channel->empty = TRUE; - channel->x1 = 0; - channel->y1 = 0; - channel->x2 = GIMP_ITEM (channel)->width; - channel->y2 = GIMP_ITEM (channel)->height; - } - - /* we know the bounds */ - channel->bounds_known = TRUE; - - /* set the new mask undo parameters */ - mu->tiles = new_tiles; - mu->x = x1; - mu->y = y1; - - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - GIMP_ITEM (channel)->width, - GIMP_ITEM (channel)->height); - - if (mu->tiles) - undo->size += tile_manager_get_memsize (mu->tiles, FALSE); - - return TRUE; -} - -static void -undo_free_mask (GimpUndo *undo, - GimpUndoMode undo_mode) -{ - MaskUndo *mu = undo->data; - - if (mu->tiles) - tile_manager_unref (mu->tiles); - - g_free (mu); -} - /**********************/ /* Item Rename Undo */