gimpcurvestool.c 41.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
/* 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
 */
Sven Neumann's avatar
Sven Neumann committed
18

19 20 21
#include "config.h"

#include <stdio.h>
22 23
#include <stdlib.h>
#include <string.h>
24
#include <errno.h>
25

26 27 28 29 30
#ifdef __GNUC__
#warning GTK_DISABLE_DEPRECATED
#endif
#undef GTK_DISABLE_DEPRECATED

Sven Neumann's avatar
Sven Neumann committed
31 32
#include <gtk/gtk.h>

33
#include "libgimpmath/gimpmath.h"
34
#include "libgimpbase/gimpbase.h"
35
#include "libgimpcolor/gimpcolor.h"
36
#include "libgimpwidgets/gimpwidgets.h"
37

38
#include "tools-types.h"
Michael Natterer's avatar
Michael Natterer committed
39

40 41
#include "config/gimpbaseconfig.h"

42
#include "base/curves.h"
Michael Natterer's avatar
Michael Natterer committed
43 44 45
#include "base/gimphistogram.h"
#include "base/gimplut.h"

46
#include "core/gimp.h"
Michael Natterer's avatar
Michael Natterer committed
47
#include "core/gimpdrawable.h"
48
#include "core/gimpdrawable-histogram.h"
Michael Natterer's avatar
Michael Natterer committed
49
#include "core/gimpimage.h"
50
#include "core/gimpimagemap.h"
51
#include "core/gimptoolinfo.h"
Michael Natterer's avatar
Michael Natterer committed
52 53

#include "widgets/gimpcursor.h"
54
#include "widgets/gimpenummenu.h"
55
#include "widgets/gimphelp-ids.h"
56
#include "widgets/gimphistogramview.h"
Michael Natterer's avatar
Michael Natterer committed
57

58 59
#include "display/gimpdisplay.h"

Michael Natterer's avatar
Michael Natterer committed
60
#include "gimpcurvestool.h"
61
#include "gimphistogramoptions.h"
62
#include "gimptoolcontrol.h"
Sven Neumann's avatar
Sven Neumann committed
63

64
#include "gimp-intl.h"
65

66

67 68 69 70
#define XRANGE_TOP     (1 << 0)
#define XRANGE_BOTTOM  (1 << 1)
#define YRANGE         (1 << 2)
#define ALL            (XRANGE_TOP | XRANGE_BOTTOM | YRANGE)
Elliot Lee's avatar
Elliot Lee committed
71

72
/*  NB: take care when changing these values: make sure the curve[] array in
73
 *  base/curves.h is large enough.
74
 */
75 76 77
#define GRAPH_WIDTH    256
#define GRAPH_HEIGHT   256
#define XRANGE_WIDTH   256
78 79
#define XRANGE_HEIGHT   12
#define YRANGE_WIDTH    12
80
#define YRANGE_HEIGHT  256
Elliot Lee's avatar
Elliot Lee committed
81 82 83
#define RADIUS           3
#define MIN_DISTANCE     8

84 85 86 87 88
#define GRAPH_MASK  (GDK_EXPOSURE_MASK       | \
                     GDK_LEAVE_NOTIFY_MASK   | \
		     GDK_POINTER_MOTION_MASK | \
		     GDK_BUTTON_PRESS_MASK   | \
		     GDK_BUTTON_RELEASE_MASK)
Elliot Lee's avatar
Elliot Lee committed
89 90


Michael Natterer's avatar
Michael Natterer committed
91 92
/*  local function prototypes  */

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
static void     gimp_curves_tool_class_init     (GimpCurvesToolClass *klass);
static void     gimp_curves_tool_init           (GimpCurvesTool      *c_tool);

static void     gimp_curves_tool_finalize       (GObject          *object);

static gboolean gimp_curves_tool_initialize     (GimpTool         *tool,
                                                 GimpDisplay      *gdisp);
static void     gimp_curves_tool_button_release (GimpTool         *tool,
                                                 GimpCoords       *coords,
                                                 guint32           time,
                                                 GdkModifierType   state,
                                                 GimpDisplay      *gdisp);

static void     gimp_curves_tool_color_picked   (GimpColorTool    *color_tool,
                                                 GimpImageType     sample_type,
                                                 GimpRGB          *color,
                                                 gint              color_index);
static void     gimp_curves_tool_map            (GimpImageMapTool *image_map_tool);
static void     gimp_curves_tool_dialog         (GimpImageMapTool *image_map_tool);
static void     gimp_curves_tool_reset          (GimpImageMapTool *image_map_tool);

static void     curves_add_point                (GimpCurvesTool   *c_tool,
                                                 gint              x,
                                                 gint              y,
                                                 gint              cchan);

static void     curves_update                   (GimpCurvesTool   *c_tool,
                                                 gint              update);

static void     curves_channel_callback         (GtkWidget        *widget,
                                                 GimpCurvesTool   *c_tool);
static void     curves_channel_reset_callback   (GtkWidget        *widget,
                                                 GimpCurvesTool   *c_tool);

static gboolean curves_set_sensitive_callback   (GimpHistogramChannel channel,
                                                 GimpCurvesTool   *c_tool);
static void     curves_curve_type_callback      (GtkWidget        *widget,
                                                 GimpCurvesTool   *c_tool);
static void     curves_load_callback            (GtkWidget        *widget,
                                                 GimpCurvesTool   *c_tool);
static void     curves_save_callback            (GtkWidget        *widget,
                                                 GimpCurvesTool   *c_tool);
static gboolean curves_graph_events             (GtkWidget        *widget,
                                                 GdkEvent         *event,
                                                 GimpCurvesTool   *c_tool);
static gboolean curves_graph_expose             (GtkWidget        *widget,
                                                 GdkEventExpose   *eevent,
                                                 GimpCurvesTool   *c_tool);

static void     file_dialog_create              (GimpCurvesTool   *c_tool);
static void     file_dialog_response            (GtkWidget        *dialog,
                                                 gint              response_id,
                                                 GimpCurvesTool   *c_tool);

static gboolean curves_read_from_file           (GimpCurvesTool   *c_tool,
                                                 FILE             *file);
static void     curves_write_to_file            (GimpCurvesTool   *c_tool,
                                                 FILE             *file);
151

Michael Natterer's avatar
Michael Natterer committed
152

153 154
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
155

156
/*  public functions  */
Michael Natterer's avatar
Michael Natterer committed
157 158

void
Nate Summers's avatar
Nate Summers committed
159
gimp_curves_tool_register (GimpToolRegisterCallback  callback,
160
                           gpointer                  data)
Michael Natterer's avatar
Michael Natterer committed
161
{
Nate Summers's avatar
Nate Summers committed
162
  (* callback) (GIMP_TYPE_CURVES_TOOL,
163
                GIMP_TYPE_HISTOGRAM_OPTIONS,
164
                gimp_color_options_gui,
165
                0,
166
                "gimp-curves-tool",
167 168
                _("Curves"),
                _("Adjust color curves"),
169
                N_("/Tools/Color Tools/_Curves..."), NULL,
170
                NULL, GIMP_HELP_TOOL_CURVES,
Nate Summers's avatar
Nate Summers committed
171
                GIMP_STOCK_TOOL_CURVES,
172
                data);
Michael Natterer's avatar
Michael Natterer committed
173 174
}

175
GType
Michael Natterer's avatar
Michael Natterer committed
176 177
gimp_curves_tool_get_type (void)
{
178
  static GType tool_type = 0;
Michael Natterer's avatar
Michael Natterer committed
179 180 181

  if (! tool_type)
    {
182
      static const GTypeInfo tool_info =
Michael Natterer's avatar
Michael Natterer committed
183 184
      {
        sizeof (GimpCurvesToolClass),
185 186 187 188 189 190 191 192
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_curves_tool_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data     */
	sizeof (GimpCurvesTool),
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_curves_tool_init,
Michael Natterer's avatar
Michael Natterer committed
193 194
      };

195
      tool_type = g_type_register_static (GIMP_TYPE_IMAGE_MAP_TOOL,
196
					  "GimpCurvesTool",
197
                                          &tool_info, 0);
Michael Natterer's avatar
Michael Natterer committed
198 199 200 201 202
    }

  return tool_type;
}

203 204 205

/*  private functions  */

Michael Natterer's avatar
Michael Natterer committed
206 207 208
static void
gimp_curves_tool_class_init (GimpCurvesToolClass *klass)
{
209 210
  GObjectClass          *object_class;
  GimpToolClass         *tool_class;
211
  GimpColorToolClass    *color_tool_class;
212
  GimpImageMapToolClass *image_map_tool_class;
Michael Natterer's avatar
Michael Natterer committed
213

214 215
  object_class         = G_OBJECT_CLASS (klass);
  tool_class           = GIMP_TOOL_CLASS (klass);
216
  color_tool_class     = GIMP_COLOR_TOOL_CLASS (klass);
217
  image_map_tool_class = GIMP_IMAGE_MAP_TOOL_CLASS (klass);
Michael Natterer's avatar
Michael Natterer committed
218

219
  parent_class = g_type_class_peek_parent (klass);
Michael Natterer's avatar
Michael Natterer committed
220

221
  object_class->finalize       = gimp_curves_tool_finalize;
222

223 224 225 226
  tool_class->initialize       = gimp_curves_tool_initialize;
  tool_class->button_release   = gimp_curves_tool_button_release;

  color_tool_class->picked     = gimp_curves_tool_color_picked;
227 228 229 230

  image_map_tool_class->map    = gimp_curves_tool_map;
  image_map_tool_class->dialog = gimp_curves_tool_dialog;
  image_map_tool_class->reset  = gimp_curves_tool_reset;
Michael Natterer's avatar
Michael Natterer committed
231 232 233
}

static void
234
gimp_curves_tool_init (GimpCurvesTool *c_tool)
Michael Natterer's avatar
Michael Natterer committed
235
{
236
  GimpImageMapTool *image_map_tool = GIMP_IMAGE_MAP_TOOL (c_tool);
237 238
  gint              i;

239
  image_map_tool->shell_desc = _("Adjust Color Curves");
240

241 242 243
  c_tool->curves  = g_new0 (Curves, 1);
  c_tool->lut     = gimp_lut_new ();
  c_tool->channel = GIMP_HISTOGRAM_VALUE;
244 245 246

  curves_init (c_tool->curves);

247
  for (i = 0; i < G_N_ELEMENTS (c_tool->col_value); i++)
248
    c_tool->col_value[i] = -1;
249 250 251

  c_tool->cursor_x = -1;
  c_tool->cursor_y = -1;
Michael Natterer's avatar
Michael Natterer committed
252 253 254
}

static void
255
gimp_curves_tool_finalize (GObject *object)
Michael Natterer's avatar
Michael Natterer committed
256
{
257
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (object);
258 259

  if (c_tool->curves)
Michael Natterer's avatar
Michael Natterer committed
260
    {
261
      g_free (c_tool->curves);
262
      c_tool->curves = NULL;
Michael Natterer's avatar
Michael Natterer committed
263
    }
264
  if (c_tool->lut)
Michael Natterer's avatar
Michael Natterer committed
265
    {
266 267
      gimp_lut_free (c_tool->lut);
      c_tool->lut = NULL;
Michael Natterer's avatar
Michael Natterer committed
268
    }
269 270 271 272 273
  if (c_tool->hist)
    {
      gimp_histogram_free (c_tool->hist);
      c_tool->hist = NULL;
    }
274
  if (c_tool->cursor_layout)
Michael Natterer's avatar
Michael Natterer committed
275
    {
276 277
      g_object_unref (c_tool->cursor_layout);
      c_tool->cursor_layout = NULL;
Michael Natterer's avatar
Michael Natterer committed
278
    }
279 280 281 282 283
  if (c_tool->xpos_layout)
    {
      g_object_unref (c_tool->xpos_layout);
      c_tool->xpos_layout = NULL;
    }
Michael Natterer's avatar
Michael Natterer committed
284

285
  G_OBJECT_CLASS (parent_class)->finalize (object);
Michael Natterer's avatar
Michael Natterer committed
286 287
}

288
static gboolean
289 290
gimp_curves_tool_initialize (GimpTool    *tool,
			     GimpDisplay *gdisp)
Michael Natterer's avatar
Michael Natterer committed
291
{
292
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool);
293 294
  GimpDrawable   *drawable;

295 296 297
  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (! drawable)
298
    return FALSE;
299

300
  if (gimp_drawable_is_indexed (drawable))
Michael Natterer's avatar
Michael Natterer committed
301
    {
302
      g_message (_("Curves for indexed layers cannot be adjusted."));
303
      return FALSE;
304
    }
Michael Natterer's avatar
Michael Natterer committed
305

306 307 308 309 310 311 312
  if (! c_tool->hist)
    {
      Gimp *gimp = GIMP_TOOL (c_tool)->tool_info->gimp;

      c_tool->hist = gimp_histogram_new (GIMP_BASE_CONFIG (gimp->config));
    }

313
  curves_init (c_tool->curves);
Michael Natterer's avatar
Michael Natterer committed
314

315
  c_tool->channel = GIMP_HISTOGRAM_VALUE;
316 317
  c_tool->color   = gimp_drawable_is_rgb (drawable);
  c_tool->alpha   = gimp_drawable_has_alpha (drawable);
318 319 320 321 322 323

  c_tool->grab_point = -1;
  c_tool->last       = 0;

  GIMP_TOOL_CLASS (parent_class)->initialize (tool, gdisp);

324 325 326 327
  /*  always pick colors  */
  gimp_color_tool_enable (GIMP_COLOR_TOOL (tool),
                          GIMP_COLOR_OPTIONS (tool->tool_info->tool_options));

328
  /* set the sensitivity of the channel menu based on the drawable type */
329 330 331
  gimp_int_option_menu_set_sensitive (GTK_OPTION_MENU (c_tool->channel_menu),
                                      (GimpIntOptionMenuSensitivityCallback) curves_set_sensitive_callback,
                                      c_tool);
332 333

  /* set the current selection */
334 335
  gimp_int_option_menu_set_history (GTK_OPTION_MENU (c_tool->channel_menu),
                                    c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
336

337 338 339
  if (! c_tool->color && c_tool->alpha)
    c_tool->channel = 1;

340
  curves_update (c_tool, ALL);
341 342 343 344

  gimp_drawable_calculate_histogram (drawable, c_tool->hist);
  gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                     c_tool->hist);
345 346

  return TRUE;
Michael Natterer's avatar
Michael Natterer committed
347 348 349
}

static void
350 351 352 353 354
gimp_curves_tool_button_release (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 guint32          time,
				 GdkModifierType  state,
				 GimpDisplay     *gdisp)
Michael Natterer's avatar
Michael Natterer committed
355
{
356
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool);
357
  GimpDrawable   *drawable;
Michael Natterer's avatar
Michael Natterer committed
358

359
  drawable = gimp_image_active_drawable (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
360

361
  if (state & GDK_SHIFT_MASK)
Michael Natterer's avatar
Michael Natterer committed
362
    {
363
      curves_add_point (c_tool, coords->x, coords->y, c_tool->channel);
364
      curves_calculate_curve (c_tool->curves, c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
365
    }
366
  else if (state & GDK_CONTROL_MASK)
Michael Natterer's avatar
Michael Natterer committed
367
    {
368
      gint i;
369

370 371 372 373 374
      for (i = 0; i < 5; i++)
        {
          curves_add_point (c_tool, coords->x, coords->y, i);
          curves_calculate_curve (c_tool->curves, c_tool->channel);
        }
Michael Natterer's avatar
Michael Natterer committed
375 376
    }

377 378 379
  /*  chain up to halt the tool */
  GIMP_TOOL_CLASS (parent_class)->button_release (tool,
                                                  coords, time, state, gdisp);
Michael Natterer's avatar
Michael Natterer committed
380 381 382
}

static void
383 384 385 386
gimp_curves_tool_color_picked (GimpColorTool *color_tool,
			       GimpImageType  sample_type,
			       GimpRGB       *color,
			       gint           color_index)
Michael Natterer's avatar
Michael Natterer committed
387
{
388 389
  GimpCurvesTool *c_tool;
  GimpDrawable   *drawable;
390
  guchar          r, g, b, a;
Michael Natterer's avatar
Michael Natterer committed
391

392 393
  c_tool = GIMP_CURVES_TOOL (color_tool);
  drawable = GIMP_IMAGE_MAP_TOOL (c_tool)->drawable;
394

395
  gimp_rgba_get_uchar (color, &r, &g, &b, &a);
396

397 398 399
  c_tool->col_value[GIMP_HISTOGRAM_RED]   = r;
  c_tool->col_value[GIMP_HISTOGRAM_GREEN] = g;
  c_tool->col_value[GIMP_HISTOGRAM_BLUE]  = b;
400

401 402
  if (gimp_drawable_has_alpha (drawable))
    c_tool->col_value[GIMP_HISTOGRAM_ALPHA] = a;
403

404 405
  if (gimp_drawable_is_indexed (drawable))
    c_tool->col_value[GIMP_HISTOGRAM_ALPHA] = color_index;
406

407
  c_tool->col_value[GIMP_HISTOGRAM_VALUE] = MAX (MAX (r, g), b);
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
408

409
  gtk_widget_queue_draw (c_tool->graph);
410
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
411

412
static void
413 414 415 416
curves_add_point (GimpCurvesTool *c_tool,
		  gint            x,
		  gint            y,
		  gint            cchan)
417 418
{
  /* Add point onto the curve */
419 420 421 422
  gint closest_point = 0;
  gint distance;
  gint curvex;
  gint i;
423

424
  switch (c_tool->curves->curve_type[cchan])
425
    {
426
    case GIMP_CURVE_SMOOTH:
427
      curvex   = c_tool->col_value[cchan];
428
      distance = G_MAXINT;
429

430 431
      for (i = 0; i < 17; i++)
	{
432 433
	  if (c_tool->curves->points[cchan][i][0] != -1)
	    if (abs (curvex - c_tool->curves->points[cchan][i][0]) < distance)
434
	      {
435
		distance = abs (curvex - c_tool->curves->points[cchan][i][0]);
436 437 438
		closest_point = i;
	      }
	}
439

440 441
      if (distance > MIN_DISTANCE)
	closest_point = (curvex + 8) / 16;
442

443 444
      c_tool->curves->points[cchan][closest_point][0] = curvex;
      c_tool->curves->points[cchan][closest_point][1] = c_tool->curves->curve[cchan][curvex];
445
      break;
446

447
    case GIMP_CURVE_FREE:
448
      c_tool->curves->curve[cchan][x] = 255 - y;
449
      break;
450
    }
Elliot Lee's avatar
Elliot Lee committed
451 452
}

453 454
static void
gimp_curves_tool_map (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
455
{
456
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (image_map_tool);
457

458
  gimp_lut_setup (c_tool->lut,
459 460 461
		  (GimpLutFunc) curves_lut_func,
                  c_tool->curves,
		  gimp_drawable_bytes (image_map_tool->drawable));
462

463 464 465
  gimp_image_map_apply (image_map_tool->image_map,
                        (GimpImageMapApplyFunc) gimp_lut_process_2,
                        c_tool->lut);
Elliot Lee's avatar
Elliot Lee committed
466 467
}

468

469 470 471
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
472

473 474
static void
gimp_curves_tool_dialog (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
475
{
476 477 478 479 480 481 482 483 484
  GimpCurvesTool  *c_tool = GIMP_CURVES_TOOL (image_map_tool);
  GimpToolOptions *tool_options;
  GtkWidget       *hbox;
  GtkWidget       *vbox;
  GtkWidget       *hbbox;
  GtkWidget       *frame;
  GtkWidget       *menu;
  GtkWidget       *table;
  GtkWidget       *button;
485

486 487 488 489 490 491 492 493 494
  hbox = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (image_map_tool->main_vbox), hbox,
                      FALSE, FALSE, 0);
  gtk_widget_show (hbox);

  vbox = gtk_vbox_new (FALSE, 4);
  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, FALSE, 0);
  gtk_widget_show (vbox);

495 496 497
  table = gtk_table_new (2, 2, FALSE);
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
498
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
499
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
500

501 502
  /*  The option menu for selecting channels  */
  hbox = gtk_hbox_new (FALSE, 4);
503 504 505 506 507 508 509 510 511
  menu = gimp_enum_option_menu_new (GIMP_TYPE_HISTOGRAM_CHANNEL,
                                    G_CALLBACK (curves_channel_callback),
                                    c_tool);
  gimp_enum_option_menu_set_stock_prefix (GTK_OPTION_MENU (menu),
                                          "gimp-channel");
  gtk_box_pack_start (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
  gtk_widget_show (menu);

  c_tool->channel_menu = menu;
512

513
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
514
  gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
515
  gtk_widget_show (button);
516

517
  g_signal_connect (button, "clicked",
518 519
                    G_CALLBACK (curves_channel_reset_callback),
                    c_tool);
520

521
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
522
                             _("Channel:"), 1.0, 0.5, hbox, 1, FALSE);
Elliot Lee's avatar
Elliot Lee committed
523 524

  /*  The table for the yrange and the graph  */
525 526 527 528
  hbox = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

Elliot Lee's avatar
Elliot Lee committed
529
  table = gtk_table_new (2, 2, FALSE);
530 531
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
532
  gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, FALSE, 0);
Elliot Lee's avatar
Elliot Lee committed
533 534 535

  /*  The range drawing area  */
  frame = gtk_frame_new (NULL);
536
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
537 538 539 540
  gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1,
		    GTK_EXPAND, GTK_EXPAND, 0, 0);
  gtk_widget_show (frame);

541 542 543 544 545
  c_tool->yrange = gtk_preview_new (GTK_PREVIEW_COLOR);
  gtk_preview_size (GTK_PREVIEW (c_tool->yrange), YRANGE_WIDTH, YRANGE_HEIGHT);
  gtk_container_add (GTK_CONTAINER (frame), c_tool->yrange);
  gtk_widget_show (c_tool->yrange);

Elliot Lee's avatar
Elliot Lee committed
546 547
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
548
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
549
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
550 551
		    GTK_SHRINK | GTK_FILL,
		    GTK_SHRINK | GTK_FILL, 0, 0);
