exchange.c 20.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
/*
 * This is a plug-in for the GIMP.
 *
 * 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
21
22
23
24
25
26
 *
 *
 */

/*
 * Exchange one color with the other (settable threshold to convert from
 * one color-shade to another...might do wonders on certain images, or be
 * totally useless on others).
 * 
 * Author: robert@experimental.net
27
28
 */

29
30
#include "config.h"

Elliot Lee's avatar
Elliot Lee committed
31
32
#include <stdio.h>
#include <stdlib.h>
33
34
35

#include <gtk/gtk.h>

36
37
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
38

39
#include "libgimp/stdplugins-intl.h"
Elliot Lee's avatar
Elliot Lee committed
40

41

42
43
#define	SCALE_WIDTH  128
#define PREVIEW_SIZE 128
44

Elliot Lee's avatar
Elliot Lee committed
45
46
47
/* datastructure to store parameters in */
typedef struct
{
48
49
50
51
52
53
  guchar  fromred, fromgreen, fromblue;
  guchar  tored, togreen, toblue;
  guchar  red_threshold, green_threshold, blue_threshold;
  gint32  image;
  gint32  drawable;
} myParams;
Elliot Lee's avatar
Elliot Lee committed
54
55

/* lets prototype */
56
57
58
static void	query (void);
static void	run   (gchar   *name,
		       gint     nparams,
Sven Neumann's avatar
Sven Neumann committed
59
		       GimpParam  *param,
60
		       gint    *nreturn_vals,
Sven Neumann's avatar
Sven Neumann committed
61
		       GimpParam **return_vals);
62

Sven Neumann's avatar
Sven Neumann committed
63
64
static void	exchange              (void);
static void	real_exchange         (gint, gint, gint, gint, gboolean);
65
66
67
68
69
70

static int	doDialog              (void);
static void	update_preview        (void);
static void	ok_callback           (GtkWidget *, gpointer);
static void	color_button_callback (GtkWidget *, gpointer);
static void	scale_callback        (GtkAdjustment *, gpointer);
Elliot Lee's avatar
Elliot Lee committed
71
72

/* some global variables */
Sven Neumann's avatar
Sven Neumann committed
73
static GimpDrawable *drw;
74
75
76
static gboolean   has_alpha;
static myParams   xargs = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static gint       running = 0;
Sven Neumann's avatar
Sven Neumann committed
77
static GimpPixelRgn  origregion;
78
79
80
81
82
static GtkWidget *preview;
static GtkWidget *from_colorbutton;
static GtkWidget *to_colorbutton;
static gint       sel_x1, sel_y1, sel_x2, sel_y2;
static gint       prev_width, prev_height, sel_width, sel_height;
Sven Neumann's avatar
Sven Neumann committed
83
static gboolean   lock_threshold = FALSE;
Elliot Lee's avatar
Elliot Lee committed
84
85

/* lets declare what we want to do */
Sven Neumann's avatar
Sven Neumann committed
86
GimpPlugInInfo PLUG_IN_INFO =
Elliot Lee's avatar
Elliot Lee committed
87
{
88
89
90
91
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
Elliot Lee's avatar
Elliot Lee committed
92
93
94
};

/* run program */
95
MAIN ()
Elliot Lee's avatar
Elliot Lee committed
96
97

/* tell GIMP who we are */
98
99
static void
query (void)
Elliot Lee's avatar
Elliot Lee committed
100
{
Sven Neumann's avatar
Sven Neumann committed
101
  static GimpParamDef args[] =
102
  {
Sven Neumann's avatar
Sven Neumann committed
103
104
105
106
107
108
109
110
111
112
113
114
    { GIMP_PDB_INT32, "run_mode", "Interactive" },
    { GIMP_PDB_IMAGE, "image", "Input image" },
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
    { GIMP_PDB_INT8, "fromred", "Red value (from)" },
    { GIMP_PDB_INT8, "fromgreen", "Green value (from)" },
    { GIMP_PDB_INT8, "fromblue", "Blue value (from)" },
    { GIMP_PDB_INT8, "tored", "Red value (to)" },
    { GIMP_PDB_INT8, "togreen", "Green value (to)" },
    { GIMP_PDB_INT8, "toblue", "Blue value (to)" },
    { GIMP_PDB_INT8, "red_threshold", "Red threshold" },
    { GIMP_PDB_INT8, "green_threshold", "Green threshold" },
    { GIMP_PDB_INT8, "blue_threshold", "Blue threshold" }
115
  };
116
  static gint nargs = sizeof (args) / sizeof (args[0]);
117
118

  gimp_install_procedure ("plug_in_exchange",
Marc Lehmann's avatar
Marc Lehmann committed
119
			  "Color Exchange",
Sven Neumann's avatar
Sven Neumann committed
120
121
			  "Exchange one color with another, optionally setting a threshold "
			  "to convert from one shade to another",
122
123
124
125
126
			  "robert@experimental.net",
			  "robert@experimental.net",
			  "June 17th, 1997",
			  N_("<Image>/Filters/Colors/Map/Color Exchange..."),
			  "RGB*",
Sven Neumann's avatar
Sven Neumann committed
127
			  GIMP_PLUGIN,
128
129
			  nargs, 0,
			  args, NULL);
Elliot Lee's avatar
Elliot Lee committed
130
131
132
}

/* main function */
133
134
135
static void
run (gchar   *name,
     gint     nparams,
Sven Neumann's avatar
Sven Neumann committed
136
     GimpParam  *param,
137
     gint    *nreturn_vals,
Sven Neumann's avatar
Sven Neumann committed
138
     GimpParam **return_vals)
