gimpcurvestool.c 36 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 48
#include "widgets/gimpenumcombobox.h"
#include "widgets/gimpenumwidgets.h"
49
#include "widgets/gimphelp-ids.h"
50
#include "widgets/gimphistogramview.h"
51
#include "widgets/gimppropwidgets.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
#define XRANGE   (1 << 0)
#define YRANGE   (1 << 1)
64 65
#define GRAPH    (1 << 2)
#define ALL      (XRANGE | YRANGE | GRAPH)
Elliot Lee's avatar
Elliot Lee committed
66

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


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

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

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

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

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

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

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

Michael Natterer's avatar
Michael Natterer committed
124

125 126
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
127

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

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

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

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

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

  return tool_type;
}

175 176 177

/*  private functions  */

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

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

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

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

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

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

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

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

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

222
  curves_init (tool->curves);
223

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

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

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

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

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

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

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

  if (! drawable)
275
    return FALSE;
276

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

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

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

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

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

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

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

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

305 306
  /*  FIXME: regression!  */
#if 0
307
  /* set the sensitivity of the channel menu based on the drawable type */
308 309 310
  gimp_int_option_menu_set_sensitive (GTK_OPTION_MENU (c_tool->channel_menu),
                                      (GimpIntOptionMenuSensitivityCallback) curves_set_sensitive_callback,
                                      c_tool);
311
#endif
312 313

  /* set the current selection */
314 315
  gimp_enum_combo_box_set_active (GIMP_ENUM_COMBO_BOX (c_tool->channel_menu),
                                  c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
316

317 318 319
  if (! c_tool->color && c_tool->alpha)
    c_tool->channel = 1;

320 321 322
  gimp_drawable_calculate_histogram (drawable, c_tool->hist);
  gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                     c_tool->hist);
323

324 325
  curves_update (c_tool, ALL);

326
  return TRUE;
Michael Natterer's avatar
Michael Natterer committed
327 328 329
}

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

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

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

350 351 352 353 354
      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
355 356
    }

357 358 359
  /*  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
360 361 362
}

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

372 373
  tool = GIMP_CURVES_TOOL (color_tool);
  drawable = GIMP_IMAGE_MAP_TOOL (tool)->drawable;
374

375
  gimp_rgba_get_uchar (color, &r, &g, &b, &a);
376

377 378 379
  tool->col_value[GIMP_HISTOGRAM_RED]   = r;
  tool->col_value[GIMP_HISTOGRAM_GREEN] = g;
  tool->col_value[GIMP_HISTOGRAM_BLUE]  = b;
380

381
  if (gimp_drawable_has_alpha (drawable))
382
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = a;
383

384
  if (gimp_drawable_is_indexed (drawable))
385
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = color_index;
386

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

389
  curves_update (tool, GRAPH);
390
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
391

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

404
  switch (tool->curves->curve_type[cchan])
405
    {
406
    case GIMP_CURVE_SMOOTH:
407
      curvex   = tool->col_value[cchan];
408
      distance = G_MAXINT;
409

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

420 421
      if (distance > MIN_DISTANCE)
	closest_point = (curvex + 8) / 16;
422

423 424
      tool->curves->points[cchan][closest_point][0] = curvex;
      tool->curves->points[cchan][closest_point][1] = tool->curves->curve[cchan][curvex];
425
      break;
426

427
    case GIMP_CURVE_FREE:
428
      tool->curves->curve[cchan][x] = 255 - y;
429
      break;
430
    }
Elliot Lee's avatar
Elliot Lee committed
431 432
}

433 434
static void
gimp_curves_tool_map (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
435
{
436
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
437

438
  gimp_lut_setup (tool->lut,
439
		  (GimpLutFunc) curves_lut_func,
440
                  tool->curves,
441
		  gimp_drawable_bytes (image_map_tool->drawable));
442

443 444
  gimp_image_map_apply (image_map_tool->image_map,
                        (GimpImageMapApplyFunc) gimp_lut_process_2,
445
                        tool->lut);
Elliot Lee's avatar
Elliot Lee committed
446 447
}

448

449 450 451
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
452

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

471 472
  tool_options = GIMP_TOOL (tool)->tool_info->tool_options;

473
  vbox = image_map_tool->main_vbox;
Elliot Lee's avatar
Elliot Lee committed
474

475 476
  /*  The option menu for selecting channels  */
  hbox = gtk_hbox_new (FALSE, 4);
477 478 479 480 481 482 483
  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);

484 485 486 487 488 489
  menu = gimp_enum_combo_box_new (GIMP_TYPE_HISTOGRAM_CHANNEL);
  g_signal_connect (menu, "changed",
                    G_CALLBACK (curves_channel_callback),
                    tool);
  gimp_enum_combo_box_set_stock_prefix (GIMP_ENUM_COMBO_BOX (menu),
                                        "gimp-channel");
490 491 492
  gtk_box_pack_start (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
  gtk_widget_show (menu);

493
  tool->channel_menu = menu;
494

495
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
496
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
497
  gtk_widget_show (button);
498

499
  g_signal_connect (button, "clicked",
500
                    G_CALLBACK (curves_channel_reset_callback),
501
                    tool);
Elliot Lee's avatar
Elliot Lee committed
502

503 504 505 506 507
  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);
