hue-saturation.c 22.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
19
20
 */
#include <stdlib.h>
#include <string.h>
#include <math.h>
21

Elliot Lee's avatar
Elliot Lee committed
22
23
24
25
26
27
#include "appenv.h"
#include "colormaps.h"
#include "drawable.h"
#include "general.h"
#include "gimage_mask.h"
#include "gdisplay.h"
28
#include "gimpui.h"
Elliot Lee's avatar
Elliot Lee committed
29
30
31
#include "hue_saturation.h"
#include "interface.h"

Sven Neumann's avatar
Sven Neumann committed
32
#include "config.h"
33
#include "libgimp/gimpcolorspace.h"
34
35
#include "libgimp/gimpintl.h"

Elliot Lee's avatar
Elliot Lee committed
36
37
38
39
40
41
#define HUE_PARTITION_MASK  GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK

#define SLIDER_WIDTH  200
#define DA_WIDTH  40
#define DA_HEIGHT 20

42
43
44
45
46
47
#define HUE_PARTITION      0x0
#define HUE_SLIDER         0x1
#define LIGHTNESS_SLIDER   0x2
#define SATURATION_SLIDER  0x4
#define DRAW               0x40
#define ALL                0xFF
Elliot Lee's avatar
Elliot Lee committed
48

49
/*  the hue-saturation structures  */
Elliot Lee's avatar
Elliot Lee committed
50

51
typedef struct _HueSaturation HueSaturation;
52

Elliot Lee's avatar
Elliot Lee committed
53
54
struct _HueSaturation
{
55
  gint x, y;    /*  coords for last mouse click  */
Elliot Lee's avatar
Elliot Lee committed
56
57
};

58
/*  the hue-saturation tool options  */
59
static ToolOptions *hue_saturation_options = NULL;
60
61
62
63
64

/*  the hue-saturation tool dialog  */
static HueSaturationDialog *hue_saturation_dialog = NULL;

/*  Local variables  */
65
66
67
68
static gint hue_transfer[6][256];
static gint lightness_transfer[6][256];
static gint saturation_transfer[6][256];
static gint default_colors[6][3] =
69
{
70
71
72
73
74
75
  { 255,   0,   0 },
  { 255, 255,   0 },
  {   0, 255,   0 },
  {   0, 255, 255 },
  {   0,   0, 255 },
  { 255,   0, 255 }
76
};
Elliot Lee's avatar
Elliot Lee committed
77

78
/*  hue saturation action functions  */
79
static void   hue_saturation_control (Tool *, ToolAction, gpointer);
Elliot Lee's avatar
Elliot Lee committed
80

81
static HueSaturationDialog * hue_saturation_dialog_new (void);
Michael Natterer's avatar
Michael Natterer committed
82
83

static void   hue_saturation_update                  (HueSaturationDialog *,
84
						      gint);
Elliot Lee's avatar
Elliot Lee committed
85
static void   hue_saturation_preview                 (HueSaturationDialog *);
86
static void   hue_saturation_reset_callback          (GtkWidget *, gpointer);
Elliot Lee's avatar
Elliot Lee committed
87
88
static void   hue_saturation_ok_callback             (GtkWidget *, gpointer);
static void   hue_saturation_cancel_callback         (GtkWidget *, gpointer);
89
static void   hue_saturation_partition_callback      (GtkWidget *, gpointer);
Elliot Lee's avatar
Elliot Lee committed
90
static void   hue_saturation_preview_update          (GtkWidget *, gpointer);
91
92
93
94
95
96
static void   hue_saturation_hue_adjustment_update        (GtkAdjustment *,
							   gpointer);
static void   hue_saturation_lightness_adjustment_update  (GtkAdjustment *,
							   gpointer);
static void   hue_saturation_saturation_adjustment_update (GtkAdjustment *,
							   gpointer);
Michael Natterer's avatar
Michael Natterer committed
97
98
static gint   hue_saturation_hue_partition_events    (GtkWidget *, GdkEvent *,
						      HueSaturationDialog *);
Elliot Lee's avatar
Elliot Lee committed
99
100
101

/*  hue saturation machinery  */

Manish Singh's avatar
Manish Singh committed
102
void
Elliot Lee's avatar
Elliot Lee committed
103
104
hue_saturation_calculate_transfers (HueSaturationDialog *hsd)
{
105
106
107
  gint value;
  gint hue;
  gint i;
Elliot Lee's avatar
Elliot Lee committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

  /*  Calculate transfers  */
  for (hue = 0; hue < 6; hue++)
    for (i = 0; i < 256; i++)
      {
	value = (hsd->hue[0] + hsd->hue[hue + 1]) * 255.0 / 360.0;
	if ((i + value) < 0)
	  hue_transfer[hue][i] = 255 + (i + value);
	else if ((i + value) > 255)
	  hue_transfer[hue][i] = i + value - 255;
	else
	  hue_transfer[hue][i] = i + value;

	/*  Lightness  */
	value = (hsd->lightness[0] + hsd->lightness[hue + 1]) * 127.0 / 100.0;
123
	value = CLAMP (value, -255, 255);
Elliot Lee's avatar
Elliot Lee committed
124
125
126
127
128
129
130
	if (value < 0)
	  lightness_transfer[hue][i] = (unsigned char) ((i * (255 + value)) / 255);
	else
	  lightness_transfer[hue][i] = (unsigned char) (i + ((255 - i) * value) / 255);

	/*  Saturation  */
	value = (hsd->saturation[0] + hsd->saturation[hue + 1]) * 255.0 / 100.0;
131
	value = CLAMP (value, -255, 255);
132
133
134
135
136
137
138
139
140

	/* This change affects the way saturation is computed. With the
	   old code (different code for value < 0), increasing the
	   saturation affected muted colors very much, and bright colors
	   less. With the new code, it affects muted colors and bright
	   colors more or less evenly. For enhancing the color in photos,
	   the new behavior is exactly what you want. It's hard for me
	   to imagine a case in which the old behavior is better.
	*/
141
	saturation_transfer[hue][i] = CLAMP ((i * (255 + value)) / 255, 0, 255);
Elliot Lee's avatar
Elliot Lee committed
142
143
144
      }
}

Manish Singh's avatar
Manish Singh committed
145
void
Elliot Lee's avatar
Elliot Lee committed
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
hue_saturation (PixelRegion *srcPR,
		PixelRegion *destPR,
		void        *user_data)
{
  HueSaturationDialog *hsd;
  unsigned char *src, *s;
  unsigned char *dest, *d;
  int alpha;
  int w, h;
  int r, g, b;
  int hue;

  hsd = (HueSaturationDialog *) user_data;

  /*  Set the transfer arrays  (for speed)  */
  h = srcPR->h;
  src = srcPR->data;
  dest = destPR->data;
  alpha = (srcPR->bytes == 4) ? TRUE : FALSE;

  while (h--)
    {
      w = srcPR->w;
      s = src;
      d = dest;
      while (w--)
	{
	  r = s[RED_PIX];
	  g = s[GREEN_PIX];
	  b = s[BLUE_PIX];

177
	  gimp_rgb_to_hls (&r, &g, &b);
Elliot Lee's avatar
Elliot Lee committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195

	  if (r < 43)
	    hue = 0;
	  else if (r < 85)
	    hue = 1;
	  else if (r < 128)
	    hue = 2;
	  else if (r < 171)
	    hue = 3;
	  else if (r < 213)
	    hue = 4;
	  else
	    hue = 5;

	  r = hue_transfer[hue][r];
	  g = lightness_transfer[hue][g];
	  b = saturation_transfer[hue][b];

196
	  gimp_hls_to_rgb (&r, &g, &b);
Elliot Lee's avatar
Elliot Lee committed
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

	  d[RED_PIX] = r;
	  d[GREEN_PIX] = g;
	  d[BLUE_PIX] = b;

	  if (alpha)
	    d[ALPHA_PIX] = s[ALPHA_PIX];

	  s += srcPR->bytes;
	  d += destPR->bytes;
	}

      src += srcPR->rowstride;
      dest += destPR->rowstride;
    }
}

214
/*  hue saturation action functions  */
Elliot Lee's avatar
Elliot Lee committed
215
216

static void
Michael Natterer's avatar
Michael Natterer committed
217
218
219
hue_saturation_control (Tool       *tool,
			ToolAction  action,
			gpointer    gdisp_ptr)
