blend_gui.c 87.8 KB
Newer Older
1 2
/*
    This file is part of darktable,
3
    copyright (c) 2009--2012 johannes hanika.
4
    copyright (c) 2011 Henrik Andersson.
5
    copyright (c) 2012--2013 Ulrich Pegelow
6 7 8 9 10 11 12 13 14 15 16 17 18 19

    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/>.
*/
20
#include "bauhaus/bauhaus.h"
21
#include "common/debug.h"
22 23
#include "common/dtpthread.h"
#include "common/opencl.h"
24 25
#include "control/control.h"
#include "develop/blend.h"
26 27
#include "develop/develop.h"
#include "develop/imageop.h"
28
#include "develop/masks.h"
29 30 31
#include "develop/tiling.h"
#include "dtgtk/button.h"
#include "dtgtk/gradientslider.h"
32 33 34 35 36
#include "gui/accelerators.h"
#include "gui/gtk.h"
#include "gui/presets.h"

#include <assert.h>
37
#include <gmodule.h>
38 39 40
#include <math.h>
#include <stdlib.h>
#include <string.h>
41
#include <strings.h>
42

43
#define CLAMP_RANGE(x, y, z) (CLAMP(x, y, z))
44
#define NEUTRAL_GRAY 0.5
45 46 47

typedef enum _iop_gui_blendif_channel_t
{
48 49 50 51 52
  ch_L = 0,
  ch_a = 1,
  ch_b = 2,
  ch_gray = 0,
  ch_red = 1,
53
  ch_green = 2,
54 55 56
  ch_blue = 3,
  ch_max = 4
} _iop_gui_blendif_channel_t;
57 58


59

60
static const dt_iop_gui_blendif_colorstop_t _gradient_L[]
61
    = { { 0.0f, { 0, 0, 0, 1.0 } },
62 63
        { 0.5f, { NEUTRAL_GRAY / 2, NEUTRAL_GRAY / 2, NEUTRAL_GRAY / 2, 1.0 } },
        { 1.0f, { NEUTRAL_GRAY, NEUTRAL_GRAY, NEUTRAL_GRAY, 1.0 } } };
64

65
static const dt_iop_gui_blendif_colorstop_t _gradient_a[]
66 67 68
    = { { 0.0f, { 0, 0.34 * NEUTRAL_GRAY * 2, 0.27 * NEUTRAL_GRAY * 2, 1.0 } },
        { 0.5f, { NEUTRAL_GRAY, NEUTRAL_GRAY, NEUTRAL_GRAY, 1.0 } },
        { 1.0f, { 0.53 * NEUTRAL_GRAY * 2, 0.08 * NEUTRAL_GRAY * 2, 0.28 * NEUTRAL_GRAY * 2, 1.0 } } };
69

70
static const dt_iop_gui_blendif_colorstop_t _gradient_b[]
71 72 73
    = { { 0.0f, { 0, 0.27 * NEUTRAL_GRAY * 2, 0.58 * NEUTRAL_GRAY * 2, 1.0 } },
        { 0.5f, { NEUTRAL_GRAY, NEUTRAL_GRAY, NEUTRAL_GRAY, 1.0 } },
        { 1.0f, { 0.81 * NEUTRAL_GRAY * 2, 0.66 * NEUTRAL_GRAY * 2, 0, 1.0 } } };
74

75
static const dt_iop_gui_blendif_colorstop_t _gradient_gray[]
76
    = { { 0.0f, { 0, 0, 0, 1.0 } },
77 78
        { 0.5f, { NEUTRAL_GRAY / 2, NEUTRAL_GRAY / 2, NEUTRAL_GRAY / 2, 1.0 } },
        { 1.0f, { NEUTRAL_GRAY, NEUTRAL_GRAY, NEUTRAL_GRAY, 1.0 } } };
79

80
static const dt_iop_gui_blendif_colorstop_t _gradient_red[] = { { 0.0f, { 0, 0, 0, 1.0 } },
81 82
                                                                { 0.5f, { NEUTRAL_GRAY / 2, 0, 0, 1.0 } },
                                                                { 1.0f, { NEUTRAL_GRAY, 0, 0, 1.0 } } };
83

84
static const dt_iop_gui_blendif_colorstop_t _gradient_green[] = { { 0.0f, { 0, 0, 0, 1.0 } },
85 86
                                                                  { 0.5f, { 0, NEUTRAL_GRAY / 2, 0, 1.0 } },
                                                                  { 1.0f, { 0, NEUTRAL_GRAY, 0, 1.0 } } };
87

88
static const dt_iop_gui_blendif_colorstop_t _gradient_blue[] = { { 0.0f, { 0, 0, 0, 1.0 } },
89 90
                                                                 { 0.5f, { 0, 0, NEUTRAL_GRAY / 2, 1.0 } },
                                                                 { 1.0f, { 0, 0, NEUTRAL_GRAY, 1.0 } } };
91

92
static const dt_iop_gui_blendif_colorstop_t _gradient_chroma[]
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    = { { 0.0f, { NEUTRAL_GRAY, NEUTRAL_GRAY, NEUTRAL_GRAY, 1.0 } },
        { 0.5f, { NEUTRAL_GRAY, NEUTRAL_GRAY / 2, NEUTRAL_GRAY, 1.0 } },
        { 1.0f, { NEUTRAL_GRAY, 0, NEUTRAL_GRAY, 1.0 } } };

static const dt_iop_gui_blendif_colorstop_t _gradient_hue[] = {
  { 0.0f, { 1.00f * 1.5f * NEUTRAL_GRAY, 0.68f * 1.5f * NEUTRAL_GRAY, 0.78f * 1.5f * NEUTRAL_GRAY, 1.0 } },
  { 0.166f, { 0.95f * 1.5f * NEUTRAL_GRAY, 0.73f * 1.5f * NEUTRAL_GRAY, 0.56f * 1.5f * NEUTRAL_GRAY, 1.0 } },
  { 0.333f, { 0.71f * 1.5f * NEUTRAL_GRAY, 0.81f * 1.5f * NEUTRAL_GRAY, 0.55f * 1.5f * NEUTRAL_GRAY, 1.0 } },
  { 0.500f, { 0.45f * 1.5f * NEUTRAL_GRAY, 0.85f * 1.5f * NEUTRAL_GRAY, 0.77f * 1.5f * NEUTRAL_GRAY, 1.0 } },
  { 0.666f, { 0.49f * 1.5f * NEUTRAL_GRAY, 0.82f * 1.5f * NEUTRAL_GRAY, 1.00f * 1.5f * NEUTRAL_GRAY, 1.0 } },
  { 0.833f, { 0.82f * 1.5f * NEUTRAL_GRAY, 0.74f * 1.5f * NEUTRAL_GRAY, 1.00f * 1.5f * NEUTRAL_GRAY, 1.0 } },
  { 1.0f, { 1.00f * 1.5f * NEUTRAL_GRAY, 0.68f * 1.5f * NEUTRAL_GRAY, 0.78f * 1.5f * NEUTRAL_GRAY, 1.0 } }
};

