colorcorrection.c 21 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
    This file is part of darktable,
    copyright (c) 2009--2010 johannes hanika.

    darktable 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 3 of the License, or
    (at your option) any later version.

    darktable 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 darktable.  If not, see <http://www.gnu.org/licenses/>.
*/
18
#ifdef HAVE_CONFIG_H
19
#include "config.h"
20
#endif
21
#include "bauhaus/bauhaus.h"
johannes hanika's avatar
johannes hanika committed
22
#include "common/colorspaces.h"
23
#include "common/opencl.h"
24
#include "control/control.h"
25 26
#include "develop/develop.h"
#include "develop/imageop.h"
27
#include "dtgtk/drawingarea.h"
28
#include "gui/accelerators.h"
29
#include "gui/gtk.h"
30
#include "gui/presets.h"
31
#include "iop/iop_api.h"
32

33
#include <assert.h>
34 35
#include <math.h>
#include <stdlib.h>
36 37
#include <string.h>

38
DT_MODULE_INTROSPECTION(1, dt_iop_colorcorrection_params_t)
39

40
#define DT_COLORCORRECTION_INSET DT_PIXEL_APPLY_DPI(5)
johannes hanika's avatar
johannes hanika committed
41
#define DT_COLORCORRECTION_MAX 40.
42

43 44 45
typedef struct dt_iop_colorcorrection_params_t
{
  float hia, hib, loa, lob, saturation;
46
} dt_iop_colorcorrection_params_t;
47 48 49 50 51

typedef struct dt_iop_colorcorrection_gui_data_t
{
  GtkDrawingArea *area;
  GtkWidget *slider;
52
  int selected;
53
  cmsHTRANSFORM xform;
54
} dt_iop_colorcorrection_gui_data_t;
55 56 57 58

typedef struct dt_iop_colorcorrection_data_t
{
  float a_scale, a_base, b_scale, b_base, saturation;
59
} dt_iop_colorcorrection_data_t;
60

61 62 63
typedef struct dt_iop_colorcorrection_global_data_t
{
  int kernel_colorcorrection;
64
} dt_iop_colorcorrection_global_data_t;
65

johannes hanika's avatar
johannes hanika committed
66 67 68 69 70
const char *name()
{
  return _("color correction");
}

71 72
int flags()
{
73
  return IOP_FLAGS_INCLUDE_IN_STYLES | IOP_FLAGS_SUPPORTS_BLENDING | IOP_FLAGS_ALLOW_TILING;
74 75
}

76
int groups()
77
{
Henrik Andersson's avatar
Henrik Andersson committed
78
  return IOP_GROUP_COLOR;
79 80
}

81
void init_presets(dt_iop_module_so_t *self)
82 83 84
{
  dt_iop_colorcorrection_params_t p;

85 86 87 88 89 90 91
  p.loa = 0.0f;
  p.lob = 0.0f;
  p.hia = 0.0f;
  p.hib = 3.0f;
  p.saturation = 1.0f;
  dt_gui_presets_add_generic(_("warm tone"), self->op, self->version(), &p, sizeof(p), 1);

92 93
  p.loa = 3.55f;
  p.lob = 0.0f;
94 95
  p.hia = -0.95f;
  p.hib = 4.5f;
96 97
  p.saturation = 1.0f;
  dt_gui_presets_add_generic(_("warming filter"), self->op, self->version(), &p, sizeof(p), 1);
98 99 100

  p.loa = -3.55f;
  p.lob = -0.0f;
101 102
  p.hia = 0.95f;
  p.hib = -4.5f;
103 104
  p.saturation = 1.0f;
  dt_gui_presets_add_generic(_("cooling filter"), self->op, self->version(), &p, sizeof(p), 1);
105 106
}

107 108 109 110 111 112 113
void init_key_accels(dt_iop_module_so_t *self)
{
  dt_accel_register_slider_iop(self, FALSE, NC_("accel", "saturation"));
}

void connect_key_accels(dt_iop_module_t *self)
{
114
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
115 116 117
  dt_accel_connect_slider_iop(self, "saturation", GTK_WIDGET(g->slider));
}

118 119
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o,
             const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
120 121
{
  dt_iop_colorcorrection_data_t *d = (dt_iop_colorcorrection_data_t *)piece->data;
122
  float *in = (float *)i;
123
  float *out = (float *)o;
124
  const int ch = piece->colors;
125
  for(size_t k = 0; k < (size_t)roi_out->width * roi_out->height; k++)
126 127
  {
    out[0] = in[0];
128 129
    out[1] = d->saturation * (in[1] + in[0] * d->a_scale + d->a_base);
    out[2] = d->saturation * (in[2] + in[0] * d->b_scale + d->b_base);
130
    out[3] = in[3];
131 132
    out += ch;
    in += ch;
133 134 135
  }
}

136
#ifdef HAVE_OPENCL
137
int process_cl(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out,
138
               const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
139 140 141 142 143 144 145 146 147 148
{
  dt_iop_colorcorrection_data_t *d = (dt_iop_colorcorrection_data_t *)piece->data;
  dt_iop_colorcorrection_global_data_t *gd = (dt_iop_colorcorrection_global_data_t *)self->data;

  cl_int err = -999;
  const int devid = piece->pipe->devid;

  const int width = roi_out->width;
  const int height = roi_out->height;

149
  size_t sizes[2] = { ROUNDUPWD(width), ROUNDUPHT(height) };
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 0, sizeof(cl_mem), &dev_in);
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 1, sizeof(cl_mem), &dev_out);
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 2, sizeof(int), &width);
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 3, sizeof(int), &height);
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 4, sizeof(float), &d->saturation);
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 5, sizeof(float), &d->a_scale);
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 6, sizeof(float), &d->a_base);
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 7, sizeof(float), &d->b_scale);
  dt_opencl_set_kernel_arg(devid, gd->kernel_colorcorrection, 8, sizeof(float), &d->b_base);
  err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_colorcorrection, sizes);
  if(err != CL_SUCCESS) goto error;

  return TRUE;

error:
  dt_print(DT_DEBUG_OPENCL, "[opencl_colorcorrection] couldn't enqueue kernel! %d\n", err);
  return FALSE;
}
#endif


void init_global(dt_iop_module_so_t *module)
{
  const int program = 2; // basic.cl from programs.conf
174 175
  dt_iop_colorcorrection_global_data_t *gd
      = (dt_iop_colorcorrection_global_data_t *)malloc(sizeof(dt_iop_colorcorrection_global_data_t));
176 177 178 179 180 181 182 183 184 185 186 187 188 189
  module->data = gd;
  gd->kernel_colorcorrection = dt_opencl_create_kernel(program, "colorcorrection");
}


void cleanup_global(dt_iop_module_so_t *module)
{
  dt_iop_colorcorrection_global_data_t *gd = (dt_iop_colorcorrection_global_data_t *)module->data;
  dt_opencl_free_kernel(gd->kernel_colorcorrection);
  free(module->data);
  module->data = NULL;
}


190 191
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe,
                   dt_dev_pixelpipe_iop_t *piece)
192 193 194
{
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)p1;
  dt_iop_colorcorrection_data_t *d = (dt_iop_colorcorrection_data_t *)piece->data;
195 196 197 198
  d->a_scale = (p->hia - p->loa) / 100.0;
  d->a_base = p->loa;
  d->b_scale = (p->hib - p->lob) / 100.0;
  d->b_base = p->lob;
199 200 201
  d->saturation = p->saturation;
}

202
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
203 204 205 206 207
{
  piece->data = malloc(sizeof(dt_iop_colorcorrection_data_t));
  self->commit_params(self, self->default_params, pipe, piece);
}

208
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
209 210
{
  free(piece->data);
211
  piece->data = NULL;
212 213 214 215 216 217 218
}

void gui_update(struct dt_iop_module_t *self)
{
  dt_iop_module_t *module = (dt_iop_module_t *)self;
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)module->params;
219
  dt_bauhaus_slider_set(g->slider, p->saturation);
jhanika's avatar
jhanika committed
220
  gtk_widget_queue_draw(self->widget);
221 222 223 224 225
}

void init(dt_iop_module_t *module)
{
  // module->data = malloc(sizeof(dt_iop_colorcorrection_data_t));
226 227
  module->params = calloc(1, sizeof(dt_iop_colorcorrection_params_t));
  module->default_params = calloc(1, sizeof(dt_iop_colorcorrection_params_t));
228
  module->default_enabled = 0;
Heiko Bauke's avatar
Heiko Bauke committed
229
  module->priority = 720; // module order created by iop_dependencies.py, do not edit!
230 231
  module->params_size = sizeof(dt_iop_colorcorrection_params_t);
  module->gui_data = NULL;
232
  dt_iop_colorcorrection_params_t tmp = (dt_iop_colorcorrection_params_t){ 0., 0., 0., 0., 1.0 };
233 234 235 236 237 238 239 240 241 242
  memcpy(module->params, &tmp, sizeof(dt_iop_colorcorrection_params_t));
  memcpy(module->default_params, &tmp, sizeof(dt_iop_colorcorrection_params_t));
}

void cleanup(dt_iop_module_t *module)
{
  free(module->params);
  module->params = NULL;
}

243
static void sat_callback(GtkWidget *slider, gpointer user_data);
244
static gboolean dt_iop_colorcorrection_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data);
245 246 247 248 249 250
static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEventMotion *event,
                                                     gpointer user_data);
static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventButton *event,
                                                    gpointer user_data);
static gboolean dt_iop_colorcorrection_leave_notify(GtkWidget *widget, GdkEventCrossing *event,
                                                    gpointer user_data);
251
static gboolean dt_iop_colorcorrection_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data);
252
static gboolean dt_iop_colorcorrection_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
253

254 255 256 257 258
void gui_init(struct dt_iop_module_t *self)
{
  self->gui_data = malloc(sizeof(dt_iop_colorcorrection_gui_data_t));
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;

259
  g->selected = 0;
260

261
  self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_BAUHAUS_SPACE);
262
  g->area = GTK_DRAWING_AREA(dtgtk_drawing_area_new_with_aspect_ratio(1.0));
Tobias Ellinghaus's avatar
Tobias Ellinghaus committed
263
  gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->area), TRUE, TRUE, 0);
264 265 266
  gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("drag the line for split toning. "
                                                     "bright means highlights, dark means shadows. "
                                                     "use mouse wheel to change saturation."));
267 268

  gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK
269
                                                 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
270 271
                                                 | GDK_LEAVE_NOTIFY_MASK | GDK_SCROLL_MASK
                                                 | GDK_SMOOTH_SCROLL_MASK | GDK_KEY_PRESS_MASK);
272
  gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE);
273
  g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_colorcorrection_draw), self);
274 275 276 277 278 279 280
  g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(dt_iop_colorcorrection_button_press),
                   self);
  g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(dt_iop_colorcorrection_motion_notify),
                   self);
  g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(dt_iop_colorcorrection_leave_notify),
                   self);
  g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(dt_iop_colorcorrection_scrolled), self);
281
  g_signal_connect(G_OBJECT(g->area), "key-press-event", G_CALLBACK(dt_iop_colorcorrection_key_press), self);
282

283
  g->slider = dt_bauhaus_slider_new_with_range(self, -3.0f, 3.0f, 0.01f, 1.0f, 2);
284
  gtk_box_pack_start(GTK_BOX(self->widget), g->slider, TRUE, TRUE, 0);
285
  gtk_widget_set_tooltip_text(g->slider, _("set the global saturation"));
286
  dt_bauhaus_widget_set_label(g->slider, NULL, _("saturation"));
287

288
  g_signal_connect(G_OBJECT(g->slider), "value-changed", G_CALLBACK(sat_callback), self);