Elliot Lee's avatar
Elliot Lee committed
220
221
222
{
  switch (action)
    {
Michael Natterer's avatar
Michael Natterer committed
223
    case PAUSE:
Elliot Lee's avatar
Elliot Lee committed
224
      break;
Michael Natterer's avatar
Michael Natterer committed
225
226

    case RESUME:
Elliot Lee's avatar
Elliot Lee committed
227
      break;
Michael Natterer's avatar
Michael Natterer committed
228
229

    case HALT:
Elliot Lee's avatar
Elliot Lee committed
230
      if (hue_saturation_dialog)
231
	hue_saturation_cancel_callback (NULL, (gpointer) hue_saturation_dialog);
Elliot Lee's avatar
Elliot Lee committed
232
      break;
Michael Natterer's avatar
Michael Natterer committed
233
234
235

    default:
      break;
Elliot Lee's avatar
Elliot Lee committed
236
237
238
239
    }
}

Tool *
240
tools_new_hue_saturation (void)
Elliot Lee's avatar
Elliot Lee committed
241
242
243
244
245
246
{
  Tool * tool;
  HueSaturation * private;

  /*  The tool options  */
  if (!hue_saturation_options)
247
    {
248
      hue_saturation_options = tool_options_new (_("Hue-Saturation"));
249
      tools_register (HUE_SATURATION, hue_saturation_options);
250
    }
Elliot Lee's avatar
Elliot Lee committed
251

252
253
  tool = tools_new_tool (HUE_SATURATION);
  private = g_new (HueSaturation, 1);
Elliot Lee's avatar
Elliot Lee committed
254

255
256
  tool->scroll_lock = TRUE;   /*  Disallow scrolling  */
  tool->preserve    = FALSE;  /*  Don't preserve on drawable change  */
257

258
  tool->private = (void *) private;
259

Elliot Lee's avatar
Elliot Lee committed
260
261
262
263
264
265
266
267
268
269
270
271
  tool->control_func = hue_saturation_control;

  return tool;
}

void
tools_free_hue_saturation (Tool *tool)
{
  HueSaturation * color_bal;

  color_bal = (HueSaturation *) tool->private;

272
  /*  Close the hue saturation dialog  */
Elliot Lee's avatar
Elliot Lee committed
273
  if (hue_saturation_dialog)
274
    hue_saturation_cancel_callback (NULL, (gpointer) hue_saturation_dialog);
Elliot Lee's avatar
Elliot Lee committed
275
276
277
278
279

  g_free (color_bal);
}

void
280
hue_saturation_initialize (GDisplay *gdisp)
Elliot Lee's avatar
Elliot Lee committed
281
{
282
  gint i;
Elliot Lee's avatar
Elliot Lee committed
283
284
285

  if (! drawable_color (gimage_active_drawable (gdisp->gimage)))
    {
286
      g_message (_("Hue-Saturation operates only on RGB color drawables."));
Elliot Lee's avatar
Elliot Lee committed
287
288
289
      return;
    }

290
  /*  The "hue-saturation" dialog  */
Elliot Lee's avatar
Elliot Lee committed
291
  if (!hue_saturation_dialog)
292
    hue_saturation_dialog = hue_saturation_dialog_new ();
Elliot Lee's avatar
Elliot Lee committed
293
294
295
296
297
298
299
300
301
302
303
  else
    if (!GTK_WIDGET_VISIBLE (hue_saturation_dialog->shell))
      gtk_widget_show (hue_saturation_dialog->shell);

  for (i = 0; i < 7; i++)
    {
      hue_saturation_dialog->hue[i] = 0.0;
      hue_saturation_dialog->lightness[i] = 0.0;
      hue_saturation_dialog->saturation[i] = 0.0;
    }

304
  hue_saturation_dialog->drawable = gimage_active_drawable (gdisp->gimage);
305
306
307
  hue_saturation_dialog->image_map =
    image_map_create (gdisp, hue_saturation_dialog->drawable);

Elliot Lee's avatar
Elliot Lee committed
308
309
310
311
  hue_saturation_update (hue_saturation_dialog, ALL);
}

void
312
hue_saturation_free (void)
Elliot Lee's avatar
Elliot Lee committed
313
314
315
316
317
{
  if (hue_saturation_dialog)
    {
      if (hue_saturation_dialog->image_map)
	{
318
	  active_tool->preserve = TRUE;
Elliot Lee's avatar
Elliot Lee committed
319
	  image_map_abort (hue_saturation_dialog->image_map);
320
	  active_tool->preserve = FALSE;
321

Elliot Lee's avatar
Elliot Lee committed
322
323
324
325
326
327
	  hue_saturation_dialog->image_map = NULL;
	}
      gtk_widget_destroy (hue_saturation_dialog->shell);
    }
}

