gimpimage-undo-push.c 85.8 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* The GIMP -- an 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
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18

19 20
#include "config.h"

Elliot Lee's avatar
Elliot Lee committed
21
#include <string.h>
22

23
#include <glib-object.h>
Sven Neumann's avatar
Sven Neumann committed
24

25 26
#include "libgimpbase/gimpbase.h"

27
#include "core-types.h"
Sven Neumann's avatar
Sven Neumann committed
28

29 30
#include "config/gimpconfig.h"
#include "config/gimpconfig-utils.h"
31

Michael Natterer's avatar
Michael Natterer committed
32 33 34
#include "base/pixel-region.h"
#include "base/tile-manager.h"

35 36
#include "paint-funcs/paint-funcs.h"

37 38
#include "gimp-parasites.h"
#include "gimp.h"
39
#include "gimpgrid.h"
40
#include "gimpimage-colormap.h"
41
#include "gimpimage-grid.h"
42 43 44
#include "gimpimage-guides.h"
#include "gimpimage-undo.h"
#include "gimpimage.h"
45
#include "gimpitemundo.h"
46 47 48 49 50
#include "gimplayer-floating-sel.h"
#include "gimplayer.h"
#include "gimplayermask.h"
#include "gimplist.h"
#include "gimpparasitelist.h"
51

52 53
#include "text/gimptextlayer.h"

54 55
#include "vectors/gimpvectors.h"

56
#include "gimp-intl.h"
jaycox's avatar
jaycox committed
57

58

59 60
/*********************/
/*  Image Type Undo  */
61
/*********************/
62 63 64 65 66 67 68 69

typedef struct _ImageTypeUndo ImageTypeUndo;

struct _ImageTypeUndo
{
  GimpImageBaseType base_type;
};

70 71 72 73 74
static gboolean undo_pop_image_type  (GimpUndo            *undo,
                                      GimpUndoMode         undo_mode,
                                      GimpUndoAccumulator *accum);
static void     undo_free_image_type (GimpUndo            *undo,
                                      GimpUndoMode         undo_mode);
75 76

gboolean
77 78
gimp_image_undo_push_image_type (GimpImage   *gimage,
                                 const gchar *undo_desc)
79
{
80
  GimpUndo *new;
81

82 83
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);

84 85 86
  if ((new = gimp_image_undo_push (gimage,
                                   sizeof (ImageTypeUndo),
                                   sizeof (ImageTypeUndo),
87
                                   GIMP_UNDO_IMAGE_TYPE, undo_desc,
88 89 90
                                   TRUE,
                                   undo_pop_image_type,
                                   undo_free_image_type)))
91
    {
Michael Natterer's avatar
Michael Natterer committed
92
      ImageTypeUndo *itu = new->data;
93 94 95 96 97 98 99 100 101 102

      itu->base_type = gimage->base_type;

      return TRUE;
    }

  return FALSE;
}

static gboolean
103 104 105
undo_pop_image_type (GimpUndo            *undo,
                     GimpUndoMode         undo_mode,
                     GimpUndoAccumulator *accum)
106
{
Michael Natterer's avatar
Michael Natterer committed
107
  ImageTypeUndo     *itu = undo->data;
108 109 110
  GimpImageBaseType  tmp;

  tmp = itu->base_type;
111 112
  itu->base_type = undo->gimage->base_type;
  undo->gimage->base_type = tmp;
113

114
  gimp_image_colormap_changed (undo->gimage, -1);
115

116
  if (itu->base_type != undo->gimage->base_type)
117
    accum->mode_changed = TRUE;
118 119 120 121 122

  return TRUE;
}

static void
123 124
undo_free_image_type (GimpUndo     *undo,
                      GimpUndoMode  undo_mode)
125
{
126
  g_free (undo->data);
127 128 129
}


Michael Natterer's avatar
Michael Natterer committed
130 131
/*********************/
/*  Image Size Undo  */
132
/*********************/
Michael Natterer's avatar
Michael Natterer committed
133 134 135 136 137

typedef struct _ImageSizeUndo ImageSizeUndo;

struct _ImageSizeUndo
{
138 139
  gint width;
  gint height;
Michael Natterer's avatar
Michael Natterer committed
140 141
};

142 143 144 145 146
static gboolean undo_pop_image_size  (GimpUndo            *undo,
                                      GimpUndoMode         undo_mode,
                                      GimpUndoAccumulator *accum);
static void     undo_free_image_size (GimpUndo            *undo,
                                      GimpUndoMode         undo_mode);
Elliot Lee's avatar
Elliot Lee committed
147

148
gboolean
149 150
gimp_image_undo_push_image_size (GimpImage   *gimage,
                                 const gchar *undo_desc)
Elliot Lee's avatar
Elliot Lee committed
151
{
152
  GimpUndo *new;
Elliot Lee's avatar
Elliot Lee committed
153

154 155
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);

156 157 158
  if ((new = gimp_image_undo_push (gimage,
                                   sizeof (ImageSizeUndo),
                                   sizeof (ImageSizeUndo),
159
                                   GIMP_UNDO_IMAGE_SIZE, undo_desc,
160 161 162
                                   TRUE,
                                   undo_pop_image_size,
                                   undo_free_image_size)))
Michael Natterer's avatar
Michael Natterer committed
163
    {
Michael Natterer's avatar
Michael Natterer committed
164
      ImageSizeUndo *isu = new->data;
Michael Natterer's avatar
Michael Natterer committed
165

166 167
      isu->width  = gimage->width;
      isu->height = gimage->height;
Michael Natterer's avatar
Michael Natterer committed
168 169 170 171 172 173 174 175

      return TRUE;
    }

  return FALSE;
}

static gboolean
176 177 178
undo_pop_image_size (GimpUndo            *undo,
                     GimpUndoMode         undo_mode,
                     GimpUndoAccumulator *accum)
Michael Natterer's avatar
Michael Natterer committed
179
{
Michael Natterer's avatar
Michael Natterer committed
180
  ImageSizeUndo *isu = undo->data;
181 182
  gint           width;
  gint           height;
Michael Natterer's avatar
Michael Natterer committed
183

184 185
  width  = isu->width;
  height = isu->height;
Michael Natterer's avatar
Michael Natterer committed
186

187 188
  isu->width  = undo->gimage->width;
  isu->height = undo->gimage->height;
Michael Natterer's avatar
Michael Natterer committed
189

190 191
  undo->gimage->width  = width;
  undo->gimage->height = height;
Michael Natterer's avatar
Michael Natterer committed
192

193
  gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (gimp_image_get_mask (undo->gimage)));
Michael Natterer's avatar
Michael Natterer committed
194

195 196
  if (undo->gimage->width  != isu->width ||
      undo->gimage->height != isu->height)
197
    accum->size_changed = TRUE;
Michael Natterer's avatar
Michael Natterer committed
198 199 200 201 202

  return TRUE;
}

static void
203 204
undo_free_image_size (GimpUndo      *undo,
                      GimpUndoMode   undo_mode)
Michael Natterer's avatar
Michael Natterer committed
205
{
206
  g_free (undo->data);
Michael Natterer's avatar
Michael Natterer committed
207 208 209 210 211
}


/***************************/
/*  Image Resolution Undo  */
212
/***************************/
Michael Natterer's avatar
Michael Natterer committed
213 214 215 216 217 218 219 220 221 222

typedef struct _ResolutionUndo ResolutionUndo;

struct _ResolutionUndo
{
  gdouble  xres;
  gdouble  yres;
  GimpUnit unit;
};

223 224 225 226 227
static gboolean undo_pop_image_resolution  (GimpUndo            *undo,
                                            GimpUndoMode         undo_mode,
                                            GimpUndoAccumulator *accum);
static void     undo_free_image_resolution (GimpUndo            *undo,
                                            GimpUndoMode         undo_mode);
Michael Natterer's avatar
Michael Natterer committed
228 229

gboolean
230 231
gimp_image_undo_push_image_resolution (GimpImage   *gimage,
                                       const gchar *undo_desc)
Michael Natterer's avatar
Michael Natterer committed
232
{
233
  GimpUndo *new;
Michael Natterer's avatar
Michael Natterer committed
234

235 236
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);

237 238 239
  if ((new = gimp_image_undo_push (gimage,
                                   sizeof (ResolutionUndo),
                                   sizeof (ResolutionUndo),
240
                                   GIMP_UNDO_IMAGE_RESOLUTION, undo_desc,
241 242 243
                                   TRUE,
                                   undo_pop_image_resolution,
                                   undo_free_image_resolution)))
