Commit a18a1d12 authored by Michael Natterer's avatar Michael Natterer 😴 Committed by Michael Natterer

Prepare the undo system for proper text layer undo:

2004-03-15  Michael Natterer  <mitch@gimp.org>

	Prepare the undo system for proper text layer undo:

	* app/core/core-enums.[ch] (enum GimpUndoType): replaced
	GIMP_UNDO_IMAGE and GIMP_UNDO_IMAGE_MOD by GIMP_UNDO_DRAWABLE.

	* app/core/gimpimage-undo-push.[ch]: ditto: replaced
	gimp_image_undo_push_image() and gimp_image_undo_push_image_mod()
	by gimp_image_undo_push_drawable() which *always* expects to get a
	TileManager passed. Also added g_return_if_fail()s to check if the
	passed in tile manager follows the semantics of the "sparse"
	boolean.

	(undo_pop_drawable): removed all code and call the new
	gimp_drawable_swap_pixels() instead (see below).

	* app/core/gimpdrawable.[ch] (gimp_drawable_push_undo): if tiles
	are NULL, create a copy of the area here and always pass tiles to
	gimp_image_undo_push_drawable(). Added lots of g_return_if_fail()
	here too.

	Added new vitrual function GimpDrawable::swap_pixels() which
	does what undo_pop_drawable() did.

	* app/core/gimpchannel.c: implement swap_pixels() and invalidate
	the channel's bounds and boundary.
