~ubuntu-branches/ubuntu/saucy/darktable/saucy

« back to all changes in this revision

Viewing changes to src/iop/colorcorrection.c

  • Committer: Bazaar Package Importer
  • Author(s): David Bremner
  • Date: 2011-04-14 23:42:12 UTC
  • Revision ID: james.westby@ubuntu.com-20110414234212-kuffcz5wiu18v6ra
Tags: upstream-0.8
ImportĀ upstreamĀ versionĀ 0.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    This file is part of darktable,
 
3
    copyright (c) 2009--2010 johannes hanika.
 
4
 
 
5
    darktable is free software: you can redistribute it and/or modify
 
6
    it under the terms of the GNU General Public License as published by
 
7
    the Free Software Foundation, either version 3 of the License, or
 
8
    (at your option) any later version.
 
9
 
 
10
    darktable is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
    GNU General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU General Public License
 
16
    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
 
17
*/
 
18
#ifdef HAVE_CONFIG_H
 
19
#include "config.h"
 
20
#endif
 
21
#include <stdlib.h>
 
22
#include <math.h>
 
23
#include <assert.h>
 
24
#include <string.h>
 
25
#ifdef HAVE_GEGL
 
26
#include <gegl.h>
 
27
#endif
 
28
#include "common/colorspaces.h"
 
29
#include "iop/colorcorrection.h"
 
30
#include "develop/develop.h"
 
31
#include "control/control.h"
 
32
#include "gui/gtk.h"
 
33
#include "develop/imageop.h"
 
34
#include "dtgtk/resetlabel.h"
 
35
 
 
36
DT_MODULE(1)
 
37
 
 
38
#define DT_COLORCORRECTION_INSET 5
 
39
#define DT_COLORCORRECTION_MAX 40.
 
40
 
 
41
const char *name()
 
42
{
 
43
  return _("color correction");
 
44
}
 
45
 
 
46
int flags()
 
47
{
 
48
  return IOP_FLAGS_INCLUDE_IN_STYLES;
 
49
}
 
50
 
 
51
int
 
52
groups ()
 
53
{
 
54
  return IOP_GROUP_COLOR;
 
55
}
 
56
 
 
57
 
 
58
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out)
 
59
{
 
60
  dt_iop_colorcorrection_data_t *d = (dt_iop_colorcorrection_data_t *)piece->data;
 
61
  float *in  = (float *)i;
 
62
  float *out = (float *)o;
 
63
  const int ch = piece->colors;
 
64
  for(int k=0; k<roi_out->width*roi_out->height; k++)
 
65
  {
 
66
    out[0] = in[0];
 
67
    out[1] = d->saturation*(in[1] + in[0] * d->a_scale + d->a_base);
 
68
    out[2] = d->saturation*(in[2] + in[0] * d->b_scale + d->b_base);
 
69
    out += ch;
 
70
    in += ch;
 
71
  }
 
72
}
 
73
 
 
74
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)
 
75
{
 
76
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)p1;
 
77
#ifdef HAVE_GEGL
 
78
  // pull in new params to gegl
 
79
  gegl_node_set(piece->input, "high_a_delta", p->hia, "high_b_delta", p->hib, "low_a_delta", p->loa, "low_b_delta", p->lob, "saturation", p->saturation, NULL);
 
80
#else
 
81
  dt_iop_colorcorrection_data_t *d = (dt_iop_colorcorrection_data_t *)piece->data;
 
82
  d->a_scale = (p->hia - p->loa)/100.0;
 
83
  d->a_base  = p->loa;
 
84
  d->b_scale = (p->hib - p->lob)/100.0;
 
85
  d->b_base  = p->lob;
 
86
  d->saturation = p->saturation;
 
87
#endif
 
88
}
 
89
 
 
90
void init_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
 
91
{
 
92
#ifdef HAVE_GEGL
 
93
  // create part of the gegl pipeline
 
94
  piece->data = NULL;
 
95
  dt_iop_colorcorrection_params_t *default_params = (dt_iop_colorcorrection_params_t *)self->default_params;
 
96
  piece->input = piece->output = gegl_node_new_child(pipe->gegl, "operation", "gegl:whitebalance", "high_a_delta", default_params->hia, "high_b_delta", default_params->hib, "low_a_delta", default_params->loa, "low_b_delta", default_params->lob, "saturation", default_params->saturation, NULL);
 
97
#else
 
98
  piece->data = malloc(sizeof(dt_iop_colorcorrection_data_t));
 
99
  self->commit_params(self, self->default_params, pipe, piece);
 
100
#endif
 
101
}
 
102
 
 
103
void cleanup_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
 
104
{
 
105
#ifdef HAVE_GEGL
 
106
  // clean up everything again.
 
107
  (void)gegl_node_remove_child(pipe->gegl, piece->input);
 
108
  // no free necessary, no data is alloc'ed
 
109
#else
 
110
  free(piece->data);
 
111
#endif
 
112
}
 
113
 
 
114
void gui_update(struct dt_iop_module_t *self)
 
115
{
 
116
  dt_iop_module_t *module = (dt_iop_module_t *)self;
 
117
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
118
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)module->params;
 
119
  dtgtk_slider_set_value(g->scale5, p->saturation);
 
120
  gtk_widget_queue_draw(self->widget);
 
121
}
 
122
 
 
123
void init(dt_iop_module_t *module)
 
124
{
 
125
  // module->data = malloc(sizeof(dt_iop_colorcorrection_data_t));
 
126
  module->params = malloc(sizeof(dt_iop_colorcorrection_params_t));
 
127
  module->default_params = malloc(sizeof(dt_iop_colorcorrection_params_t));
 
128
  module->default_enabled = 0;
 
129
  module->priority = 800;
 
130
  module->params_size = sizeof(dt_iop_colorcorrection_params_t);
 
131
  module->gui_data = NULL;
 
132
  dt_iop_colorcorrection_params_t tmp = (dt_iop_colorcorrection_params_t)
 
133
  {
 
134
    0., 0., 0., 0., 1.0
 
135
  };
 
136
  memcpy(module->params, &tmp, sizeof(dt_iop_colorcorrection_params_t));
 
137
  memcpy(module->default_params, &tmp, sizeof(dt_iop_colorcorrection_params_t));
 
138
}
 
139
 
 
140
void cleanup(dt_iop_module_t *module)
 
141
{
 
142
  free(module->gui_data);
 
143
  module->gui_data = NULL;
 
144
  free(module->params);
 
145
  module->params = NULL;
 
146
}
 
147
 
 
148
static void sat_callback (GtkDarktableSlider *slider, gpointer user_data);
 
149
static gboolean dt_iop_colorcorrection_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data);
 
150
static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data);
 
151
static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data);
 
152
static gboolean dt_iop_colorcorrection_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data);
 
153
static gboolean dt_iop_colorcorrection_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data);
 
154
static gboolean dt_iop_colorcorrection_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data);
 
155
 
 
156
void gui_init(struct dt_iop_module_t *self)
 
157
{
 
158
  self->gui_data = malloc(sizeof(dt_iop_colorcorrection_gui_data_t));
 
159
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
160
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
 
161
 
 
162
  g->selected = g->dragging = 0;
 
163
  g->press_x = g->press_y = -1;
 
164
 
 
165
  self->widget = GTK_WIDGET(gtk_vbox_new(FALSE, DT_GUI_IOP_MODULE_CONTROL_SPACING));
 
166
  g->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
 
167
  GtkWidget *asp = gtk_aspect_frame_new(NULL, 0.5, 0.5, 1.0, TRUE);
 
168
  gtk_box_pack_start(GTK_BOX(self->widget), asp, TRUE, TRUE, 0);
 
169
  gtk_container_add(GTK_CONTAINER(asp), GTK_WIDGET(g->area));
 
170
  gtk_drawing_area_size(g->area, 258, 258);
 
171
 
 
172
  gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK);
 
173
  g_signal_connect (G_OBJECT (g->area), "expose-event",
 
174
                    G_CALLBACK (dt_iop_colorcorrection_expose), self);
 
175
  g_signal_connect (G_OBJECT (g->area), "button-press-event",
 
176
                    G_CALLBACK (dt_iop_colorcorrection_button_press), self);
 
177
  g_signal_connect (G_OBJECT (g->area), "button-release-event",
 
178
                    G_CALLBACK (dt_iop_colorcorrection_button_release), self);
 
179
  g_signal_connect (G_OBJECT (g->area), "motion-notify-event",
 
180
                    G_CALLBACK (dt_iop_colorcorrection_motion_notify), self);
 
181
  g_signal_connect (G_OBJECT (g->area), "leave-notify-event",
 
182
                    G_CALLBACK (dt_iop_colorcorrection_leave_notify), self);
 
183
  g_signal_connect (G_OBJECT (g->area), "scroll-event",
 
184
                    G_CALLBACK (dt_iop_colorcorrection_scrolled), self);
 
185
 
 
186
  g->hbox = GTK_HBOX(gtk_hbox_new(FALSE, 0));
 
187
  gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->hbox), TRUE, TRUE, 0);
 
188
  g->vbox1 = GTK_VBOX(gtk_vbox_new(FALSE, 0));
 
189
  g->vbox2 = GTK_VBOX(gtk_vbox_new(FALSE, 0));
 
190
  gtk_box_pack_start(GTK_BOX(g->hbox), GTK_WIDGET(g->vbox1), FALSE, FALSE, 5);
 
191
  gtk_box_pack_start(GTK_BOX(g->hbox), GTK_WIDGET(g->vbox2), TRUE, TRUE, 5);
 
192
  GtkWidget *label = dtgtk_reset_label_new(_("saturation"), self, &p->saturation, sizeof(float));
 
193
  gtk_box_pack_start(GTK_BOX(g->vbox1), GTK_WIDGET(label), TRUE, TRUE, 0);
 
194
  g->scale5 = DTGTK_SLIDER(dtgtk_slider_new_with_range(DARKTABLE_SLIDER_BAR,-3.0, 3.0, 0.01, p->saturation,2));
 
195
 
 
196
  gtk_box_pack_start(GTK_BOX(g->vbox2), GTK_WIDGET(g->scale5), TRUE, TRUE, 0);
 
197
 
 
198
 
 
199
  g_signal_connect (G_OBJECT (g->scale5), "value-changed",
 
200
                    G_CALLBACK (sat_callback), self);
 
201
  g->hsRGB = dt_colorspaces_create_srgb_profile();
 
202
  g->hLab  = dt_colorspaces_create_lab_profile();
 
203
  g->xform = cmsCreateTransform(g->hLab, TYPE_Lab_DBL, g->hsRGB, TYPE_RGB_DBL,
 
204
                                INTENT_PERCEPTUAL, 0);//cmsFLAGS_NOTPRECALC);
 
205
}
 
206
 
 
207
void gui_cleanup(struct dt_iop_module_t *self)
 
208
{
 
209
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
210
  dt_colorspaces_cleanup_profile(g->hsRGB);
 
211
  dt_colorspaces_cleanup_profile(g->hLab);
 
212
  cmsDeleteTransform(g->xform);
 
213
  free(self->gui_data);
 
214
  self->gui_data = NULL;
 
215
}
 
216
 
 
217
static void sat_callback (GtkDarktableSlider *slider, gpointer user_data)
 
218
{
 
219
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
220
  if(self->dt->gui->reset) return;
 
221
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
 
222
  p->saturation = dtgtk_slider_get_value(slider);
 
223
  dt_dev_add_history_item(darktable.develop, self, TRUE);
 
224
  gtk_widget_queue_draw(self->widget);
 
225
}
 
226
 
 
227
static gboolean dt_iop_colorcorrection_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
 
228
{
 
229
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
230
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
231
  dt_iop_colorcorrection_params_t *p  = (dt_iop_colorcorrection_params_t *)self->params;
 
232
  dt_iop_colorcorrection_params_t *p1 = &g->press_params;
 
233
 
 
234
  const int inset = DT_COLORCORRECTION_INSET;
 
235
  int width = widget->allocation.width, height = widget->allocation.height;
 
236
  cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
 
237
  cairo_t *cr = cairo_create(cst);
 
238
  // clear bg
 
239
  cairo_set_source_rgb (cr, .2, .2, .2);
 
240
  cairo_paint(cr);
 
241
 
 
242
  cairo_translate(cr, inset, inset);
 
243
  width -= 2*inset;
 
244
  height -= 2*inset;
 
245
  // flip y:
 
246
  cairo_translate(cr, 0, height);
 
247
  cairo_scale(cr, 1., -1.);
 
248
  const int cells = 8;
 
249
  for(int j=0; j<cells; j++) for(int i=0; i<cells; i++)
 
250
    {
 
251
      double rgb[3] = {0.5, 0.5, 0.5}; // Lab: rgb grey converted to Lab
 
252
      cmsCIELab Lab;
 
253
      Lab.L = 53.390011;
 
254
      Lab.a = Lab.b = 0; // grey
 
255
      // dt_iop_sRGB_to_Lab(rgb, Lab, 0, 0, 1.0, 1, 1); // get grey in Lab
 
256
      // printf("lab = %f %f %f\n", Lab[0], Lab[1], Lab[2]);
 
257
      Lab.a = p->saturation*(Lab.a + Lab.L * .05*DT_COLORCORRECTION_MAX*(i/(cells-1.0) - .5));
 
258
      Lab.b = p->saturation*(Lab.b + Lab.L * .05*DT_COLORCORRECTION_MAX*(j/(cells-1.0) - .5));
 
259
      cmsDoTransform(g->xform, &Lab, rgb, 1);
 
260
      // dt_iop_Lab_to_sRGB(Lab, rgb, 0, 0, 1.0, 1, 1);
 
261
      cairo_set_source_rgb (cr, rgb[0], rgb[1], rgb[2]);
 
262
      cairo_rectangle(cr, width*i/(float)cells, height*j/(float)cells, width/(float)cells-1, height/(float)cells-1);
 
263
      cairo_fill(cr);
 
264
    }
 
265
  float loa, hia, lob, hib;
 
266
  if(!g->dragging) p1 = p;
 
267
  loa = .5f*(width + width*p1->loa/(float)DT_COLORCORRECTION_MAX);
 
268
  hia = .5f*(width + width*p1->hia/(float)DT_COLORCORRECTION_MAX);
 
269
  lob = .5f*(height + height*p1->lob/(float)DT_COLORCORRECTION_MAX);
 
270
  hib = .5f*(height + height*p1->hib/(float)DT_COLORCORRECTION_MAX);
 
271
  cairo_set_line_width(cr, 2.);
 
272
  if(g->dragging)
 
273
  {
 
274
    cairo_rectangle(cr, loa, lob, hia-loa, hib-lob);
 
275
    if(g->selected & 1) loa = /*MIN(g->selected < 0xf ? hia :  INFINITY,*/ loa + g->mouse_x-g->press_x;//);
 
276
    if(g->selected & 2) lob = /*MIN(g->selected < 0xf ? hib :  INFINITY,*/ lob + g->mouse_y-g->press_y;//);
 
277
    if(g->selected & 4) hia = /*MAX(g->selected < 0xf ? loa : -INFINITY,*/ hia + g->mouse_x-g->press_x;//);
 
278
    if(g->selected & 8) hib = /*MAX(g->selected < 0xf ? lob : -INFINITY,*/ hib + g->mouse_y-g->press_y;//);
 
279
    p->loa = (2.0*loa - width) *DT_COLORCORRECTION_MAX/(float)width;
 
280
    p->hia = (2.0*hia - width) *DT_COLORCORRECTION_MAX/(float)width;
 
281
    p->lob = (2.0*lob - height)*DT_COLORCORRECTION_MAX/(float)height;
 
282
    p->hib = (2.0*hib - height)*DT_COLORCORRECTION_MAX/(float)height;
 
283
  }
 
284
  else
 
285
  {
 
286
    cairo_set_source_rgb(cr, .1, .1, .1);
 
287
    cairo_move_to(cr, loa, hib);
 
288
    cairo_line_to(cr, loa, lob);
 
289
    cairo_line_to(cr, hia, lob);
 
290
    cairo_stroke(cr);
 
291
    cairo_set_source_rgb(cr, .9, .9, .9);
 
292
    cairo_move_to(cr, hia, lob);
 
293
    cairo_line_to(cr, hia, hib);
 
294
    cairo_line_to(cr, loa, hib);
 
295
    cairo_stroke(cr);
 
296
    cairo_rectangle(cr, loa, lob, hia-loa, hib-lob);
 
297
    if(g->selected & 1) loa = loa < hia ? loa-7 : loa+7;
 
298
    if(g->selected & 2) lob = lob < hib ? lob-7 : lob+7;
 
299
    if(g->selected & 4) hia = loa < hia ? hia+7 : hia-7;
 
300
    if(g->selected & 8) hib = lob < hib ? hib+7 : hib-7;
 
301
  }
 
302
  cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
 
303
  cairo_set_source_rgba(cr, .9, .9, .9, .5);
 
304
  cairo_rectangle(cr, loa, lob, hia-loa, hib-lob);
 
305
  cairo_fill_preserve(cr);
 
306
  cairo_stroke(cr);
 
307
  if(g->dragging)
 
308
    dt_dev_add_history_item(darktable.develop, self, TRUE);
 
309
 
 
310
  cairo_destroy(cr);
 
311
  cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget));
 