328
329
330
/***************************/
/*  Hue-Saturation dialog  */
/***************************/
Elliot Lee's avatar
Elliot Lee committed
331

332
static HueSaturationDialog *
333
hue_saturation_dialog_new (void)
Elliot Lee's avatar
Elliot Lee committed
334
335
336
337
338
339
340
341
342
{
  HueSaturationDialog *hsd;
  GtkWidget *main_vbox;
  GtkWidget *main_hbox;
  GtkWidget *vbox;
  GtkWidget *hbox;
  GtkWidget *table;
  GtkWidget *label;
  GtkWidget *slider;
343
344
  GtkWidget *abox;
  GtkWidget *spinbutton;
Elliot Lee's avatar
Elliot Lee committed
345
346
347
348
349
  GtkWidget *toggle;
  GtkWidget *radio_button;
  GtkWidget *frame;
  GtkObject *data;
  GSList *group = NULL;
350
  gint i;
351

352
  gchar *hue_partition_names[] =
Elliot Lee's avatar
Elliot Lee committed
353
  {
354
355
356
357
358
359
360
    N_("Master"),
    N_("R"),
    N_("Y"),
    N_("G"),
    N_("C"),
    N_("B"),
    N_("M")
Elliot Lee's avatar
Elliot Lee committed
361
  };
362

363
  hsd = g_new (HueSaturationDialog, 1);
364
  hsd->hue_partition = ALL_HUES;
365
  hsd->preview       = TRUE;
Elliot Lee's avatar
Elliot Lee committed
366
367

  /*  The shell and main vbox  */
368
  hsd->shell = gimp_dialog_new (_("Hue-Saturation"), "hue_saturation",
369
370
371
372
373
				tools_help_func, NULL,
				GTK_WIN_POS_NONE,
				FALSE, TRUE, FALSE,

				_("OK"), hue_saturation_ok_callback,
374
				hsd, NULL, NULL, TRUE, FALSE,
375
				_("Reset"), hue_saturation_reset_callback,
376
				hsd, NULL, NULL, FALSE, FALSE,
377
				_("Cancel"), hue_saturation_cancel_callback,
378
				hsd, NULL, NULL, FALSE, TRUE,
379
380

				NULL);
Elliot Lee's avatar
Elliot Lee committed
381

382
383
  main_vbox = gtk_vbox_new (FALSE, 4);
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 4);
384
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (hsd->shell)->vbox), main_vbox);
Elliot Lee's avatar
Elliot Lee committed
385
386

  /*  The main hbox containing hue partitions and sliders  */
387
  main_hbox = gtk_hbox_new (FALSE, 4);
Elliot Lee's avatar
Elliot Lee committed
388
389
390
391
  gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, FALSE, FALSE, 0);

  /*  The table containing hue partitions  */
  table = gtk_table_new (7, 2, FALSE);
392
393
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
Elliot Lee's avatar
Elliot Lee committed
394
395
396
397
398
399
400
  gtk_box_pack_start (GTK_BOX (main_hbox), table, FALSE, FALSE, 0);

  /*  the radio buttons for hue partitions  */
  for (i = 0; i < 7; i++)
    {
      radio_button = gtk_radio_button_new_with_label (group, hue_partition_names[i]);
      group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio_button));
401
402
      gtk_object_set_data (GTK_OBJECT (radio_button), "hue_partition",
			   (gpointer) i);
