gimpcurvestool.c 32.8 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
Elliot Lee's avatar
Elliot Lee committed
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This program is free software: you can redistribute it and/or modify
Elliot Lee's avatar
Elliot Lee committed
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
Elliot Lee's avatar
Elliot Lee committed
7 8 9 10 11 12 13 14
 * (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
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
Sven Neumann's avatar
Sven Neumann committed
17

18 19
#include "config.h"

20 21 22
#include <errno.h>

#include <glib/gstdio.h>
23
#include <gegl.h>
Sven Neumann's avatar
Sven Neumann committed
24 25
#include <gtk/gtk.h>

26
#include "libgimpbase/gimpbase.h"
27
#include "libgimpcolor/gimpcolor.h"
28
#include "libgimpconfig/gimpconfig.h"
29
#include "libgimpwidgets/gimpwidgets.h"
30

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

33 34
#include "operations/gimpcurvesconfig.h"
#include "operations/gimpoperationcurves.h"
35

36
#include "core/gimp.h"
37
#include "core/gimpcurve.h"
Sven Neumann's avatar
Sven Neumann committed
38
#include "core/gimpcurve-map.h"
Michael Natterer's avatar
Michael Natterer committed
39
#include "core/gimpdrawable.h"
40
#include "core/gimpdrawable-histogram.h"
41
#include "core/gimperror.h"
42
#include "core/gimphistogram.h"
Michael Natterer's avatar
Michael Natterer committed
43 44
#include "core/gimpimage.h"

45
#include "widgets/gimpcolorbar.h"
46
#include "widgets/gimphelp-ids.h"
47
#include "widgets/gimpcurveview.h"
48
#include "widgets/gimpwidgets-utils.h"
Michael Natterer's avatar
Michael Natterer committed
49

50 51
#include "display/gimpdisplay.h"

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

55
#include "gimp-intl.h"
56

57

58 59 60
#define GRAPH_SIZE 256
#define BAR_SIZE    12
#define RADIUS       4
Elliot Lee's avatar
Elliot Lee committed
61 62


Michael Natterer's avatar
Michael Natterer committed
63 64
/*  local function prototypes  */

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
static void       gimp_curves_tool_constructed     (GObject              *object);

static gboolean   gimp_curves_tool_initialize      (GimpTool             *tool,
                                                    GimpDisplay          *display,
                                                    GError              **error);
static void       gimp_curves_tool_button_release  (GimpTool             *tool,
                                                    const GimpCoords     *coords,
                                                    guint32               time,
                                                    GdkModifierType       state,
                                                    GimpButtonReleaseType release_type,
                                                    GimpDisplay          *display);
static gboolean   gimp_curves_tool_key_press       (GimpTool             *tool,
                                                    GdkEventKey          *kevent,
                                                    GimpDisplay          *display);
static void       gimp_curves_tool_oper_update     (GimpTool             *tool,
                                                    const GimpCoords     *coords,
                                                    GdkModifierType       state,
                                                    gboolean              proximity,
                                                    GimpDisplay          *display);

static gchar    * gimp_curves_tool_get_operation   (GimpFilterTool       *filter_tool,
                                                    gchar               **title,
                                                    gchar               **description,
                                                    gchar               **undo_desc,
                                                    gchar               **icon_name,
90 91 92 93
                                                    gchar               **help_id,
                                                    gboolean             *has_settings,
                                                    gchar               **import_dialog_title,
                                                    gchar               **export_dialog_title);
94 95 96 97 98 99 100 101
static void       gimp_curves_tool_dialog          (GimpFilterTool       *filter_tool);
static void       gimp_curves_tool_reset           (GimpFilterTool       *filter_tool);
static gboolean   gimp_curves_tool_settings_import (GimpFilterTool       *filter_tool,
                                                    GInputStream         *input,
                                                    GError              **error);
static gboolean   gimp_curves_tool_settings_export (GimpFilterTool       *filter_tool,
                                                    GOutputStream        *output,
                                                    GError              **error);
Ell's avatar
Ell committed
102 103 104 105 106 107
static void       gimp_curves_tool_color_picked    (GimpFilterTool       *filter_tool,
                                                    gpointer              identifier,
                                                    gdouble               x,
                                                    gdouble               y,
                                                    const Babl           *sample_format,
                                                    const GimpRGB        *color);
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

static void       gimp_curves_tool_export_setup    (GimpSettingsBox      *settings_box,
                                                    GtkFileChooserDialog *dialog,
                                                    gboolean              export,
                                                    GimpCurvesTool       *tool);
static void       gimp_curves_tool_update_channel  (GimpCurvesTool       *tool);
static void       gimp_curves_tool_config_notify   (GObject              *object,
                                                    GParamSpec           *pspec,
                                                    GimpCurvesTool       *tool);

static void       curves_channel_callback          (GtkWidget            *widget,
                                                    GimpCurvesTool       *tool);
static void       curves_channel_reset_callback    (GtkWidget            *widget,
                                                    GimpCurvesTool       *tool);

static gboolean   curves_menu_sensitivity          (gint                  value,
                                                    gpointer              data);

static void       curves_curve_type_callback       (GtkWidget            *widget,
                                                    GimpCurvesTool       *tool);

129 130 131
static gboolean   curves_get_channel_color         (GtkWidget            *widget,
                                                    GimpHistogramChannel  channel,
                                                    GimpRGB              *color);
132 133 134


G_DEFINE_TYPE (GimpCurvesTool, gimp_curves_tool, GIMP_TYPE_FILTER_TOOL)
135 136

#define parent_class gimp_curves_tool_parent_class
137

Michael Natterer's avatar
Michael Natterer committed
138

139
/*  public functions  */
Michael Natterer's avatar
Michael Natterer committed
140 141

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

158 159 160

/*  private functions  */

Michael Natterer's avatar
Michael Natterer committed
161 162 163
static void
gimp_curves_tool_class_init (GimpCurvesToolClass *klass)
{
164 165 166
  GObjectClass        *object_class      = G_OBJECT_CLASS (klass);
  GimpToolClass       *tool_class        = GIMP_TOOL_CLASS (klass);
  GimpFilterToolClass *filter_tool_class = GIMP_FILTER_TOOL_CLASS (klass);
167

168
  object_class->constructed          = gimp_curves_tool_constructed;
169

170 171 172 173
  tool_class->initialize             = gimp_curves_tool_initialize;
  tool_class->button_release         = gimp_curves_tool_button_release;
  tool_class->key_press              = gimp_curves_tool_key_press;
  tool_class->oper_update            = gimp_curves_tool_oper_update;
174

175 176 177 178 179
  filter_tool_class->get_operation   = gimp_curves_tool_get_operation;
  filter_tool_class->dialog          = gimp_curves_tool_dialog;
  filter_tool_class->reset           = gimp_curves_tool_reset;
  filter_tool_class->settings_import = gimp_curves_tool_settings_import;
  filter_tool_class->settings_export = gimp_curves_tool_settings_export;
Ell's avatar
Ell committed
180
  filter_tool_class->color_picked    = gimp_curves_tool_color_picked;
Michael Natterer's avatar
Michael Natterer committed
181 182 183
}

static void
184
gimp_curves_tool_init (GimpCurvesTool *tool)
Michael Natterer's avatar
Michael Natterer committed
185
{
186
  gint i;
187

188 189
  for (i = 0; i < G_N_ELEMENTS (tool->picked_color); i++)
    tool->picked_color[i] = -1.0;
Michael Natterer's avatar
Michael Natterer committed
190 191
}

192 193 194 195 196
static void
gimp_curves_tool_constructed (GObject *object)
{
  G_OBJECT_CLASS (parent_class)->constructed (object);

197
  g_signal_connect_object (GIMP_FILTER_TOOL (object)->config, "notify",
198 199
                           G_CALLBACK (gimp_curves_tool_config_notify),
                           object, 0);
200 201
}

202
static gboolean
203 204 205
gimp_curves_tool_initialize (GimpTool     *tool,
                             GimpDisplay  *display,
                             GError      **error)
Michael Natterer's avatar
Michael Natterer committed
206
{
Ell's avatar
Ell committed
207 208 209 210
  GimpCurvesTool *c_tool      = GIMP_CURVES_TOOL (tool);
  GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (tool);
  GimpImage      *image       = gimp_display_get_image (display);
  GimpDrawable   *drawable    = gimp_image_get_active_drawable (image);
211
  GimpHistogram  *histogram;
212

213 214 215 216
  if (! GIMP_TOOL_CLASS (parent_class)->initialize (tool, display, error))
    {
      return FALSE;
    }
217

218
  histogram = gimp_histogram_new (FALSE);
219
  gimp_drawable_calculate_histogram (drawable, histogram);
220
  gimp_histogram_view_set_background (GIMP_HISTOGRAM_VIEW (c_tool->graph),
221
                                      histogram);
222
  g_object_unref (histogram);
223

224
  if (gimp_drawable_get_component_type (drawable) == GIMP_COMPONENT_TYPE_U8)
225 226 227 228 229 230
    {
      gimp_curve_view_set_range_x (GIMP_CURVE_VIEW (c_tool->graph), 0, 255);
      gimp_curve_view_set_range_y (GIMP_CURVE_VIEW (c_tool->graph), 0, 255);
    }
  else
    {
231 232
      gimp_curve_view_set_range_x (GIMP_CURVE_VIEW (c_tool->graph), 0, 100);
      gimp_curve_view_set_range_y (GIMP_CURVE_VIEW (c_tool->graph), 0, 100);
233 234
    }

Ell's avatar
Ell committed
235 236 237
  /*  always pick colors  */
  gimp_filter_tool_enable_color_picking (filter_tool, NULL, FALSE);

238
  return TRUE;
Michael Natterer's avatar
Michael Natterer committed
239 240 241
}

static void
242
gimp_curves_tool_button_release (GimpTool              *tool,
243
                                 const GimpCoords      *coords,
244 245 246 247
                                 guint32                time,
                                 GdkModifierType        state,
                                 GimpButtonReleaseType  release_type,
                                 GimpDisplay           *display)
Michael Natterer's avatar
Michael Natterer committed
248
{
249 250 251
  GimpCurvesTool   *c_tool      = GIMP_CURVES_TOOL (tool);
  GimpFilterTool   *filter_tool = GIMP_FILTER_TOOL (tool);
  GimpCurvesConfig *config      = GIMP_CURVES_CONFIG (filter_tool->config);
Michael Natterer's avatar
Michael Natterer committed
252

253
  if (state & gimp_get_extend_selection_mask ())
Michael Natterer's avatar
Michael Natterer committed
254
    {
255
      GimpCurve *curve = config->curve[config->channel];
256
      gdouble    value = c_tool->picked_color[config->channel];
257
      gint       closest;
258

259
      closest = gimp_curve_get_closest_point (curve, value);
260

261
      gimp_curve_view_set_selected (GIMP_CURVE_VIEW (c_tool->graph),
262
                                    closest);
263

264
      gimp_curve_set_point (curve, closest,
265
                            value, gimp_curve_map_value (curve, value));
Michael Natterer's avatar
Michael Natterer committed
266
    }
267
  else if (state & gimp_get_toggle_behavior_mask ())
Michael Natterer's avatar
Michael Natterer committed
268
    {
269
      GimpHistogramChannel channel;
270

271 272 273
      for (channel = GIMP_HISTOGRAM_VALUE;
           channel <= GIMP_HISTOGRAM_ALPHA;
           channel++)
274
        {
275 276
          GimpCurve *curve = config->curve[channel];
          gdouble    value = c_tool->picked_color[channel];
277
          gint       closest;
278

279 280 281
          if (value != -1)
            {
              closest = gimp_curve_get_closest_point (curve, value);
282

283 284
              gimp_curve_view_set_selected (GIMP_CURVE_VIEW (c_tool->graph),
                                            closest);
285

286 287 288
              gimp_curve_set_point (curve, closest,
                                    value, gimp_curve_map_value (curve, value));
            }
289
        }
Michael Natterer's avatar
Michael Natterer committed
290 291
    }

292
  /*  chain up to halt the tool */
293 294
  GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state,
                                                  release_type, display);
Michael Natterer's avatar
Michael Natterer committed
295 296
}

297
static gboolean
298 299
gimp_curves_tool_key_press (GimpTool    *tool,
                            GdkEventKey *kevent,
300
                            GimpDisplay *display)
301
{
302 303
  GimpCurvesTool *c_tool = GIMP_CURVES_TOOL (tool);

304 305 306 307 308
  if (tool->display && c_tool->graph)
    {
      if (gtk_widget_event (c_tool->graph, (GdkEvent *) kevent))
        return TRUE;
    }
309 310

  return GIMP_TOOL_CLASS (parent_class)->key_press (tool, kevent, display);
311 312 313
}

static void
314 315 316 317 318
gimp_curves_tool_oper_update (GimpTool         *tool,
                              const GimpCoords *coords,
                              GdkModifierType   state,
                              gboolean          proximity,
                              GimpDisplay      *display)
319
{
320 321
  if (gimp_filter_tool_on_guide (GIMP_FILTER_TOOL (tool),
                                 coords, display))
322
    {
323 324
      GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
                                                   display);
325
    }
326 327
  else
    {
328 329 330 331
      GimpColorPickMode  mode;
      gchar             *status      = NULL;
      GdkModifierType    extend_mask = gimp_get_extend_selection_mask ();
      GdkModifierType    toggle_mask = gimp_get_toggle_behavior_mask ();
332

333
      gimp_tool_pop_status (tool, display);
334

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
      if (state & extend_mask)
        {
          mode   = GIMP_COLOR_PICK_MODE_PALETTE;
          status = g_strdup (_("Click to add a control point"));
        }
      else if (state & toggle_mask)
        {
          mode   = GIMP_COLOR_PICK_MODE_PALETTE;
          status = g_strdup (_("Click to add control points to all channels"));
        }
      else
        {
          mode   = GIMP_COLOR_PICK_MODE_NONE;
          status = gimp_suggest_modifiers (_("Click to locate on curve"),
                                           (extend_mask | toggle_mask) & ~state,
                                           _("%s: add control point"),
                                           _("%s: add control points to all channels"),
                                           NULL);
        }
354

355 356 357 358 359 360 361
      GIMP_COLOR_TOOL (tool)->pick_mode = mode;

      if (proximity)
        gimp_tool_push_status (tool, display, "%s", status);

      g_free (status);
    }