Elliot Lee's avatar
Elliot Lee committed
139
{
Sven Neumann's avatar
Sven Neumann committed
140
141
142
  static GimpParam	values[1];
  GimpRunModeType	runmode;
  GimpPDBStatusType 	status = GIMP_PDB_SUCCESS;
Elliot Lee's avatar
Elliot Lee committed
143

144
145
  *nreturn_vals = 1;
  *return_vals = values;
Elliot Lee's avatar
Elliot Lee committed
146

Sven Neumann's avatar
Sven Neumann committed
147
  values[0].type = GIMP_PDB_STATUS;
148
  values[0].data.d_status = status;
Elliot Lee's avatar
Elliot Lee committed
149

150
151
152
153
  runmode        = param[0].data.d_int32;
  xargs.image    = param[1].data.d_image;
  xargs.drawable = param[2].data.d_drawable;
  drw = gimp_drawable_get (xargs.drawable);
154

Marc Lehmann's avatar
Marc Lehmann committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  /* initialize misc. things */
  gimp_drawable_mask_bounds (drw->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  sel_width = sel_x2 - sel_x1;
  sel_height = sel_y2 - sel_y1;
  if (sel_width > PREVIEW_SIZE)
    prev_width = PREVIEW_SIZE;
  else
    prev_width = sel_width;
  if (sel_height > PREVIEW_SIZE)
    prev_height = PREVIEW_SIZE;
  else
    prev_height = sel_height;
  has_alpha = gimp_drawable_has_alpha (drw->id);

169
170
  switch (runmode)
    {
Sven Neumann's avatar
Sven Neumann committed
171
    case GIMP_RUN_INTERACTIVE:
172
173
174
175
176
177
178
179
180
181
182
      INIT_I18N_UI();
      /* retrieve stored arguments (if any) */
      gimp_get_data ("plug_in_exchange", &xargs);
      /* initialize using foreground color */
      gimp_palette_get_foreground (&xargs.fromred,
				   &xargs.fromgreen,
				   &xargs.fromblue);
      if (!doDialog ())
	return;
      break;

Sven Neumann's avatar
Sven Neumann committed
183
    case GIMP_RUN_WITH_LAST_VALS:
184
185
186
187
188
189
190
191
192
193
194
195
      INIT_I18N();
      gimp_get_data ("plug_in_exchange", &xargs);
      /* 
       * instead of recalling the last-set values,
       * run with the current foreground as 'from'
       * color, making ALT-F somewhat more useful.
       */
      gimp_palette_get_foreground (&xargs.fromred,
				   &xargs.fromgreen,
				   &xargs.fromblue);
      break;

Sven Neumann's avatar
Sven Neumann committed
196
    case GIMP_RUN_NONINTERACTIVE:
197
      INIT_I18N();
Marc Lehmann's avatar
Marc Lehmann committed
198
      if (nparams != 12)
199
	{
Sven Neumann's avatar
Sven Neumann committed
200
	  status = GIMP_PDB_EXECUTION_ERROR;
201
202
	}
      else
Elliot Lee's avatar
Elliot Lee committed
203
	{
204
205
206
207
208
209
210
211
212
	  xargs.fromred         = param[3].data.d_int8;
	  xargs.fromgreen       = param[4].data.d_int8;
	  xargs.fromblue        = param[5].data.d_int8;
	  xargs.tored           = param[6].data.d_int8;
	  xargs.togreen         = param[7].data.d_int8;
	  xargs.toblue          = param[8].data.d_int8;
	  xargs.red_threshold   = param[9].data.d_int32;
	  xargs.green_threshold = param[10].data.d_int32;
	  xargs.blue_threshold  = param[11].data.d_int32;
Elliot Lee's avatar
Elliot Lee committed
213
	}
214
215
216
217
218
      break;
    default:	
      break;
    }

Sven Neumann's avatar
Sven Neumann committed
219
  if (status == GIMP_PDB_SUCCESS)
220
221
    {
      if (gimp_drawable_is_rgb (drw->id))
Elliot Lee's avatar
Elliot Lee committed
222
	{
223
224
225
226
227
228
	  gimp_progress_init (_("Color Exchange..."));
	  gimp_tile_cache_ntiles (2 * (drw->width / gimp_tile_width () + 1));
	  exchange ();	
	  gimp_drawable_detach( drw);

	  /* store our settings */
Sven Neumann's avatar
Sven Neumann committed
229
	  if (runmode == GIMP_RUN_INTERACTIVE)
230
231
232
	    gimp_set_data ("plug_in_exchange", &xargs, sizeof (myParams));

	  /* and flush */
Sven Neumann's avatar
Sven Neumann committed
233
	  if (runmode != GIMP_RUN_NONINTERACTIVE)
234
	    gimp_displays_flush ();
Elliot Lee's avatar
Elliot Lee committed
235
	}
236
      else
Sven Neumann's avatar
Sven Neumann committed
237
	status = GIMP_PDB_EXECUTION_ERROR;
238
239
    }
  values[0].data.d_status = status;
Elliot Lee's avatar
Elliot Lee committed
240
241
242
}

/* do the exchanging */
243
244
static void
exchange (void)
Elliot Lee's avatar
Elliot Lee committed
245
{
246
247
  /* do the real exchange */
  real_exchange (-1, -1, -1, -1, FALSE);
Elliot Lee's avatar
Elliot Lee committed
248
249
250
}

/* show our dialog */
251
static gint
252
doDialog (void)
Elliot Lee's avatar
Elliot Lee committed
253
{
254
255
256
  GtkWidget *dialog;
  GtkWidget *mainbox;
  GtkWidget *frame;
257
258
  GtkWidget *abox;
  GtkWidget *pframe;
259
260
261
  GtkWidget *table;
  GtkWidget *colorbutton;
  GtkObject *adj;
Sven Neumann's avatar
Sven Neumann committed
262
263
264
  GtkObject *red_threshold   = NULL;
  GtkObject *green_threshold = NULL;
  GtkObject *blue_threshold  = NULL;
265
266
267
  gint  framenumber;

  gimp_ui_init ("exchange", TRUE);
268
269
270
271
272
273
274

  /* load pixelregion */
  gimp_pixel_rgn_init (&origregion, drw,
		       0, 0, PREVIEW_SIZE, PREVIEW_SIZE, FALSE, FALSE);

  /* set up the dialog */
  dialog = gimp_dialog_new (_("Color Exchange"), "exchange",
275
			    gimp_standard_help_func, "filters/exchange.html",
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
			    GTK_WIN_POS_MOUSE,
			    FALSE, TRUE, FALSE,

			    _("OK"), ok_callback,
			    NULL, NULL, NULL, TRUE, FALSE,
			    _("Cancel"), gtk_widget_destroy,
			    NULL, 1, NULL, FALSE, TRUE,

			    NULL);

  gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
		      GTK_SIGNAL_FUNC (gtk_main_quit),
		      NULL);

  /* do some boxes here */
291
292
  mainbox = gtk_vbox_new (FALSE, 4);
  gtk_container_set_border_width (GTK_CONTAINER (mainbox), 6);
293
294
295
296
297
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), mainbox,
		      TRUE, TRUE, 0);

  frame = gtk_frame_new (_("Preview"));
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
298
  gtk_box_pack_start (GTK_BOX (mainbox), frame, FALSE, FALSE, 0);
