gimpcurvestool.c 36.2 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/gimpenumcombobox.h"
Sven Neumann's avatar
Sven Neumann committed
48
#include "widgets/gimpenumstore.h"
49
#include "widgets/gimpenumwidgets.h"
50
#include "widgets/gimphelp-ids.h"
51
#include "widgets/gimphistogramview.h"
52
#include "widgets/gimppropwidgets.h"
Michael Natterer's avatar
Michael Natterer committed
53

54 55
#include "display/gimpdisplay.h"

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

60
#include "gimp-intl.h"
61

62

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

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


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

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

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

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

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

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

Sven Neumann's avatar
Sven Neumann committed
114 115 116
static gboolean curves_menu_visible_func        (GtkTreeModel     *model,
                                                 GtkTreeIter      *iter,
                                                 gpointer          data);
117
static void     curves_curve_type_callback      (GtkWidget        *widget,
118
                                                 GimpCurvesTool   *tool);
119 120
static gboolean curves_graph_events             (GtkWidget        *widget,
                                                 GdkEvent         *event,
121
                                                 GimpCurvesTool   *tool);
122 123
static gboolean curves_graph_expose             (GtkWidget        *widget,
                                                 GdkEventExpose   *eevent,
124
                                                 GimpCurvesTool   *tool);
125

Michael Natterer's avatar
Michael Natterer committed
126

127 128
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
129

130
/*  public functions  */
Michael Natterer's avatar
Michael Natterer committed
131 132

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

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

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

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

  return tool_type;
}

177 178 179

/*  private functions  */

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

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

193
  parent_class = g_type_class_peek_parent (klass);
Michael Natterer's avatar
Michael Natterer committed
194

195 196 197 198 199 200
  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;
201

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

207 208 209
  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;
210

211 212
  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
213 214 215
}

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

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

224
  curves_init (tool->curves);
225

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

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

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

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

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

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

274 275 276
  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (! drawable)
277
    return FALSE;
278

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

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

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

292
  curves_init (c_tool->curves);
Michael Natterer's avatar
Michael Natterer committed
293

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

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

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

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

Sven Neumann's avatar
Sven Neumann committed
307 308
  gimp_enum_combo_box_set_visible (GIMP_ENUM_COMBO_BOX (c_tool->channel_menu),
                                   curves_menu_visible_func, c_tool);
309

310 311
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (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 482 483 484 485
  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");
486 487 488
  gtk_box_pack_start (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
  gtk_widget_show (menu);

489
  tool->channel_menu = menu;
490

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

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

499 500 501 502 503
  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);
504

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

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

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

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

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

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

557 558

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

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

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

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

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

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

587

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

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

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

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

610 611 612 613 614
  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);
615 616

  /*  The radio box for selecting the curve type  */
617
  frame = gimp_frame_new (_("Curve Type"));
618 619 620 621
  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,
622
				  "gimp-curve", GTK_ICON_SIZE_MENU,
623
				  G_CALLBACK (curves_curve_type_callback),
624 625 626 627 628 629
				  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);
630 631 632 633 634 635

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

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

644
  tool->grab_point = -1;
645

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

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

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

static gboolean
709 710
gimp_curves_tool_settings_save (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
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 742
  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;
743
}
744

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

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

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

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

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

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

static void
797
curves_channel_callback (GtkWidget      *widget,
798
			 GimpCurvesTool *tool)
Elliot Lee's avatar
Elliot Lee committed
799
{
800 801 802 803
  gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget),
                                 (gint *) &tool->channel);
  gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (tool->graph),
                                   tool->channel);
804

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

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

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

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

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

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

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

828
static gboolean
Sven Neumann's avatar
Sven Neumann committed
829