362 363
}

364
static gchar *
365 366 367 368 369
gimp_curves_tool_get_operation (GimpFilterTool  *filter_tool,
                                gchar          **title,
                                gchar          **description,
                                gchar          **undo_desc,
                                gchar          **icon_name,
370 371 372 373
                                gchar          **help_id,
                                gboolean        *has_settings,
                                gchar          **import_dialog_title,
                                gchar          **export_dialog_title)
374
{
375 376 377 378
  *description         = g_strdup (_("Adjust Color Curves"));
  *has_settings        = TRUE;
  *import_dialog_title = g_strdup (_("Import Curves"));
  *export_dialog_title = g_strdup (_("Export Curves"));
379

380
  return g_strdup ("gimp:curves");
381
}
BST 1999 Andy Thomas's avatar
BST 1999 Andy Thomas committed
382

383

384 385 386
/*******************/
/*  Curves dialog  */
/*******************/
Elliot Lee's avatar
Elliot Lee committed
387

388
static void
389
gimp_curves_tool_dialog (GimpFilterTool *filter_tool)
Elliot Lee's avatar
Elliot Lee committed
390
{
391 392 393
  GimpCurvesTool   *tool         = GIMP_CURVES_TOOL (filter_tool);
  GimpToolOptions  *tool_options = GIMP_TOOL_GET_OPTIONS (filter_tool);
  GimpCurvesConfig *config       = GIMP_CURVES_CONFIG (filter_tool->config);
394
  GtkListStore     *store;
395
  GtkWidget        *main_vbox;
396
  GtkWidget        *frame_vbox;
397 398 399 400
  GtkWidget        *vbox;
  GtkWidget        *hbox;
  GtkWidget        *hbox2;
  GtkWidget        *label;
401
  GtkWidget        *main_frame;
402 403 404 405
  GtkWidget        *frame;
  GtkWidget        *table;
  GtkWidget        *button;
  GtkWidget        *bar;
406
  GtkWidget        *combo;
407

408
  g_signal_connect (filter_tool->settings_box, "file-dialog-setup",
409
                    G_CALLBACK (gimp_curves_tool_export_setup),
410
                    filter_tool);
411

412
  main_vbox = gimp_filter_tool_dialog_get_vbox (filter_tool);
Elliot Lee's avatar
Elliot Lee committed
413

414
  /*  The combo box for selecting channels  */
415 416 417 418
  main_frame = gimp_frame_new (NULL);
  gtk_box_pack_start (GTK_BOX (main_vbox), main_frame, TRUE, TRUE, 0);
  gtk_widget_show (main_frame);

Michael Natterer's avatar
Michael Natterer committed
419
  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
420
  gtk_frame_set_label_widget (GTK_FRAME (main_frame), hbox);
421 422
  gtk_widget_show (hbox);

423
  label = gtk_label_new_with_mnemonic (_("Cha_nnel:"));
424 425 426
  gimp_label_set_attributes (GTK_LABEL (label),
                             PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
                             -1);
427 428 429
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

430 431 432
  store = gimp_enum_store_new_with_range (GIMP_TYPE_HISTOGRAM_CHANNEL,
                                          GIMP_HISTOGRAM_VALUE,
                                          GIMP_HISTOGRAM_ALPHA);
433 434
  tool->channel_menu =
    gimp_enum_combo_box_new_with_model (GIMP_ENUM_STORE (store));
435 436
  g_object_unref (store);

437 438
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (tool->channel_menu),
                                 config->channel);
439 440
  gimp_enum_combo_box_set_icon_prefix (GIMP_ENUM_COMBO_BOX (tool->channel_menu),
                                       "gimp-channel");
441 442
  gimp_int_combo_box_set_sensitivity (GIMP_INT_COMBO_BOX (tool->channel_menu),
                                      curves_menu_sensitivity, filter_tool, NULL);
443 444
  gtk_box_pack_start (GTK_BOX (hbox), tool->channel_menu, FALSE, FALSE, 0);
  gtk_widget_show (tool->channel_menu);
445

446 447 448
  g_signal_connect (tool->channel_menu, "changed",
                    G_CALLBACK (curves_channel_callback),
                    tool);
449

450
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), tool->channel_menu);
451

452
  button = gtk_button_new_with_mnemonic (_("R_eset Channel"));
453
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
454
  gtk_widget_show (button);
455

456
  g_signal_connect (button, "clicked",
457
                    G_CALLBACK (curves_channel_reset_callback),
458
                    tool);
Elliot Lee's avatar
Elliot Lee committed
459

460
  /*  The histogram scale radio buttons  */
461 462 463
  hbox2 = gimp_prop_enum_icon_box_new (G_OBJECT (tool_options),
                                       "histogram-scale", "gimp-histogram",
                                       0, 0);
464 465
  gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
  gtk_widget_show (hbox2);
466

467 468 469 470
  frame_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
  gtk_container_add (GTK_CONTAINER (main_frame), frame_vbox);
  gtk_widget_show (frame_vbox);

471
  /*  The table for the color bars and the graph  */
Elliot Lee's avatar
Elliot Lee committed
472
  table = gtk_table_new (2, 2, FALSE);
473 474
  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
475
  gtk_box_pack_start (GTK_BOX (frame_vbox), table, TRUE, TRUE, 0);
476 477

  /*  The left color bar  */
Michael Natterer's avatar
Michael Natterer committed
478
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
479
  gtk_table_attach (GTK_TABLE (table), vbox, 0, 1, 0, 1,
480
                    GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
481
  gtk_widget_show (vbox);
Elliot Lee's avatar
Elliot Lee committed
482 483

  frame = gtk_frame_new (NULL);
484
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
485
  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
486 487
  gtk_widget_show (frame);

488 489 490 491
  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);
492

Elliot Lee's avatar
Elliot Lee committed
493 494
  /*  The curves graph  */
  frame = gtk_frame_new (NULL);
495
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Elliot Lee's avatar
Elliot Lee committed
496
  gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
497
                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
498
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
499

500
  tool->graph = gimp_curve_view_new ();
501 502
  gimp_curve_view_set_range_x (GIMP_CURVE_VIEW (tool->graph), 0, 255);
  gimp_curve_view_set_range_y (GIMP_CURVE_VIEW (tool->graph), 0, 255);
503 504 505 506
  gtk_widget_set_size_request (tool->graph,
                               GRAPH_SIZE + RADIUS * 2,
                               GRAPH_SIZE + RADIUS * 2);
  g_object_set (tool->graph,
507 508 509
                "border-width", RADIUS,
                "subdivisions", 1,
                NULL);
510 511
  gtk_container_add (GTK_CONTAINER (frame), tool->graph);
  gtk_widget_show (tool->graph);
512

513 514 515 516
  g_object_bind_property (G_OBJECT (tool_options), "histogram-scale",
                          G_OBJECT (tool->graph),  "histogram-scale",
                          G_BINDING_SYNC_CREATE |
                          G_BINDING_BIDIRECTIONAL);
517 518

  /*  The bottom color bar  */
Michael Natterer's avatar
Michael Natterer committed
519
  hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
520
  gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2,
521
                    GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
522
  gtk_widget_show (hbox2);
523

Elliot Lee's avatar
Elliot Lee committed
524
  frame = gtk_frame_new (NULL);
525
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
526
  gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, RADIUS);