508

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

  frame = gtk_frame_new (NULL);
522
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
523
  gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
524 525
  gtk_widget_show (frame);

526 527 528 529
  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);
530

Elliot Lee's avatar
Elliot Lee committed
531 532
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
533
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
534
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
535
		    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
536
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
537

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

554
  g_signal_connect (tool->graph, "event",
555
		    G_CALLBACK (curves_graph_events),
556 557
		    tool);
  g_signal_connect_after (tool->graph, "expose_event",
558
                          G_CALLBACK (curves_graph_expose),
559
                          tool);
Elliot Lee's avatar
Elliot Lee committed
560

561 562

  gimp_histogram_options_connect_view (GIMP_HISTOGRAM_OPTIONS (tool_options),
563 564 565 566 567 568 569
                                       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);
570

Elliot Lee's avatar
Elliot Lee committed
571
  frame = gtk_frame_new (NULL);
572
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
573
  gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
574 575
  gtk_widget_show (frame);

576 577 578 579
  vbox2 = gtk_vbox_new (TRUE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox2);
  gtk_widget_show (vbox2);

580 581 582 583
  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);
584

585 586 587 588
  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_box_pack_start (GTK_BOX (vbox2), bar, TRUE, TRUE, 0);
  gtk_widget_show (bar);

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

591

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

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

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

608 609 610 611 612
  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);
613

614 615 616 617 618
  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);
619 620 621 622 623 624 625

  /*  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,
626
				  "gimp-curve", GTK_ICON_SIZE_MENU,
627
				  G_CALLBACK (curves_curve_type_callback),
628 629 630 631 632 633
				  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);
634 635 636 637 638 639

  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
640 641
}

642
static void
643
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
644
{
645
  GimpCurvesTool       *tool = GIMP_CURVES_TOOL (image_map_tool);
646
  GimpHistogramChannel  channel;
647

648
  tool->grab_point = -1;
649

650 651 652
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
653
    curves_channel_reset (tool->curves, channel);
654

655
  curves_update (tool, XRANGE | GRAPH);
656 657
}

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

static gboolean
713 714
gimp_curves_tool_settings_save (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
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 742 743 744 745 746
  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;
747
}
748

749
/* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
Elliot Lee's avatar
Elliot Lee committed
750
static void
751
curves_update (GimpCurvesTool *tool,
752
	       gint            update)
Elliot Lee's avatar
Elliot Lee committed
753
{
754
  GimpHistogramChannel channel;
755

756
  if (tool->color)
757
    {
758
      channel = tool->channel;
759
    }
760
  else
761
    {
762
      if (tool->channel == 2)
763
        channel = GIMP_HISTOGRAM_ALPHA;
764
      else
765
        channel = GIMP_HISTOGRAM_VALUE;
766
    }
767

768 769 770
  if (update & GRAPH)
    gtk_widget_queue_draw (tool->graph);

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

Michael Natterer's avatar
Michael Natterer committed
783 784 785
	case GIMP_HISTOGRAM_RED:
	case GIMP_HISTOGRAM_GREEN:
	case GIMP_HISTOGRAM_BLUE:
786 787 788 789
          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]);
790
	  break;
791
	}
Elliot Lee's avatar
Elliot Lee committed
792
    }
793

Elliot Lee's avatar
Elliot Lee committed
794 795
  if (update & YRANGE)
    {
796
      gimp_color_bar_set_channel (GIMP_COLOR_BAR (tool->yrange), channel);
Elliot Lee's avatar
Elliot Lee committed
797 798 799 800
    }
}

static void
801
curves_channel_callback (GtkWidget      *widget,
802
			 GimpCurvesTool *tool)
Elliot Lee's avatar
Elliot Lee committed
803
{
804 805 806 807 808
  if (gimp_enum_combo_box_get_active (GIMP_ENUM_COMBO_BOX (widget),
                                      (gint *) &tool->channel))
    {
      gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (tool->graph),
                                       tool->channel);
809

810 811 812 813
      /* FIXME: hack */
      if (! tool->color && tool->alpha)
        tool->channel = (tool->channel > 1) ? 2 : 1;
    }
Elliot Lee's avatar
Elliot Lee committed
814

815
  gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (tool->curve_type),
816
                                   tool->curves->curve_type[tool->channel]);
817

818
  curves_update (tool, ALL);
Elliot Lee's avatar
Elliot Lee committed
819 820 821
}

static void
822
curves_channel_reset_callback (GtkWidget      *widget,
823
                               GimpCurvesTool *tool)
Elliot Lee's avatar
Elliot Lee committed
824
{
825
  tool->grab_point = -1;
Elliot Lee's avatar
Elliot Lee committed
826

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

829
  curves_update (tool, XRANGE | GRAPH);
Elliot Lee's avatar
Elliot Lee committed
830

831
  gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool));
Elliot Lee's avatar
Elliot Lee committed
832 833
}

834
static gboolean
835
curves_set_sensitive_callback (GimpHistogramChannel  channel,