Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageop.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2014 johannes hanika.
4 Copyright (C) 2010-2011 Bruce Guenter.
5 Copyright (C) 2010-2012 Henrik Andersson.
6 Copyright (C) 2010 Stuart Henderson.
7 Copyright (C) 2011 Antony Dovgal.
8 Copyright (C) 2011 Brian Teague.
9 Copyright (C) 2011-2012 Jérémy Rosen.
10 Copyright (C) 2011 Robert Bieber.
11 Copyright (C) 2011 Rostyslav Pidgornyi.
12 Copyright (C) 2011-2020 Tobias Ellinghaus.
13 Copyright (C) 2011-2015, 2017, 2019 Ulrich Pegelow.
14 Copyright (C) 2012-2014, 2019-2022 Aldric Renaudin.
15 Copyright (C) 2012 Edouard Gomez.
16 Copyright (C) 2012-2013, 2015, 2018, 2020 parafin.
17 Copyright (C) 2012-2013, 2018-2022 Pascal Obry.
18 Copyright (C) 2012 Richard Wonka.
19 Copyright (C) 2013-2016 Roman Lebedev.
20 Copyright (C) 2013 Simon Spannagel.
21 Copyright (C) 2013 Thomas Pryds.
22 Copyright (C) 2014, 2017, 2021 Dan Torop.
23 Copyright (C) 2014 Mikhail Trishchenkov.
24 Copyright (C) 2014-2016 Pedro Côrte-Real.
25 Copyright (C) 2017 Dominik Markiewicz.
26 Copyright (C) 2017-2019 Edgardo Hoszowski.
27 Copyright (C) 2017-2020 Heiko Bauke.
28 Copyright (C) 2017 Peter Budai.
29 Copyright (C) 2018 Matthieu Moy.
30 Copyright (C) 2018 rawfiner.
31 Copyright (C) 2019-2026 Aurélien PIERRE.
32 Copyright (C) 2019-2022 Diederik Ter Rahe.
33 Copyright (C) 2019 Jacques Le Clerc.
34 Copyright (C) 2020-2022 Chris Elston.
35 Copyright (C) 2020-2022 Hanno Schwalm.
36 Copyright (C) 2020 Harold le Clément de Saint-Marcq.
37 Copyright (C) 2020-2021 Hubert Kowalski.
38 Copyright (C) 2020-2021 Marco.
39 Copyright (C) 2020 Philippe Weyland.
40 Copyright (C) 2020-2021 Ralf Brown.
41 Copyright (C) 2021 Mark-64.
42 Copyright (C) 2021-2022 Philipp Lutz.
43 Copyright (C) 2021 Sakari Kapanen.
44 Copyright (C) 2022 Martin Bařinka.
45 Copyright (C) 2022 Miloš Komarčević.
46 Copyright (C) 2022 Nicolas Auffray.
47 Copyright (C) 2023 Alynx Zhou.
48 Copyright (C) 2023 Luca Zulberti.
49 Copyright (C) 2025-2026 Guillaume Stutin.
50 Copyright (C) 2025 Miguel Moquillon.
51
52 darktable is free software: you can redistribute it and/or modify
53 it under the terms of the GNU General Public License as published by
54 the Free Software Foundation, either version 3 of the License, or
55 (at your option) any later version.
56
57 darktable is distributed in the hope that it will be useful,
58 but WITHOUT ANY WARRANTY; without even the implied warranty of
59 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60 GNU General Public License for more details.
61
62 You should have received a copy of the GNU General Public License
63 along with darktable. If not, see <http://www.gnu.org/licenses/>.
64*/
65
66#include "common/darktable.h"
67#include "common/sentry.h"
68#include "common/telemetry.h"
69#include "develop/imageop.h"
70#include "bauhaus/bauhaus.h"
71#include "common/collection.h"
72#include "common/debug.h"
73#include "common/exif.h"
74#include "common/history.h"
75#include "common/imagebuf.h"
78#include "common/module.h"
79#include "common/opencl.h"
81#include "control/control.h"
82#include "control/signal.h"
83#include "develop/blend.h"
84#include "develop/develop.h"
85#include "develop/format.h"
86#include "develop/masks.h"
87#include "develop/tiling.h"
88#include "gui/gdkkeys.h"
89#include "gui/presets.h"
90#include "dtgtk/button.h"
91#include "dtgtk/expander.h"
93#include "dtgtk/icon.h"
94
96#include "gui/gtk.h"
97#include "gui/gui_throttle.h"
98#include "gui/presets.h"
99#ifdef GDK_WINDOWING_QUARTZ
100#include "osx/osx.h"
101#endif
102
103#include <assert.h>
104#include <gmodule.h>
105#include <math.h>
106#include <complex.h>
107#include <stdlib.h>
108
109static sqlite3_stmt *_iop_presets_select_stmt = NULL;
110#include <string.h>
111#include <strings.h>
112#include <time.h>
113
114#define DT_IOP_HEADER_MENU_OPEN "dt-module-header-menu-open"
115#define DT_IOP_HEADER_MENU_DISMISS_CLICK "dt-module-header-menu-dismiss-click"
116#define DT_IOP_HEADER_IGNORE_RELEASE "dt-module-header-ignore-release"
117
123
124static gboolean _iop_plugin_focus_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval,
125 GdkModifierType modifier, gpointer data);
126static gboolean _iop_plugin_enable_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval,
127 GdkModifierType modifier, gpointer data);
128static gboolean _iop_plugin_header_button_release(GtkWidget *w, GdkEventButton *e, gpointer user_data);
129static void _gui_set_single_expanded(dt_iop_module_t *module, gboolean expanded);
130
131float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
132{
133 return pipe->iscale / roi_in->scale;
134}
135
136
146
147static void _iop_modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
148 struct dt_dev_pixelpipe_iop_t *piece,
149 const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
150{
151 *roi_in = *roi_out;
152}
153
154static void _iop_modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
155 struct dt_dev_pixelpipe_iop_t *piece,
156 dt_iop_roi_t *roi_out, const dt_iop_roi_t *roi_in)
157{
158 *roi_out = *roi_in;
159}
160
161/* default group for modules which do not implement the default_group() function */
162static int default_default_group(void)
163{
164 return IOP_GROUP_TECHNICAL;
165}
166
167/* default flags for modules which does not implement the flags() function */
168static int default_flags(void)
169{
170 return 0;
171}
172
173/* default operation tags for modules which does not implement the flags() function */
175{
176 return 0;
177}
178
179/* default operation tags filter for modules which does not implement the flags() function */
181{
182 return 0;
183}
184
185static const char **default_description(struct dt_iop_module_t *self)
186{
187 return NULL;
188}
189
190static const char *default_aliases(void)
191{
192 return "";
193}
194
195static const char *default_deprecated_msg(void)
196{
197 return NULL;
198}
199
200static gboolean default_has_defaults(struct dt_iop_module_t *self)
201{
202 return memcmp(self->params, self->default_params, self->params_size) == 0;
203}
204
206 const dt_dev_pixelpipe_iop_t *piece)
207{
208 (void)self;
209 (void)pipe;
210 (void)piece;
211 return FALSE;
212}
213
214static void default_commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params,
216{
217 memcpy(piece->data, params, self->params_size);
218}
219
220// WARNING: this works only if the data struct has the same size
221// as the param structure. You need to implement your own IOP module
222// method if they don't match !!!
225{
226 size_t data_size = (size_t)self->params_size;
227 piece->data = dt_calloc_align(data_size);
228 piece->data_size = data_size;
229}
230
233{
234 dt_free_align(piece->data);
235 piece->data = NULL;
236}
237
239{
241}
242
244{
245 dt_free(module->params);
246 dt_free(module->default_params);
247}
248
249static void _iop_color_picker_data_ready_callback(gpointer instance, gpointer user_data)
250{
251 dt_iop_module_t *const module = user_data;
252 GtkWidget *picker = NULL;
253 dt_dev_pixelpipe_t *pipe = NULL;
254 const dt_dev_pixelpipe_iop_t *piece = NULL;
255 if(IS_NULL_PTR(module) || IS_NULL_PTR(module->color_picker_apply)) return;
256 if(dt_iop_color_picker_get_ready_data(module, &picker, &pipe, &piece)) return;
257
258 dt_print(DT_DEBUG_DEV, "[picker] dispatch module=%s picker=%p pipe=%p hash=%" PRIu64 "\n",
259 module->op, (void *)picker, (void *)pipe, piece ? piece->global_hash : 0);
260
261 if(!module->blend_data || !blend_color_picker_apply(module, picker, pipe, (dt_dev_pixelpipe_iop_t *)piece))
262 module->color_picker_apply(module, picker, pipe, (dt_dev_pixelpipe_iop_t *)piece);
263}
264
265
267 const dt_dev_pixelpipe_iop_t *piece, float *points,
268 size_t points_count)
269{
270 (void)self;
271 (void)pipe;
272 (void)piece;
273 (void)points;
274 (void)points_count;
275 return 1;
276}
278 const dt_dev_pixelpipe_iop_t *piece, float *points,
279 size_t points_count)
280{
281 (void)self;
282 (void)pipe;
283 (void)piece;
284 (void)points;
285 (void)points_count;
286 return 1;
287}
288
289static int default_process(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
290 const struct dt_dev_pixelpipe_iop_t *piece,
291 const void *const i, void *const o)
292{
293 const struct dt_iop_roi_t *const roi_in = &piece->roi_in;
294 const struct dt_iop_roi_t *const roi_out = &piece->roi_out;
295 if(roi_in->width <= 1 || roi_in->height <= 1 || roi_out->width <= 1 || roi_out->height <= 1) return 0;
296 return self->process_plain(self, pipe, piece, i, o);
297}
298
304{
305 return NULL;
306}
307static void *default_get_p(const void *param, const char *name)
308{
309 return NULL;
310}
312{
313 return NULL;
314}
315
317{
318 size_t param_size = module->so->get_introspection()->size;
319 module->params_size = param_size;
320 /* Keep ownership explicit: if init is re-entered on the same instance,
321 * release previous params before rebuilding defaults from introspection. */
322 if(!IS_NULL_PTR(module->params))
323 {
324 dt_free(module->params);
325 module->params = NULL;
326 }
327 if(!IS_NULL_PTR(module->default_params))
328 {
329 dt_free(module->default_params);
330 module->default_params = NULL;
331 }
332 module->params = (dt_iop_params_t *)calloc(1, param_size);
333 module->default_params = (dt_iop_params_t *)calloc(1, param_size);
334
335 module->default_enabled = 0;
336 module->gui_data = NULL;
337
338 dt_introspection_field_t *i = module->so->get_introspection_linear();
339 while(i->header.type != DT_INTROSPECTION_TYPE_NONE)
340 {
341 switch(i->header.type)
342 {
344 *(float*)((uint8_t *)module->default_params + i->header.offset) = i->Float.Default;
345 break;
347 *(int*)((uint8_t *)module->default_params + i->header.offset) = i->Int.Default;
348 break;
350 *(unsigned int*)((uint8_t *)module->default_params + i->header.offset) = i->UInt.Default;
351 break;
353 *(unsigned short*)((uint8_t *)module->default_params + i->header.offset) = i->UShort.Default;
354 break;
356 *(int*)((uint8_t *)module->default_params + i->header.offset) = i->Enum.Default;
357 break;
359 *(gboolean*)((uint8_t *)module->default_params + i->header.offset) = i->Bool.Default;
360 break;
362 *(char*)((uint8_t *)module->default_params + i->header.offset) = i->Char.Default;
363 break;
365 memset((uint8_t *)module->default_params + i->header.offset, 0, i->header.size);
366 break;
368 {
369 if(i->Array.type == DT_INTROSPECTION_TYPE_CHAR) break;
370
371 size_t element_size = i->Array.field->header.size;
372 if(element_size % sizeof(int))
373 {
374 int8_t *p = (int8_t *)module->default_params + i->header.offset;
375 for (size_t c = element_size; c < i->header.size; c++, p++)
376 p[element_size] = *p;
377 }
378 else
379 {
380 element_size /= sizeof(int);
381 size_t num_ints = i->header.size / sizeof(int);
382
383 int *p = (int *)((uint8_t *)module->default_params + i->header.offset);
384 for (size_t c = element_size; c < num_ints; c++, p++)
385 p[element_size] = *p;
386 }
387 }
388 break;
390 // ignore STRUCT; nothing to do
391 break;
392 default:
393 fprintf(stderr, "unsupported introspection type \"%s\" encountered in dt_iop_default_init (field %s)\n", i->header.type_name, i->header.field_name);
394 break;
395 }
396
397 i++;
398 }
399}
400
401int default_iop_focus(dt_gui_module_t *m, gboolean toggle)
402{
403 dt_iop_module_t *module = (dt_iop_module_t *) m;
404
405 // Expand and scroll
407 {
410 }
411 else if(toggle)
412 {
416 }
417
418 return 1;
419}
420
421int dt_iop_load_module_so(void *m, const char *libname, const char *module_name)
422{
423 dt_iop_module_so_t *module = (dt_iop_module_so_t *)m;
424 g_strlcpy(module->op, module_name, sizeof(module->op));
425
426#define INCLUDE_API_FROM_MODULE_LOAD "iop_load_module"
427#include "iop/iop_api.h"
428
429 if(IS_NULL_PTR(module->init)) module->init = dt_iop_default_init;
430 if(IS_NULL_PTR(module->modify_roi_in)) module->modify_roi_in = _iop_modify_roi_in;
431 if(IS_NULL_PTR(module->modify_roi_out)) module->modify_roi_out = _iop_modify_roi_out;
432
433 #ifdef HAVE_OPENCL
434 if(IS_NULL_PTR(module->process_tiling_cl)) module->process_tiling_cl = darktable.opencl->inited ? default_process_tiling_cl : NULL;
435 if(!darktable.opencl->inited) module->process_cl = NULL;
436 #endif // HAVE_OPENCL
437
438 module->process_plain = module->process;
439 module->process = default_process;
440
441 module->data = NULL;
442
443 // the introspection api
444 module->have_introspection = FALSE;
445 if(module->introspection_init)
446 {
447 if(!module->introspection_init(module, DT_INTROSPECTION_VERSION))
448 {
449 // set the introspection related fields in module
450 module->have_introspection = TRUE;
451
452 if(module->get_p == default_get_p ||
453 module->get_f == default_get_f ||
454 module->get_introspection_linear == default_get_introspection_linear ||
455 module->get_introspection == default_get_introspection)
456 goto api_h_error;
457 }
458 else
459 fprintf(stderr, "[iop_load_module] failed to initialize introspection for operation `%s'\n", module_name);
460 }
461
462 if(module->init_global) module->init_global(module);
463 return 0;
464}
465
467{
468 module->dev = dev;
469 module->widget = NULL;
470 module->header = NULL;
471 module->off = NULL;
472 module->hide_enable_button = 0;
473 module->request_color_pick = DT_REQUEST_COLORPICK_OFF;
474 module->request_histogram = DT_REQUEST_ONLY_IN_GUI;
475 module->histogram_stats.bins_count = 0;
476 module->histogram_stats.pixels = 0;
477 module->multi_priority = 0;
478 module->iop_order = 0;
479 for(int k = 0; k < 3; k++)
480 {
481 module->picked_color[k] = module->picked_output_color[k] = 0.0f;
482 module->picked_color_min[k] = module->picked_output_color_min[k] = 666.0f;
483 module->picked_color_max[k] = module->picked_output_color_max[k] = -666.0f;
484 }
485 module->histogram_cst = IOP_CS_NONE;
486 module->histogram = NULL;
487 module->histogram_max[0] = module->histogram_max[1] = module->histogram_max[2] = module->histogram_max[3]
488 = 0;
489 module->histogram_middle_grey = FALSE;
490 module->request_mask_display = DT_DEV_PIXELPIPE_DISPLAY_NONE;
491 module->bypass_cache = FALSE;
492 module->enabled = module->default_enabled = module->workflow_enabled = 0; // all modules disabled by default.
493 g_strlcpy(module->op, so->op, 20);
494 module->raster_mask.source.users = g_hash_table_new(NULL, NULL);
495 module->raster_mask.source.masks = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, dt_free_gpointer);
496 module->raster_mask.sink.source = NULL;
497 module->raster_mask.sink.id = 0;
498
499 // only reference cached results of dlopen:
500 module->module = so->module;
501 module->so = so;
502
503#define INCLUDE_API_FROM_MODULE_LOAD_BY_SO
504#include "iop/iop_api.h"
505
506 module->version = so->version;
507 module->process_plain = so->process_plain;
508 module->have_introspection = so->have_introspection;
509
510 module->reset_button = NULL;
511 module->presets_button = NULL;
512 module->fusion_slider = NULL;
513
514 module->global_data = so->data;
515
516 // now init the instance:
517 module->init(module);
518 module->hash = DT_PIXELPIPE_CACHE_HASH_INVALID;
519 module->blendop_hash = DT_PIXELPIPE_CACHE_HASH_INVALID;
520
521 if(module->params_size == 0)
522 {
523 fprintf(stderr, "[iop_load_module] `%s' needs to have a params size > 0!\n", so->op);
524 return 1; // empty params hurt us in many places, just add a dummy value
525 }
526
527 /* Allocate params only when module init did not allocate them already.
528 * Some init paths (notably default_init) already own the params buffers. */
529 if(IS_NULL_PTR(module->params))
530 module->params = calloc(1, module->params_size);
531 if(IS_NULL_PTR(module->default_params))
532 module->default_params = calloc(1, module->params_size);
533 module->blend_params = calloc(1, sizeof(dt_develop_blend_params_t));
534 module->default_blendop_params = calloc(1, sizeof(dt_develop_blend_params_t));
535
536 // Don't init defaults here, it's done when reading/initing history
537
538 /* pass on the dt_gui_module_t args for bauhaus widgets
539 * only when a GUI lifetime exists for this module instance. */
540 if(IS_NULL_PTR(module->dev) || module->dev->gui_attached)
541 {
542 module->common_fields.name = delete_underscore(module->name());
543 module->common_fields.view = g_strdup(_("Darkroom")); // IOP modules belong necessarily to darkroom
544 }
545 else
546 {
547 module->common_fields.name = NULL;
548 module->common_fields.view = NULL;
549 }
550 module->common_fields.widget_list = NULL;
551 module->common_fields.widget_list_bh = NULL;
552 module->common_fields.focus = module->iop_focus;
553 module->common_fields.deprecated = (module->flags() & IOP_FLAGS_DEPRECATED) == IOP_FLAGS_DEPRECATED;
554
555 return 0;
556}
557
559 struct dt_dev_pixelpipe_iop_t *piece)
560{
561 module->init_pipe(module, pipe, piece);
563}
564
577 struct dt_dev_pixelpipe_iop_t *piece)
578{
579 if(IS_NULL_PTR(piece)) return;
580
582 {
584 "[dt_iop_cleanup_pipe] missing module, skipping module pipe cleanup\n");
585 }
586 else if(IS_NULL_PTR(pipe))
587 {
589 "[dt_iop_cleanup_pipe] missing pipe for `%s`, skipping module pipe cleanup\n",
590 module->op);
591 }
592 else
593 {
594 dt_iop_module_so_t *module_so = module->so;
595 gboolean module_so_loaded = FALSE;
596
597 /* Search the process-owned descriptor list by address before reading the
598 * candidate. A removed instance may outlive its GUI, but its descriptor
599 * must remain one of the objects loaded at startup. */
600 for(GList *iop = g_list_first(darktable.iop); iop; iop = g_list_next(iop))
601 {
602 if(iop->data == module_so)
603 {
605 break;
606 }
607 }
608
611 "[dt_iop_cleanup_pipe] invalid shared-object descriptor %p, skipping module pipe cleanup\n",
612 (void *)module_so);
613 else if(module->cleanup_pipe != module_so->cleanup_pipe)
615 "[dt_iop_cleanup_pipe] stale cleanup callback for `%s`, skipping module pipe cleanup\n",
616 module_so->op);
617 else
618 module_so->cleanup_pipe(module, pipe, piece);
619 }
620
621 if(!IS_NULL_PTR(piece->blendop_data))
622 {
624 piece->blendop_data = NULL;
625 }
626}
627
628static void _gui_delete_callback(GtkButton *button, dt_iop_module_t *module)
629{
630 dt_develop_t *dev = module->dev;
631
632 // we search another module with the same base
633 // we want the next module if any or the previous one
634 GList *modules = module->dev->iop;
635 dt_iop_module_t *next = NULL;
636 int find = 0;
637 while(modules)
638 {
640 if(mod == module)
641 {
642 find = 1;
643 if(next) break;
644 }
645 else if(mod->instance == module->instance)
646 {
647 next = mod;
648 if(find) break;
649 }
651 }
652 if(IS_NULL_PTR(next)) return; // what happened ???
653
654 if(module->module_will_remove && !module->module_will_remove(module)) return;
655
657
658 // we must pay attention if priority is 0
659 const gboolean is_zero = (module->multi_priority == 0);
660
661 // We are about to destroy this module GUI. Drop darkroom focus first so the
662 // center expose callback cannot call module->gui_post_expose() with a stale
663 // module->gui_data pointer during teardown-triggered redraws.
665
667
668 // we remove the plugin effectively
670 {
671 // we just hide the module to avoid lots of gtk critical warnings
672 gtk_widget_hide(module->expander);
673
676 }
677
678 // we remove all references in the history stack and dev->iop
679 // this will inform that a module has been removed from history
680 // we do it here so we have the multi_priorities to reconstruct
681 // de deleted module if the user undo it
683
684 // if module was priority 0, then we set next to priority 0
685 if(is_zero)
686 {
687 // we want the first one in history
688 dt_iop_module_t *first = NULL;
689 GList *history = dev->history;
690 while(history)
691 {
692 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
693 if(!hist || !hist->module)
694 {
695 history = g_list_next(history);
696 continue;
697 }
698 if(hist->module->instance == module->instance && hist->module != module)
699 {
700 first = hist->module;
701 break;
702 }
703 history = g_list_next(history);
704 }
705 if(IS_NULL_PTR(first)) first = next;
706
707 // we set priority of first to 0
709
710 // we change this in the history stack too
711 for(history = dev->history; history; history = g_list_next(history))
712 {
713 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
714 if(hist->module == first) hist->multi_priority = 0;
715 }
716 }
717
718 // Commit undo snapshot for the whole delete operation (module removal + multi_priority adjustments).
720
721 // Save history
723
724 // don't delete the module, a pipe may still need it
725 dev->alliop = g_list_append(dev->alliop, module);
726
727 /* redraw */
730
732}
733
735{
736 GtkWidget *expander = module->expander;
737 return (expander && gtk_widget_is_visible(expander) && !dt_iop_is_hidden(module));
738}
739
741 gboolean enable, gboolean write_history, const char *reason)
742{
743 if(IS_NULL_PTR(dev)) return FALSE;
744
747
748 if(!IS_NULL_PTR(reason)) dt_ioppr_check_iop_order(dev, 0, reason);
749
751 return TRUE;
752}
753
760
767
769{
770 dt_iop_module_t *prev = NULL;
772 {
774 if(mod == module)
775 break;
777 prev = mod;
778 }
779 return prev;
780}
781
783{
784 dt_iop_module_t *next = NULL;
786 {
788 if(mod == module)
789 break;
791 next = mod;
792 }
793 return next;
794}
795
797{
798 // make sure the duplicated module appears in the history
799 dt_dev_add_history_item(base->dev, base, FALSE, FALSE);
800
801 // first we create the new module
803 dt_iop_module_t *module = dt_dev_module_duplicate(base->dev, base);
805 if(IS_NULL_PTR(module)) return NULL;
806
807 // we set the gui part of it
808 /* initialize gui if iop have one defined */
810 {
811 // make sure gui_init and reload defaults is called safely
813
814 /* add module to right panel */
816 darktable.gui->scroll_to_header_once = module->expander;
817
818 dt_iop_reload_defaults(module); // some modules like profiled denoise update the gui in reload_defaults
819
820 if(copy_params)
821 {
822 memcpy(module->params, base->params, module->params_size);
824 {
826 if(base->blend_params->mask_id > 0)
827 {
828 module->blend_params->mask_id = 0;
830 }
831 }
832 }
833
836 if(base != module && !IS_NULL_PTR(base->expander)) _gui_set_single_expanded(base, FALSE);
838
839 if(module->dev->gui_attached)
841
842 // we save the new instance creation
844 }
845
846 /* update ui to new parameters */
848
849 return module;
850}
851
853
862static gboolean _rename_module_idle(gpointer user_data)
863{
864 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
866
867 return G_SOURCE_REMOVE;
868}
869
870static void _gui_copy_callback(GtkButton *button, gpointer user_data)
871{
872 dt_iop_module_t *module = dt_iop_gui_duplicate(user_data, FALSE);
873 if(IS_NULL_PTR(module)) return;
874
876}
877
878static void _gui_duplicate_callback(GtkButton *button, gpointer user_data)
879{
880 dt_iop_module_t *module = dt_iop_gui_duplicate(user_data, TRUE);
881 if(IS_NULL_PTR(module)) return;
882
884}
885
887{
888 int ended = 0;
889 guint key = dt_keys_mainpad_alternatives(event->keyval);
890
891 if(event->type == GDK_FOCUS_CHANGE || key == GDK_KEY_Return)
892 {
894 {
895 // name is not empty, set new multi_name
896
897 const gchar *name = gtk_entry_get_text(GTK_ENTRY(entry));
898
899 // restore saved 1st character of instance name (without it the same name wouls still produce unnecessary copy + add history item)
900 module->multi_name[0] = module->multi_name[sizeof(module->multi_name) - 1];
901 module->multi_name[sizeof(module->multi_name) - 1] = 0;
902
903 if(g_strcmp0(module->multi_name, name) != 0)
904 {
905 g_strlcpy(module->multi_name, name, sizeof(module->multi_name));
907 }
908 }
909 else
910 {
911 // clear out multi-name (set 1st char to 0)
912 module->multi_name[0] = 0;
914 }
915
916 ended = 1;
917 }
918 else if(key == GDK_KEY_Escape)
919 {
920 // restore saved 1st character of instance name
921 module->multi_name[0] = module->multi_name[sizeof(module->multi_name) - 1];
922 module->multi_name[sizeof(module->multi_name) - 1] = 0;
923
924 ended = 1;
925 }
926
927 if(ended)
928 {
930 gtk_widget_destroy(entry);
933 return TRUE;
934 }
935
936 return FALSE; /* event not handled */
937}
938
940{
941 int width = 0;
942 GtkBorder padding;
943
947 &padding);
948 gtk_widget_set_size_request(entry, width + padding.left + padding.right + 1, -1);
949
950 return TRUE;
951}
952
954{
956 if(focused && GTK_IS_ENTRY(focused)) return;
957
958 GtkWidget *entry = gtk_entry_new();
960
961 gtk_widget_set_name(entry, "iop-panel-label");
963 gtk_entry_set_max_length(GTK_ENTRY(entry), sizeof(module->multi_name) - 1);
964 gtk_entry_set_text(GTK_ENTRY(entry), module->multi_name);
965
966 // remove instance name but save 1st character in case of escape
967 module->multi_name[sizeof(module->multi_name) - 1] = module->multi_name[0];
968 module->multi_name[0] = 0;
970
972 g_signal_connect(entry, "key-press-event", G_CALLBACK(_rename_module_key_press), module);
973 g_signal_connect(entry, "focus-out-event", G_CALLBACK(_rename_module_key_press), module);
974 g_signal_connect(entry, "style-updated", G_CALLBACK(_rename_module_resize), module);
976
977 gtk_box_pack_start(GTK_BOX(module->header), entry, TRUE, TRUE, 0);
978 gtk_widget_show(entry);
980}
981
982static void _gui_rename_callback(GtkButton *button, dt_iop_module_t *module)
983{
985}
986
987static gboolean _iop_plugin_header_menu_dismiss_idle(gpointer user_data)
988{
989 GtkWidget *expander = GTK_WIDGET(user_data);
990 if(GTK_IS_WIDGET(expander))
992
993 g_object_unref(expander);
994 return G_SOURCE_REMOVE;
995}
996
997static void _iop_plugin_header_menu_deactivate(GtkWidget *menu, gpointer user_data)
998{
999 GtkWidget *expander = GTK_WIDGET(user_data);
1000 if(!GTK_IS_WIDGET(expander)) return;
1001
1011}
1012
1013static gboolean _gui_multiinstance_callback(GtkButton *button, GdkEventButton *event, gpointer user_data)
1014{
1015 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
1016
1017 if(!IS_NULL_PTR(event) && event->button == 3)
1018 {
1019 if(!(module->flags() & IOP_FLAGS_ONE_INSTANCE)) _gui_copy_callback(button, user_data);
1020 return TRUE;
1021 }
1022 else if(!IS_NULL_PTR(event) && event->button == 2)
1023 {
1024 return FALSE;
1025 }
1026
1028 GtkWidget *item;
1029
1030 item = gtk_menu_item_new_with_label(_("new instance"));
1031 // gtk_widget_set_tooltip_text(item, _("add a new instance of this module to the pipe"));
1033 gtk_widget_set_sensitive(item, module->multi_show_new);
1034 gtk_menu_shell_append(menu, item);
1035
1036 item = gtk_menu_item_new_with_label(_("duplicate instance"));
1037 // gtk_widget_set_tooltip_text(item, _("add a copy of this instance to the pipe"));
1039 gtk_widget_set_sensitive(item, module->multi_show_new);
1040 gtk_menu_shell_append(menu, item);
1041
1042 item = gtk_menu_item_new_with_label(_("delete"));
1043 // gtk_widget_set_tooltip_text(item, _("delete this instance"));
1045 gtk_widget_set_sensitive(item, module->multi_show_close);
1046 gtk_menu_shell_append(menu, item);
1047
1049
1050 item = gtk_menu_item_new_with_label(_("rename"));
1052 gtk_menu_shell_append(menu, item);
1053
1054 if(!IS_NULL_PTR(module->expander))
1055 {
1057 g_signal_connect_data(G_OBJECT(menu), "deactivate",
1060 }
1061
1063
1064 // make sure the button is deactivated now that the menu is opened
1065 if(button) dtgtk_button_set_active(DTGTK_BUTTON(button), FALSE);
1066 return TRUE;
1067}
1068
1069static void _gui_off_callback(GtkToggleButton *togglebutton, gpointer user_data)
1070{
1071 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
1072
1073 if(!darktable.gui->reset)
1074 {
1083
1085 {
1086 module->enabled = 1;
1090 }
1091 else
1092 {
1093 module->enabled = 0;
1094
1095 // if current module is set as the CAT instance, remove that setting
1096 if(module->dev->proxy.chroma_adaptation == module)
1097 module->dev->proxy.chroma_adaptation = NULL;
1098
1100 }
1101 }
1102
1103 char tooltip[512];
1105 snprintf(tooltip, sizeof(tooltip), module->enabled ? _("%s is switched on") : _("%s is switched off"),
1106 module_label);
1110}
1111
1113{
1114 gboolean is_hidden = TRUE;
1115 if(!(module->flags() & IOP_FLAGS_HIDDEN))
1116 {
1117 if(IS_NULL_PTR(module->gui_init))
1118 g_debug("Module '%s' is not hidden and lacks implementation of gui_init()...", module->op);
1119 else if(!module->gui_cleanup)
1120 g_debug("Module '%s' is not hidden and lacks implementation of gui_cleanup()...", module->op);
1121 else
1122 is_hidden = FALSE;
1123 }
1124 return is_hidden;
1125}
1126
1128{
1129 return dt_iop_so_is_hidden(module->so);
1130}
1131
1133{
1134 return !dt_iop_is_hidden(module) && !IS_NULL_PTR(module->expander) && gtk_widget_is_visible(module->expander);
1135}
1136
1138{
1140 lab = gtk_bin_get_child(GTK_BIN(lab));
1141 gtk_widget_set_name(lab, "iop-panel-label");
1142
1143 char *module_name = dt_history_item_get_label(module);
1144 dt_capitalize_label(module_name);
1146 dt_free(module_name);
1147
1148 // Module name hasn't changed or no instance name: abort now
1149 if(!g_strcmp0(module_name, gtk_label_get_text(GTK_LABEL(lab))) || module->multi_name[0] == '\0')
1150 return;
1151
1153 if(mod->instance_name)
1154 {
1155 char *instance_path = dt_accels_build_path(_("Darkroom/Modules/Instances"), mod->instance_name);
1158 dt_free(mod->instance_name);
1159 }
1160
1161 gchar *clean_name = delete_underscore(module->name());
1163
1164 mod->instance_name
1165 = g_strdup_printf("%s/%s", clean_name, (module->multi_name[0] != '\0') ? module->multi_name : "0");
1166
1168 darktable.gui->accels->darkroom_accels, _("Darkroom/Modules/Instances"),
1169 mod->instance_name);
1170
1172
1174 g_object_set(G_OBJECT(lab), "xalign", 0.0, (gchar *)0);
1175}
1176
1178{
1179 if (IS_NULL_PTR(module->header)) /* some modules such as overexposed don't actually have a header */
1180 return;
1181
1182 // set panel name to display correct multi-instance
1186}
1187
1189{
1190 // set on/off icon
1191 if(module->default_enabled && module->hide_enable_button)
1192 {
1194 }
1195 else if(!module->default_enabled && module->hide_enable_button)
1196 {
1198 }
1199 else
1200 {
1202 }
1203}
1204
1206{
1207 if(IS_NULL_PTR(module)) return;
1208
1209 if(module->off)
1210 {
1212 if(module->hide_enable_button)
1214 else
1216
1217 dt_gui_remove_class(GTK_WIDGET(module->off), "dt_iop_enable_forced_on");
1218 dt_gui_remove_class(GTK_WIDGET(module->off), "dt_iop_enable_forced_off");
1219 if(module->hide_enable_button)
1220 {
1222 module->enabled ? "dt_iop_enable_forced_on" : "dt_iop_enable_forced_off");
1223 }
1224
1226 }
1227}
1228
1230{
1231 ++darktable.gui->reset;
1232
1233 // Add the accelerators
1234 if(!dt_iop_is_hidden(module) && !(module->flags() & IOP_FLAGS_DEPRECATED))
1235 {
1236 gchar *clean_name = delete_underscore(module->name());
1238
1239 // slash is not allowed in module names because that makes accel pathes fail
1240 assert(g_strrstr(clean_name, "/") == NULL);
1241
1243 const gchar *const main_scope = _("Darkroom/Modules");
1245
1247
1248 // NOTE: we should enable the accel only if the module is disable-able, but this property is set at runtime
1249 // in reload_defaults(), which depends on the image metadata for each pipeline.
1250 // We have no way of knowing here at init time.
1251 // if(!module->hide_enable_button)
1252 dt_accels_new_darkroom_action(_iop_plugin_enable_accel, module, mod->accel_path, _("Enable"), 0, 0, _("Enables the module"));
1253
1255 }
1256
1257 // We absolutely need to init the module controls after the module object
1258 if(module->gui_init) module->gui_init(module);
1259 if(module->color_picker_apply)
1260 {
1263 }
1264
1265 --darktable.gui->reset;
1266}
1267
1269{
1271 if(module->reload_defaults)
1272 {
1273 // report if reload_defaults was called unnecessarily => this should be considered a bug
1274 // the whole point of reload_defaults is to update defaults _based on current image_
1275 // any required initialisation should go in init (and not be performed repeatedly here)
1276 if(module->dev)
1277 {
1278 module->reload_defaults(module);
1279 dt_print(DT_DEBUG_PARAMS, "[params] defaults reloaded for %s\n", module->op);
1280 }
1281 else
1282 {
1283 fprintf(stderr, "reload_defaults should not be called without image.\n");
1284 }
1285 }
1287
1289
1291}
1292
1293
1295{
1296 // Skip auto-preset regeneration when the build + UI language haven't changed.
1297 if(module_so->init_presets && dt_gui_presets_autogen_enabled())
1298 module_so->init_presets(module_so);
1299
1300 // this seems like a reasonable place to check for and update legacy
1301 // presets.
1302
1303 const int32_t module_version = module_so->version();
1305 {
1308 "SELECT name, op_version, op_params, blendop_version, blendop_params FROM data.presets WHERE operation = ?1",
1310 }
1315
1316 while(sqlite3_step(stmt) == SQLITE_ROW)
1317 {
1318 const char *name = (char *)sqlite3_column_text(stmt, 0);
1320 const void *old_params = (void *)sqlite3_column_blob(stmt, 2);
1321 const int32_t old_params_size = sqlite3_column_bytes(stmt, 2);
1323 const void *old_blend_params = (void *)sqlite3_column_blob(stmt, 4);
1325
1326 if(old_params_version == 0)
1327 {
1328 // this preset doesn't have a version. go digging through the database
1329 // to find a history entry that matches the preset params, and get
1330 // the module version from that.
1331
1334 "SELECT module FROM main.history WHERE operation = ?1 AND op_params = ?2", -1,
1335 &stmt2, NULL);
1338
1340 {
1342 }
1343 else
1344 {
1345 fprintf(stderr, "[imageop_init_presets] WARNING: Could not find versioning information for '%s' "
1346 "preset '%s'\nUntil some is found, the preset will be unavailable.\n(To make it "
1347 "return, please load an image that uses the preset.)\n",
1348 module_so->op, name);
1350 continue;
1351 }
1352
1354
1355 // we found an old params version. Update the database with it.
1356
1357 fprintf(stderr, "[imageop_init_presets] Found version %d for '%s' preset '%s'\n", old_params_version,
1358 module_so->op, name);
1359
1361 "UPDATE data.presets SET op_version=?1 WHERE operation=?2 AND name=?3", -1,
1362 &stmt2, NULL);
1366
1369 }
1370
1371 if(module_version > old_params_version && !IS_NULL_PTR(module_so->legacy_params))
1372 {
1373 // we need a dt_iop_module_t for legacy_params()
1374 dt_iop_module_t *module;
1375 module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
1377 {
1378 dt_free(module);
1379 continue;
1380 }
1381/*
1382 module->init(module);
1383 if(module->params_size == 0)
1384 {
1385 dt_iop_cleanup_module(module);
1386 dt_free(module);
1387 continue;
1388 }
1389 // we call reload_defaults() in case the module defines it
1390 if(module->reload_defaults) module->reload_defaults(module); // why not call dt_iop_reload_defaults? (if needed at all)
1391*/
1392
1393 const int32_t new_params_size = module->params_size;
1394 void *new_params = calloc(1, new_params_size);
1395
1396 // convert the old params to new
1397 if(module->legacy_params(module, old_params, old_params_version, new_params, module_version))
1398 {
1399 dt_free(new_params);
1401 dt_free(module);
1402 continue;
1403 }
1404
1405 fprintf(stderr, "[imageop_init_presets] updating '%s' preset '%s' from version %d to version %d\nto:'%s'",
1406 module_so->op, name, old_params_version, module_version,
1408
1409 // and write the new params back to the database
1411 // clang-format off
1413 "SET op_version=?1, op_params=?2 "
1414 "WHERE operation=?3 AND name=?4",
1415 -1, &stmt2, NULL);
1416 // clang-format on
1417 DT_DEBUG_SQLITE3_BIND_INT(stmt2, 1, module->version());
1421
1424
1425 dt_free(new_params);
1427 dt_free(module);
1428 }
1429 else if(module_version > old_params_version)
1430 {
1431 fprintf(stderr, "[imageop_init_presets] Can't upgrade '%s' preset '%s' from version %d to %d, no "
1432 "legacy_params() implemented \n",
1433 module_so->op, name, old_params_version, module_version);
1434 }
1435
1437 {
1439 "[imageop_init_presets] updating '%s' preset '%s' from blendop version %d to version %d\n",
1441
1442 // we need a dt_iop_module_t for dt_develop_blend_legacy_params()
1443 // using dt_develop_blend_legacy_params_by_so won't help as we need "module" anyway
1444 dt_iop_module_t *module;
1445 module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
1447 {
1448 dt_free(module);
1449 continue;
1450 }
1451
1452 if(module->params_size == 0)
1453 {
1455 dt_free(module);
1456 continue;
1457 }
1459
1460 // convert the old blend params to new
1465 {
1466 // do nothing
1467 }
1468 else
1469 {
1470 memcpy(new_blend_params, module->default_blendop_params, sizeof(dt_develop_blend_params_t));
1471 }
1472
1473 // and write the new blend params back to the database
1475 // clang-format off
1477 "SET blendop_version=?1, blendop_params=?2 "
1478 "WHERE operation=?3 AND name=?4",
1479 -1, &stmt2, NULL);
1480 // clang-format on
1486
1489
1492 dt_free(module);
1493 }
1494 }
1496}
1497
1498
1499static void _init_module_so(void *m)
1500{
1501 dt_iop_module_so_t *module = (dt_iop_module_so_t *)m;
1502
1504
1505 // do not init accelerators if there is no gui
1506 if(darktable.gui)
1507 {
1508 // create a gui and have the widgets register their accelerators
1510
1512 {
1514
1515 static gboolean blending_accels_initialized = FALSE;
1517 {
1518 dt_iop_colorspace_type_t cst = module->blend_colorspace(module_instance, NULL, NULL);
1519
1520 if((module->flags() & IOP_FLAGS_SUPPORTS_BLENDING) &&
1521 !(module->flags() & IOP_FLAGS_NO_MASKS) &&
1522 (cst == IOP_CS_LAB || dt_iop_colorspace_is_rgb(cst)))
1523 {
1526
1528 }
1529 }
1530
1532
1534
1535 }
1536
1538 }
1539}
1540
1542{
1543 // Batch presets initialization in a single transaction to avoid per-module BEGIN/COMMIT overhead.
1548}
1549
1551{
1552 memset(module, 0, sizeof(dt_iop_module_t));
1554 {
1555 dt_free(module);
1556 return 1;
1557 }
1558 return 0;
1559}
1560
1562{
1563 module->cleanup(module);
1564
1565 if(!IS_NULL_PTR(module->common_fields.name))
1566 {
1567 dt_free(module->common_fields.name);
1568 module->common_fields.name = NULL;
1569 }
1570 if(!IS_NULL_PTR(module->common_fields.view))
1571 {
1572 dt_free(module->common_fields.view);
1573 module->common_fields.view = NULL;
1574 }
1575
1576 dt_free(module->blend_params);
1577 dt_free(module->default_blendop_params);
1578
1579 // don't have a picker pointing to a disappeared module
1583 {
1589 }
1590
1591 dt_free(module->histogram);
1592 g_hash_table_destroy(module->raster_mask.source.users);
1593 g_hash_table_destroy(module->raster_mask.source.masks);
1594 module->raster_mask.source.users = NULL;
1595 module->raster_mask.source.masks = NULL;
1596}
1597
1599{
1601 {
1604 }
1605
1606 while(darktable.iop)
1607 {
1608 dt_iop_module_so_t *module = (dt_iop_module_so_t *)darktable.iop->data;
1609 if(module->cleanup_global) module->cleanup_global(module);
1610 if(module->module) g_module_close(module->module);
1611 dt_free(darktable.iop->data);
1613 }
1614}
1615
1617{
1618 (void)mask_mode;
1619 static const int key = 0;
1620
1621 gboolean drawn_used = FALSE;
1622 gboolean parametric_used = FALSE;
1624
1626 {
1628 g_hash_table_insert(module->raster_mask.source.masks, GINT_TO_POINTER(key), modulename);
1629 }
1630 else
1631 {
1632 g_hash_table_remove(module->raster_mask.source.masks, GINT_TO_POINTER(key));
1633 }
1634}
1635
1637{
1638 if(IS_NULL_PTR(module)) return FALSE;
1639
1640 const gboolean mask_mode_raster = module->blend_params
1641 && ((module->blend_params->mask_mode & DEVELOP_MASK_RASTER) == DEVELOP_MASK_RASTER);
1642 const gboolean has_raster_sink = (!IS_NULL_PTR(module->raster_mask.sink.source));
1643
1645}
1646
1648{
1649 if(IS_NULL_PTR(module)) return FALSE;
1650
1651 const gboolean supports_blending
1652 = ((module->flags() & IOP_FLAGS_SUPPORTS_BLENDING) == IOP_FLAGS_SUPPORTS_BLENDING);
1653 const gboolean internal_masks = ((module->flags() & IOP_FLAGS_INTERNAL_MASKS) == IOP_FLAGS_INTERNAL_MASKS);
1654
1656 if(IS_NULL_PTR(module->blend_params)) return internal_masks;
1657
1658 gboolean raster_used = FALSE;
1659 gboolean drawn_used = FALSE;
1660 gboolean parametric_used = FALSE;
1662
1664}
1665
1666// make sure that blend_params are in sync with the iop struct
1668{
1669 if(module->raster_mask.sink.source)
1670 g_hash_table_remove(module->raster_mask.sink.source->raster_mask.source.users, module);
1671
1672 if(module->blend_params != blendop_params)
1673 memcpy(module->blend_params, blendop_params, sizeof(dt_develop_blend_params_t));
1674
1675 if(blendop_params->blend_cst == DEVELOP_BLEND_CS_NONE)
1676 {
1677 module->blend_params->blend_cst = dt_develop_blend_default_module_blend_colorspace(module);
1678 }
1679 dt_iop_set_mask_mode(module, blendop_params->mask_mode);
1680
1681 // This assumes that the module providing raster mask to the current one is ALWAYS
1682 // MANDATORILY before the current one BOTH in history order AND in pipe order,
1683 // because the current function is run in history order when we load/reload/pop history
1684 if(module->dev)
1685 for(GList *iter = g_list_first(module->dev->iop); iter; iter = g_list_next(iter))
1686 {
1688 if(!strcmp(m->op, blendop_params->raster_mask_source))
1689 {
1690 if(m->multi_priority == blendop_params->raster_mask_instance)
1691 {
1692 g_hash_table_insert(m->raster_mask.source.users, module, GINT_TO_POINTER(blendop_params->raster_mask_id));
1693 dt_print(DT_DEBUG_MASKS, "[raster masks] Committing raster mask from %s (%s) into %s (%s)\n", m->op, m->multi_name, module->op,
1694 module->multi_name);
1695 module->raster_mask.sink.source = m;
1696 module->raster_mask.sink.id = blendop_params->raster_mask_id;
1697 return;
1698 }
1699 }
1700 }
1701 // else if no module->dev, it means we are only loading module's .so
1702
1703 module->raster_mask.sink.source = NULL;
1704 module->raster_mask.sink.id = 0;
1705}
1706
1707gboolean _iop_validate_params(dt_introspection_field_t *field, gpointer params, gboolean report)
1708{
1709 dt_iop_params_t *p = (dt_iop_params_t *)((uint8_t *)params + field->header.offset);
1710
1711 gboolean all_ok = TRUE;
1712
1713 switch(field->header.type)
1714 {
1716 for(int i = 0; i < field->Struct.entries; i++)
1717 {
1718 dt_introspection_field_t *entry = field->Struct.fields[i];
1719
1720 all_ok &= _iop_validate_params(entry, params, report);
1721 }
1722 break;
1724 all_ok = FALSE;
1725 for(int i = field->Union.entries - 1; i >= 0 ; i--)
1726 {
1727 dt_introspection_field_t *entry = field->Union.fields[i];
1728
1729 if(_iop_validate_params(entry, params, report && i == 0))
1730 {
1731 all_ok = TRUE;
1732 break;
1733 }
1734 }
1735 break;
1738 {
1739 if(!memchr(p, '\0', field->Array.count))
1740 {
1741 if(report)
1742 fprintf(stderr, "validation check failed in _iop_validate_params for type \"%s\"; string not null terminated.\n",
1743 field->header.type_name);
1744 all_ok = FALSE;
1745 }
1746 }
1747 else
1748 {
1749 for(int i = 0, item_offset = 0; i < field->Array.count; i++, item_offset += field->Array.field->header.size)
1750 {
1751 if(!_iop_validate_params(field->Array.field, (uint8_t *)params + item_offset, report))
1752 {
1753 if(report)
1754 fprintf(stderr, "validation check failed in _iop_validate_params for type \"%s\", for array element \"%d\"\n",
1755 field->header.type_name, i);
1756 all_ok = FALSE;
1757 break;
1758 }
1759 }
1760 }
1761 break;
1763 all_ok = isnan(*(float*)p) || ((*(float*)p >= field->Float.Min && *(float*)p <= field->Float.Max));
1764 break;
1766 all_ok = (*(int*)p >= field->Int.Min && *(int*)p <= field->Int.Max);
1767 break;
1769 all_ok = (*(unsigned int*)p >= field->UInt.Min && *(unsigned int*)p <= field->UInt.Max);
1770 break;
1772 all_ok = (*(unsigned short int*)p >= field->UShort.Min && *(unsigned short int*)p <= field->UShort.Max);
1773 break;
1775 all_ok = (*(uint8_t*)p >= field->Int8.Min && *(uint8_t*)p <= field->Int8.Max);
1776 break;
1778 all_ok = (*(char*)p >= field->Char.Min && *(char*)p <= field->Char.Max);
1779 break;
1781 all_ok = creal(*(float complex*)p) >= creal(field->FloatComplex.Min) &&
1782 creal(*(float complex*)p) <= creal(field->FloatComplex.Max) &&
1783 cimag(*(float complex*)p) >= cimag(field->FloatComplex.Min) &&
1784 cimag(*(float complex*)p) <= cimag(field->FloatComplex.Max);
1785 break;
1787 all_ok = FALSE;
1788 for(dt_introspection_type_enum_tuple_t *i = field->Enum.values; i && i->name; i++)
1789 {
1790 if(i->value == *(int*)p)
1791 {
1792 all_ok = TRUE;
1793 break;
1794 }
1795 }
1796 break;
1798 // *(gboolean*)p
1799 break;
1801 // TODO: special case float2
1802 break;
1803 default:
1804 fprintf(stderr, "unsupported introspection type \"%s\" encountered in _iop_validate_params (field %s)\n",
1805 field->header.type_name, field->header.name);
1806 all_ok = FALSE;
1807 break;
1808 }
1809
1810 if(!all_ok && report)
1811 fprintf(stderr, "validation check failed in _iop_validate_params for type \"%s\"%s%s\n",
1812 field->header.type_name, (*field->header.name ? ", field: " : ""), field->header.name);
1813
1814 return all_ok;
1815}
1816
1817
1819{
1820 // Use module fingerprints to determine if two instances are actually the same
1821 return mod_1 == mod_2
1822 && mod_1->instance == mod_2->instance
1823 && mod_1->multi_priority == mod_2->multi_priority
1824 && mod_1->iop_order == mod_2->iop_order;
1825}
1826
1827
1828void _hash_raster_masks(gpointer key, gpointer value, uint64_t *hash)
1829{
1830 dt_iop_module_t *module = (dt_iop_module_t *)key;
1831
1832 // Use only "constant" module params with regard to the pipeline
1833 // init/resync aka we can't use any module pre-computed hash.
1834 *hash = dt_hash(*hash, (char *)module->op, sizeof(module->op));
1835 *hash = dt_hash(*hash, (char *)&module->iop_order, sizeof(module->iop_order));
1836 *hash = dt_hash(*hash, (char *)&module->instance, sizeof(module->instance));
1837 *hash = dt_hash(*hash, (char *)&module->multi_priority, sizeof(module->multi_priority));
1838 *hash = dt_hash(*hash, (char *)module->blend_params, sizeof(dt_develop_blend_params_t));
1839}
1840
1841
1843{
1844 // Blend params are always inited even when module doesn't support blending
1845 hash = dt_hash(hash, (char *)module->blend_params, sizeof(dt_develop_blend_params_t));
1846
1847 if(module->flags() & IOP_FLAGS_SUPPORTS_BLENDING)
1848 {
1849 // Drawn masks from dev for this module
1850 if(!IS_NULL_PTR(masks))
1851 {
1852 dt_masks_form_t *grp = dt_masks_get_from_id_ext(masks, module->blend_params->mask_id);
1853 hash = dt_masks_group_get_hash(hash, grp);
1854 }
1855
1856 // else : no module->dev when running from init_default_params()
1857
1858 // If module PROVIDES raster masks to others later in the pipe:
1859 // Account for later modules that reuse the raster mask provided by the current module.
1860 // This is a little cache invalidation trick: we change the final piece hash of this module,
1861 // to signal to the pipeline that it needs to recompute from lower than just the last changed module,
1862 // if that module references the raster mask produced here.
1863 // This contains the list of consumer modules:
1864 g_hash_table_foreach(module->raster_mask.source.users, (GHFunc)_hash_raster_masks, (gpointer)&hash);
1865
1866 // module->raster_mask.source.masks contains only one mask as of now,
1867 // aka its blendop output, so no need to iterate over that.
1868
1869 // If module CONSUMES raster masks from a module earlier in the pipe:
1870 // Account for its blendops.
1871 dt_iop_module_t *raster_source = module->raster_mask.sink.source;
1872 if(raster_source)
1873 {
1874 // Drawn masks
1875 if(!IS_NULL_PTR(masks))
1876 {
1877 dt_masks_form_t *raster_grp = dt_masks_get_from_id_ext(masks, raster_source->blend_params->mask_id);
1878 hash = dt_masks_group_get_hash(hash, raster_grp);
1879 }
1880
1881 // Blending
1882 hash = dt_hash(hash, (char *)raster_source->blend_params, sizeof(dt_develop_blend_params_t));
1883 }
1884 }
1885
1886 module->blendop_hash = hash;
1887}
1888
1889
1891{
1892 // Uniform way of getting the full state hash of user-defined parameters,
1893 // including masks and blending.
1894 // WARNING: doesn't take into account parameters dynamically set at runtime.
1895
1896 uint64_t hash = dt_hash(5381, (char *)module->op, sizeof(dt_dev_operation_t));
1897 hash = dt_hash(hash, (char *)&module->enabled, sizeof(gboolean));
1898 hash = dt_hash(hash, (char *)&module->instance, sizeof(int32_t));
1899 hash = dt_hash(hash, (char *)&module->multi_priority, sizeof(int));
1900 hash = dt_hash(hash, (char *)&module->iop_order, sizeof(int));
1901
1902 // Compute stand-alone blendop hash (mask hash) from the above
1903 // save to module->blendop_hash
1904 dt_iop_compute_blendop_hash(module, hash, masks);
1905
1906 // Finish our module-wide (output) hash
1907 hash = dt_hash(hash, (char *)module->params, module->params_size);
1908 hash = dt_hash(hash, (char *)&module->blendop_hash, sizeof(uint64_t));
1909
1910 module->hash = hash;
1911}
1912
1914 dt_develop_blend_params_t *blendop_params, dt_dev_pixelpipe_t *pipe,
1916{
1917 // We need to commit also modules that are disabled because some of them
1918 // may self-enabled at commit time, depending on image input.
1919 // 1. commit params
1920 memcpy(piece->blendop_data, blendop_params, sizeof(dt_develop_blend_params_t));
1921
1922#ifdef HAVE_OPENCL
1923 // assume process_cl is ready, commit_params can overwrite this.
1924 if(module->process_cl)
1925 piece->process_cl_ready = 1;
1926
1927 piece->cache_output_on_ram = 0;
1928#endif // HAVE_OPENCL
1929
1930 // register if module allows tiling, commit_params can overwrite this.
1931 if(module->flags() & IOP_FLAGS_ALLOW_TILING)
1932 piece->process_tiling_ready = 1;
1933
1934 if(darktable.unmuted & DT_DEBUG_PARAMS && module->so->get_introspection())
1935 _iop_validate_params(module->so->get_introspection()->field, params, TRUE);
1936
1937 module->commit_params(module, params, pipe, piece);
1938
1939 gchar *string = g_strdup_printf("/plugins/%s/opencl", module->op);
1940
1941 if(!dt_conf_key_exists(string) || !dt_conf_key_not_empty(string))
1942 dt_conf_set_bool(string, TRUE);
1943
1944 piece->process_cl_ready &= dt_conf_get_bool(string);
1945 dt_free(string);
1946
1947 //uint64_t old_hash = module->hash;
1948
1949 // 2. Update the internal hash
1950 // We need to update the blendop params dynamically, because drawn masks (forms)
1951 // belong to pipeline not to modules user params, and raster masks travel through the pipe.
1952 // So, module's blendops depend on the current and whole state of dev->forms if they use them
1954
1955 uint64_t hash = module->hash;
1956
1957 //if(old_hash != hash)
1958 // fprintf(stdout, "WARNING: hash changed at history -> pipeline commit time for %s\n", module->op);
1959
1960 /* Some modules seal part of their effective runtime contract only in commit_params(),
1961 * after reading GUI-only state, pipe mode, or other non-history inputs. Those modules
1962 * must opt in explicitly, because piece->data may also contain transient pointers or
1963 * scratch state for other modules and therefore cannot be hashed blindly. */
1964 if(module->runtime_data_hash(module, pipe, piece))
1965 {
1966 hash = dt_hash(hash, (const char *)piece->data, piece->data_size);
1967 }
1968
1969 piece->global_hash = piece->hash = hash;
1970 piece->global_mask_hash = piece->blendop_hash = module->blendop_hash;
1971
1972 dt_print(DT_DEBUG_PARAMS, "[pixelpipe] params commit for %s (%s) in pipe %s with hash %" PRIu64 "\n",
1973 module->op, module->multi_name,
1974 dt_pixelpipe_get_pipe_name(pipe->type), piece->hash);
1975}
1976
1983static void _iop_gui_widget_gone(gpointer user_data, GObject *where_the_object_was)
1984{
1985 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
1986 if(IS_NULL_PTR(module)) return;
1987
1988 if(module->header == (GtkWidget *)where_the_object_was) module->header = NULL;
1989 if(module->expander == (GtkWidget *)where_the_object_was) module->expander = NULL;
1990
1991 if(IS_NULL_PTR(darktable.gui)) return;
1992
1996}
1997
1999{
2000 if(IS_NULL_PTR(module)) return;
2002 if(!IS_NULL_PTR(module->dev) && module->dev->gui_module == module) module->dev->gui_module = NULL;
2003
2004 // remove multiple delayed gtk_widget_queue_draw triggers
2005 if(module->widget)
2006 while(g_idle_remove_by_data(module->widget));
2007
2008 // Detach accels
2009 if(!dt_iop_is_hidden(module) && !(module->flags() & IOP_FLAGS_DEPRECATED))
2010 {
2012 dt_free(mod->accel_path);
2013 }
2014
2015 if(mod->instance_name)
2016 {
2017 char *instance_path = dt_accels_build_path(_("Darkroom/Modules/Instances"), mod->instance_name);
2020 }
2021
2022 dt_free(mod->instance_name);
2023
2024 // widget_list doesn't own the widget referenced, so don't deep_free
2026 g_list_free(m->widget_list);
2027 m->widget_list = NULL;
2028 g_list_free(m->widget_list_bh);
2029 m->widget_list_bh = NULL;
2030 dt_free(m->name);
2031 m->name = NULL;
2032 dt_free(m->view);
2033 m->view = NULL;
2034
2035 if(module->color_picker_apply)
2036 {
2038 }
2039 // History refresh can delete pipeline-only modules created for ordering/history
2040 // resolution. They have a module GUI cleanup callback but no module GUI data.
2041 if(module->gui_cleanup && !IS_NULL_PTR(module->gui_data))
2042 module->gui_cleanup(module);
2044
2045 // size-allocate callbacks can still read scroll targets while GTK tears down widgets
2047 {
2048 if(darktable.gui->scroll_to[0] == module->header || darktable.gui->scroll_to[0] == module->expander)
2050 if(darktable.gui->scroll_to[1] == module->header || darktable.gui->scroll_to[1] == module->expander)
2052 if(darktable.gui->scroll_to_header_once == module->expander)
2054 }
2055
2056 /* Release the transient widget tree explicitly. In normal GUI lifetime, these
2057 * widgets are parented and get destroyed by container teardown. During module
2058 * probe/init paths, they can stay unparented and would otherwise leak. */
2059 if(!IS_NULL_PTR(module->expander) && GTK_IS_WIDGET(module->expander))
2060 {
2061 GtkWidget *expander = module->expander;
2062 g_object_ref_sink(expander);
2063 gtk_widget_destroy(expander);
2064 g_object_unref(expander);
2065 }
2066 else
2067 {
2068 if(!IS_NULL_PTR(module->header) && GTK_IS_WIDGET(module->header))
2069 {
2070 GtkWidget *header = module->header;
2071 g_object_ref_sink(header);
2072 gtk_widget_destroy(header);
2073 g_object_unref(header);
2074 }
2075
2076 if(!IS_NULL_PTR(module->widget) && GTK_IS_WIDGET(module->widget))
2077 {
2078 GtkWidget *widget = module->widget;
2079 g_object_ref_sink(widget);
2080 gtk_widget_destroy(widget);
2081 g_object_unref(widget);
2082 }
2083 }
2084
2085 module->widget = NULL;
2086 module->header = NULL;
2087 module->expander = NULL;
2088 module->off = NULL;
2089}
2090
2092{
2093 ++darktable.gui->reset;
2095 {
2096 if(module->gui_data)
2097 {
2099
2100 if(module->params && module->gui_update)
2101 module->gui_update(module);
2102
2105 }
2107 }
2108 --darktable.gui->reset;
2109}
2110
2112{
2113 ++darktable.gui->reset;
2114 if(module->gui_reset && !dt_iop_is_hidden(module)) module->gui_reset(module);
2115 --darktable.gui->reset;
2116}
2117
2118static void _gui_reset_callback(GtkButton *button, GdkEventButton *event, dt_iop_module_t *module)
2119{
2120 // never use the callback if module is always disabled
2121 const gboolean disabled = !module->default_enabled && module->hide_enable_button;
2122 if(disabled) return;
2123
2124 //Ctrl is used to apply any auto-presets to the current module
2125 //If Ctrl was not pressed, or no auto-presets were applied, reset the module parameters
2126 // FIXME: can we stop with all the easter-eggs key modifiers doing undocumented stuff all along ?
2128 {
2129 // if a drawn mask is set, remove it from the list
2130 if(module->blend_params->mask_id > 0)
2131 {
2133 // FIXME: ask the user if he wants to delete the mask, or just unlink them.
2136 }
2137 /* reset to default params */
2139 dt_iop_commit_blend_params(module, module->default_blendop_params);
2140
2141 /* reset ui to its defaults */
2143
2144 /* update ui to default params*/
2146
2148 }
2149}
2150
2151static void _presets_popup_callback(GtkButton *button, dt_iop_module_t *module)
2152{
2153 const gboolean disabled = !module->default_enabled && module->hide_enable_button;
2154 if(disabled) return;
2155
2157
2159 {
2164 }
2165
2167}
2168
2170{
2172
2173 if(darktable.gui->reset || (out_focus_module == module)) return;
2174
2175 darktable.develop->gui_module = module;
2176 if(!IS_NULL_PTR(module))
2177 {
2178 const gboolean scroll_new_instance_to_header
2179 = (darktable.gui->scroll_to_header_once == module->expander
2180 && !IS_NULL_PTR(module->header) && GTK_IS_WIDGET(module->header));
2181 darktable.gui->scroll_to[1] = scroll_new_instance_to_header ? module->header : module->expander;
2182 }
2183
2184 /* lets lose the focus of previous focus module*/
2186 {
2190 {
2193 }
2194
2195 if(out_focus_module->gui_focus)
2197
2200
2202
2203 /* reset mask view */
2205
2206 /* do stuff needed in the blending gui */
2208
2209 /* redraw the expander */
2211
2212 /* and finally collection restore hinter messages */
2214
2215 // we also remove the focus css class
2217 dt_gui_remove_class(iop_w, "dt_module_focus");
2218 }
2219
2220 /* set the focus on module */
2221 if(!IS_NULL_PTR(module))
2222 {
2223 // In case we tried giving focus to a module that is not in the visible tab
2225
2227
2228 if(module->gui_focus) module->gui_focus(module, TRUE);
2229
2230 /* redraw the expander */
2231 gtk_widget_queue_draw(module->expander);
2232 gtk_widget_grab_focus(module->expander);
2233
2234 /* set the focus on the first child to enable arrow-key navigation and accessibility stuff */
2235 GList *widget_list = ((dt_gui_module_t *)module)->widget_list;
2236 if(widget_list)
2237 {
2238 GList *first_child = g_list_first(widget_list);
2239 if(first_child)
2240 {
2241 GtkWidget *widget = (GtkWidget *)first_child->data;
2242 if(widget) gtk_widget_grab_focus(widget);
2243 }
2244 }
2245
2246 // we also add the focus css class
2248 dt_gui_add_class(iop_w, "dt_module_focus");
2249 }
2250
2254}
2255
2256/*
2257 * NEW EXPANDER
2258 */
2259
2260static void _gui_set_single_expanded(dt_iop_module_t *module, gboolean expanded)
2261{
2262 if(IS_NULL_PTR(module->expander)) return;
2263
2264 /* update expander arrow state */
2266
2267 /* store expanded state of module.
2268 * we do that first, so update_expanded won't think it should be visible
2269 * and undo our changes right away. */
2270 module->expanded = expanded;
2271
2272 /* show / hide plugin widget */
2273 if(expanded)
2274 {
2275 /* set this module to receive focus / draw events*/
2277
2278 /* focus the current module */
2279 for(int k = 0; k < DT_UI_CONTAINER_SIZE; k++)
2281
2282 /* redraw center, iop might have post expose */
2284 }
2285 else
2286 {
2287 if(module->dev->gui_module == module)
2288 {
2291 }
2292 }
2293
2294 if(expanded)
2295 dt_gui_add_class(module->expander, "expanded");
2296 else
2297 dt_gui_remove_class(module->expander, "expanded");
2298
2299 char var[1024];
2300 snprintf(var, sizeof(var), "plugins/darkroom/%s/expanded", module->op);
2301 dt_conf_set_bool(var, expanded);
2302}
2303
2306{
2307 for(GList *iop = g_list_first(darktable.develop->iop); iop; iop = g_list_next(iop))
2308 {
2309 dt_iop_module_t *m = (dt_iop_module_t *)iop->data;
2310
2311 // Handle invisible modules
2312 if(IS_NULL_PTR(m) || !m->expander) continue;
2313
2314 if(dim && m != module)
2316 else
2318 }
2319}
2320
2322{
2323 if(IS_NULL_PTR(module) || !module->expander) return;
2324 if(collapse_others)
2325 {
2326 for(GList *iop = g_list_first(darktable.develop->iop); iop; iop = g_list_next(iop))
2327 {
2328 dt_iop_module_t *m = (dt_iop_module_t *)iop->data;
2330 }
2331 }
2332
2334 _iop_dim_all_but((expanded) ? module : NULL, expanded);
2336}
2337
2339{
2340 if(IS_NULL_PTR(module->expander)) return;
2341
2342 const gboolean expanded = module->expanded;
2343
2345}
2346
2347static gboolean _iop_plugin_body_button_press(GtkWidget *w, GdkEventButton *e, gpointer user_data)
2348{
2349 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
2350
2351 /* Reset the scrolling focus. If the click happened on any bauhaus element,
2352 * its internal button_press method will set it for itself */
2354
2355 gboolean handled = FALSE;
2356
2357 if(e->button == 1)
2358 {
2360 handled = TRUE;
2361 }
2362 else if(e->button == 3)
2363 {
2365 handled = TRUE;
2366 }
2367 return handled;
2368}
2369
2370static gboolean _iop_plugin_header_activate(GtkWidget* self, gboolean group_cycling, gpointer user_data)
2371{
2372 dt_gui_module_t *module = (dt_gui_module_t *)user_data;
2373 if(IS_NULL_PTR(module) || !module->focus) return FALSE;
2374 return module->focus(module, TRUE);
2375}
2376
2377static gboolean _iop_plugin_header_child_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
2378{
2379 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
2380 if(module && module->expander)
2381 g_object_set_data(G_OBJECT(module->expander), "dt-module-header-child-click", GINT_TO_POINTER(TRUE));
2382
2383 return FALSE;
2384}
2385
2387 GdkModifierType modifier, gpointer data)
2388{
2389 dt_gui_module_t *module = (dt_gui_module_t *)data;
2390 dt_iop_module_t *iop = (dt_iop_module_t *)data;
2391 if(IS_NULL_PTR(module) || !module->focus) return FALSE;
2392
2393 // Accel search explicitly targets a module, so allow modulegroups to leave
2394 // the Pipeline tab once for this focus request.
2395 if(iop->expander)
2396 g_object_set_data(G_OBJECT(iop->expander), "dt-modulegroups-switch-from-active-once",
2398
2399 return module->focus(module, FALSE);
2400}
2401
2403 GdkModifierType modifier, gpointer data)
2404{
2405 dt_iop_module_t *module = (dt_iop_module_t *)data;
2406 if(IS_NULL_PTR(module)) return FALSE;
2407
2408 // Direct actions from accel search should prioritize Pipeline when they focus
2409 // the edited module right after applying the change.
2410 if(!IS_NULL_PTR(module->expander))
2411 g_object_set_data(G_OBJECT(module->expander), "dt-modulegroups-prefer-active-once",
2413
2414 // Kind of ugly to go through history to change module GUI state
2415 // FIXME: we should have a GUI callback that enables module and dispatches history instead,
2416 // history should not care about module GUI. This is a wrong, reversed inheritance.
2417 if(!module->hide_enable_button)
2418 {
2419 module->enabled = TRUE;
2421 }
2422
2425 return TRUE;
2426}
2427
2428static gboolean _iop_plugin_header_button_press(GtkWidget *w, GdkEventButton *e, gpointer user_data)
2429{
2430 if(e->type == GDK_2BUTTON_PRESS || e->type == GDK_3BUTTON_PRESS) return TRUE;
2431
2432 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
2433 if(IS_NULL_PTR(module)) return FALSE;
2434
2435 if(!IS_NULL_PTR(module->expander)
2438 {
2440 return TRUE;
2441 }
2442
2443 /* Reset the scrolling focus. If the click happened on any bauhaus element,
2444 * its internal button_press method will set it for itself */
2446
2447 if(e->button == 1)
2448 {
2449 if(module->expander) g_object_set_data(G_OBJECT(module->expander), "dt-module-dragged", NULL);
2450
2451 if(!dt_modifier_is(e->state, GDK_CONTROL_MASK))
2452 {
2453 return FALSE;
2454 }
2455 else
2456 {
2458 return TRUE;
2459 }
2460 }
2461 else if(e->button == 3)
2462 {
2464
2465 return TRUE;
2466 }
2467 return FALSE;
2468}
2469
2470static gboolean _iop_plugin_header_button_release(GtkWidget *w, GdkEventButton *e, gpointer user_data)
2471{
2472 if(e->button != 1 || e->type != GDK_BUTTON_RELEASE) return FALSE;
2473
2474 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
2475 if(IS_NULL_PTR(module) || !module->expander) return FALSE;
2476
2478 {
2480 return TRUE;
2481 }
2482
2485 {
2486 return TRUE;
2487 }
2488
2489 if(g_object_get_data(G_OBJECT(module->expander), "dt-module-header-child-click"))
2490 {
2491 g_object_set_data(G_OBJECT(module->expander), "dt-module-header-child-click", NULL);
2492 return FALSE;
2493 }
2494
2495 if(g_object_get_data(G_OBJECT(module->expander), "dt-module-dragged"))
2496 {
2497 g_object_set_data(G_OBJECT(module->expander), "dt-module-dragged", NULL);
2498 return TRUE;
2499 }
2500
2501 // make gtk scroll to the module once it updated its allocation size
2502 const gboolean collapse_others = dt_modifier_is(e->state, GDK_SHIFT_MASK) ? FALSE : TRUE;
2505
2506 return TRUE;
2507}
2508
2510{
2511 if(darktable.gui->reset) return;
2512
2515
2516 module->request_mask_display
2517 &= ~(DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL
2518 | DT_DEV_PIXELPIPE_DISPLAY_ANY | DT_DEV_PIXELPIPE_DISPLAY_STICKY);
2519
2520 if(is_active)
2521 module->request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_MASK;
2522
2524
2525 // set the module show mask button too
2526 if(bd->showmask)
2528
2529 ++darktable.gui->reset;
2530 if(GTK_IS_TOGGLE_BUTTON(bd->filter[0].channel_display))
2531 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->filter[0].channel_display), FALSE);
2532 if(GTK_IS_TOGGLE_BUTTON(bd->filter[1].channel_display))
2533 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->filter[1].channel_display), FALSE);
2534 --darktable.gui->reset;
2535
2538}
2539
2541 gboolean *drawn_used, gboolean *parametric_used)
2542{
2547
2548 if(IS_NULL_PTR(module) || IS_NULL_PTR(module->blend_params)) return;
2549
2550 const dt_iop_gui_blend_data_t *bd = (const dt_iop_gui_blend_data_t *)module->blend_data;
2551 gboolean top = FALSE;
2552 gboolean raster = FALSE;
2553 gboolean drawn = FALSE;
2554 gboolean parametric = FALSE;
2556
2557 // look if the user disabled masks modes
2558
2559 // raster mask must be enabled and a raster mask must be selected in the combo
2560 if(!IS_NULL_PTR(bd) && GTK_IS_TOGGLE_BUTTON(bd->raster_enable)
2562 raster = FALSE;
2563
2564 if(!IS_NULL_PTR(bd) && GTK_IS_TOGGLE_BUTTON(bd->masks_enable)
2566 drawn = FALSE;
2567
2568 if(!IS_NULL_PTR(bd) && GTK_IS_TOGGLE_BUTTON(bd->blendif_enable)
2570 parametric = FALSE;
2571
2576}
2577
2578static gboolean _mask_indicator_tooltip(GtkWidget *treeview, gint x, gint y, gboolean kb_mode,
2580{
2581 (void)treeview;
2582 (void)x;
2583 (void)y;
2584 (void)kb_mode;
2585
2586 gboolean res = FALSE;
2587 if(module->mask_indicator)
2588 {
2589 gchar *type = _("unknown mask");
2590 gchar *text;
2593 if(!top_enabled) return FALSE;
2594
2596 type=_("drawn + parametric mask");
2597 else if(drawn_used)
2598 type=_("drawn mask");
2599 else if(parametric_used)
2600 type=_("parametric mask");
2601 else if(raster_used)
2602 type=_("raster mask");
2603 else
2604 return FALSE;
2605 gchar *part1 = g_strdup_printf(_("this module has a '%s'"), type);
2606 gchar *part2 = NULL;
2607 if(raster_used && module->raster_mask.sink.source)
2608 {
2609 gchar *source = dt_history_item_get_name(module->raster_mask.sink.source);
2610 part2 = g_strdup_printf(_("taken from module %s"), source);
2611 dt_free(source);
2612 }
2613
2614 if(part2)
2615 {
2616 gchar *details = g_strdup_printf("%s\n%s", part2, _("click to display (module must be activated first)"));
2617 dt_free(part2);
2618 part2 = details;
2619 }
2620 else
2621 {
2622 part2 = g_strdup(_("click to display (module must be activated first)"));
2623 }
2624
2625 if(part2)
2626 text = g_strconcat(part1, "\n", part2, NULL);
2627 else
2628 text = g_strdup(part1);
2629
2631 res = TRUE;
2632 dt_free(part1);
2633 dt_free(part2);
2634 dt_free(text);
2635 }
2636 return res;
2637}
2638
2640{
2641 if(IS_NULL_PTR(module) || IS_NULL_PTR(module->mask_indicator)) return;
2642
2643 const gboolean support_blending = (module->flags() & IOP_FLAGS_SUPPORTS_BLENDING) == IOP_FLAGS_SUPPORTS_BLENDING;
2644
2645 if(!support_blending || !module->blend_params)
2646 {
2647 gtk_widget_set_visible(GTK_WIDGET(module->mask_indicator), FALSE);
2650 return;
2651 }
2652
2655
2656 const gboolean use_masks = top_enabled && (raster_used || drawn_used || parametric_used);
2657
2659 gtk_widget_set_sensitive(GTK_WIDGET(module->mask_indicator), module->enabled);
2661}
2662
2663gboolean _iop_tooltip_callback(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode,
2664 GtkTooltip *tooltip, gpointer user_data)
2665{
2666 dt_iop_module_t *module = (dt_iop_module_t *)user_data;
2667
2668 const char **des = module->description(module);
2669
2670 if(IS_NULL_PTR(des)) return FALSE;
2671
2673 GtkWidget *grid = gtk_grid_new();
2677
2678 GtkWidget *label = gtk_label_new(des[0] ? des[0] : "");
2682 // if there is no more description, do not add a separator
2683 if(des[1]) dt_gui_add_class(label, "dt_section_label");
2684 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
2685
2689
2690 const char *icon_purpose = "\342\237\263";
2691 const char *icon_input = "\342\207\245";
2692 const char *icon_process = "\342\237\264";
2693 const char *icon_output = "\342\206\246";
2694
2696 const char *ilabs[4] = {_("Purpose"), _("Input"), _("Process"), _("Output")};
2697
2698 for(int k=1; k<5; k++)
2699 {
2700 if(des[k])
2701 {
2702 label = gtk_label_new(icons[k-1]);
2704 gtk_grid_attach(GTK_GRID(grid), label, 0, k, 1, 1);
2706
2707 label = gtk_label_new(ilabs[k-1]);
2709 gtk_grid_attach(GTK_GRID(grid), label, 1, k, 1, 1);
2711
2712 label = gtk_label_new(":");
2714 gtk_grid_attach(GTK_GRID(grid), label, 2, k, 1, 1);
2716
2717 label = gtk_label_new(des[k]);
2719 gtk_grid_attach(GTK_GRID(grid), label, 3, k, 1, 1);
2721 }
2722 }
2723
2724 gtk_box_pack_start(GTK_BOX(vbox), grid, FALSE, FALSE, 0);
2725 gtk_widget_show_all(vbox);
2727
2728 return TRUE;
2729}
2730
2732{
2734 gtk_widget_set_name(GTK_WIDGET(header), "module-header");
2735
2737 GtkWidget *expander = dtgtk_expander_new(header, iopw);
2738 dt_gui_add_class(expander, "dt_module_frame");
2739 dt_gui_add_class(expander, "dt_iop_module");
2740
2744
2745 dt_gui_add_class(pluginui_frame, "dt_plugin_ui");
2746
2747 module->header = header;
2748
2749 /* setup the header box */
2750 g_signal_connect(G_OBJECT(header_evb), "button-press-event", G_CALLBACK(_iop_plugin_header_button_press), module);
2751 g_signal_connect(G_OBJECT(header_evb), "button-release-event", G_CALLBACK(_iop_plugin_header_button_release), module);
2752 g_signal_connect(G_OBJECT(header_evb), "mnemonic-activate", G_CALLBACK(_iop_plugin_header_activate), module);
2754
2755 /* connect mouse button callbacks for focus and presets */
2756 g_signal_connect(G_OBJECT(body_evb), "button-press-event", G_CALLBACK(_iop_plugin_body_button_press), module);
2758
2759 /*
2760 * initialize the header widgets
2761 */
2763
2764 /* init empty place for icon, this is then set in CSS if needed */
2765 char w_name[256] = { 0 };
2766 snprintf(w_name, sizeof(w_name), "iop-panel-icon-%s", module->op);
2769
2770 /* add module label */
2774 gtk_container_add(GTK_CONTAINER(lab), label);
2775 gtk_label_set_mnemonic_widget(GTK_LABEL(label), header_evb);
2776
2777 if((module->flags() & IOP_FLAGS_DEPRECATED) && module->deprecated_msg())
2778 gtk_widget_set_tooltip_text(lab, module->deprecated_msg());
2779 else
2780 {
2781 gtk_widget_set_name(lab, "iop_description");
2783 }
2784
2785 /* add mask preview button */
2787
2790 g_signal_connect(G_OBJECT(hw[IOP_MODULE_MASK]), "button-press-event",
2792 g_signal_connect(G_OBJECT(hw[IOP_MODULE_MASK]), "query-tooltip",
2794 module->mask_indicator = hw[IOP_MODULE_MASK];
2795
2796 /* add multi instances menu button */
2798 module->multimenu_button = GTK_WIDGET(hw[IOP_MODULE_INSTANCE]);
2800 _("multiple instance actions\nright-click creates new instance"));
2801 g_signal_connect(G_OBJECT(hw[IOP_MODULE_INSTANCE]), "button-press-event",
2804 module);
2805
2807
2808 /* add reset button */
2810 module->reset_button = GTK_WIDGET(hw[IOP_MODULE_RESET]);
2811 gtk_widget_set_tooltip_text(GTK_WIDGET(hw[IOP_MODULE_RESET]), _("reset parameters\nctrl+click to reapply any automatic presets"));
2812 g_signal_connect(G_OBJECT(hw[IOP_MODULE_RESET]), "button-press-event",
2815
2816 /* add preset button if module has implementation */
2818 module->presets_button = GTK_WIDGET(hw[IOP_MODULE_PRESETS]);
2819 if(!(module->flags() & IOP_FLAGS_ONE_INSTANCE))
2820 gtk_widget_set_tooltip_text(GTK_WIDGET(hw[IOP_MODULE_PRESETS]), _("presets\nright-click to apply on new instance"));
2821 g_signal_connect(G_OBJECT(hw[IOP_MODULE_PRESETS]), "button-press-event",
2824
2825 /* add enabled button */
2827
2828 dt_gui_add_class(hw[IOP_MODULE_SWITCH], "dt_iop_enable_button");
2831 g_signal_connect(G_OBJECT(hw[IOP_MODULE_SWITCH]), "button-press-event",
2834
2835 module->off = DTGTK_TOGGLEBUTTON(hw[IOP_MODULE_SWITCH]);
2837
2838 /* reorder header, for now, iop are always in the right panel */
2839 for(int i = 0; i <= IOP_MODULE_LABEL; i++)
2840 {
2841 if(hw[i])
2842 gtk_box_pack_start(GTK_BOX(header), hw[i], FALSE, FALSE, 0);
2843 }
2844 for(int i = IOP_MODULE_LAST - 1; i > IOP_MODULE_LABEL; i--)
2845 {
2846 if(hw[i])
2847 gtk_box_pack_end(GTK_BOX(header), hw[i], FALSE, FALSE, 0);
2848 }
2849
2850 dt_gui_add_help_link(header, dt_get_help_url("module_header"));
2851 // for the module label, point to module specific help page
2853
2856
2857 // show deprecated message if any
2858 if(module->deprecated_msg())
2859 {
2860 GtkWidget *lb = gtk_label_new(module->deprecated_msg());
2863 dt_gui_add_class(lb, "dt_warning");
2865 gtk_widget_show(lb);
2866 }
2867
2868 /* initialize blending state if supported; the detached widget is hosted by the masks lib */
2871 dt_gui_add_class(module->widget, "dt_plugin_ui_main");
2874
2875 module->expander = expander;
2878
2879 /* update header */
2881
2884
2886}
2887
2892
2894{
2895 // return gtkframe (pluginui_frame)
2897}
2898
2899void dt_iop_nap(int32_t usec)
2900{
2901 if(usec <= 0) return;
2902
2903 // relinquish processor
2904 sched_yield();
2905
2906 // additionally wait the given amount of time
2907 g_usleep(usec);
2908}
2909
2911{
2912 return module->bypass_cache;
2913}
2914
2916{
2917 module->bypass_cache = state;
2918
2919 if(state && module->dev)
2920 {
2921 // Disable other modules bypass if set.
2922 for(GList *iop = g_list_last(module->dev->iop);
2923 iop;
2924 iop = g_list_previous(iop))
2925 {
2926 dt_iop_module_t *current = (dt_iop_module_t *)iop->data;
2927 if(current != module && current->bypass_cache) current->bypass_cache = FALSE;
2928 }
2929 }
2930}
2931
2932
2937
2939{
2940 dt_iop_module_t *result = NULL;
2941
2942 for(GList *modules = iop_list; modules; modules = g_list_next(modules))
2943 {
2945 if(strcmp(mod->op, op) == 0)
2946 {
2947 result = mod;
2948 break;
2949 }
2950 }
2951
2952 return result;
2953}
2954
2959
2960int dt_iop_get_module_flags(const char *op)
2961{
2963 while(modules)
2964 {
2965 dt_iop_module_so_t *module = (dt_iop_module_so_t *)modules->data;
2966 if(!strcmp(module->op, op)) return module->flags();
2968 }
2969 return 0;
2970}
2971
2972// to be called before issuing any query based on memory.darktable_iop_names
2974{
2975 if(IS_NULL_PTR(darktable.iop)) return;
2976
2977 // Faster than building a huge VALUES string: reuse a prepared statement and bind per module.
2981 "INSERT INTO memory.darktable_iop_names (operation, name) VALUES (?1, ?2)",
2982 -1, &stmt, NULL);
2983 if(IS_NULL_PTR(stmt)) return;
2984
2986 for(GList *iop = darktable.iop; iop; iop = g_list_next(iop))
2987 {
2988 dt_iop_module_so_t *module = (dt_iop_module_so_t *)iop->data;
2994 }
2997}
2998
2999const gchar *dt_iop_get_localized_name(const gchar *op)
3000{
3001 // Prepare mapping op -> localized name
3002 static GHashTable *module_names = NULL;
3004 {
3006 for(GList *iop = darktable.iop; iop; iop = g_list_next(iop))
3007 {
3008 dt_iop_module_so_t *module = (dt_iop_module_so_t *)iop->data;
3010 }
3011 }
3012 if(!IS_NULL_PTR(op))
3013 {
3014 return (gchar *)g_hash_table_lookup(module_names, op);
3015 }
3016 else {
3017 return _("ERROR");
3018 }
3019}
3020
3021const gchar *dt_iop_get_localized_aliases(const gchar *op)
3022{
3023 // Prepare mapping op -> localized name
3024 static GHashTable *module_aliases = NULL;
3026 {
3028 for(GList *iop = darktable.iop; iop; iop = g_list_next(iop))
3029 {
3030 dt_iop_module_so_t *module = (dt_iop_module_so_t *)iop->data;
3032 }
3033 }
3034 if(!IS_NULL_PTR(op))
3035 {
3036 return (gchar *)g_hash_table_lookup(module_aliases, op);
3037 }
3038 else {
3039 return _("ERROR");
3040 }
3041}
3042
3044{
3046 gpointer key, value;
3047
3048 g_hash_table_iter_init(&iter, module->raster_mask.source.users);
3050 {
3052
3054
3055 // also fix history entries
3056 for(GList *hiter = module->dev->history; hiter; hiter = g_list_next(hiter))
3057 {
3059 if(hist->module == sink_module)
3061 }
3062 }
3063
3064 module->multi_priority = new_priority;
3065}
3066
3068{
3070 gpointer key, value;
3071
3072 g_hash_table_iter_init(&iter, module->raster_mask.source.users);
3074 {
3075 if(GPOINTER_TO_INT(value) == id)
3076 return TRUE;
3077 }
3078 return FALSE;
3079}
3080
3081dt_iop_module_t *dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
3082{
3084
3085 for(GList *m = modules; m; m = g_list_next(m))
3086 {
3088
3089 if(strcmp(mod->op, operation) == 0
3090 && (mod->multi_priority == multi_priority || multi_priority == -1))
3091 {
3092 mod_ret = mod;
3093 break;
3094 }
3095 }
3096 return mod_ret;
3097}
3098
3099dt_iop_module_t *dt_iop_get_module_by_instance_name(GList *modules, const char *operation, const char *multi_name)
3100{
3102
3103 for(GList *m = modules; m; m = g_list_next(m))
3104 {
3106
3107 if((strcmp(mod->op, operation) == 0)
3108 && ((IS_NULL_PTR(multi_name)) || (strcmp(mod->multi_name, multi_name) == 0)))
3109 {
3110 mod_ret = mod;
3111 break;
3112 }
3113 }
3114 return mod_ret;
3115}
3116
3118{
3119 gboolean is_first = TRUE;
3120 GList *iop = modules;
3121 while(iop)
3122 {
3123 dt_iop_module_t *m = (dt_iop_module_t *)iop->data;
3124 if(!strcmp(m->op, module->op))
3125 {
3126 is_first = (m == module);
3127 break;
3128 }
3129 iop = g_list_next(iop);
3130 }
3131
3132 return is_first;
3133}
3134
3136{
3137 dt_iop_module_t *self = (dt_iop_module_t*)data;
3139}
3140
3141const char **dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process,
3142 const char *output)
3143{
3144 static const char *str_out[5] = {NULL, NULL, NULL, NULL, NULL};
3145
3146 str_out[0] = main_text;
3147 str_out[1] = purpose;
3148 str_out[2] = input;
3149 str_out[3] = process;
3150 str_out[4] = output;
3151
3152 return (const char **)str_out;
3153}
3154
3156{
3157 if(IS_NULL_PTR(action)) return;
3158 dt_iop_module_t *module = (dt_iop_module_t *)action;
3159
3160 if(module->gui_changed) module->gui_changed(module, widget, data);
3161
3163
3165
3166 if(!IS_NULL_PTR(widget) && g_object_get_data(G_OBJECT(widget), "dt-blendop-header-update"))
3168 else
3170}
3171
3172
3174{
3176
3177 for(GList *w = g_list_first(m->widget_list_bh); w; w = g_list_next(w))
3178 {
3179 GtkWidget *widget = (GtkWidget *)w->data;
3180 struct dt_bauhaus_widget_t *bhw = DT_BAUHAUS_WIDGET(widget);
3181 if(IS_NULL_PTR(bhw)) continue;
3182
3183 switch(bhw->type)
3184 {
3185 case DT_BAUHAUS_SLIDER:
3186 switch(bhw->field_type)
3187 {
3189 dt_bauhaus_slider_set(widget, *(float *)bhw->field);
3190 break;
3192 dt_bauhaus_slider_set(widget, *(int *)bhw->field);
3193 break;
3195 dt_bauhaus_slider_set(widget, *(unsigned short *)bhw->field);
3196 break;
3197 default:
3198 fprintf(stderr, "[dt_bauhaus_update_module] unsupported slider data type\n");
3199 }
3200 break;
3202 switch(bhw->field_type)
3203 {
3205 dt_bauhaus_combobox_set_from_value(widget, *(int *)bhw->field);
3206 break;
3208 dt_bauhaus_combobox_set(widget, *(int *)bhw->field);
3209 break;
3211 dt_bauhaus_combobox_set(widget, *(unsigned int *)bhw->field);
3212 break;
3214 dt_bauhaus_combobox_set(widget, *(gboolean *)bhw->field);
3215 break;
3216 default:
3217 fprintf(stderr, "[dt_bauhaus_update_module] unsupported combo data type\n");
3218 }
3219 break;
3220 default:
3221 fprintf(stderr, "[dt_bauhaus_update_module] invalid bauhaus widget type encountered\n");
3222 }
3223 }
3224}
3225
3227{
3229 dt_iop_module_t *module = (dt_iop_module_t *)w->module;
3230 if(IS_NULL_PTR(w->field) || IS_NULL_PTR(module)) return;
3231
3232 switch(w->type)
3233 {
3234 case DT_BAUHAUS_SLIDER:
3235 {
3236 float val = dt_bauhaus_slider_get(widget);
3237 switch(w->field_type)
3238 {
3240 {
3241 float *f = w->field, prevf = *f; *f = val;
3242 if(*f != prevf) dt_iop_gui_changed(module, widget, &prevf);
3243 break;
3244 }
3246 {
3247 int *i = w->field, previ = *i; *i = val;
3248 if(*i != previ) dt_iop_gui_changed(module, widget, &previ);
3249 break;
3250 }
3252 {
3253 unsigned short *s = w->field, prevs = *s; *s = val;
3254 if(*s != prevs) dt_iop_gui_changed(module, widget, &prevs);
3255 break;
3256 }
3257 default:
3258 fprintf(stderr, "[_bauhaus_slider_value_change] unsupported slider data type\n");
3259 }
3260 break;
3261 }
3263 {
3265 switch(w->field_type)
3266 {
3268 {
3269 if(d->active >= 0)
3270 {
3271 const dt_bauhaus_combobox_entry_t *entry = g_ptr_array_index(d->entries, d->active);
3272 int *e = w->field, preve = *e; *e = GPOINTER_TO_INT(entry->data);
3273 if(*e != preve) dt_iop_gui_changed(module, widget, &preve);
3274 }
3275 break;
3276 }
3278 {
3279 int *i = w->field, previ = *i; *i = d->active;
3280 if(*i != previ) dt_iop_gui_changed(module, widget, &previ);
3281 break;
3282 }
3284 {
3285 unsigned int *u = w->field, prevu = *u; *u = d->active;
3286 if(*u != prevu) dt_iop_gui_changed(module, widget, &prevu);
3287 break;
3288 }
3290 {
3291 gboolean *b = w->field, prevb = *b; *b = d->active;
3292 if(*b != prevb) dt_iop_gui_changed(module, widget, &prevb);
3293 break;
3294 }
3295 default:
3296 fprintf(stderr, "[_bauhaus_combobox_set] unsupported combo data type\n");
3297 }
3298 break;
3299 }
3300 default:
3301 fprintf(stderr, "[dt_bauhaus_value_changed_default_callback] invalid bauhaus widget type encountered for %s %s: %i\n", w->label, w->module->name, w->type);
3302 }
3303}
3304
3305// clang-format off
3306// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
3307// vim: shiftwidth=2 expandtab tabstop=2 cindent
3308// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
3309// clang-format on
void dt_accels_remove_shortcut(dt_accels_t *accels, const char *path)
Remove the shortcut object identified by path and all its accels.
void dt_accels_new_virtual_instance_shortcut(dt_accels_t *accels, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gpointer data, GtkAccelGroup *accel_group, const gchar *action_scope, const gchar *action_name)
gchar * dt_accels_build_path(const gchar *scope, const gchar *feature)
void dt_accels_remove_accel(dt_accels_t *accels, const char *path, gpointer data)
Recursively remove all accels for all shortcuts containing path. This is unneeded for accels attached...
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition ashift.c:3153
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define m
Definition basecurve.c:278
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3483
gboolean dt_bauhaus_combobox_set_from_value(GtkWidget *widget, int value)
Definition bauhaus.c:2330
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2301
@ DT_BAUHAUS_COMBOBOX
Definition bauhaus.h:87
@ DT_BAUHAUS_SLIDER
Definition bauhaus.h:86
#define DT_BAUHAUS_WIDGET(obj)
Definition bauhaus.h:60
int width
Definition bilateral.h:1
void dt_develop_blend_init_blend_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:157
dt_develop_blend_colorspace_t dt_develop_blend_default_module_blend_colorspace(dt_iop_module_t *module)
Definition blend.c:135
int dt_develop_blend_version(void)
Definition blend.c:1630
int dt_develop_blend_legacy_params(dt_iop_module_t *module, const void *const old_params, const int old_version, void *new_params, const int new_version, const int length)
Definition blend.c:1694
void dt_develop_blend_get_mask_usage(const dt_iop_module_t *module, const dt_develop_blend_params_t *params, gboolean *top_enabled, gboolean *raster_used, gboolean *drawn_used, gboolean *parametric_used)
Definition blend.c:246
gboolean blend_color_picker_apply(dt_iop_module_t *module, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void dt_iop_gui_init_blending(dt_iop_module_t *module)
Definition blend_gui.c:5023
dt_develop_blend_colorspace_t
Definition blend.h:55
@ DEVELOP_BLEND_CS_NONE
Definition blend.h:56
void dt_iop_gui_update_blending(dt_iop_module_t *module)
Definition blend_gui.c:4336
void dt_iop_gui_blending_lose_focus(dt_iop_module_t *module)
Definition blend_gui.c:4624
void dt_iop_gui_cleanup_blending(dt_iop_module_t *module)
Definition blend_gui.c:4185
void dt_iop_gui_blending_reload_defaults(dt_iop_module_t *module)
Definition blend_gui.c:4685
void dtgtk_button_set_active(GtkDarktableButton *button, gboolean active)
Definition button.c:176
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:134
#define DTGTK_BUTTON(obj)
Definition button.h:39
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_collection_hint_message(const dt_collection_t *collection)
dt_iop_colorspace_type_t
@ IOP_CS_LAB
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
int dt_iop_color_picker_get_ready_data(const dt_iop_module_t *module, GtkWidget **picker, dt_dev_pixelpipe_t **pipe, const dt_dev_pixelpipe_iop_t **piece)
const dt_aligned_pixel_t f
const float top
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
char * key
int type
char * name
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
int dt_conf_key_exists(const char *key)
gboolean dt_conf_key_not_empty(const char *name)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:861
#define dt_control_queue_cursor(cursor)
Definition control.h:135
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
@ DT_DEBUG_PARAMS
Definition darktable.h:736
@ DT_DEBUG_ALWAYS
Definition darktable.h:713
@ DT_DEBUG_DEV
Definition darktable.h:717
@ DT_DEBUG_MASKS
Definition darktable.h:727
#define dt_free(ptr)
Definition darktable.h:456
static gchar * delete_underscore(const char *s)
Definition darktable.h:1083
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
Definition darktable.h:1043
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
Definition darktable.h:893
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
void dt_database_end_transaction_batch(const struct dt_database_t *db)
Definition database.c:4764
void dt_database_begin_transaction_batch(const struct dt_database_t *db)
Definition database.c:4744
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3646
#define dt_database_start_transaction(db)
Definition database.h:77
#define dt_database_release_transaction(db)
Definition database.h:78
#define DT_DEBUG_SQLITE3_BIND_BLOB(a, b, c, d, e)
Definition debug.h:119
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition debug.h:107
#define DT_DEBUG_SQLITE3_BIND_TEXT(a, b, c, d, e)
Definition debug.h:118
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
Definition debug.h:115
void dt_dev_write_history(dt_develop_t *dev, gboolean async)
Thread-safe wrapper around dt_dev_write_history_ext() for dev->image_storage.id.
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:41
#define dt_dev_pixelpipe_rebuild_all(dev)
#define dt_dev_pixelpipe_update_history_main(dev)
void dt_dev_signal_modules_moved(dt_develop_t *dev)
Definition develop.c:1608
void dt_dev_modulegroups_switch_tab(dt_develop_t *dev, dt_iop_module_t *module)
Definition develop.c:1181
void dt_dev_module_remove(dt_develop_t *dev, dt_iop_module_t *module)
Definition develop.c:1289
void dt_dev_undo_start_record(dt_develop_t *dev)
Definition develop.c:1614
gchar * dt_history_item_get_label(const struct dt_iop_module_t *module)
Definition develop.c:1458
void dt_dev_undo_end_record(dt_develop_t *dev)
Definition develop.c:1625
gchar * dt_history_item_get_name(const struct dt_iop_module_t *module)
Definition develop.c:1493
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
Definition develop.h:117
void dtgtk_cairo_paint_module_switch_on(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_presets(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_showmask(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_multiinstance(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_module_switch(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_reset(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
char * dt_exif_xmp_encode(const unsigned char *input, const int len, int *output_len)
Definition exif.cc:2246
GtkWidget * dtgtk_expander_get_header_event_box(GtkDarktableExpander *expander)
Definition expander.c:49
GtkWidget * dtgtk_expander_get_body_event_box(GtkDarktableExpander *expander)
Definition expander.c:63
GtkWidget * dtgtk_expander_get_frame(GtkDarktableExpander *expander)
Definition expander.c:35
GtkWidget * dtgtk_expander_get_body(GtkDarktableExpander *expander)
Definition expander.c:56
void dtgtk_expander_set_expanded(GtkDarktableExpander *expander, gboolean expanded)
Definition expander.c:70
GtkWidget * dtgtk_expander_new(GtkWidget *header, GtkWidget *body)
Definition expander.c:101
#define DTGTK_EXPANDER(obj)
Definition expander.h:30
static guint dt_keys_mainpad_alternatives(const guint key_val)
Remap keypad keys to usual mainpad ones.
Definition gdkkeys.h:113
void dt_gui_menu_popup(GtkMenu *menu, GtkWidget *button, GdkGravity widget_anchor, GdkGravity menu_anchor)
Definition gtk.c:2953
void dt_gui_remove_class(GtkWidget *widget, const gchar *class_name)
Definition gtk.c:143
GtkWidget * dt_gui_container_nth_child(GtkContainer *container, int which)
Definition gtk.c:2892
void dt_capitalize_label(gchar *text)
Definition gtk.c:3150
void dt_gui_add_help_link(GtkWidget *widget, char *link)
Definition gtk.c:2022
void dt_gui_refocus_center()
Definition gtk.c:3234
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnects accels when a text or search entry gets the focus, and reconnects them when it looses it....
Definition gtk.c:3225
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
Definition gtk.c:133
void dt_ui_container_focus_widget(dt_ui_t *ui, const dt_ui_container_t c, GtkWidget *w)
gives a widget focus in the container
Definition gtk.c:1723
#define dt_accels_new_darkroom_action(a, b, c, d, e, f, g)
Definition gtk.h:430
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
gboolean dt_gui_presets_autoapply_for_module(dt_iop_module_t *module)
void dt_gui_presets_popup_menu_show_for_module(dt_iop_module_t *module)
gboolean dt_gui_presets_autogen_enabled()
#define DT_GUI_MODULE(x)
void dt_gui_throttle_cancel(gpointer source)
static gboolean enable(dt_image_t *image)
const char * tooltip
Definition image.h:251
static gboolean _iop_plugin_enable_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer data)
Definition imageop.c:2402
static int default_operation_tags(void)
Definition imageop.c:174
dt_iop_module_t * dt_iop_get_module_from_list(GList *iop_list, const char *op)
Definition imageop.c:2938
static void _gui_reset_callback(GtkButton *button, GdkEventButton *event, dt_iop_module_t *module)
Definition imageop.c:2118
dt_iop_module_t * dt_iop_get_module(const char *op)
Definition imageop.c:2955
static int default_distort_backtransform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count)
Definition imageop.c:277
void dt_iop_set_darktable_iop_table()
Definition imageop.c:2973
static gboolean _gui_multiinstance_callback(GtkButton *button, GdkEventButton *event, gpointer user_data)
Definition imageop.c:1013
static const char * default_aliases(void)
Definition imageop.c:190
void dt_iop_gui_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1998
static void _init_module_so(void *m)
Definition imageop.c:1499
void dt_iop_load_default_params(dt_iop_module_t *module)
Definition imageop.c:137
dt_iop_module_t * dt_iop_get_module_by_instance_name(GList *modules, const char *operation, const char *multi_name)
Definition imageop.c:3099
static int default_distort_transform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count)
Definition imageop.c:266
static gboolean _iop_plugin_header_button_release(GtkWidget *w, GdkEventButton *e, gpointer user_data)
Definition imageop.c:2470
GtkWidget * dt_iop_gui_get_pluginui(dt_iop_module_t *module)
Definition imageop.c:2893
static int default_default_group(void)
Definition imageop.c:162
gboolean dt_iop_is_raster_mask_used(dt_iop_module_t *module, int id)
Definition imageop.c:3067
static void _iop_plugin_header_menu_deactivate(GtkWidget *menu, gpointer user_data)
Definition imageop.c:997
void dt_iop_commit_params(dt_iop_module_t *module, dt_iop_params_t *params, dt_develop_blend_params_t *blendop_params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:1913
void dt_iop_compute_module_hash(dt_iop_module_t *module, GList *masks)
Definition imageop.c:1890
void dt_iop_add_remove_mask_indicator(dt_iop_module_t *module)
Definition imageop.c:2639
void dt_iop_reload_defaults(dt_iop_module_t *module)
Definition imageop.c:1268
void _hash_raster_masks(gpointer key, gpointer value, uint64_t *hash)
Definition imageop.c:1828
void dt_iop_gui_set_expander(dt_iop_module_t *module)
Definition imageop.c:2731
void dt_iop_throttled_history_update(gpointer data)
Definition imageop.c:3135
void dt_iop_compute_blendop_hash(dt_iop_module_t *module, uint64_t hash, GList *masks)
Definition imageop.c:1842
dt_iop_module_t * dt_iop_gui_get_next_visible_module(dt_iop_module_t *module)
Definition imageop.c:782
void dt_iop_init_pipe(struct dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:558
static gboolean _rename_module_key_press(GtkWidget *entry, GdkEventKey *event, dt_iop_module_t *module)
Definition imageop.c:886
static gboolean _iop_plugin_header_activate(GtkWidget *self, gboolean group_cycling, gpointer user_data)
Definition imageop.c:2370
static void _iop_panel_label(dt_iop_module_t *module)
Definition imageop.c:1137
gboolean dt_iop_is_first_instance(GList *modules, dt_iop_module_t *module)
Definition imageop.c:3117
static int default_flags(void)
Definition imageop.c:168
int dt_iop_load_module_so(void *m, const char *libname, const char *module_name)
Definition imageop.c:421
void dt_iop_gui_init(dt_iop_module_t *module)
Definition imageop.c:1229
void dt_iop_commit_blend_params(dt_iop_module_t *module, const dt_develop_blend_params_t *blendop_params)
Definition imageop.c:1667
void dt_iop_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1561
static gboolean _iop_plugin_focus_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer data)
Definition imageop.c:2386
static void _iop_modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out, const dt_iop_roi_t *roi_in)
Definition imageop.c:154
gboolean dt_iop_module_has_raster_mask(const dt_iop_module_t *module)
Definition imageop.c:1636
void dt_iop_gui_update(dt_iop_module_t *module)
Definition imageop.c:2091
const gchar * dt_iop_get_localized_aliases(const gchar *op)
Definition imageop.c:3021
const gchar * dt_iop_get_localized_name(const gchar *op)
Definition imageop.c:2999
void dt_bauhaus_update_module(dt_iop_module_t *self)
Definition imageop.c:3173
static void default_commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:214
static dt_introspection_field_t * default_get_f(const char *name)
Definition imageop.c:311
int dt_iop_load_module(dt_iop_module_t *module, dt_iop_module_so_t *module_so, dt_develop_t *dev)
Definition imageop.c:1550
gboolean _iop_validate_params(dt_introspection_field_t *field, gpointer params, gboolean report)
Definition imageop.c:1707
int dt_iop_load_module_by_so(dt_iop_module_t *module, dt_iop_module_so_t *so, dt_develop_t *dev)
Definition imageop.c:466
static void default_cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:231
static void default_gui_cleanup(dt_iop_module_t *self)
Definition imageop.c:238
static void _display_mask_indicator_callback(GtkToggleButton *bt, dt_iop_module_t *module)
Definition imageop.c:2509
void dt_iop_gui_reset(dt_iop_module_t *module)
Definition imageop.c:2111
static void default_init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:223
gboolean dt_iop_module_needs_mask_history(const dt_iop_module_t *module)
Definition imageop.c:1647
void dt_iop_load_modules_so(void)
Definition imageop.c:1541
void dt_iop_nap(int32_t usec)
Definition imageop.c:2899
static void default_cleanup(dt_iop_module_t *module)
Definition imageop.c:243
void dt_iop_default_init(dt_iop_module_t *module)
Definition imageop.c:316
void _iop_dim_all_but(dt_iop_module_t *module, gboolean dim)
Definition imageop.c:2305
void dt_iop_gui_update_expanded(dt_iop_module_t *module)
Definition imageop.c:2338
void dt_iop_gui_update_header(dt_iop_module_t *module)
Definition imageop.c:1177
void dt_iop_unload_modules_so()
Definition imageop.c:1598
static gboolean _iop_plugin_header_menu_dismiss_idle(gpointer user_data)
Definition imageop.c:987
void dt_iop_gui_set_enable_button(dt_iop_module_t *module)
Definition imageop.c:1205
int default_iop_focus(dt_gui_module_t *m, gboolean toggle)
Definition imageop.c:401
void dt_iop_cleanup_pipe(struct dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece)
Release module-owned resources for one pixelpipe node.
Definition imageop.c:576
static const char ** default_description(struct dt_iop_module_t *self)
Definition imageop.c:185
static void _gui_copy_callback(GtkButton *button, gpointer user_data)
Definition imageop.c:870
gboolean dt_iop_is_visible(dt_iop_module_t *module)
Definition imageop.c:1132
void dt_iop_request_focus(dt_iop_module_t *module)
Definition imageop.c:2169
dt_iop_module_t * dt_iop_gui_get_previous_visible_module(dt_iop_module_t *module)
Definition imageop.c:768
static const char * default_deprecated_msg(void)
Definition imageop.c:195
gboolean dt_iop_is_hidden(dt_iop_module_t *module)
Definition imageop.c:1127
static gboolean default_has_defaults(struct dt_iop_module_t *self)
Definition imageop.c:200
static gboolean _iop_plugin_body_button_press(GtkWidget *w, GdkEventButton *e, gpointer user_data)
Definition imageop.c:2347
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:3141
GtkWidget * dt_iop_gui_get_widget(dt_iop_module_t *module)
Definition imageop.c:2888
gboolean dt_iop_so_is_hidden(dt_iop_module_so_t *module)
Definition imageop.c:1112
static void _gui_set_single_expanded(dt_iop_module_t *module, gboolean expanded)
Definition imageop.c:2260
float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
Definition imageop.c:131
void dt_iop_gui_changed(dt_iop_module_t *action, GtkWidget *widget, gpointer data)
Definition imageop.c:3155
int dt_iop_get_module_flags(const char *op)
Definition imageop.c:2960
static void _iop_color_picker_data_ready_callback(gpointer instance, gpointer user_data)
Definition imageop.c:249
static void _mask_indicator_get_usage(dt_iop_module_t *module, gboolean *top_enabled, gboolean *raster_used, gboolean *drawn_used, gboolean *parametric_used)
Definition imageop.c:2540
static gboolean _iop_plugin_header_child_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
Definition imageop.c:2377
static gboolean _mask_indicator_tooltip(GtkWidget *treeview, gint x, gint y, gboolean kb_mode, GtkTooltip *tooltip, dt_iop_module_t *module)
Definition imageop.c:2578
void dt_iop_gui_set_enable_button_icon(GtkWidget *w, dt_iop_module_t *module)
Definition imageop.c:1188
static gboolean default_runtime_data_hash(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition imageop.c:205
gboolean dt_iop_gui_move_module_before(dt_iop_module_t *module, dt_iop_module_t *module_next, const char *reason)
Move a module before another one and commit the GUI-side effects.
Definition imageop.c:754
void dt_bauhaus_value_changed_default_callback(GtkWidget *widget)
Definition imageop.c:3226
dt_iop_module_t * dt_iop_get_colorout_module(void)
Definition imageop.c:2933
gboolean dt_iop_check_modules_equal(dt_iop_module_t *mod_1, dt_iop_module_t *mod_2)
Definition imageop.c:1818
#define DT_IOP_HEADER_IGNORE_RELEASE
Definition imageop.c:116
static void _presets_popup_callback(GtkButton *button, dt_iop_module_t *module)
Definition imageop.c:2151
static int default_operation_tags_filter(void)
Definition imageop.c:180
#define DT_IOP_HEADER_MENU_DISMISS_CLICK
Definition imageop.c:115
static sqlite3_stmt * _iop_presets_select_stmt
Definition imageop.c:109
static void _iop_gui_widget_gone(gpointer user_data, GObject *where_the_object_was)
Clear GUI pointers that still reference one iop widget being finalized.
Definition imageop.c:1983
static gboolean _rename_module_resize(GtkWidget *entry, GdkEventKey *event, dt_iop_module_t *module)
Definition imageop.c:939
void dt_iop_gui_set_expanded(dt_iop_module_t *module, gboolean expanded, gboolean collapse_others)
Definition imageop.c:2321
static void _gui_delete_callback(GtkButton *button, dt_iop_module_t *module)
Definition imageop.c:628
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
Definition imageop.c:2915
static dt_introspection_t * default_get_introspection(void)
Definition imageop.c:303
gboolean dt_iop_get_cache_bypass(dt_iop_module_t *module)
Definition imageop.c:2910
gboolean dt_iop_gui_move_module_after(dt_iop_module_t *module, dt_iop_module_t *module_prev, const char *reason)
Move a module after another one and commit the GUI-side effects.
Definition imageop.c:761
void dt_iop_set_mask_mode(dt_iop_module_t *module, int mask_mode)
Definition imageop.c:1616
static gboolean _rename_module_idle(gpointer user_data)
Definition imageop.c:862
static gboolean _iop_plugin_header_button_press(GtkWidget *w, GdkEventButton *e, gpointer user_data)
Definition imageop.c:2428
static void _iop_modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
Definition imageop.c:147
gboolean _iop_tooltip_callback(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data)
Definition imageop.c:2663
static void _init_presets(dt_iop_module_so_t *module_so)
Definition imageop.c:1294
void dt_iop_gui_rename_module(dt_iop_module_t *module)
Definition imageop.c:953
dt_iop_module_t * dt_iop_gui_duplicate(dt_iop_module_t *base, gboolean copy_params)
Definition imageop.c:796
gboolean dt_iop_gui_module_is_visible(dt_iop_module_t *module)
Definition imageop.c:734
dt_iop_module_t * dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
Definition imageop.c:3081
gboolean dt_iop_gui_commit_iop_order_change(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable, gboolean write_history, const char *reason)
Commit the GUI-side consequences of an IOP-order change.
Definition imageop.c:740
static void _gui_duplicate_callback(GtkButton *button, gpointer user_data)
Definition imageop.c:878
static void * default_get_p(const void *param, const char *name)
Definition imageop.c:307
static dt_introspection_field_t * default_get_introspection_linear(void)
Definition imageop.c:299
void dt_iop_update_multi_priority(dt_iop_module_t *module, int new_priority)
Definition imageop.c:3043
static void _gui_off_callback(GtkToggleButton *togglebutton, gpointer user_data)
Definition imageop.c:1069
static void _gui_rename_callback(GtkButton *button, dt_iop_module_t *module)
Definition imageop.c:982
#define DT_IOP_HEADER_MENU_OPEN
Definition imageop.c:114
static int default_process(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
Definition imageop.c:289
static gboolean dt_iop_colorspace_is_rgb(const dt_iop_colorspace_type_t cst)
Definition imageop.h:213
#define IOP_GUI_FREE
Definition imageop.h:602
@ IOP_MODULE_ICON
Definition imageop.h:106
@ IOP_MODULE_PRESETS
Definition imageop.h:111
@ IOP_MODULE_RESET
Definition imageop.h:110
@ IOP_MODULE_LABEL
Definition imageop.h:107
@ IOP_MODULE_MASK
Definition imageop.h:108
@ IOP_MODULE_LAST
Definition imageop.h:112
@ IOP_MODULE_SWITCH
Definition imageop.h:105
@ IOP_MODULE_INSTANCE
Definition imageop.h:109
@ IOP_FLAGS_HIDDEN
Definition imageop.h:170
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:168
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
@ IOP_FLAGS_ONE_INSTANCE
Definition imageop.h:172
@ IOP_FLAGS_NO_MASKS
Definition imageop.h:175
@ IOP_GROUP_TECHNICAL
Definition imageop.h:143
#define DT_INTROSPECTION_VERSION
@ DT_INTROSPECTION_TYPE_BOOL
@ DT_INTROSPECTION_TYPE_ENUM
@ DT_INTROSPECTION_TYPE_OPAQUE
@ DT_INTROSPECTION_TYPE_NONE
@ DT_INTROSPECTION_TYPE_ARRAY
@ DT_INTROSPECTION_TYPE_CHAR
@ DT_INTROSPECTION_TYPE_FLOAT
@ DT_INTROSPECTION_TYPE_UNION
@ DT_INTROSPECTION_TYPE_UINT
@ DT_INTROSPECTION_TYPE_USHORT
@ DT_INTROSPECTION_TYPE_INT8
@ DT_INTROSPECTION_TYPE_STRUCT
@ DT_INTROSPECTION_TYPE_FLOATCOMPLEX
@ DT_INTROSPECTION_TYPE_INT
gboolean dt_ioppr_move_iop_after(struct dt_develop_t *dev, dt_iop_module_t *module, dt_iop_module_t *module_prev)
Move a module instance after another module in the pipe.
Definition iop_order.c:2251
gboolean dt_ioppr_move_iop_before(struct dt_develop_t *dev, dt_iop_module_t *module, dt_iop_module_t *module_next)
Move a module instance before another module in the pipe.
Definition iop_order.c:2219
int dt_ioppr_check_iop_order(dt_develop_t *dev, const int32_t imgid, const char *msg)
Debug helper to validate the current order for a develop context.
Definition iop_order.c:2377
static const float x
float *const restrict const size_t k
void dt_masks_iop_use_same_as(struct dt_iop_module_t *module, struct dt_iop_module_t *src)
void dt_masks_reset_form_gui(void)
@ DT_MASKS_EVENT_RESET
Definition masks.h:163
dt_masks_form_t * dt_masks_get_from_id_ext(GList *forms, int id)
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
void dt_masks_form_delete(struct dt_iop_module_t *module, dt_masks_form_t *grp, dt_masks_form_t *form)
void dt_masks_group_update_name(dt_iop_module_t *module)
uint64_t dt_masks_group_get_hash(uint64_t hash, dt_masks_form_t *form)
GList * dt_module_load_modules(const char *subdir, size_t module_size, int(*load_module_so)(void *module, const char *libname, const char *plugin_name), void(*init_module)(void *module), gint(*sort_modules)(gconstpointer a, gconstpointer b))
Definition module.c:36
char * dt_pixelpipe_get_pipe_name(dt_dev_pixelpipe_type_t pipe_type)
void dt_sentry_record_module_usage(const char *category, const char *name)
Definition sentry.c:492
char dt_dev_operation_t[20]
Definition settings.h:38
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:368
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:347
@ DT_SIGNAL_MASK_CHANGED
Definition signal.h:303
@ DT_SIGNAL_DEVELOP_MASKS_GUI_CHANGED
Definition signal.h:307
@ DT_SIGNAL_CONTROL_PICKERDATA_READY
This signal is raised when new color picker data are available in darkroom. no param,...
Definition signal.h:293
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:357
struct _GtkWidget GtkWidget
Definition splash.h:29
const float uint32_t state[4]
const float const float param
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_collection_t * collection
Definition darktable.h:781
GList * iop
Definition darktable.h:761
const struct dt_database_t * db
Definition darktable.h:779
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_opencl_t * opencl
Definition darktable.h:785
int32_t unmuted
Definition darktable.h:760
struct dt_develop_t * develop
Definition darktable.h:770
GtkAccelGroup * darkroom_accels
Definition bauhaus.h:130
gpointer data
Definition bauhaus.h:137
char label[256]
Definition bauhaus.h:186
dt_bauhaus_data_t data
Definition bauhaus.h:218
dt_gui_module_t *gpointer field
Definition bauhaus.h:181
dt_introspection_type_t field_type
Definition bauhaus.h:183
dt_bauhaus_type_t type
Definition bauhaus.h:177
struct dt_develop_blend_params_t * blend_params
Definition dev_history.h:55
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
int32_t gui_attached
Definition develop.h:162
struct dt_develop_t::@19 color_picker
Authoritative darkroom color-picker state.
GList * iop
Definition develop.h:279
gboolean update_pending
Definition develop.h:388
GtkWidget * widget
Definition develop.h:384
struct dt_iop_module_t * gui_module
Definition develop.h:165
GList * history
Definition develop.h:275
GList * alliop
Definition develop.h:281
struct dt_iop_module_t *struct dt_iop_color_picker_t * picker
Definition develop.h:383
gboolean enabled
Definition develop.h:387
GList * forms
Definition develop.h:321
void * blend_params
Definition develop.h:307
int32_t reset
Definition gtk.h:172
dt_accels_t * accels
Definition gtk.h:194
GtkMenu * presets_popup_menu
Definition gtk.h:169
GtkWidget * has_scroll_focus
Definition gtk.h:228
dt_ui_t * ui
Definition gtk.h:164
GtkWidget * scroll_to[2]
Definition gtk.h:221
GtkWidget * scroll_to_header_once
Definition gtk.h:222
The dt_gui_module_t type is the intersection between a dt_lib_module_t and a dt_iop_module_t structur...
union dt_introspection_field_t * field
dt_introspection_type_t type
dt_introspection_type_enum_tuple_t * values
dt_introspection_type_t type
union dt_introspection_field_t ** fields
union dt_introspection_field_t ** fields
dt_iop_module_t * self
Definition imageop.c:120
GModule *dt_dev_operation_t op
Definition imageop.h:230
dt_iop_params_t * default_params
Definition imageop.h:307
struct dt_develop_blend_params_t * blend_params
Definition imageop.h:316
struct dt_develop_t * dev
Definition imageop.h:296
gboolean bypass_cache
Definition imageop.h:270
int(* process_plain)(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
Definition imageop.h:373
GtkWidget * expander
Definition imageop.h:345
struct dt_develop_blend_params_t * default_blendop_params
Definition imageop.h:316
int32_t params_size
Definition imageop.h:309
dt_iop_params_t * params
Definition imageop.h:307
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
int inited
Definition opencl.h:232
void dt_telemetry_record_module_usage(const char *category, const char *name)
Definition telemetry.c:422
void dtgtk_togglebutton_set_paint(GtkDarktableToggleButton *button, DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
GtkWidget * dtgtk_togglebutton_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
#define DTGTK_TOGGLEBUTTON(obj)
dt_bauhaus_combobox_data_t combobox
Definition bauhaus.h:160
dt_introspection_type_float_complex_t FloatComplex
dt_introspection_type_header_t header
dt_introspection_type_ushort_t UShort
dt_introspection_type_float_t Float
dt_introspection_type_union_t Union
dt_introspection_type_uint_t UInt
dt_introspection_type_int_t Int
dt_introspection_type_char_t Char
dt_introspection_type_int8_t Int8
dt_introspection_type_array_t Array
dt_introspection_type_enum_t Enum
dt_introspection_type_struct_t Struct
char * dt_get_help_url(char *name)
void dt_ui_container_add_widget(dt_ui_t *ui, const dt_ui_container_t c, GtkWidget *w)
@ DT_UI_CONTAINER_SIZE
@ DT_UI_CONTAINER_PANEL_RIGHT_CENTER