Elliot Lee's avatar
Elliot Lee committed
527 528
  gtk_widget_show (frame);

Michael Natterer's avatar
Michael Natterer committed
529 530
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
  gtk_box_set_homogeneous (GTK_BOX (vbox), TRUE);
531 532
  gtk_container_add (GTK_CONTAINER (frame), vbox);
  gtk_widget_show (vbox);
533

534 535
  tool->xrange = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_widget_set_size_request (tool->xrange, -1, BAR_SIZE / 2);
536
  gtk_box_pack_start (GTK_BOX (vbox), tool->xrange, TRUE, TRUE, 0);
537
  gtk_widget_show (tool->xrange);
538

539
  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
540
  gtk_box_pack_start (GTK_BOX (vbox), bar, TRUE, TRUE, 0);
541 542
  gtk_widget_show (bar);

543
  gtk_widget_show (table);
Elliot Lee's avatar
Elliot Lee committed
544

Michael Natterer's avatar
Michael Natterer committed
545
  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
546
  gtk_box_pack_end (GTK_BOX (frame_vbox), hbox, FALSE, FALSE, 0);
547
  gtk_widget_show (hbox);
548

549 550 551
  label = gtk_label_new_with_mnemonic (_("Curve _type:"));
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);
552

553
  tool->curve_type = combo = gimp_enum_combo_box_new (GIMP_TYPE_CURVE_TYPE);
554 555
  gimp_enum_combo_box_set_icon_prefix (GIMP_ENUM_COMBO_BOX (combo),
                                       "gimp-curve");
556 557 558 559 560
  gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), 0,
                              G_CALLBACK (curves_curve_type_callback),
                              tool);
  gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
  gtk_widget_show (combo);
Sven Neumann's avatar
Sven Neumann committed
561 562

  gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
563 564

  gimp_curves_tool_update_channel (tool);
Elliot Lee's avatar
Elliot Lee committed
565 566
}

567
static void
568
gimp_curves_tool_reset (GimpFilterTool *filter_tool)
569
{
570
  GimpCurvesConfig     *config = GIMP_CURVES_CONFIG (filter_tool->config);
571
  GimpCurvesConfig     *default_config;
572
  GimpHistogramChannel  channel;
573

574
  default_config = GIMP_CURVES_CONFIG (filter_tool->default_config);
575

576 577 578 579
  for (channel = GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
    {
580 581
      if (default_config)
        {
582
          GimpCurveType curve_type = config->curve[channel]->curve_type;
583

584
          g_object_freeze_notify (G_OBJECT (config->curve[channel]));
585 586

          gimp_config_copy (GIMP_CONFIG (default_config->curve[channel]),
587
                            GIMP_CONFIG (config->curve[channel]),
588 589
                            0);

590
          g_object_set (config->curve[channel],
591 592 593
                        "curve-type", curve_type,
                        NULL);

594
          g_object_thaw_notify (G_OBJECT (config->curve[channel]));
595 596 597
        }
      else
        {
598
          gimp_curve_reset (config->curve[channel], FALSE);
599
        }
600
    }
601 602
}

603
static gboolean
604 605 606
gimp_curves_tool_settings_import (GimpFilterTool  *filter_tool,
                                  GInputStream    *input,
                                  GError         **error)
607
{
608
  GimpCurvesConfig *config = GIMP_CURVES_CONFIG (filter_tool->config);
609 610
  gchar             header[64];
  gsize             bytes_read;
611

612 613 614
  if (! g_input_stream_read_all (input, header, sizeof (header),
                                 &bytes_read, NULL, error) ||
      bytes_read != sizeof (header))
615
    {
616
      g_prefix_error (error, _("Could not read header: "));
617 618 619
      return FALSE;
    }

620
  g_seekable_seek (G_SEEKABLE (input), 0, G_SEEK_SET, NULL, NULL);
621

622
  if (g_str_has_prefix (header, "# GIMP Curves File\n"))
623
    return gimp_curves_config_load_cruft (config, input, error);
624

625 626 627
  return GIMP_FILTER_TOOL_CLASS (parent_class)->settings_import (filter_tool,
                                                                 input,
                                                                 error);
628 629 630
}

static gboolean
631 632 633
gimp_curves_tool_settings_export (GimpFilterTool  *filter_tool,
                                  GOutputStream   *output,
                                  GError         **error)
634
{
635 636
  GimpCurvesTool   *tool   = GIMP_CURVES_TOOL (filter_tool);
  GimpCurvesConfig *config = GIMP_CURVES_CONFIG (filter_tool->config);
637

638
  if (tool->export_old_format)
639
    return gimp_curves_config_save_cruft (config, output, error);
640

641 642 643
  return GIMP_FILTER_TOOL_CLASS (parent_class)->settings_export (filter_tool,
                                                                 output,
                                                                 error);
644 645
}

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
static void
gimp_curves_tool_color_picked (GimpFilterTool *filter_tool,
                               gpointer        identifier,
                               gdouble         x,
                               gdouble         y,
                               const Babl     *sample_format,
                               const GimpRGB  *color)
{
  GimpCurvesTool   *tool   = GIMP_CURVES_TOOL (filter_tool);
  GimpCurvesConfig *config = GIMP_CURVES_CONFIG (filter_tool->config);
  GimpDrawable     *drawable;

  drawable = GIMP_FILTER_TOOL (tool)->drawable;

  tool->picked_color[GIMP_HISTOGRAM_RED]   = color->r;
  tool->picked_color[GIMP_HISTOGRAM_GREEN] = color->g;
  tool->picked_color[GIMP_HISTOGRAM_BLUE]  = color->b;

  if (gimp_drawable_has_alpha (drawable))
    tool->picked_color[GIMP_HISTOGRAM_ALPHA] = color->a;
  else
    tool->picked_color[GIMP_HISTOGRAM_ALPHA] = -1;

  tool->picked_color[GIMP_HISTOGRAM_VALUE] = MAX (MAX (color->r, color->g),
                                                  color->b);

  gimp_curve_view_set_xpos (GIMP_CURVE_VIEW (tool->graph),
                            tool->picked_color[config->channel]);
}

676 677 678 679 680 681 682
static void
gimp_curves_tool_export_setup (GimpSettingsBox      *settings_box,
                               GtkFileChooserDialog *dialog,
                               gboolean              export,
                               GimpCurvesTool       *tool)
{
  GtkWidget *button;
683

684 685 686 687 688 689 690 691
  if (! export)
    return;

  button = gtk_check_button_new_with_mnemonic (_("Use _old curves file format"));
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
                                tool->export_old_format);
  gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), button);
  gtk_widget_show (button);
