gimpcurvestool.c 41 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 316 317 318 319 320 321 322
  c_tool->color   = gimp_drawable_is_rgb (drawable);
  c_tool->channel = GIMP_HISTOGRAM_VALUE;

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

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

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

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

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

336
  curves_update (c_tool, ALL);
337 338 339 340

  gimp_drawable_calculate_histogram (drawable, c_tool->hist);
  gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                     c_tool->hist);
341 342

  return TRUE;
Michael Natterer's avatar
Michael Natterer committed
343 344 345
}

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

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

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

366 367 368 369 370
      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
371 372
    }

373 374 375
  /*  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
376 377 378
}

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

388 389
  c_tool = GIMP_CURVES_TOOL (color_tool);
  drawable = GIMP_IMAGE_MAP_TOOL (c_tool)->drawable;
390

391
  gimp_rgba_get_uchar (color, &r, &g, &b, &a);
392

393 394 395
  c_tool->col_value[GIMP_HISTOGRAM_RED]   = r;
  c_tool->col_value[GIMP_HISTOGRAM_GREEN] = g;
  c_tool->col_value[GIMP_HISTOGRAM_BLUE]  = b;
396

397 398
  if (gimp_drawable_has_alpha (drawable))
    c_tool->col_value[GIMP_HISTOGRAM_ALPHA] = a;
399

400 401
  if (gimp_drawable_is_indexed (drawable))
    c_tool->col_value[GIMP_HISTOGRAM_ALPHA] = color_index;
402

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

405
  gtk_widget_queue_draw (c_tool->graph);
406
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
407

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

420
  switch (c_tool->curves->curve_type[cchan])
421
    {
422
    case GIMP_CURVE_SMOOTH:
423
      curvex   = c_tool->col_value[cchan];
424
      distance = G_MAXINT;
425

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

436 437
      if (distance > MIN_DISTANCE)
	closest_point = (curvex + 8) / 16;
438

439 440
      c_tool->curves->points[cchan][closest_point][0] = curvex;
      c_tool->curves->points[cchan][closest_point][1] = c_tool->curves->curve[cchan][curvex];
441
      break;
442

443
    case GIMP_CURVE_FREE:
444
      c_tool->curves->curve[cchan][x] = 255 - y;
445
      break;
446
    }
Elliot Lee's avatar
Elliot Lee committed
447 448
}

449 450
static void
gimp_curves_tool_map (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
451
{
452
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (image_map_tool);
453

454
  gimp_lut_setup (c_tool->lut,
455 456 457
		  (GimpLutFunc) curves_lut_func,
                  c_tool->curves,
		  gimp_drawable_bytes (image_map_tool->drawable));
458

459 460 461
  gimp_image_map_apply (image_map_tool->image_map,
                        (GimpImageMapApplyFunc) gimp_lut_process_2,
                        c_tool->lut);
Elliot Lee's avatar
Elliot Lee committed
462 463
}

464

465 466 467
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
468

469 470
static void
gimp_curves_tool_dialog (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
471
{
472 473 474 475 476 477 478 479 480
  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;
481

482 483 484 485 486 487 488 489 490
  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);

491 492 493
  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);
494
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
495
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
496

497 498
  /*  The option menu for selecting channels  */
  hbox = gtk_hbox_new (FALSE, 4);
499 500 501 502 503 504 505 506 507
  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;
508

509
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
510 511
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  gtk_widget_show (button);
512

513
  g_signal_connect (button, "clicked",
514 515
                    G_CALLBACK (curves_channel_reset_callback),
                    c_tool);
516

517 518 519
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
                             _("Modify Curves for Channel:"), 1.0, 0.5,
                             hbox, 1, FALSE);
Elliot Lee's avatar
Elliot Lee committed
520 521

  /*  The table for the yrange and the graph  */
522 523 524 525
  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
526
  table = gtk_table_new (2, 2, FALSE);
527 528
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
529
  gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, FALSE, 0);
Elliot Lee's avatar
Elliot Lee committed
530 531 532

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

538 539 540 541 542
  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
543 544
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
545
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
546
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
547 548
		    GTK_SHRINK | GTK_FILL,
		    GTK_SHRINK | GTK_FILL, 0, 0);
549
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
550

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

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

571 572 573 574 575

  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
576 577
  /*  The range drawing area  */
  frame = gtk_frame_new (NULL);
578
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
579 580 581 582
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 1, 2,
		    GTK_EXPAND, GTK_EXPAND, 0, 0);
  gtk_widget_show (frame);

583 584 585 586
  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);
587

588
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
589

590 591 592
  hbox = gtk_hbox_new (FALSE, 6);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);
593

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

599
  hbbox = gtk_hbutton_box_new ();
600
  gtk_container_set_border_width (GTK_CONTAINER (hbbox), 2);
601
  gtk_box_set_spacing (GTK_BOX (hbbox), 4);
602
  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_SPREAD);
603
  gtk_container_add (GTK_CONTAINER (frame), hbbox);
604
  gtk_widget_show (hbbox);
605

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

612
  g_signal_connect (button, "clicked",
613
		    G_CALLBACK (curves_load_callback),
614
		    c_tool);
615

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

622
  g_signal_connect (button, "clicked",
623
		    G_CALLBACK (curves_save_callback),
624
		    c_tool);
625 626 627 628 629 630 631

  /*  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,
632
				  "gimp-curve", GTK_ICON_SIZE_MENU,
633 634 635 636 637 638 639 640 641
				  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
642 643
}

644
static void
645
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
646
{
647
  GimpCurvesTool       *c_tool = GIMP_CURVES_TOOL (image_map_tool);
648
  GimpHistogramChannel  channel;
649 650 651

  c_tool->grab_point = -1;

652 653 654 655
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
    curves_channel_reset (c_tool->curves, channel);
656

657 658
  curves_update (c_tool, XRANGE_TOP);
  gtk_widget_queue_draw (c_tool->graph);
659 660
}

661

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

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

Elliot Lee's avatar
Elliot Lee committed
682 683
  if (update & XRANGE_TOP)
    {
684
      guchar buf[XRANGE_WIDTH * 3];
685

686
      switch (sel_channel)
687
	{
Michael Natterer's avatar
Michael Natterer committed
688 689
	case GIMP_HISTOGRAM_VALUE:
	case GIMP_HISTOGRAM_ALPHA:
690
	  for (i = 0; i < XRANGE_HEIGHT / 2; i++)
691
	    {
692
	      for (j = 0; j < XRANGE_WIDTH ; j++)
693
		{
694 695 696
		  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];
697
		}
698
	      gtk_preview_draw_row (GTK_PREVIEW (c_tool->xrange),
699
				    buf, 0, i, XRANGE_WIDTH);
700
	    }
701 702
	  break;

Michael Natterer's avatar
Michael Natterer committed
703 704 705
	case GIMP_HISTOGRAM_RED:
	case GIMP_HISTOGRAM_GREEN:
	case GIMP_HISTOGRAM_BLUE:
706
	  {
707
	    for (i = 0; i < XRANGE_HEIGHT / 2; i++)
708
	      {
709 710
		for (j = 0; j < XRANGE_WIDTH; j++)
		  {
711 712 713
		    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];
714
		  }
715
		gtk_preview_draw_row (GTK_PREVIEW (c_tool->xrange),
716
				      buf, 0, i, XRANGE_WIDTH);
717
	      }
718
	    break;
719 720
	  }

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

727 728 729
      gtk_widget_queue_draw_area (c_tool->xrange,
                                  0, 0,
                                  XRANGE_WIDTH, XRANGE_HEIGHT / 2);
Elliot Lee's avatar
Elliot Lee committed
730
    }
731

Elliot Lee's avatar
Elliot Lee committed
732 733
  if (update & XRANGE_BOTTOM)
    {
734
      guchar buf[XRANGE_WIDTH * 3];
Elliot Lee's avatar
Elliot Lee committed
735 736

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

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

747 748 749
      gtk_widget_queue_draw_area (c_tool->xrange,
                                  0, XRANGE_HEIGHT / 2,
                                  XRANGE_WIDTH, XRANGE_HEIGHT / 2);
Elliot Lee's avatar
Elliot Lee committed
750
    }
751

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

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

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

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

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

782
	  gtk_preview_draw_row (GTK_PREVIEW (c_tool->yrange),
783
				buf, 0, i, YRANGE_WIDTH);
Elliot Lee's avatar
Elliot Lee committed
784 785
	}

786
      gtk_widget_queue_draw (c_tool->yrange);
Elliot Lee's avatar
Elliot Lee committed
787 788 789 790
    }
}

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

796 797 798 799 800 801
  gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                   c_tool->channel);

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

803 804
  gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (c_tool->curve_type),
			           c_tool->curves->curve_type[c_tool->channel]);
805

806
  curves_update (c_tool, XRANGE_TOP | YRANGE);
Elliot Lee's avatar
Elliot Lee committed
807 808 809
}

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

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

817 818
  curves_update (c_tool, XRANGE_TOP);
  gtk_widget_queue_draw (c_tool->graph);
Elliot Lee's avatar
Elliot Lee committed
819

820
  gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (c_tool));
Elliot Lee's avatar
Elliot Lee committed
821 822
}

823
static gboolean
824 825
curves_set_sensitive_callback (GimpHistogramChannel  channel,
                               GimpCurvesTool       *c_tool)
826 827 828 829 830 831 832 833
{
  switch (channel)
    {
    case GIMP_HISTOGRAM_VALUE:
      return TRUE;
    case GIMP_HISTOGRAM_RED:
    case GIMP_HISTOGRAM_GREEN:
    case GIMP_HISTOGRAM_BLUE:
834
      return c_tool->color;
835
    case GIMP_HISTOGRAM_ALPHA: