bucket_fill.c 16.3 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
 */
#include <stdlib.h>
Michael Natterer's avatar
Michael Natterer committed
19
20
21

#include <gdk/gdkkeysyms.h>

Elliot Lee's avatar
Elliot Lee committed
22
23
#include "appenv.h"
#include "bucket_fill.h"
24
#include "cursorutil.h"
Elliot Lee's avatar
Elliot Lee committed
25
26
27
28
#include "drawable.h"
#include "fuzzy_select.h"
#include "gdisplay.h"
#include "gimage_mask.h"
Michael Natterer's avatar
Michael Natterer committed
29
#include "gimpui.h"
Elliot Lee's avatar
Elliot Lee committed
30
31
#include "interface.h"
#include "paint_funcs.h"
32
#include "paint_options.h"
Elliot Lee's avatar
Elliot Lee committed
33
34
35
36
#include "selection.h"
#include "tools.h"
#include "undo.h"

Sven Neumann's avatar
Sven Neumann committed
37
#include "config.h"
38
39
#include "libgimp/gimpintl.h"

40
41
/*  the bucket fill structures  */

Elliot Lee's avatar
Elliot Lee committed
42
43
44
typedef struct _BucketTool BucketTool;
struct _BucketTool
{
45
46
  gint  target_x;  /*  starting x coord  */
  gint  target_y;  /*  starting y coord  */
Elliot Lee's avatar
Elliot Lee committed
47
48
};

49
50
51
typedef struct _BucketOptions BucketOptions;
struct _BucketOptions
{
52
  PaintOptions    paint_options;
53

54
55
  gdouble         threshold;
  gdouble         threshold_d;
56
  GtkObject      *threshold_w;
57

58
59
  gboolean        sample_merged;
  gboolean        sample_merged_d;
60
  GtkWidget      *sample_merged_w;
61

62
63
  BucketFillMode  fill_mode;
  BucketFillMode  fill_mode_d;
64
  GtkWidget      *fill_mode_w[3];
65
66
};

67
68

/*  the bucket fill tool options  */
69
70
71
static BucketOptions *bucket_options = NULL;


Elliot Lee's avatar
Elliot Lee committed
72
/*  local function prototypes  */
Michael Natterer's avatar
Michael Natterer committed
73

Elliot Lee's avatar
Elliot Lee committed
74
75
76
77
static void  bucket_fill_button_press    (Tool *, GdkEventButton *, gpointer);
static void  bucket_fill_button_release  (Tool *, GdkEventButton *, gpointer);
static void  bucket_fill_cursor_update   (Tool *, GdkEventMotion *, gpointer);

78
79
80
81
static void  bucket_fill_line_color      (guchar *, guchar *, guchar *,
					  gboolean, gint, gint);
static void  bucket_fill_line_pattern    (guchar *, guchar *, TempBuf *,
					  gboolean, gint, gint, gint, gint);
Elliot Lee's avatar
Elliot Lee committed
82
83


84
/*  functions  */
Elliot Lee's avatar
Elliot Lee committed
85

86
static void
87
bucket_options_reset (void)
88
89
90
{
  BucketOptions *options = bucket_options;

91
  paint_options_reset ((PaintOptions *) options);
92
93
94
95
96

  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->sample_merged_w),
				options->sample_merged_d);
  gtk_adjustment_set_value (GTK_ADJUSTMENT (options->threshold_w),
			    options->threshold_d);
97
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->fill_mode_w[options->fill_mode_d]), TRUE);
98
99
}