299
300
  gtk_widget_show (frame);

301
302
303
304
305
306
307
308
309
310
  abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  gtk_container_add (GTK_CONTAINER (frame), abox);
  gtk_widget_show (abox);

  pframe = gtk_frame_new (NULL);
  gtk_frame_set_shadow_type (GTK_FRAME (pframe), GTK_SHADOW_IN);
  gtk_container_set_border_width (GTK_CONTAINER (pframe), 4);
  gtk_container_add (GTK_CONTAINER (abox), pframe);
  gtk_widget_show (pframe);

311
312
  preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  gtk_preview_size (GTK_PREVIEW (preview), prev_width, prev_height);
313
  gtk_container_add (GTK_CONTAINER (pframe), preview);
314
315
316
317
318
319
  update_preview ();
  gtk_widget_show (preview); 

  /* and our scales */
  for (framenumber = 0; framenumber < 2; framenumber++)
    {
320
321
322
      guint id;

      frame = gtk_frame_new (framenumber ? _("To Color") : _("From Color"));
323
      gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
324
      gtk_box_pack_start (GTK_BOX (mainbox), frame, FALSE, FALSE, 0);
325
      gtk_widget_show (frame);
326
327
328
329
330

      table = gtk_table_new (framenumber ? 3 : 9, 4, FALSE);
      gtk_table_set_col_spacings (GTK_TABLE (table), 4);
      gtk_table_set_row_spacings (GTK_TABLE (table), 2);
      gtk_container_set_border_width (GTK_CONTAINER (table), 4);
331
      gtk_container_add (GTK_CONTAINER (frame), table);
332
333
334
335
336
337
338
339
340
      gtk_widget_show (table);

      colorbutton = gimp_color_button_new (framenumber ?
					   _("Color Exchange: To Color") :
					   _("Color Exchange: From Color"),
					   SCALE_WIDTH / 2, 16,
					   framenumber ?
					   &xargs.tored : &xargs.fromred,
					   3);
341
      gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
342
				 NULL, 0.0, 0.0,
343
				 colorbutton, 1, TRUE);
344
345
346
347
348
349
350
351
352
353
354
355
      gtk_signal_connect (GTK_OBJECT (colorbutton), "color_changed",
			  GTK_SIGNAL_FUNC (color_button_callback),
			  NULL);

      if (framenumber)
	to_colorbutton = colorbutton;
      else
	from_colorbutton = colorbutton;

      adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
				  _("Red:"), SCALE_WIDTH, 0,
				  framenumber ? xargs.tored : xargs.fromred,
356
357
358
				  0, 255, 1, 8, 0,
				  TRUE, 0, 0,
				  NULL, NULL);
359
360
361
362
363
364
365
      gtk_object_set_user_data (GTK_OBJECT (adj), colorbutton);
      gtk_object_set_data (GTK_OBJECT (colorbutton), "red", adj);
      id = gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
			       GTK_SIGNAL_FUNC (scale_callback),
			       framenumber ? &xargs.tored : &xargs.fromred);
      gtk_object_set_data (GTK_OBJECT (adj), "handler", (gpointer) id);

366
      if (! framenumber)
367
	{
Sven Neumann's avatar
Sven Neumann committed
368
369
370
371
372
373
374
375
376
377
378
	  red_threshold = 
	    adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
					_("Red Threshold:"), SCALE_WIDTH, 0,
					xargs.red_threshold,
					0, 255, 1, 8, 0,
					TRUE, 0, 0,
					NULL, NULL);
	  id = gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
				   GTK_SIGNAL_FUNC (scale_callback),
				   &xargs.red_threshold);
	  gtk_object_set_data (GTK_OBJECT (adj), "handler", (gpointer) id);
379
380
381
382
383
	}

      adj = gimp_scale_entry_new (GTK_TABLE (table), 0, framenumber ? 2 : 3,
				  _("Green:"), SCALE_WIDTH, 0,
				  framenumber ? xargs.togreen : xargs.fromgreen,
384
385
386
				  0, 255, 1, 8, 0,
				  TRUE, 0, 0,
				  NULL, NULL);
387
388
389
390
391
392
393
      gtk_object_set_user_data (GTK_OBJECT (adj), colorbutton);
      gtk_object_set_data (GTK_OBJECT (colorbutton), "green", adj);
      id = gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
			       GTK_SIGNAL_FUNC (scale_callback),
			       framenumber ? &xargs.togreen : &xargs.fromgreen);
      gtk_object_set_data (GTK_OBJECT (adj), "handler", (gpointer) id);

394
      if (! framenumber)
395
	{
Sven Neumann's avatar
Sven Neumann committed
396
397
398
399
400
401
402
403
404
405
406
407
	  green_threshold =
	    adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 4,
					_("Green Threshold:"), SCALE_WIDTH, 0,
					xargs.green_threshold,
					0, 255, 1, 8, 0,
					TRUE, 0, 0,
					NULL, NULL);
	  gtk_object_set_user_data (GTK_OBJECT (adj), red_threshold);
	  id = gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
				   GTK_SIGNAL_FUNC (scale_callback),
				   &xargs.green_threshold);
	  gtk_object_set_data (GTK_OBJECT (adj), "handler", (gpointer) id);
408
409
410
411
412
	}

      adj = gimp_scale_entry_new (GTK_TABLE (table), 0, framenumber ? 3 : 5,
				  _("Blue:"), SCALE_WIDTH, 0,
				  framenumber ? xargs.toblue : xargs.fromblue,
413
414
415
				  0, 255, 1, 8, 0,
				  TRUE, 0, 0,
				  NULL, NULL);
416
417
418
419
420
421
422
      gtk_object_set_user_data (GTK_OBJECT (adj), colorbutton);
      gtk_object_set_data (GTK_OBJECT (colorbutton), "blue", adj);
      id = gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
			       GTK_SIGNAL_FUNC (scale_callback),
			       framenumber ? &xargs.toblue : &xargs.fromblue);
      gtk_object_set_data (GTK_OBJECT (adj), "handler", (gpointer) id);

423
      if (! framenumber)