692

693 694 695
  g_signal_connect (button, "toggled",
                    G_CALLBACK (gimp_toggle_button_update),
                    &tool->export_old_format);
696
}
697

Elliot Lee's avatar
Elliot Lee committed
698
static void
699
gimp_curves_tool_update_channel (GimpCurvesTool *tool)
Elliot Lee's avatar
Elliot Lee committed
700
{
701 702 703
  GimpFilterTool       *filter_tool = GIMP_FILTER_TOOL (tool);
  GimpCurvesConfig     *config      = GIMP_CURVES_CONFIG (filter_tool->config);
  GimpCurve            *curve       = config->curve[config->channel];
704
  GimpHistogramChannel  channel;
705

706 707
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (tool->channel_menu),
                                 config->channel);
708

709
  switch (config->channel)
710
    {
711 712 713 714 715 716 717
      guchar r[256];
      guchar g[256];
      guchar b[256];

    case GIMP_HISTOGRAM_VALUE:
    case GIMP_HISTOGRAM_ALPHA:
    case GIMP_HISTOGRAM_RGB:
718
    case GIMP_HISTOGRAM_LUMINANCE:
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
      gimp_curve_get_uchar (curve, sizeof (r), r);

      gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->xrange),
                                  r, r, r);
      break;

    case GIMP_HISTOGRAM_RED:
    case GIMP_HISTOGRAM_GREEN:
    case GIMP_HISTOGRAM_BLUE:
      gimp_curve_get_uchar (config->curve[GIMP_HISTOGRAM_RED],
                            sizeof (r), r);
      gimp_curve_get_uchar (config->curve[GIMP_HISTOGRAM_GREEN],
                            sizeof (g), g);
      gimp_curve_get_uchar (config->curve[GIMP_HISTOGRAM_BLUE],
                            sizeof (b), b);

      gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->xrange),
                                  r, g, b);
      break;
    }

  gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (tool->graph),
                                   config->channel);
  gimp_curve_view_set_xpos (GIMP_CURVE_VIEW (tool->graph),
                            tool->picked_color[config->channel]);

  gimp_color_bar_set_channel (GIMP_COLOR_BAR (tool->yrange),
                              config->channel);
