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

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

27
#include "libgimpcolor/gimpcolor.h"
28
#include "libgimpwidgets/gimpwidgets.h"
29

30
#include "tools-types.h"
Michael Natterer's avatar
Michael Natterer committed
31

32 33
#include "config/gimpbaseconfig.h"

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

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

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

51 52
#include "display/gimpdisplay.h"

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

57
#include "gimp-intl.h"
58

59

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

65 66 67 68
#define GRAPH_SIZE    256
#define BAR_SIZE       12
#define RADIUS          3
#define MIN_DISTANCE    8
Elliot Lee's avatar
Elliot Lee committed
69 70


Michael Natterer's avatar
Michael Natterer committed
71 72
/*  local function prototypes  */

73
static void     gimp_curves_tool_class_init     (GimpCurvesToolClass *klass);
74
static void     gimp_curves_tool_init           (GimpCurvesTool      *tool);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

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);
93 94 95 96
static gboolean gimp_curves_tool_settings_load  (GimpImageMapTool *image_map_tool,
                                                 gpointer          fp);
static gboolean gimp_curves_tool_settings_save  (GimpImageMapTool *image_map_tool,
                                                 gpointer          fp);
97

98
static void     curves_add_point                (GimpCurvesTool   *tool,
99 100 101 102
                                                 gint              x,
                                                 gint              y,
                                                 gint              cchan);

103
static void     curves_update                   (GimpCurvesTool   *tool,
104 105 106
                                                 gint              update);

static void     curves_channel_callback         (GtkWidget        *widget,
107
                                                 GimpCurvesTool   *tool);
108
static void     curves_channel_reset_callback   (GtkWidget        *widget,
109
                                                 GimpCurvesTool   *tool);
110 111

static gboolean curves_set_sensitive_callback   (GimpHistogramChannel channel,
112
                                                 GimpCurvesTool   *tool);
113
static void     curves_curve_type_callback      (GtkWidget        *widget,
114
                                                 GimpCurvesTool   *tool);
115 116
static gboolean curves_graph_events             (GtkWidget        *widget,
                                                 GdkEvent         *event,
117
                                                 GimpCurvesTool   *tool);
118 119
static gboolean curves_graph_expose             (GtkWidget        *widget,
                                                 GdkEventExpose   *eevent,
120
                                                 GimpCurvesTool   *tool);
121

Michael Natterer's avatar
Michael Natterer committed
122

123 124
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
125

126
/*  public functions  */
Michael Natterer's avatar
Michael Natterer committed
127 128

void
Nate Summers's avatar
Nate Summers committed
129
gimp_curves_tool_register (GimpToolRegisterCallback  callback,
130
                           gpointer                  data)
Michael Natterer's avatar
Michael Natterer committed
131
{
Nate Summers's avatar
Nate Summers committed
132
  (* callback) (GIMP_TYPE_CURVES_TOOL,
133
                GIMP_TYPE_HISTOGRAM_OPTIONS,
134
                gimp_color_options_gui,
135
                0,
136
                "gimp-curves-tool",
137 138
                _("Curves"),
                _("Adjust color curves"),
139
                N_("/Tools/Color Tools/_Curves..."), NULL,
140
                NULL, GIMP_HELP_TOOL_CURVES,
Nate Summers's avatar
Nate Summers committed
141
                GIMP_STOCK_TOOL_CURVES,
142
                data);
Michael Natterer's avatar
Michael Natterer committed
143 144
}