424
	{
Sven Neumann's avatar
Sven Neumann committed
425
426
427
428
429
430
431
432
433
434
435
436
437
438
	  blue_threshold = 
	    adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 6,
					_("Blue Threshold:"), SCALE_WIDTH, 0,
					xargs.blue_threshold,
					0, 255, 1, 8, 0,
					TRUE, 0, 0,
					NULL, NULL);
	  gtk_object_set_user_data (GTK_OBJECT (adj), green_threshold);
	  id = gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
				   GTK_SIGNAL_FUNC (scale_callback),
				   &xargs.blue_threshold);
	  gtk_object_set_data (GTK_OBJECT (adj), "handler", (gpointer) id);

	  gtk_object_set_user_data (GTK_OBJECT (red_threshold), blue_threshold);
439
440
	}

441
      if (! framenumber)
Elliot Lee's avatar
Elliot Lee committed
442
	{
443
444
	  GtkWidget *button;

445
446
	  button = gtk_check_button_new_with_label (_("Lock Thresholds"));
	  gtk_table_attach (GTK_TABLE (table), button, 1, 3, 7, 8,
447
			    GTK_FILL, 0, 0, 0);
Sven Neumann's avatar
Sven Neumann committed
448
	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), lock_threshold);
449
	  gtk_signal_connect (GTK_OBJECT (button), "clicked",
Sven Neumann's avatar
Sven Neumann committed
450
451
			      GTK_SIGNAL_FUNC (gimp_toggle_button_update),
			      &lock_threshold);
452
	  gtk_widget_show (button);
Elliot Lee's avatar
Elliot Lee committed
453
	}
454
455
456
457
458
    }

  /* show everything */
  gtk_widget_show (mainbox);
  gtk_widget_show (dialog);
Elliot Lee's avatar
Elliot Lee committed
459

460
461
  gtk_main ();
  gdk_flush ();
Elliot Lee's avatar
Elliot Lee committed
462

463
  return running;
Elliot Lee's avatar
Elliot Lee committed
464
465
}