747

748
  gimp_curve_view_remove_all_backgrounds (GIMP_CURVE_VIEW (tool->graph));
749

750 751 752 753
  for (channel = GIMP_HISTOGRAM_VALUE;
       channel <= GIMP_HISTOGRAM_ALPHA;
       channel++)
    {
754 755 756 757 758
      GimpRGB  curve_color;
      gboolean has_color;

      has_color = curves_get_channel_color (tool->graph, channel, &curve_color);

759
      if (channel == config->channel)
760
        {
761
          gimp_curve_view_set_curve (GIMP_CURVE_VIEW (tool->graph), curve,
762
                                     has_color ? &curve_color : NULL);
763
        }
764 765 766 767
      else
        {
          gimp_curve_view_add_background (GIMP_CURVE_VIEW (tool->graph),
                                          config->curve[channel],
768
                                          has_color ? &curve_color : NULL);
769 770
        }
    }
771

772 773 774
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (tool->curve_type),
                                 curve->curve_type);
}
Elliot Lee's avatar
Elliot Lee committed
775

776 777 778 779 780 781 782
static void
gimp_curves_tool_config_notify (GObject        *object,
                                GParamSpec     *pspec,
                                GimpCurvesTool *tool)
{
  GimpCurvesConfig *config = GIMP_CURVES_CONFIG (object);
  GimpCurve        *curve  = config->curve[config->channel];
783

784 785
  if (! tool->xrange)
    return;
786

787 788 789
  if (! strcmp (pspec->name, "channel"))
    {
      gimp_curves_tool_update_channel (GIMP_CURVES_TOOL (tool));
790 791 792
    }
  else if (! strcmp (pspec->name, "curve"))
    {
793 794
      gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (tool->curve_type),
                                     curve->curve_type);
795 796
    }
}
797

798 799 800 801
static void
curves_channel_callback (GtkWidget      *widget,
                         GimpCurvesTool *tool)
{
802 803
  GimpFilterTool   *filter_tool = GIMP_FILTER_TOOL (tool);
  GimpCurvesConfig *config      = GIMP_CURVES_CONFIG (filter_tool->config);
804 805 806 807 808 809 810 811
  gint              value;

  if (gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value) &&
      config->channel != value)
    {
      g_object_set (config,
                    "channel", value,
                    NULL);
812
    }
Elliot Lee's avatar
Elliot Lee committed
813 814 815
}

static void
816
curves_channel_reset_callback (GtkWidget      *widget,
817
                               GimpCurvesTool *tool)
Elliot Lee's avatar
Elliot Lee committed
818
{
819 820
  GimpFilterTool   *filter_tool = GIMP_FILTER_TOOL (tool);
  GimpCurvesConfig *config      = GIMP_CURVES_CONFIG (filter_tool->config);
821 822

  gimp_curve_reset (config->curve[config->channel], FALSE);
Elliot Lee's avatar
Elliot Lee committed
823 824
}

825
static gboolean
826 827
curves_menu_sensitivity (gint      value,
                         gpointer  data)
828
{
829
  GimpDrawable         *drawable = GIMP_FILTER_TOOL (data)->drawable;
830
  GimpHistogramChannel  channel  = value;
Sven Neumann's avatar
Sven Neumann committed
831

832 833 834
  if (!drawable)
    return FALSE;

835 836 837 838
  switch (channel)
    {
    case GIMP_HISTOGRAM_VALUE:
      return TRUE;
839

840 841 842
    case GIMP_HISTOGRAM_RED:
    case GIMP_HISTOGRAM_GREEN:
    case GIMP_HISTOGRAM_BLUE:
843
      return gimp_drawable_is_rgb (drawable);
844

845
    case GIMP_HISTOGRAM_ALPHA:
846
      return gimp_drawable_has_alpha (drawable);
847 848 849

    case GIMP_HISTOGRAM_RGB:
      return FALSE;
850 851 852

    case GIMP_HISTOGRAM_LUMINANCE:
      return FALSE;
853
    }
854

855 856 857
  return FALSE;
}

Elliot Lee's avatar
Elliot Lee committed
858
static void
859
curves_curve_type_callback (GtkWidget      *widget,
860
                            GimpCurvesTool *tool)
Elliot Lee's avatar
Elliot Lee committed
861
{
862
  gint value;
Elliot Lee's avatar
Elliot Lee committed
863

Sven Neumann's avatar