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
#include <errno.h>
25

26 27 28 29 30
#ifdef __GNUC__
#warning GTK_DISABLE_DEPRECATED
#endif
#undef GTK_DISABLE_DEPRECATED

Sven Neumann's avatar
Sven Neumann committed
31 32
#include <gtk/gtk.h>

33
#include "libgimpmath/gimpmath.h"
34
#include "libgimpbase/gimpbase.h"
35
#include "libgimpwidgets/gimpwidgets.h"
36

37
#include "tools-types.h"
Michael Natterer's avatar
Michael Natterer committed
38

39
#include "base/curves.h"
Michael Natterer's avatar
Michael Natterer committed
40 41 42 43 44
#include "base/gimphistogram.h"
#include "base/gimplut.h"

#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
45
#include "core/gimpimagemap.h"
Michael Natterer's avatar
Michael Natterer committed
46 47

#include "widgets/gimpcursor.h"
48
#include "widgets/gimpenummenu.h"
Michael Natterer's avatar
Michael Natterer committed
49

50 51
#include "display/gimpdisplay.h"

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

55 56
#include "libgimp/gimpintl.h"

57

58 59 60 61 62 63
#define GRAPH          0x1
#define XRANGE_TOP     0x2
#define XRANGE_BOTTOM  0x4
#define YRANGE         0x8
#define DRAW          0x10
#define ALL           0xFF
Elliot Lee's avatar
Elliot Lee committed
64

65
/*  NB: take care when changing these values: make sure the curve[] array in
66
 *  base/curves.h is large enough.
67
 */
68 69 70 71 72 73
#define GRAPH_WIDTH    256
#define GRAPH_HEIGHT   256
#define XRANGE_WIDTH   256
#define XRANGE_HEIGHT   16
#define YRANGE_WIDTH    16
#define YRANGE_HEIGHT  256
Elliot Lee's avatar
Elliot Lee committed
74 75 76 77 78 79 80 81 82 83 84 85
#define RADIUS           3
#define MIN_DISTANCE     8

#define GRAPH_MASK  GDK_EXPOSURE_MASK | \
		    GDK_POINTER_MOTION_MASK | \
		    GDK_POINTER_MOTION_HINT_MASK | \
                    GDK_ENTER_NOTIFY_MASK | \
		    GDK_BUTTON_PRESS_MASK | \
		    GDK_BUTTON_RELEASE_MASK | \
		    GDK_BUTTON1_MOTION_MASK


Michael Natterer's avatar
Michael Natterer committed
86 87 88
/*  local function prototypes  */

static void   gimp_curves_tool_class_init     (GimpCurvesToolClass *klass);
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
static void   gimp_curves_tool_init           (GimpCurvesTool      *c_tool);

static void   gimp_curves_tool_finalize       (GObject          *object);

static void   gimp_curves_tool_initialize     (GimpTool         *tool,
					       GimpDisplay      *gdisp);
static void   gimp_curves_tool_button_press   (GimpTool         *tool,
                                               GimpCoords       *coords,
                                               guint32           time,
					       GdkModifierType   state,
					       GimpDisplay      *gdisp);
static void   gimp_curves_tool_button_release (GimpTool         *tool,
                                               GimpCoords       *coords,
                                               guint32           time,
					       GdkModifierType   state,
					       GimpDisplay      *gdisp);
static void   gimp_curves_tool_motion         (GimpTool         *tool,
                                               GimpCoords       *coords,
                                               guint32           time,
					       GdkModifierType   state,
					       GimpDisplay      *gdisp);

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);

static void   curves_color_update             (GimpTool         *tool,
					       GimpDisplay      *gdisp,
					       GimpDrawable     *drawable,
					       gint              x,
					       gint              y);
static void   curves_add_point                (GimpCurvesTool   *c_tool,
					       gint              x,
					       gint              y,
					       gint              cchan);

static void   curves_update                   (GimpCurvesTool   *c_tool,
                                               gint              update);

static void   curves_channel_callback         (GtkWidget        *widget,
                                               gpointer          data);
static void   curves_channel_reset_callback   (GtkWidget        *widget,
                                               gpointer          data);

static gboolean curves_set_sensitive_callback (gpointer          item_data,
                                               GimpCurvesTool   *c_tool);
static void   curves_smooth_callback          (GtkWidget        *widget,
                                               gpointer          data);
static void   curves_free_callback            (GtkWidget        *widget,
                                               gpointer          data);

static void   curves_load_callback            (GtkWidget        *widget,
                                               gpointer          data);
static void   curves_save_callback            (GtkWidget        *widget,
                                               gpointer          data);
static gint   curves_graph_events             (GtkWidget        *widget,
                                               GdkEvent         *event,
                                               GimpCurvesTool   *c_tool);

static void       file_dialog_create          (GimpCurvesTool   *c_tool);
static void       file_dialog_ok_callback     (GimpCurvesTool   *c_tool);
static gboolean   file_dialog_cancel_callback (GimpCurvesTool   *c_tool);

static gboolean   curves_read_from_file       (GimpCurvesTool   *c_tool,
                                               FILE             *file);
static void       curves_write_to_file        (GimpCurvesTool   *c_tool,
                                               FILE             *file);

Michael Natterer's avatar
Michael Natterer committed
157

158 159
static GimpImageMapToolClass *parent_class = NULL;

Michael Natterer's avatar
Michael Natterer committed
160

161
/*  public functions  */
Michael Natterer's avatar
Michael Natterer committed
162 163

void
Nate Summers's avatar
Nate Summers committed
164
gimp_curves_tool_register (GimpToolRegisterCallback  callback,
165
                           gpointer                  data)
Michael Natterer's avatar
Michael Natterer committed
166
{
Nate Summers's avatar
Nate Summers committed
167
  (* callback) (GIMP_TYPE_CURVES_TOOL,
168 169
                NULL,
                FALSE,
170
                "gimp-curves-tool",
171 172
                _("Curves"),
                _("Adjust color curves"),
173
                N_("/Layer/Colors/Curves..."), NULL,
174
                NULL, "tools/curves.html",
Nate Summers's avatar
Nate Summers committed
175
                GIMP_STOCK_TOOL_CURVES,
176
                data);
Michael Natterer's avatar
Michael Natterer committed
177 178
}

179
GType
Michael Natterer's avatar
Michael Natterer committed
180 181
gimp_curves_tool_get_type (void)
{
182
  static GType tool_type = 0;
Michael Natterer's avatar
Michael Natterer committed
183 184 185

  if (! tool_type)
    {
186
      static const GTypeInfo tool_info =
Michael Natterer's avatar
Michael Natterer committed
187 188
      {
        sizeof (GimpCurvesToolClass),
189 190 191 192 193 194 195 196
	(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
197 198
      };

199 200 201
      tool_type = g_type_register_static (GIMP_TYPE_IMAGE_MAP_TOOL,
					  "GimpCurvesTool", 
                                          &tool_info, 0);
Michael Natterer's avatar
Michael Natterer committed
202 203 204 205 206
    }

  return tool_type;
}

207 208 209

/*  private functions  */

Michael Natterer's avatar
Michael Natterer committed
210 211 212
static void
gimp_curves_tool_class_init (GimpCurvesToolClass *klass)
{
213 214 215
  GObjectClass          *object_class;
  GimpToolClass         *tool_class;
  GimpImageMapToolClass *image_map_tool_class;
Michael Natterer's avatar
Michael Natterer committed
216

217 218 219
  object_class         = G_OBJECT_CLASS (klass);
  tool_class           = GIMP_TOOL_CLASS (klass);
  image_map_tool_class = GIMP_IMAGE_MAP_TOOL_CLASS (klass);
Michael Natterer's avatar
Michael Natterer committed
220

221
  parent_class = g_type_class_peek_parent (klass);
Michael Natterer's avatar
Michael Natterer committed
222

223 224 225 226 227 228 229 230 231 232
  object_class->finalize       = gimp_curves_tool_finalize;

  tool_class->initialize       = gimp_curves_tool_initialize;
  tool_class->button_press     = gimp_curves_tool_button_press;
  tool_class->button_release   = gimp_curves_tool_button_release;
  tool_class->motion           = gimp_curves_tool_motion;

  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;
Michael Natterer's avatar
Michael Natterer committed
233 234 235
}

static void
236
gimp_curves_tool_init (GimpCurvesTool *c_tool)
Michael Natterer's avatar
Michael Natterer committed
237
{
238 239 240 241 242
  GimpImageMapTool *image_map_tool;
  gint              i;

  image_map_tool = GIMP_IMAGE_MAP_TOOL (c_tool);

243
  image_map_tool->shell_desc  = _("Adjust Color Curves");
244

245 246 247
  c_tool->curves              = g_new0 (Curves, 1);
  c_tool->lut                 = gimp_lut_new ();
  c_tool->channel             = GIMP_HISTOGRAM_VALUE;
248 249 250 251 252 253 254 255

  curves_init (c_tool->curves);

  for (i = 0;
       i < (sizeof (c_tool->col_value) /
            sizeof (c_tool->col_value[0]));
       i++)
    c_tool->col_value[i] = 0;
Michael Natterer's avatar
Michael Natterer committed
256 257 258
}

static void
259
gimp_curves_tool_finalize (GObject *object)
Michael Natterer's avatar
Michael Natterer committed
260
{
261
  GimpCurvesTool *c_tool;
Michael Natterer's avatar
Michael Natterer committed
262

263 264 265
  c_tool = GIMP_CURVES_TOOL (object);

  if (c_tool->curves)
Michael Natterer's avatar
Michael Natterer committed
266
    {
267 268
      g_free(c_tool->curves);
      c_tool->curves = NULL;
Michael Natterer's avatar
Michael Natterer committed
269 270
    }

271
  if (c_tool->lut)
Michael Natterer's avatar
Michael Natterer committed
272
    {
273 274
      gimp_lut_free (c_tool->lut);
      c_tool->lut = NULL;
Michael Natterer's avatar
Michael Natterer committed
275 276
    }

277
  if (c_tool->pixmap)
Michael Natterer's avatar
Michael Natterer committed
278
    {
279 280
      g_object_unref (c_tool->pixmap);
      c_tool->pixmap = NULL;
Michael Natterer's avatar
Michael Natterer committed
281
    }
282 283

  if (c_tool->cursor_layout)
Michael Natterer's avatar
Michael Natterer committed
284
    {
285 286
      g_object_unref (c_tool->cursor_layout);
      c_tool->cursor_layout = NULL;
Michael Natterer's avatar
Michael Natterer committed
287 288
    }

289 290 291 292 293
  if (c_tool->xpos_layout)
    {
      g_object_unref (c_tool->xpos_layout);
      c_tool->xpos_layout = NULL;
    }
Michael Natterer's avatar
Michael Natterer committed
294

295
  G_OBJECT_CLASS (parent_class)->finalize (object);
Michael Natterer's avatar
Michael Natterer committed
296 297 298
}

static void
299 300
gimp_curves_tool_initialize (GimpTool    *tool,
			     GimpDisplay *gdisp)
Michael Natterer's avatar
Michael Natterer committed
301
{
302 303 304 305
  GimpCurvesTool *c_tool;
  GimpDrawable   *drawable;

  c_tool = GIMP_CURVES_TOOL (tool);
306 307

  if (gimp_drawable_is_indexed (gimp_image_active_drawable (gdisp->gimage)))
Michael Natterer's avatar
Michael Natterer committed
308
    {
309 310 311
      g_message (_("Curves for indexed drawables cannot be adjusted."));
      return;
    }
Michael Natterer's avatar
Michael Natterer committed
312

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

315
  curves_init (c_tool->curves);
Michael Natterer's avatar
Michael Natterer committed
316

317 318 319 320 321 322 323 324 325 326 327 328 329 330
  c_tool->color   = gimp_drawable_is_rgb (drawable);
  c_tool->channel = GIMP_HISTOGRAM_VALUE;

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

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

  /* set the sensitivity of the channel menu based on the drawable type */
  gimp_option_menu_set_sensitive (GTK_OPTION_MENU (c_tool->channel_menu),
                                  (GimpOptionMenuSensitivityCallback) curves_set_sensitive_callback,
                                  c_tool);

  /* set the current selection */
331 332
  gimp_option_menu_set_history (GTK_OPTION_MENU (c_tool->channel_menu),
                                GINT_TO_POINTER (c_tool->channel));
Michael Natterer's avatar
Michael Natterer committed
333

334
  curves_update (c_tool, ALL);
Michael Natterer's avatar
Michael Natterer committed
335 336 337
}

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

  c_tool = GIMP_CURVES_TOOL (tool);
Michael Natterer's avatar
Michael Natterer committed
348 349 350 351 352

  drawable = gimp_image_active_drawable (gdisp->gimage);

  tool->gdisp = gdisp;

353 354 355
  g_assert (drawable == tool->drawable);

#if 0
Michael Natterer's avatar
Michael Natterer committed
356 357
  if (drawable != tool->drawable)
    {
358
      gimp_tool_control_set_preserve (tool->control, TRUE);
359
      gimp_image_map_abort (GIMP_IMAGE_MAP_TOOL (tool)->image_map);
360
      gimp_tool_control_set_preserve (tool->control, FALSE);
Michael Natterer's avatar
Michael Natterer committed
361 362 363

      tool->drawable = drawable;

364 365 366 367
      c_tool->color  = gimp_drawable_is_rgb (drawable);

      GIMP_IMAGE_MAP_TOOL (tool)->drawable  = drawable;
      GIMP_IMAGE_MAP_TOOL (tool)->image_map = gimp_image_map_new (TRUE, drawable);
368 369

      gimp_option_menu_set_sensitive 
370
        (GTK_OPTION_MENU (c_tool->channel_menu),
371
         (GimpOptionMenuSensitivityCallback) curves_set_sensitive_callback,
372
         c_tool);
Michael Natterer's avatar
Michael Natterer committed
373
    }
374
#endif
Michael Natterer's avatar
Michael Natterer committed
375

376
  gimp_tool_control_activate (tool->control);
Michael Natterer's avatar
Michael Natterer committed
377

378
  curves_color_update (tool, gdisp, drawable, coords->x, coords->y);
379
  curves_update (c_tool, GRAPH | DRAW);
Michael Natterer's avatar
Michael Natterer committed
380 381 382
}

static void
383 384 385 386 387
gimp_curves_tool_button_release (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 guint32          time,
				 GdkModifierType  state,
				 GimpDisplay     *gdisp)
Michael Natterer's avatar
Michael Natterer committed
388
{
389 390
  GimpCurvesTool *c_tool;
  GimpDrawable   *drawable;
Michael Natterer's avatar
Michael Natterer committed
391

392 393 394
  c_tool = GIMP_CURVES_TOOL (tool);

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

396
  curves_color_update (tool, gdisp, drawable, coords->x, coords->y);
Michael Natterer's avatar
Michael Natterer committed
397

398
  if (state & GDK_SHIFT_MASK)
Michael Natterer's avatar
Michael Natterer committed
399
    {
400
      curves_add_point (c_tool, coords->x, coords->y, c_tool->channel);
401
      curves_calculate_curve (c_tool->curves, c_tool->channel);
Michael Natterer's avatar
Michael Natterer committed
402
    }
403
  else if (state & GDK_CONTROL_MASK)
Michael Natterer's avatar
Michael Natterer committed
404
    {
405
      gint i;
406

407 408 409 410 411
      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
412 413
    }

414 415 416
  gimp_tool_control_halt (tool->control);

  curves_update (c_tool, GRAPH | DRAW);
Michael Natterer's avatar
Michael Natterer committed
417 418 419
}

static void
420 421 422 423 424
gimp_curves_tool_motion (GimpTool        *tool,
                         GimpCoords      *coords,
                         guint32          time,
			 GdkModifierType  state,
			 GimpDisplay     *gdisp)
Michael Natterer's avatar
Michael Natterer committed
425
{
426 427
  GimpCurvesTool *c_tool;
  GimpDrawable   *drawable;
Michael Natterer's avatar
Michael Natterer committed
428

429
  c_tool = GIMP_CURVES_TOOL (tool);
Elliot Lee's avatar
Elliot Lee committed
430

431
  drawable = gimp_image_active_drawable (gdisp->gimage);
Elliot Lee's avatar
Elliot Lee committed
432

433 434
  curves_color_update (tool, gdisp, drawable, coords->x, coords->y);
  curves_update (c_tool, GRAPH | DRAW);
Elliot Lee's avatar
Elliot Lee committed
435 436
}

BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
437
static void
438 439 440 441 442
curves_color_update (GimpTool       *tool,
                     GimpDisplay    *gdisp,
                     GimpDrawable   *drawable,
                     gint            x,
                     gint            y)
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
443
{
444 445 446 447 448 449 450 451 452 453 454 455
  GimpCurvesTool *c_tool;
  guchar         *color;
  gint            offx;
  gint            offy;
  gint            maxval;
  gboolean        has_alpha;
  gboolean        is_indexed;
  GimpImageType   sample_type;

  c_tool = GIMP_CURVES_TOOL (tool);

  if (! (tool && gimp_tool_control_is_active (tool->control)))
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
456 457
    return;

458
  gimp_drawable_offsets (drawable, &offx, &offy);
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
459 460 461 462

  x -= offx;
  y -= offy;

463 464
  if (! (color = gimp_image_map_get_color_at (GIMP_IMAGE_MAP_TOOL (tool)->image_map,
                                              x, y)))
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
465 466
    return;

467
  sample_type = gimp_drawable_type (drawable);
468 469
  is_indexed  = gimp_drawable_is_indexed (drawable);
  has_alpha   = GIMP_IMAGE_TYPE_HAS_ALPHA (sample_type);
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
470

471 472 473
  c_tool->col_value[GIMP_HISTOGRAM_RED]   = color[RED_PIX];
  c_tool->col_value[GIMP_HISTOGRAM_GREEN] = color[GREEN_PIX];
  c_tool->col_value[GIMP_HISTOGRAM_BLUE]  = color[BLUE_PIX];
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
474 475

  if (has_alpha)
476
    c_tool->col_value[GIMP_HISTOGRAM_ALPHA] = color[3];
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
477 478

  if (is_indexed)
479
    c_tool->col_value[GIMP_HISTOGRAM_ALPHA] = color[4];
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
480

481
  maxval = MAX (color[RED_PIX], color[GREEN_PIX]);
482
  c_tool->col_value[GIMP_HISTOGRAM_VALUE] = MAX (maxval, color[BLUE_PIX]);
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
483

484
  g_free (color);
485
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
486

487
static void
488 489 490 491
curves_add_point (GimpCurvesTool *c_tool,
		  gint            x,
		  gint            y,
		  gint            cchan)
492 493
{
  /* Add point onto the curve */
494 495 496 497
  gint closest_point = 0;
  gint distance;
  gint curvex;
  gint i;
498

499
  switch (c_tool->curves->curve_type[cchan])
500
    {
501 502
    case CURVES_SMOOTH:
      curvex   = c_tool->col_value[cchan];
503
      distance = G_MAXINT;
504

505 506
      for (i = 0; i < 17; i++)
	{
507 508
	  if (c_tool->curves->points[cchan][i][0] != -1)
	    if (abs (curvex - c_tool->curves->points[cchan][i][0]) < distance)
509
	      {
510
		distance = abs (curvex - c_tool->curves->points[cchan][i][0]);
511 512 513 514 515 516 517
		closest_point = i;
	      }
	}
      
      if (distance > MIN_DISTANCE)
	closest_point = (curvex + 8) / 16;
      
518 519
      c_tool->curves->points[cchan][closest_point][0] = curvex;
      c_tool->curves->points[cchan][closest_point][1] = c_tool->curves->curve[cchan][curvex];
520 521
      break;
      
522 523
    case CURVES_FREE:
      c_tool->curves->curve[cchan][x] = 255 - y;
524
      break;
525
    }
Elliot Lee's avatar
Elliot Lee committed
526 527
}

528 529
static void
gimp_curves_tool_map (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
530
{
531
  GimpCurvesTool *c_tool;
532

533
  c_tool = GIMP_CURVES_TOOL (image_map_tool);
534

535 536 537 538 539 540 541
  gimp_lut_setup (c_tool->lut, 
		  (GimpLutFunc) curves_lut_func,
                  c_tool->curves,
		  gimp_drawable_bytes (image_map_tool->drawable));
  gimp_image_map_apply (image_map_tool->image_map,
                        (GimpImageMapApplyFunc) gimp_lut_process_2,
                        c_tool->lut);
Elliot Lee's avatar
Elliot Lee committed
542 543
}

544

545 546 547
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
548

549 550
static void
gimp_curves_tool_dialog (GimpImageMapTool *image_map_tool)
Elliot Lee's avatar
Elliot Lee committed
551
{
552 553
  GimpCurvesTool *c_tool;
  GtkWidget      *hbox;
554
  GtkWidget      *vbox;
555 556 557 558
  GtkWidget      *hbbox;
  GtkWidget      *frame;
  GtkWidget      *table;
  GtkWidget      *button;
559

560
  c_tool = GIMP_CURVES_TOOL (image_map_tool);
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
561

562 563 564 565 566 567 568 569 570
  hbox = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (image_map_tool->main_vbox), hbox,
                      FALSE, FALSE, 0);
  gtk_widget_show (hbox);

  vbox = gtk_vbox_new (FALSE, 4);
  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, FALSE, 0);
  gtk_widget_show (vbox);

571 572 573
  table = gtk_table_new (2, 2, FALSE);
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
574
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
575
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
576

577 578
  /*  The option menu for selecting channels  */
  hbox = gtk_hbox_new (FALSE, 4);
579

580 581 582 583 584 585
  c_tool->channel_menu =
    gimp_enum_option_menu_new (GIMP_TYPE_HISTOGRAM_CHANNEL,
                               G_CALLBACK (curves_channel_callback),
                               c_tool);
  gtk_box_pack_start (GTK_BOX (hbox), c_tool->channel_menu, FALSE, FALSE, 0);
  gtk_widget_show (c_tool->channel_menu);
586

587
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
588 589
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  gtk_widget_show (button);
590

591 592 593
  g_signal_connect (G_OBJECT (button), "clicked",
                    G_CALLBACK (curves_channel_reset_callback),
                    c_tool);
594

595 596 597
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
                             _("Modify Curves for Channel:"), 1.0, 0.5,
                             hbox, 1, FALSE);
Elliot Lee's avatar
Elliot Lee committed
598

599 600 601
  /*  The option menu for selecting the drawing method  */
  c_tool->curve_type_menu =
    gimp_option_menu_new (FALSE,
Elliot Lee's avatar
Elliot Lee committed
602

603
                          _("Smooth"), curves_smooth_callback,
604
                          c_tool, GINT_TO_POINTER (CURVES_SMOOTH), NULL, TRUE,
Elliot Lee's avatar
Elliot Lee committed
605

606
                          _("Free"), curves_free_callback,
607
                          c_tool, GINT_TO_POINTER (CURVES_FREE), NULL, FALSE,
Elliot Lee's avatar
Elliot Lee committed
608

609
                          NULL);
Elliot Lee's avatar
Elliot Lee committed
610

611 612 613
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
                             _("Curve Type:"), 1.0, 0.5,
                             c_tool->curve_type_menu, 1, TRUE);
Elliot Lee's avatar
Elliot Lee committed
614 615 616

  /*  The table for the yrange and the graph  */
  table = gtk_table_new (2, 2, FALSE);
617 618
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
619
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
Elliot Lee's avatar
Elliot Lee committed
620 621 622

  /*  The range drawing area  */
  frame = gtk_frame_new (NULL);
623
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
624 625 626 627
  gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1,
		    GTK_EXPAND, GTK_EXPAND, 0, 0);
  gtk_widget_show (frame);

628 629 630 631 632
  c_tool->yrange = gtk_preview_new (GTK_PREVIEW_COLOR);
  gtk_preview_size (GTK_PREVIEW (c_tool->yrange), YRANGE_WIDTH, YRANGE_HEIGHT);
  gtk_container_add (GTK_CONTAINER (frame), c_tool->yrange);
  gtk_widget_show (c_tool->yrange);

Elliot Lee's avatar
Elliot Lee committed
633 634
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
635
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
636
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
637 638
		    GTK_SHRINK | GTK_FILL,
		    GTK_SHRINK | GTK_FILL, 0, 0);
639
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
640

641 642 643
  c_tool->graph = gtk_drawing_area_new ();
  gtk_widget_set_size_request (c_tool->graph,
                               GRAPH_WIDTH  + RADIUS * 2,
644
                               GRAPH_HEIGHT + RADIUS * 2);
645 646 647
  gtk_widget_set_events (c_tool->graph, GRAPH_MASK);
  gtk_container_add (GTK_CONTAINER (frame), c_tool->graph);
  gtk_widget_show (c_tool->graph);
648

649
  g_signal_connect (G_OBJECT (c_tool->graph), "event",
650
		    G_CALLBACK (curves_graph_events),
651
		    c_tool);
Elliot Lee's avatar
Elliot Lee committed
652 653 654

  /*  The range drawing area  */
  frame = gtk_frame_new (NULL);
655
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
656 657 658 659
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 1, 2,
		    GTK_EXPAND, GTK_EXPAND, 0, 0);
  gtk_widget_show (frame);

660 661 662 663
  c_tool->xrange = gtk_preview_new (GTK_PREVIEW_COLOR);
  gtk_preview_size (GTK_PREVIEW (c_tool->xrange), XRANGE_WIDTH, XRANGE_HEIGHT);
  gtk_container_add (GTK_CONTAINER (frame), c_tool->xrange);
  gtk_widget_show (c_tool->xrange);
664

665
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
666

667
  /*  Horizontal button box for load / save  */
668 669 670 671
  frame = gtk_frame_new (_("All Channels"));
  gtk_box_pack_end (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  gtk_widget_show (frame);

672
  hbbox = gtk_hbutton_box_new ();
673
  gtk_container_set_border_width (GTK_CONTAINER (hbbox), 2);
674
  gtk_box_set_spacing (GTK_BOX (hbbox), 4);
675
  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_SPREAD);
676
  gtk_container_add (GTK_CONTAINER (frame), hbbox);
677
  gtk_widget_show (hbbox);
678

679
  button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
680 681
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
682
  gimp_help_set_help_data (button, _("Read curves settings from file"), NULL);
683 684
  gtk_widget_show (button);

685 686
  g_signal_connect (G_OBJECT (button), "clicked",
		    G_CALLBACK (curves_load_callback),
687
		    c_tool);
688

689
  button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
690 691
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
692
  gimp_help_set_help_data (button, _("Save curves settings to file"), NULL);
693 694
  gtk_widget_show (button);

695 696
  g_signal_connect (G_OBJECT (button), "clicked",
		    G_CALLBACK (curves_save_callback),
697
		    c_tool);
Elliot Lee's avatar
Elliot Lee committed
698 699
}

700
static void
701
gimp_curves_tool_reset (GimpImageMapTool *image_map_tool)
702
{
703 704
  GimpCurvesTool       *c_tool;
  GimpHistogramChannel  channel;
705 706 707 708 709

  c_tool = GIMP_CURVES_TOOL (image_map_tool);

  c_tool->grab_point = -1;

710 711 712 713
  for (channel =  GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
    curves_channel_reset (c_tool->curves, channel);
714 715

  curves_update (c_tool, GRAPH | XRANGE_TOP | DRAW);
716 717
}

718
static void
719 720 721
curve_print_loc (GimpCurvesTool *c_tool,
		 gint            xpos,
		 gint            ypos)
722
{
723
  gchar buf[32];
724

725
  if (! c_tool->cursor_layout)
726
    {
727 728 729 730
      c_tool->cursor_layout = gtk_widget_create_pango_layout (c_tool->graph,
                                                              "x:888 y:888");
      pango_layout_get_pixel_extents (c_tool->cursor_layout, 
                                      NULL, &c_tool->cursor_rect);
731 732
    }
  
733
  if (xpos >= 0 && xpos <= 255 && ypos >=0 && ypos <= 255)
734
    {
735 736
      gdk_draw_rectangle (c_tool->graph->window, 
			  c_tool->graph->style->bg_gc[GTK_STATE_ACTIVE],
737
			  TRUE, 
738 739 740 741
                          RADIUS * 2 + 2, 
                          RADIUS * 2 + 2, 
			  c_tool->cursor_rect.width  + 4,
			  c_tool->cursor_rect.height + 5);
742

743 744
      gdk_draw_rectangle (c_tool->graph->window, 
			  c_tool->graph->style->black_gc,
745
			  FALSE, 
746 747 748 749
                          RADIUS * 2 + 2, 
                          RADIUS * 2 + 2, 
			  c_tool->cursor_rect.width  + 3, 
			  c_tool->cursor_rect.height + 4);
750 751
      
      g_snprintf (buf, sizeof (buf), "x:%3d y:%3d",xpos, ypos);
752 753 754 755 756 757
      pango_layout_set_text (c_tool->cursor_layout, buf, 11);
      gdk_draw_layout (c_tool->graph->window, 
                       c_tool->graph->style->black_gc,
		       RADIUS * 2 + 4 + c_tool->cursor_rect.x,
		       RADIUS * 2 + 5 + c_tool->cursor_rect.y,
		       c_tool->cursor_layout);
758 759 760
    }
}

761
/* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
Elliot Lee's avatar
Elliot Lee committed
762
static void
763 764
curves_update (GimpCurvesTool *c_tool,
	       gint            update)
Elliot Lee's avatar
Elliot Lee committed
765
{
766 767 768 769 770
  GimpHistogramChannel sel_channel;
  gint                 i, j;
  gchar                buf[32];
  gint                 offset;
  gint                 height;
771
  
772
  if (c_tool->color)
773
    {
774
      sel_channel = c_tool->channel;
775
    }
776 777
  else 
    {
778
      if (c_tool->channel == 2)
779 780 781 782
        sel_channel = GIMP_HISTOGRAM_ALPHA;
      else
        sel_channel = GIMP_HISTOGRAM_VALUE;
    }
783

Elliot Lee's avatar
Elliot Lee committed
784 785
  if (update & XRANGE_TOP)
    {
786
      guchar buf[XRANGE_WIDTH * 3];
787

788
      switch (sel_channel)
789
	{
Michael Natterer's avatar
Michael Natterer committed
790 791
	case GIMP_HISTOGRAM_VALUE:
	case GIMP_HISTOGRAM_ALPHA:
792
	  for (i = 0; i < XRANGE_HEIGHT / 2; i++)
793
	    {
794
	      for (j = 0; j < XRANGE_WIDTH ; j++)
795
		{
796 797 798
		  buf[j * 3 + 0] = c_tool->curves->curve[sel_channel][j];
		  buf[j * 3 + 1] = c_tool->curves->curve[sel_channel][j];
		  buf[j * 3 + 2] = c_tool->curves->curve[sel_channel][j];
799
		}
800
	      gtk_preview_draw_row (GTK_PREVIEW (c_tool->xrange),
801
				    buf, 0, i, XRANGE_WIDTH);
802
	    }
803 804
	  break;

Michael Natterer's avatar
Michael Natterer committed
805 806 807
	case GIMP_HISTOGRAM_RED:
	case GIMP_HISTOGRAM_GREEN:
	case GIMP_HISTOGRAM_BLUE:
808
	  {
809
	    for (i = 0; i < XRANGE_HEIGHT / 2; i++)
810
	      {
811 812
		for (j = 0; j < XRANGE_WIDTH; j++)
		  {
813 814 815
		    buf[j * 3 + 0] = c_tool->curves->curve[GIMP_HISTOGRAM_RED][j];
		    buf[j * 3 + 1] = c_tool->curves->curve[GIMP_HISTOGRAM_GREEN][j];
		    buf[j * 3 + 2] = c_tool->curves->curve[GIMP_HISTOGRAM_BLUE][j];
816
		  }
817
		gtk_preview_draw_row (GTK_PREVIEW (c_tool->xrange),
818
				      buf, 0, i, XRANGE_WIDTH);
819
	      }
820
	    break;
821 822
	  }

823
	default:
824
	  g_warning ("unknown channel type %d, can't happen!?!?",
825
		     c_tool->channel);
826
	  break;
827
	}
Elliot Lee's avatar
Elliot Lee committed
828 829

      if (update & DRAW)
830 831 832
        gtk_widget_queue_draw_area (c_tool->xrange,
                                    0, 0,
                                    XRANGE_WIDTH, XRANGE_HEIGHT / 2);
Elliot Lee's avatar
Elliot Lee committed
833
    }
834

Elliot Lee's avatar
Elliot Lee committed
835 836
  if (update & XRANGE_BOTTOM)
    {
837
      guchar buf[XRANGE_WIDTH * 3];
Elliot Lee's avatar
Elliot Lee committed
838 839

      for (i = 0; i < XRANGE_WIDTH; i++)
840 841 842 843 844
        {
          buf[i * 3 + 0] = i;
          buf[i * 3 + 1] = i;
          buf[i * 3 + 2] = i;
        }
Elliot Lee's avatar
Elliot Lee committed
845 846

      for (i = XRANGE_HEIGHT / 2; i < XRANGE_HEIGHT; i++)
847 848
	gtk_preview_draw_row (GTK_PREVIEW (c_tool->xrange),
                              buf, 0, i, XRANGE_WIDTH);
Elliot Lee's avatar
Elliot Lee committed
849 850

      if (update & DRAW)
851 852 853
        gtk_widget_queue_draw_area (c_tool->xrange,
                                    0, XRANGE_HEIGHT / 2,
                                    XRANGE_WIDTH, XRANGE_HEIGHT / 2);
Elliot Lee's avatar
Elliot Lee committed
854
    }
855

Elliot Lee's avatar
Elliot Lee committed
856 857
  if (update & YRANGE)
    {
858 859
      guchar buf[YRANGE_WIDTH * 3];
      guchar pix[3];
Elliot Lee's avatar
Elliot Lee committed
860 861 862

      for (i = 0; i < YRANGE_HEIGHT; i++)
	{
863
	  switch (sel_channel)
864
	    {
Michael Natterer's avatar
Michael Natterer committed
865 866
	    case GIMP_HISTOGRAM_VALUE:
	    case GIMP_HISTOGRAM_ALPHA:
867 868 869
	      pix[0] = pix[1] = pix[2] = (255 - i);
	      break;

Michael Natterer's avatar
Michael Natterer committed
870 871 872
	    case GIMP_HISTOGRAM_RED:
	    case GIMP_HISTOGRAM_GREEN:
	    case GIMP_HISTOGRAM_BLUE:
873
	      pix[0] = pix[1] = pix[2] = 0;
874
	      pix[sel_channel - 1] = (255 - i);
875 876
	      break;

877
	    default:
878
	      g_warning ("unknown channel type %d, can't happen!?!?",
879
			 c_tool->channel);
880
	      break;
881
	    }
882 883

	  for (j = 0; j < YRANGE_WIDTH * 3; j++)
884
	    buf[j] = pix[j%3];
Elliot Lee's avatar
Elliot Lee committed
885

886
	  gtk_preview_draw_row (GTK_PREVIEW (c_tool->yrange),
887
				buf, 0, i, YRANGE_WIDTH);
Elliot Lee's avatar
Elliot Lee committed
888 889 890
	}

      if (update & DRAW)
891
	gtk_widget_queue_draw (c_tool->yrange);
Elliot Lee's avatar
Elliot Lee committed
892
    }
893 894

  if ((update & GRAPH) && (update & DRAW) && c_tool->pixmap)
Elliot Lee's avatar
Elliot Lee committed
895 896 897 898
    {
      GdkPoint points[256];

      /*  Clear the pixmap  */
899 900
      gdk_draw_rectangle (c_tool->pixmap,
                          c_tool->graph->style->bg_gc[GTK_STATE_NORMAL],
901 902
			  TRUE, 0, 0,
			  GRAPH_WIDTH + RADIUS * 2, GRAPH_HEIGHT + RADIUS * 2);
Elliot Lee's avatar
Elliot Lee committed
903 904 905