289 290 291
  cmsHPROFILE hsRGB = dt_colorspaces_get_profile(DT_COLORSPACE_SRGB, "", DT_PROFILE_DIRECTION_IN)->profile;
  cmsHPROFILE hLab = dt_colorspaces_get_profile(DT_COLORSPACE_LAB, "", DT_PROFILE_DIRECTION_ANY)->profile;
  g->xform = cmsCreateTransform(hLab, TYPE_Lab_DBL, hsRGB, TYPE_RGB_DBL, INTENT_PERCEPTUAL,
292
                                0); // cmsFLAGS_NOTPRECALC);
293 294 295 296
}

void gui_cleanup(struct dt_iop_module_t *self)
{
johannes hanika's avatar
johannes hanika committed
297 298
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
  cmsDeleteTransform(g->xform);
299 300 301 302
  free(self->gui_data);
  self->gui_data = NULL;
}

303
static void sat_callback(GtkWidget *slider, gpointer user_data)
304 305 306 307
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  if(self->dt->gui->reset) return;
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
308
  p->saturation = dt_bauhaus_slider_get(slider);
309
  dt_dev_add_history_item(darktable.develop, self, TRUE);
jhanika's avatar
jhanika committed
310
  gtk_widget_queue_draw(self->widget);
311
}
jhanika's avatar
jhanika committed
312

313
static gboolean dt_iop_colorcorrection_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
jhanika's avatar
jhanika committed
314 315
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
316
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
317
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
jhanika's avatar
jhanika committed
318 319

  const int inset = DT_COLORCORRECTION_INSET;
320 321 322
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  int width = allocation.width, height = allocation.height;
323 324
  cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);
jhanika's avatar
jhanika committed
325
  // clear bg
326
  cairo_set_source_rgb(cr, .2, .2, .2);
jhanika's avatar
jhanika committed
327 328 329
  cairo_paint(cr);

  cairo_translate(cr, inset, inset);
330 331 332
  cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
  width -= 2 * inset;
  height -= 2 * inset;
jhanika's avatar
jhanika committed
333 334 335 336
  // flip y:
  cairo_translate(cr, 0, height);
  cairo_scale(cr, 1., -1.);
  const int cells = 8;
337 338
  for(int j = 0; j < cells; j++)
    for(int i = 0; i < cells; i++)
339
    {
340
      double rgb[3] = { 0.5, 0.5, 0.5 }; // Lab: rgb grey converted to Lab
341 342 343 344 345
      cmsCIELab Lab;
      Lab.L = 53.390011;
      Lab.a = Lab.b = 0; // grey
      // dt_iop_sRGB_to_Lab(rgb, Lab, 0, 0, 1.0, 1, 1); // get grey in Lab
      // printf("lab = %f %f %f\n", Lab[0], Lab[1], Lab[2]);
346 347
      Lab.a = p->saturation * (Lab.a + Lab.L * .05 * DT_COLORCORRECTION_MAX * (i / (cells - 1.0) - .5));
      Lab.b = p->saturation * (Lab.b + Lab.L * .05 * DT_COLORCORRECTION_MAX * (j / (cells - 1.0) - .5));
348 349
      cmsDoTransform(g->xform, &Lab, rgb, 1);
      // dt_iop_Lab_to_sRGB(Lab, rgb, 0, 0, 1.0, 1, 1);
350 351 352 353
      cairo_set_source_rgb(cr, rgb[0], rgb[1], rgb[2]);
      cairo_rectangle(cr, width * i / (float)cells, height * j / (float)cells,
                      width / (float)cells - DT_PIXEL_APPLY_DPI(1),
                      height / (float)cells - DT_PIXEL_APPLY_DPI(1));
354 355
      cairo_fill(cr);
    }
356
  cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
357
  float loa, hia, lob, hib;
358 359 360 361
  loa = .5f * (width + width * p->loa / (float)DT_COLORCORRECTION_MAX);
  hia = .5f * (width + width * p->hia / (float)DT_COLORCORRECTION_MAX);
  lob = .5f * (height + height * p->lob / (float)DT_COLORCORRECTION_MAX);
  hib = .5f * (height + height * p->hib / (float)DT_COLORCORRECTION_MAX);
