gimpcurvestool.c 39.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
#include "config/gimpguiconfig.h"
33

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/gimphelp-ids.h"
48
#include "widgets/gimphistogramview.h"
Michael Natterer's avatar
Michael Natterer committed
49

50 51
#include "display/gimpdisplay.h"

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

56
#include "gimp-intl.h"
57

58

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

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


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

72
static void     gimp_curves_tool_class_init     (GimpCurvesToolClass *klass);
73
static void     gimp_curves_tool_init           (GimpCurvesTool      *tool);
74 75 76 77 78

static void     gimp_curves_tool_finalize       (GObject          *object);

static gboolean gimp_curves_tool_initialize     (GimpTool         *tool,
                                                 GimpDisplay      *gdisp);
79 80 81 82
static void     gimp_curves_tool_oper_update    (GimpTool         *tool,
                                                 GimpCoords       *coords,
                                                 GdkModifierType   state,
                                                 GimpDisplay      *gdisp);
83 84 85 86 87 88 89
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,
90
                                                 GimpColorPickState pick_state,
91 92 93 94 95 96
                                                 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);
97 98 99 100
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);
101

102
static void     curves_add_point                (GimpCurvesTool   *tool,
103 104
                                                 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_menu_sensitivity         (gint              value,
Sven Neumann's avatar
Sven Neumann committed
114
                                                 gpointer          data);
115

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

Michael Natterer's avatar
Michael Natterer committed
125

126 127
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
128

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

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

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

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

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

  return tool_type;
}

176 177 178

/*  private functions  */

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

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

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

194 195 196
  object_class->finalize     = gimp_curves_tool_finalize;

  tool_class->initialize     = gimp_curves_tool_initialize;
197
  tool_class->oper_update    = gimp_curves_tool_oper_update;
198 199 200
  tool_class->button_release = gimp_curves_tool_button_release;

  color_tool_class->picked   = gimp_curves_tool_color_picked;
201

202 203 204
  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");
205
  image_map_tool_class->load_button_tip   = _("Load curves settings from file");
206
  image_map_tool_class->save_dialog_title = _("Save Curves");
207
  image_map_tool_class->save_button_tip   = _("Save curves settings to file");
208

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

213 214
  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
215 216 217
}

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

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

226
  curves_init (tool->curves);
227

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

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

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

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

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

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

276 277 278
  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (! drawable)
279
    return FALSE;
280

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

287
  if (! c_tool->hist)
288
    c_tool->hist = gimp_histogram_new ();
289

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
  gimp_int_combo_box_set_sensitivity (GIMP_INT_COMBO_BOX (c_tool->channel_menu),
                                      curves_menu_sensitivity, c_tool, NULL);
307

308 309
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (c_tool->channel_menu),
                                 c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
310

311 312 313
  /* FIXME: hack */
  if (! c_tool->color)
    c_tool->channel = (c_tool->channel == GIMP_HISTOGRAM_ALPHA) ? 1 : 0;
314

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

319 320
  curves_update (c_tool, ALL);

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

324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
static void
gimp_curves_tool_oper_update (GimpTool        *tool,
                              GimpCoords      *coords,
                              GdkModifierType  state,
                              GimpDisplay     *gdisp)
{
  GimpColorPickMode  mode   = GIMP_COLOR_PICK_MODE_NONE;
  const gchar       *status = NULL;

  GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, gdisp);

  gimp_tool_pop_status (tool, gdisp);

  if (state & GDK_SHIFT_MASK)
    {
      mode   = GIMP_COLOR_PICK_MODE_PALETTE;
      status = _("Click to add a control point.");
    }
  else if (state & GDK_CONTROL_MASK)
    {
      mode   = GIMP_COLOR_PICK_MODE_PALETTE;
      status = _("Click to add control points to all channels.");
    }

  GIMP_COLOR_TOOL (tool)->pick_mode = mode;

  if (status)
    gimp_tool_push_status (tool, gdisp, status);
}

Michael Natterer's avatar
Michael Natterer committed
354
static void
355 356 357
gimp_curves_tool_button_release (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 guint32          time,
358 359
                                 GdkModifierType  state,
                                 GimpDisplay     *gdisp)