Elliot Lee's avatar
Elliot Lee committed
100
static BucketOptions *
101
bucket_options_new (void)
Elliot Lee's avatar
Elliot Lee committed
102
103
{
  BucketOptions *options;
104

Elliot Lee's avatar
Elliot Lee committed
105
  GtkWidget *vbox;
106
  GtkWidget *hbox;
Elliot Lee's avatar
Elliot Lee committed
107
  GtkWidget *label;
108
  GtkWidget *scale;
Sven Neumann's avatar
Sven Neumann committed
109
  GtkWidget *frame;
Elliot Lee's avatar
Elliot Lee committed
110

111
  /*  the new bucket fill tool options structure  */
Elliot Lee's avatar
Elliot Lee committed
112
  options = (BucketOptions *) g_malloc (sizeof (BucketOptions));
113
114
115
  paint_options_init ((PaintOptions *) options,
		      BUCKET_FILL,
		      bucket_options_reset);
116
  options->sample_merged = options->sample_merged_d = FALSE;
117
  options->threshold     = options->threshold_d     = 15.0;
118
  options->fill_mode     = options->fill_mode_d     = FG_BUCKET_FILL;
Elliot Lee's avatar
Elliot Lee committed
119
120

  /*  the main vbox  */
121
  vbox = ((ToolOptions *) options)->main_vbox;
122

Elliot Lee's avatar
Elliot Lee committed
123
  /*  the threshold scale  */
124
  hbox = gtk_hbox_new (FALSE, 4);
125
126
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

127
128
  label = gtk_label_new (_("Threshold:"));
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
129
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
Elliot Lee's avatar
Elliot Lee committed
130
131
  gtk_widget_show (label);

132
133
134
  options->threshold_w =
    gtk_adjustment_new (options->threshold_d, 1.0, 255.0, 1.0, 1.0, 0.0);
  scale = gtk_hscale_new (GTK_ADJUSTMENT (options->threshold_w));
135
  gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
136
137
138
  gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
  gtk_signal_connect (GTK_OBJECT (options->threshold_w), "value_changed",
Michael Natterer's avatar
Michael Natterer committed
139
		      GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
Elliot Lee's avatar
Elliot Lee committed
140
		      &options->threshold);
141
  gtk_widget_show (scale);
Elliot Lee's avatar
Elliot Lee committed
142

143
  gtk_widget_show (hbox);
144

145
146
147
148
  /*  the sample merged toggle  */
  options->sample_merged_w =
    gtk_check_button_new_with_label (_("Sample Merged"));
  gtk_signal_connect (GTK_OBJECT (options->sample_merged_w), "toggled",
Michael Natterer's avatar
Michael Natterer committed
149
		      GTK_SIGNAL_FUNC (gimp_toggle_button_update),
150
151
152
		      &options->sample_merged);
  gtk_box_pack_start (GTK_BOX (vbox), options->sample_merged_w, FALSE, FALSE, 0);
  gtk_widget_show (options->sample_merged_w);
Elliot Lee's avatar
Elliot Lee committed
153

Sven Neumann's avatar
Sven Neumann committed
154
  /*  fill type  */
Michael Natterer's avatar
Michael Natterer committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  frame =
    gimp_radio_group_new2 (TRUE, _("Fill Type"),
			   gimp_radio_button_update,
			   &options->fill_mode, (gpointer) options->fill_mode,

			   _("FG Color Fill"),
			   (gpointer) FG_BUCKET_FILL,
			   &options->fill_mode_w[0],
			   _("BG Color Fill"),
			   (gpointer) BG_BUCKET_FILL,
			   &options->fill_mode_w[1],
			   _("Pattern Fill"),
			   (gpointer) PATTERN_BUCKET_FILL,
			   &options->fill_mode_w[2],

			   NULL);

Sven Neumann's avatar
Sven Neumann committed
172
173
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
174
175
176
177

  return options;
}

178
/*  bucket fill action functions  */
Elliot Lee's avatar
Elliot Lee committed
179

180
static void
181
182
183
bucket_fill_button_press (Tool           *tool,
			  GdkEventButton *bevent,
			  gpointer        gdisp_ptr)
Elliot Lee's avatar
Elliot Lee committed
184
185
186
{
  GDisplay * gdisp;
  BucketTool * bucket_tool;
187
  gboolean use_offsets;
Elliot Lee's avatar
Elliot Lee committed
188
189
190
191
192
193
194
195
196
197
198
199

  gdisp = (GDisplay *) gdisp_ptr;
  bucket_tool = (BucketTool *) tool->private;

  use_offsets = (bucket_options->sample_merged) ? FALSE : TRUE;

  gdisplay_untransform_coords (gdisp, bevent->x, bevent->y,
			       &bucket_tool->target_x,
			       &bucket_tool->target_y, FALSE, use_offsets);

  /*  Make the tool active and set the gdisplay which owns it  */
  gdk_pointer_grab (gdisp->canvas->window, FALSE,
200
201
202
		    GDK_POINTER_MOTION_HINT_MASK |
		    GDK_BUTTON1_MOTION_MASK |
		    GDK_BUTTON_RELEASE_MASK,
Elliot Lee's avatar
Elliot Lee committed
203
204
205
206
207
208
209
		    NULL, NULL, bevent->time);

  /*  Make the tool active and set the gdisplay which owns it  */
  tool->gdisp_ptr = gdisp_ptr;
  tool->state = ACTIVE;
}