362
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.));
363 364 365
  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  cairo_move_to(cr, loa, lob);
  cairo_line_to(cr, hia, hib);
366
  cairo_stroke(cr);
367 368 369

  cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
  if(g->selected == 1)
370
    cairo_arc(cr, loa, lob, DT_PIXEL_APPLY_DPI(5), 0, 2. * M_PI);
371
  else
372
    cairo_arc(cr, loa, lob, DT_PIXEL_APPLY_DPI(3), 0, 2. * M_PI);
373 374 375 376
  cairo_fill(cr);

  cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
  if(g->selected == 2)
377
    cairo_arc(cr, hia, hib, DT_PIXEL_APPLY_DPI(5), 0, 2. * M_PI);
378
  else
379
    cairo_arc(cr, hia, hib, DT_PIXEL_APPLY_DPI(3), 0, 2. * M_PI);
380
  cairo_fill(cr);
jhanika's avatar
jhanika committed
381

382 383 384 385
  cairo_destroy(cr);
  cairo_set_source_surface(crf, cst, 0, 0);
  cairo_paint(crf);
  cairo_surface_destroy(cst);
jhanika's avatar
jhanika committed
386 387 388
  return TRUE;
}

389 390
static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEventMotion *event,
                                                     gpointer user_data)
jhanika's avatar
jhanika committed
391
{
392 393 394 395
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
  const int inset = DT_COLORCORRECTION_INSET;
396 397
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
398
  int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset;
399 400
  const float mouse_x = CLAMP(event->x - inset, 0, width);
  const float mouse_y = CLAMP(height - 1 - event->y + inset, 0, height);
401 402
  const float ma = (2.0 * mouse_x - width) * DT_COLORCORRECTION_MAX / (float)width;
  const float mb = (2.0 * mouse_y - height) * DT_COLORCORRECTION_MAX / (float)height;
403
  if(event->state & GDK_BUTTON1_MASK)
404
  {
405
    if(g->selected == 1)
406
    {
407 408 409
      p->loa = ma;
      p->lob = mb;
      dt_dev_add_history_item(darktable.develop, self, TRUE);
410
    }
411
    else if(g->selected == 2)
412
    {
413 414 415
      p->hia = ma;
      p->hib = mb;
      dt_dev_add_history_item(darktable.develop, self, TRUE);
416
    }
417
  }
418
  else
419
  {
420
    g->selected = 0;
421
    const float thrs = DT_PIXEL_APPLY_DPI(5.0f);
422 423 424 425 426 427
    const float distlo = (p->loa - ma) * (p->loa - ma) + (p->lob - mb) * (p->lob - mb);
    const float disthi = (p->hia - ma) * (p->hia - ma) + (p->hib - mb) * (p->hib - mb);
    if(distlo < thrs * thrs && distlo < disthi)
      g->selected = 1;
    else if(disthi < thrs * thrs && disthi <= distlo)
      g->selected = 2;
428
  }
429
  if(g->selected > 0) gtk_widget_grab_focus(widget);
430 431
  gtk_widget_queue_draw(self->widget);
  return TRUE;
jhanika's avatar
jhanika committed
432 433
}

434 435
static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventButton *event,
                                                    gpointer user_data)
jhanika's avatar
jhanika committed
436
{
437
  if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
438
  {
439
    // double click resets:
440
    dt_iop_module_t *self = (dt_iop_module_t *)user_data;
441
    dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
442
    dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
443 444
    switch(g->selected)
    {
445
      case 1: // only reset lo
446 447 448
        p->loa = p->lob = 0.0;
        dt_dev_add_history_item(darktable.develop, self, TRUE);
        break;
449
      case 2: // only reset hi
450 451 452 453 454
        p->hia = p->hib = 0.0;
        dt_dev_add_history_item(darktable.develop, self, TRUE);
        break;
      default: // reset everything
      {
455
        dt_iop_colorcorrection_params_t *d = (dt_iop_colorcorrection_params_t *)self->default_params;
456 457 458 459
        memcpy(p, d, sizeof(*p));
        dt_dev_add_history_item(darktable.develop, self, TRUE);
      }
    }
460 461 462
    return TRUE;
  }
  return FALSE;
jhanika's avatar
jhanika committed
463 464
}

465 466
static gboolean dt_iop_colorcorrection_leave_notify(GtkWidget *widget, GdkEventCrossing *event,
                                                    gpointer user_data)
jhanika's avatar
jhanika committed
467
{
468 469
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  gtk_widget_queue_draw(self->widget);
jhanika's avatar
jhanika committed
470 471 472
  return TRUE;
}

473
static gboolean dt_iop_colorcorrection_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
474 475 476 477
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
478

479 480
  gdouble delta_y;
  if(dt_gui_get_scroll_deltas(event, NULL, &delta_y))
481
  {
482 483 484
     p->saturation = CLAMP(p->saturation - 0.1 * delta_y, -3.0, 3.0);
     dt_bauhaus_slider_set(g->slider, p->saturation);
     gtk_widget_queue_draw(widget);
485
  }
486

487 488 489
  return TRUE;
}

490 491
#define COLORCORRECTION_DEFAULT_STEP (0.5f)

492 493 494 495 496 497 498 499 500 501 502 503
static gboolean dt_iop_colorcorrection_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
  if(g->selected < 1) return FALSE;

  int handled = 0;
  float dx = 0.0f, dy = 0.0f;
  if(event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
  {
    handled = 1;
504
    dy = COLORCORRECTION_DEFAULT_STEP;
505 506 507 508
  }
  else if(event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
  {
    handled = 1;
509
    dy = -COLORCORRECTION_DEFAULT_STEP;
510 511 512 513
  }
  else if(event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right)
  {
    handled = 1;
514
    dx = COLORCORRECTION_DEFAULT_STEP;
515 516 517 518
  }
  else if(event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left)
  {
    handled = 1;
519
    dx = -COLORCORRECTION_DEFAULT_STEP;
520 521
  }

522
  if(!handled) return TRUE;
523

524
  float multiplier;
525

526 527 528 529 530 531 532 533 534 535 536 537 538
  GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask();
  if((event->state & modifiers) == GDK_SHIFT_MASK)
  {
    multiplier = dt_conf_get_float("darkroom/ui/scale_rough_step_multiplier");
  }
  else if((event->state & modifiers) == GDK_CONTROL_MASK)
  {
    multiplier = dt_conf_get_float("darkroom/ui/scale_precise_step_multiplier");
  }
  else
  {
    multiplier = dt_conf_get_float("darkroom/ui/scale_step_multiplier");
  }
539

540 541
  dx *= multiplier;
  dy *= multiplier;
542

543 544 545 546 547 548 549 550 551 552
  switch(g->selected)
  {
    case 1: // only set lo
      p->loa = CLAMP(p->loa + dx, -DT_COLORCORRECTION_MAX, DT_COLORCORRECTION_MAX);
      p->lob = CLAMP(p->lob + dy, -DT_COLORCORRECTION_MAX, DT_COLORCORRECTION_MAX);
      break;
    case 2: // only set hi
      p->hia = CLAMP(p->hia + dx, -DT_COLORCORRECTION_MAX, DT_COLORCORRECTION_MAX);
      p->hib = CLAMP(p->hib + dy, -DT_COLORCORRECTION_MAX, DT_COLORCORRECTION_MAX);
      break;
553 554
  }

555 556 557
  dt_dev_add_history_item(darktable.develop, self, TRUE);
  gtk_widget_queue_draw(widget);

558 559 560
  return TRUE;
}

Richard Wonka's avatar
Richard Wonka committed
561
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
562
// vim: shiftwidth=2 expandtab tabstop=2 cindent
Tobias Ellinghaus's avatar
Tobias Ellinghaus committed
563
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;