gimpcurvestool.c 35.8 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"
50
#include "widgets/gimppropwidgets.h"
Michael Natterer's avatar
Michael Natterer committed
51

52 53
#include "display/gimpdisplay.h"

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

58
#include "gimp-intl.h"
59

60

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

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


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

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

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);
94 95 96 97
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);
98

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

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

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

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

Michael Natterer's avatar
Michael Natterer committed
123

124 125
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
126

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

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

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

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

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

  return tool_type;
}

174 175 176

/*  private functions  */

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

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

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

192 193 194 195 196 197
  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;
198

199 200 201 202
  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");
203

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

208 209
  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
210 211 212
}

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

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

221
  curves_init (tool->curves);
222

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

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

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

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

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

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

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

  if (! drawable)
274
    return FALSE;
275

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

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

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

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

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

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

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

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

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

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

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

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

320 321
  curves_update (c_tool, ALL);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

444

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

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

467 468
  tool_options = GIMP_TOOL (tool)->tool_info->tool_options;

469
  vbox = image_map_tool->main_vbox;
Elliot Lee's avatar
Elliot Lee committed
470

471 472
  /*  The option menu for selecting channels  */
  hbox = gtk_hbox_new (FALSE, 4);
473 474 475 476 477 478 479
  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);

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

488
  tool->channel_menu = menu;
489

490
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
491
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
492
  gtk_widget_show (button);
493

494
  g_signal_connect (button, "clicked",
495
                    G_CALLBACK (curves_channel_reset_callback),
496
                    tool);
Elliot Lee's avatar
Elliot Lee committed
497

498 499 500 501 502
  menu = gimp_prop_enum_stock_box_new (G_OBJECT (tool_options),
                                       "histogram-scale", "gimp-histogram",
                                       0, 0);
  gtk_box_pack_end (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
  gtk_widget_show (menu);
503

504
  /*  The table for the color bars and the graph  */
Elliot Lee's avatar
Elliot Lee committed
505
  table = gtk_table_new (2, 2, FALSE);
506 507
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
508 509 510 511 512 513 514
  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
515 516

  frame = gtk_frame_new (NULL);
517
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
518
  gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
519 520
  gtk_widget_show (frame);

521 522 523 524
  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);
525

Elliot Lee's avatar
Elliot Lee committed
526 527
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
528
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
529
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
530
		    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
531
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
532

533 534 535 536 537 538 539 540 541
  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,
542 543 544
                "border-width", RADIUS,
                "subdivisions", 1,
                NULL);
545 546 547
  GIMP_HISTOGRAM_VIEW (tool->graph)->light_histogram = TRUE;
  gtk_container_add (GTK_CONTAINER (frame), tool->graph);
  gtk_widget_show (tool->graph);
548

549
  g_signal_connect (tool->graph, "event",
550
		    G_CALLBACK (curves_graph_events),
551 552
		    tool);
  g_signal_connect_after (tool->graph, "expose_event",
553
                          G_CALLBACK (curves_graph_expose),
554
                          tool);
Elliot Lee's avatar
Elliot Lee committed
555

556 557

  gimp_histogram_options_connect_view (GIMP_HISTOGRAM_OPTIONS (tool_options),
558 559 560 561 562 563 564
                                       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);
565

Elliot Lee's avatar
Elliot Lee committed
566
  frame = gtk_frame_new (NULL);
567
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
568
  gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
569 570
  gtk_widget_show (frame);

571 572 573 574
  vbox2 = gtk_vbox_new (TRUE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox2);
  gtk_widget_show (vbox2);

575 576 577 578
  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);
579

580 581 582 583
  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_box_pack_start (GTK_BOX (vbox2), bar, TRUE, TRUE, 0);
  gtk_widget_show (bar);

584
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
585

586

587 588 589
  hbox = gtk_hbox_new (FALSE, 6);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);
590

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

596 597 598 599 600 601
  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);
602

603 604 605 606 607
  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);
608

609 610 611 612 613
  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);
614 615 616 617 618 619 620

  /*  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,
621
				  "gimp-curve", GTK_ICON_SIZE_MENU,
622
				  G_CALLBACK (curves_curve_type_callback),
623 624 625 626 627 628
				  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);
629 630 631 632 633 634

  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
635 636
}

637
static void
638
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
639
{
640
  GimpCurvesTool       *tool = GIMP_CURVES_TOOL (image_map_tool);
641
  GimpHistogramChannel  channel;
642

643
  tool->grab_point = -1;
644

645 646 647
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
648
    curves_channel_reset (tool->curves, channel);
649

650
  curves_update (tool, XRANGE | GRAPH);
651 652
}

653
static gboolean
654 655
gimp_curves_tool_settings_load (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
656
{
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
  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)
	    {
678 679
              /*  FIXME: should have a helpful error message here  */
	      g_printerr ("fields != 2");
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
	      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;
705 706 707
}

static gboolean
708 709
gimp_curves_tool_settings_save (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
710
{
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
  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;
742
}
743

744
/* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
Elliot Lee's avatar
Elliot Lee committed
745
static void
746
curves_update (GimpCurvesTool *tool,
747
	       gint            update)
Elliot Lee's avatar
Elliot Lee committed
748
{
749
  GimpHistogramChannel channel;
750

751
  if (tool->color)
752
    {
753
      channel = tool->channel;
754
    }
755
  else
756
    {
757
      if (tool->channel == 2)
758
        channel = GIMP_HISTOGRAM_ALPHA;
759
      else
760
        channel = GIMP_HISTOGRAM_VALUE;
761
    }
762

763 764 765
  if (update & GRAPH)
    gtk_widget_queue_draw (tool->graph);

766
  if (update & XRANGE)
Elliot Lee's avatar
Elliot Lee committed
767
    {
768
      switch (channel)
769
	{
Michael Natterer's avatar
Michael Natterer committed
770 771
	case GIMP_HISTOGRAM_VALUE:
	case GIMP_HISTOGRAM_ALPHA:
772 773 774 775
          gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->xrange),
                                      tool->curves->curve[channel],
                                      tool->curves->curve[channel],
                                      tool->curves->curve[channel]);
776 777
	  break;

Michael Natterer's avatar
Michael Natterer committed
778 779 780
	case GIMP_HISTOGRAM_RED:
	case GIMP_HISTOGRAM_GREEN:
	case GIMP_HISTOGRAM_BLUE:
781 782 783 784
          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]);
785
	  break;
786
	}
Elliot Lee's avatar
Elliot Lee committed
787
    }
788

Elliot Lee's avatar
Elliot Lee committed
789 790
  if (update & YRANGE)
    {
791
      gimp_color_bar_set_channel (GIMP_COLOR_BAR (tool->yrange), channel);
Elliot Lee's avatar
Elliot Lee committed
792 793 794 795
    }
}

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

801 802
  gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (tool->graph),
                                   tool->channel);
803 804

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

808 809
  gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (tool->curve_type),
			           tool->curves->curve_type[tool->channel]);
810

811
  curves_update (tool, ALL);
Elliot Lee's avatar
Elliot Lee committed
812 813 814
}

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

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

822
  curves_update (tool, XRANGE | GRAPH);
Elliot Lee's avatar
Elliot Lee committed
823

824
  gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool));
Elliot Lee's avatar
Elliot Lee committed
825 826
}

827
static gboolean
828
curves_set_sensitive_callback (GimpHistogramChannel  channel,
829