Michael Natterer's avatar
Michael Natterer committed
244
    {
Michael Natterer's avatar
Michael Natterer committed
245
      ResolutionUndo *ru = new->data;
Michael Natterer's avatar
Michael Natterer committed
246 247 248 249 250 251 252 253 254 255 256 257

      ru->xres = gimage->xresolution;
      ru->yres = gimage->yresolution;
      ru->unit = gimage->unit;

      return TRUE;
    }

  return FALSE;
}

static gboolean
258 259 260
undo_pop_image_resolution (GimpUndo            *undo,
                           GimpUndoMode         undo_mode,
                           GimpUndoAccumulator *accum)
Michael Natterer's avatar
Michael Natterer committed
261
{
Michael Natterer's avatar
Michael Natterer committed
262
  ResolutionUndo *ru = undo->data;
Michael Natterer's avatar
Michael Natterer committed
263

264 265
  if (ABS (ru->xres - undo->gimage->xresolution) >= 1e-5 ||
      ABS (ru->yres - undo->gimage->yresolution) >= 1e-5)
Michael Natterer's avatar
Michael Natterer committed
266
    {
267 268
      gdouble xres;
      gdouble yres;
Michael Natterer's avatar
Michael Natterer committed
269

270 271
      xres = undo->gimage->xresolution;
      yres = undo->gimage->yresolution;
Michael Natterer's avatar
Michael Natterer committed
272

273 274
      undo->gimage->xresolution = ru->xres;
      undo->gimage->yresolution = ru->yres;
Michael Natterer's avatar
Michael Natterer committed
275

276 277
      ru->xres = xres;
      ru->yres = yres;
Michael Natterer's avatar
Michael Natterer committed
278

279
      accum->resolution_changed = TRUE;
Michael Natterer's avatar
Michael Natterer committed
280 281
    }

282
  if (ru->unit != undo->gimage->unit)
Michael Natterer's avatar
Michael Natterer committed
283
    {
284
      GimpUnit unit;
Michael Natterer's avatar
Michael Natterer committed
285

286 287
      unit = undo->gimage->unit;
      undo->gimage->unit = ru->unit;
288
      ru->unit = unit;
Michael Natterer's avatar
Michael Natterer committed
289

290
      accum->unit_changed = TRUE;
Michael Natterer's avatar
Michael Natterer committed
291 292 293 294 295 296
    }

  return TRUE;
}

static void
297 298
undo_free_image_resolution (GimpUndo      *undo,
                            GimpUndoMode   undo_mode)
Michael Natterer's avatar
Michael Natterer committed
299
{
300
  g_free (undo->data);
Michael Natterer's avatar
Michael Natterer committed
301 302 303
}


304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
/****************/
/*  Grid Undo   */
/****************/

typedef struct _GridUndo GridUndo;

struct _GridUndo
{
  GimpGrid *grid;
};

static gboolean undo_pop_image_grid  (GimpUndo            *undo,
                                      GimpUndoMode         undo_mode,
                                      GimpUndoAccumulator *accum);
static void     undo_free_image_grid (GimpUndo            *undo,
                                      GimpUndoMode         undo_mode);

gboolean
gimp_image_undo_push_image_grid (GimpImage   *gimage,
                                 const gchar *undo_desc,
                                 GimpGrid    *grid)
{
  GimpUndo *new;

  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
329
  g_return_val_if_fail (GIMP_IS_GRID (grid), FALSE);
330 331 332 333 334

  if ((new = gimp_image_undo_push (gimage,
                                   sizeof (GridUndo),
                                   sizeof (GridUndo),
                                   GIMP_UNDO_IMAGE_GRID, undo_desc,
335
                                   TRUE,
336 337 338
                                   undo_pop_image_grid,
                                   undo_free_image_grid)))
    {
339
      GridUndo *gu = new->data;
340

341
      gu->grid = gimp_config_duplicate (GIMP_CONFIG (grid));
342 343 344 345 346 347 348 349 350 351 352 353

      return TRUE;
    }

  return FALSE;
}

static gboolean
undo_pop_image_grid (GimpUndo            *undo,
                     GimpUndoMode         undo_mode,
                     GimpUndoAccumulator *accum)
{
354 355
  GridUndo *gu = undo->data;
  GimpGrid *grid;
356

357
  grid = gimp_config_duplicate (GIMP_CONFIG (undo->gimage->grid));
358

359
  gimp_image_set_grid (undo->gimage, gu->grid, FALSE);
360

361 362
  g_object_unref (gu->grid);
  gu->grid = grid;
363 364 365 366 367 368 369 370

  return TRUE;
}