145
GType
Michael Natterer's avatar
Michael Natterer committed
146 147
gimp_curves_tool_get_type (void)
{
148
  static GType tool_type = 0;
Michael Natterer's avatar
Michael Natterer committed
149 150 151

  if (! tool_type)
    {
152
      static const GTypeInfo tool_info =
Michael Natterer's avatar
Michael Natterer committed
153 154
      {
        sizeof (GimpCurvesToolClass),
155 156 157 158 159 160 161 162
	(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
163 164
      };

165
      tool_type = g_type_register_static (GIMP_TYPE_IMAGE_MAP_TOOL,
166
					  "GimpCurvesTool",
167
                                          &tool_info, 0);
Michael Natterer's avatar
Michael Natterer committed
168 169 170 171 172
    }

  return tool_type;
}

173 174 175

/*  private functions  */

Michael Natterer's avatar
Michael Natterer committed
176 177 178
static void
gimp_curves_tool_class_init (GimpCurvesToolClass *klass)
{
179 180
  GObjectClass          *object_class;
  GimpToolClass         *tool_class;
181
  GimpColorToolClass    *color_tool_class;
182
  GimpImageMapToolClass *image_map_tool_class;
Michael Natterer's avatar
Michael Natterer committed
183

184 185
  object_class         = G_OBJECT_CLASS (klass);
  tool_class           = GIMP_TOOL_CLASS (klass);
186
  color_tool_class     = GIMP_COLOR_TOOL_CLASS (klass);
187
  image_map_tool_class = GIMP_IMAGE_MAP_TOOL_CLASS (klass);
Michael Natterer's avatar
Michael Natterer committed
188

189
  parent_class = g_type_class_peek_parent (klass);
Michael Natterer's avatar
Michael Natterer committed
190

191 192 193 194 195 196
  object_class->finalize     = gimp_curves_tool_finalize;

  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;
197

198 199 200 201
  image_map_tool_class->shell_desc        = _("Adjust Color Curves");
  image_map_tool_class->settings_name     = "curves";
  image_map_tool_class->load_dialog_title = _("Load Curves");
  image_map_tool_class->save_dialog_title = _("Save Curves");
202

203 204 205
  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;
206

207 208
  image_map_tool_class->settings_load     = gimp_curves_tool_settings_load;
  image_map_tool_class->settings_save     = gimp_curves_tool_settings_save;
Michael Natterer's avatar
Michael Natterer committed
209 210 211
}

static void
212
gimp_curves_tool_init (GimpCurvesTool *tool)
Michael Natterer's avatar
Michael Natterer committed
213
{
214
  gint i;
215

216 217 218
  tool->curves  = g_new0 (Curves, 1);
  tool->lut     = gimp_lut_new ();
  tool->channel = GIMP_HISTOGRAM_VALUE;
219

220
  curves_init (tool->curves);
221

222 223
  for (i = 0; i < G_N_ELEMENTS (tool->col_value); i++)
    tool->col_value[i] = -1;
224

225 226
  tool->cursor_x = -1;
  tool->cursor_y = -1;
Michael Natterer's avatar
Michael Natterer committed
227 228 229
}

static void
230
gimp_curves_tool_finalize (GObject *object)
Michael Natterer's avatar
Michael Natterer committed
231
{
232
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (object);
233

234
  if (tool->curves)
Michael Natterer's avatar
Michael Natterer committed
235
    {
236 237
      g_free (tool->curves);
      tool->curves = NULL;
Michael Natterer's avatar
Michael Natterer committed
238
    }
239
  if (tool->lut)
Michael Natterer's avatar
Michael Natterer committed
240
    {
241 242
      gimp_lut_free (tool->lut);
      tool->lut = NULL;
Michael Natterer's avatar
Michael Natterer committed
243
    }
244
  if (tool->hist)
245
    {
246 247
      gimp_histogram_free (tool->hist);
      tool->hist = NULL;
248
    }
249
  if (tool->cursor_layout)
Michael Natterer's avatar
Michael Natterer committed
250
    {
251 252
      g_object_unref (tool->cursor_layout);
      tool->cursor_layout = NULL;
Michael Natterer's avatar
Michael Natterer committed
253
    }
254
  if (tool->xpos_layout)
255
    {
256 257
      g_object_unref (tool->xpos_layout);
      tool->xpos_layout = NULL;
258
    }
Michael Natterer's avatar
Michael Natterer committed
259

260
  G_OBJECT_CLASS (parent_class)->finalize (object);
Michael Natterer's avatar
Michael Natterer committed
261 262
}

263
static gboolean
264 265
gimp_curves_tool_initialize (GimpTool    *tool,
			     GimpDisplay *gdisp)
Michael Natterer's avatar
Michael Natterer committed
266
{
267
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool);
268 269
  GimpDrawable   *drawable;

270 271 272
  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (! drawable)
273
    return FALSE;
274

275
  if (gimp_drawable_is_indexed (drawable))
Michael Natterer's avatar
Michael Natterer committed
276
    {
277
      g_message (_("Curves for indexed layers cannot be adjusted."));
278
      return FALSE;
279
    }
Michael Natterer's avatar
Michael Natterer committed
280

281 282 283 284 285 286 287
  if (! c_tool->hist)
    {
      Gimp *gimp = GIMP_TOOL (c_tool)->tool_info->gimp;

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

288
  curves_init (c_tool->curves);
Michael Natterer's avatar
Michael Natterer committed
289

290
  c_tool->channel = GIMP_HISTOGRAM_VALUE;
291 292
  c_tool->color   = gimp_drawable_is_rgb (drawable);
  c_tool->alpha   = gimp_drawable_has_alpha (drawable);
293 294 295 296 297 298

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

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

299 300 301 302
  /*  always pick colors  */
  gimp_color_tool_enable (GIMP_COLOR_TOOL (tool),
                          GIMP_COLOR_OPTIONS (tool->tool_info->tool_options));

303
  /* set the sensitivity of the channel menu based on the drawable type */
304 305 306
  gimp_int_option_menu_set_sensitive (GTK_OPTION_MENU (c_tool->channel_menu),
                                      (GimpIntOptionMenuSensitivityCallback) curves_set_sensitive_callback,
                                      c_tool);
307 308

  /* set the current selection */
309 310
  gimp_int_option_menu_set_history (GTK_OPTION_MENU (c_tool->channel_menu),
                                    c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
311

312 313 314
  if (! c_tool->color && c_tool->alpha)
    c_tool->channel = 1;

315 316 317
  gimp_drawable_calculate_histogram (drawable, c_tool->hist);
  gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                     c_tool->hist);
318

319 320
  curves_update (c_tool, ALL);

321
  return TRUE;
Michael Natterer's avatar
Michael Natterer committed
322 323 324
}

static void
325 326 327 328 329
gimp_curves_tool_button_release (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 guint32          time,
				 GdkModifierType  state,
				 GimpDisplay     *gdisp)
Michael Natterer's avatar
Michael Natterer committed
330
{
331
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool);
332
  GimpDrawable   *drawable;
Michael Natterer's avatar
Michael Natterer committed
333

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

336
  if (state & GDK_SHIFT_MASK)
Michael Natterer's avatar
Michael Natterer committed
337
    {
338
      curves_add_point (c_tool, coords->x, coords->y, c_tool->channel);
339
      curves_calculate_curve (c_tool->curves, c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
340
    }
341
  else if (state & GDK_CONTROL_MASK)
Michael Natterer's avatar
Michael Natterer committed
342
    {
343
      gint i;
344

345 346 347 348 349
      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
350 351
    }

352 353 354
  /*  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
355 356 357
}

static void
358 359 360 361
gimp_curves_tool_color_picked (GimpColorTool *color_tool,
			       GimpImageType  sample_type,
			       GimpRGB       *color,
			       gint           color_index)
Michael Natterer's avatar
Michael Natterer committed
362
{
363
  GimpCurvesTool *tool;
364
  GimpDrawable   *drawable;
365
  guchar          r, g, b, a;
Michael Natterer's avatar
Michael Natterer committed
366

367 368
  tool = GIMP_CURVES_TOOL (color_tool);
  drawable = GIMP_IMAGE_MAP_TOOL (tool)->drawable;
369

370
  gimp_rgba_get_uchar (color, &r, &g, &b, &a);
371

372 373 374
  tool->col_value[GIMP_HISTOGRAM_RED]   = r;
  tool->col_value[GIMP_HISTOGRAM_GREEN] = g;
  tool->col_value[GIMP_HISTOGRAM_BLUE]  = b;
375

376
  if (gimp_drawable_has_alpha (drawable))
377
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = a;
378

379
  if (gimp_drawable_is_indexed (drawable))
380
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = color_index;
381

382
  tool->col_value[GIMP_HISTOGRAM_VALUE] = MAX (MAX (r, g), b);
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
383

384
  curves_update (tool, GRAPH);
385
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
386

387
static void
388
curves_add_point (GimpCurvesTool *tool,
389 390 391
		  gint            x,
		  gint            y,
		  gint            cchan)
392 393
{
  /* Add point onto the curve */
394 395 396 397
  gint closest_point = 0;
  gint distance;
  gint curvex;
  gint i;
398

399
  switch (tool->curves->curve_type[cchan])
400
    {
401
    case GIMP_CURVE_SMOOTH:
402
      curvex   = tool->col_value[cchan];
403
      distance = G_MAXINT;
404

405 406
      for (i = 0; i < 17; i++)
	{
407 408
	  if (tool->curves->points[cchan][i][0] != -1)
	    if (abs (curvex - tool->curves->points[cchan][i][0]) < distance)
409
	      {
410
		distance = abs (curvex - tool->curves->points[cchan][i][0]);
411 412 413
		closest_point = i;
	      }
	}
414

415 416
      if (distance > MIN_DISTANCE)
	closest_point = (curvex + 8) / 16;
417

418 419
      tool->curves->points[cchan][closest_point][0] = curvex;
      tool->curves->points[cchan][closest_point][1] = tool->curves->curve[cchan][curvex];
420
      break;
421

422
    case GIMP_CURVE_FREE:
423
      tool->curves->curve[cchan][x] = 255 - y;
424
      break;
425
    }
Elliot Lee's avatar
Elliot Lee committed
426 427
}

428 429
static void
gimp_curves_tool_map (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
430
{
431
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
432

433
  gimp_lut_setup (tool->lut,
434
		  (GimpLutFunc) curves_lut_func,
435
                  tool->curves,
436
		  gimp_drawable_bytes (image_map_tool->drawable));
437

438 439
  gimp_image_map_apply (image_map_tool->image_map,
                        (GimpImageMapApplyFunc) gimp_lut_process_2,
440
                        tool->lut);
Elliot Lee's avatar
Elliot Lee committed
441 442
}

443

444 445 446
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
447

448 449
static void
gimp_curves_tool_dialog (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
450
{
451
  GimpCurvesTool  *tool = GIMP_CURVES_TOOL (image_map_tool);
452 453
  GimpToolOptions *tool_options;
  GtkWidget       *vbox;
454 455 456 457 458
  GtkWidget       *vbox2;
  GtkWidget       *hbox;
  GtkWidget       *hbox2;
  GtkWidget       *label;
  GtkWidget       *bbox;
459 460 461 462
  GtkWidget       *frame;
  GtkWidget       *menu;
  GtkWidget       *table;
  GtkWidget       *button;
463
  GtkWidget       *bar;
464
  gint             padding;
465

466
  vbox = image_map_tool->main_vbox;
Elliot Lee's avatar
Elliot Lee committed
467

468 469
  /*  The option menu for selecting channels  */
  hbox = gtk_hbox_new (FALSE, 4);
470 471 472 473 474 475 476
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

  label = gtk_label_new (_("Channel:"));
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

477 478
  menu = gimp_enum_option_menu_new (GIMP_TYPE_HISTOGRAM_CHANNEL,
                                    G_CALLBACK (curves_channel_callback),
479
                                    tool);
480 481 482 483 484
  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);

485
  tool->channel_menu = menu;
486

487
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
488
  gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
489
  gtk_widget_show (button);
490

491
  g_signal_connect (button, "clicked",
492
                    G_CALLBACK (curves_channel_reset_callback),
493
                    tool);
Elliot Lee's avatar
Elliot Lee committed
494

495

496
  /*  The table for the color bars and the graph  */
Elliot Lee's avatar
Elliot Lee committed
497
  table = gtk_table_new (2, 2, FALSE);
498 499
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
500 501 502 503 504 505 506
  gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);

  /*  The left color bar  */
  vbox2 = gtk_vbox_new (FALSE, 0);
  gtk_table_attach (GTK_TABLE (table), vbox2, 0, 1, 0, 1,
		    GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  gtk_widget_show (vbox2);
Elliot Lee's avatar
Elliot Lee committed
507 508

  frame = gtk_frame_new (NULL);
509
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
510
  gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
511 512
  gtk_widget_show (frame);

513 514 515 516
  tool->yrange = gimp_color_bar_new (GTK_ORIENTATION_VERTICAL);
  gtk_widget_set_size_request (tool->yrange, BAR_SIZE, -1);
  gtk_container_add (GTK_CONTAINER (frame), tool->yrange);
  gtk_widget_show (tool->yrange);
517

Elliot Lee's avatar
Elliot Lee committed
518 519
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
520
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
521
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
522
		    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
523
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
524

525 526 527 528 529 530 531 532 533
  tool->graph = gimp_histogram_view_new (FALSE);
  gtk_widget_set_size_request (tool->graph,
                               GRAPH_SIZE + RADIUS * 2,
                               GRAPH_SIZE + RADIUS * 2);
  gtk_widget_add_events (tool->graph, (GDK_BUTTON_PRESS_MASK   |
                                       GDK_BUTTON_RELEASE_MASK |
                                       GDK_POINTER_MOTION_MASK |
                                       GDK_LEAVE_NOTIFY_MASK));
  g_object_set (tool->graph,
534 535 536
                "border-width", RADIUS,
                "subdivisions", 1,
                NULL);
537 538 539
  GIMP_HISTOGRAM_VIEW (tool->graph)->light_histogram = TRUE;
  gtk_container_add (GTK_CONTAINER (frame), tool->graph);
  gtk_widget_show (tool->graph);
540

541
  g_signal_connect (tool->graph, "event",
542
		    G_CALLBACK (curves_graph_events),
543 544
		    tool);
  g_signal_connect_after (tool->graph, "expose_event",
545
                          G_CALLBACK (curves_graph_expose),
546
                          tool);
Elliot Lee's avatar
Elliot Lee committed
547

548

549
  tool_options = GIMP_TOOL (tool)->tool_info->tool_options;
550
  gimp_histogram_options_connect_view (GIMP_HISTOGRAM_OPTIONS (tool_options),
551 552 553 554 555 556 557
                                       GIMP_HISTOGRAM_VIEW (tool->graph));

  /*  The bottom color bar  */
  hbox2 = gtk_hbox_new (FALSE, 0);
  gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2,
		    GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
  gtk_widget_show (hbox2);
558

Elliot Lee's avatar
Elliot Lee committed
559
  frame = gtk_frame_new (NULL);
560
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
561
  gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
562 563
  gtk_widget_show (frame);

564 565 566 567
  vbox2 = gtk_vbox_new (TRUE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox2);
  gtk_widget_show (vbox2);

568 569 570 571
  tool->xrange = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_widget_set_size_request (tool->xrange, -1, BAR_SIZE / 2);
  gtk_box_pack_start (GTK_BOX (vbox2), tool->xrange, TRUE, TRUE, 0);
  gtk_widget_show (tool->xrange);
572

573 574 575 576
  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_box_pack_start (GTK_BOX (vbox2), bar, TRUE, TRUE, 0);
  gtk_widget_show (bar);

577
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
578

579

580 581 582
  hbox = gtk_hbox_new (FALSE, 6);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);
583

584
  /*  Horizontal button box for load / save */
585
  frame = gtk_frame_new (_("All Channels"));
586
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
587 588
  gtk_widget_show (frame);

589 590 591 592 593 594
  bbox = gtk_hbutton_box_new ();
  gtk_container_set_border_width (GTK_CONTAINER (bbox), 2);
  gtk_box_set_spacing (GTK_BOX (bbox), 4);
  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
  gtk_container_add (GTK_CONTAINER (frame), bbox);
  gtk_widget_show (bbox);
595

596 597 598 599 600
  gtk_box_pack_start (GTK_BOX (bbox), image_map_tool->load_button,
                      FALSE, FALSE, 0);
  gimp_help_set_help_data (image_map_tool->load_button,
                           _("Read curves settings from file"), NULL);
  gtk_widget_show (image_map_tool->load_button);
601

602 603 604 605 606
  gtk_box_pack_start (GTK_BOX (bbox), image_map_tool->save_button,
                      FALSE, FALSE, 0);
  gimp_help_set_help_data (image_map_tool->save_button,
                           _("Save curves settings to file"), NULL);
  gtk_widget_show (image_map_tool->save_button);
607 608 609 610 611 612 613

  /*  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,
614
				  "gimp-curve", GTK_ICON_SIZE_MENU,
615
				  G_CALLBACK (curves_curve_type_callback),
616 617 618 619 620 621
				  tool,
				  &tool->curve_type);

  gtk_widget_style_get (bbox, "child_internal_pad_x", &padding, NULL);

  gimp_enum_stock_box_set_child_padding (hbox, padding, -1);
622 623 624 625 626 627

  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
628 629
}

630
static void
631
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
632
{
633
  GimpCurvesTool       *tool = GIMP_CURVES_TOOL (image_map_tool);
634
  GimpHistogramChannel  channel;
635

636
  tool->grab_point = -1;
637

638 639 640
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
641
    curves_channel_reset (tool->curves, channel);
642

643
  curves_update (tool, XRANGE | GRAPH);
644 645
}

646
static gboolean
647 648
gimp_curves_tool_settings_load (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
649
{
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
  FILE           *file = fp;
  gint            i, j;
  gint            fields;
  gchar           buf[50];
  gint            index[5][17];
  gint            value[5][17];

  if (! fgets (buf, sizeof (buf), file))
    return FALSE;

  if (strcmp (buf, "# GIMP Curves File\n") != 0)
    return FALSE;

  for (i = 0; i < 5; i++)
    {
      for (j = 0; j < 17; j++)
	{
	  fields = fscanf (file, "%d %d ", &index[i][j], &value[i][j]);
	  if (fields != 2)
	    {
	      g_print ("fields != 2");
	      return FALSE;
	    }
	}
    }

  for (i = 0; i < 5; i++)
    {
      tool->curves->curve_type[i] = GIMP_CURVE_SMOOTH;

      for (j = 0; j < 17; j++)
	{
	  tool->curves->points[i][j][0] = index[i][j];
	  tool->curves->points[i][j][1] = value[i][j];
	}
    }

  for (i = 0; i < 5; i++)
    curves_calculate_curve (tool->curves, i);

  curves_update (tool, ALL);

  gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (tool->curve_type),
			           GIMP_CURVE_SMOOTH);

  return TRUE;
697 698 699
}

static gboolean
700 701
gimp_curves_tool_settings_save (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
702
{
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
  FILE           *file = fp;
  gint            i, j;
  gint32          index;

  for (i = 0; i < 5; i++)
    if (tool->curves->curve_type[i] == GIMP_CURVE_FREE)
      {
	/*  pick representative points from the curve
            and make them control points  */
	for (j = 0; j <= 8; j++)
	  {
	    index = CLAMP0255 (j * 32);
	    tool->curves->points[i][j * 2][0] = index;
	    tool->curves->points[i][j * 2][1] = tool->curves->curve[i][index];
	  }
      }

  fprintf (file, "# GIMP Curves File\n");

  for (i = 0; i < 5; i++)
    {
      for (j = 0; j < 17; j++)
	fprintf (file, "%d %d ",
                 tool->curves->points[i][j][0],
                 tool->curves->points[i][j][1]);

      fprintf (file, "\n");
    }

  return TRUE;
734
}
735

736
/* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
Elliot Lee's avatar
Elliot Lee committed
737
static void
738
curves_update (GimpCurvesTool *tool,
739
	       gint            update)
Elliot Lee's avatar
Elliot Lee committed
740
{
741
  GimpHistogramChannel channel;
742

743
  if (tool->color)
744
    {
745
      channel = tool->channel;
746
    }
747
  else
748
    {
749
      if (tool->channel == 2)
750
        channel = GIMP_HISTOGRAM_ALPHA;
751
      else
752
        channel = GIMP_HISTOGRAM_VALUE;
753
    }
754

755 756 757
  if (update & GRAPH)
    gtk_widget_queue_draw (tool->graph);

758
  if (update & XRANGE)
Elliot Lee's avatar
Elliot Lee committed
759
    {
760
      switch (channel)
761
	{
Michael Natterer's avatar
Michael Natterer committed
762 763
	case GIMP_HISTOGRAM_VALUE:
	case GIMP_HISTOGRAM_ALPHA:
764 765 766 767
          gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->xrange),
                                      tool->curves->curve[channel],
                                      tool->curves->curve[channel],
                                      tool->curves->curve[channel]);
768 769
	  break;

Michael Natterer's avatar
Michael Natterer committed
770 771 772
	case GIMP_HISTOGRAM_RED:
	case GIMP_HISTOGRAM_GREEN:
	case GIMP_HISTOGRAM_BLUE:
773 774 775 776
          gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->xrange),
                                      tool->curves->curve[GIMP_HISTOGRAM_RED],
                                      tool->curves->curve[GIMP_HISTOGRAM_GREEN],
                                      tool->curves->curve[GIMP_HISTOGRAM_BLUE]);
777
	  break;
778
	}
Elliot Lee's avatar
Elliot Lee committed
779
    }
780

Elliot Lee's avatar
Elliot Lee committed
781 782
  if (update & YRANGE)
    {
783
      gimp_color_bar_set_channel (GIMP_COLOR_BAR (tool->yrange), channel);
Elliot Lee's avatar
Elliot Lee committed
784 785 786 787
    }
}

static void
788
curves_channel_callback (GtkWidget      *widget,
789
			 GimpCurvesTool *tool)
Elliot Lee's avatar
Elliot Lee committed
790
{
791
  gimp_menu_item_update (widget, &tool->channel);
Elliot Lee's avatar
Elliot Lee committed
792

793 794
  gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (tool->graph),
                                   tool->channel);
795 796

  /* FIXME: hack */
797 798
  if (! tool->color && tool->alpha)
    tool->channel = (tool->channel > 1) ? 2 : 1;
Elliot Lee's avatar
Elliot Lee committed
799

800 801
  gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (tool->curve_type),
			           tool->curves->curve_type[tool->channel]);
802

803
  curves_update (tool, ALL);
Elliot Lee's avatar
Elliot Lee committed
804 805 806
}

static void
807
curves_channel_reset_callback (GtkWidget      *widget,
808
                               GimpCurvesTool *tool)
Elliot Lee's avatar
Elliot Lee committed
809
{
810
  tool->grab_point = -1;
Elliot Lee's avatar
Elliot Lee committed
811

812
  curves_channel_reset (tool->curves, tool->channel);
Elliot Lee's avatar
Elliot Lee committed
813

814
  curves_update (tool, XRANGE | GRAPH);
Elliot Lee's avatar
Elliot Lee committed
815

816
  gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool));
Elliot Lee's avatar
Elliot Lee committed
817 818
}

819
static gboolean
820
curves_set_sensitive_callback (GimpHistogramChannel  channel,
821
                               GimpCurvesTool       *tool)
822 823 824 825 826
{
  switch (channel)
    {
    case GIMP_HISTOGRAM_VALUE:
      return TRUE;
827

828 829 830
    case GIMP_HISTOGRAM_RED:
    case GIMP_HISTOGRAM_GREEN:
    case GIMP_HISTOGRAM_BLUE: