gimpcurvestool.c 42.4 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
#include <gtk/gtk.h>
26
#include <gdk/gdkkeysyms.h>
Sven Neumann's avatar
Sven Neumann committed
27

28
#include "libgimpcolor/gimpcolor.h"
29
#include "libgimpwidgets/gimpwidgets.h"
30

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

33
#include "config/gimpguiconfig.h"
34

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

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

46
#include "widgets/gimpcolorbar.h"
Michael Natterer's avatar
Michael Natterer committed
47
#include "widgets/gimpcursor.h"
48
#include "widgets/gimphelp-ids.h"
49
#include "widgets/gimphistogramview.h"
Michael Natterer's avatar
Michael Natterer committed
50

51 52
#include "display/gimpdisplay.h"

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

57
#include "gimp-intl.h"
58

59

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

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


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

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

static void     gimp_curves_tool_finalize       (GObject          *object);

static gboolean gimp_curves_tool_initialize     (GimpTool         *tool,
                                                 GimpDisplay      *gdisp);
80
static void     gimp_curves_tool_button_release (GimpTool         *tool,
81
                                                 GimpCoords       *coords,
82
                                                 guint32           time,
83 84
                                                 GdkModifierType   state,
                                                 GimpDisplay      *gdisp);
85 86 87 88
static gboolean gimp_curves_tool_key_press      (GimpTool         *tool,
                                                 GdkEventKey      *kevent,
                                                 GimpDisplay      *gdisp);
static void     gimp_curves_tool_oper_update    (GimpTool         *tool,
89 90 91 92 93
                                                 GimpCoords       *coords,
                                                 GdkModifierType   state,
                                                 GimpDisplay      *gdisp);

static void     gimp_curves_tool_color_picked   (GimpColorTool    *color_tool,
94
                                                 GimpColorPickState pick_state,
95 96 97 98 99 100
                                                 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);
101 102 103 104
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);
105

106
static void     curves_add_point                (GimpCurvesTool   *tool,
107 108 109
                                                 gint              channel);
static gboolean curves_key_press                (GimpCurvesTool   *tool,
                                                 GdkEventKey      *kevent);
110
static void     curves_update                   (GimpCurvesTool   *tool,
111 112 113
                                                 gint              update);

static void     curves_channel_callback         (GtkWidget        *widget,
114
                                                 GimpCurvesTool   *tool);
115
static void     curves_channel_reset_callback   (GtkWidget        *widget,
116
                                                 GimpCurvesTool   *tool);
117

118
static gboolean curves_menu_sensitivity         (gint              value,
Sven Neumann's avatar
Sven Neumann committed
119
                                                 gpointer          data);
120

121
static void     curves_curve_type_callback      (GtkWidget        *widget,
122
                                                 GimpCurvesTool   *tool);
123 124
static gboolean curves_graph_events             (GtkWidget        *widget,
                                                 GdkEvent         *event,
125
                                                 GimpCurvesTool   *tool);
126 127
static gboolean curves_graph_expose             (GtkWidget        *widget,
                                                 GdkEventExpose   *eevent,
128
                                                 GimpCurvesTool   *tool);
129

Michael Natterer's avatar
Michael Natterer committed
130

131 132
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
133

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

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

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

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

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

  return tool_type;
}

181 182 183

/*  private functions  */

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

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

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

199 200 201 202
  object_class->finalize     = gimp_curves_tool_finalize;

  tool_class->initialize     = gimp_curves_tool_initialize;
  tool_class->button_release = gimp_curves_tool_button_release;
203 204
  tool_class->key_press      = gimp_curves_tool_key_press;
  tool_class->oper_update    = gimp_curves_tool_oper_update;
205 206

  color_tool_class->picked   = gimp_curves_tool_color_picked;
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");
211
  image_map_tool_class->load_button_tip   = _("Load curves settings from file");
212
  image_map_tool_class->save_dialog_title = _("Save Curves");
213
  image_map_tool_class->save_button_tip   = _("Save curves settings to file");
214

215 216 217
  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;
218

219 220
  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
221 222 223
}

static void
224
gimp_curves_tool_init (GimpCurvesTool *tool)
Michael Natterer's avatar
Michael Natterer committed
225
{
226
  gint i;
227

228 229 230
  tool->curves  = g_new0 (Curves, 1);
  tool->lut     = gimp_lut_new ();
  tool->channel = GIMP_HISTOGRAM_VALUE;
231

232
  curves_init (tool->curves);
233

234 235
  for (i = 0; i < G_N_ELEMENTS (tool->col_value); i++)
    tool->col_value[i] = -1;
236

237 238
  tool->cursor_x = -1;
  tool->cursor_y = -1;
Michael Natterer's avatar
Michael Natterer committed
239 240 241
}

static void
242
gimp_curves_tool_finalize (GObject *object)
Michael Natterer's avatar
Michael Natterer committed
243
{
244
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (object);
245

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

272
  G_OBJECT_CLASS (parent_class)->finalize (object);
Michael Natterer's avatar
Michael Natterer committed
273 274
}

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

282 283 284
  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (! drawable)
285
    return FALSE;
286

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

293
  if (! c_tool->hist)
294
    c_tool->hist = gimp_histogram_new ();
295

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

298
  c_tool->channel = GIMP_HISTOGRAM_VALUE;
299 300
  c_tool->color   = gimp_drawable_is_rgb (drawable);
  c_tool->alpha   = gimp_drawable_has_alpha (drawable);
301

302 303 304
  c_tool->selected = 0;
  c_tool->grabbed  = FALSE;
  c_tool->last     = 0;
305 306 307

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

308 309 310 311
  /*  always pick colors  */
  gimp_color_tool_enable (GIMP_COLOR_TOOL (tool),
                          GIMP_COLOR_OPTIONS (tool->tool_info->tool_options));

312 313
  gimp_int_combo_box_set_sensitivity (GIMP_INT_COMBO_BOX (c_tool->channel_menu),
                                      curves_menu_sensitivity, c_tool, NULL);
314

315 316
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (c_tool->channel_menu),
                                 c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
317

318 319 320
  /* FIXME: hack */
  if (! c_tool->color)
    c_tool->channel = (c_tool->channel == GIMP_HISTOGRAM_ALPHA) ? 1 : 0;
321

322 323 324
  gimp_drawable_calculate_histogram (drawable, c_tool->hist);
  gimp_histogram_view_set_histogram (GIMP_HISTOGRAM_VIEW (c_tool->graph),
                                     c_tool->hist);
325

326 327
  curves_update (c_tool, ALL);

328
  return TRUE;
Michael Natterer's avatar
Michael Natterer committed
329 330 331
}

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

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

343
  if (state & GDK_SHIFT_MASK)
Michael Natterer's avatar
Michael Natterer committed
344
    {
345
      curves_add_point (c_tool, c_tool->channel);
346
      curves_calculate_curve (c_tool->curves, c_tool->channel);
347
      curves_update (c_tool, GRAPH | XRANGE);
Michael Natterer's avatar
Michael Natterer committed
348
    }
349
  else if (state & GDK_CONTROL_MASK)
Michael Natterer's avatar
Michael Natterer committed
350
    {
351
      gint i;
352

353 354
      for (i = 0; i < 5; i++)
        {
355
          curves_add_point (c_tool, i);
356 357
          curves_calculate_curve (c_tool->curves, c_tool->channel);
        }
358

359
      curves_update (c_tool, GRAPH | XRANGE);
Michael Natterer's avatar
Michael Natterer committed
360 361
    }

362 363 364
  /*  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
365 366
}

367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
gboolean
gimp_curves_tool_key_press (GimpTool    *tool,
                            GdkEventKey *kevent,
                            GimpDisplay *gdisp)
{
  return curves_key_press (GIMP_CURVES_TOOL (tool), kevent);
}

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
405
static void
406 407
gimp_curves_tool_color_picked (GimpColorTool      *color_tool,
                               GimpColorPickState  pick_state,
408 409 410
                               GimpImageType       sample_type,
                               GimpRGB            *color,
                               gint                color_index)
Michael Natterer's avatar
Michael Natterer committed
411
{
412
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (color_tool);
413
  GimpDrawable   *drawable;
414
  guchar          r, g, b, a;
Michael Natterer's avatar
Michael Natterer committed
415

416
  drawable = GIMP_IMAGE_MAP_TOOL (tool)->drawable;
417

418
  gimp_rgba_get_uchar (color, &r, &g, &b, &a);
419

420 421 422
  tool->col_value[GIMP_HISTOGRAM_RED]   = r;
  tool->col_value[GIMP_HISTOGRAM_GREEN] = g;
  tool->col_value[GIMP_HISTOGRAM_BLUE]  = b;
423

424
  if (gimp_drawable_has_alpha (drawable))
425
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = a;
426

427
  if (gimp_drawable_is_indexed (drawable))
428
    tool->col_value[GIMP_HISTOGRAM_ALPHA] = color_index;
429

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

432
  curves_update (tool, GRAPH);
433
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
434

435
static void
436
curves_add_point (GimpCurvesTool *tool,
437
                  gint            channel)
438 439
{
  /* Add point onto the curve */
440 441 442 443
  gint closest_point = 0;
  gint distance;
  gint curvex;
  gint i;
444

445
  switch (tool->curves->curve_type[channel])
446
    {
447
    case GIMP_CURVE_SMOOTH:
448
      curvex   = tool->col_value[channel];
449
      distance = G_MAXINT;
450

451
      for (i = 0; i < CURVES_NUM_POINTS; i++)
452
        {
453 454
          if (tool->curves->points[channel][i][0] != -1)
            if (abs (curvex - tool->curves->points[channel][i][0]) < distance)
455
              {
456
                distance = abs (curvex - tool->curves->points[channel][i][0]);
457 458 459
                closest_point = i;
              }
        }
460

461
      if (distance > MIN_DISTANCE)
462
        closest_point = (curvex + 8) / 16;
463

464 465 466 467
      tool->curves->points[channel][closest_point][0] = curvex;
      tool->curves->points[channel][closest_point][1] = tool->curves->curve[channel][curvex];

      tool->selected = closest_point;
468
      break;
469

470
    case GIMP_CURVE_FREE:
471
      /* do nothing for free form curves */
472
      break;
473
    }
Elliot Lee's avatar
Elliot Lee committed
474 475
}

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
static gboolean
curves_key_press (GimpCurvesTool *tool,
                  GdkEventKey    *kevent)
{
  gint     i      = tool->selected;
  gint     y      = tool->curves->points[tool->channel][i][1];
  gboolean update = FALSE;

  if (tool->grabbed ||
      tool->curves->curve_type[tool->channel] == GIMP_CURVE_FREE)
    return FALSE;

  switch (kevent->keyval)
    {
    case GDK_Left:
      for (i = i - 1; i >= 0 && !update; i--)
        {
          if (tool->curves->points[tool->channel][i][0] != -1)
            {
              tool->selected = i;
              update = TRUE;
            }
        }
      break;

    case GDK_Right:
      for (i = i + 1; i < CURVES_NUM_POINTS && !update; i++)
        {
          if (tool->curves->points[tool->channel][i][0] != -1)
            {
              tool->selected = i;
              update = TRUE;
            }
        }
      break;

    case GDK_Up:
      if (y < 255)
        {
          y = y + (kevent->state & GDK_SHIFT_MASK ? 16 : 1);
          tool->curves->points[tool->channel][i][1] = MIN (y, 255);
          curves_calculate_curve (tool->curves, tool->channel);
          update = TRUE;
        }
      break;

    case GDK_Down:
      if (y > 0)
        {
          y = y - (kevent->state & GDK_SHIFT_MASK ? 16 : 1);
          tool->curves->points[tool->channel][i][1] = MAX (y, 0);
          curves_calculate_curve (tool->curves, tool->channel);
          update = TRUE;
        }
      break;

    default:
      break;
    }

  if (update)
    {
      curves_update (tool, GRAPH);
      gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool));
    }

  return update;
}

545 546
static void
gimp_curves_tool_map (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
547
{
548
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
549

550
  gimp_lut_setup (tool->lut,
551
                  (GimpLutFunc) curves_lut_func,
552
                  tool->curves,
553
                  gimp_drawable_bytes (image_map_tool->drawable));
554

555
  gimp_image_map_apply (image_map_tool->image_map,
556
                        (GimpImageMapApplyFunc) gimp_lut_process,
557
                        tool->lut);
Elliot Lee's avatar
Elliot Lee committed
558 559
}

560

561 562 563
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
564

565 566
static void
gimp_curves_tool_dialog (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
567
{
568
  GimpCurvesTool  *tool = GIMP_CURVES_TOOL (image_map_tool);
569
  GimpToolOptions *tool_options;
570
  GtkListStore    *store;
571
  GtkWidget       *vbox;
572 573 574 575 576
  GtkWidget       *vbox2;
  GtkWidget       *hbox;
  GtkWidget       *hbox2;
  GtkWidget       *label;
  GtkWidget       *bbox;
577 578 579 580
  GtkWidget       *frame;
  GtkWidget       *menu;
  GtkWidget       *table;
  GtkWidget       *button;
581
  GtkWidget       *bar;
582
  gint             padding;
583

584 585
  tool_options = GIMP_TOOL (tool)->tool_info->tool_options;

586
  vbox = image_map_tool->main_vbox;
Elliot Lee's avatar
Elliot Lee committed
587

588
  /*  The option menu for selecting channels  */
589
  hbox = gtk_hbox_new (FALSE, 6);
590 591 592
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

593
  label = gtk_label_new_with_mnemonic (_("Cha_nnel:"));
594 595 596
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

597 598 599
  store = gimp_enum_store_new_with_range (GIMP_TYPE_HISTOGRAM_CHANNEL,
                                          GIMP_HISTOGRAM_VALUE,
                                          GIMP_HISTOGRAM_ALPHA);
600
  menu = gimp_enum_combo_box_new_with_model (GIMP_ENUM_STORE (store));
601 602
  g_object_unref (store);

603 604 605 606 607
  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");
608 609 610
  gtk_box_pack_start (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
  gtk_widget_show (menu);

611
  tool->channel_menu = menu;
612

613 614
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), menu);

615
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
616
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
617
  gtk_widget_show (button);
618

619
  g_signal_connect (button, "clicked",
620
                    G_CALLBACK (curves_channel_reset_callback),
621
                    tool);
Elliot Lee's avatar
Elliot Lee committed
622

623 624 625 626 627
  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);
628

629
  /*  The table for the color bars and the graph  */
Elliot Lee's avatar
Elliot Lee committed
630
  table = gtk_table_new (2, 2, FALSE);
631 632
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
633 634 635 636 637
  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,
638
                    GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
639
  gtk_widget_show (vbox2);
Elliot Lee's avatar
Elliot Lee committed
640 641

  frame = gtk_frame_new (NULL);
642
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
643
  gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
644 645
  gtk_widget_show (frame);

646 647 648 649
  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);
650

Elliot Lee's avatar
Elliot Lee committed
651 652
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
653
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
654
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
655
                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
656
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
657

658 659 660 661
  tool->graph = gimp_histogram_view_new (FALSE);
  gtk_widget_set_size_request (tool->graph,
                               GRAPH_SIZE + RADIUS * 2,
                               GRAPH_SIZE + RADIUS * 2);
662
  GTK_WIDGET_SET_FLAGS (tool->graph, GTK_CAN_FOCUS);
663 664 665
  gtk_widget_add_events (tool->graph, (GDK_BUTTON_PRESS_MASK   |
                                       GDK_BUTTON_RELEASE_MASK |
                                       GDK_POINTER_MOTION_MASK |
666
                                       GDK_KEY_PRESS_MASK      |
667 668
                                       GDK_LEAVE_NOTIFY_MASK));
  g_object_set (tool->graph,
669 670 671
                "border-width", RADIUS,
                "subdivisions", 1,
                NULL);
672 673 674
  GIMP_HISTOGRAM_VIEW (tool->graph)->light_histogram = TRUE;
  gtk_container_add (GTK_CONTAINER (frame), tool->graph);
  gtk_widget_show (tool->graph);
675

676
  g_signal_connect (tool->graph, "event",
677 678
                    G_CALLBACK (curves_graph_events),
                    tool);
679
  g_signal_connect_after (tool->graph, "expose-event",
680
                          G_CALLBACK (curves_graph_expose),
681
                          tool);
Elliot Lee's avatar
Elliot Lee committed
682

683 684

  gimp_histogram_options_connect_view (GIMP_HISTOGRAM_OPTIONS (tool_options),
685 686 687 688 689
                                       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,
690
                    GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
691
  gtk_widget_show (hbox2);
692

Elliot Lee's avatar
Elliot Lee committed
693
  frame = gtk_frame_new (NULL);
694
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
695
  gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
696 697
  gtk_widget_show (frame);

698 699 700 701
  vbox2 = gtk_vbox_new (TRUE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox2);
  gtk_widget_show (vbox2);

702 703 704 705
  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);
706

707 708 709 710
  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_box_pack_start (GTK_BOX (vbox2), bar, TRUE, TRUE, 0);
  gtk_widget_show (bar);

711
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
712

713

714 715 716
  hbox = gtk_hbox_new (FALSE, 6);
  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);
717

718
  /*  Horizontal button box for load / save */
719
  frame = gimp_frame_new (_("All Channels"));
720
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
721 722
  gtk_widget_show (frame);

723 724
  bbox = gtk_hbutton_box_new ();
  gtk_box_set_spacing (GTK_BOX (bbox), 4);
725
  gtk_container_add (GTK_CONTAINER (frame), bbox);
726
  gtk_widget_show (bbox);
727

728 729 730
  gtk_box_pack_start (GTK_BOX (bbox), image_map_tool->load_button,
                      FALSE, FALSE, 0);
  gtk_widget_show (image_map_tool->load_button);
731

732 733 734
  gtk_box_pack_start (GTK_BOX (bbox), image_map_tool->save_button,
                      FALSE, FALSE, 0);
  gtk_widget_show (image_map_tool->save_button);
735 736

  /*  The radio box for selecting the curve type  */
737
  frame = gimp_frame_new (_("Curve Type"));
738 739 740 741
  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,
742 743 744 745
                                  "gimp-curve", GTK_ICON_SIZE_MENU,
                                  G_CALLBACK (curves_curve_type_callback),
                                  tool,
                                  &tool->curve_type);
746

747
  gtk_widget_style_get (bbox, "child-internal-pad-x", &padding, NULL);
748 749

  gimp_enum_stock_box_set_child_padding (hbox, padding, -1);
750 751 752 753 754 755

  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
756 757
}

758
static void
759
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
760
{
761
  GimpCurvesTool       *tool = GIMP_CURVES_TOOL (image_map_tool);
762
  GimpHistogramChannel  channel;
763

764
  tool->grabbed = FALSE;
765

766 767 768
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
769
    curves_channel_reset (tool->curves, channel);
770

771
  curves_update (tool, XRANGE | GRAPH);
772 773
}

774
static gboolean
775 776
gimp_curves_tool_settings_load (GimpImageMapTool *image_map_tool,
                                gpointer          fp)
777
{
778 779 780 781 782
  GimpCurvesTool *tool = GIMP_CURVES_TOOL (image_map_tool);
  FILE           *file = fp;
  gint            i, j;
  gint            fields;
  gchar           buf[50];
783 784
  gint            index[5][CURVES_NUM_POINTS];
  gint            value[5][CURVES_NUM_POINTS];
785 786 787 788 789 790 791 792 793

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

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

  for (i = 0; i < 5; i++)
    {
794
      for (j = 0; j < CURVES_NUM_POINTS; j++)
795 796 797 798
        {
          fields = fscanf (file, "%d %d ", &index[i][j], &value[i][j]);
          if (fields != 2)
            {
799
              /*  FIXME: should have a helpful error message here  */
800 801 802 803
              g_printerr ("fields != 2");
              return FALSE;
            }
        }
804 805 806 807 808 809
    }

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

810
      for (j = 0; j < CURVES_NUM_POINTS; j++)
811 812 813 814
        {
          tool->curves->points[i][j][0] = index[i][j];
          tool->curves->points[i][j][1] = value[i][j];
        }
815 816 817 818 819 820 821 822
    }

  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),
823
                                   GIMP_CURVE_SMOOTH);
824 825

  return TRUE;
826 827 828
}

static gboolean
Michael Natterer's avatar