parent 8b2d1f8e
2004-03-15 Michael Natterer <mitch@gimp.org>
Prepare the undo system for proper text layer undo:
* app/core/core-enums.[ch] (enum GimpUndoType): replaced
GIMP_UNDO_IMAGE and GIMP_UNDO_IMAGE_MOD by GIMP_UNDO_DRAWABLE.
* app/core/gimpimage-undo-push.[ch]: ditto: replaced
gimp_image_undo_push_image() and gimp_image_undo_push_image_mod()
by gimp_image_undo_push_drawable() which *always* expects to get a
TileManager passed. Also added g_return_if_fail()s to check if the
passed in tile manager follows the semantics of the "sparse"
boolean.
(undo_pop_drawable): removed all code and call the new
gimp_drawable_swap_pixels() instead (see below).
* app/core/gimpdrawable.[ch] (gimp_drawable_push_undo): if tiles
are NULL, create a copy of the area here and always pass tiles to
gimp_image_undo_push_drawable(). Added lots of g_return_if_fail()
here too.
Added new vitrual function GimpDrawable::swap_pixels() which
does what undo_pop_drawable() did.
* app/core/gimpchannel.c: implement swap_pixels() and invalidate
the channel's bounds and boundary.
2004-03-15 Sven Neumann <sven@gimp.org>
* app/gui/preferences-dialog.c: don't show a web-browser setting
......@@ -612,14 +612,13 @@ static const GEnumValue gimp_undo_type_enum_values[] =
{ GIMP_UNDO_GROUP_PARASITE_REMOVE, N_("Remove Parasite"), "group-parasite-remove" },
{ GIMP_UNDO_GROUP_VECTORS_IMPORT, N_("Import Paths"), "group-vectors-import" },
{ GIMP_UNDO_GROUP_MISC, N_("Plug-In"), "group-misc" },
{ GIMP_UNDO_IMAGE, N_("Image"), "image" },
{ GIMP_UNDO_IMAGE_MOD, N_("Image Mod"), "image-mod" },
{ GIMP_UNDO_IMAGE_TYPE, N_("Image Type"), "image-type" },
{ GIMP_UNDO_IMAGE_SIZE, N_("Image Size"), "image-size" },
{ GIMP_UNDO_IMAGE_RESOLUTION, N_("Resolution Change"), "image-resolution" },
{ GIMP_UNDO_IMAGE_GRID, N_("Grid"), "image-grid" },
{ GIMP_UNDO_IMAGE_GUIDE, N_("Guide"), "image-guide" },
{ GIMP_UNDO_IMAGE_COLORMAP, N_("Change Indexed Palette"), "image-colormap" },
{ GIMP_UNDO_DRAWABLE, N_("Drawable Mod"), "drawable" },
{ GIMP_UNDO_MASK, N_("Selection Mask"), "mask" },
{ GIMP_UNDO_ITEM_RENAME, N_("Rename Item"), "item-rename" },
{ GIMP_UNDO_ITEM_DISPLACE, N_("Move Item"), "item-displace" },
......
......@@ -447,14 +447,13 @@ typedef enum /*< pdb-skip >*/
/* Undo types which actually do something */
GIMP_UNDO_IMAGE, /*< desc="Image" >*/
GIMP_UNDO_IMAGE_MOD, /*< desc="Image Mod" >*/
GIMP_UNDO_IMAGE_TYPE, /*< desc="Image Type" >*/
GIMP_UNDO_IMAGE_SIZE, /*< desc="Image Size" >*/
GIMP_UNDO_IMAGE_RESOLUTION, /*< desc="Resolution Change" >*/
GIMP_UNDO_IMAGE_GRID, /*< desc="Grid" >*/
GIMP_UNDO_IMAGE_GUIDE, /*< desc="Guide" >*/
GIMP_UNDO_IMAGE_COLORMAP, /*< desc="Change Indexed Palette" >*/
GIMP_UNDO_DRAWABLE, /*< desc="Drawable Mod" >*/
GIMP_UNDO_MASK, /*< desc="Selection Mask" >*/
GIMP_UNDO_ITEM_RENAME, /*< desc="Rename Item" >*/
GIMP_UNDO_ITEM_DISPLACE, /*< desc="Move Item" >*/
......
......@@ -134,6 +134,13 @@ static void gimp_channel_set_tiles (GimpDrawable *drawable,
const gchar *undo_desc,
TileManager *tiles,
GimpImageType type);
static void gimp_channel_swap_pixels (GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height);
static gboolean gimp_channel_real_boundary (GimpChannel *channel,
const BoundSeg **segs_in,
......@@ -255,6 +262,7 @@ gimp_channel_class_init (GimpChannelClass *klass)
drawable_class->apply_region = gimp_channel_apply_region;
drawable_class->replace_region = gimp_channel_replace_region;
drawable_class->set_tiles = gimp_channel_set_tiles;
drawable_class->swap_pixels = gimp_channel_swap_pixels;
klass->boundary = gimp_channel_real_boundary;
klass->bounds = gimp_channel_real_bounds;
......@@ -773,6 +781,23 @@ gimp_channel_set_tiles (GimpDrawable *drawable,
tiles, type);
}
static void
gimp_channel_swap_pixels (GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height)
{
gimp_drawable_invalidate_boundary (drawable);
GIMP_DRAWABLE_CLASS (parent_class)->swap_pixels (drawable, tiles, sparse,
x, y, width, height);
GIMP_CHANNEL (drawable)->bounds_known = FALSE;
}
static gboolean
gimp_channel_real_boundary (GimpChannel *channel,
const BoundSeg **segs_in,
......
......@@ -114,6 +114,14 @@ static void gimp_drawable_real_set_tiles (GimpDrawable *drawable,
TileManager *tiles,
GimpImageType type);
static void gimp_drawable_real_swap_pixels (GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height);
/* private variables */
......@@ -208,6 +216,7 @@ gimp_drawable_class_init (GimpDrawableClass *klass)
klass->apply_region = gimp_drawable_real_apply_region;
klass->replace_region = gimp_drawable_real_replace_region;
klass->set_tiles = gimp_drawable_real_set_tiles;
klass->swap_pixels = gimp_drawable_real_swap_pixels;
}
static void
......@@ -602,6 +611,70 @@ gimp_drawable_real_set_tiles (GimpDrawable *drawable,
drawable->has_alpha = GIMP_IMAGE_TYPE_HAS_ALPHA (type);
}
static void
gimp_drawable_real_swap_pixels (GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height)
{
if (sparse)
{
gint i, j;
for (i = y; i < (y + height); i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
{
for (j = x; j < (x + width); j += (TILE_WIDTH - (j % TILE_WIDTH)))
{
Tile *src_tile;
Tile *dest_tile;
src_tile = tile_manager_get_tile (tiles, j, i, FALSE, FALSE);
if (tile_is_valid (src_tile))
{
/* swap tiles, not pixels! */
src_tile = tile_manager_get_tile (tiles,
j, i, TRUE, FALSE /*TRUE*/);
dest_tile = tile_manager_get_tile (gimp_drawable_data (drawable), j, i, TRUE, FALSE /* TRUE */);
tile_manager_map_tile (tiles,
j, i, dest_tile);
tile_manager_map_tile (gimp_drawable_data (drawable),
j, i, src_tile);
#if 0
swap_pixels (tile_data_pointer (src_tile, 0, 0),
tile_data_pointer (dest_tile, 0, 0),
tile_size (src_tile));
#endif
tile_release (dest_tile, FALSE /* TRUE */);
tile_release (src_tile, FALSE /* TRUE */);
}
}
}
}
else
{
PixelRegion PR1, PR2;
pixel_region_init (&PR1, tiles,
0, 0, width, height, TRUE);
pixel_region_init (&PR2, gimp_drawable_data (drawable),
x, y, width, height, TRUE);
swap_region (&PR1, &PR2);
}
gimp_drawable_update (drawable, x, y, width, height);
}
/* public functions */
void
gimp_drawable_configure (GimpDrawable *drawable,
GimpImage *gimage,
......@@ -737,6 +810,22 @@ gimp_drawable_set_tiles (GimpDrawable *drawable,
tiles, type);
}
void
gimp_drawable_swap_pixels (GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height)
{
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (tiles != NULL);
GIMP_DRAWABLE_GET_CLASS (drawable)->swap_pixels (drawable, tiles, sparse,
x, y, width, height);
}
void
gimp_drawable_push_undo (GimpDrawable *drawable,
const gchar *undo_desc,
......@@ -747,19 +836,57 @@ gimp_drawable_push_undo (GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse)
{
GimpItem *item;
gint x, y, width, height;
gboolean new_tiles = FALSE;
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (sparse == FALSE || tiles != NULL);
item = GIMP_ITEM (drawable);
g_return_if_fail (sparse == FALSE ||
tile_manager_width (tiles) == gimp_item_width (item));
g_return_if_fail (sparse == FALSE ||
tile_manager_height (tiles) == gimp_item_height (item));
#if 0
g_printerr ("gimp_drawable_push_undo (%s, %d, %d, %d, %d)\n",
sparse ? "TRUE" : "FALSE", x1, y1, x2 - x1, y2 - y1);
#endif
if (! gimp_rectangle_intersect (x1, y1,
x2 - x1, y2 - y1,
0, 0,
gimp_item_width (item),
gimp_item_height (item),
&x, &y, &width, &height))
{
g_warning ("gimp_drawable_push_undo: tried to push empty region");
return;
}
if (! tiles)
gimp_image_undo_push_image (gimp_item_get_image (GIMP_ITEM (drawable)),
undo_desc,
drawable,
x1, y1, x2, y2);
else
gimp_image_undo_push_image_mod (gimp_item_get_image (GIMP_ITEM (drawable)),
undo_desc,
drawable,
x1, y1, x2, y2,
tiles, sparse);
{
PixelRegion srcPR, destPR;
tiles = tile_manager_new (width, height, gimp_drawable_bytes (drawable));
pixel_region_init (&srcPR, gimp_drawable_data (drawable),
x, y, width, height, FALSE);
pixel_region_init (&destPR, tiles,
0, 0, width, height, TRUE);
copy_region (&srcPR, &destPR);
new_tiles = TRUE;
}
gimp_image_undo_push_drawable (gimp_item_get_image (GIMP_ITEM (drawable)),
undo_desc, drawable,
tiles, sparse,
x, y, width, height);
if (new_tiles)
tile_manager_unref (tiles);
}
TileManager *
......
......@@ -86,6 +86,13 @@ struct _GimpDrawableClass
const gchar *undo_desc,
TileManager *tiles,
GimpImageType type);
void (* swap_pixels) (GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height);
};
......@@ -135,6 +142,13 @@ void gimp_drawable_set_tiles (GimpDrawable *drawable,
TileManager *tiles,
GimpImageType type);
void gimp_drawable_swap_pixels (GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height);
void gimp_drawable_push_undo (GimpDrawable *drawable,
const gchar *undo_desc,
......
......@@ -33,7 +33,6 @@
#include "base/pixel-region.h"
#include "base/tile-manager.h"
#include "base/tile.h"
#include "paint-funcs/paint-funcs.h"
......@@ -64,245 +63,6 @@
#include "gimp-intl.h"
/****************/
/* Image Undo */
/****************/
typedef struct _ImageUndo ImageUndo;
struct _ImageUndo
{
TileManager *tiles;
gint x1, y1, x2, y2;
gboolean sparse;
};
static gboolean undo_pop_image (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
static void undo_free_image (GimpUndo *undo,
GimpUndoMode undo_mode);
gboolean
gimp_image_undo_push_image (GimpImage *gimage,
const gchar *undo_desc,
GimpDrawable *drawable,
gint x1,
gint y1,
gint x2,
gint y2)
{
GimpUndo *new;
GimpItem *item;
gint64 size;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
item = GIMP_ITEM (drawable);
x1 = CLAMP (x1, 0, gimp_item_width (item));
y1 = CLAMP (y1, 0, gimp_item_height (item));
x2 = CLAMP (x2, 0, gimp_item_width (item));
y2 = CLAMP (y2, 0, gimp_item_height (item));
size = sizeof (ImageUndo) + ((x2 - x1) * (y2 - y1) *
gimp_drawable_bytes (drawable));
if ((new = gimp_image_undo_push_item (gimage, item,
size, sizeof (ImageUndo),
GIMP_UNDO_IMAGE, undo_desc,
TRUE,
undo_pop_image,
undo_free_image)))
{
ImageUndo *image_undo;
TileManager *tiles;
PixelRegion srcPR, destPR;
image_undo = new->data;
/* If we cannot create a new temp buf -- either because our
* parameters are degenerate or something else failed, simply
* return an unsuccessful push.
*/
tiles = tile_manager_new ((x2 - x1), (y2 - y1),
gimp_drawable_bytes (drawable));
pixel_region_init (&srcPR, gimp_drawable_data (drawable),
x1, y1, (x2 - x1), (y2 - y1), FALSE);
pixel_region_init (&destPR, tiles,
0, 0, (x2 - x1), (y2 - y1), TRUE);
copy_region (&srcPR, &destPR);
/* set the image undo structure */
image_undo->tiles = tiles;
image_undo->x1 = x1;
image_undo->y1 = y1;
image_undo->x2 = x2;
image_undo->y2 = y2;
image_undo->sparse = FALSE;
return TRUE;
}
return FALSE;
}
gboolean
gimp_image_undo_push_image_mod (GimpImage *gimage,
const gchar *undo_desc,
GimpDrawable *drawable,
gint x1,
gint y1,
gint x2,
gint y2,
TileManager *tiles,
gboolean sparse)
{
GimpUndo *new;
GimpItem *item;
gint64 size;
gint dwidth, dheight;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
g_return_val_if_fail (tiles != NULL, FALSE);
item = GIMP_ITEM (drawable);
dwidth = gimp_item_width (item);
dheight = gimp_item_height (item);
x1 = CLAMP (x1, 0, dwidth);
y1 = CLAMP (y1, 0, dheight);
x2 = CLAMP (x2, 0, dwidth);
y2 = CLAMP (y2, 0, dheight);
size = sizeof (ImageUndo) + tile_manager_get_memsize (tiles);
if ((new = gimp_image_undo_push_item (gimage, item,
size, sizeof (ImageUndo),
GIMP_UNDO_IMAGE_MOD, undo_desc,
TRUE,
undo_pop_image,
undo_free_image)))
{
ImageUndo *image_undo;
image_undo = new->data;
image_undo->tiles = tile_manager_ref (tiles);
image_undo->x1 = x1;
image_undo->y1 = y1;
image_undo->x2 = x2;
image_undo->y2 = y2;
image_undo->sparse = sparse;
return TRUE;
}
return FALSE;
}
static gboolean
undo_pop_image (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
ImageUndo *image_undo;
GimpDrawable *drawable;
TileManager *tiles;
PixelRegion PR1, PR2;
gint x, y;
gint w, h;
image_undo = (ImageUndo *) undo->data;
drawable = GIMP_DRAWABLE (GIMP_ITEM_UNDO (undo)->item);
tiles = image_undo->tiles;
/* some useful values */
x = image_undo->x1;
y = image_undo->y1;
if (GIMP_IS_CHANNEL (drawable))
gimp_drawable_invalidate_boundary (drawable);
if (image_undo->sparse == FALSE)
{
w = tile_manager_width (tiles);
h = tile_manager_height (tiles);
pixel_region_init (&PR1, tiles,
0, 0, w, h, TRUE);
pixel_region_init (&PR2, gimp_drawable_data (drawable),
x, y, w, h, TRUE);
/* swap the regions */
swap_region (&PR1, &PR2);
}
else
{
Tile *src_tile;
Tile *dest_tile;
gint i, j;
w = image_undo->x2 - image_undo->x1;
h = image_undo->y2 - image_undo->y1;
for (i = y; i < image_undo->y2; i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
{
for (j = x; j < image_undo->x2; j += (TILE_WIDTH - (j % TILE_WIDTH)))
{
src_tile = tile_manager_get_tile (tiles, j, i, FALSE, FALSE);
if (tile_is_valid (src_tile))
{
/* swap tiles, not pixels! */
src_tile = tile_manager_get_tile (tiles,
j, i, TRUE, FALSE /*TRUE*/);
dest_tile = tile_manager_get_tile (gimp_drawable_data (drawable), j, i, TRUE, FALSE /* TRUE */);
tile_manager_map_tile (tiles,
j, i, dest_tile);
tile_manager_map_tile (gimp_drawable_data (drawable),
j, i, src_tile);
#if 0
swap_pixels (tile_data_pointer (src_tile, 0, 0),
tile_data_pointer (dest_tile, 0, 0),
tile_size (src_tile));
#endif
tile_release (dest_tile, FALSE /* TRUE */);
tile_release (src_tile, FALSE /* TRUE */);
}
}
}
}
if (GIMP_IS_CHANNEL (drawable))
GIMP_CHANNEL (drawable)->bounds_known = FALSE;
gimp_drawable_update (drawable, x, y, w, h);
return TRUE;
}
static void
undo_free_image (GimpUndo *undo,
GimpUndoMode undo_mode)
{
ImageUndo *image_undo;
image_undo = (ImageUndo *) undo->data;
tile_manager_unref (image_undo->tiles);
g_free (image_undo);
}
/*********************/
/* Image Type Undo */
/*********************/
......@@ -819,6 +579,110 @@ undo_free_image_colormap (GimpUndo *undo,
}
/*******************/
/* Drawable Undo */
/*******************/
typedef struct _DrawableUndo DrawableUndo;
struct _DrawableUndo
{
TileManager *tiles;
gboolean sparse;
gint x, y, width, height;
};
static gboolean undo_pop_drawable (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
static void undo_free_drawable (GimpUndo *undo,
GimpUndoMode undo_mode);
gboolean
gimp_image_undo_push_drawable (GimpImage *gimage,
const gchar *undo_desc,
GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height)
{
GimpItem *item;
GimpUndo *new;
gint64 size;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
g_return_val_if_fail (tiles != NULL, FALSE);
g_return_val_if_fail (sparse == TRUE ||
tile_manager_width (tiles) == width, FALSE);
g_return_val_if_fail (sparse == TRUE ||
tile_manager_height (tiles) == height, FALSE);
item = GIMP_ITEM (drawable);
g_return_val_if_fail (sparse == FALSE ||
tile_manager_width (tiles) == gimp_item_width (item),
FALSE);
g_return_val_if_fail (sparse == FALSE ||
tile_manager_height (tiles) == gimp_item_height (item),
FALSE);
size = sizeof (DrawableUndo) + tile_manager_get_memsize (tiles);
if ((new = gimp_image_undo_push_item (gimage, item,
size, sizeof (DrawableUndo),
GIMP_UNDO_DRAWABLE, undo_desc,
TRUE,
undo_pop_drawable,
undo_free_drawable)))
{
DrawableUndo *drawable_undo = new->data;
drawable_undo->tiles = tile_manager_ref (tiles);
drawable_undo->sparse = sparse;
drawable_undo->x = x;
drawable_undo->y = y;
drawable_undo->width = width;
drawable_undo->height = height;
return TRUE;
}
return FALSE;
}
static gboolean
undo_pop_drawable (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
DrawableUndo *drawable_undo = undo->data;
gimp_drawable_swap_pixels (GIMP_DRAWABLE (GIMP_ITEM_UNDO (undo)->item),
drawable_undo->tiles,
drawable_undo->sparse,
drawable_undo->x,
drawable_undo->y,
drawable_undo->width,
drawable_undo->height);
return TRUE;
}
static void
undo_free_drawable (GimpUndo *undo,
GimpUndoMode undo_mode)
{
DrawableUndo *drawable_undo = undo->data;
tile_manager_unref (drawable_undo->tiles);
g_free (drawable_undo);
}
/***************/
/* Mask Undo */
/***************/
......
......@@ -22,22 +22,6 @@
/* image undos */
gboolean gimp_image_undo_push_image (GimpImage *gimage,
const gchar *undo_desc,
GimpDrawable *drawable,
gint x1,
gint y1,
gint x2,
gint y2);
gboolean gimp_image_undo_push_image_mod (GimpImage *gimage,
const gchar *undo_desc,
GimpDrawable *drawable,
gint x1,
gint y1,
gint x2,
gint y2,
TileManager *tiles,
gboolean sparse);
gboolean gimp_image_undo_push_image_type (GimpImage *gimage,
const gchar *undo_desc);
gboolean gimp_image_undo_push_image_size (GimpImage *gimage,
......@@ -54,6 +38,19 @@ gboolean gimp_image_undo_push_image_colormap (GimpImage *gimage,
const gchar *undo_desc);
/* drawable undo */
gboolean gimp_image_undo_push_drawable (GimpImage *gimage,
const gchar *undo_desc,
GimpDrawable *drawable,
TileManager *tiles,
gboolean sparse,
gint x,
gint y,
gint width,
gint height);
/* mask undo */
gboolean gimp_image_undo_push_mask (GimpImage *gimage,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment