gimpdrawable.c 21.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
Sven Neumann's avatar
Sven Neumann committed
18

19 20
#include "config.h"

21
#include <stdlib.h>
Sven Neumann's avatar
Sven Neumann committed
22
#include <stdio.h>
23
#include <string.h>
24

25
#include <glib-object.h>
Sven Neumann's avatar
Sven Neumann committed
26

27 28
#include "libgimpcolor/gimpcolor.h"
#include "libgimpmath/gimpmath.h"
29
#include "libgimpbase/gimpbase.h"
30

Michael Natterer's avatar
Michael Natterer committed
31
#include "core-types.h"
32

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

37 38
#include "paint-funcs/paint-funcs.h"

39
#include "gimp.h"
40
#include "gimpchannel.h"
Michael Natterer's avatar
Michael Natterer committed
41
#include "gimpcontext.h"
42
#include "gimpdrawable.h"
43
#include "gimpdrawable-preview.h"
44
#include "gimpimage.h"
45
#include "gimpimage-mask.h"
46
#include "gimpimage-undo-push.h"
47
#include "gimplayer.h"
48
#include "gimplist.h"
49
#include "gimpmarshal.h"
50
#include "gimpparasitelist.h"
51
#include "gimppreviewcache.h"
52

53
#include "gimp-intl.h"
54

55 56 57

enum
{
58
  VISIBILITY_CHANGED,
59 60 61
  LAST_SIGNAL
};

62

63 64
/*  local function prototypes  */

65 66
static void       gimp_drawable_class_init         (GimpDrawableClass *klass);
static void       gimp_drawable_init               (GimpDrawable      *drawable);
67

68
static void       gimp_drawable_finalize           (GObject           *object);
69

70
static gsize      gimp_drawable_get_memsize        (GimpObject        *object);
71

72 73 74 75 76
static void       gimp_drawable_invalidate_preview (GimpViewable      *viewable);

static GimpItem * gimp_drawable_duplicate          (GimpItem          *item,
                                                    GType              new_type,
                                                    gboolean           add_alpha);
77 78 79 80 81 82
static void       gimp_drawable_scale              (GimpItem          *item,
                                                    gint               new_width,
                                                    gint               new_height,
                                                    gint               new_offset_x,
                                                    gint               new_offset_y,
                                                    GimpInterpolationType interp_type);
83

84

85 86
/*  private variables  */

87 88
static guint gimp_drawable_signals[LAST_SIGNAL] = { 0 };

89
static GimpItemClass *parent_class = NULL;
90 91


92
GType
Manish Singh's avatar
Manish Singh committed
93
gimp_drawable_get_type (void)
94
{
95
  static GType drawable_type = 0;
96 97 98

  if (! drawable_type)
    {
99
      static const GTypeInfo drawable_info =
100
      {
101 102 103 104 105 106
        sizeof (GimpDrawableClass),
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_drawable_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data     */
107
	sizeof (GimpDrawable),
108 109
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_drawable_init,
110 111
      };

112
      drawable_type = g_type_register_static (GIMP_TYPE_ITEM,
113 114
					      "GimpDrawable", 
					      &drawable_info, 0);
115 116 117
    }

  return drawable_type;
118 119 120
}

