gimpcurvestool.c 41 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
#include "libgimpbase/gimpenv.h"
30

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

33
#include "config/gimpbaseconfig.h"
34
#include "config/gimpguiconfig.h"
35

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

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

47
#include "widgets/gimpcolorbar.h"
Michael Natterer's avatar
Michael Natterer committed
48
#include "widgets/gimpcursor.h"
49
#include "widgets/gimpenumcombobox.h"
Sven Neumann's avatar
Sven Neumann committed
50
#include "widgets/gimpenumstore.h"
51
#include "widgets/gimpenumwidgets.h"
52
#include "widgets/gimphelp-ids.h"
53
#include "widgets/gimphistogramview.h"
54
#include "widgets/gimppropwidgets.h"
Michael Natterer's avatar
Michael Natterer committed
55

56 57
#include "display/gimpdisplay.h"

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

62
#include "gimp-intl.h"
63

64

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

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


Michael Natterer's avatar
Michael Natterer committed
76 77
/*  local function prototypes  */

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

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);
98 99 100 101
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);
102

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

108
static void     curves_update                   (GimpCurvesTool   *tool,
109 110 111
                                                 gint              update);

static void     curves_channel_callback         (GtkWidget        *widget,
112
                                                 GimpCurvesTool   *tool);
113
static void     curves_channel_reset_callback   (GtkWidget        *widget,
114
                                                 GimpCurvesTool   *tool);
115

Sven Neumann's avatar
Sven Neumann committed
116 117 118
static gboolean curves_menu_visible_func        (GtkTreeModel     *model,
                                                 GtkTreeIter      *iter,
                                                 gpointer          data);
119
static void     curves_curve_type_callback      (GtkWidget        *widget,
120
                                                 GimpCurvesTool   *tool);
121 122
static gboolean curves_graph_events             (GtkWidget        *widget,
                                                 GdkEvent         *event,
123
                                                 GimpCurvesTool   *tool);
124 125
static gboolean curves_graph_expose             (GtkWidget        *widget,
                                                 GdkEventExpose   *eevent,
126
                                                 GimpCurvesTool   *tool);
127 128 129 130
static void gimp_curves_tool_store_settings     (GtkWidget        *widget,
                                                 gpointer          data);
static void gimp_curves_tool_recall_settings    (GtkWidget        *widget,
                                                 gpointer          data);
Michael Natterer's avatar
Michael Natterer committed
131

132 133
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
134

135
/*  public functions  */
Michael Natterer's avatar
Michael Natterer committed
136 137

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

154
GType
Michael Natterer's avatar
Michael Natterer committed
155 156
gimp_curves_tool_get_type (void)
{
157
  static GType tool_type = 0;
Michael Natterer's avatar
Michael Natterer committed
158 159 160

  if (! tool_type)
    {
161
      static const GTypeInfo tool_info =
Michael Natterer's avatar
Michael Natterer committed
162 163
      {
        sizeof (GimpCurvesToolClass),
164 165 166 167 168 169 170 171
        (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
172 173
      };

174
      tool_type = g_type_register_static (GIMP_TYPE_IMAGE_MAP_TOOL,
175
                                          "GimpCurvesTool",
176
                                          &tool_info, 0);
Michael Natterer's avatar
Michael Natterer committed
177 178 179 180 181
    }

  return tool_type;
}

182 183 184

/*  private functions  */

Michael Natterer's avatar
Michael Natterer committed
185 186 187
static void
gimp_curves_tool_class_init (GimpCurvesToolClass *klass)
{
188 189
  GObjectClass          *object_class;
  GimpToolClass         *tool_class;
190
  GimpColorToolClass    *color_tool_class;
191
  GimpImageMapToolClass *image_map_tool_class;
Michael Natterer's avatar
Michael Natterer committed
192

193 194
  object_class         = G_OBJECT_CLASS (klass);
  tool_class           = GIMP_TOOL_CLASS (klass);
195
  color_tool_class     = GIMP_COLOR_TOOL_CLASS (klass);
196
  image_map_tool_class = GIMP_IMAGE_MAP_TOOL_CLASS (klass);
Michael Natterer's avatar
Michael Natterer committed
197

198
  parent_class = g_type_class_peek_parent (klass);
Michael Natterer's avatar
Michael Natterer committed
199

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

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

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

216 217
  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
218 219 220
}

static void
221
gimp_curves_tool_init (GimpCurvesTool *tool)
Michael Natterer's avatar
Michael Natterer committed
222
{
223
  gint i;
224

225 226 227
  tool->curves  = g_new0 (Curves, 1);
  tool->lut     = gimp_lut_new ();
  tool->channel = GIMP_HISTOGRAM_VALUE;
228

229
  curves_init (tool->curves);
230

231 232
  for (i = 0; i < G_N_ELEMENTS (tool->col_value); i++)
    tool->col_value[i] = -1;
233

234 235
  tool->cursor_x = -1;
  tool->cursor_y = -1;
Michael Natterer's avatar
Michael Natterer committed
236 237 238
}

static void
239
gimp_curves_tool_finalize (GObject *object)
Michael Natterer's avatar
Michael Natterer committed
240
{
241
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (object);
242

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

269
  G_OBJECT_CLASS (parent_class)->finalize (object);
Michael Natterer's avatar
Michael Natterer committed
270 271
}

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

279 280 281
  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (! drawable)
282
    return FALSE;
283

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

290 291 292 293 294 295 296
  if (! c_tool->hist)
    {
      Gimp *gimp = GIMP_TOOL (c_tool)->tool_info->gimp;

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

297
  curves_init (c_tool->curves);
Michael Natterer's avatar
Michael Natterer committed
298

299
  c_tool->channel = GIMP_HISTOGRAM_VALUE;
300 301
  c_tool->color   = gimp_drawable_is_rgb (drawable);
  c_tool->alpha   = gimp_drawable_has_alpha (drawable);
302 303 304 305 306 307

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

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

308 309 310 311 312 313
  GIMP_IMAGE_MAP_OPTIONS (tool->tool_info->tool_options)->settings 
    = g_build_filename (gimp_directory (),
                        GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->settings_name,
                        G_DIR_SEPARATOR_S,
                        NULL);

314 315 316 317
  /*  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
318 319
  gimp_enum_combo_box_set_visible (GIMP_ENUM_COMBO_BOX (c_tool->channel_menu),
                                   curves_menu_visible_func, c_tool);
320

321 322
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (c_tool->channel_menu),
                                 c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
323

324 325 326
  if (! c_tool->color && c_tool->alpha)
    c_tool->channel = 1;

327 328 329
  gimp_drawable_calculate_histogram (drawable, c_tool->hist);
  gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                     c_tool->hist);
330

331 332
  curves_update (c_tool, ALL);

333
  return TRUE;
Michael Natterer's avatar
Michael Natterer committed
334 335 336
}

static void
337 338 339
gimp_curves_tool_button_release (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 guint32          time,
340 341
                                 GdkModifierType  state,
                                 GimpDisplay     *gdisp)
Michael Natterer's avatar
Michael Natterer committed
342
{
343
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool);
344
  GimpDrawable   *drawable;
Michael Natterer's avatar
Michael Natterer committed
345

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

348
  if (state & GDK_SHIFT_MASK)
Michael Natterer's avatar
Michael Natterer committed
349
    {
350
      curves_add_point (c_tool, coords->x, coords->y, c_tool->channel);
351
      curves_calculate_curve (c_tool->curves, c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
352
    }
353
  else if (state & GDK_CONTROL_MASK)
Michael Natterer's avatar
Michael Natterer committed
354
    {
355
      gint i;
356

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

364 365 366
  /*  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
367 368 369
}

static void
370
gimp_curves_tool_color_picked (GimpColorTool *color_tool,
371 372 373
                               GimpImageType  sample_type,
                               GimpRGB       *color,
                               gint           color_index)
Michael Natterer's avatar
Michael Natterer committed
374
{
375
  GimpCurvesTool *tool;
376
  GimpDrawable   *drawable;
377
  guchar          r, g, b, a;
Michael Natterer's avatar
Michael Natterer committed
378

379 380
  tool = GIMP_CURVES_TOOL (color_tool);
  drawable = GIMP_IMAGE_MAP_TOOL (tool)->drawable;
381

382
  gimp_rgba_get_uchar (color, &r, &g, &b, &a);
383

384 385 386
  tool->col_value[GIMP_HISTOGRAM_RED]   = r;
  tool->col_value[GIMP_HISTOGRAM_GREEN] = g;
  tool->col_value[GIMP_HISTOGRAM_BLUE]  = b;
387

388
  if (gimp_drawable_has_alpha (drawable))
389
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = a;
390

391
  if (gimp_drawable_is_indexed (drawable))
392
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = color_index;
393

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

396
  curves_update (tool, GRAPH);
397
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
398

399
static void
400
curves_add_point (GimpCurvesTool *tool,
401 402 403
                  gint            x,
                  gint            y,
                  gint            cchan)
404 405
{
  /* Add point onto the curve */
406 407 408 409
  gint closest_point = 0;
  gint distance;
  gint curvex;
  gint i;
410

411
  switch (tool->curves->curve_type[cchan])
412
    {
413
    case GIMP_CURVE_SMOOTH:
414
      curvex   = tool->col_value[cchan];
415
      distance = G_MAXINT;
416

417
      for (i = 0; i < 17; i++)
418 419 420 421 422 423 424 425
        {
          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;
              }
        }
426

427
      if (distance > MIN_DISTANCE)
428
        closest_point = (curvex + 8) / 16;
429

430 431
      tool->curves->points[cchan][closest_point][0] = curvex;
      tool->curves->points[cchan][closest_point][1] = tool->curves->curve[cchan][curvex];
432
      break;
433

434
    case GIMP_CURVE_FREE:
435
      tool->curves->curve[cchan][x] = 255 - y;
436
      break;
437
    }
Elliot Lee's avatar
Elliot Lee committed
438 439
}