312
  cairo_set_source_surface (cr_pixmap, cst, 0, 0);
 
313
  cairo_paint(cr_pixmap);
 
314
  cairo_destroy(cr_pixmap);
 
315
  cairo_surface_destroy(cst);
 
316
  return TRUE;
 
317
}
 
318
 
 
319
static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
 
320
{
 
321
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
322
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
323
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
 
324
  const int inset = DT_COLORCORRECTION_INSET;
 
325
  int width = widget->allocation.width - 2*inset, height = widget->allocation.height - 2*inset;
 
326
  g->mouse_x = CLAMP(event->x - inset, 0, width);
 
327
  g->mouse_y = CLAMP(height - 1 - event->y + inset, 0, height);
 
328
  if(!g->dragging)
 
329
  {
 
330
    g->press_x = g->mouse_x;
 
331
    g->press_y = g->mouse_y;
 
332
    const float loa = .5f*(width + width*p->loa/(float)DT_COLORCORRECTION_MAX),
 
333
                hia = .5f*(width + width*p->hia/(float)DT_COLORCORRECTION_MAX),
 
334
                lob = .5f*(height + height*p->lob/(float)DT_COLORCORRECTION_MAX),
 
335
                hib = .5f*(height + height*p->hib/(float)DT_COLORCORRECTION_MAX);
 
336
    g->selected = 0;
 
337
    if(loa <= hia)
 
338
    {
 
339
      if(g->press_x <= loa) g->selected |= 1;
 
340
      if(g->press_x >= hia) g->selected |= 4;
 
341
    }
 
342
    else
 
343
    {
 
344
      if(g->press_x <= hia) g->selected |= 4;
 
345
      if(g->press_x >= loa) g->selected |= 1;
 
346
    }
 
347
    if(lob <= hib)
 
348
    {
 
349
      if(g->press_y <= lob) g->selected |= 2;
 
350
      if(g->press_y >= hib) g->selected |= 8;
 
351
    }
 
352
    else
 
353
    {
 
354
      if(g->press_y <= hib) g->selected |= 8;
 
355
      if(g->press_y >= lob) g->selected |= 2;
 
356
    }
 
357
    if(g->press_x > MIN(loa, hia) && g->press_x < MAX(hia,loa) && g->press_y > MIN(lob,hib) && g->press_y < MAX(hib,lob)) g->selected = 0xf;
 
358
    g->press_params = *p;
 
359
  }
 
360
  gtk_widget_queue_draw(self->widget);
 
361
  gint x, y;
 
362
  gdk_window_get_pointer(event->window, &x, &y, NULL);
 
363
  return TRUE;
 
364
}
 
365
 
 
366
static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
 
367
{
 
368
  if(event->button == 1)
 
369
  {
 
370
    dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
371
    dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
372
    g->dragging = 1;
 
373
    return TRUE;
 
374
  }
 
375
  return FALSE;
 
376
}
 
377
 
 
378
static gboolean dt_iop_colorcorrection_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
 
379
{
 
380
  if(event->button == 1)
 
381
  {
 
382
    dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
383
    dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
384
    g->dragging = 0;
 
385
    return TRUE;
 
386
  }
 
387
  return FALSE;
 
388
}
 
389
 
 
390
static gboolean dt_iop_colorcorrection_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
 
391
{
 
392
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
393
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
394
  g->selected = g->dragging = 0;
 
395
  gtk_widget_queue_draw(self->widget);
 
396
  return TRUE;
 
397
}
 
398
 
 
399
static gboolean dt_iop_colorcorrection_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
 
400
{
 
401
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
 
402
  dt_iop_colorcorrection_gui_data_t *g = (dt_iop_colorcorrection_gui_data_t *)self->gui_data;
 
403
  dt_iop_colorcorrection_params_t *p = (dt_iop_colorcorrection_params_t *)self->params;
 
404
  if(event->direction == GDK_SCROLL_UP   && p->saturation > -3.0) p->saturation -= 0.1;
 
405
  if(event->direction == GDK_SCROLL_DOWN && p->saturation <  3.0) p->saturation += 0.1;
 
406
  dtgtk_slider_set_value(g->scale5, p->saturation);
 
407
  gtk_widget_queue_draw(widget);
 
408
  return TRUE;
 
409
}
 
410