static void
undo_free_image_grid (GimpUndo     *undo,
                      GimpUndoMode  undo_mode)
{
371
  GridUndo *gu = undo->data;
372 373 374 375 376 377 378 379

  if (gu->grid)
    g_object_unref (gu->grid);

  g_free (gu);
}


Michael Natterer's avatar
Michael Natterer committed
380 381
/****************/
/*  Guide Undo  */
382
/****************/
383

Michael Natterer's avatar
Michael Natterer committed
384
typedef struct _GuideUndo GuideUndo;
Elliot Lee's avatar
Elliot Lee committed
385

Michael Natterer's avatar
Michael Natterer committed
386 387
struct _GuideUndo
{
388 389 390
  GimpGuide           *guide;
  gint                 position;
  GimpOrientationType  orientation;
Michael Natterer's avatar
Michael Natterer committed
391
};
Elliot Lee's avatar
Elliot Lee committed
392

393 394 395 396 397
static gboolean undo_pop_image_guide  (GimpUndo            *undo,
                                       GimpUndoMode         undo_mode,
                                       GimpUndoAccumulator *accum);
static void     undo_free_image_guide (GimpUndo            *undo,
                                       GimpUndoMode         undo_mode);
Elliot Lee's avatar
Elliot Lee committed
398

399
gboolean
400 401 402
gimp_image_undo_push_image_guide (GimpImage   *gimage,
                                  const gchar *undo_desc,
                                  GimpGuide   *guide)
Elliot Lee's avatar
Elliot Lee committed
403
{
404
  GimpUndo *new;
Elliot Lee's avatar
Elliot Lee committed
405

406 407 408
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
  g_return_val_if_fail (guide != NULL, FALSE);

409 410 411
  if ((new = gimp_image_undo_push (gimage,
                                   sizeof (GuideUndo),
                                   sizeof (GuideUndo),
412
                                   GIMP_UNDO_IMAGE_GUIDE, undo_desc,
413 414 415
                                   TRUE,
                                   undo_pop_image_guide,
                                   undo_free_image_guide)))
Elliot Lee's avatar
Elliot Lee committed
416
    {
Michael Natterer's avatar
Michael Natterer committed
417
      GuideUndo *gu = new->data;
418

419 420 421
      gu->guide       = gimp_image_guide_ref (guide);
      gu->position    = guide->position;
      gu->orientation = guide->orientation;
422

Michael Natterer's avatar
Michael Natterer committed
423 424
      return TRUE;
    }
425

Michael Natterer's avatar
Michael Natterer committed
426 427
  return FALSE;
}
428

Michael Natterer's avatar
Michael Natterer committed
429
static gboolean
430 431 432
undo_pop_image_guide (GimpUndo            *undo,
                      GimpUndoMode         undo_mode,
                      GimpUndoAccumulator *accum)
Michael Natterer's avatar
Michael Natterer committed
433
{
434
  GuideUndo           *gu = undo->data;
435 436
  gint                 old_position;
  GimpOrientationType  old_orientation;
437

438 439
  old_position    = gu->guide->position;
  old_orientation = gu->guide->orientation;
440

441
  if (gu->guide->position == -1)
442 443 444 445 446 447
    {
      undo->gimage->guides = g_list_prepend (undo->gimage->guides, gu->guide);
      gu->guide->position = gu->position;
      gimp_image_guide_ref (gu->guide);
      gimp_image_update_guide (undo->gimage, gu->guide);
    }
448
  else if (gu->position == -1)
449 450 451
    {
      gimp_image_remove_guide (undo->gimage, gu->guide, FALSE);
    }
452
  else
453 454 455 456 457
    {
      gimp_image_update_guide (undo->gimage, gu->guide);
      gu->guide->position = gu->position;
      gimp_image_update_guide (undo->gimage, gu->guide);
    }
458

459 460 461 462
  gu->guide->orientation = gu->orientation;

  gu->position    = old_position;
  gu->orientation = old_orientation;
463

Elliot Lee's avatar
Elliot Lee committed
464 465 466
  return TRUE;
}

467
static void
468 469
undo_free_image_guide (GimpUndo     *undo,
                       GimpUndoMode  undo_mode)
Elliot Lee's avatar
Elliot Lee committed
470
{
471
  GuideUndo *gu = undo->data;
Elliot Lee's avatar
Elliot Lee committed
472

473
  gimp_image_guide_unref (gu->guide);
474
  g_free (gu);
Elliot Lee's avatar
Elliot Lee committed
475 476
}

477

478 479 480 481 482 483 484 485
/*******************/
/*  Colormap Undo  */
/*******************/

typedef struct _ColormapUndo ColormapUndo;

struct _ColormapUndo
{
486 487
  gint    num_colors;
  guchar *cmap;
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
};

static gboolean undo_pop_image_colormap  (GimpUndo            *undo,
                                          GimpUndoMode         undo_mode,
                                          GimpUndoAccumulator *accum);
static void     undo_free_image_colormap (GimpUndo            *undo,
                                          GimpUndoMode         undo_mode);

gboolean
gimp_image_undo_push_image_colormap (GimpImage   *gimage,
                                     const gchar *undo_desc)
{
  GimpUndo *new;

  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);

  if ((new = gimp_image_undo_push (gimage,
                                   sizeof (ColormapUndo),
                                   sizeof (ColormapUndo),
                                   GIMP_UNDO_IMAGE_COLORMAP, undo_desc,
                                   TRUE,
                                   undo_pop_image_colormap,
                                   undo_free_image_colormap)))
    {
512
      ColormapUndo *cu = new->data;
513 514

      cu->num_colors = gimp_image_get_colormap_size (gimage);
515 516
      cu->cmap       = g_memdup (gimp_image_get_colormap (gimage),
                                 cu->num_colors * 3);
517 518 519 520 521 522 523 524 525 526 527 528

      return TRUE;
    }

  return FALSE;
}

static gboolean
undo_pop_image_colormap (GimpUndo            *undo,
                         GimpUndoMode         undo_mode,
                         GimpUndoAccumulator *accum)
{
529 530
  ColormapUndo *cu = undo->data;
  guchar       *cmap;
531 532 533
  gint          num_colors;

  num_colors = gimp_image_get_colormap_size (undo->gimage);
534 535
  cmap       = g_memdup (gimp_image_get_colormap (undo->gimage),
                         num_colors * 3);
536 537 538

  gimp_image_set_colormap (undo->gimage, cu->cmap, cu->num_colors, FALSE);

539 540 541
  if (cu->cmap)
    g_free (cu->cmap);

542
  cu->num_colors = num_colors;
543
  cu->cmap       = cmap;
544 545 546 547 548 549 550 551

  return TRUE;
}

static void
undo_free_image_colormap (GimpUndo     *undo,
                          GimpUndoMode  undo_mode)
{
552 553 554 555 556 557
  ColormapUndo *cu = undo->data;

  if (cu->cmap)
    g_free (cu->cmap);

  g_free (cu);
558 559 560
}


561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
/*******************/
/*  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;

643 644
  undo->size -= tile_manager_get_memsize (drawable_undo->tiles);

645 646 647 648 649 650 651 652
  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);

653 654
  undo->size += tile_manager_get_memsize (drawable_undo->tiles);

655 656 657 658 659 660 661 662 663 664 665 666 667 668
  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);
}


669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
/***********************/
/*  Drawable Mod Undo  */
/***********************/

typedef struct _DrawableModUndo DrawableModUndo;

struct _DrawableModUndo
{
  TileManager   *tiles;
  GimpImageType  type;
  gint           offset_x;
  gint		 offset_y;
};

static gboolean undo_pop_drawable_mod  (GimpUndo            *undo,
                                        GimpUndoMode         undo_mode,
                                        GimpUndoAccumulator *accum);
static void     undo_free_drawable_mod (GimpUndo            *undo,
                                        GimpUndoMode         undo_mode);

gboolean
690 691 692
gimp_image_undo_push_drawable_mod (GimpImage    *gimage,
                                   const gchar  *undo_desc,
                                   GimpDrawable *drawable)
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
{
  GimpUndo *new;
  gint64    size;

  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

  size = sizeof (DrawableModUndo) + tile_manager_get_memsize (drawable->tiles);

  if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (drawable),
                                        size, sizeof (DrawableModUndo),
                                        GIMP_UNDO_DRAWABLE_MOD, undo_desc,
                                        TRUE,
                                        undo_pop_drawable_mod,
                                        undo_free_drawable_mod)))
    {
      DrawableModUndo *drawable_undo = new->data;

      drawable_undo->tiles    = tile_manager_ref (drawable->tiles);
      drawable_undo->type     = drawable->type;
      drawable_undo->offset_x = GIMP_ITEM (drawable)->offset_x;
      drawable_undo->offset_y = GIMP_ITEM (drawable)->offset_y;

      return TRUE;
    }

  return FALSE;
}