Elliot Lee's avatar
Elliot Lee committed
403
404
405
406

      if (!i)
	{
	  gtk_table_attach (GTK_TABLE (table), radio_button, 0, 2, 0, 1,
407
			    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
408
409
410
411
	}
      else
	{
	  gtk_table_attach (GTK_TABLE (table), radio_button, 0, 1, i, i + 1,
412
			    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
413
414
415
416

	  frame = gtk_frame_new (NULL);
	  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
	  gtk_table_attach (GTK_TABLE (table), frame,  1, 2, i, i + 1,
417
			    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
418
	  hsd->hue_partition_da[i - 1] = gtk_preview_new (GTK_PREVIEW_COLOR);
419
420
421
422
	  gtk_preview_size (GTK_PREVIEW (hsd->hue_partition_da[i - 1]),
			    DA_WIDTH, DA_HEIGHT);
	  gtk_widget_set_events (hsd->hue_partition_da[i - 1],
				 HUE_PARTITION_MASK);
Elliot Lee's avatar
Elliot Lee committed
423
	  gtk_signal_connect (GTK_OBJECT (hsd->hue_partition_da[i - 1]), "event",
424
			      GTK_SIGNAL_FUNC (hue_saturation_hue_partition_events),
Elliot Lee's avatar
Elliot Lee committed
425
426
427
428
429
430
431
432
			      hsd);
	  gtk_container_add (GTK_CONTAINER (frame), hsd->hue_partition_da[i - 1]);

	  gtk_widget_show (hsd->hue_partition_da[i - 1]);
	  gtk_widget_show (frame);
	}

      gtk_signal_connect (GTK_OBJECT (radio_button), "toggled",
433
			  GTK_SIGNAL_FUNC (hue_saturation_partition_callback),
Elliot Lee's avatar
Elliot Lee committed
434
			  hsd);
435

Elliot Lee's avatar
Elliot Lee committed
436
437
      gtk_widget_show (radio_button);
    }
438

Elliot Lee's avatar
Elliot Lee committed
439
440
441
  gtk_widget_show (table);

  /*  The vbox for the table and preview toggle  */
442
  vbox = gtk_vbox_new (FALSE, 4);
Elliot Lee's avatar
Elliot Lee committed
443
444
  gtk_box_pack_start (GTK_BOX (main_hbox), vbox, FALSE, FALSE, 0);

445
  label = gtk_label_new (_("Hue / Lightness / Saturation Adjustments"));
Elliot Lee's avatar
Elliot Lee committed
446
447
448
449
450
451
  gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

  /*  The table containing sliders  */
  table = gtk_table_new (3, 3, FALSE);
452
453
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
Elliot Lee's avatar
Elliot Lee committed
454
455
456
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);

  /*  Create the hue scale widget  */
457
  label = gtk_label_new (_("Hue"));
458
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
Elliot Lee's avatar
Elliot Lee committed
459
  gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
460
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
461
462
463

  data = gtk_adjustment_new (0, -180, 180.0, 1.0, 1.0, 0.0);
  hsd->hue_data = GTK_ADJUSTMENT (data);
464
465
466

  slider = gtk_hscale_new (hsd->hue_data);
  gtk_widget_set_usize (slider, SLIDER_WIDTH, -1);
Elliot Lee's avatar
Elliot Lee committed
467
468
469
470
471
  gtk_scale_set_digits (GTK_SCALE (slider), 0);
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
  gtk_table_attach (GTK_TABLE (table), slider, 1, 2, 0, 1,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL,
472
473
474
475
476
477
478
479
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);

  abox = gtk_vbox_new (FALSE, 0);
  spinbutton = gtk_spin_button_new (hsd->hue_data, 1.0, 0);
  gtk_widget_set_usize (spinbutton, 74, -1);
  gtk_box_pack_end (GTK_BOX (abox), spinbutton, FALSE, FALSE, 0);
  gtk_table_attach (GTK_TABLE (table), abox, 2, 3, 0, 1,
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
480

481
482
  gtk_signal_connect (GTK_OBJECT (hsd->hue_data), "value_changed",
		      GTK_SIGNAL_FUNC (hue_saturation_hue_adjustment_update),
Elliot Lee's avatar
Elliot Lee committed
483
484
485
486
		      hsd);

  gtk_widget_show (label);
  gtk_widget_show (slider);
487
488
  gtk_widget_show (spinbutton);
  gtk_widget_show (abox);
Elliot Lee's avatar
Elliot Lee committed
489
490

  /*  Create the lightness scale widget  */
491
  label = gtk_label_new (_("Lightness"));
492
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
Elliot Lee's avatar
Elliot Lee committed
493
  gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
494
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
495
496
497

  data = gtk_adjustment_new (0, -100.0, 100.0, 1.0, 1.0, 0.0);
  hsd->lightness_data = GTK_ADJUSTMENT (data);
498
499
500

  slider = gtk_hscale_new (hsd->lightness_data);
  gtk_widget_set_usize (slider, SLIDER_WIDTH, -1);
Elliot Lee's avatar
Elliot Lee committed
501
502
503
504
505
  gtk_scale_set_digits (GTK_SCALE (slider), 0);
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
  gtk_table_attach (GTK_TABLE (table), slider, 1, 2, 1, 2,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL,
506
507
508
509
510
511
512
513
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);

  abox = gtk_vbox_new (FALSE, 0);
  spinbutton = gtk_spin_button_new (hsd->lightness_data, 1.0, 0);
  gtk_widget_set_usize (spinbutton, 75, -1);
  gtk_box_pack_end (GTK_BOX (abox), spinbutton, FALSE, FALSE, 0);
  gtk_table_attach (GTK_TABLE (table), abox, 2, 3, 1, 2,
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
514

515
516
  gtk_signal_connect (GTK_OBJECT (hsd->lightness_data), "value_changed",
		      GTK_SIGNAL_FUNC (hue_saturation_lightness_adjustment_update),
Elliot Lee's avatar
Elliot Lee committed
517
518
519
520
		      hsd);

  gtk_widget_show (label);
  gtk_widget_show (slider);
521
522
  gtk_widget_show (spinbutton);
  gtk_widget_show (abox);
Elliot Lee's avatar
Elliot Lee committed
523
524

  /*  Create the saturation scale widget  */
525
  label = gtk_label_new (_("Saturation"));
526
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
Elliot Lee's avatar
Elliot Lee committed
527
  gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
528
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
529
530
531

  data = gtk_adjustment_new (0, -100.0, 100.0, 1.0, 1.0, 0.0);
  hsd->saturation_data = GTK_ADJUSTMENT (data);
532
533
534

  slider = gtk_hscale_new (hsd->saturation_data);
  gtk_widget_set_usize (slider, SLIDER_WIDTH, -1);
Elliot Lee's avatar
Elliot Lee committed
535
536
537
538
539
  gtk_scale_set_digits (GTK_SCALE (slider), 0);
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
  gtk_table_attach (GTK_TABLE (table), slider, 1, 2, 2, 3,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL,
540
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
Elliot Lee's avatar
Elliot Lee committed
541

542
543
544
545
546
547
548
549
550
  abox = gtk_vbox_new (FALSE, 0);
  spinbutton = gtk_spin_button_new (hsd->saturation_data, 1.0, 0);
  gtk_widget_set_usize (spinbutton, 75, -1);
  gtk_box_pack_end (GTK_BOX (abox), spinbutton, FALSE, FALSE, 0);
  gtk_table_attach (GTK_TABLE (table), abox, 2, 3, 2, 3,
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);

  gtk_signal_connect (GTK_OBJECT (hsd->saturation_data), "value_changed",
		      GTK_SIGNAL_FUNC (hue_saturation_saturation_adjustment_update),
Elliot Lee's avatar
Elliot Lee committed
551
552
553
554
		      hsd);

  gtk_widget_show (label);
  gtk_widget_show (slider);
555
556
  gtk_widget_show (spinbutton);
  gtk_widget_show (abox);
Elliot Lee's avatar
Elliot Lee committed
557

558
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
559

560
561
562
  /*  Horizontal box for preview toggle button  */
  hbox = gtk_hbox_new (FALSE, 4);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
Elliot Lee's avatar
Elliot Lee committed
563
564

  /*  The preview toggle  */
565
  toggle = gtk_check_button_new_with_label (_("Preview"));
566
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), hsd->preview);
567
568
  gtk_box_pack_end (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);

Elliot Lee's avatar
Elliot Lee committed
569
  gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
570
		      GTK_SIGNAL_FUNC (hue_saturation_preview_update),
Elliot Lee's avatar
Elliot Lee committed
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
		      hsd);

  gtk_widget_show (toggle);
  gtk_widget_show (hbox);

  gtk_widget_show (vbox);
  gtk_widget_show (main_hbox);
  gtk_widget_show (main_vbox);
  gtk_widget_show (hsd->shell);

  return hsd;
}