466
467
468
static void
ok_callback (GtkWidget *widget,
	     gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
469
{
470
  running = TRUE;
Elliot Lee's avatar
Elliot Lee committed
471

472
  gtk_widget_destroy (GTK_WIDGET (data));
Elliot Lee's avatar
Elliot Lee committed
473
474
}

475
476
477
static void
color_button_callback (GtkWidget *widget,
		       gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
478
{
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  GtkObject *red_adj;
  GtkObject *green_adj;
  GtkObject *blue_adj;

  guint red_handler;
  guint green_handler;
  guint blue_handler;

  red_adj   = (GtkObject *) gtk_object_get_data (GTK_OBJECT (widget), "red");
  green_adj = (GtkObject *) gtk_object_get_data (GTK_OBJECT (widget), "green");
  blue_adj  = (GtkObject *) gtk_object_get_data (GTK_OBJECT (widget), "blue");

  red_handler   = (guint) gtk_object_get_data (GTK_OBJECT (red_adj),
					       "handler");
  green_handler = (guint) gtk_object_get_data (GTK_OBJECT (green_adj),
					       "handler");
  blue_handler  = (guint) gtk_object_get_data (GTK_OBJECT (blue_adj),
					       "handler");

  gtk_signal_handler_block (GTK_OBJECT (red_adj),   red_handler);
  gtk_signal_handler_block (GTK_OBJECT (green_adj), green_handler);
  gtk_signal_handler_block (GTK_OBJECT (blue_adj),  blue_handler);

  if (widget == from_colorbutton)
    {
      gtk_adjustment_set_value (GTK_ADJUSTMENT (red_adj),   xargs.fromred);
      gtk_adjustment_set_value (GTK_ADJUSTMENT (green_adj), xargs.fromgreen);
      gtk_adjustment_set_value (GTK_ADJUSTMENT (blue_adj),  xargs.fromblue);
    }
  else
    {
      gtk_adjustment_set_value (GTK_ADJUSTMENT (red_adj),   xargs.tored);
      gtk_adjustment_set_value (GTK_ADJUSTMENT (green_adj), xargs.togreen);
      gtk_adjustment_set_value (GTK_ADJUSTMENT (blue_adj),  xargs.toblue);
    }
Elliot Lee's avatar
Elliot Lee committed
514

515
516
517
518
519
  gtk_signal_handler_unblock (GTK_OBJECT (red_adj),   red_handler);
  gtk_signal_handler_unblock (GTK_OBJECT (green_adj), green_handler);
  gtk_signal_handler_unblock (GTK_OBJECT (blue_adj),  blue_handler);

  update_preview ();
520
521
}

522
523
524
static void
scale_callback (GtkAdjustment *adj,
		gpointer       data)
525
{
Sven Neumann's avatar
Sven Neumann committed
526
  GtkObject *object;
527
528
529
  guchar    *val = data;
  guint      handler;
  gint       i;
530
531
532

  *val = (guchar) adj->value;

Sven Neumann's avatar
Sven Neumann committed
533
  object = gtk_object_get_user_data (GTK_OBJECT (adj));
534

Sven Neumann's avatar
Sven Neumann committed
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  if (GIMP_IS_COLOR_BUTTON (object))
    {
      gimp_color_button_update (GIMP_COLOR_BUTTON (object));
    }
  else if (GTK_IS_ADJUSTMENT (object) && lock_threshold == TRUE)
    {
      for (i = 0; i < 2; i++)
	{
	  handler = (guint) gtk_object_get_data (GTK_OBJECT (object), "handler");
	  gtk_signal_handler_block (GTK_OBJECT (object), handler);
	  gtk_adjustment_set_value (GTK_ADJUSTMENT (object), adj->value);
	  gtk_signal_handler_unblock (GTK_OBJECT (object), handler);

	  object = gtk_object_get_user_data (GTK_OBJECT (object));
	}
      xargs.red_threshold = xargs.green_threshold = xargs.blue_threshold = *val;
    }
552
553

  update_preview ();
554
555
}

556
557
static void
update_preview (void)
558
{
559
560
561
  real_exchange (sel_x1, sel_y1,
		 sel_x1 + prev_width, sel_y1 + prev_height,
		 TRUE);
562

563
564
  gtk_widget_draw (preview, NULL);
  gdk_flush ();
Elliot Lee's avatar
Elliot Lee committed
565
}
566

567
static void
568
569
570
571
real_exchange (gint     x1,
	       gint     y1,
	       gint     x2,
	       gint     y2,
Sven Neumann's avatar
Sven Neumann committed
572
	       gboolean do_preview)
573
{
Sven Neumann's avatar
Sven Neumann committed
574
  GimpPixelRgn  srcPR, destPR;
575
576
577
  guchar    *src_row, *dest_row;
  gint       x, y, bpp = drw->bpp;
  gint       width, height;
578

579
580
581
582
583
584
585
586
  /* fill if necessary */
  if (x1 == -1 || y1 == -1 || x2 == -1 || y2 == -1)
    {
      x1 = sel_x1;
      y1 = sel_y1;
      x2 = sel_x2;
      y2 = sel_y2;
    }
587

588
589
590
  /* check for valid coordinates */
  width  = x2 - x1;
  height = y2 - y1;
591

592
593
  /* allocate memory */
  src_row  = g_new (guchar, drw->width * bpp);
594

Sven Neumann's avatar
Sven Neumann committed
595
  if (do_preview && has_alpha)
596
597
598
    dest_row = g_new (guchar, drw->width * (bpp - 1));
  else
    dest_row = g_new (guchar, drw->width * bpp);
599

600
601
602
603
604
  /* initialize the pixel regions */
  /*
    gimp_pixel_rgn_init (&srcPR, drw, x1, y1, width, height, FALSE, FALSE);
  */
  gimp_pixel_rgn_init (&srcPR, drw, 0, 0, drw->width, drw->height, FALSE, FALSE);
605

Sven Neumann's avatar
Sven Neumann committed
606
  if (! do_preview)
607
    gimp_pixel_rgn_init (&destPR, drw, 0, 0, width, height, TRUE, TRUE);
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
  for (y = y1; y < y2; y++)
    {
      gimp_pixel_rgn_get_row (&srcPR, src_row, 0, y, drw->width);
      for (x = x1; x < x2; x++)
	{
	  gint pixel_red, pixel_green, pixel_blue;
	  gint min_red, max_red, min_green, max_green, min_blue, max_blue;
	  gint new_red, new_green, new_blue;
	  gint idx, rest;

	  /* get boundary values */
	  min_red   = MAX (xargs.fromred - xargs.red_threshold, 0);
	  min_green = MAX (xargs.fromgreen - xargs.green_threshold, 0);
	  min_blue  = MAX (xargs.fromblue - xargs.blue_threshold, 0);

	  max_red   = MIN (xargs.fromred + xargs.red_threshold, 255);
	  max_green = MIN (xargs.fromgreen + xargs.green_threshold, 255);
	  max_blue  = MIN (xargs.fromblue + xargs.blue_threshold, 255);

	  /* get current pixel-values */
	  pixel_red   = src_row[x * bpp];
	  pixel_green = src_row[x * bpp + 1];
	  pixel_blue  = src_row[x * bpp + 2];

	  /* shift down for preview */
Sven Neumann's avatar
Sven Neumann committed
634
	  if (do_preview)
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
	    {
	      if (has_alpha)
		idx = (x - x1) * (bpp - 1);
	      else
		idx = (x - x1) * bpp;
	    }
	  else
	    idx = x * bpp;

	  /* want this pixel? */
	  if (pixel_red >= min_red &&
	      pixel_red <= max_red &&
	      pixel_green >= min_green &&
	      pixel_green <= max_green &&
	      pixel_blue >= min_blue &&
	      pixel_blue <= max_blue)
	    {
	      gint red_delta, green_delta, blue_delta;

	      red_delta   = pixel_red - xargs.fromred;
	      green_delta = pixel_green - xargs.fromgreen;
	      blue_delta  = pixel_blue - xargs.fromblue;
	      new_red   = (guchar) CLAMP (xargs.tored + red_delta, 0, 255);
	      new_green = (guchar) CLAMP (xargs.togreen + green_delta, 0, 255);
	      new_blue  = (guchar) CLAMP (xargs.toblue + blue_delta, 0, 255);
	    }
	  else
	    {
	      new_red   = pixel_red;
	      new_green = pixel_green;
	      new_blue  = pixel_blue;
	    }

	  /* fill buffer (cast it too) */
	  dest_row[idx + 0] = (guchar) new_red;
	  dest_row[idx + 1] = (guchar) new_green;
	  dest_row[idx + 2] = (guchar) new_blue;

	  /* copy rest (most likely alpha-channel) */
	  for (rest = 3; rest < bpp; rest++)
	    dest_row[idx + rest] = src_row[x * bpp + rest];
	}
      /* store the dest */
Sven Neumann's avatar
Sven Neumann committed
678
      if (do_preview)
679
680
681
682
	gtk_preview_draw_row (GTK_PREVIEW (preview), dest_row, 0, y - y1, width);
      else
	gimp_pixel_rgn_set_row (&destPR, dest_row, 0, y, drw->width);
      /* and tell the user what we're doing */
Sven Neumann's avatar
Sven Neumann committed
683
      if (! do_preview && (y % 10) == 0)
684
685
686
687
	gimp_progress_update ((double) y / (double) height);
    }
  g_free(src_row);
  g_free(dest_row);
Sven Neumann's avatar
Sven Neumann committed
688
  if (! do_preview)
689
690
691
692
693
694
695
    {
      /* update the processed region */
      gimp_drawable_flush (drw);
      gimp_drawable_merge_shadow (drw->id, TRUE);
      gimp_drawable_update (drw->id, x1, y1, width, height);
    }
}