Michael Natterer's avatar
Michael Natterer committed
360
{
361
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool);
362
  GimpDrawable   *drawable;
Michael Natterer's avatar
Michael Natterer committed
363

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

366
  if (state & GDK_SHIFT_MASK)
Michael Natterer's avatar
Michael Natterer committed
367
    {
368
      curves_add_point (c_tool, c_tool->channel);
369
      curves_calculate_curve (c_tool->curves, c_tool->channel);
370
      curves_update (c_tool, GRAPH | XRANGE);
Michael Natterer's avatar
Michael Natterer committed
371
    }
372
  else if (state & GDK_CONTROL_MASK)
Michael Natterer's avatar
Michael Natterer committed
373
    {
374
      gint i;
375

376 377
      for (i = 0; i < 5; i++)
        {
378
          curves_add_point (c_tool, i);
379 380
          curves_calculate_curve (c_tool->curves, c_tool->channel);
        }
381

382
      curves_update (c_tool, GRAPH | XRANGE);
Michael Natterer's avatar
Michael Natterer committed
383 384
    }

385 386 387
  /*  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
388 389 390
}

static void
391 392
gimp_curves_tool_color_picked (GimpColorTool      *color_tool,
                               GimpColorPickState  pick_state,
393 394 395
                               GimpImageType       sample_type,
                               GimpRGB            *color,
                               gint                color_index)
Michael Natterer's avatar
Michael Natterer committed
396
{
397
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (color_tool);
398
  GimpDrawable   *drawable;
399
  guchar          r, g, b, a;
Michael Natterer's avatar
Michael Natterer committed
400

401
  drawable = GIMP_IMAGE_MAP_TOOL (tool)->drawable;
402

403
  gimp_rgba_get_uchar (color, &r, &g, &b, &a);
404

405 406 407
  tool->col_value[GIMP_HISTOGRAM_RED]   = r;
  tool->col_value[GIMP_HISTOGRAM_GREEN] = g;
  tool->col_value[GIMP_HISTOGRAM_BLUE]  = b;
408

409
  if (gimp_drawable_has_alpha (drawable))
410
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = a;
411

412
  if (gimp_drawable_is_indexed (drawable))
413
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = color_index;
414

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

417
  curves_update (tool, GRAPH);
418
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
419

420
static void
421
curves_add_point (GimpCurvesTool *tool,
422
                  gint            cchan)
423 424
{
  /* Add point onto the curve */
425 426 427 428
  gint closest_point = 0;
  gint distance;
  gint curvex;
  gint i;
429

430
  switch (tool->curves->curve_type[cchan])
431
    {
432
    case GIMP_CURVE_SMOOTH:
433
      curvex   = tool->col_value[cchan];
434
      distance = G_MAXINT;
435

436
      for (i = 0; i < CURVES_NUM_POINTS; i++)
437 438 439 440 441 442 443 444
        {
          if (tool->curves->points[cchan][i][0] != -1)
            if (abs (curvex - tool->curves->points[cchan][i][0]) < distance)
              {
                distance = abs (curvex - tool->curves->points[cchan][i][0]);
                closest_point = i;
              }
        }
445

446
      if (distance > MIN_DISTANCE)
447
        closest_point = (curvex + 8) / 16;
448

449 450
      tool->curves->points[cchan][closest_point][0] = curvex;
      tool->curves->points[cchan][closest_point][1] = tool->curves->curve[cchan][curvex];
451
      break;
452

453
    case GIMP_CURVE_FREE:
454
      /* do nothing for free form curves */
455
      break;
456
    }
Elliot Lee's avatar
Elliot Lee committed
457 458
}