static const dt_iop_gui_blendif_colorstop_t _gradient_HUE[]
    = { { 0.0f, { NEUTRAL_GRAY, 0, 0, 1.0 } },
        { 0.166f, { NEUTRAL_GRAY, NEUTRAL_GRAY, 0, 1.0 } },
        { 0.332f, { 0, NEUTRAL_GRAY, 0, 1.0 } },
        { 0.498f, { 0, NEUTRAL_GRAY, NEUTRAL_GRAY, 1.0 } },
        { 0.664f, { 0, 0, NEUTRAL_GRAY, 1.0 } },
        { 0.830f, { NEUTRAL_GRAY, 0, NEUTRAL_GRAY, 1.0 } },
        { 1.0f, { NEUTRAL_GRAY, 0, 0, 1.0 } } };
115 116 117


static inline void _RGB_2_HSL(const float *RGB, float *HSL)
118 119 120 121 122 123 124 125 126 127 128 129 130
{
  float H, S, L;

  float R = RGB[0];
  float G = RGB[1];
  float B = RGB[2];

  float var_Min = fminf(R, fminf(G, B));
  float var_Max = fmaxf(R, fmaxf(G, B));
  float del_Max = var_Max - var_Min;

  L = (var_Max + var_Min) / 2.0f;

131
  if(del_Max == 0.0f)
132 133 134 135 136 137
  {
    H = 0.0f;
    S = 0.0f;
  }
  else
  {
138 139 140 141
    if(L < 0.5f)
      S = del_Max / (var_Max + var_Min);
    else
      S = del_Max / (2.0f - var_Max - var_Min);
142 143 144 145 146

    float del_R = (((var_Max - R) / 6.0f) + (del_Max / 2.0f)) / del_Max;
    float del_G = (((var_Max - G) / 6.0f) + (del_Max / 2.0f)) / del_Max;
    float del_B = (((var_Max - B) / 6.0f) + (del_Max / 2.0f)) / del_Max;

147 148 149 150 151 152 153 154
    if(R == var_Max)
      H = del_B - del_G;
    else if(G == var_Max)
      H = (1.0f / 3.0f) + del_R - del_B;
    else if(B == var_Max)
      H = (2.0f / 3.0f) + del_G - del_R;
    else
      H = 0.0f; // make GCC happy
155

156 157
    if(H < 0.0f) H += 1.0f;
    if(H > 1.0f) H -= 1.0f;
158 159 160 161 162 163 164 165
  }

  HSL[0] = H;
  HSL[1] = S;
  HSL[2] = L;
}


166
static inline void _Lab_2_LCH(const float *Lab, float *LCH)
167
{
168 169
  float var_H = atan2f(Lab[2], Lab[1]);

170 171 172 173
  if(var_H > 0.0f)
    var_H = var_H / (2.0f * M_PI);
  else
    var_H = 1.0f - fabs(var_H) / (2.0f * M_PI);
174 175

  LCH[0] = Lab[0];
176
  LCH[1] = sqrtf(Lab[1] * Lab[1] + Lab[2] * Lab[2]);
177
  LCH[2] = var_H;
178 179 180
}


181
static void _blendif_scale(dt_iop_colorspace_type_t cst, const float *in, float *out)
Ulrich Pegelow's avatar
Ulrich Pegelow committed
182
{
183 184
  float temp[4];

Ulrich Pegelow's avatar
Ulrich Pegelow committed
185 186 187
  switch(cst)
  {
    case iop_cs_Lab:
188
      _Lab_2_LCH(in, temp);
Ulrich Pegelow's avatar
Ulrich Pegelow committed
189
      out[0] = CLAMP_RANGE(in[0] / 100.0f, 0.0f, 1.0f);
190 191
      out[1] = CLAMP_RANGE((in[1] + 128.0f) / 256.0f, 0.0f, 1.0f);
      out[2] = CLAMP_RANGE((in[2] + 128.0f) / 256.0f, 0.0f, 1.0f);
192
      out[3] = CLAMP_RANGE(temp[1] / (128.0f * sqrtf(2.0f)), 0.0f, 1.0f);
193 194
      out[4] = CLAMP_RANGE(temp[2], 0.0f, 1.0f);
      out[5] = out[6] = out[7] = -1;
195
      break;
Ulrich Pegelow's avatar
Ulrich Pegelow committed
196
    case iop_cs_rgb:
197
      _RGB_2_HSL(in, temp);
198
      out[0] = CLAMP_RANGE(0.3f * in[0] + 0.59f * in[1] + 0.11f * in[2], 0.0f, 1.0f);
Ulrich Pegelow's avatar
Ulrich Pegelow committed
199 200 201
      out[1] = CLAMP_RANGE(in[0], 0.0f, 1.0f);
      out[2] = CLAMP_RANGE(in[1], 0.0f, 1.0f);
      out[3] = CLAMP_RANGE(in[2], 0.0f, 1.0f);
202 203 204 205
      out[4] = CLAMP_RANGE(temp[0], 0.0f, 1.0f);
      out[5] = CLAMP_RANGE(temp[1], 0.0f, 1.0f);
      out[6] = CLAMP_RANGE(temp[2], 0.0f, 1.0f);
      out[7] = -1;
206
      break;
Ulrich Pegelow's avatar
Ulrich Pegelow committed
207
    default:
208
      out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = -1.0f;
Ulrich Pegelow's avatar
Ulrich Pegelow committed
209 210
  }
}
211

212
static void _blendif_cook(dt_iop_colorspace_type_t cst, const float *in, float *out)
213
{
214 215
  float temp[4];

216 217 218
  switch(cst)
  {
    case iop_cs_Lab:
219
      _Lab_2_LCH(in, temp);
220 221 222
      out[0] = in[0];
      out[1] = in[1];
      out[2] = in[2];
223
      out[3] = temp[1] / (128.0f * sqrtf(2.0f)) * 100.0f;
224
      out[4] = temp[2] * 360.0f;
225
      out[5] = out[6] = out[7] = -1;
226
      break;
227
    case iop_cs_rgb:
228
      _RGB_2_HSL(in, temp);
229 230 231 232 233 234 235
      out[0] = (0.3f * in[0] + 0.59f * in[1] + 0.11f * in[2]) * 255.0f;
      out[1] = in[0] * 255.0f;
      out[2] = in[1] * 255.0f;
      out[3] = in[2] * 255.0f;
      out[4] = temp[0] * 360.0f;
      out[5] = temp[1] * 100.0f;
      out[6] = temp[2] * 100.0f;
236
      out[7] = -1;
237
      break;
238
    default:
239
      out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = -1.0f;
240 241 242 243
  }
}


244
static void _blendif_scale_print_L(float value, char *string, int n)
245
{
246
  snprintf(string, n, "%-4.0f", value * 100.0f);
247 248
}

249
static void _blendif_scale_print_ab(float value, char *string, int n)
250
{
251
  snprintf(string, n, "%-4.0f", value * 256.0f - 128.0f);
252 253
}

254
static void _blendif_scale_print_rgb(float value, char *string, int n)
255
{
256
  snprintf(string, n, "%-4.0f", value * 255.0f);
257 258
}

259
static void _blendif_scale_print_hue(float value, char *string, int n)
260
{
261
  snprintf(string, n, "%-4.0f", value * 360.0f);
262 263
}

264
static void _blendif_scale_print_default(float value, char *string, int n)
265
{
266
  snprintf(string, n, "%-4.0f", value * 100.0f);
267 268
}

269
static void _blendop_masks_mode_callback(GtkWidget *combo, dt_iop_gui_blend_data_t *data)
270
{
271 272
  const unsigned int mask_mode = GPOINTER_TO_UINT(
      g_list_nth_data(data->masks_modes, dt_bauhaus_combobox_get(data->masks_modes_combo)));
273 274 275 276

  data->module->blend_params->mask_mode = mask_mode;

  if(mask_mode & DEVELOP_MASK_ENABLED)
277
  {
278
    gtk_widget_show(GTK_WIDGET(data->top_box));
279 280 281
  }
  else
  {
282 283
    gtk_widget_hide(GTK_WIDGET(data->top_box));
  }
Ulrich Pegelow's avatar
Ulrich Pegelow committed
284

285 286 287
  if((mask_mode & DEVELOP_MASK_ENABLED)
     && ((data->masks_inited && (mask_mode & DEVELOP_MASK_MASK))
         || (data->blendif_inited && (mask_mode & DEVELOP_MASK_CONDITIONAL))))
288
  {
289 290
    if(data->blendif_inited && (mask_mode & DEVELOP_MASK_CONDITIONAL))
    {
291 292 293 294
      dt_bauhaus_combobox_set(data->masks_combine_combo,
                              g_list_index(data->masks_combine,
                                           GUINT_TO_POINTER(data->module->blend_params->mask_combine
                                                            & (DEVELOP_COMBINE_INV | DEVELOP_COMBINE_INCL))));
295 296 297 298 299
      gtk_widget_hide(GTK_WIDGET(data->masks_invert_combo));
      gtk_widget_show(GTK_WIDGET(data->masks_combine_combo));
    }
    else
    {
300 301 302 303
      dt_bauhaus_combobox_set(
          data->masks_invert_combo,
          g_list_index(data->masks_invert,
                       GUINT_TO_POINTER(data->module->blend_params->mask_combine & DEVELOP_COMBINE_INV)));
304 305 306 307
      gtk_widget_show(GTK_WIDGET(data->masks_invert_combo));
      gtk_widget_hide(GTK_WIDGET(data->masks_combine_combo));
    }

308 309 310 311 312 313 314 315 316
    /*
     * if this iop is operating in raw space, it has only 1 channel per pixel,
     * thus there is no alpha channel where we would normally store mask
     * that would get displayed if following button have been pressed.
     *
     * TODO: revisit if/once there semi-raw iops (e.g temperature) with blending
     */
    if(dt_iop_module_colorspace(data->module) == iop_cs_RAW)
    {
317
      data->module->request_mask_display = DT_DEV_PIXELPIPE_DISPLAY_NONE;
318
      dtgtk_button_set_active(DTGTK_BUTTON(data->showmask), 0);
319 320 321 322 323 324 325
      gtk_widget_hide(GTK_WIDGET(data->showmask));
    }
    else
    {
      gtk_widget_show(GTK_WIDGET(data->showmask));
    }

326 327 328 329
    gtk_widget_show(GTK_WIDGET(data->bottom_box));
  }
  else
  {
330
    data->module->request_mask_display = DT_DEV_PIXELPIPE_DISPLAY_NONE;
331
    dtgtk_button_set_active(DTGTK_BUTTON(data->showmask), 0);
332 333 334
    data->module->suppress_mask = 0;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->suppress), 0);

335
    gtk_widget_hide(GTK_WIDGET(data->bottom_box));
336 337
  }

338 339 340 341
  if(data->masks_inited && (mask_mode & DEVELOP_MASK_MASK))
  {
    gtk_widget_show(GTK_WIDGET(data->masks_box));
  }
342
  else if(data->masks_inited)
343
  {
344
    dt_masks_set_edit_mode(data->module, DT_MASKS_EDIT_OFF);
345 346 347 348
    gtk_widget_hide(GTK_WIDGET(data->masks_box));
  }
  else
  {
349 350
    gtk_widget_hide(GTK_WIDGET(data->masks_box));
  }
351

352

353
  if(data->blendif_inited && (mask_mode & DEVELOP_MASK_CONDITIONAL))
354 355 356
  {
    gtk_widget_show(GTK_WIDGET(data->blendif_box));
  }
357
  else if(data->blendif_inited)
358
  {
359 360
    /* switch off color picker - only if it was requested by blendif */
    if(data->module->request_color_pick == DT_REQUEST_COLORPICK_BLEND)
Ulrich Pegelow's avatar
Ulrich Pegelow committed
361
    {
362
      data->module->request_color_pick = DT_REQUEST_COLORPICK_OFF;
Ulrich Pegelow's avatar
Ulrich Pegelow committed
363 364 365
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->colorpicker), 0);
    }

366 367
    gtk_widget_hide(GTK_WIDGET(data->blendif_box));
  }
368 369 370 371
  else
  {
    gtk_widget_hide(GTK_WIDGET(data->blendif_box));
  }
372 373 374 375 376

  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}


377
static void _blendop_blend_mode_callback(GtkWidget *combo, dt_iop_gui_blend_data_t *data)
378
{
379 380
  data->module->blend_params->blend_mode = GPOINTER_TO_UINT(
      g_list_nth_data(data->blend_modes, dt_bauhaus_combobox_get(data->blend_modes_combo)));
381 382 383
  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}

384
static void _blendop_masks_combine_callback(GtkWidget *combo, dt_iop_gui_blend_data_t *data)
385
{
386 387 388
  const unsigned combine = GPOINTER_TO_UINT(
      g_list_nth_data(data->masks_combine, dt_bauhaus_combobox_get(data->masks_combine_combo)));
  data->module->blend_params->mask_combine &= ~(DEVELOP_COMBINE_INV | DEVELOP_COMBINE_INCL);
389
  data->module->blend_params->mask_combine |= combine;
390 391
  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}
392

393
static void _blendop_masks_invert_callback(GtkWidget *combo, dt_iop_gui_blend_data_t *data)
394
{
395 396 397 398 399 400 401
  unsigned int invert = GPOINTER_TO_UINT(g_list_nth_data(data->masks_invert,
                                                         dt_bauhaus_combobox_get(data->masks_invert_combo)))
                        & DEVELOP_COMBINE_INV;
  if(invert)
    data->module->blend_params->mask_combine |= DEVELOP_COMBINE_INV;
  else
    data->module->blend_params->mask_combine &= ~DEVELOP_COMBINE_INV;
402 403 404
  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}

405
static void _blendop_opacity_callback(GtkWidget *slider, dt_iop_gui_blend_data_t *data)
406 407
{
  data->module->blend_params->opacity = dt_bauhaus_slider_get(slider);
408 409 410
  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}

411
static void _blendop_blendif_radius_callback(GtkWidget *slider, dt_iop_gui_blend_data_t *data)
412 413 414 415
{
  data->module->blend_params->radius = dt_bauhaus_slider_get(slider);
  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}
416

417
static void _blendop_blendif_upper_callback(GtkDarktableGradientSlider *slider, dt_iop_gui_blend_data_t *data)
418 419 420 421
{
  if(darktable.gui->reset) return;
  dt_develop_blend_params_t *bp = data->module->blend_params;

422 423 424
  int tab = data->tab;
  int ch = data->channels[tab][1];

425
  float *parameters = &(bp->blendif_parameters[4 * ch]);
426

427
  for(int k = 0; k < 4; k++) parameters[k] = dtgtk_gradient_slider_multivalue_get_value(slider, k);
428

429
  for(int k = 0; k < 4; k++)
430 431
  {
    char text[256];
Roman Lebedev's avatar
Roman Lebedev committed
432
    (data->scale_print[tab])(parameters[k], text, sizeof(text));
433 434 435 436 437
    gtk_label_set_text(data->upper_label[k], text);
  }

  /** de-activate processing of this channel if maximum span is selected */
  if(parameters[1] == 0.0f && parameters[2] == 1.0f)
438
    bp->blendif &= ~(1 << ch);
439
  else
440
    bp->blendif |= (1 << ch);
441 442 443 444 445

  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}


446
static void _blendop_blendif_lower_callback(GtkDarktableGradientSlider *slider, dt_iop_gui_blend_data_t *data)
447 448 449 450
{
  if(darktable.gui->reset) return;
  dt_develop_blend_params_t *bp = data->module->blend_params;

451 452 453
  int tab = data->tab;
  int ch = data->channels[tab][0];

454
  float *parameters = &(bp->blendif_parameters[4 * ch]);
455

456
  for(int k = 0; k < 4; k++) parameters[k] = dtgtk_gradient_slider_multivalue_get_value(slider, k);
457

458
  for(int k = 0; k < 4; k++)
459 460
  {
    char text[256];
Roman Lebedev's avatar
Roman Lebedev committed
461
    (data->scale_print[tab])(parameters[k], text, sizeof(text));
462 463 464 465 466
    gtk_label_set_text(data->lower_label[k], text);
  }

  /** de-activate processing of this channel if maximum span is selected */
  if(parameters[1] == 0.0f && parameters[2] == 1.0f)
467
    bp->blendif &= ~(1 << ch);
468
  else
469
    bp->blendif |= (1 << ch);
470 471 472 473 474

  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}


475
static void _blendop_blendif_polarity_callback(GtkToggleButton *togglebutton, dt_iop_gui_blend_data_t *data)
476 477 478 479 480 481 482
{
  int active = gtk_toggle_button_get_active(togglebutton);
  if(darktable.gui->reset) return;
  dt_develop_blend_params_t *bp = data->module->blend_params;

  int tab = data->tab;
  int ch = GTK_WIDGET(togglebutton) == data->lower_polarity ? data->channels[tab][0] : data->channels[tab][1];
483 484
  GtkDarktableGradientSlider *slider = GTK_WIDGET(togglebutton) == data->lower_polarity ? data->lower_slider
                                                                                        : data->upper_slider;
485 486

  if(!active)
487
    bp->blendif |= (1 << (ch + 16));
488
  else
489
    bp->blendif &= ~(1 << (ch + 16));
490

491 492 493 494 495 496 497 498
  dtgtk_gradient_slider_multivalue_set_marker(
      slider, active ? GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG : GRADIENT_SLIDER_MARKER_UPPER_OPEN_BIG, 0);
  dtgtk_gradient_slider_multivalue_set_marker(
      slider, active ? GRADIENT_SLIDER_MARKER_UPPER_FILLED_BIG : GRADIENT_SLIDER_MARKER_LOWER_FILLED_BIG, 1);
  dtgtk_gradient_slider_multivalue_set_marker(
      slider, active ? GRADIENT_SLIDER_MARKER_UPPER_FILLED_BIG : GRADIENT_SLIDER_MARKER_LOWER_FILLED_BIG, 2);
  dtgtk_gradient_slider_multivalue_set_marker(
      slider, active ? GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG : GRADIENT_SLIDER_MARKER_UPPER_OPEN_BIG, 3);
499 500 501 502

  dt_dev_add_history_item(darktable.develop, data->module, TRUE);
}

503

504 505
static void _blendop_blendif_tab_switch(GtkNotebook *notebook, GtkWidget *page, guint page_num,
                                        dt_iop_gui_blend_data_t *data)
506
{
507
  data->tab = page_num;
508 509 510 511
  dt_iop_gui_update_blendif(data->module);
}


512
static void _blendop_blendif_pick_toggled(GtkToggleButton *togglebutton, dt_iop_module_t *module)
Ulrich Pegelow's avatar
Ulrich Pegelow committed
513 514 515
{
  if(darktable.gui->reset) return;

516 517
  /* if module itself already requested color pick don't tamper with it. A module color picker takes
   * precedence. */
518
  if(module->request_color_pick == DT_REQUEST_COLORPICK_MODULE)
Ulrich Pegelow's avatar
Ulrich Pegelow committed
519 520 521 522
  {
    gtk_toggle_button_set_active(togglebutton, 0);
    return;
  }
523

524 525
  module->request_color_pick
      = (gtk_toggle_button_get_active(togglebutton) ? DT_REQUEST_COLORPICK_BLEND : DT_REQUEST_COLORPICK_OFF);
Ulrich Pegelow's avatar
Ulrich Pegelow committed
526 527

  /* set the area sample size */
528
  if(module->request_color_pick != DT_REQUEST_COLORPICK_OFF)
Ulrich Pegelow's avatar
Ulrich Pegelow committed
529
  {
Ulrich Pegelow's avatar
Ulrich Pegelow committed
530
    dt_lib_colorpicker_set_point(darktable.lib, 0.5, 0.5);
Ulrich Pegelow's avatar
Ulrich Pegelow committed
531 532
    dt_dev_reprocess_all(module->dev);
  }
533 534
  else
    dt_control_queue_redraw();
535

Ulrich Pegelow's avatar
Ulrich Pegelow committed
536 537 538 539
  if(module->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->off), 1);
  dt_iop_request_focus(module);
}

540
static void _blendop_blendif_showmask_clicked(GtkWidget *button, GdkEventButton *event, dt_iop_module_t *module)
541 542 543
{
  if(darktable.gui->reset) return;

544 545 546 547 548 549
  if(event->button == 1)
  {
    const int has_mask_display = module->request_mask_display & (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL);

    module->request_mask_display &= ~(DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL | DT_DEV_PIXELPIPE_DISPLAY_ANY);

550
    GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask();
551
    if((event->state & modifiers) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
552
      module->request_mask_display |= (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL);
553
    else if((event->state & modifiers) == GDK_SHIFT_MASK)
554
      module->request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_CHANNEL;
555
    else if((event->state & modifiers) == GDK_CONTROL_MASK)
556 557 558 559
      module->request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_MASK;
    else
      module->request_mask_display |= (has_mask_display ? 0 : DT_DEV_PIXELPIPE_DISPLAY_MASK);

560
    if(module->request_mask_display & (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL))
561
      dtgtk_button_set_active(DTGTK_BUTTON(button), 1);
562
    else
563
      dtgtk_button_set_active(DTGTK_BUTTON(button), 0);
564 565


566 567 568 569 570
    if(module->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->off), 1);

    dt_iop_request_focus(module);
    dt_dev_reprocess_all(module->dev);
  }
571
}
Ulrich Pegelow's avatar
Ulrich Pegelow committed
572

573
static void _blendop_blendif_suppress_toggled(GtkToggleButton *togglebutton, dt_iop_module_t *module)
574 575 576 577 578 579 580
{
  module->suppress_mask = gtk_toggle_button_get_active(togglebutton);
  if(darktable.gui->reset) return;

  if(module->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->off), 1);
  dt_iop_request_focus(module);

581
  dt_dev_reprocess_all(module->dev);
582 583
}

584
static void _blendop_blendif_reset(GtkButton *button, dt_iop_module_t *module)
585
{
586
  module->blend_params->blendif = module->default_blendop_params->blendif;
587 588
  memcpy(module->blend_params->blendif_parameters, module->default_blendop_params->blendif_parameters,
         4 * DEVELOP_BLENDIF_SIZE * sizeof(float));
589 590 591 592 593

  dt_iop_gui_update_blendif(module);
  dt_dev_add_history_item(darktable.develop, module, TRUE);
}

594
static void _blendop_blendif_invert(GtkButton *button, dt_iop_module_t *module)
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
{
  if(darktable.gui->reset) return;

  dt_iop_gui_blend_data_t *data = module->blend_data;

  unsigned int toggle_mask = 0;

  switch(data->csp)
  {
    case iop_cs_Lab:
      toggle_mask = DEVELOP_BLENDIF_Lab_MASK << 16;
      break;

    case iop_cs_rgb:
      toggle_mask = DEVELOP_BLENDIF_RGB_MASK << 16;
      break;

    case iop_cs_RAW:
      toggle_mask = 0;
      break;
  }

  module->blend_params->blendif ^= toggle_mask;
618
  module->blend_params->mask_combine ^= DEVELOP_COMBINE_MASKS_POS;
619 620 621 622 623
  module->blend_params->mask_combine ^= DEVELOP_COMBINE_INCL;
  dt_iop_gui_update_blending(module);
  dt_dev_add_history_item(darktable.develop, module, TRUE);
}

624
static int _blendop_masks_add_path(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
625
{
626
  if(darktable.gui->reset) return FALSE;
627 628
  dt_iop_gui_blend_data_t *bd = (dt_iop_gui_blend_data_t *)self->blend_data;

629
  if(event->button == 1)
630
  {
631
    // we want to be sure that the iop has focus
632
    dt_iop_request_focus(self);
633
    self->request_color_pick = DT_REQUEST_COLORPICK_OFF;
634 635
    bd->masks_shown = DT_MASKS_EDIT_FULL;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->masks_edit), TRUE);
636
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
637
    // we create the new form
638 639 640 641 642 643 644 645 646
    dt_masks_form_t *form = dt_masks_create(DT_MASKS_PATH);
    dt_masks_change_form_gui(form);
    darktable.develop->form_gui->creation = TRUE;
    darktable.develop->form_gui->creation_module = self;
    dt_control_queue_redraw_center();
    return TRUE;
  }

  return FALSE;
647 648
}

649
static int _blendop_masks_add_circle(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
650
{
651
  if(darktable.gui->reset) return FALSE;
652 653
  dt_iop_gui_blend_data_t *bd = (dt_iop_gui_blend_data_t *)self->blend_data;

654
  if(event->button == 1)
655
  {
656
    // we want to be sure that the iop has focus
657
    dt_iop_request_focus(self);
658
    self->request_color_pick = DT_REQUEST_COLORPICK_OFF;
659 660
    bd->masks_shown = DT_MASKS_EDIT_FULL;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->masks_edit), TRUE);
661
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
662
    // we create the new form
663 664 665 666 667 668 669 670 671
    dt_masks_form_t *spot = dt_masks_create(DT_MASKS_CIRCLE);
    dt_masks_change_form_gui(spot);
    darktable.develop->form_gui->creation = TRUE;
    darktable.develop->form_gui->creation_module = self;
    dt_control_queue_redraw_center();
    return TRUE;
  }

  return FALSE;
672
}
Ulrich Pegelow's avatar
Ulrich Pegelow committed
673

674
static int _blendop_masks_add_ellipse(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
675 676 677 678
{
  if(darktable.gui->reset) return FALSE;
  dt_iop_gui_blend_data_t *bd = (dt_iop_gui_blend_data_t *)self->blend_data;

679
  if(event->button == 1)
680
  {
681
    // we want to be sure that the iop has focus
682
    dt_iop_request_focus(self);
683
    self->request_color_pick = DT_REQUEST_COLORPICK_OFF;
684 685
    bd->masks_shown = DT_MASKS_EDIT_FULL;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->masks_edit), TRUE);
686
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
687
    // we create the new form
688 689 690 691 692 693 694 695 696 697 698
    dt_masks_form_t *spot = dt_masks_create(DT_MASKS_ELLIPSE);
    dt_masks_change_form_gui(spot);
    darktable.develop->form_gui->creation = TRUE;
    darktable.develop->form_gui->creation_module = self;
    dt_control_queue_redraw_center();
    return TRUE;
  }

  return FALSE;
}

699
static int _blendop_masks_add_brush(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
Ulrich Pegelow's avatar
Ulrich Pegelow committed
700 701 702 703
{
  if(darktable.gui->reset) return FALSE;
  dt_iop_gui_blend_data_t *bd = (dt_iop_gui_blend_data_t *)self->blend_data;

704
  if(event->button == 1)
Ulrich Pegelow's avatar
Ulrich Pegelow committed
705
  {
706
    // we want to be sure that the iop has focus
Ulrich Pegelow's avatar
Ulrich Pegelow committed
707
    dt_iop_request_focus(self);
708
    self->request_color_pick = DT_REQUEST_COLORPICK_OFF;
Ulrich Pegelow's avatar
Ulrich Pegelow committed
709 710
    bd->masks_shown = DT_MASKS_EDIT_FULL;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->masks_edit), TRUE);
711
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
712
    // we create the new form
Ulrich Pegelow's avatar
Ulrich Pegelow committed
713 714 715 716 717 718 719 720 721 722 723
    dt_masks_form_t *form = dt_masks_create(DT_MASKS_BRUSH);
    dt_masks_change_form_gui(form);
    darktable.develop->form_gui->creation = TRUE;
    darktable.develop->form_gui->creation_module = self;
    dt_control_queue_redraw_center();
    return TRUE;
  }

  return FALSE;
}

724
static int _blendop_masks_add_gradient(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
725 726 727 728
{
  if(darktable.gui->reset) return FALSE;
  dt_iop_gui_blend_data_t *bd = (dt_iop_gui_blend_data_t *)self->blend_data;

729
  if(event->button == 1)
730
  {
731
    // we want to be sure that the iop has focus
732
    dt_iop_request_focus(self);
733
    self->request_color_pick = DT_REQUEST_COLORPICK_OFF;
734 735
    bd->masks_shown = DT_MASKS_EDIT_FULL;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->masks_edit), TRUE);
736
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
737
    // we create the new form
738 739 740 741 742 743 744 745 746 747 748 749
    dt_masks_form_t *spot = dt_masks_create(DT_MASKS_GRADIENT);
    dt_masks_change_form_gui(spot);
    darktable.develop->form_gui->creation = TRUE;
    darktable.develop->form_gui->creation_module = self;
    dt_control_queue_redraw_center();
    return TRUE;
  }

  return FALSE;
}


750
static int _blendop_masks_show_and_edit(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
751
{
752
  if(darktable.gui->reset) return FALSE;
753 754
  dt_iop_gui_blend_data_t *bd = (dt_iop_gui_blend_data_t *)self->blend_data;

755
  if(event->button == 1)
756 757
  {
    darktable.gui->reset = 1;
758

759
    dt_iop_request_focus(self);
760
    self->request_color_pick = DT_REQUEST_COLORPICK_OFF;
761

762
    dt_masks_form_t *grp = dt_masks_get_from_id(darktable.develop, self->blend_params->mask_id);
763
    if(grp && (grp->type & DT_MASKS_GROUP) && g_list_length(grp->points) > 0)
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
    {
      const int control_button_pressed = event->state & GDK_CONTROL_MASK;

      switch(bd->masks_shown)
      {
        case DT_MASKS_EDIT_FULL:
          bd->masks_shown = control_button_pressed ? DT_MASKS_EDIT_RESTRICTED : DT_MASKS_EDIT_OFF;
          break;

        case DT_MASKS_EDIT_RESTRICTED:
          bd->masks_shown = !control_button_pressed ? DT_MASKS_EDIT_FULL : DT_MASKS_EDIT_OFF;
          break;

        default:
        case DT_MASKS_EDIT_OFF:
          bd->masks_shown = control_button_pressed ? DT_MASKS_EDIT_RESTRICTED : DT_MASKS_EDIT_FULL;
      }
    }
    else
      bd->masks_shown = DT_MASKS_EDIT_OFF;
784

785 786
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->masks_edit), bd->masks_shown != DT_MASKS_EDIT_OFF);
    dt_masks_set_edit_mode(self, bd->masks_shown);
787

788 789 790 791 792 793
    darktable.gui->reset = 0;

    return TRUE;
  }

  return FALSE;
794 795
}

796
static void _blendop_masks_polarity_callback(GtkToggleButton *togglebutton, dt_iop_module_t *self)
797 798 799 800 801 802 803 804 805 806 807 808 809
{
  if(darktable.gui->reset) return;

  int active = gtk_toggle_button_get_active(togglebutton);
  dt_develop_blend_params_t *bp = (dt_develop_blend_params_t *)self->blend_params;

  if(active)
    bp->mask_combine |= DEVELOP_COMBINE_MASKS_POS;
  else
    bp->mask_combine &= ~DEVELOP_COMBINE_MASKS_POS;

  dt_dev_add_history_item(darktable.develop, self, TRUE);
}
810

811
static gboolean _blendop_blendif_draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *module)
Ulrich Pegelow's avatar
Ulrich Pegelow committed
812 813 814 815 816
{
  if(darktable.gui->reset) return FALSE;

  dt_iop_gui_blend_data_t *data = module->blend_data;

817 818
  float picker_mean[8], picker_min[8], picker_max[8];
  float cooked[8];
819
  float *raw_mean, *raw_min, *raw_max;
820 821
  char text[256];
  GtkLabel *label;
Ulrich Pegelow's avatar
Ulrich Pegelow committed
822 823

  if(widget == GTK_WIDGET(data->lower_slider))
824
  {
825 826 827
    raw_mean = module->picked_color;
    raw_min = module->picked_color_min;
    raw_max = module->picked_color_max;
828 829
    label = data->lower_picker_label;
  }
Ulrich Pegelow's avatar
Ulrich Pegelow committed
830
  else
831
  {
832 833 834
    raw_mean = module->picked_output_color;
    raw_min = module->picked_output_color_min;
    raw_max = module->picked_output_color_max;
835 836
    label = data->upper_picker_label;
  }
Ulrich Pegelow's avatar
Ulrich Pegelow committed
837 838

  darktable.gui->reset = 1;
839
  if((module->request_color_pick == DT_REQUEST_COLORPICK_BLEND) && (raw_min[0] != INFINITY))
Ulrich Pegelow's avatar
Ulrich Pegelow committed
840
  {
841 842 843 844
    _blendif_scale(data->csp, raw_mean, picker_mean);
    _blendif_scale(data->csp, raw_min, picker_min);
    _blendif_scale(data->csp, raw_max, picker_max);
    _blendif_cook(data->csp, raw_mean, cooked);
845

846 847 848
    if(data->channels[data->tab][0] >= 8) // min and max make no sense for HSL and LCh
      picker_min[data->tab] = picker_max[data->tab] = picker_mean[data->tab];

849
    snprintf(text, sizeof(text), "(%.1f)", cooked[data->tab]);
Ulrich Pegelow's avatar
Ulrich Pegelow committed
850

851 852
    dtgtk_gradient_slider_multivalue_set_picker_meanminmax(
        DTGTK_GRADIENT_SLIDER(widget), picker_mean[data->tab], picker_min[data->tab], picker_max[data->tab]);
853
    gtk_label_set_text(label, text);
Ulrich Pegelow's avatar
Ulrich Pegelow committed
854 855 856
  }
  else
  {
857
    dtgtk_gradient_slider_multivalue_set_picker(DTGTK_GRADIENT_SLIDER(widget), NAN);
858
    gtk_label_set_text(label, "");
Ulrich Pegelow's avatar
Ulrich Pegelow committed
859
  }
Ulrich Pegelow's avatar
Ulrich Pegelow committed
860

861 862
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->colorpicker),
                               (module->request_color_pick == DT_REQUEST_COLORPICK_BLEND ? 1 : 0));
Ulrich Pegelow's avatar
Ulrich Pegelow committed
863

Ulrich Pegelow's avatar
Ulrich Pegelow committed
864 865 866 867 868
  darktable.gui->reset = 0;

  return FALSE;
}

869 870
// magic mode: if mouse curser enters a gradient slider with shift and/or control pressed we
// enter channel display and/or mask display mode
871 872 873
static gboolean _blendop_blendif_enter(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *module)
{
  if(darktable.gui->reset) return FALSE;
874 875
  dt_iop_gui_blend_data_t *data = module->blend_data;

876
  dt_pthread_mutex_lock(&data->lock);
877 878 879 880 881 882 883 884 885 886 887
  if(data->timeout_handle)
  {
    // purge any remaining timeout handlers
    g_source_remove(data->timeout_handle);
    data->timeout_handle = 0;
  }
  else
  {
    // save request_mask_display to restore later
    data->save_for_leave = module->request_mask_display;
  }
888
  dt_pthread_mutex_unlock(&data->lock);
889

890
  dt_dev_pixelpipe_display_mask_t new_request_mask_display = module->request_mask_display;
891

892 893 894 895 896 897 898 899 900 901 902 903 904 905
  // depending on shift modifiers we activate channel and/or mask display
  GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask();
  if((event->state & modifiers) == (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
  {
    new_request_mask_display |= (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL);
  }
  else if((event->state & modifiers) == GDK_SHIFT_MASK)
  {
    new_request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_CHANNEL;
  }
  else if((event->state & modifiers) == GDK_CONTROL_MASK)
  {
    new_request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_MASK;
  }
906

907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
  // in case user requests channel display: get the cannel
  if(new_request_mask_display & DT_DEV_PIXELPIPE_DISPLAY_CHANNEL)
  {
    int tab = data->tab;
    int inout = (widget == GTK_WIDGET(data->lower_slider)) ? 0 : 1;
    dt_dev_pixelpipe_display_mask_t channel = data->display_channel[tab][inout];

    new_request_mask_display &= ~DT_DEV_PIXELPIPE_DISPLAY_ANY;
    new_request_mask_display |= channel;
  }

  // only if something has changed: reprocess center view
  if(new_request_mask_display != module->request_mask_display)
  {
    module->request_mask_display = new_request_mask_display;
    dt_dev_reprocess_all(module->dev);
  }
924 925 926 927

  return TRUE;
}

928 929 930 931 932 933
// handler for delayed mask/channel display mode switch-off
static gboolean _blendop_blendif_leave_delayed(gpointer data)
{
  dt_iop_module_t *module = (dt_iop_module_t *)data;
  dt_iop_gui_blend_data_t *bd = module->blend_data;

934
  dt_pthread_mutex_lock(&bd->lock);
935
  // restore saved request_mask_display and reprocess image
936
  if(bd->timeout_handle && (module->request_mask_display != bd->save_for_leave))
937 938 939 940 941 942
  {
    module->request_mask_display = bd->save_for_leave;
    dt_dev_reprocess_all(module->dev);
  }

  bd->timeout_handle = 0;
943
  dt_pthread_mutex_unlock(&bd->lock);
944 945 946 947 948 949

  // return FALSE and thereby terminate the handler
  return FALSE;
}

// de-activate magic mode when leaving the gradient slider
950 951 952
static gboolean _blendop_blendif_leave(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *module)
{
  if(darktable.gui->reset) return FALSE;
953
  dt_iop_gui_blend_data_t *data = module->blend_data;
954

955
  if(module->request_mask_display & (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL))
956 957 958
  {
    // do not immediately switch-off mask/channel display in case user leaves gradient only briefly.
    // instead we activate a handler function that gets triggered after some timeout
959 960
    dt_pthread_mutex_lock(&data->lock);
    if(!data->timeout_handle && (module->request_mask_display != data->save_for_leave))
961
      data->timeout_handle = g_timeout_add(1000, _blendop_blendif_leave_delayed, module);
962
    dt_pthread_mutex_unlock(&data->lock);
963
  }
964 965 966 967

  return TRUE;
}

Ulrich Pegelow's avatar
Ulrich Pegelow committed
968

969
void dt_iop_gui_update_blendif(dt_iop_module_t *module)
970 971 972
{
  dt_iop_gui_blend_data_t *data = module->blend_data;
  dt_develop_blend_params_t *bp = module->blend_params;
973
  dt_develop_blend_params_t *dp = module->default_blendop_params;
974

975
  if(!data || !data->blendif_support || !data->blendif_inited) return;
976

977
  dt_pthread_mutex_lock(&data->lock);
978 979 980 981
  if(data->timeout_handle)
  {
    g_source_remove(data->timeout_handle);
    data->timeout_handle = 0;
982 983 984 985 986
    if(module->request_mask_display != data->save_for_leave)
    {
      module->request_mask_display = data->save_for_leave;
      dt_dev_reprocess_all(module->dev);
    }
987
  }
988
  dt_pthread_mutex_unlock(&data->lock);
989

990 991 992 993
  int tab = data->tab;
  int in_ch = data->channels[tab][0];
  int out_ch = data->channels[tab][1];

994 995 996 997
  float *iparameters = &(bp->blendif_parameters[4 * in_ch]);
  float *oparameters = &(bp->blendif_parameters[4 * out_ch]);
  float *idefaults = &(dp->blendif_parameters[4 * in_ch]);
  float *odefaults = &(dp->blendif_parameters[4 * out_ch]);
998

999 1000
  int ipolarity = !(bp->blendif & (1 << (in_ch + 16)));
  int opolarity = !(bp->blendif & (1 << (out_ch + 16)));
1001 1002 1003 1004 1005
  char text[256];

  int reset = darktable.gui->reset;
  darktable.gui->reset = 1;

1006 1007 1008
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->lower_polarity), ipolarity);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->upper_polarity), opolarity);

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
  dtgtk_gradient_slider_multivalue_set_marker(
      data->lower_slider,
      ipolarity ? GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG : GRADIENT_SLIDER_MARKER_UPPER_OPEN_BIG, 0);
  dtgtk_gradient_slider_multivalue_set_marker(
      data->lower_slider,
      ipolarity ? GRADIENT_SLIDER_MARKER_UPPER_FILLED_BIG : GRADIENT_SLIDER_MARKER_LOWER_FILLED_BIG, 1);
  dtgtk_gradient_slider_multivalue_set_marker(
      data->lower_slider,
      ipolarity ? GRADIENT_SLIDER_MARKER_UPPER_FILLED_BIG : GRADIENT_SLIDER_MARKER_LOWER_FILLED_BIG, 2);
  dtgtk_gradient_slider_multivalue_set_marker(
      data->lower_slider,
      ipolarity ? GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG : GRADIENT_SLIDER_MARKER_UPPER_OPEN_BIG, 3);

  dtgtk_gradient_slider_multivalue_set_marker(
      data->upper_slider,
      opolarity ? GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG : GRADIENT_SLIDER_MARKER_UPPER_OPEN_BIG, 0);
  dtgtk_gradient_slider_multivalue_set_marker(
      data->upper_slider,
      opolarity ? GRADIENT_SLIDER_MARKER_UPPER_FILLED_BIG : GRADIENT_SLIDER_MARKER_LOWER_FILLED_BIG, 1);
  dtgtk_gradient_slider_multivalue_set_marker(
      data->upper_slider,
      opolarity ? GRADIENT_SLIDER_MARKER_UPPER_FILLED_BIG : GRADIENT_SLIDER_MARKER_LOWER_FILLED_BIG, 2);
  dtgtk_gradient_slider_multivalue_set_marker(
      data->upper_slider,
      opolarity ? GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG : GRADIENT_SLIDER_MARKER_UPPER_OPEN_BIG, 3);

  for(int k = 0; k < 4; k++)
1036 1037 1038
  {
    dtgtk_gradient_slider_multivalue_set_value(data->lower_slider, iparameters[k], k);
    dtgtk_gradient_slider_multivalue_set_value(data->upper_slider, oparameters[k], k);
1039 1040
    dtgtk_gradient_slider_multivalue_set_resetvalue(data->lower_slider, idefaults[k], k);
    dtgtk_gradient_slider_multivalue_set_resetvalue(data->upper_slider, odefaults[k], k);
1041 1042
  }

1043
  for(int k = 0; k < 4; k++)
1044
  {
Roman Lebedev's avatar
Roman Lebedev committed
1045
    (data->scale_print[tab])(iparameters[k], text, sizeof(text));
1046
    gtk_label_set_text(data->lower_label[k], text);
Roman Lebedev's avatar
Roman Lebedev committed
1047
    (data->scale_print[tab])(oparameters[k], text, sizeof(text));
1048 1049 1050
    gtk_label_set_text(data->upper_label[k], text);
  }

1051 1052
  dtgtk_gradient_slider_multivalue_clear_stops(data->lower_slider);
  dtgtk_gradient_slider_multivalue_clear_stops(data->upper_slider);
1053

1054
  for(int k = 0; k < data->numberstops[tab]; k++)
1055 1056
  {
    dtgtk_gradient_slider_multivalue_set_stop(data->lower_slider, (data->colorstops[tab])[k].stoppoint,
1057
                                              (data->colorstops[tab])[k].color);
1058
    dtgtk_gradient_slider_multivalue_set_stop(data->upper_slider, (data->colorstops[tab])[k].stoppoint,
1059
                                              (data->colorstops[tab])[k].color);
1060
  }
1061

1062 1063
  dtgtk_gradient_slider_multivalue_set_increment(data->lower_slider, data->increments[tab]);
  dtgtk_gradient_slider_multivalue_set_increment(data->upper_slider, data->increments[tab]);
1064

1065 1066 1067 1068
  darktable.gui->reset = reset;
}


1069
void dt_iop_gui_init_blendif(GtkBox *blendw, dt_iop_module_t *module)
1070
{
1071
  dt_iop_gui_blend_data_t *bd = (dt_iop_gui_blend_data_t *)module->blend_data;
1072

1073
  bd->blendif_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_BAUHAUS_SPACE));
1074

1075
  /* create and add blendif support if module supports it */
1076
  if(bd->blendif_support)
1077
  {
1078
    char *Lab_labels[] = { "  L  ", "  a  ", "  b  ", " C ", " h " };
1079 1080 1081
    char *Lab_tooltips[]
        = { _("sliders for L channel"), _("sliders for a channel"), _("sliders for b channel"),
            _("sliders for chroma channel (of LCh)"), _("sliders for hue channel (of LCh)") };
1082
    char *rgb_labels[] = { _(" g "), _(" R "), _(" G "), _(" B "), _(" H "), _(" S "), _(" L ") };
1083 1084 1085 1086
    char *rgb_tooltips[]
        = { _("sliders for gray value"), _("sliders for red channel"), _("sliders for green channel"),
            _("sliders for blue channel"), _("sliders for hue channel (of HSL)"),
            _("sliders for chroma channel (of HSL)"), _("sliders for value channel (of HSL)") };
1087

1088 1089 1090
    char *ttinput = _("adjustment based on input received by this module:\n* range defined by upper markers: "
                      "blend fully\n* range defined by lower markers: do not blend at all\n* range between "
                      "adjacent upper/lower markers: blend gradually");
1091

1092 1093 1094
    char *ttoutput = _("adjustment based on unblended output of this module:\n* range defined by upper "
                       "markers: blend fully\n* range defined by lower markers: do not blend at all\n* range "
                       "between adjacent upper/lower markers: blend gradually");
1095

1096
    bd->tab = 0;
1097
    const int bs = DT_PIXEL_APPLY_DPI(14);
1098 1099 1100 1101 1102 1103 1104 1105

    int maxchannels = 0;
    char **labels = NULL;
    char **tooltips = NULL;

    switch(bd->csp)
    {
      case iop_cs_Lab:
1106
        maxchannels = 5;
1107 1108 1109 1110 1111
        labels = Lab_labels;
        tooltips = Lab_tooltips;
        bd->scale_print[0] = _blendif_scale_print_L;
        bd->scale_print[1] = _blendif_scale_print_ab;
        bd->scale_print[2] = _blendif_scale_print_ab;
1112
        bd->scale_print[3] = _blendif_scale_print_default;
1113
        bd->scale_print[4] = _blendif_scale_print_hue;
1114 1115 1116 1117 1118
        bd->increments[0] = 1.0f / 100.0f;
        bd->increments[1] = 1.0f / 256.0f;
        bd->increments[2] = 1.0f / 256.0f;
        bd->increments[3] = 1.0f / 100.0f;
        bd->increments[4] = 1.0f / 360.0f;
1119 1120 1121 1122 1123 1124
        bd->channels[0][0] = DEVELOP_BLENDIF_L_in;
        bd->channels[0][1] = DEVELOP_BLENDIF_L_out;
        bd->channels[1][0] = DEVELOP_BLENDIF_A_in;
        bd->channels[1][1] = DEVELOP_BLENDIF_A_out;
        bd->channels[2][0] = DEVELOP_BLENDIF_B_in;
        bd->channels[2][1] = DEVELOP_BLENDIF_B_out;</