552
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
553

554
  c_tool->graph = gimp_histogram_view_new (FALSE);
555 556
  gtk_widget_set_size_request (c_tool->graph,
                               GRAPH_WIDTH  + RADIUS * 2,
557
                               GRAPH_HEIGHT + RADIUS * 2);
558
  gtk_widget_set_events (c_tool->graph, GRAPH_MASK);
559 560 561 562 563
  g_object_set (c_tool->graph,
                "border-width", RADIUS,
                "subdivisions", 1,
                NULL);
  GIMP_HISTOGRAM_VIEW (c_tool->graph)->light_histogram = TRUE;
564 565
  gtk_container_add (GTK_CONTAINER (frame), c_tool->graph);
  gtk_widget_show (c_tool->graph);
566

567
  g_signal_connect (c_tool->graph, "event",
568
		    G_CALLBACK (curves_graph_events),
569
		    c_tool);
570 571 572
  g_signal_connect_after (c_tool->graph, "expose_event",
                          G_CALLBACK (curves_graph_expose),
                          c_tool);
Elliot Lee's avatar
Elliot Lee committed
573

574 575 576 577 578

  tool_options = GIMP_TOOL (c_tool)->tool_info->tool_options;
  gimp_histogram_options_connect_view (GIMP_HISTOGRAM_OPTIONS (tool_options),
                                       GIMP_HISTOGRAM_VIEW (c_tool->graph));

Elliot Lee's avatar
Elliot Lee committed
579 580
  /*  The range drawing area  */
  frame = gtk_frame_new (NULL);
581
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
582 583 584 585
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 1, 2,
		    GTK_EXPAND, GTK_EXPAND, 0, 0);
  gtk_widget_show (frame);

586 587 588 589
  c_tool->xrange = gtk_preview_new (GTK_PREVIEW_COLOR);
  gtk_preview_size (GTK_PREVIEW (c_tool->xrange), XRANGE_WIDTH, XRANGE_HEIGHT);
  gtk_container_add (GTK_CONTAINER (frame), c_tool->xrange);
  gtk_widget_show (c_tool->xrange);
590

591
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
592

593 594 595
  hbox = gtk_hbox_new (FALSE, 6);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);
596

597
  /*  Horizontal button box for load / save */
598
  frame = gtk_frame_new (_("All Channels"));
599
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
600 601
  gtk_widget_show (frame);

602
  hbbox = gtk_hbutton_box_new ();
603
  gtk_container_set_border_width (GTK_CONTAINER (hbbox), 2);
604
  gtk_box_set_spacing (GTK_BOX (hbbox), 4);
605
  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_SPREAD);
606
  gtk_container_add (GTK_CONTAINER (frame), hbbox);
607
  gtk_widget_show (hbbox);
608

609
  button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
610 611
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
612
  gimp_help_set_help_data (button, _("Read curves settings from file"), NULL);
613 614
  gtk_widget_show (button);

615
  g_signal_connect (button, "clicked",
616
		    G_CALLBACK (curves_load_callback),
617
		    c_tool);
618

619
  button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
620 621
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
622
  gimp_help_set_help_data (button, _("Save curves settings to file"), NULL);
623 624
  gtk_widget_show (button);

625
  g_signal_connect (button, "clicked",
626
		    G_CALLBACK (curves_save_callback),
627
		    c_tool);
628 629 630 631 632 633 634

  /*  The radio box for selecting the curve type  */
  frame = gtk_frame_new (_("Curve Type"));
  gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  gtk_widget_show (frame);

  hbox = gimp_enum_stock_box_new (GIMP_TYPE_CURVE_TYPE,
635
				  "gimp-curve", GTK_ICON_SIZE_MENU,
636 637 638 639 640 641 642 643 644
				  G_CALLBACK (curves_curve_type_callback),
				  c_tool,
				  &c_tool->curve_type);

  gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
  gtk_box_set_spacing (GTK_BOX (hbox), 4);

  gtk_container_add (GTK_CONTAINER (frame), hbox);
  gtk_widget_show (hbox);
Elliot Lee's avatar
Elliot Lee committed
645 646
}

647
static void
648
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
649
{
650
  GimpCurvesTool       *c_tool = GIMP_CURVES_TOOL (image_map_tool);
651
  GimpHistogramChannel  channel;
652 653 654

  c_tool->grab_point = -1;

655 656 657 658
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
    curves_channel_reset (c_tool->curves, channel);
659

660 661
  curves_update (c_tool, XRANGE_TOP);
  gtk_widget_queue_draw (c_tool->graph);
662 663
}

664

665
/* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
Elliot Lee's avatar
Elliot Lee committed
666
static void
667 668
curves_update (GimpCurvesTool *c_tool,
	       gint            update)
Elliot Lee's avatar
Elliot Lee committed
669
{
670 671
  GimpHistogramChannel sel_channel;
  gint                 i, j;
672

673
  if (c_tool->color)
674
    {
675
      sel_channel = c_tool->channel;
676
    }
677
  else
678
    {
679
      if (c_tool->channel == 2)
680 681 682 683
        sel_channel = GIMP_HISTOGRAM_ALPHA;
      else
        sel_channel = GIMP_HISTOGRAM_VALUE;
    }
684

Elliot Lee's avatar
Elliot Lee committed
685 686
  if (update & XRANGE_TOP)
    {
687
      guchar buf[XRANGE_WIDTH * 3];
688

689
      switch (sel_channel)
690
	{
Michael Natterer's avatar
Michael Natterer committed
691 692
	case GIMP_HISTOGRAM_VALUE:
	case GIMP_HISTOGRAM_ALPHA:
693
	  for (i = 0; i < XRANGE_HEIGHT / 2; i++)
694
	    {
695
	      for (j = 0; j < XRANGE_WIDTH ; j++)
696
		{
697 698 699
		  buf[j * 3 + 0] = c_tool->curves->curve[sel_channel][j];
		  buf[j * 3 + 1] = c_tool->curves->curve[sel_channel][j];
		  buf[j * 3 + 2] = c_tool->curves->curve[sel_channel][j];
700
		}
701
	      gtk_preview_draw_row (GTK_PREVIEW (c_tool->xrange),
702
				    buf, 0, i, XRANGE_WIDTH);
703
	    }
704 705
	  break;

Michael Natterer's avatar
Michael Natterer committed
706 707 708
	case GIMP_HISTOGRAM_RED:
	case GIMP_HISTOGRAM_GREEN:
	case GIMP_HISTOGRAM_BLUE:
709
	  {
710
	    for (i = 0; i < XRANGE_HEIGHT / 2; i++)
711
	      {
712 713
		for (j = 0; j < XRANGE_WIDTH; j++)
		  {
714 715 716
		    buf[j * 3 + 0] = c_tool->curves->curve[GIMP_HISTOGRAM_RED][j];
		    buf[j * 3 + 1] = c_tool->curves->curve[GIMP_HISTOGRAM_GREEN][j];
		    buf[j * 3 + 2] = c_tool->curves->curve[GIMP_HISTOGRAM_BLUE][j];
717
		  }
718
		gtk_preview_draw_row (GTK_PREVIEW (c_tool->xrange),
719
				      buf, 0, i, XRANGE_WIDTH);
720
	      }
721
	    break;
722 723
	  }

724
	default:
725
	  g_warning ("unknown channel type %d, can't happen!?!?",
726
		     c_tool->channel);
727
	  break;
728
	}
Elliot Lee's avatar
Elliot Lee committed
729

730 731 732
      gtk_widget_queue_draw_area (c_tool->xrange,
                                  0, 0,
                                  XRANGE_WIDTH, XRANGE_HEIGHT / 2);
Elliot Lee's avatar
Elliot Lee committed
733
    }
734

Elliot Lee's avatar
Elliot Lee committed
735 736
  if (update & XRANGE_BOTTOM)
    {
737
      guchar buf[XRANGE_WIDTH * 3];
Elliot Lee's avatar
Elliot Lee committed
738 739

      for (i = 0; i < XRANGE_WIDTH; i++)
740 741 742 743 744
        {
          buf[i * 3 + 0] = i;
          buf[i * 3 + 1] = i;
          buf[i * 3 + 2] = i;
        }
Elliot Lee's avatar
Elliot Lee committed
745 746

      for (i = XRANGE_HEIGHT / 2; i < XRANGE_HEIGHT; i++)
747 748
	gtk_preview_draw_row (GTK_PREVIEW (c_tool->xrange),
                              buf, 0, i, XRANGE_WIDTH);
Elliot Lee's avatar
Elliot Lee committed
749

750 751 752
      gtk_widget_queue_draw_area (c_tool->xrange,
                                  0, XRANGE_HEIGHT / 2,
                                  XRANGE_WIDTH, XRANGE_HEIGHT / 2);
Elliot Lee's avatar
Elliot Lee committed
753
    }
754

Elliot Lee's avatar
Elliot Lee committed
755 756
  if (update & YRANGE)
    {
757 758
      guchar buf[YRANGE_WIDTH * 3];
      guchar pix[3];
Elliot Lee's avatar
Elliot Lee committed
759 760 761

      for (i = 0; i < YRANGE_HEIGHT; i++)
	{
762
	  switch (sel_channel)
763
	    {
Michael Natterer's avatar
Michael Natterer committed
764 765
	    case GIMP_HISTOGRAM_VALUE:
	    case GIMP_HISTOGRAM_ALPHA:
766 767 768
	      pix[0] = pix[1] = pix[2] = (255 - i);
	      break;

Michael Natterer's avatar
Michael Natterer committed
769 770 771
	    case GIMP_HISTOGRAM_RED:
	    case GIMP_HISTOGRAM_GREEN:
	    case GIMP_HISTOGRAM_BLUE:
772
	      pix[0] = pix[1] = pix[2] = 0;
773
	      pix[sel_channel - 1] = (255 - i);
774 775
	      break;

776
	    default:
777
	      g_warning ("unknown channel type %d, can't happen!?!?",
778
			 c_tool->channel);
779
	      break;
780
	    }
781 782

	  for (j = 0; j < YRANGE_WIDTH * 3; j++)
783
	    buf[j] = pix[j%3];
Elliot Lee's avatar
Elliot Lee committed
784

785
	  gtk_preview_draw_row (GTK_PREVIEW (c_tool->yrange),
786
				buf, 0, i, YRANGE_WIDTH);
Elliot Lee's avatar
Elliot Lee committed
787 788
	}

789
      gtk_widget_queue_draw (c_tool->yrange);
Elliot Lee's avatar
Elliot Lee committed
790 791 792 793
    }
}

static void
794 795
curves_channel_callback (GtkWidget      *widget,
			 GimpCurvesTool *c_tool)
Elliot Lee's avatar
Elliot Lee committed
796
{
797
  gimp_menu_item_update (widget, &c_tool->channel);
Elliot Lee's avatar
Elliot Lee committed
798

799 800 801 802
  gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                   c_tool->channel);

  /* FIXME: hack */
803
  if (! c_tool->color && c_tool->alpha)
804
    c_tool->channel = (c_tool->channel > 1) ? 2 : 1;
Elliot Lee's avatar
Elliot Lee committed
805

806 807
  gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (c_tool->curve_type),
			           c_tool->curves->curve_type[c_tool->channel]);
808

809
  curves_update (c_tool, XRANGE_TOP | YRANGE);
Elliot Lee's avatar
Elliot Lee committed
810 811 812
}

static void
813 814
curves_channel_reset_callback (GtkWidget      *widget,
                               GimpCurvesTool *c_tool)
Elliot Lee's avatar
Elliot Lee committed
815
{
816
  c_tool->grab_point = -1;
Elliot Lee's avatar
Elliot Lee committed
817

818
  curves_channel_reset (c_tool->curves, c_tool->channel);
Elliot Lee's avatar
Elliot Lee committed
819

820 821
  curves_update (c_tool, XRANGE_TOP);
  gtk_widget_queue_draw (c_tool->graph);
Elliot Lee's avatar
Elliot Lee committed
822

823
  gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (c_tool));
Elliot Lee's avatar
Elliot Lee committed
824 825
}