210
static void
211
212
213
bucket_fill_button_release (Tool           *tool,
			    GdkEventButton *bevent,
			    gpointer        gdisp_ptr)
Elliot Lee's avatar
Elliot Lee committed
214
215
216
217
{
  GDisplay * gdisp;
  BucketTool * bucket_tool;
  Argument *return_vals;
218
  gint nreturn_vals;
Elliot Lee's avatar
Elliot Lee committed
219
220
221
222
223
224
225
226
227
228

  gdisp = (GDisplay *) gdisp_ptr;
  bucket_tool = (BucketTool *) tool->private;

  gdk_pointer_ungrab (bevent->time);
  gdk_flush ();

  /*  if the 3rd button isn't pressed, fill the selected region  */
  if (! (bevent->state & GDK_BUTTON3_MASK))
    {
229
230
231
232
233
234
235
236
237
238
239
240
      return_vals =
	procedural_db_run_proc ("gimp_bucket_fill",
				&nreturn_vals,
				PDB_DRAWABLE, drawable_ID (gimage_active_drawable (gdisp->gimage)),
				PDB_INT32, (gint32) bucket_options->fill_mode,
				PDB_INT32, (gint32) gimp_context_get_paint_mode (NULL),
				PDB_FLOAT, (gdouble) gimp_context_get_opacity (NULL) * 100,
				PDB_FLOAT, (gdouble) bucket_options->threshold,
				PDB_INT32, (gint32) bucket_options->sample_merged,
				PDB_FLOAT, (gdouble) bucket_tool->target_x,
				PDB_FLOAT, (gdouble) bucket_tool->target_y,
				PDB_END);
Elliot Lee's avatar
Elliot Lee committed
241

242
      if (return_vals && return_vals[0].value.pdb_int == PDB_SUCCESS)
Elliot Lee's avatar
Elliot Lee committed
243
244
	gdisplays_flush ();
      else
245
	g_message (_("Bucket Fill operation failed."));
Elliot Lee's avatar
Elliot Lee committed
246
247
248
249
250
251
252
253

      procedural_db_destroy_args (return_vals, nreturn_vals);
    }

  tool->state = INACTIVE;
}

static void
254
255
256
bucket_fill_cursor_update (Tool           *tool,
			   GdkEventMotion *mevent,
			   gpointer        gdisp_ptr)
Elliot Lee's avatar
Elliot Lee committed
257
258
259
260
{
  GDisplay *gdisp;
  Layer *layer;
  GdkCursorType ctype = GDK_TOP_LEFT_ARROW;
261
262
  gint x, y;
  gint off_x, off_y;
Elliot Lee's avatar
Elliot Lee committed
263
264
265
266

  gdisp = (GDisplay *) gdisp_ptr;

  gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, FALSE, FALSE);
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  if ((layer = gimage_get_active_layer (gdisp->gimage))) 
    {
      drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
      if (x >= off_x && y >= off_y &&
	  x < (off_x + drawable_width (GIMP_DRAWABLE(layer))) &&
	  y < (off_y + drawable_height (GIMP_DRAWABLE(layer))))
	{
	  /*  One more test--is there a selected region?
	   *  if so, is cursor inside?
	   */
	  if (gimage_mask_is_empty (gdisp->gimage))
	    ctype = GDK_TCROSS;
	  else if (gimage_mask_value (gdisp->gimage, x, y))
	    ctype = GDK_TCROSS;
	}
    }
Elliot Lee's avatar
Elliot Lee committed
283
284
285
  gdisplay_install_tool_cursor (gdisp, ctype);
}

Sven Neumann's avatar
Sven Neumann committed
286
static void
287
bucket_fill_modifier_key_func (Tool        *tool,
288
289
			       GdkEventKey *kevent,
			       gpointer     gdisp_ptr)
Sven Neumann's avatar
Sven Neumann committed
290
{
291
  switch (kevent->keyval)
Sven Neumann's avatar
Sven Neumann committed
292
    {
293
    case GDK_Alt_L: case GDK_Alt_R:
Sven Neumann's avatar
Sven Neumann committed
294
      break;
295
    case GDK_Shift_L: case GDK_Shift_R:
296
297
      break;
    case GDK_Control_L: case GDK_Control_R:
298
299
300
301
302
303
304
305
306
307
308
      switch (bucket_options->fill_mode)
	{
	case FG_BUCKET_FILL:
	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bucket_options->fill_mode_w[BG_BUCKET_FILL]), TRUE);
	  break;
	case BG_BUCKET_FILL:
	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bucket_options->fill_mode_w[FG_BUCKET_FILL]), TRUE);
	  break;
	default:
	  break;
	}