static gboolean
undo_pop_drawable_mod (GimpUndo            *undo,
                       GimpUndoMode         undo_mode,
                       GimpUndoAccumulator *accum)
{
  DrawableModUndo *drawable_undo = undo->data;
  GimpDrawable    *drawable      = GIMP_DRAWABLE (GIMP_ITEM_UNDO (undo)->item);
  TileManager     *tiles;
  GimpImageType    drawable_type;
  gint             offset_x, offset_y;

733 734
  undo->size -= tile_manager_get_memsize (drawable_undo->tiles);

735 736 737 738 739 740 741 742 743 744 745 746 747 748
  tiles         = drawable_undo->tiles;
  drawable_type = drawable_undo->type;
  offset_x      = drawable_undo->offset_x;
  offset_y      = drawable_undo->offset_y;

  drawable_undo->tiles    = tile_manager_ref (drawable->tiles);
  drawable_undo->type     = drawable->type;
  drawable_undo->offset_x = GIMP_ITEM (drawable)->offset_x;
  drawable_undo->offset_y = GIMP_ITEM (drawable)->offset_y;

  gimp_drawable_set_tiles_full (drawable, FALSE, NULL,
                                tiles, drawable_type, offset_x, offset_y);
  tile_manager_unref (tiles);

749 750
  undo->size += tile_manager_get_memsize (drawable_undo->tiles);

751 752 753 754 755 756 757 758 759 760 761 762 763 764
  return TRUE;
}

static void
undo_free_drawable_mod (GimpUndo     *undo,
                        GimpUndoMode  undo_mode)
{
  DrawableModUndo *drawable_undo = undo->data;

  tile_manager_unref (drawable_undo->tiles);
  g_free (drawable_undo);
}


765 766
/***************/
/*  Mask Undo  */
767
/***************/
768 769 770 771 772

typedef struct _MaskUndo MaskUndo;

struct _MaskUndo
{
773 774
  TileManager *tiles;  /*  the actual mask  */
  gint         x, y;   /*  offsets          */
775 776
};

777 778 779 780 781
static gboolean undo_pop_mask  (GimpUndo            *undo,
                                GimpUndoMode         undo_mode,
                                GimpUndoAccumulator *accum);
static void     undo_free_mask (GimpUndo            *undo,
                                GimpUndoMode         undo_mode);
782 783

gboolean
784 785 786
gimp_image_undo_push_mask (GimpImage   *gimage,
                           const gchar *undo_desc,
                           GimpChannel *mask)
787
{
788
  TileManager *undo_tiles = NULL;
789
  gint         x1, y1, x2, y2;
790
  GimpUndo    *new;
791
  gint64       size;
792

793 794 795
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
  g_return_val_if_fail (GIMP_IS_CHANNEL (mask), FALSE);

796 797
  size = sizeof (MaskUndo);

798 799
  if (gimp_channel_bounds (mask, &x1, &y1, &x2, &y2))
    {
800 801
      GimpDrawable *drawable = GIMP_DRAWABLE (mask);
      PixelRegion   srcPR, destPR;
802

803 804
      undo_tiles = tile_manager_new (x2 - x1, y2 - y1,
                                     gimp_drawable_bytes (drawable));
805

806 807
      pixel_region_init (&srcPR, gimp_drawable_data (drawable),
                         x1, y1, x2 - x1, y2 - y1, FALSE);
808
      pixel_region_init (&destPR, undo_tiles,
809
                         0, 0, x2 - x1, y2 - y1, TRUE);
810 811 812

      copy_region (&srcPR, &destPR);

813 814
      size += tile_manager_get_memsize (undo_tiles);
    }
815

816 817 818 819 820 821
  if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (mask),
                                        size, sizeof (MaskUndo),
                                        GIMP_UNDO_MASK, undo_desc,
                                        FALSE,
                                        undo_pop_mask,
                                        undo_free_mask)))
822
    {
823
      MaskUndo *mask_undo = new->data;
824

825 826 827
      mask_undo->tiles = undo_tiles;
      mask_undo->x     = x1;
      mask_undo->y     = y1;
828 829 830 831 832

      return TRUE;
    }

  if (undo_tiles)
833
    tile_manager_unref (undo_tiles);
834 835 836 837 838

  return FALSE;
}

static gboolean
839 840 841
undo_pop_mask (GimpUndo            *undo,
               GimpUndoMode         undo_mode,
               GimpUndoAccumulator *accum)
842
{
Michael Natterer's avatar
Michael Natterer committed
843 844
  MaskUndo    *mu      = undo->data;
  GimpChannel *channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (undo)->item);
845 846 847
  TileManager *new_tiles;
  PixelRegion  srcPR, destPR;
  gint         x1, y1, x2, y2;
848 849 850
  gint         width  = 0;
  gint         height = 0;
  guchar       empty  = 0;
851

852 853 854
  if (mu->tiles)
    undo->size -= tile_manager_get_memsize (mu->tiles);

855
  if (gimp_channel_bounds (channel, &x1, &y1, &x2, &y2))
856 857 858
    {
      new_tiles = tile_manager_new ((x2 - x1), (y2 - y1), 1);

859
      pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
860 861 862 863 864 865
                         x1, y1, (x2 - x1), (y2 - y1), FALSE);
      pixel_region_init (&destPR, new_tiles,
			 0, 0, (x2 - x1), (y2 - y1), TRUE);

      copy_region (&srcPR, &destPR);

866
      pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
867 868 869 870 871
			 x1, y1, (x2 - x1), (y2 - y1), TRUE);

      color_region (&srcPR, &empty);
    }
  else
872 873 874
    {
      new_tiles = NULL;
    }
875

876
  if (mu->tiles)
877
    {
878 879
      width  = tile_manager_width (mu->tiles);
      height = tile_manager_height (mu->tiles);
880

881
      pixel_region_init (&srcPR, mu->tiles,
882
			 0, 0, width, height, FALSE);
883
      pixel_region_init (&destPR, GIMP_DRAWABLE (channel)->tiles,
884
			 mu->x, mu->y, width, height, TRUE);
885 886 887

      copy_region (&srcPR, &destPR);

888
      tile_manager_unref (mu->tiles);
889 890
    }

891 892
  /* invalidate the current bounds and boundary of the mask */
  gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (channel));
893

894
  if (mu->tiles)
895
    {
896 897 898 899 900
      channel->empty = FALSE;
      channel->x1    = mu->x;
      channel->y1    = mu->y;
      channel->x2    = mu->x + width;
      channel->y2    = mu->y + height;
901 902 903
    }
  else
    {
904 905 906
      channel->empty = TRUE;
      channel->x1    = 0;
      channel->y1    = 0;
907 908
      channel->x2    = GIMP_ITEM (channel)->width;
      channel->y2    = GIMP_ITEM (channel)->height;
909 910 911
    }

  /* we know the bounds */
912
  channel->bounds_known = TRUE;
913 914

  /*  set the new mask undo parameters  */
915 916 917
  mu->tiles = new_tiles;
  mu->x     = x1;
  mu->y     = y1;
918

919 920 921 922
  gimp_drawable_update (GIMP_DRAWABLE (channel),
                        0, 0,
                        GIMP_ITEM (channel)->width,
                        GIMP_ITEM (channel)->height);
923

924 925 926
  if (mu->tiles)
    undo->size += tile_manager_get_memsize (mu->tiles);

927 928 929 930
  return TRUE;
}

static void
931 932
undo_free_mask (GimpUndo     *undo,
                GimpUndoMode  undo_mode)
933
{
Michael Natterer's avatar
Michael Natterer committed
934
  MaskUndo *mu = undo->data;
935

936
  if (mu->tiles)
937
    tile_manager_unref (mu->tiles);
938

939
  g_free (mu);
940 941 942
}


943 944
/**********************/
/*  Item Rename Undo  */
945
/**********************/
946 947 948 949 950

typedef struct _ItemRenameUndo ItemRenameUndo;

struct _ItemRenameUndo
{
951
  gchar *name;
952 953
};

954 955 956 957 958
static gboolean undo_pop_item_rename  (GimpUndo            *undo,
                                       GimpUndoMode         undo_mode,
                                       GimpUndoAccumulator *accum);
static void     undo_free_item_rename (GimpUndo            *undo,
                                       GimpUndoMode         undo_mode);
959 960

gboolean
961
gimp_image_undo_push_item_rename (GimpImage   *gimage,
962 963
                                  const gchar *undo_desc,
                                  GimpItem    *item)