static void
121
gimp_drawable_class_init (GimpDrawableClass *klass)
122
{
123
  GObjectClass      *object_class;
124 125
  GimpObjectClass   *gimp_object_class;
  GimpViewableClass *viewable_class;
126
  GimpItemClass     *item_class;
127

128 129 130
  object_class      = G_OBJECT_CLASS (klass);
  gimp_object_class = GIMP_OBJECT_CLASS (klass);
  viewable_class    = GIMP_VIEWABLE_CLASS (klass);
131
  item_class        = GIMP_ITEM_CLASS (klass);
132

133
  parent_class = g_type_class_peek_parent (klass);
134

135
  gimp_drawable_signals[VISIBILITY_CHANGED] =
136 137 138 139 140
    g_signal_new ("visibility_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpDrawableClass, visibility_changed),
		  NULL, NULL,
141
		  gimp_marshal_VOID__VOID,
142
		  G_TYPE_NONE, 0);
143

144
  object_class->finalize             = gimp_drawable_finalize;
145

146
  gimp_object_class->get_memsize     = gimp_drawable_get_memsize;
147

148
  viewable_class->invalidate_preview = gimp_drawable_invalidate_preview;
149
  viewable_class->get_preview_size   = gimp_drawable_get_preview_size;
150
  viewable_class->get_popup_size     = gimp_drawable_get_popup_size;
151
  viewable_class->get_preview        = gimp_drawable_get_preview;
152

153
  item_class->duplicate              = gimp_drawable_duplicate;
154
  item_class->scale                  = gimp_drawable_scale;
155

Michael Natterer's avatar
Michael Natterer committed
156
  klass->visibility_changed          = NULL;
157 158
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
static void
gimp_drawable_init (GimpDrawable *drawable)
{
  drawable->tiles         = NULL;
  drawable->visible       = FALSE;
  drawable->width         = 0;
  drawable->height        = 0;
  drawable->offset_x      = 0;
  drawable->offset_y      = 0;
  drawable->bytes         = 0;
  drawable->type          = -1;
  drawable->has_alpha     = FALSE;
  drawable->preview_cache = NULL;
  drawable->preview_valid = FALSE;
}

static void
176
gimp_drawable_finalize (GObject *object)
177 178 179 180 181 182 183 184
{
  GimpDrawable *drawable;

  g_return_if_fail (GIMP_IS_DRAWABLE (object));

  drawable = GIMP_DRAWABLE (object);

  if (drawable->tiles)
185 186 187 188
    {
      tile_manager_destroy (drawable->tiles);
      drawable->tiles = NULL;
    }
189 190 191 192

  if (drawable->preview_cache)
    gimp_preview_cache_invalidate (&drawable->preview_cache);

193
  G_OBJECT_CLASS (parent_class)->finalize (object);
194 195
}

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
static gsize
gimp_drawable_get_memsize (GimpObject *object)
{
  GimpDrawable *drawable;
  gsize         memsize = 0;

  drawable = GIMP_DRAWABLE (object);

  if (drawable->tiles)
    memsize += tile_manager_get_memsize (drawable->tiles);

  if (drawable->preview_cache)
    memsize += gimp_preview_cache_get_memsize (drawable->preview_cache);

  return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object);
}

213 214 215 216 217 218
static void
gimp_drawable_invalidate_preview (GimpViewable *viewable)
{
  GimpDrawable *drawable;
  GimpImage    *gimage;

219 220 221
  if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview)
    GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable);

222 223 224 225
  drawable = GIMP_DRAWABLE (viewable);

  drawable->preview_valid = FALSE;

226 227 228
  if (drawable->preview_cache)
    gimp_preview_cache_invalidate (&drawable->preview_cache);

229
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
230 231

  if (gimage)
232
    gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));
233 234
}

235 236 237 238
static GimpItem *
gimp_drawable_duplicate (GimpItem *item,
                         GType     new_type,
                         gboolean  add_alpha)
239
{
240 241
  GimpDrawable  *drawable;
  GimpItem      *new_item;
242 243 244 245 246 247 248
  GimpDrawable  *new_drawable;
  GimpImageType  new_image_type;
  PixelRegion    srcPR;
  PixelRegion    destPR;

  g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL);

249 250 251 252 253 254 255 256
  new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type,
                                                        add_alpha);

  if (! GIMP_IS_DRAWABLE (new_item))
    return new_item;

  drawable     = GIMP_DRAWABLE (item);
  new_drawable = GIMP_DRAWABLE (new_item);
257 258

  if (add_alpha)
259
    new_image_type = gimp_drawable_type_with_alpha (drawable);
260
  else
261
    new_image_type = gimp_drawable_type (drawable);
262 263

  gimp_drawable_configure (new_drawable,
264
                           gimp_item_get_image (GIMP_ITEM (drawable)),
265 266
                           drawable->offset_x,
                           drawable->offset_y,
267 268 269
                           gimp_drawable_width (drawable),
                           gimp_drawable_height (drawable),
                           new_image_type,
270
                           GIMP_OBJECT (new_drawable)->name);
271

272
  new_drawable->visible = drawable->visible;
273 274 275

  pixel_region_init (&srcPR, drawable->tiles, 
                     0, 0, 
276 277
                     gimp_drawable_width (drawable),
                     gimp_drawable_height (drawable),
278 279 280
                     FALSE);
  pixel_region_init (&destPR, new_drawable->tiles,
                     0, 0, 
281 282
                     gimp_drawable_width (new_drawable),
                     gimp_drawable_height (new_drawable),
283 284 285
                     TRUE);

  if (new_image_type == drawable->type)