459 460
static void
gimp_curves_tool_map (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
461
{
462
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
463

464
  gimp_lut_setup (tool->lut,
465
                  (GimpLutFunc) curves_lut_func,
466
                  tool->curves,
467
                  gimp_drawable_bytes (image_map_tool->drawable));
468

469
  gimp_image_map_apply (image_map_tool->image_map,
470
                        (GimpImageMapApplyFunc) gimp_lut_process,
471
                        tool->lut);
Elliot Lee's avatar
Elliot Lee committed
472 473
}

474

475 476 477
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
478

479 480
static void
gimp_curves_tool_dialog (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
481
{
482
  GimpCurvesTool  *tool = GIMP_CURVES_TOOL (image_map_tool);
483
  GimpToolOptions *tool_options;
484
  GtkListStore    *store;
485
  GtkWidget       *vbox;
486 487 488 489 490
  GtkWidget       *vbox2;
  GtkWidget       *hbox;
  GtkWidget       *hbox2;
  GtkWidget       *label;
  GtkWidget       *bbox;
491 492 493 494
  GtkWidget       *frame;
  GtkWidget       *menu;
  GtkWidget       *table;
  GtkWidget       *button;
495
  GtkWidget       *bar;
496
  gint             padding;
497

498 499
  tool_options = GIMP_TOOL (tool)->tool_info->tool_options;

500
  vbox = image_map_tool->main_vbox;
Elliot Lee's avatar
Elliot Lee committed
501

502
  /*  The option menu for selecting channels  */
503
  hbox = gtk_hbox_new (FALSE, 6);
504 505 506
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

507
  label = gtk_label_new_with_mnemonic (_("Cha_nnel:"));
508 509 510
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

511 512 513
  store = gimp_enum_store_new_with_range (GIMP_TYPE_HISTOGRAM_CHANNEL,
                                          GIMP_HISTOGRAM_VALUE,
                                          GIMP_HISTOGRAM_ALPHA);
514
  menu = gimp_enum_combo_box_new_with_model (GIMP_ENUM_STORE (store));
515 516
  g_object_unref (store);

517 518 519 520 521
  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");
522 523 524
  gtk_box_pack_start (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
  gtk_widget_show (menu);

525
  tool->channel_menu = menu;
526

527 528
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), menu);

529
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
530
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
531
  gtk_widget_show (button);
532

533
  g_signal_connect (button, "clicked",
534
                    G_CALLBACK (curves_channel_reset_callback),
535
                    tool);
Elliot Lee's avatar
Elliot Lee committed
536

537 538 539 540 541
  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);
542

543
  /*  The table for the color bars and the graph  */
Elliot Lee's avatar
Elliot Lee committed
544
  table = gtk_table_new (2, 2, FALSE);
545 546
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
547 548 549 550 551
  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,
552
                    GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
553
  gtk_widget_show (vbox2);
Elliot Lee's avatar
Elliot Lee committed
554 555

  frame = gtk_frame_new (NULL);
556
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
557
  gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
558 559
  gtk_widget_show (frame);

560 561 562 563
  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);
564

Elliot Lee's avatar
Elliot Lee committed
565 566
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
567
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
568
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
569
                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
570
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
571

572 573 574 575 576 577 578 579 580
  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,
581 582 583
                "border-width", RADIUS,
                "subdivisions", 1,
                NULL);
584 585 586
  GIMP_HISTOGRAM_VIEW (tool->graph)->light_histogram = TRUE;
  gtk_container_add (GTK_CONTAINER (frame), tool->graph);
  gtk_widget_show (tool->graph);
587

588
  g_signal_connect (tool->graph, "event",
589 590
                    G_CALLBACK (curves_graph_events),
                    tool);
591
  g_signal_connect_after (tool->graph, "expose-event",
592
                          G_CALLBACK (curves_graph_expose),
593
                          tool);
Elliot Lee's avatar
Elliot Lee committed
594

595 596

  gimp_histogram_options_connect_view (GIMP_HISTOGRAM_OPTIONS (tool_options),
597 598 599 600 601
                                       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,
602
                    GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
603
  gtk_widget_show (hbox2);
604

Elliot Lee's avatar
Elliot Lee committed
605
  frame = gtk_frame_new (NULL);
606
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
607
  gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
608 609
  gtk_widget_show (frame);

610 611 612 613
  vbox2 = gtk_vbox_new (TRUE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox2);
  gtk_widget_show (vbox2);

614 615 616 617
  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);
618

619 620 621 622
  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_box_pack_start (GTK_BOX (vbox2), bar, TRUE, TRUE, 0);
  gtk_widget_show (bar);

623
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
624

625

626 627 628
  hbox = gtk_hbox_new (FALSE, 6);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);
629

630
  /*  Horizontal button box for load / save */