440 441
static void
gimp_curves_tool_map (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
442
{
443
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
444

445
  gimp_lut_setup (tool->lut,
446
                  (GimpLutFunc) curves_lut_func,
447
                  tool->curves,
448
                  gimp_drawable_bytes (image_map_tool->drawable));
449

450 451
  gimp_image_map_apply (image_map_tool->image_map,
                        (GimpImageMapApplyFunc) gimp_lut_process_2,
452
                        tool->lut);
Elliot Lee's avatar
Elliot Lee committed
453 454
}

455

456 457 458
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
459

460 461
static void
gimp_curves_tool_dialog (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
462
{
463
  GimpCurvesTool  *tool = GIMP_CURVES_TOOL (image_map_tool);
464 465
  GimpToolOptions *tool_options;
  GtkWidget       *vbox;
466 467 468 469 470
  GtkWidget       *vbox2;
  GtkWidget       *hbox;
  GtkWidget       *hbox2;
  GtkWidget       *label;
  GtkWidget       *bbox;
471 472 473 474
  GtkWidget       *frame;
  GtkWidget       *menu;
  GtkWidget       *table;
  GtkWidget       *button;
475
  GtkWidget       *bar;
476
  gint             padding;
477

478 479
  tool_options = GIMP_TOOL (tool)->tool_info->tool_options;

480
  vbox = image_map_tool->main_vbox;
Elliot Lee's avatar
Elliot Lee committed
481

482
  /*  The option menu for selecting channels  */
483
  hbox = gtk_hbox_new (FALSE, 6);
484 485 486 487 488 489 490
  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);

491 492 493 494 495 496
  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");
497 498 499
  gtk_box_pack_start (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
  gtk_widget_show (menu);

500
  tool->channel_menu = menu;
501

502
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
503
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
504
  gtk_widget_show (button);
505

506
  g_signal_connect (button, "clicked",
507
                    G_CALLBACK (curves_channel_reset_callback),
508
                    tool);
Elliot Lee's avatar
Elliot Lee committed
509

510 511 512 513 514
  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);
515

516
  /*  The table for the color bars and the graph  */
Elliot Lee's avatar
Elliot Lee committed
517
  table = gtk_table_new (2, 2, FALSE);
518 519
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
520 521 522 523 524
  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,
525
                    GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
526
  gtk_widget_show (vbox2);
Elliot Lee's avatar
Elliot Lee committed
527 528

  frame = gtk_frame_new (NULL);
529
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
530
  gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
531 532
  gtk_widget_show (frame);

533 534 535 536
  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);
537

Elliot Lee's avatar
Elliot Lee committed
538 539
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
540
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
541
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
542
                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
543
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
544

545 546 547 548 549 550 551 552 553
  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,
554 555 556
                "border-width", RADIUS,
                "subdivisions", 1,
                NULL);
557 558 559
  GIMP_HISTOGRAM_VIEW (tool->graph)->light_histogram = TRUE;
  gtk_container_add (GTK_CONTAINER (frame), tool->graph);
  gtk_widget_show (tool->graph);
560

561
  g_signal_connect (tool->graph, "event",
562 563
                    G_CALLBACK (curves_graph_events),
                    tool);
564
  g_signal_connect_after (tool->graph, "expose_event",
565
                          G_CALLBACK (curves_graph_expose),
566
                          tool);
Elliot Lee's avatar
Elliot Lee committed
567

568 569

  gimp_histogram_options_connect_view (GIMP_HISTOGRAM_OPTIONS (tool_options),
570 571 572 573 574
                                       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,
575
                    GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
576
  gtk_widget_show (hbox2);
577

Elliot Lee's avatar
Elliot Lee committed
578
  frame = gtk_frame_new (NULL);
579
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
580
  gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
581 582
  gtk_widget_show (frame);

583 584 585 586
  vbox2 = gtk_vbox_new (TRUE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox2);
  gtk_widget_show (vbox2);

587 588 589 590
  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);
591

592 593 594 595
  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_box_pack_start (GTK_BOX (vbox2), bar, TRUE, TRUE, 0);
  gtk_widget_show (bar);

596
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
597

598

599 600 601
  hbox = gtk_hbox_new (FALSE, 6);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);
602

603
  /*  Horizontal button box for load / save */
604
  frame = gimp_frame_new (_("All Channels"));
605
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
606 607
  gtk_widget_show (frame);

608 609 610 611
  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox);
  gtk_widget_show (vbox);

612 613 614 615
  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);
616
  gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
617
  gtk_widget_show (bbox);
618

619 620 621 622 623
  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);
624

625 626 627 628 629
  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);
630

631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
  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_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
  gtk_widget_show (bbox);

  button = gtk_button_new_with_mnemonic (_("S_tore"));
  gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
  g_signal_connect (button, "clicked",
                    G_CALLBACK (gimp_curves_tool_store_settings),
                    tool);
  gimp_help_set_help_data (button,
                           _("Remember curve temporarily"), NULL);
  gtk_widget_show (button);

  button = gtk_button_new_with_mnemonic (_("_Recall"));
  gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
  g_signal_connect (button, "clicked",
                    G_CALLBACK (gimp_curves_tool_recall_settings),
                    tool);
  gimp_help_set_help_data (button,
                           _("Recall most recently stored curve"), NULL);
  gtk_widget_show (button);

656
  /*  The radio box for selecting the curve type  */
657
  frame = gimp_frame_new (_("Curve Type"));
658 659 660 661
  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,
662 663 664 665
                                  "gimp-curve", GTK_ICON_SIZE_MENU,
                                  G_CALLBACK (curves_curve_type_callback),
                                  tool,
                                  &tool->curve_type);
666 667 668 669

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

  gimp_enum_stock_box_set_child_padding (hbox, padding, -1);
670 671 672 673 674 675

  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
676 677
}

678
static void
679
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
680
{
681
  GimpCurvesTool       *tool = GIMP_CURVES_TOOL (image_map_tool);
682
  GimpHistogramChannel  channel;
683

684
  tool->grab_point = -1;
685

686 687 688
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
689
    curves_channel_reset (tool->curves, channel);
690

691
  curves_update (tool, XRANGE | GRAPH);
692 693
}

694
static gboolean
695 696
gimp_curves_tool_settings_load (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
697
{
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
  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++)
715 716 717 718
        {
          fields = fscanf (file, "%d %d ", &index[i][j], &value[i][j]);
          if (fields != 2)
            {
719
              /*  FIXME: should have a helpful error message here  */
720 721 722 723
              g_printerr ("fields != 2");
              return FALSE;
            }
        }
724 725 726 727 728 729 730
    }

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

      for (j = 0; j < 17; j++)
731 732 733 734
        {
          tool->curves->points[i][j][0] = index[i][j];
          tool->curves->points[i][j][1] = value[i][j];
        }
735 736 737 738 739 740 741 742
    }

  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),
743
                                   GIMP_CURVE_SMOOTH);
744 745

  return TRUE;
746 747 748
}

static gboolean
749 750
gimp_curves_tool_settings_save (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
751
{
752 753 754 755 756 757 758 759
  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)
      {
760
        /*  pick representative points from the curve
761
            and make them control points  */
762 763 764 765 766 767
        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];
          }
768 769 770 771 772 773 774
      }

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

  for (i = 0; i < 5; i++)
    {
      for (j = 0; j < 17; j++)
775
        fprintf (file, "%d %d ",
776 777 778 779 780 781 782
                 tool->curves->points[i][j][0],
                 tool->curves->points[i][j][1]);

      fprintf (file, "\n");
    }

  return TRUE;
783
}
784

785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
static void
gimp_curves_tool_store_settings (GtkWidget *widget,
                                 gpointer data)
{
  GimpImageMapTool *tool = (GimpImageMapTool *)data;
  gchar *tmp;
  FILE  *fp;

  tmp = g_build_filename (gimp_directory (),
                          GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->settings_name,
                          G_DIR_SEPARATOR_S,
                          ".stored-curve",
                          NULL);

  fp = fopen (tmp, "w");
  if (!fp)
    {
      g_message ("Unable to open file for curves store.");
      return;
    }

  gimp_curves_tool_settings_save (tool, (gpointer)fp);
  fclose (fp);
  g_free (tmp);
}


static void
gimp_curves_tool_recall_settings (GtkWidget *widget,
                                 gpointer data)
{
  GimpImageMapTool *tool = (GimpImageMapTool *)data;
  gchar *tmp;
  FILE  *fp;

  tmp = g_build_filename (gimp_directory (),
                          GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->settings_name,
                          G_DIR_SEPARATOR_S,
                          ".stored-curve",
                          NULL);

  fp = fopen (tmp, "r");
  if (!fp)
    {
      g_message ("Unable to open file for curves recall.");
      return;
    }

  gimp_curves_tool_settings_load (tool, (gpointer)fp);
  fclose (fp);
  g_free (tmp);
}

838
/* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
Elliot Lee's avatar
Elliot Lee committed
839
static void
840
curves_update (GimpCurvesTool *tool,
841
               gint            update)
Elliot Lee's avatar
Elliot Lee committed
842
{
843
  GimpHistogramChannel channel;
844

845
  if (tool->color)
846
    {
847
      channel = tool->channel;
848
    }
849
  else
850
    {
851
      if (tool->channel == 2)
852
        channel = GIMP_HISTOGRAM_ALPHA;
853
      else
854
        channel = GIMP_HISTOGRAM_VALUE;
855
    }
856

857 858 859
  if (update & GRAPH)
    gtk_widget_queue_draw (tool->graph);

860
  if (update & XRANGE)
Elliot Lee's avatar
Elliot Lee committed
861
    {