286
    copy_region (&srcPR, &destPR);
287
  else
288
    add_alpha_region (&srcPR, &destPR);
289

290 291 292
  return new_item;
}

293 294 295 296 297 298 299 300 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 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
static void
gimp_drawable_scale (GimpItem              *item,
                     gint                   new_width,
                     gint                   new_height,
                     gint                   new_offset_x,
                     gint                   new_offset_y,
                     GimpInterpolationType  interpolation_type)
{
  GimpDrawable *drawable;
  PixelRegion   srcPR, destPR;
  TileManager  *new_tiles;

  drawable = GIMP_DRAWABLE (item);

  /*  Update the old position  */
  gimp_drawable_update (drawable, 0, 0, drawable->width, drawable->height);

  /*  Allocate the new channel  */
  new_tiles = tile_manager_new (new_width, new_height, drawable->bytes);

  /*  Configure the pixel regions  */
  pixel_region_init (&srcPR, drawable->tiles,
		     0, 0,
		     drawable->width,
		     drawable->height,
                     FALSE);

  pixel_region_init (&destPR, new_tiles,
                     0, 0,
                     new_width, new_height,
                     TRUE);

  /*  Scale the drawable -
   *   If the drawable is indexed, then we don't use pixel-value
   *   resampling because that doesn't necessarily make sense for indexed
   *   images.
   */
  if (gimp_drawable_is_indexed (drawable))
    interpolation_type = GIMP_INTERPOLATION_NONE;

  scale_region (&srcPR, &destPR, interpolation_type);

  /*  Configure the new channel  */
  drawable->tiles    = new_tiles;
  drawable->width    = new_width;
  drawable->height   = new_height;
  drawable->offset_x = new_offset_x;
  drawable->offset_y = new_offset_y;

  /*  Update the new position  */
  gimp_drawable_update (drawable, 0, 0, drawable->width, drawable->height);

  gimp_viewable_size_changed (GIMP_VIEWABLE (drawable));
}

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
void
gimp_drawable_configure (GimpDrawable  *drawable,
			 GimpImage     *gimage,
                         gint           offset_x,
                         gint           offset_y,
			 gint           width,
			 gint           height, 
			 GimpImageType  type,
			 const gchar   *name)
{
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (GIMP_IS_IMAGE (gimage));

  /*  if not already configured by gimp_item_copy()  */
  if (! GIMP_ITEM (drawable)->ID)
    gimp_item_configure (GIMP_ITEM (drawable), gimage, name);

  drawable->width     = width;
  drawable->height    = height;
  drawable->type      = type;
  drawable->bytes     = GIMP_IMAGE_TYPE_BYTES (type);
  drawable->has_alpha = GIMP_IMAGE_TYPE_HAS_ALPHA (type);
  drawable->offset_x  = offset_x;
  drawable->offset_y  = offset_y;

  if (drawable->tiles)
    tile_manager_destroy (drawable->tiles);

  drawable->tiles = tile_manager_new (width, height,
                                      drawable->bytes);

  drawable->visible = TRUE;

  /*  preview variables  */
  drawable->preview_cache = NULL;
  drawable->preview_valid = FALSE;
384 385
}

Michael Natterer's avatar
Michael Natterer committed
386 387 388 389
void
gimp_drawable_update (GimpDrawable *drawable,
		      gint          x,
		      gint          y,
390 391
		      gint          w,
		      gint          h)
Michael Natterer's avatar
Michael Natterer committed
392 393 394 395 396 397 398
{
  GimpImage *gimage;
  gint       offset_x;
  gint       offset_y;

  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

399
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
Michael Natterer's avatar
Michael Natterer committed
400 401 402 403 404 405 406 407 408 409 410 411 412

  g_return_if_fail (gimage != NULL);

  gimp_drawable_offsets (drawable, &offset_x, &offset_y);
  x += offset_x;
  y += offset_y;

  gimp_image_update (gimage, x, y, w, h);

  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable));
}

void
413 414
gimp_drawable_push_undo (GimpDrawable *drawable,
                         const gchar  *undo_desc,
415 416 417 418 419 420
                         gint          x1,
                         gint          y1,
                         gint          x2,
                         gint          y2, 
                         TileManager  *tiles,
                         gboolean      sparse)
Michael Natterer's avatar
Michael Natterer committed
421 422 423
{
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

424
  if (! tiles)
425 426 427 428
    gimp_image_undo_push_image (gimp_item_get_image (GIMP_ITEM (drawable)),
                                undo_desc,
                                drawable, 
                                x1, y1, x2, y2);
Michael Natterer's avatar
Michael Natterer committed
429
  else
430 431 432 433 434
    gimp_image_undo_push_image_mod (gimp_item_get_image (GIMP_ITEM (drawable)),
                                    undo_desc,
                                    drawable, 
                                    x1, y1, x2, y2,
                                    tiles, sparse);
Michael Natterer's avatar
Michael Natterer committed
435 436
}

437
void
438
gimp_drawable_merge_shadow (GimpDrawable *drawable,
439 440
			    gboolean      push_undo,
                            const gchar  *undo_desc)
441
{
442
  GimpImage   *gimage;
443 444
  PixelRegion  shadowPR;
  gint         x1, y1, x2, y2;
445

Manish Singh's avatar
Manish Singh committed
446
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
447

448
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
449

450
  g_return_if_fail (GIMP_IS_IMAGE (gimage));
Manish Singh's avatar
Manish Singh committed
451
  g_return_if_fail (gimage->shadow != NULL);
452

453 454 455 456 457 458 459
  /*  A useful optimization here is to limit the update to the
   *  extents of the selection mask, as it cannot extend beyond
   *  them.
   */
  gimp_drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
  pixel_region_init (&shadowPR, gimage->shadow, x1, y1,
		     (x2 - x1), (y2 - y1), FALSE);
460 461
  gimp_image_apply_image (gimage, drawable, &shadowPR,
                          push_undo, undo_desc,
462 463
                          GIMP_OPACITY_OPAQUE, GIMP_REPLACE_MODE,
                          NULL, x1, y1);
464 465 466
}

void
467 468
gimp_drawable_fill (GimpDrawable  *drawable,
		    const GimpRGB *color)
469
{
470
  GimpImage   *gimage;
471 472 473
  PixelRegion  destPR;
  guchar       c[MAX_CHANNELS];
  guchar       i;
474

Manish Singh's avatar
Manish Singh committed
475 476
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

477
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
478

Manish Singh's avatar
Manish Singh committed
479
  g_return_if_fail (gimage != NULL);
480

481
  switch (GIMP_IMAGE_TYPE_BASE_TYPE (gimp_drawable_type (drawable)))
482
    {
483
    case GIMP_RGB:
484 485 486 487 488
      gimp_rgba_get_uchar (color,
			   &c[RED_PIX],
			   &c[GREEN_PIX],
			   &c[BLUE_PIX],
			   &c[ALPHA_PIX]);
489
      if (gimp_drawable_type (drawable) != GIMP_RGBA_IMAGE)
490
	c[ALPHA_PIX] = 255;
491
      break;
492

493
    case GIMP_GRAY:
494 495 496 497 498
      gimp_rgba_get_uchar (color,
			   &c[GRAY_PIX],
			   NULL,
			   NULL,
			   &c[ALPHA_G_PIX]);
499
      if (gimp_drawable_type (drawable) != GIMP_GRAYA_IMAGE)
500
	c[ALPHA_G_PIX] = 255;
501
      break;
502

503
    case GIMP_INDEXED:
504 505 506 507
      gimp_rgb_get_uchar (color,
			  &c[RED_PIX],
			  &c[GREEN_PIX],
			  &c[BLUE_PIX]);
508
      gimp_image_transform_color (gimage, drawable, c, &i, GIMP_RGB);
509
      c[INDEXED_PIX] = i;
510
      if (gimp_drawable_type (drawable) == GIMP_INDEXEDA_IMAGE)
511 512 513 514 515
	gimp_rgba_get_uchar (color,
			     NULL,
			     NULL,
			     NULL,
			     &c[ALPHA_I_PIX]);
516
      break;
517

518
    default:
519 520
      g_warning ("%s: Cannot fill unknown image type.", 
                 G_GNUC_PRETTY_FUNCTION);
521 522 523 524 525 526
      break;
    }

  pixel_region_init (&destPR,
		     gimp_drawable_data (drawable),
		     0, 0,
527
		     gimp_drawable_width  (drawable),
528 529 530
		     gimp_drawable_height (drawable),
		     TRUE);
  color_region (&destPR, c);
Michael Natterer's avatar
Michael Natterer committed
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546

  gimp_drawable_update (drawable,
			0, 0,
			gimp_drawable_width  (drawable),
			gimp_drawable_height (drawable));
}

void
gimp_drawable_fill_by_type (GimpDrawable *drawable,
			    GimpContext  *context,
			    GimpFillType  fill_type)
{
  GimpRGB color;

  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

547
  color.a = GIMP_OPACITY_OPAQUE;
Michael Natterer's avatar
Michael Natterer committed
548 549 550

  switch (fill_type)
    {
551
    case GIMP_FOREGROUND_FILL:
Michael Natterer's avatar
Michael Natterer committed
552 553 554
      gimp_context_get_foreground (context, &color);
      break;

555
    case  GIMP_BACKGROUND_FILL:
Michael Natterer's avatar
Michael Natterer committed
556 557 558
      gimp_context_get_background (context, &color);
      break;

559
    case GIMP_WHITE_FILL:
Michael Natterer's avatar
Michael Natterer committed
560 561 562
      gimp_rgb_set (&color, 1.0, 1.0, 1.0);
      break;

563
    case GIMP_TRANSPARENT_FILL:
564
      gimp_rgba_set (&color, 0.0, 0.0, 0.0, GIMP_OPACITY_TRANSPARENT);
Michael Natterer's avatar
Michael Natterer committed
565 566
      break;

567
    case  GIMP_NO_FILL:
Michael Natterer's avatar
Michael Natterer committed
568 569 570
      return;

    default:
571
      g_warning ("%s: unknown fill type %d", G_GNUC_PRETTY_FUNCTION, fill_type);
Michael Natterer's avatar
Michael Natterer committed
572 573 574 575
      return;
    }

  gimp_drawable_fill (drawable, &color);
576 577
}

578
gboolean
579
gimp_drawable_mask_bounds (GimpDrawable *drawable, 
580 581 582 583
			   gint         *x1,
			   gint         *y1,
			   gint         *x2,
			   gint         *y2)
584
{
Manish Singh's avatar
Manish Singh committed
585
  GimpImage *gimage;
586
  gint       off_x, off_y;
587

Manish Singh's avatar
Manish Singh committed
588
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
589

590
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
591

Manish Singh's avatar
Manish Singh committed
592
  g_return_val_if_fail (gimage != NULL, FALSE);
593

594
  if (gimp_image_mask_bounds (gimage, x1, y1, x2, y2))
595 596
    {
      gimp_drawable_offsets (drawable, &off_x, &off_y);
597
      *x1 = CLAMP (*x1 - off_x, 0, gimp_drawable_width  (drawable));
598
      *y1 = CLAMP (*y1 - off_y, 0, gimp_drawable_height (drawable));
599
      *x2 = CLAMP (*x2 - off_x, 0, gimp_drawable_width  (drawable));
600 601 602 603 604
      *y2 = CLAMP (*y2 - off_y, 0, gimp_drawable_height (drawable));
      return TRUE;
    }
  else
    {
605
      *x2 = gimp_drawable_width  (drawable);
606 607 608 609 610
      *y2 = gimp_drawable_height (drawable);
      return FALSE;
    }
}

611
gboolean
612
gimp_drawable_has_alpha (const GimpDrawable *drawable)
613
{
Manish Singh's avatar
Manish Singh committed
614 615 616
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

  return drawable->has_alpha;
617
}
618

619
GimpImageType
620
gimp_drawable_type (const GimpDrawable *drawable)
621
{
Manish Singh's avatar
Manish Singh committed
622 623 624
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

  return drawable->type;
625 626
}

627
GimpImageType
628
gimp_drawable_type_with_alpha (const GimpDrawable *drawable)
629
{
Manish Singh's avatar
Manish Singh committed
630
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);
631

632
  return GIMP_IMAGE_TYPE_WITH_ALPHA (gimp_drawable_type (drawable));
633 634 635 636 637 638 639
}

gboolean
gimp_drawable_is_rgb (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

640
  return GIMP_IMAGE_TYPE_IS_RGB (gimp_drawable_type (drawable));
641 642 643 644 645 646 647
}

gboolean
gimp_drawable_is_gray (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

648
  return GIMP_IMAGE_TYPE_IS_GRAY (gimp_drawable_type (drawable));
649 650 651 652 653 654 655
}

gboolean
gimp_drawable_is_indexed (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

656
  return GIMP_IMAGE_TYPE_IS_INDEXED (gimp_drawable_type (drawable));
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
}

TileManager *
gimp_drawable_data (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);

  return drawable->tiles;
}

TileManager *
gimp_drawable_shadow (GimpDrawable *drawable)
{
  GimpImage *gimage;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);

674
  if (! (gimage = gimp_item_get_image (GIMP_ITEM (drawable))))
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
    return NULL;

  return gimp_image_shadow (gimage, drawable->width, drawable->height, 
			    drawable->bytes);
}

gint
gimp_drawable_bytes (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

  return drawable->bytes;
}

gint
gimp_drawable_bytes_with_alpha (const GimpDrawable *drawable)
{
692 693
  GimpImageType type;

694 695
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

696
  type = GIMP_IMAGE_TYPE_WITH_ALPHA (gimp_drawable_type (drawable));
697

698
  return GIMP_IMAGE_TYPE_BYTES (type);
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
}

gint
gimp_drawable_width (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

  return drawable->width;
}

gint
gimp_drawable_height (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

  return drawable->height;
715 716
}

717
gboolean
718
gimp_drawable_get_visible (const GimpDrawable *drawable)
719
{
720 721
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

722 723 724
  return drawable->visible;
}

725 726
void
gimp_drawable_set_visible (GimpDrawable *drawable,
727 728
                           gboolean      visible,
                           gboolean      push_undo)
729 730 731 732 733
{
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

  if (drawable->visible != visible)
    {
734 735 736 737 738 739 740 741 742
      if (push_undo)
        {
          GimpImage *gimage = gimp_item_get_image (GIMP_ITEM (drawable));

          if (gimage)
            gimp_image_undo_push_drawable_visibility (gimage, NULL, drawable);
        }

      drawable->visible = visible ? TRUE : FALSE;
743

744
      g_signal_emit (drawable, gimp_drawable_signals[VISIBILITY_CHANGED], 0);
Michael Natterer's avatar
Michael Natterer committed
745 746 747 748 749

      gimp_drawable_update (drawable,
			    0, 0,
			    drawable->width,
			    drawable->height);
750 751 752
    }
}

753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
void
gimp_drawable_offsets (const GimpDrawable *drawable,
		       gint               *off_x,
		       gint               *off_y)
{
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

  *off_x = drawable->offset_x;
  *off_y = drawable->offset_y;
}

guchar *
gimp_drawable_cmap (const GimpDrawable *drawable)
{
  GimpImage *gimage;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);

771
  if (! (gimage = gimp_item_get_image (GIMP_ITEM (drawable))))
772 773 774 775 776
    return NULL;

  return gimage->cmap;
}

777 778 779 780
guchar *
gimp_drawable_get_color_at (GimpDrawable *drawable,
			    gint          x,
			    gint          y)
781
{
782
  Tile   *tile;
783 784
  guchar *src;
  guchar *dest;
785

Manish Singh's avatar
Manish Singh committed
786
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
787
  g_return_val_if_fail (gimp_item_get_image (GIMP_ITEM (drawable)) ||
788
			! gimp_drawable_is_indexed (drawable), NULL);
789 790 791 792

  /* do not make this a g_return_if_fail() */
  if ( !(x >= 0 && x < drawable->width && y >= 0 && y < drawable->height))
    return NULL;
Manish Singh's avatar
Manish Singh committed
793

794
  dest = g_new (guchar, 5);
Manish Singh's avatar
Manish Singh committed
795

796 797 798
  tile = tile_manager_get_tile (gimp_drawable_data (drawable), x, y,
				TRUE, FALSE);
  src = tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT);
Manish Singh's avatar
Manish Singh committed
799

800
  gimp_image_get_color (gimp_item_get_image (GIMP_ITEM (drawable)),
801
			gimp_drawable_type (drawable), dest, src);
Manish Singh's avatar
Manish Singh committed
802

803
  if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_drawable_type (drawable)))
804 805 806
    dest[3] = src[gimp_drawable_bytes (drawable) - 1];
  else
    dest[3] = 255;
Manish Singh's avatar
Manish Singh committed
807

Marc Lehmann's avatar
Marc Lehmann committed
808
  if (gimp_drawable_is_indexed (drawable))
809 810 811
    dest[4] = src[0];
  else
    dest[4] = 0;
Manish Singh's avatar
Manish Singh committed
812

813
  tile_release (tile, FALSE);
Manish Singh's avatar
Manish Singh committed
814

815 816
  return dest;
}