static void
hue_saturation_update (HueSaturationDialog *hsd,
586
		       gint                 update)
Elliot Lee's avatar
Elliot Lee committed
587
{
588
589
590
  gint i, j, b;
  gint rgb[3];
  guchar buf[DA_WIDTH * 3];
Elliot Lee's avatar
Elliot Lee committed
591
592
593

  if (update & HUE_SLIDER)
    {
594
595
      gtk_adjustment_set_value (GTK_ADJUSTMENT (hsd->hue_data),
				hsd->hue[hsd->hue_partition]);
Elliot Lee's avatar
Elliot Lee committed
596
597
598
    }
  if (update & LIGHTNESS_SLIDER)
    {
599
600
      gtk_adjustment_set_value (GTK_ADJUSTMENT (hsd->lightness_data),
				hsd->lightness[hsd->hue_partition]);
Elliot Lee's avatar
Elliot Lee committed
601
602
603
    }
  if (update & SATURATION_SLIDER)
    {
604
605
      gtk_adjustment_set_value (GTK_ADJUSTMENT (hsd->saturation_data),
				hsd->saturation[hsd->hue_partition]);
Elliot Lee's avatar
Elliot Lee committed
606
607
608
609
610
611
    }

  hue_saturation_calculate_transfers (hsd);

  for (i = 0; i < 6; i++)
    {
612
      rgb[RED_PIX]   = default_colors[i][RED_PIX];
Elliot Lee's avatar
Elliot Lee committed
613
      rgb[GREEN_PIX] = default_colors[i][GREEN_PIX];
614
      rgb[BLUE_PIX]  = default_colors[i][BLUE_PIX];
Elliot Lee's avatar
Elliot Lee committed
615

616
      gimp_rgb_to_hls (rgb, rgb + 1, rgb + 2);
Elliot Lee's avatar
Elliot Lee committed
617

618
      rgb[RED_PIX]   = hue_transfer[i][rgb[RED_PIX]];
Elliot Lee's avatar
Elliot Lee committed
619
      rgb[GREEN_PIX] = lightness_transfer[i][rgb[GREEN_PIX]];
620
      rgb[BLUE_PIX]  = saturation_transfer[i][rgb[BLUE_PIX]];
Elliot Lee's avatar
Elliot Lee committed
621

622
      gimp_hls_to_rgb (rgb, rgb + 1, rgb + 2);
Elliot Lee's avatar
Elliot Lee committed
623
624
625

      for (j = 0; j < DA_WIDTH; j++)
	for (b = 0; b < 3; b++)
626
	  buf[j * 3 + b] = (guchar) rgb[b];
Elliot Lee's avatar
Elliot Lee committed
627
628

      for (j = 0; j < DA_HEIGHT; j++)
629
630
	gtk_preview_draw_row (GTK_PREVIEW (hsd->hue_partition_da[i]),
			      buf, 0, j, DA_WIDTH);
Elliot Lee's avatar
Elliot Lee committed
631
632
633
634
635
636
637
638
639
640

      if (update & DRAW)
	gtk_widget_draw (hsd->hue_partition_da[i], NULL);
    }
}

