exchange.c 20.2 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
59
60
61
62
static void	query (void);
static void	run   (gchar   *name,
		       gint     nparams,
		       GParam  *param,
		       gint    *nreturn_vals,
		       GParam **return_vals);

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 */
73
74
75
76
77
78
79
80
81
82
static GDrawable *drw;
static gboolean   has_alpha;
static myParams   xargs = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static gint       running = 0;
static GPixelRgn  origregion;
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
86
87

/* lets declare what we want to do */
GPlugInInfo PLUG_IN_INFO =
{
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
{
101
102
103
104
105
106
107
108
109
110
111
112
113
  static GParamDef args[] =
  {
    { PARAM_INT32, "run_mode", "Interactive" },
    { PARAM_IMAGE, "image", "Input image" },
    { PARAM_DRAWABLE, "drawable", "Input drawable" },
    { PARAM_INT8, "fromred", "Red value (from)" },
    { PARAM_INT8, "fromgreen", "Green value (from)" },
    { PARAM_INT8, "fromblue", "Blue value (from)" },
    { PARAM_INT8, "tored", "Red value (to)" },
    { PARAM_INT8, "togreen", "Green value (to)" },
    { PARAM_INT8, "toblue", "Blue value (to)" },
    { PARAM_INT8, "red_threshold", "Red threshold" },
    { PARAM_INT8, "green_threshold", "Green threshold" },
114
    { PARAM_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
127
			  "robert@experimental.net",
			  "robert@experimental.net",
			  "June 17th, 1997",
			  N_("<Image>/Filters/Colors/Map/Color Exchange..."),
			  "RGB*",
			  PROC_PLUG_IN,
128
129
			  nargs, 0,
			  args, NULL);
Elliot Lee's avatar
Elliot Lee committed
130
131
132
}

/* main function */
133
134
135
136
137
138
static void
run (gchar   *name,
     gint     nparams,
     GParam  *param,
     gint    *nreturn_vals,
     GParam **return_vals)
Elliot Lee's avatar
Elliot Lee committed
139
{
140
141
142
  static GParam	values[1];
  GRunModeType	runmode;
  GStatusType 	status = STATUS_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

147
148
  values[0].type = PARAM_STATUS;
  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

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  switch (runmode)
    {
    case RUN_INTERACTIVE:
      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);
      /* and initialize some other 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);
      if (!doDialog ())
	return;
      break;

    case RUN_WITH_LAST_VALS:
      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;

    case RUN_NONINTERACTIVE:
      INIT_I18N();
      if (nparams != 10)
198
199
200
201
	{
	  status = STATUS_EXECUTION_ERROR;
	}
      else
Elliot Lee's avatar
Elliot Lee committed
202
	{
203
204
205
206
207
208
209
210
211
	  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
212
	}
213
214
215
216
217
218
219
220
      break;
    default:	
      break;
    }

  if (status == STATUS_SUCCESS)
    {
      if (gimp_drawable_is_rgb (drw->id))
Elliot Lee's avatar
Elliot Lee committed
221
	{
222
223
224
225
226
227
228
229
230
231
232
233
	  gimp_progress_init (_("Color Exchange..."));
	  gimp_tile_cache_ntiles (2 * (drw->width / gimp_tile_width () + 1));
	  exchange ();	
	  gimp_drawable_detach( drw);

	  /* store our settings */
	  if (runmode == RUN_INTERACTIVE)
	    gimp_set_data ("plug_in_exchange", &xargs, sizeof (myParams));

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

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

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

  gimp_ui_init ("exchange", TRUE);
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289

  /* 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",
			    gimp_plugin_help_func, "filters/exchange.html",
			    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 */
290
291
  mainbox = gtk_vbox_new (FALSE, 4);
  gtk_container_set_border_width (GTK_CONTAINER (mainbox), 6);
292
293
294
295
296
  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);
297
  gtk_box_pack_start (GTK_BOX (mainbox), frame, FALSE, FALSE, 0);
298
299
  gtk_widget_show (frame);

300
301
302
303
304
305
306
307
308
309
  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);

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

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

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

      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);
330
      gtk_container_add (GTK_CONTAINER (frame), table);
331
332
333
334
335
336
337
338
339
      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);
340
      gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
341
				 NULL, 0.0, 0.0,
342
				 colorbutton, 1, TRUE);
343
344
345
346
347
348
349
350
351
352
353
354
      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,
355
356
357
				  0, 255, 1, 8, 0,
				  TRUE, 0, 0,
				  NULL, NULL);
358
359
360
361
362
363
364
      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);

365
      if (! framenumber)
366
	{
Sven Neumann's avatar
Sven Neumann committed
367
368
369
370
371
372
373
374
375
376
377
	  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);
378
379
380
381
382
	}

      adj = gimp_scale_entry_new (GTK_TABLE (table), 0, framenumber ? 2 : 3,
				  _("Green:"), SCALE_WIDTH, 0,
				  framenumber ? xargs.togreen : xargs.fromgreen,
383
384
385
				  0, 255, 1, 8, 0,
				  TRUE, 0, 0,
				  NULL, NULL);
386
387
388
389
390
391
392
      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);

393
      if (! framenumber)
394
	{
Sven Neumann's avatar
Sven Neumann committed
395
396
397
398
399
400
401
402
403
404
405
406
	  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);
407
408
409
410
411
	}

      adj = gimp_scale_entry_new (GTK_TABLE (table), 0, framenumber ? 3 : 5,
				  _("Blue:"), SCALE_WIDTH, 0,
				  framenumber ? xargs.toblue : xargs.fromblue,
412
413
414
				  0, 255, 1, 8, 0,
				  TRUE, 0, 0,
				  NULL, NULL);
415
416
417
418
419
420
421
      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);

422
      if (! framenumber)
423
	{
Sven Neumann's avatar
Sven Neumann committed
424
425
426
427
428
429
430
431
432
433
434
435
436
437
	  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);
438
439
	}

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

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

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

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

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

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

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

474
475
476
static void
color_button_callback (GtkWidget *widget,
		       gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
477
{
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
  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
513

514
515
516
517
518
  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 ();
519
520
}

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

  *val = (guchar) adj->value;

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

Sven Neumann's avatar
Sven Neumann committed
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  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;
    }
551
552

  update_preview ();
553
554
}

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

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

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

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

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

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

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

599
600
601
602
603
  /* 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);
604

Sven Neumann's avatar
Sven Neumann committed
605
  if (! do_preview)
606
    gimp_pixel_rgn_init (&destPR, drw, 0, 0, width, height, TRUE, TRUE);
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
  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
633
	  if (do_preview)
634
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
	    {
	      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
677
      if (do_preview)
678
679
680
681
	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
682
      if (! do_preview && (y % 10) == 0)
683
684
685
686
	gimp_progress_update ((double) y / (double) height);
    }
  g_free(src_row);
  g_free(dest_row);
Sven Neumann's avatar
Sven Neumann committed
687
  if (! do_preview)
688
689
690
691
692
693
694
    {
      /* update the processed region */
      gimp_drawable_flush (drw);
      gimp_drawable_merge_shadow (drw->id, TRUE);
      gimp_drawable_update (drw->id, x1, y1, width, height);
    }
}