gimpcurvestool.c 39.6 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

Sven Neumann's avatar
Sven Neumann committed
26 27
#include <gtk/gtk.h>

28
#include "libgimpbase/gimpbase.h"
29
#include "libgimpcolor/gimpcolor.h"
30
#include "libgimpwidgets/gimpwidgets.h"
31

32
#include "tools-types.h"
Michael Natterer's avatar
Michael Natterer committed
33

34 35
#include "config/gimpbaseconfig.h"

36
#include "base/curves.h"
Michael Natterer's avatar
Michael Natterer committed
37 38 39
#include "base/gimphistogram.h"
#include "base/gimplut.h"

40
#include "core/gimp.h"
Michael Natterer's avatar
Michael Natterer committed
41
#include "core/gimpdrawable.h"
42
#include "core/gimpdrawable-histogram.h"
Michael Natterer's avatar
Michael Natterer committed
43
#include "core/gimpimage.h"
44
#include "core/gimpimagemap.h"
45
#include "core/gimptoolinfo.h"
Michael Natterer's avatar
Michael Natterer committed
46

47
#include "widgets/gimpcolorbar.h"
Michael Natterer's avatar
Michael Natterer committed
48
#include "widgets/gimpcursor.h"
49
#include "widgets/gimpenummenu.h"
50
#include "widgets/gimphelp-ids.h"
51
#include "widgets/gimphistogramview.h"
Michael Natterer's avatar
Michael Natterer committed
52

53 54
#include "display/gimpdisplay.h"

Michael Natterer's avatar
Michael Natterer committed
55
#include "gimpcurvestool.h"
56
#include "gimphistogramoptions.h"
57
#include "gimptoolcontrol.h"
Sven Neumann's avatar
Sven Neumann committed
58

59
#include "gimp-intl.h"
60

61

62 63 64
#define XRANGE   (1 << 0)
#define YRANGE   (1 << 1)
#define ALL      (XRANGE | YRANGE)
Elliot Lee's avatar
Elliot Lee committed
65

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

78 79 80 81 82
#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
83 84


Michael Natterer's avatar
Michael Natterer committed
85 86
/*  local function prototypes  */

87 88 89 90 91 92 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
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);
145

Michael Natterer's avatar
Michael Natterer committed
146

147 148
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
149

150
/*  public functions  */
Michael Natterer's avatar
Michael Natterer committed
151 152

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

169
GType
Michael Natterer's avatar
Michael Natterer committed
170 171
gimp_curves_tool_get_type (void)
{
172
  static GType tool_type = 0;
Michael Natterer's avatar
Michael Natterer committed
173 174 175

  if (! tool_type)
    {
176
      static const GTypeInfo tool_info =
Michael Natterer's avatar
Michael Natterer committed
177 178
      {
        sizeof (GimpCurvesToolClass),
179 180 181 182 183 184 185 186
	(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
187 188
      };

189
      tool_type = g_type_register_static (GIMP_TYPE_IMAGE_MAP_TOOL,
190
					  "GimpCurvesTool",
191
                                          &tool_info, 0);
Michael Natterer's avatar
Michael Natterer committed
192 193 194 195 196
    }

  return tool_type;
}

197 198 199

/*  private functions  */

Michael Natterer's avatar
Michael Natterer committed
200 201 202
static void
gimp_curves_tool_class_init (GimpCurvesToolClass *klass)
{
203 204
  GObjectClass          *object_class;
  GimpToolClass         *tool_class;
205
  GimpColorToolClass    *color_tool_class;
206
  GimpImageMapToolClass *image_map_tool_class;
Michael Natterer's avatar
Michael Natterer committed
207

208 209
  object_class         = G_OBJECT_CLASS (klass);
  tool_class           = GIMP_TOOL_CLASS (klass);
210
  color_tool_class     = GIMP_COLOR_TOOL_CLASS (klass);
211
  image_map_tool_class = GIMP_IMAGE_MAP_TOOL_CLASS (klass);
Michael Natterer's avatar
Michael Natterer committed
212

213
  parent_class = g_type_class_peek_parent (klass);
Michael Natterer's avatar
Michael Natterer committed
214

215
  object_class->finalize       = gimp_curves_tool_finalize;
216

217 218 219 220
  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;
221 222 223 224

  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
225 226 227
}

static void
228
gimp_curves_tool_init (GimpCurvesTool *c_tool)
Michael Natterer's avatar
Michael Natterer committed
229
{
230
  GimpImageMapTool *image_map_tool = GIMP_IMAGE_MAP_TOOL (c_tool);
231 232
  gint              i;

233
  image_map_tool->shell_desc = _("Adjust Color Curves");
234

235 236 237
  c_tool->curves  = g_new0 (Curves, 1);
  c_tool->lut     = gimp_lut_new ();
  c_tool->channel = GIMP_HISTOGRAM_VALUE;
238 239 240

  curves_init (c_tool->curves);

241
  for (i = 0; i < G_N_ELEMENTS (c_tool->col_value); i++)
242
    c_tool->col_value[i] = -1;
243 244 245

  c_tool->cursor_x = -1;
  c_tool->cursor_y = -1;
Michael Natterer's avatar
Michael Natterer committed
246 247 248
}

static void
249
gimp_curves_tool_finalize (GObject *object)
Michael Natterer's avatar
Michael Natterer committed
250
{
251
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (object);
252 253

  if (c_tool->curves)
Michael Natterer's avatar
Michael Natterer committed
254
    {
255
      g_free (c_tool->curves);
256
      c_tool->curves = NULL;
Michael Natterer's avatar
Michael Natterer committed
257
    }
258
  if (c_tool->lut)
Michael Natterer's avatar
Michael Natterer committed
259
    {
260 261
      gimp_lut_free (c_tool->lut);
      c_tool->lut = NULL;
Michael Natterer's avatar
Michael Natterer committed
262
    }
263 264 265 266 267
  if (c_tool->hist)
    {
      gimp_histogram_free (c_tool->hist);
      c_tool->hist = NULL;
    }
268
  if (c_tool->cursor_layout)
Michael Natterer's avatar
Michael Natterer committed
269
    {
270 271
      g_object_unref (c_tool->cursor_layout);
      c_tool->cursor_layout = NULL;
Michael Natterer's avatar
Michael Natterer committed
272
    }
273 274 275 276 277
  if (c_tool->xpos_layout)
    {
      g_object_unref (c_tool->xpos_layout);
      c_tool->xpos_layout = NULL;
    }
Michael Natterer's avatar
Michael Natterer committed
278

279
  G_OBJECT_CLASS (parent_class)->finalize (object);
Michael Natterer's avatar
Michael Natterer committed
280 281
}

282
static gboolean
283 284
gimp_curves_tool_initialize (GimpTool    *tool,
			     GimpDisplay *gdisp)
Michael Natterer's avatar
Michael Natterer committed
285
{
286
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool);
287 288
  GimpDrawable   *drawable;

289 290 291
  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (! drawable)
292
    return FALSE;
293

294
  if (gimp_drawable_is_indexed (drawable))
Michael Natterer's avatar
Michael Natterer committed
295
    {
296
      g_message (_("Curves for indexed layers cannot be adjusted."));
297
      return FALSE;
298
    }
Michael Natterer's avatar
Michael Natterer committed
299

300 301 302 303 304 305 306
  if (! c_tool->hist)
    {
      Gimp *gimp = GIMP_TOOL (c_tool)->tool_info->gimp;

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

307
  curves_init (c_tool->curves);
Michael Natterer's avatar
Michael Natterer committed
308

309
  c_tool->channel = GIMP_HISTOGRAM_VALUE;
310 311
  c_tool->color   = gimp_drawable_is_rgb (drawable);
  c_tool->alpha   = gimp_drawable_has_alpha (drawable);
312 313 314 315 316 317

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

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

318 319 320 321
  /*  always pick colors  */
  gimp_color_tool_enable (GIMP_COLOR_TOOL (tool),
                          GIMP_COLOR_OPTIONS (tool->tool_info->tool_options));

322
  /* set the sensitivity of the channel menu based on the drawable type */
323 324 325
  gimp_int_option_menu_set_sensitive (GTK_OPTION_MENU (c_tool->channel_menu),
                                      (GimpIntOptionMenuSensitivityCallback) curves_set_sensitive_callback,
                                      c_tool);
326 327

  /* set the current selection */
328 329
  gimp_int_option_menu_set_history (GTK_OPTION_MENU (c_tool->channel_menu),
                                    c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
330

331 332 333
  if (! c_tool->color && c_tool->alpha)
    c_tool->channel = 1;

334
  curves_update (c_tool, ALL);
335 336 337 338

  gimp_drawable_calculate_histogram (drawable, c_tool->hist);
  gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                     c_tool->hist);
339 340

  return TRUE;
Michael Natterer's avatar
Michael Natterer committed
341 342 343
}

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

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

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

364 365 366 367 368
      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
369 370
    }

371 372 373
  /*  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
374 375 376
}

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

386 387
  c_tool = GIMP_CURVES_TOOL (color_tool);
  drawable = GIMP_IMAGE_MAP_TOOL (c_tool)->drawable;
388

389
  gimp_rgba_get_uchar (color, &r, &g, &b, &a);
390

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

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

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

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

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

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

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

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

434 435
      if (distance > MIN_DISTANCE)
	closest_point = (curvex + 8) / 16;
436

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

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

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

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

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

462

463 464 465
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
466

467 468
static void
gimp_curves_tool_dialog (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
469
{
470 471 472 473 474 475 476 477 478
  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;
479 480
  GtkWidget       *vbox2;
  GtkWidget       *bar;
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
  gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
511
  gtk_widget_show (button);
512

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

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

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

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

537 538
  c_tool->yrange = gimp_color_bar_new (GTK_ORIENTATION_VERTICAL);
  gtk_widget_set_size_request (c_tool->yrange, YRANGE_WIDTH, YRANGE_HEIGHT);
539 540 541
  gtk_container_add (GTK_CONTAINER (frame), c_tool->yrange);
  gtk_widget_show (c_tool->yrange);

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

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

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

570 571 572 573 574

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

582 583 584 585 586 587 588 589
  vbox2 = gtk_vbox_new (TRUE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox2);
  gtk_widget_show (vbox2);

  c_tool->xrange = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_widget_set_size_request (c_tool->xrange,
                               XRANGE_WIDTH, XRANGE_HEIGHT / 2);
  gtk_box_pack_start (GTK_BOX (vbox2), c_tool->xrange, TRUE, TRUE, 0);
590
  gtk_widget_show (c_tool->xrange);
591

592 593 594 595
  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_box_pack_start (GTK_BOX (vbox2), bar, TRUE, TRUE, 0);
  gtk_widget_show (bar);

596
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
597

598 599 600
  hbox = gtk_hbox_new (FALSE, 6);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);
601

602
  /*  Horizontal button box for load / save */
603
  frame = gtk_frame_new (_("All Channels"));
604
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
605 606
  gtk_widget_show (frame);

607
  hbbox = gtk_hbutton_box_new ();
608
  gtk_container_set_border_width (GTK_CONTAINER (hbbox), 2);
609
  gtk_box_set_spacing (GTK_BOX (hbbox), 4);
610
  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_SPREAD);
611
  gtk_container_add (GTK_CONTAINER (frame), hbbox);
612
  gtk_widget_show (hbbox);
613

614
  button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
615 616
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
617
  gimp_help_set_help_data (button, _("Read curves settings from file"), NULL);
618 619
  gtk_widget_show (button);

620
  g_signal_connect (button, "clicked",
621
		    G_CALLBACK (curves_load_callback),
622
		    c_tool);
623

624
  button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
625 626
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
627
  gimp_help_set_help_data (button, _("Save curves settings to file"), NULL);
628 629
  gtk_widget_show (button);

630
  g_signal_connect (button, "clicked",
631
		    G_CALLBACK (curves_save_callback),
632
		    c_tool);
633 634 635 636 637 638 639

  /*  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,
640
				  "gimp-curve", GTK_ICON_SIZE_MENU,
641 642 643 644 645 646 647 648 649
				  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
650 651
}

652
static void
653
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
654
{
655
  GimpCurvesTool       *c_tool = GIMP_CURVES_TOOL (image_map_tool);
656
  GimpHistogramChannel  channel;
657 658 659

  c_tool->grab_point = -1;

660 661 662 663
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
    curves_channel_reset (c_tool->curves, channel);
664

665
  curves_update (c_tool, XRANGE);
666
  gtk_widget_queue_draw (c_tool->graph);
667 668
}

669

670
/* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
Elliot Lee's avatar
Elliot Lee committed
671
static void
672 673
curves_update (GimpCurvesTool *c_tool,
	       gint            update)
Elliot Lee's avatar
Elliot Lee committed
674
{
675
  GimpHistogramChannel channel;
676

677
  if (c_tool->color)
678
    {
679
      channel = c_tool->channel;
680
    }
681
  else
682
    {
683
      if (c_tool->channel == 2)
684
        channel = GIMP_HISTOGRAM_ALPHA;
685
      else
686
        channel = GIMP_HISTOGRAM_VALUE;
687
    }
688

689
  if (update & XRANGE)
Elliot Lee's avatar
Elliot Lee committed
690
    {
691
      switch (channel)
692
	{
Michael Natterer's avatar
Michael Natterer committed
693 694
	case GIMP_HISTOGRAM_VALUE:
	case GIMP_HISTOGRAM_ALPHA:
695 696 697 698
          gimp_color_bar_set_buffers (GIMP_COLOR_BAR (c_tool->xrange),
                                      c_tool->curves->curve[channel],
                                      c_tool->curves->curve[channel],
                                      c_tool->curves->curve[channel]);
699 700
	  break;

Michael Natterer's avatar
Michael Natterer committed
701 702 703
	case GIMP_HISTOGRAM_RED:
	case GIMP_HISTOGRAM_GREEN:
	case GIMP_HISTOGRAM_BLUE:
704 705 706 707
          gimp_color_bar_set_buffers (GIMP_COLOR_BAR (c_tool->xrange),
                                      c_tool->curves->curve[GIMP_HISTOGRAM_RED],
                                      c_tool->curves->curve[GIMP_HISTOGRAM_GREEN],
                                      c_tool->curves->curve[GIMP_HISTOGRAM_BLUE]);
708
	  break;
709
	}
Elliot Lee's avatar
Elliot Lee committed
710
    }
711

Elliot Lee's avatar
Elliot Lee committed
712 713
  if (update & YRANGE)
    {
714
      gimp_color_bar_set_channel (GIMP_COLOR_BAR (c_tool->yrange), channel);
Elliot Lee's avatar
Elliot Lee committed
715 716 717 718
    }
}

static void
719 720
curves_channel_callback (GtkWidget      *widget,
			 GimpCurvesTool *c_tool)
Elliot Lee's avatar
Elliot Lee committed
721
{
722
  gimp_menu_item_update (widget, &c_tool->channel);
Elliot Lee's avatar
Elliot Lee committed
723

724 725 726 727
  gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                   c_tool->channel);

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

731 732
  gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (c_tool->curve_type),
			           c_tool->curves->curve_type[c_tool->channel]);
733

734
  curves_update (c_tool, ALL);
Elliot Lee's avatar
Elliot Lee committed
735 736 737
}

static void
738 739
curves_channel_reset_callback (GtkWidget      *widget,
                               GimpCurvesTool *c_tool)
Elliot Lee's avatar
Elliot Lee committed
740
{
741
  c_tool->grab_point = -1;
Elliot Lee's avatar
Elliot Lee committed
742

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

745
  curves_update (c_tool, XRANGE);
746
  gtk_widget_queue_draw (c_tool->graph);
Elliot Lee's avatar
Elliot Lee committed
747

748
  gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (c_tool));
Elliot Lee's avatar
Elliot Lee committed
749 750
}

751
static gboolean
752 753
curves_set_sensitive_callback (GimpHistogramChannel  channel,
                               GimpCurvesTool       *c_tool)
754 755 756 757 758
{
  switch (channel)
    {
    case GIMP_HISTOGRAM_VALUE:
      return TRUE;
759

760 761 762
    case GIMP_HISTOGRAM_RED:
    case GIMP_HISTOGRAM_GREEN:
    case GIMP_HISTOGRAM_BLUE:
763
      return c_tool->color;
764

765
    case GIMP_HISTOGRAM_ALPHA:
766
      return gimp_drawable_has_alpha (GIMP_IMAGE_MAP_TOOL (c_tool)->drawable);
767
    }
768

769 770 771
  return FALSE;
}

Elliot Lee's avatar
Elliot Lee committed
772
static void
773 774
curves_curve_type_callback (GtkWidget      *widget,
			    GimpCurvesTool *c_tool)
Elliot Lee's avatar
Elliot Lee committed
775
{
776
  GimpCurveType curve_type;
Elliot Lee's avatar
Elliot Lee committed
777

778
  gimp_radio_button_update (widget, &curve_type);
Elliot Lee's avatar
Elliot Lee committed
779

780
  if (c_tool->curves->curve_type[c_tool->channel] != curve_type)
Elliot Lee's avatar
Elliot Lee committed
781
    {
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
      c_tool->curves->curve_type[c_tool->channel] = curve_type;

      if (curve_type == GIMP_CURVE_SMOOTH)
        {
          gint   i;
          gint32 index;

          /*  pick representative points from the curve
           *  and make them control points
           */
          for (i = 0; i <= 8; i++)
            {
              index = CLAMP0255 (i * 32);
              c_tool->curves->points[c_tool->channel][i * 2][0] = index;
              c_tool->curves->points[c_tool->channel][i * 2][1] = c_tool->curves->curve[c_tool->channel][index];
            }
        }
799

800
      curves_calculate_curve (c_tool->curves, c_tool->channel);
801

802
      curves_update (c_tool, XRANGE);
803
      gtk_widget_queue_draw (c_tool->graph);
Elliot Lee's avatar
Elliot Lee committed
804

805
      gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (c_tool));
806
    }
Elliot Lee's avatar
Elliot Lee committed
807 808
}

809 810 811 812
static gboolean
curves_graph_events (GtkWidget      *widget,
		     GdkEvent       *event,
		     GimpCurvesTool *c_tool)
Elliot Lee's avatar
Elliot Lee committed
813 814
{
  static GdkCursorType cursor_type = GDK_TOP_LEFT_ARROW;
815

816
  GdkCursorType   new_cursor = GDK_X_CURSOR;
Elliot Lee's avatar
Elliot Lee committed
817 818
  GdkEventButton *bevent;
  GdkEventMotion *mevent;
819 820 821 822 823 824
  gint            i;
  gint            tx, ty;
  gint            x, y;
  gint            closest_point;
  gint            distance;
  gint            x1, x2, y1, y2;
Elliot Lee's avatar
Elliot Lee committed
825 826

  /*  get the pointer position  */
827
  gdk_window_get_pointer (c_tool->graph->window, &tx, &ty, NULL);
828 829
  x = CLAMP ((tx - RADIUS), 0, 255);
  y = CLAMP ((ty - RADIUS), 0, 255);
Elliot Lee's avatar
Elliot Lee committed
830 831

  distance = G_MAXINT;
832
  for (i = 0, closest_point = 0; i < 17; i++)
Elliot Lee's avatar
Elliot Lee committed
833
    {
834 835
      if (c_tool->curves->points[c_tool->channel][i][0] != -1)
	if (abs (x - c_tool->curves->points[c_tool->channel][i][0]) < distance)
Elliot Lee's avatar
Elliot Lee committed
836
	  {