static void
hue_saturation_preview (HueSaturationDialog *hsd)
{
  if (!hsd->image_map)
641
642
643
644
645
    {
      g_warning ("hue_saturation_preview(): No image map");
      return;
    }

646
  active_tool->preserve = TRUE;
Elliot Lee's avatar
Elliot Lee committed
647
  image_map_apply (hsd->image_map, hue_saturation, (void *) hsd);
648
  active_tool->preserve = FALSE;
Elliot Lee's avatar
Elliot Lee committed
649
650
}

651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
static void
hue_saturation_reset_callback (GtkWidget *widget,
			       gpointer   data)
{
  HueSaturationDialog *hsd;

  hsd = (HueSaturationDialog *) data;

  hsd->hue[hsd->hue_partition] = 0.0;
  hsd->lightness[hsd->hue_partition] = 0.0;
  hsd->saturation[hsd->hue_partition] = 0.0;

  hue_saturation_update (hsd, ALL);

  if (hsd->preview)
    hue_saturation_preview (hsd);
}

Elliot Lee's avatar
Elliot Lee committed
669
670
static void
hue_saturation_ok_callback (GtkWidget *widget,
671
			    gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
672
673
674
{
  HueSaturationDialog *hsd;

675
  hsd = (HueSaturationDialog *) data;
Elliot Lee's avatar
Elliot Lee committed
676
677
678
679

  if (GTK_WIDGET_VISIBLE (hsd->shell))
    gtk_widget_hide (hsd->shell);

680
681
  active_tool->preserve = TRUE;

Elliot Lee's avatar
Elliot Lee committed
682
683
684
685
686
687
  if (!hsd->preview)
    image_map_apply (hsd->image_map, hue_saturation, (void *) hsd);

  if (hsd->image_map)
    image_map_commit (hsd->image_map);

688
689
  active_tool->preserve = FALSE;

Elliot Lee's avatar
Elliot Lee committed
690
  hsd->image_map = NULL;
691
692
693

  active_tool->gdisp_ptr = NULL;
  active_tool->drawable = NULL;
Elliot Lee's avatar
Elliot Lee committed
694
695
696
697
}

static void
hue_saturation_cancel_callback (GtkWidget *widget,
698
				gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
699
700
701
{
  HueSaturationDialog *hsd;

702
703
  hsd = (HueSaturationDialog *) data;

Elliot Lee's avatar
Elliot Lee committed
704
705
706
707
708
  if (GTK_WIDGET_VISIBLE (hsd->shell))
    gtk_widget_hide (hsd->shell);

  if (hsd->image_map)
    {
709
      active_tool->preserve = TRUE;
Elliot Lee's avatar
Elliot Lee committed
710
      image_map_abort (hsd->image_map);
711
      active_tool->preserve = FALSE;
712

Elliot Lee's avatar
Elliot Lee committed
713
      gdisplays_flush ();
714
      hsd->image_map = NULL;
Elliot Lee's avatar
Elliot Lee committed
715
    }
716
717
718

  active_tool->gdisp_ptr = NULL;
  active_tool->drawable = NULL;
Elliot Lee's avatar
Elliot Lee committed
719
720
721
}

static void
722
723
hue_saturation_partition_callback (GtkWidget *widget,
				   gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
724
725
{
  HueSaturationDialog *hsd;
726
  HueRange partition;
Elliot Lee's avatar
Elliot Lee committed
727

728
  hsd = (HueSaturationDialog *) data;
Elliot Lee's avatar
Elliot Lee committed
729

730
731
732
  partition = (HueRange) gtk_object_get_data (GTK_OBJECT (widget),
					      "hue_partition");
  hsd->hue_partition = partition;
Elliot Lee's avatar
Elliot Lee committed
733
734
735
736
737

  hue_saturation_update (hsd, ALL);
}

static void
738
hue_saturation_preview_update (GtkWidget *widget,
Elliot Lee's avatar
Elliot Lee committed
739
740
741
742
743
744
			       gpointer   data)
{
  HueSaturationDialog *hsd;

  hsd = (HueSaturationDialog *) data;

745
  if (GTK_TOGGLE_BUTTON (widget)->active)
Elliot Lee's avatar
Elliot Lee committed
746
747
748
749
750
751
752
753
754
    {
      hsd->preview = TRUE;
      hue_saturation_preview (hsd);
    }
  else
    hsd->preview = FALSE;
}

static void
755
756
hue_saturation_hue_adjustment_update (GtkAdjustment *adjustment,
				      gpointer       data)
Elliot Lee's avatar
Elliot Lee committed
757
758
759
760
761
762
763
764
{
  HueSaturationDialog *hsd;

  hsd = (HueSaturationDialog *) data;

  if (hsd->hue[hsd->hue_partition] != adjustment->value)
    {
      hsd->hue[hsd->hue_partition] = adjustment->value;
765
      hue_saturation_update (hsd, DRAW);
Elliot Lee's avatar
Elliot Lee committed
766
767
768
769
770
771
772

      if (hsd->preview)
	hue_saturation_preview (hsd);
    }
}

static void
773
774
hue_saturation_lightness_adjustment_update (GtkAdjustment *adjustment,
					    gpointer       data)
Elliot Lee's avatar
Elliot Lee committed
775
776
777
778
779
780
781
782
{
  HueSaturationDialog *hsd;

  hsd = (HueSaturationDialog *) data;

  if (hsd->lightness[hsd->hue_partition] != adjustment->value)
    {
      hsd->lightness[hsd->hue_partition] = adjustment->value;
783
      hue_saturation_update (hsd, DRAW);
Elliot Lee's avatar
Elliot Lee committed
784
785
786
787
788
789
790

      if (hsd->preview)
	hue_saturation_preview (hsd);
    }
}

static void
791
792
hue_saturation_saturation_adjustment_update (GtkAdjustment *adjustment,
					     gpointer       data)
Elliot Lee's avatar
Elliot Lee committed
793
794
795
796
797
798
799
800
{
  HueSaturationDialog *hsd;

  hsd = (HueSaturationDialog *) data;

  if (hsd->saturation[hsd->hue_partition] != adjustment->value)
    {
      hsd->saturation[hsd->hue_partition] = adjustment->value;
801
      hue_saturation_update (hsd, DRAW);
Elliot Lee's avatar
Elliot Lee committed
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824

      if (hsd->preview)
	hue_saturation_preview (hsd);
    }
}

static gint
hue_saturation_hue_partition_events (GtkWidget           *widget,
				     GdkEvent            *event,
				     HueSaturationDialog *hsd)
{
  switch (event->type)
    {
    case GDK_EXPOSE:
      hue_saturation_update (hsd, HUE_PARTITION);
      break;

    default:
      break;
    }

  return FALSE;
}