964
{
965
  GimpUndo    *new;
966
  gint64       size;
967
  const gchar *name;
968

969 970 971
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
  g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);

972 973 974 975
  name = gimp_object_get_name (GIMP_OBJECT (item));

  size = sizeof (ItemRenameUndo) + strlen (name) + 1;

976
  if ((new = gimp_image_undo_push_item (gimage, item,
977
                                        size, sizeof (ItemRenameUndo),
978 979 980 981
                                        GIMP_UNDO_ITEM_RENAME, undo_desc,
                                        TRUE,
                                        undo_pop_item_rename,
                                        undo_free_item_rename)))
982
    {
Michael Natterer's avatar
Michael Natterer committed
983
      ItemRenameUndo *iru = new->data;
984

985
      iru->name = g_strdup (name);
986 987 988 989 990 991 992 993

      return TRUE;
    }

  return FALSE;
}

static gboolean
994 995 996
undo_pop_item_rename (GimpUndo            *undo,
                      GimpUndoMode         undo_mode,
                      GimpUndoAccumulator *accum)
997
{
Michael Natterer's avatar
Michael Natterer committed
998 999
  ItemRenameUndo *iru  = undo->data;
  GimpItem       *item = GIMP_ITEM_UNDO (undo)->item;
1000 1001
  gchar          *tmp;

1002 1003
  undo->size -= strlen (iru->name);

1004
  tmp = g_strdup (gimp_object_get_name (GIMP_OBJECT (item)));
1005 1006 1007 1008 1009
  gimp_object_set_name (GIMP_OBJECT (item), iru->name);
  g_free (iru->name);
  iru->name = tmp;

  undo->size += strlen (iru->name);
1010 1011 1012 1013 1014

  return TRUE;
}

static void
1015 1016
undo_free_item_rename (GimpUndo     *undo,
                       GimpUndoMode  undo_mode)
1017
{
Michael Natterer's avatar
Michael Natterer committed
1018
  ItemRenameUndo *iru = undo->data;
1019

1020
  g_free (iru->name);
1021 1022 1023 1024
  g_free (iru);
}


1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
/****************************/
/*  Item displacement Undo  */
/****************************/

typedef struct _ItemDisplaceUndo ItemDisplaceUndo;

struct _ItemDisplaceUndo
{
  gint old_offset_x;
  gint old_offset_y;
};

static gboolean undo_pop_item_displace  (GimpUndo            *undo,
                                         GimpUndoMode         undo_mode,
                                         GimpUndoAccumulator *accum);
static void     undo_free_item_displace (GimpUndo            *undo,
                                         GimpUndoMode         undo_mode);

gboolean
gimp_image_undo_push_item_displace (GimpImage   *gimage,
                                    const gchar *undo_desc,
                                    GimpItem    *item)
{
  GimpUndo *new;

  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
  g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);

  if ((new = gimp_image_undo_push_item (gimage, item,
                                        sizeof (ItemDisplaceUndo),
                                        sizeof (ItemDisplaceUndo),
                                        GIMP_UNDO_ITEM_DISPLACE, undo_desc,
                                        TRUE,
                                        undo_pop_item_displace,
                                        undo_free_item_displace)))
    {
Michael Natterer's avatar
Michael Natterer committed
1061
      ItemDisplaceUndo *idu = new->data;
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075

      gimp_item_offsets (item, &idu->old_offset_x, &idu->old_offset_y);

      return TRUE;
    }

  return FALSE;
}

static gboolean
undo_pop_item_displace (GimpUndo            *undo,
                        GimpUndoMode         undo_mode,
                        GimpUndoAccumulator *accum)
{
Michael Natterer's avatar
Michael Natterer committed
1076 1077
  ItemDisplaceUndo *idu  = undo->data;
  GimpItem         *item = GIMP_ITEM_UNDO (undo)->item;
1078 1079 1080 1081 1082 1083 1084 1085
  gint              offset_x;
  gint              offset_y;

  gimp_item_offsets (item, &offset_x, &offset_y);

  gimp_item_translate (item,
                       idu->old_offset_x - offset_x,
                       idu->old_offset_y - offset_y,
1086
                       FALSE);
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097

  idu->old_offset_x = offset_x;
  idu->old_offset_y = offset_y;

  return TRUE;
}

static void
undo_free_item_displace (GimpUndo     *undo,
                         GimpUndoMode  undo_mode)
{
Michael Natterer's avatar
Michael Natterer committed
1098