Sven Neumann's avatar
Sven Neumann committed
309
310
311
      break;
    }
}
Elliot Lee's avatar
Elliot Lee committed
312

313
314
315
316
void
bucket_fill (GimpImage      *gimage,
	     GimpDrawable   *drawable,
	     BucketFillMode  fill_mode,
317
318
319
320
321
322
	     gint            paint_mode,
	     gdouble         opacity,
	     gdouble         threshold,
	     gboolean        sample_merged,
	     gdouble         x,
	     gdouble         y)
Elliot Lee's avatar
Elliot Lee committed
323
324
{
  TileManager *buf_tiles;
325
326
327
328
329
330
331
  PixelRegion  bufPR, maskPR;
  Channel     *mask = NULL;
  gint       bytes;
  gboolean   has_alpha;
  gint       x1, y1, x2, y2;
  guchar     col [MAX_CHANNELS];
  guchar    *d1, *d2;
332
  GPattern  *pattern;
333
334
  TempBuf   *pat_buf;
  gboolean   new_buf = FALSE;
Elliot Lee's avatar
Elliot Lee committed
335
336
337

  pat_buf = NULL;

338
  if (fill_mode == FG_BUCKET_FILL)
339
    gimage_get_foreground (gimage, drawable, col);
340
  else if (fill_mode == BG_BUCKET_FILL)
341
    gimage_get_background (gimage, drawable, col);
342
  else if (fill_mode == PATTERN_BUCKET_FILL)
Elliot Lee's avatar
Elliot Lee committed
343
    {
344
      pattern = gimp_context_get_pattern (NULL);
Elliot Lee's avatar
Elliot Lee committed
345
346
347

      if (!pattern)
	{
348
	  g_message (_("No available patterns for this operation."));
Elliot Lee's avatar
Elliot Lee committed
349
350
351
352
353
354
	  return;
	}

      /*  If the pattern doesn't match the image in terms of color type,
       *  transform it.  (ie  pattern is RGB, image is indexed)
       */
355
356
      if (((pattern->mask->bytes == 3) && !drawable_color (drawable)) ||
	  ((pattern->mask->bytes == 1) && !drawable_gray (drawable)))
Elliot Lee's avatar
Elliot Lee committed
357
358
359
	{
	  int size;

360
	  if ((pattern->mask->bytes == 1) && drawable_color (drawable))
Elliot Lee's avatar
Elliot Lee committed
361
362
363
364
365
366
367
368
369
370
	    pat_buf = temp_buf_new (pattern->mask->width, pattern->mask->height, 3, 0, 0, NULL);
	  else
	    pat_buf = temp_buf_new (pattern->mask->width, pattern->mask->height, 1, 0, 0, NULL);

	  d1 = temp_buf_data (pattern->mask);
	  d2 = temp_buf_data (pat_buf);

	  size = pattern->mask->width * pattern->mask->height;
	  while (size--)
	    {
371
	      gimage_transform_color (gimage, drawable, d1, d2,
Elliot Lee's avatar
Elliot Lee committed
372
373
374
375
376
				      (pattern->mask->bytes == 3) ? RGB : GRAY);
	      d1 += pattern->mask->bytes;
	      d2 += pat_buf->bytes;
	    }

377
	  new_buf = TRUE;
Elliot Lee's avatar
Elliot Lee committed
378
379
380
381
382
	}
      else
	pat_buf = pattern->mask;
    }

383
  gimp_add_busy_cursors ();
384

385
386
  bytes = drawable_bytes (drawable);
  has_alpha = drawable_has_alpha (drawable);
Elliot Lee's avatar
Elliot Lee committed
387
388
389
390

  /*  If there is no selection mask, the do a seed bucket
   *  fill...To do this, calculate a new contiguous region
   */
391
  if (! drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2))
Elliot Lee's avatar
Elliot Lee committed
392
    {
393
      mask = find_contiguous_region (gimage, drawable, TRUE, (int) threshold,
Elliot Lee's avatar
Elliot Lee committed
394
395
396
397
398
399
400
401
402
403
				     (int) x, (int) y, sample_merged);

      channel_bounds (mask, &x1, &y1, &x2, &y2);

      /*  make sure we handle the mask correctly if it was sample-merged  */
      if (sample_merged)
	{
	  int off_x, off_y;

	  /*  Limit the channel bounds to the drawable's extents  */
404
	  drawable_offsets (drawable, &off_x, &off_y);
405
406
407
408
	  x1 = CLAMP (x1, off_x, (off_x + drawable_width (drawable)));
	  y1 = CLAMP (y1, off_y, (off_y + drawable_height (drawable)));
	  x2 = CLAMP (x2, off_x, (off_x + drawable_width (drawable)));
	  y2 = CLAMP (y2, off_y, (off_y + drawable_height (drawable)));
Elliot Lee's avatar
Elliot Lee committed
409

410
	  pixel_region_init (&maskPR, drawable_data (GIMP_DRAWABLE (mask)), 
411
			     x1, y1, (x2 - x1), (y2 - y1), TRUE);
Elliot Lee's avatar
Elliot Lee committed
412
413
414
415
416
417
418
419

	  /*  translate mask bounds to drawable coords  */
	  x1 -= off_x;
	  y1 -= off_y;
	  x2 -= off_x;
	  y2 -= off_y;
	}
      else
420
	pixel_region_init (&maskPR, drawable_data (GIMP_DRAWABLE (mask)), 
421
			   x1, y1, (x2 - x1), (y2 - y1), TRUE);
Elliot Lee's avatar
Elliot Lee committed
422
423
424
425
426
427
428
429

      /*  if the gimage doesn't have an alpha channel,
       *  make sure that the temp buf does.  We need the
       *  alpha channel to fill with the region calculated above
       */
      if (! has_alpha)
	{
	  bytes ++;
430
	  has_alpha = TRUE;
Elliot Lee's avatar
Elliot Lee committed
431
432
433
434
435
436
437
438
439
440
441
442
	}
    }

  buf_tiles = tile_manager_new ((x2 - x1), (y2 - y1), bytes);
  pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE);

  if (mask)
    bucket_fill_region (fill_mode, &bufPR, &maskPR, col, pat_buf, x1, y1, has_alpha);
  else
    bucket_fill_region (fill_mode, &bufPR, NULL, col, pat_buf, x1, y1, has_alpha);

  pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), FALSE);
443
  gimage_apply_image (gimage, drawable, &bufPR, TRUE,
Elliot Lee's avatar
Elliot Lee committed
444
445
446
		      (opacity * 255) / 100, paint_mode, NULL, x1, y1);

  /*  update the image  */
447
  drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1));
Elliot Lee's avatar
Elliot Lee committed
448
449
450
451
452
453
454
455
456
457

  /*  free the temporary buffer  */
  tile_manager_destroy (buf_tiles);

  /*  free the mask  */
  if (mask)
    channel_delete (mask);

  if (new_buf)
    temp_buf_free (pat_buf);
458

459
  gimp_remove_busy_cursors (NULL);
Elliot Lee's avatar
Elliot Lee committed
460
461
462
}

static void
463
464
465
466
467
468
bucket_fill_line_color (guchar   *buf,
			guchar   *mask,
			guchar   *col,
			gboolean  has_alpha,
			gint      bytes,
			gint      width)
Elliot Lee's avatar
Elliot Lee committed
469
{
470
  gint alpha, b;
Elliot Lee's avatar
Elliot Lee committed
471
472
473
474
475
476
477
478
479
480
481
482

  alpha = (has_alpha) ? bytes - 1 : bytes;
  while (width--)
    {
      for (b = 0; b < alpha; b++)
	buf[b] = col[b];

      if (has_alpha)
	{
	  if (mask)
	    buf[alpha] = *mask++;
	  else
Manish Singh's avatar
Manish Singh committed
483
	    buf[alpha] = OPAQUE_OPACITY;
Elliot Lee's avatar
Elliot Lee committed
484
485
486
487
488
489
490
	}

      buf += bytes;
    }
}

static void
491
492
493
494
495
496
497
498
bucket_fill_line_pattern (guchar   *buf,
			  guchar   *mask,
			  TempBuf  *pattern,
			  gboolean  has_alpha,
			  gint      bytes,
			  gint      x,
			  gint      y,
			  gint      width)
Elliot Lee's avatar
Elliot Lee committed
499
{
500
501
502
  guchar *pat, *p;
  gint alpha, b;
  gint i;
Elliot Lee's avatar
Elliot Lee committed
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520

  /*  Get a pointer to the appropriate scanline of the pattern buffer  */
  pat = temp_buf_data (pattern) +
    (y % pattern->height) * pattern->width * pattern->bytes;

  alpha = (has_alpha) ? bytes - 1 : bytes;
  for (i = 0; i < width; i++)
    {
      p = pat + ((i + x) % pattern->width) * pattern->bytes;

      for (b = 0; b < alpha; b++)
	buf[b] = p[b];

      if (has_alpha)
	{
	  if (mask)
	    buf[alpha] = *mask++;
	  else
Manish Singh's avatar
Manish Singh committed
521
	    buf[alpha] = OPAQUE_OPACITY;
Elliot Lee's avatar
Elliot Lee committed
522
523
524
525
526
527
	}

      buf += bytes;
    }
}

528
void
529
530
531
bucket_fill_region (BucketFillMode  fill_mode,
		    PixelRegion    *bufPR,
		    PixelRegion    *maskPR,
532
		    guchar         *col,
533
		    TempBuf        *pattern,
534
535
536
		    gint            off_x,
		    gint            off_y,
		    gboolean        has_alpha)
Elliot Lee's avatar
Elliot Lee committed
537
{
538
539
  guchar *s, *m;
  gint y;
Elliot Lee's avatar
Elliot Lee committed
540
541
  void *pr;

542
543
544
  for (pr = pixel_regions_register (2, bufPR, maskPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
Elliot Lee's avatar
Elliot Lee committed
545
546
547
548
549
550
551
552
553
554
555
    {
      s = bufPR->data;
      if (maskPR)
	m = maskPR->data;
      else
	m = NULL;

      for (y = 0; y < bufPR->h; y++)
	{
	  switch (fill_mode)
	    {
556
557
	    case FG_BUCKET_FILL:
	    case BG_BUCKET_FILL:
Elliot Lee's avatar
Elliot Lee committed
558
559
	      bucket_fill_line_color (s, m, col, has_alpha, bufPR->bytes, bufPR->w);
	      break;
560
	    case PATTERN_BUCKET_FILL:
Elliot Lee's avatar
Elliot Lee committed
561
562
563
564
565
566
567
568
569
570
571
572
	      bucket_fill_line_pattern (s, m, pattern, has_alpha, bufPR->bytes,
					off_x + bufPR->x, off_y + y + bufPR->y, bufPR->w);
	      break;
	    }
	  s += bufPR->rowstride;

	  if (maskPR)
	    m += maskPR->rowstride;
	}
    }
}

573
574
575
/**********************************/
/*  Global bucket fill functions  */
/**********************************/
Elliot Lee's avatar
Elliot Lee committed
576
577

Tool *
Manish Singh's avatar
Manish Singh committed
578
tools_new_bucket_fill (void)
Elliot Lee's avatar
Elliot Lee committed
579
580
581
582
{
  Tool * tool;
  BucketTool * private;

583
  /*  The tool options  */
Elliot Lee's avatar
Elliot Lee committed
584
  if (! bucket_options)
585
586
587
    {
      bucket_options = bucket_options_new ();
      tools_register (BUCKET_FILL, (ToolOptions *) bucket_options);
588
589
590

      /*  press all default buttons  */
      bucket_options_reset ();
591
    }
Elliot Lee's avatar
Elliot Lee committed
592

593
594
  tool = tools_new_tool (BUCKET_FILL);
  private = g_new (BucketTool, 1);
Elliot Lee's avatar
Elliot Lee committed
595

596
  tool->scroll_lock = TRUE;  /*  Disallow scrolling  */
597

598
  tool->private = (void *) private;
599

600
  tool->button_press_func   = bucket_fill_button_press;
Elliot Lee's avatar
Elliot Lee committed
601
  tool->button_release_func = bucket_fill_button_release;
602
603
  tool->modifier_key_func   = bucket_fill_modifier_key_func;
  tool->cursor_update_func  = bucket_fill_cursor_update;
Elliot Lee's avatar
Elliot Lee committed
604
605
606
607
608

  return tool;
}

void
609
tools_free_bucket_fill (Tool *tool)
Elliot Lee's avatar
Elliot Lee committed
610
611
612
613
614
615
616
{
  BucketTool * bucket_tool;

  bucket_tool = (BucketTool *) tool->private;

  g_free (bucket_tool);
}