631
  frame = gimp_frame_new (_("All Channels"));
632
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
633 634
  gtk_widget_show (frame);

635 636
  bbox = gtk_hbutton_box_new ();
  gtk_box_set_spacing (GTK_BOX (bbox), 4);
637
  gtk_container_add (GTK_CONTAINER (frame), bbox);
638
  gtk_widget_show (bbox);
639

640 641 642
  gtk_box_pack_start (GTK_BOX (bbox), image_map_tool->load_button,
                      FALSE, FALSE, 0);
  gtk_widget_show (image_map_tool->load_button);
643

644 645 646
  gtk_box_pack_start (GTK_BOX (bbox), image_map_tool->save_button,
                      FALSE, FALSE, 0);
  gtk_widget_show (image_map_tool->save_button);
647 648

  /*  The radio box for selecting the curve type  */
649
  frame = gimp_frame_new (_("Curve Type"));
650 651 652 653
  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,
654 655 656 657
                                  "gimp-curve", GTK_ICON_SIZE_MENU,
                                  G_CALLBACK (curves_curve_type_callback),
                                  tool,
                                  &tool->curve_type);
658

659
  gtk_widget_style_get (bbox, "child-internal-pad-x", &padding, NULL);
660 661

  gimp_enum_stock_box_set_child_padding (hbox, padding, -1);
662 663 664 665 666 667

  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
668 669
}

670
static void
671
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
672
{
673
  GimpCurvesTool       *tool = GIMP_CURVES_TOOL (image_map_tool);
674
  GimpHistogramChannel  channel;
675

676
  tool->grab_point = -1;
677

678 679 680
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
681
    curves_channel_reset (tool->curves, channel);
682

683
  curves_update (tool, XRANGE | GRAPH);
684 685
}

686
static gboolean
687 688
gimp_curves_tool_settings_load (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
689
{
690 691 692 693 694
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
  FILE           *file = fp;
  gint            i, j;
  gint            fields;
  gchar           buf[50];
695 696
  gint            index[5][CURVES_NUM_POINTS];
  gint            value[5][CURVES_NUM_POINTS];
697 698 699 700 701 702 703 704 705

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

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

  for (i = 0; i < 5; i++)
    {
706
      for (j = 0; j < CURVES_NUM_POINTS; j++)
707 708 709 710
        {
          fields = fscanf (file, "%d %d ", &index[i][j], &value[i][j]);
          if (fields != 2)
            {
711
              /*  FIXME: should have a helpful error message here  */
712 713 714 715
              g_printerr ("fields != 2");
              return FALSE;
            }
        }
716 717 718 719 720 721
    }

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

722
      for (j = 0; j < CURVES_NUM_POINTS; j++)
723 724 725 726
        {
          tool->curves->points[i][j][0] = index[i][j];
          tool->curves->points[i][j][1] = value[i][j];
        }
727 728 729 730 731 732 733 734
    }

  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),
735
                                   GIMP_CURVE_SMOOTH);
736 737

  return TRUE;
738 739 740
}

static gboolean
741 742
gimp_curves_tool_settings_save (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
743
{
744 745 746 747 748 749 750 751
  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)
      {
752
        /*  pick representative points from the curve
753
            and make them control points  */
754 755 756 757 758 759
        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];
          }
760 761 762 763 764 765
      }

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

  for (i = 0; i < 5; i++)
    {
766
      for (j = 0; j < CURVES_NUM_POINTS; j++)
767
        fprintf (file, "%d %d ",
768 769 770 771 772 773 774
                 tool->curves->points[i][j][0],
                 tool->curves->points[i][j][1]);

      fprintf (file, "\n");
    }

  return TRUE;
775
}
776

777
/* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
Elliot Lee's avatar
Elliot Lee committed
778
static void
779
curves_update (GimpCurvesTool *tool,
780
               gint            update)
Elliot Lee's avatar
Elliot Lee committed
781
{
782
  GimpHistogramChannel channel;
783

784
  if (tool->color)
785
    {
786
      channel = tool->channel;
787
    }
788
  else
789
    {
790 791
      /* FIXME: hack */
      if (tool->channel == 1)
792
        channel = GIMP_HISTOGRAM_ALPHA;
793
      else
794