Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
gui/presets.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 Bruce Guenter.
4 Copyright (C) 2010-2012 Henrik Andersson.
5 Copyright (C) 2010-2014, 2018 johannes hanika.
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-2016, 2018-2019 Tobias Ellinghaus.
12 Copyright (C) 2011-2013 Ulrich Pegelow.
13 Copyright (C) 2012, 2020-2021 Aldric Renaudin.
14 Copyright (C) 2012 Ivan Tarozzi.
15 Copyright (C) 2012 José Carlos García Sogo.
16 Copyright (C) 2012, 2017-2018, 2020 parafin.
17 Copyright (C) 2012 Richard Wonka.
18 Copyright (C) 2013, 2018-2021 Pascal Obry.
19 Copyright (C) 2013-2017 Roman Lebedev.
20 Copyright (C) 2013 Simon Spannagel.
21 Copyright (C) 2013 Thomas Pryds.
22 Copyright (C) 2014 Pascal de Bruijn.
23 Copyright (C) 2015 Pedro Côrte-Real.
24 Copyright (C) 2017-2018, 2021 Heiko Bauke.
25 Copyright (C) 2019, 2022-2026 Aurélien PIERRE.
26 Copyright (C) 2019 Jakub Filipowicz.
27 Copyright (C) 2019 Sam Smith.
28 Copyright (C) 2020-2022 Chris Elston.
29 Copyright (C) 2020 darkelectron.
30 Copyright (C) 2020-2021 Diederik Ter Rahe.
31 Copyright (C) 2020 Hanno Schwalm.
32 Copyright (C) 2020 Harold le Clément de Saint-Marcq.
33 Copyright (C) 2020-2021 Hubert Kowalski.
34 Copyright (C) 2020 Tomasz Golinski.
35 Copyright (C) 2021 luzpaz.
36 Copyright (C) 2021 Marco.
37 Copyright (C) 2021 Marco Carrarini.
38 Copyright (C) 2021-2022 Nicolas Auffray.
39 Copyright (C) 2021 Ralf Brown.
40 Copyright (C) 2022 Martin Bařinka.
41 Copyright (C) 2022 Miloš Komarčević.
42
43 darktable is free software: you can redistribute it and/or modify
44 it under the terms of the GNU General Public License as published by
45 the Free Software Foundation, either version 3 of the License, or
46 (at your option) any later version.
47
48 darktable is distributed in the hope that it will be useful,
49 but WITHOUT ANY WARRANTY; without even the implied warranty of
50 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51 GNU General Public License for more details.
52
53 You should have received a copy of the GNU General Public License
54 along with darktable. If not, see <http://www.gnu.org/licenses/>.
55*/
56
57#ifdef HAVE_CONFIG_H
58#include "config.h"
59#include "common/conf.h"
60#endif
61#include "widgets/bauhaus.h"
63#include "history/presets.h"
64#include "control/control.h"
65#include "develop/blend.h"
66#include "develop/develop.h"
67
68#include "gui/application.h"
69#include "gui/presets.h"
70#ifdef GDK_WINDOWING_QUARTZ
71#include "osx/osx.h"
72#endif
73#include <assert.h>
74#include "widgets/dialog.h"
76
79 = { 0., 1. / 8000, 1. / 4000, 1. / 2000, 1. / 1000, 1. / 1000, 1. / 500, 1. / 250,
80 1. / 125, 1. / 60, 1. / 30, 1. / 15, 1. / 15, 1. / 8, 1. / 4, 1. / 2,
81 1, 2, 4, 8, 15, 30, 60, FLT_MAX };
83 = { "0", "1/8000", "1/4000", "1/2000", "1/1000", "1/1000", "1/500", "1/250",
84 "1/125", "1/60", "1/30", "1/15", "1/15", "1/8", "1/4", "1/2",
85 "1\"", "2\"", "4\"", "8\"", "15\"", "30\"", "60\"", "+" };
88 = { 0, 0.5, 0.7, 1.0, 1.4, 2.0, 2.8, 4.0, 5.6, 8.0, 11.0, 16.0, 22.0, 32.0, 45.0, 64.0, 90.0, 128.0, FLT_MAX };
90 = { "f/0", "f/0.5", "f/0.7", "f/1.0", "f/1.4", "f/2", "f/2.8", "f/4", "f/5.6", "f/8",
91 "f/11", "f/16", "f/22", "f/32", "f/45", "f/64", "f/90", "f/128", "f/+" };
92
94
95// format string and corresponding flag stored into the database
96static const char *_gui_presets_format_value_str[5]
97 = { N_("non-raw"), N_("raw"), N_("HDR"), N_("monochrome"), N_("color") };
99
100// this is also called for non-gui applications linking to libansel!
101// so beware, don't use any dt_gui_get_global() stuff here .. (or change this behaviour in darktable.c)
103{
104 // Avoid regenerating all auto-presets on every startup when the build and UI language are unchanged.
105 // This cuts a large number of INSERTs during module load without altering behavior across upgrades.
106 gchar *lang = dt_conf_get_string("ui_last/gui_language");
107 if(IS_NULL_PTR(lang)) lang = g_strdup("");
108 gchar *sig = g_strdup_printf("%s|%s", darktable_package_version, lang);
109 gchar *prev = dt_conf_get_string("ui_last/presets_autogen_signature");
110 _gui_presets_autogen_enabled = !(prev && !g_strcmp0(prev, sig));
111 dt_conf_set_string("ui_last/presets_autogen_signature", sig);
112 dt_free(prev);
113 dt_free(sig);
114 dt_free(lang);
115
116 // remove auto generated presets from plugins, not the user included ones.
118 {
120 }
121}
122
127
129{
130 /* Every statement this used to finalise belongs to database/preset_repository.c now,
131 * and is released with the rest of its cache. */
133}
134
135void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version,
136 const void *params, const int32_t params_size,
137 const int32_t enabled)
138{
139 // DEVELOP_BLEND_CS_NONE only until _init_presets() (develop/imageop.c) writes the module's own space
140 dt_develop_blend_params_t default_blendop_params;
143 name, op, version, params, params_size,
144 &default_blendop_params, enabled);
145}
146
148 const char *name, dt_dev_operation_t op, const int32_t version,
149 const void *params, const int32_t params_size,
150 const void *blend_params, const int32_t enabled)
151{
153 blend_params, sizeof(dt_develop_blend_params_t),
155}
156
157static gchar *_get_active_preset_name(dt_iop_module_t *module, int *writeprotect)
158{
159 // if we sort by writeprotect DESC then in case user copied the writeprotected preset
160 // then the preset name returned will be writeprotected and thus not deletable
161 // sorting ASC prefers user created presets. (the repository does that ordering)
162 GList *presets = dt_preset_repository_list_for_iop(module->op, module->version());
163
164 gchar *name = NULL;
165 for(GList *l = presets; l; l = g_list_next(l))
166 {
167 const dt_module_preset_t *p = (const dt_module_preset_t *)l->data;
168
169 if(!memcmp(module->params, p->op_params, MIN(p->op_params_size, module->params_size))
170 && !memcmp(module->blend_params, p->blendop_params,
171 MIN(p->blendop_params_size, (int)sizeof(dt_develop_blend_params_t)))
172 && module->enabled == p->enabled)
173 {
174 name = g_strdup(p->name);
175 *writeprotect = p->writeprotect;
176 break;
177 }
178 }
179 g_list_free_full(presets, dt_module_preset_free);
180 return name;
181}
182
183static void _menuitem_delete_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
184{
185 int writeprotect = -1;
186 gchar *name = _get_active_preset_name(module, &writeprotect);
187 if(IS_NULL_PTR(name)) return;
188
189 if(writeprotect)
190 {
191 dt_control_log(_("preset `%s' is write-protected, can't delete!"), name);
192 dt_free(name);
193 return;
194 }
195
196 gint res = GTK_RESPONSE_YES;
197
198 if(dt_conf_get_bool("plugins/lighttable/preset/ask_before_delete_preset"))
199 {
201 GtkWidget *dialog
202 = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
203 GTK_BUTTONS_YES_NO, _("do you really want to delete the preset `%s'?"), name);
204#ifdef GDK_WINDOWING_QUARTZ
206#endif
207 gtk_window_set_title(GTK_WINDOW(dialog), _("delete preset?"));
208 res = gtk_dialog_run(GTK_DIALOG(dialog));
209 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
210 gtk_widget_destroy(dialog);
211 dt_gui_refocus_parent(dialog_parent);
212 }
213
214 if(res == GTK_RESPONSE_YES)
215 dt_lib_presets_remove(name, module->op, module->version());
216
217 dt_free(name);
218}
220{
221 dt_gui_store_last_preset(gtk_entry_get_text(g->name));
222}
223
224static void _edit_preset_response(GtkDialog *dialog, gint response_id, dt_gui_presets_edit_dialog_t *g)
225{
226 if(response_id == GTK_RESPONSE_OK)
227 {
228 // we want to save the preset in the database
229
230 // we verify eventual name collisions
231 const gchar *name = gtk_entry_get_text(g->name);
232 if(((g->old_id >= 0) && (strcmp(g->original_name, name) != 0)) || (g->old_id < 0))
233 {
234 if(IS_NULL_PTR(name) || *name == '\0' || strcmp(_("new preset"), name) == 0)
235 {
236 // show error dialog
237 GtkWidget *dlg_changename
238 = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
239 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("please give preset a name"));
240#ifdef GDK_WINDOWING_QUARTZ
241 dt_osx_disallow_fullscreen(dlg_changename);
242#endif
243
244 gtk_window_set_title(GTK_WINDOW(dlg_changename), _("unnamed preset"));
245
246 gtk_dialog_run(GTK_DIALOG(dlg_changename));
247 gtk_widget_destroy(dlg_changename);
248 return;
249 }
250
251 // editing existing preset with different name or store new preset -> check for a preset with the same
252 // name:
253 if(dt_preset_repository_module_preset_exists(g->operation, g->op_version, name))
254 {
255 // show overwrite question dialog
256 GtkWidget *dlg_overwrite = gtk_message_dialog_new(
257 GTK_WINDOW(dialog), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
258 GTK_BUTTONS_YES_NO, _("preset `%s' already exists.\ndo you want to overwrite?"), name);
259#ifdef GDK_WINDOWING_QUARTZ
260 dt_osx_disallow_fullscreen(dlg_overwrite);
261#endif
262
263 gtk_window_set_title(GTK_WINDOW(dlg_overwrite), _("overwrite preset?"));
264
265 const gint dlg_ret = gtk_dialog_run(GTK_DIALOG(dlg_overwrite));
266 gtk_widget_destroy(dlg_overwrite);
267
268 // if result is BUTTON_NO or ESCAPE keypress exit without destroying dialog, to permit other name
269 if(dlg_ret == GTK_RESPONSE_YES)
270 {
271 // we remove the preset that will be overwrite
272 dt_lib_presets_remove(name, g->operation, g->op_version);
273 }
274 else
275 return;
276 }
277 }
278
279 int format = 0;
280 for(int k = 0; k < 5; k++)
281 format += gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->format_btn[k])) * _gui_presets_format_flag[k];
282 format ^= DT_PRESETS_FOR_NOT;
283
284 // commit all the user input fields
285 const dt_preset_conditions_t conditions
286 = { .name = (gchar *)name,
287 .description = (gchar *)gtk_entry_get_text(g->description),
288 .model = (gchar *)gtk_entry_get_text(GTK_ENTRY(g->model)),
289 .maker = (gchar *)gtk_entry_get_text(GTK_ENTRY(g->maker)),
290 .lens = (gchar *)gtk_entry_get_text(GTK_ENTRY(g->lens)),
291 .iso_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(g->iso_min)),
292 .iso_max = gtk_spin_button_get_value(GTK_SPIN_BUTTON(g->iso_max)),
293 .exposure_min = dt_gui_presets_exposure_value[dt_bauhaus_combobox_get(g->exposure_min)],
294 .exposure_max = dt_gui_presets_exposure_value[dt_bauhaus_combobox_get(g->exposure_max)],
295 .aperture_min = dt_gui_presets_aperture_value[dt_bauhaus_combobox_get(g->aperture_min)],
296 .aperture_max = dt_gui_presets_aperture_value[dt_bauhaus_combobox_get(g->aperture_max)],
297 .focal_length_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(g->focal_length_min)),
298 .focal_length_max = gtk_spin_button_get_value(GTK_SPIN_BUTTON(g->focal_length_max)),
299 .autoapply = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->autoapply)),
300 .filter = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->filter)),
301 .format = format };
302
303 if(g->old_id >= 0)
304 {
305 // we update presets values
306 dt_preset_repository_update_conditions(g->old_id, &conditions);
307 }
308 else if(g->iop)
309 {
310 // we create a new preset
311 dt_preset_repository_insert_with_conditions(&conditions, g->operation, g->op_version,
312 g->iop->params, g->iop->params_size, g->iop->enabled,
313 g->iop->blend_params, sizeof(dt_develop_blend_params_t),
315 }
316 else
317 {
318 // we are in the lib case currently we set set all params to 0
319 dt_preset_repository_insert_with_conditions(&conditions, g->operation, g->op_version,
320 NULL, 0, 0, NULL, 0, 0);
321 }
322
323 if(g->callback) ((void (*)(dt_gui_presets_edit_dialog_t *))g->callback)(g);
324 }
325 else if(response_id == GTK_RESPONSE_YES && g->old_id)
326 {
327 const gchar *name = gtk_entry_get_text(g->name);
328
329 // ask for destination directory
330 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
331 _("select directory"), GTK_WINDOW(dialog), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
332 _("_select as output destination"), _("_cancel"));
333 dt_conf_get_folder_to_file_chooser("ui_last/export_path", GTK_FILE_CHOOSER(filechooser));
334
335 // save if accepted
336 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
337 {
338 char *filedir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
339 dt_presets_save_to_file(g->old_id, name, filedir);
340 dt_control_log(_("preset %s was successfully exported"), name);
341 dt_free(filedir);
342 dt_conf_set_folder_from_file_chooser("ui_last/export_path", GTK_FILE_CHOOSER(filechooser));
343 }
344
345 g_object_unref(GTK_WIDGET(filechooser));
346 return; // we don't close the window so other actions can be performed if needed
347 }
348 else if(response_id == GTK_RESPONSE_REJECT && g->old_id)
349 {
350 dt_gui_presets_confirm_and_delete(GTK_WIDGET(dialog), g->original_name, g->operation, g->old_id);
351
352 if(g->callback) ((void (*)(dt_gui_presets_edit_dialog_t *))g->callback)(g);
353 }
354
355 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
356 gtk_widget_destroy(GTK_WIDGET(dialog));
357 dt_gui_refocus_parent(dialog_parent);
358 dt_free(g->original_name);
359 dt_free(g->module_name);
360 dt_free(g->operation);
361 dt_free(g);
362}
363
364void dt_gui_presets_confirm_and_delete(GtkWidget *parent_dialog, const char *name, const char *module_name, int rowid)
365{
366 if(IS_NULL_PTR(module_name)) return;
367
368 // This means with want to remove the preset
369 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(parent_dialog), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
370 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
371 _("do you really want to delete the preset `%s'?"), name);
372#ifdef GDK_WINDOWING_QUARTZ
374#endif
375
376 gtk_window_set_title(GTK_WINDOW(dialog), _("delete preset?"));
377 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
378 {
379 // remove the preset from the database
381 }
382 gtk_widget_destroy(dialog);
383}
384
385static void _check_buttons_activated(GtkCheckButton *button, dt_gui_presets_edit_dialog_t *g)
386{
387 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->autoapply))
388 || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->filter)))
389 {
390 gtk_widget_set_visible(GTK_WIDGET(g->details), TRUE);
391 gtk_widget_set_no_show_all(GTK_WIDGET(g->details), FALSE);
392 gtk_widget_show_all(GTK_WIDGET(g->details));
393 gtk_widget_set_no_show_all(GTK_WIDGET(g->details), TRUE);
394 }
395 else
396 gtk_widget_set_visible(GTK_WIDGET(g->details), FALSE);
397}
398
399static void _presets_show_edit_dialog(dt_gui_presets_edit_dialog_t *g, gboolean allow_name_change,
400 gboolean allow_desc_change, gboolean allow_remove)
401{
402 /* Create the widgets */
403 char title[1024];
404 snprintf(title, sizeof(title), _("edit `%s' for module `%s'"), g->original_name, g->module_name);
405 GtkWidget *dialog = gtk_dialog_new_with_buttons
406 (title, g->parent, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
407 _("_cancel"), GTK_RESPONSE_CANCEL, _("_export..."), GTK_RESPONSE_YES,
408 _("delete"), GTK_RESPONSE_REJECT, _("_ok"), GTK_RESPONSE_OK, NULL);
409 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
410
411#ifdef GDK_WINDOWING_QUARTZ
413#endif
414 GtkContainer *content_area = GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
415 GtkBox *box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING));
416 gtk_container_add(content_area, GTK_WIDGET(box));
417
418 g->name = GTK_ENTRY(gtk_entry_new());
419 dt_accels_disconnect_on_text_input(GTK_WIDGET(g->name));
420 gtk_entry_set_text(g->name, g->original_name);
421 if(allow_name_change)
422 gtk_entry_set_activates_default(g->name, TRUE);
423 else
424 gtk_widget_set_sensitive(GTK_WIDGET(g->name), FALSE);
425 gtk_box_pack_start(box, GTK_WIDGET(g->name), FALSE, FALSE, 0);
426 gtk_widget_set_tooltip_text(GTK_WIDGET(g->name), _("name of the preset"));
427
428 g->description = GTK_ENTRY(gtk_entry_new());
429 dt_accels_disconnect_on_text_input(GTK_WIDGET(g->description));
430 if(allow_desc_change)
431 gtk_entry_set_activates_default(g->description, TRUE);
432 else
433 gtk_widget_set_sensitive(GTK_WIDGET(g->description), FALSE);
434 gtk_box_pack_start(box, GTK_WIDGET(g->description), FALSE, FALSE, 0);
435 gtk_widget_set_tooltip_text(GTK_WIDGET(g->description), _("description or further information"));
436
437 g->autoapply
438 = GTK_CHECK_BUTTON(gtk_check_button_new_with_label(_("auto apply this preset to matching images")));
439 gtk_box_pack_start(box, GTK_WIDGET(g->autoapply), FALSE, FALSE, 0);
440 g->filter
441 = GTK_CHECK_BUTTON(gtk_check_button_new_with_label(_("only show this preset for matching images")));
442 gtk_widget_set_tooltip_text(GTK_WIDGET(g->filter), _("be very careful with this option. "
443 "this might be the last time you see your preset."));
444 gtk_box_pack_start(box, GTK_WIDGET(g->filter), FALSE, FALSE, 0);
445 if(IS_NULL_PTR(g->iop))
446 {
447 // lib usually don't support autoapply
448 gtk_widget_set_no_show_all(GTK_WIDGET(g->autoapply), !dt_presets_module_can_autoapply(g->module_name));
449 // for libs, we don't want the filtering option as it's not implemented...
450 gtk_widget_set_no_show_all(GTK_WIDGET(g->filter), TRUE);
451 }
452 g_signal_connect(G_OBJECT(g->autoapply), "toggled", G_CALLBACK(_check_buttons_activated), g);
453 g_signal_connect(G_OBJECT(g->filter), "toggled", G_CALLBACK(_check_buttons_activated), g);
454
455 int line = 0;
456 g->details = gtk_grid_new();
457 gtk_grid_set_row_spacing(GTK_GRID(g->details), DT_GUI_BOX_SPACING);
458 gtk_grid_set_column_spacing(GTK_GRID(g->details), DT_GUI_BOX_SPACING);
459 gtk_box_pack_start(box, GTK_WIDGET(g->details), TRUE, TRUE, 0);
460
461 GtkWidget *label = NULL;
462
463 // model, maker, lens
464 g->model = gtk_entry_new();
466 gtk_widget_set_hexpand(GTK_WIDGET(g->model), TRUE);
467 /* xgettext:no-c-format */
468 gtk_widget_set_tooltip_text(g->model, _("string to match model (use % as wildcard)"));
469 label = gtk_label_new(_("model"));
470 gtk_widget_set_halign(label, GTK_ALIGN_START);
471 gtk_grid_attach(GTK_GRID(g->details), label, 0, line++, 1, 1);
472 gtk_grid_attach_next_to(GTK_GRID(g->details), g->model, label, GTK_POS_RIGHT, 2, 1);
473
474 g->maker = gtk_entry_new();
476 /* xgettext:no-c-format */
477 gtk_widget_set_tooltip_text(g->maker, _("string to match maker (use % as wildcard)"));
478 label = gtk_label_new(_("maker"));
479 gtk_widget_set_halign(label, GTK_ALIGN_START);
480 gtk_grid_attach(GTK_GRID(g->details), label, 0, line++, 1, 1);
481 gtk_grid_attach_next_to(GTK_GRID(g->details), g->maker, label, GTK_POS_RIGHT, 2, 1);
482
483 g->lens = gtk_entry_new();
485 /* xgettext:no-c-format */
486 gtk_widget_set_tooltip_text(g->lens, _("string to match lens (use % as wildcard)"));
487 label = gtk_label_new(_("lens"));
488 gtk_widget_set_halign(label, GTK_ALIGN_START);
489 gtk_grid_attach(GTK_GRID(g->details), label, 0, line++, 1, 1);
490 gtk_grid_attach_next_to(GTK_GRID(g->details), g->lens, label, GTK_POS_RIGHT, 2, 1);
491
492 // iso
493 label = gtk_label_new(_("ISO"));
494 gtk_widget_set_halign(label, GTK_ALIGN_START);
495 g->iso_min = gtk_spin_button_new_with_range(0, FLT_MAX, 100);
496 gtk_widget_set_tooltip_text(g->iso_min, _("minimum ISO value"));
497 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(g->iso_min), 0);
498 g->iso_max = gtk_spin_button_new_with_range(0, FLT_MAX, 100);
499 gtk_widget_set_tooltip_text(g->iso_max, _("maximum ISO value"));
500 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(g->iso_max), 0);
501 gtk_grid_attach(GTK_GRID(g->details), label, 0, line++, 1, 1);
502 gtk_grid_attach_next_to(GTK_GRID(g->details), g->iso_min, label, GTK_POS_RIGHT, 1, 1);
503 gtk_grid_attach_next_to(GTK_GRID(g->details), g->iso_max, g->iso_min, GTK_POS_RIGHT, 1, 1);
504
505 // exposure
506 label = gtk_label_new(_("exposure"));
507 gtk_widget_set_halign(label, GTK_ALIGN_START);
510 gtk_widget_set_tooltip_text(g->exposure_min, _("minimum exposure time"));
511 gtk_widget_set_tooltip_text(g->exposure_max, _("maximum exposure time"));
512 for(int k = 0; k < dt_gui_presets_exposure_value_cnt; k++)
514 for(int k = 0; k < dt_gui_presets_exposure_value_cnt; k++)
516 gtk_grid_attach(GTK_GRID(g->details), label, 0, line++, 1, 1);
517 gtk_grid_attach_next_to(GTK_GRID(g->details), g->exposure_min, label, GTK_POS_RIGHT, 1, 1);
518 gtk_grid_attach_next_to(GTK_GRID(g->details), g->exposure_max, g->exposure_min, GTK_POS_RIGHT, 1, 1);
519
520 // aperture
521 label = gtk_label_new(_("aperture"));
522 gtk_widget_set_halign(label, GTK_ALIGN_START);
525 gtk_widget_set_tooltip_text(g->aperture_min, _("minimum aperture value"));
526 gtk_widget_set_tooltip_text(g->aperture_max, _("maximum aperture value"));
527 for(int k = 0; k < dt_gui_presets_aperture_value_cnt; k++)
529 for(int k = 0; k < dt_gui_presets_aperture_value_cnt; k++)
531 gtk_grid_attach(GTK_GRID(g->details), label, 0, line++, 1, 1);
532 gtk_grid_attach_next_to(GTK_GRID(g->details), g->aperture_min, label, GTK_POS_RIGHT, 1, 1);
533 gtk_grid_attach_next_to(GTK_GRID(g->details), g->aperture_max, g->aperture_min, GTK_POS_RIGHT, 1, 1);
534
535 // focal length
536 label = gtk_label_new(_("focal length"));
537 gtk_widget_set_halign(label, GTK_ALIGN_START);
538 g->focal_length_min = gtk_spin_button_new_with_range(0, 1000, 10);
539 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(g->focal_length_min), 0);
540 g->focal_length_max = gtk_spin_button_new_with_range(0, 1000, 10);
541 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(g->focal_length_max), 0);
542 gtk_widget_set_tooltip_text(g->focal_length_min, _("minimum focal length"));
543 gtk_widget_set_tooltip_text(g->focal_length_max, _("maximum focal length"));
544 gtk_grid_attach(GTK_GRID(g->details), label, 0, line++, 1, 1);
545 gtk_grid_attach_next_to(GTK_GRID(g->details), g->focal_length_min, label, GTK_POS_RIGHT, 1, 1);
546 gtk_grid_attach_next_to(GTK_GRID(g->details), g->focal_length_max, g->focal_length_min, GTK_POS_RIGHT, 1, 1);
547
548 // raw/hdr/ldr/mono/color
549 label = gtk_label_new(_("format"));
550 gtk_widget_set_halign(label, GTK_ALIGN_START);
551 gtk_grid_attach(GTK_GRID(g->details), label, 0, line, 1, 1);
552 gtk_widget_set_tooltip_text(label, _("select image types you want this preset to be available for"));
553
554 for(int i = 0; i < 5; i++)
555 {
556 g->format_btn[i] = gtk_check_button_new_with_label(_(_gui_presets_format_value_str[i]));
557 gtk_grid_attach(GTK_GRID(g->details), g->format_btn[i], 1, line + i, 2, 1);
558 }
559
560 gtk_widget_set_no_show_all(GTK_WIDGET(g->details), TRUE);
561
562 dt_preset_conditions_t c = { 0 };
563 int rowid = -1;
564 if(dt_preset_repository_get_conditions(g->operation, g->op_version, g->original_name, &c, &rowid))
565 {
566 g->old_id = rowid;
567 gtk_entry_set_text(GTK_ENTRY(g->description), c.description);
568 gtk_entry_set_text(GTK_ENTRY(g->model), c.model);
569 gtk_entry_set_text(GTK_ENTRY(g->maker), c.maker);
570 gtk_entry_set_text(GTK_ENTRY(g->lens), c.lens);
571 gtk_spin_button_set_value(GTK_SPIN_BUTTON(g->iso_min), c.iso_min);
572 gtk_spin_button_set_value(GTK_SPIN_BUTTON(g->iso_max), c.iso_max);
573
574 float val = c.exposure_min;
575 int k = 0;
576 for(; k < dt_gui_presets_exposure_value_cnt && val > dt_gui_presets_exposure_value[k]; k++)
577 ;
578 dt_bauhaus_combobox_set(g->exposure_min, k);
579 val = c.exposure_max;
580 for(k = 0; k < dt_gui_presets_exposure_value_cnt && val > dt_gui_presets_exposure_value[k]; k++)
581 ;
582 dt_bauhaus_combobox_set(g->exposure_max, k);
583 val = c.aperture_min;
584 for(k = 0; k < dt_gui_presets_aperture_value_cnt && val > dt_gui_presets_aperture_value[k]; k++)
585 ;
586 dt_bauhaus_combobox_set(g->aperture_min, k);
587 val = c.aperture_max;
588 for(k = 0; k < dt_gui_presets_aperture_value_cnt && val > dt_gui_presets_aperture_value[k]; k++)
589 ;
590 dt_bauhaus_combobox_set(g->aperture_max, k);
591 gtk_spin_button_set_value(GTK_SPIN_BUTTON(g->focal_length_min), c.focal_length_min);
592 gtk_spin_button_set_value(GTK_SPIN_BUTTON(g->focal_length_max), c.focal_length_max);
593 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->autoapply), c.autoapply);
594 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->filter), c.filter);
595 const int format = c.format ^ DT_PRESETS_FOR_NOT;
596 for(k = 0; k < 5; k++)
597 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->format_btn[k]), format & (_gui_presets_format_flag[k]));
599 }
600 else
601 {
602 gtk_entry_set_text(GTK_ENTRY(g->description), "");
603 gtk_entry_set_text(GTK_ENTRY(g->model), "%");
604 gtk_entry_set_text(GTK_ENTRY(g->maker), "%");
605 gtk_entry_set_text(GTK_ENTRY(g->lens), "%");
606 gtk_spin_button_set_value(GTK_SPIN_BUTTON(g->iso_min), 0);
607 gtk_spin_button_set_value(GTK_SPIN_BUTTON(g->iso_max), FLT_MAX);
608
609 float val = 0;
610 int k = 0;
611 for(; k < dt_gui_presets_exposure_value_cnt && val > dt_gui_presets_exposure_value[k]; k++)
612 ;
613 dt_bauhaus_combobox_set(g->exposure_min, k);
614 val = 100000000;
615 for(k = 0; k < dt_gui_presets_exposure_value_cnt && val > dt_gui_presets_exposure_value[k]; k++)
616 ;
617 dt_bauhaus_combobox_set(g->exposure_max, k);
618 val = 0;
619 for(k = 0; k < dt_gui_presets_aperture_value_cnt && val > dt_gui_presets_aperture_value[k]; k++)
620 ;
621 dt_bauhaus_combobox_set(g->aperture_min, k);
622 val = 100000000;
623 for(k = 0; k < dt_gui_presets_aperture_value_cnt && val > dt_gui_presets_aperture_value[k]; k++)
624 ;
625 dt_bauhaus_combobox_set(g->aperture_max, k);
626 gtk_spin_button_set_value(GTK_SPIN_BUTTON(g->focal_length_min), 0);
627 gtk_spin_button_set_value(GTK_SPIN_BUTTON(g->focal_length_max), 1000);
628 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->autoapply), 0);
629 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->filter), 0);
630 for(k = 0; k < 5; k++) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->format_btn[k]), TRUE);
631 }
632
633 // disable remove button if needed
634 if(!allow_remove || g->old_id < 0)
635 {
636 GtkWidget *w = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_REJECT);
637 if(w) gtk_widget_set_sensitive(w, FALSE);
638 }
639 // disable export button if the preset is not already in the database
640 if(g->old_id < 0)
641 {
642 GtkWidget *w = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
643 if(w) gtk_widget_set_sensitive(w, FALSE);
644 }
645
646 // put focus on cancel button if 2 first entries deactivated
647 if(!allow_desc_change && !allow_name_change)
648 {
649 GtkWidget *w = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
650 if(w) gtk_widget_grab_focus(w);
651 }
652
653 g_signal_connect(dialog, "response", G_CALLBACK(_edit_preset_response), g);
654 gtk_widget_show_all(dialog);
655}
656
657void dt_gui_presets_show_iop_edit_dialog(const char *name_in, dt_iop_module_t *module, GCallback final_callback,
658 gpointer data, gboolean allow_name_change, gboolean allow_desc_change,
659 gboolean allow_remove, GtkWindow *parent)
660{
663 g->old_id = -1;
664 g->original_name = g_strdup(name_in);
665 g->iop = module;
666 g->operation = g_strdup(module->op);
667 g->op_version = module->version();
668 g->module_name = g_strdup(module->name());
669 g->callback = final_callback;
670 g->data = data;
671 g->parent = parent;
672
673 _presets_show_edit_dialog(g, allow_name_change, allow_desc_change, allow_remove);
674}
675
676void dt_gui_presets_show_edit_dialog(const char *name_in, const char *module_name, int rowid,
677 GCallback final_callback, gpointer data, gboolean allow_name_change,
678 gboolean allow_desc_change, gboolean allow_remove, GtkWindow *parent)
679{
680 gchar *operation = NULL;
681 int op_version = 0;
682 if(dt_preset_repository_get_identity(rowid, &operation, &op_version))
683 {
686 g->old_id = rowid;
687 g->original_name = g_strdup(name_in);
688 g->operation = operation; // ownership passes to the dialog
689 g->op_version = op_version;
690 g->module_name = g_strdup(module_name);
691 g->callback = final_callback;
692 g->data = data;
693 g->parent = parent;
694
695 _presets_show_edit_dialog(g, allow_name_change, allow_desc_change, allow_remove);
696 }
697}
698
699static void _edit_preset(const char *name_in, dt_iop_module_t *module)
700{
701 gchar *name = NULL;
702 if(IS_NULL_PTR(name_in))
703 {
704 int writeprotect = -1;
705 name = _get_active_preset_name(module, &writeprotect);
706 if(IS_NULL_PTR(name)) return;
707 if(writeprotect)
708 {
709 dt_control_log(_("preset `%s' is write-protected! can't edit it!"), name);
710 dt_free(name);
711 return;
712 }
713 }
714 else
715 name = g_strdup(name_in);
716
718 FALSE, GTK_WINDOW(dt_gui_main_window()));
719 dt_free(name);
720}
721
722static void _menuitem_edit_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
723{
724 _edit_preset(NULL, module);
725}
726
727static void _menuitem_update_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
728{
729 gchar *name = g_object_get_data(G_OBJECT(menuitem), "dt-preset-name");
730
731 gint res = GTK_RESPONSE_YES;
732
733 if(dt_conf_get_bool("plugins/lighttable/preset/ask_before_delete_preset"))
734 {
736 GtkWidget *dialog
737 = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
738 GTK_BUTTONS_YES_NO, _("do you really want to update the preset `%s'?"), name);
739#ifdef GDK_WINDOWING_QUARTZ
741#endif
742 gtk_window_set_title(GTK_WINDOW(dialog), _("update preset?"));
743 res = gtk_dialog_run(GTK_DIALOG(dialog));
744 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
745 gtk_widget_destroy(dialog);
746 dt_gui_refocus_parent(dialog_parent);
747 }
748
749 if(res == GTK_RESPONSE_YES)
750 {
751 // commit all the module fields
752 dt_preset_repository_update_iop_params(module->op, name, module->version(),
753 module->params, module->params_size, module->enabled,
756 }
757}
758
759static void _menuitem_new_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
760{
761 // add new preset
762 dt_lib_presets_remove(_("new preset"), module->op, module->version());
763
764 // then show edit dialog
765 _edit_preset(_("new preset"), module);
766}
767
769{
770 dt_module_preset_t *p = dt_preset_repository_get_iop_preset(module->op, module->version(), name);
771
772 if(p)
773 {
774 if(p->op_params && (p->op_params_size == module->params_size))
775 {
776 memcpy(module->params, p->op_params, p->op_params_size);
777 module->enabled = p->enabled;
778 }
779 if(p->blendop_params && (p->blendop_version == dt_develop_blend_version())
780 && (p->blendop_params_size == (int)sizeof(dt_develop_blend_params_t)))
781 {
782 dt_iop_commit_blend_params(module, p->blendop_params);
783 }
784 else if(p->blendop_params
785 && dt_develop_blend_legacy_params(module, p->blendop_params, p->blendop_version,
787 p->blendop_params_size) == 0)
788 {
789 // do nothing
790 }
791 else
792 {
794 }
795
796 if(!p->writeprotect) dt_gui_store_last_preset(name);
797 }
799
800 dt_iop_gui_update(module);
802 gtk_widget_queue_draw(dt_iop_gui_get_widget(module));
803}
804
805static void _menuitem_pick_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
806{
807 gchar *name = g_object_get_data(G_OBJECT(menuitem), "dt-preset-name");
809}
810
812{
813 dt_image_t *image = &module->dev->image_storage;
814 const gboolean has_matrix = dt_image_is_matrix_correction_supported(image);
815 const char *workflow_preset = (has_matrix) ? _("scene-referred default") : "\t\n";
816
817 int iformat = 0;
818 if(dt_image_needs_rawprepare(image)) iformat |= FOR_RAW;
819 else iformat |= FOR_LDR;
820 if(dt_image_is_hdr(image)) iformat |= FOR_HDR;
821
822 int excluded = 0;
823 if(dt_image_monochrome_flags(image)) excluded |= FOR_NOT_MONO;
824 else excluded |= FOR_NOT_COLOR;
825
826 const dt_preset_match_t match = { .exif_model = image->exif_model,
827 .exif_maker = image->exif_maker,
828 .camera_alias = image->camera_alias,
829 .camera_maker = image->camera_maker,
830 .exif_lens = image->exif_lens,
831 .iso = image->exif_iso,
832 .exposure = image->exif_exposure,
833 .aperture = image->exif_aperture,
834 .focal_length = image->exif_focal_length,
835 // 0: dontcare, 1: ldr, 2: raw plus monochrome & color
836 .format = iformat,
837 .excluded = excluded };
838
839 GList *names = dt_preset_repository_find_autoapply(module->op, module->version(),
840 &match, workflow_preset);
841
842 gboolean applied = FALSE;
843 for(GList *l = names; l; l = g_list_next(l))
844 {
845 dt_gui_presets_apply_preset((const char *)l->data, module);
846 applied = TRUE;
847 }
848 g_list_free_full(names, g_free);
849
850 return applied;
851}
852
853static gboolean _menuitem_button_released_preset(GtkMenuItem *menuitem, GdkEventButton *event,
854 dt_iop_module_t *module)
855{
856 if (event->button == 1 || (module->flags() & IOP_FLAGS_ONE_INSTANCE))
857 {
858 _menuitem_pick_preset(menuitem, module);
859 }
860 else if (event->button == 3)
861 {
862 dt_iop_module_t *new_module = dt_iop_gui_duplicate(module, FALSE);
863 if(new_module)
864 {
865 _menuitem_pick_preset(menuitem, new_module);
866 dt_iop_gui_rename_module(new_module);
867 }
868 }
869
870 return FALSE;
871}
872
873#ifdef HAVE_OPENCL
874static void _opencl_disable_callback(GtkButton *button, dt_iop_module_t *module)
875{
876 gboolean active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(button));
877 gchar *string = g_strdup_printf("/plugins/%s/opencl", module->op);
878 dt_conf_set_bool(string, active);
879 dt_free(string);
880}
881
882static void _cache_disable_callback(GtkButton *button, dt_iop_module_t *module)
883{
884 gboolean active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(button));
885 gchar *string = g_strdup_printf("/plugins/%s/cache", module->op);
886 dt_conf_set_bool(string, active);
887 dt_free(string);
888}
889#endif
890
891// preset names containing '|' are split into a nested submenu hierarchy, the same way
892// style names (src/libs/styles.c, src/gui/actions/styles.c) and tag names
893// (src/libs/tagging.c) are grouped into a tree: every non-empty '|'-separated segment but
894// the last becomes an intermediate submenu, the last segment is the leaf entry. `path` is
895// the '|'-joined prefix built so far and is used as the cache key so a shared prefix reuses
896// the same submenu instead of creating a duplicate.
897static GtkWidget *_presets_get_submenu(GtkWidget *parent, GHashTable *submenus, const gchar *path,
898 const gchar *label)
899{
900 GtkWidget *submenu = g_hash_table_lookup(submenus, path);
901 if(submenu) return submenu;
902
903 GtkWidget *item = gtk_menu_item_new_with_label(label);
904 submenu = gtk_menu_new();
905 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
906 gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
907
908 g_hash_table_insert(submenus, g_strdup(path), submenu);
909 return submenu;
910}
911
913 dt_iop_params_t *params, int32_t params_size,
914 dt_develop_blend_params_t *bl_params, dt_iop_module_t *module,
915 const dt_image_t *image,
916 void (*pick_callback)(GtkMenuItem *, void *),
917 void *callback_data)
918{
919 GtkMenu *menu = dt_gui_get_global()->presets_popup_menu;
920 if(menu) gtk_widget_destroy(GTK_WIDGET(menu));
921 dt_gui_get_global()->presets_popup_menu = GTK_MENU(gtk_menu_new());
923 const gboolean hide_default = dt_conf_get_bool("plugins/darkroom/hide_default_presets");
924 const gboolean default_first = dt_conf_get_bool("modules/default_presets_first");
925
926 GtkWidget *mi;
927 int active_preset = -1, cnt = 0, writeprotect = 0; //, selected_default = 0;
928
929 // order: get shipped defaults first
930 dt_preset_match_t match = { 0 };
931 gboolean have_match = FALSE;
932 if(image)
933 {
934 // only matching if filter is on:
935 int iformat = 0;
937 iformat |= FOR_RAW;
938 else
939 iformat |= FOR_LDR;
940
941 if(dt_image_is_hdr(image))
942 iformat |= FOR_HDR;
943
944 int excluded = 0;
946 excluded |= FOR_NOT_MONO;
947 else
948 excluded |= FOR_NOT_COLOR;
949
950 match.exif_model = image->exif_model;
951 match.exif_maker = image->exif_maker;
952 match.camera_alias = image->camera_alias;
953 match.camera_maker = image->camera_maker;
954 match.exif_lens = image->exif_lens;
955 match.iso = image->exif_iso;
956 match.exposure = image->exif_exposure;
957 match.aperture = image->exif_aperture;
958 match.focal_length = image->exif_focal_length;
959 match.format = iformat;
960 match.excluded = excluded;
961 have_match = TRUE;
962 }
963
964 GList *presets = dt_preset_repository_list_for_menu(op, have_match ? &match : NULL, default_first);
965 // collect all presets for op from db
966 gboolean found = 0;
967 int last_wp = -1;
968 GHashTable *submenus = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
969 for(GList *l = presets; l; l = g_list_next(l))
970 {
971 const dt_module_preset_t *p = (const dt_module_preset_t *)l->data;
972 const int chk_writeprotect = p->writeprotect;
973 if(hide_default && chk_writeprotect)
974 {
975 //skip default module if set to hide them.
976 continue;
977 }
978 if(last_wp == -1)
979 {
980 last_wp = chk_writeprotect;
981 }
982 else if(last_wp != chk_writeprotect)
983 {
984 last_wp = chk_writeprotect;
985 gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
986 }
987 const void *op_params = p->op_params;
988 const int32_t op_params_size = p->op_params_size;
989 const void *blendop_params = p->blendop_params;
990 const int32_t bl_params_size = p->blendop_params_size;
991 const int32_t preset_version = p->op_version;
992 const int32_t enabled = p->enabled;
993 const int32_t isdisabled = (preset_version == version ? 0 : 1);
994 const char *name = p->name;
995 gboolean isdefault = FALSE;
996
997 if(dt_gui_get_global()->last_preset && strcmp(dt_gui_get_global()->last_preset, name) == 0)
998 found = TRUE;
999
1000 if(module
1001 && !memcmp(module->default_params, op_params,
1002 MIN(op_params_size, module->params_size))
1003 && !memcmp(module->default_blendop_params, blendop_params,
1004 MIN(bl_params_size, sizeof(dt_develop_blend_params_t))))
1005 isdefault = TRUE;
1006
1007 gchar **split = g_strsplit(name, "|", -1);
1008 int leaf = -1;
1009 for(int i = 0; split[i]; i++)
1010 if(split[i][0] != '\0') leaf = i;
1011
1012 GtkWidget *parent_menu = GTK_WIDGET(menu);
1013 if(leaf > 0)
1014 {
1015 GString *path = g_string_new(NULL);
1016 for(int i = 0; i < leaf; i++)
1017 {
1018 if(split[i][0] == '\0') continue;
1019 if(path->len > 0) g_string_append_c(path, '|');
1020 g_string_append(path, split[i]);
1021 parent_menu = _presets_get_submenu(parent_menu, submenus, path->str, split[i]);
1022 }
1023 g_string_free(path, TRUE);
1024 }
1025 const gchar *leaf_name = leaf >= 0 ? split[leaf] : name;
1026
1027 gchar *label;
1028 if(isdefault)
1029 label = g_strdup_printf("%s %s", leaf_name, _("(default)"));
1030 else
1031 label = g_strdup(leaf_name);
1032 mi = gtk_menu_item_new_with_label(label);
1033
1034 dt_free(label);
1035 g_strfreev(split);
1036
1037 if(module
1038 && !memcmp(params, op_params, MIN(op_params_size, params_size))
1039 && !memcmp(bl_params, blendop_params, MIN(bl_params_size, sizeof(dt_develop_blend_params_t)))
1040 && module->enabled == enabled)
1041 {
1042 active_preset = cnt;
1043 writeprotect = p->writeprotect;
1044 dt_gui_add_class(mi, "menu-active");
1045 }
1046
1047 if(isdisabled)
1048 {
1049 gtk_widget_set_sensitive(mi, 0);
1050 gtk_widget_set_tooltip_text(mi, _("disabled: wrong module version"));
1051 }
1052 else
1053 {
1054 g_object_set_data_full(G_OBJECT(mi), "dt-preset-name", g_strdup(name), g_free);
1055 if(module)
1056 {
1057 g_signal_connect(G_OBJECT(mi), "button-release-event", G_CALLBACK(_menuitem_button_released_preset),
1058 module);
1059 }
1060 else if(pick_callback)
1061 g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(pick_callback), callback_data);
1062 gtk_widget_set_tooltip_text(mi, p->description);
1063 }
1064 gtk_menu_shell_append(GTK_MENU_SHELL(parent_menu), mi);
1065 cnt++;
1066 }
1067 g_list_free_full(presets, dt_module_preset_free);
1068 g_hash_table_destroy(submenus);
1069
1070 if(cnt > 0) gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1071
1072 if(module)
1073 {
1074 if(active_preset >= 0 && !writeprotect)
1075 {
1076 mi = gtk_menu_item_new_with_label(_("edit this preset.."));
1077 g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_edit_preset), module);
1078 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1079
1080 mi = gtk_menu_item_new_with_label(_("delete this preset"));
1081 g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_delete_preset), module);
1082 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1083 }
1084 else
1085 {
1086 mi = gtk_menu_item_new_with_label(_("store new preset.."));
1087 g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_new_preset), module);
1088 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1089
1090 if(dt_gui_get_global()->last_preset && found)
1091 {
1092 char *markup = g_markup_printf_escaped("%s <span weight='bold'>%s</span>", _("update preset"),
1093 dt_gui_get_global()->last_preset);
1094 mi = gtk_menu_item_new_with_label("");
1095 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(mi))), markup);
1096 g_object_set_data_full(G_OBJECT(mi), "dt-preset-name", g_strdup(dt_gui_get_global()->last_preset), g_free);
1097 g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_update_preset), module);
1098 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1099 dt_free(markup);
1100 }
1101 }
1102 }
1103
1104 // and the parameters entry if needed
1105 if(module && (module->set_preferences))
1106 {
1107 gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1108 if(module->set_preferences) module->set_preferences(GTK_MENU_SHELL(menu), module);
1109 }
1110
1111#ifdef HAVE_OPENCL
1112 // OpenCL prefs
1113 if(module && module->process_cl)
1114 {
1115 gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1116
1117 GtkWidget *item = gtk_check_menu_item_new_with_label(_("Use OpenCL (GPU computing)"));
1118 gtk_widget_set_tooltip_text(item, _("Run this module on GPU if possible.\n"
1119 "Disable if you face recurring issues on GPU with this module.\n"
1120 "Does not require a restart."));
1121 gchar *string = g_strdup_printf("/plugins/%s/opencl", module->op);
1122
1123 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), dt_conf_get_bool(string));
1124 dt_free(string);
1125
1126 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(_opencl_disable_callback), module);
1127 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1128
1129 item = gtk_check_menu_item_new_with_label(_("Cache the GPU output"));
1130 gtk_widget_set_tooltip_text(item, _("Store the output of this module in cache when running on GPU.\n"
1131 "This may prevent some recomputations, at the cost of more memory I/O.\n"
1132 "The trade-off is worth it only for slow modules."));
1133 string = g_strdup_printf("/plugins/%s/cache", module->op);
1134
1135 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), dt_conf_get_bool(string));
1136 dt_free(string);
1137
1138 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(_cache_disable_callback), module);
1139 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1140 }
1141#endif
1142}
1143
1145 int32_t params_size, void *blendop_params,
1146 const dt_image_t *image,
1147 void (*pick_callback)(GtkMenuItem *, void *),
1148 void *callback_data)
1149{
1150 _gui_presets_popup_menu_show_internal(op, version, params, params_size, blendop_params, NULL, image,
1151 pick_callback, callback_data);
1152}
1153
1155{
1156 _gui_presets_popup_menu_show_internal(module->op, module->version(), module->params, module->params_size,
1157 module->blend_params, module, &module->dev->image_storage, NULL, NULL);
1158}
1159
1160void dt_gui_presets_update_mml(const char *name, dt_dev_operation_t op, const int32_t version,
1161 const char *maker, const char *model, const char *lens)
1162{
1163 dt_preset_repository_update_camera(op, version, name, maker, model, lens);
1164}
1165
1166void dt_gui_presets_update_iso(const char *name, dt_dev_operation_t op, const int32_t version,
1167 const float min, const float max)
1168{
1170}
1171
1172void dt_gui_presets_update_av(const char *name, dt_dev_operation_t op, const int32_t version, const float min,
1173 const float max)
1174{
1176}
1177
1178void dt_gui_presets_update_tv(const char *name, dt_dev_operation_t op, const int32_t version, const float min,
1179 const float max)
1180{
1182}
1183
1184void dt_gui_presets_update_fl(const char *name, dt_dev_operation_t op, const int32_t version, const float min,
1185 const float max)
1186{
1188}
1189
1190void dt_gui_presets_update_ldr(const char *name, dt_dev_operation_t op, const int32_t version,
1191 const int ldrflag)
1192{
1194}
1195
1196void dt_gui_presets_update_autoapply(const char *name, dt_dev_operation_t op, const int32_t version,
1197 const int autoapply)
1198{
1200}
1201
1202void dt_gui_presets_update_filter(const char *name, dt_dev_operation_t op, const int32_t version,
1203 const int filter)
1204{
1206}
1207
1208// clang-format off
1209// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1210// vim: shiftwidth=2 expandtab tabstop=2 cindent
1211// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1212// clang-format on
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnect accels while a text or search entry has the focus, and reconnect them when it loses it....
GtkWidget * dt_gui_main_window(void)
void dt_gui_store_last_preset(const char *name)
const char ** description(struct dt_iop_module_t *self)
Definition ashift.c:168
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
size_t params_size(dt_imageio_module_format_t *self)
Definition avif.c:571
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2090
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
void dt_develop_blend_init_blend_parameters(dt_develop_blend_params_t *blend_params, dt_develop_blend_colorspace_t cst)
Definition blend.c:212
int dt_develop_blend_version(void)
Definition blend.c:1714
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:1778
@ DEVELOP_BLEND_CS_NONE
Definition blend.h:54
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
static const float const float const float min
const float max
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
gchar * dt_conf_get_string(const char *name)
Read the stored string for name as a private copy.
void dt_conf_set_string(const char *name, const char *val)
void dt_conf_set_folder_from_file_chooser(const char *name, GtkFileChooser *chooser)
gboolean dt_conf_get_folder_to_file_chooser(const char *name, GtkFileChooser *chooser)
gboolean dt_image_is_matrix_correction_supported(const dt_image_t *img)
int dt_image_monochrome_flags(const dt_image_t *img)
gboolean dt_image_is_hdr(const dt_image_t *img)
gboolean dt_image_needs_rawprepare(const dt_image_t *img)
const char darktable_package_version[]
void dt_control_log(const char *msg,...)
Definition control.c:824
struct dt_develop_t * dt_dev_get_global(void)
Definition darktable.c:528
struct dt_gui_gtk_t * dt_gui_get_global(void)
Definition darktable.c:523
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:43
void dt_gui_refocus_parent(GtkWindow *parent)
Definition dialog.c:64
GHashTable * names
GtkWidget* -> the name the application knows it by.
GtkWidget * window
gboolean enabled
–doc was passed on the command line
const int res
Definition dtpthread.h:351
gboolean dt_gui_presets_autoapply_for_module(dt_iop_module_t *module)
void dt_gui_presets_show_edit_dialog(const char *name_in, const char *module_name, int rowid, GCallback final_callback, gpointer data, gboolean allow_name_change, gboolean allow_desc_change, gboolean allow_remove, GtkWindow *parent)
static void _opencl_disable_callback(GtkButton *button, dt_iop_module_t *module)
static void _edit_preset_final_callback(dt_gui_presets_edit_dialog_t *g)
void dt_gui_presets_show_iop_edit_dialog(const char *name_in, dt_iop_module_t *module, GCallback final_callback, gpointer data, gboolean allow_name_change, gboolean allow_desc_change, gboolean allow_remove, GtkWindow *parent)
void dt_gui_presets_popup_menu_show_for_params(dt_dev_operation_t op, int32_t version, void *params, int32_t params_size, void *blendop_params, const dt_image_t *image, void(*pick_callback)(GtkMenuItem *, void *), void *callback_data)
const int dt_gui_presets_exposure_value_cnt
Definition gui/presets.c:77
static void _menuitem_update_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
void dt_gui_presets_update_filter(const char *name, dt_dev_operation_t op, const int32_t version, const int filter)
void dt_gui_presets_confirm_and_delete(GtkWidget *parent_dialog, const char *name, const char *module_name, int rowid)
static void _presets_show_edit_dialog(dt_gui_presets_edit_dialog_t *g, gboolean allow_name_change, gboolean allow_desc_change, gboolean allow_remove)
void dt_gui_presets_update_ldr(const char *name, dt_dev_operation_t op, const int32_t version, const int ldrflag)
const float dt_gui_presets_aperture_value[]
Definition gui/presets.c:88
const int dt_gui_presets_aperture_value_cnt
Definition gui/presets.c:86
void dt_gui_presets_update_av(const char *name, dt_dev_operation_t op, const int32_t version, const float min, const float max)
static void _menuitem_new_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
void dt_gui_presets_update_fl(const char *name, dt_dev_operation_t op, const int32_t version, const float min, const float max)
static void _cache_disable_callback(GtkButton *button, dt_iop_module_t *module)
static void _menuitem_edit_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
void dt_gui_presets_popup_menu_show_for_module(dt_iop_module_t *module)
void dt_gui_presets_update_iso(const char *name, dt_dev_operation_t op, const int32_t version, const float min, const float max)
void dt_gui_presets_init()
void dt_gui_presets_update_mml(const char *name, dt_dev_operation_t op, const int32_t version, const char *maker, const char *model, const char *lens)
static void _edit_preset_response(GtkDialog *dialog, gint response_id, dt_gui_presets_edit_dialog_t *g)
const char * dt_gui_presets_exposure_value_str[]
Definition gui/presets.c:83
static GtkWidget * _presets_get_submenu(GtkWidget *parent, GHashTable *submenus, const gchar *path, const gchar *label)
void dt_gui_presets_add_with_blendop(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const void *blend_params, const int32_t enabled)
static void _check_buttons_activated(GtkCheckButton *button, dt_gui_presets_edit_dialog_t *g)
void dt_gui_presets_cleanup()
static void _menuitem_pick_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
static void _gui_presets_popup_menu_show_internal(dt_dev_operation_t op, int32_t version, dt_iop_params_t *params, int32_t params_size, dt_develop_blend_params_t *bl_params, dt_iop_module_t *module, const dt_image_t *image, void(*pick_callback)(GtkMenuItem *, void *), void *callback_data)
static gchar * _get_active_preset_name(dt_iop_module_t *module, int *writeprotect)
static void _menuitem_delete_preset(GtkMenuItem *menuitem, dt_iop_module_t *module)
static gboolean _menuitem_button_released_preset(GtkMenuItem *menuitem, GdkEventButton *event, dt_iop_module_t *module)
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled)
static void _edit_preset(const char *name_in, dt_iop_module_t *module)
const char * dt_gui_presets_aperture_value_str[]
Definition gui/presets.c:90
static gboolean _gui_presets_autogen_enabled
Definition gui/presets.c:93
const float dt_gui_presets_exposure_value[]
Definition gui/presets.c:79
void dt_gui_presets_apply_preset(const gchar *name, dt_iop_module_t *module)
static const int _gui_presets_format_flag[5]
Definition gui/presets.c:98
gboolean dt_gui_presets_autogen_enabled()
void dt_gui_presets_update_tv(const char *name, dt_dev_operation_t op, const int32_t version, const float min, const float max)
void dt_gui_presets_update_autoapply(const char *name, dt_dev_operation_t op, const int32_t version, const int autoapply)
static const char * _gui_presets_format_value_str[5]
Definition gui/presets.c:97
#define DT_PRESETS_FOR_NOT
Definition gui/presets.h:70
#define DT_GUI_MODULE(x)
void dt_presets_save_to_file(const int rowid, const char *preset_name, const char *filedir)
gboolean dt_presets_module_can_autoapply(const gchar *operation)
@ FOR_RAW
@ FOR_NOT_MONO
@ FOR_LDR
@ FOR_HDR
@ FOR_NOT_COLOR
char dt_dev_operation_t[20]
The string identifying an operation in the history stack ("exposure", "colorbalancergb",...
Definition history.h:50
void dt_iop_commit_blend_params(dt_iop_module_t *module, const dt_develop_blend_params_t *blendop_params)
Definition imageop.c:1234
void dt_iop_gui_update(dt_iop_module_t *module)
GtkWidget * dt_iop_gui_get_widget(dt_iop_module_t *module)
@ IOP_FLAGS_ONE_INSTANCE
Definition imageop.h:191
void dt_iop_gui_rename_module(dt_iop_module_t *module)
dt_iop_module_t * dt_iop_gui_duplicate(dt_iop_module_t *base, gboolean copy_params)
Create another instance of base, insert it into dev->iop and give it a GUI.
float iso_max
const char * maker
int iso_min
const char * model
void dt_lib_presets_remove(const gchar *preset, const gchar *module_name, int module_version)
Definition lib.c:285
static void pick_callback(GtkMenuItem *menuitem, dt_lib_module_info_t *minfo)
Definition lib.c:337
float *const restrict const size_t k
#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 macros.h:96
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
void dt_osx_disallow_fullscreen(GtkWidget *widget)
Definition osx.mm:105
const char * name
Definition pdf.h:90
void dt_preset_repository_add_iop_preset(const char *name, const char *operation, const int op_version, const void *params, const int params_size, const void *blend_params, const int blend_params_size, const int blendop_version, const int enabled)
Store an IOP preset, blend parameters included, replacing any of the same name.
void dt_module_preset_free(gpointer data)
Release one dt_module_preset_t. Suits g_list_free_full().
void dt_preset_repository_update_range(const char *operation, const int op_version, const char *name, const dt_preset_range_t range, const double min, const double max)
Set the <range>_min / <range>_max pair of (operation, op_version, name).
void dt_preset_repository_delete_shipped(void)
Delete every write-protected preset – the auto-generated ones, dropped at startup so module code can ...
void dt_preset_repository_cleanup(void)
Finalise the cached statements. See dt_colorlabel_repository_cleanup().
void dt_preset_repository_update_iop_params(const char *operation, const char *name, const int op_version, const void *params, const int params_size, const int enabled, const void *blend_params, const int blend_params_size, const int blendop_version)
Replace the module payload of (operation, name), at any version.
dt_module_preset_t * dt_preset_repository_get_iop_preset(const char *operation, const int op_version, const char *name)
One IOP preset by name, blend parameters included, or NULL.
void dt_preset_repository_update_conditions(const int rowid, const dt_preset_conditions_t *c)
Overwrite the conditions of the row at rowid.
GList * dt_preset_repository_list_for_menu(const char *operation, const dt_preset_match_t *match, const gboolean shipped_first)
Presets of operation to offer in a menu, in display order.
void dt_preset_repository_update_camera(const char *operation, const int op_version, const char *name, const char *maker, const char *model, const char *lens)
Set the camera match of (operation, op_version, name).
gboolean dt_preset_repository_get_conditions(const char *operation, const int op_version, const char *name, dt_preset_conditions_t *c, int *rowid)
Read the conditions of (operation, op_version, name).
gboolean dt_preset_repository_module_preset_exists(const char *operation, const int op_version, const char *name)
TRUE when (operation, op_version, name) exists.
GList * dt_preset_repository_list_for_iop(const char *operation, const int op_version)
Every preset of (operation, op_version), with blend parameters.
void dt_preset_repository_delete_by_rowid_unprotected(const int rowid)
Delete the row at rowid unless it is write-protected.
void dt_preset_conditions_free(dt_preset_conditions_t *c)
Release the strings owned by c (not c itself).
gboolean dt_preset_repository_get_identity(const int rowid, gchar **operation, int *op_version)
The (operation, op_version) a rowid belongs to. Returns FALSE if there is none; *operation is newly a...
void dt_preset_repository_update_flag(const char *operation, const int op_version, const char *name, const dt_preset_flag_t flag, const int value)
Set one integer condition of (operation, op_version, name).
void dt_preset_repository_insert_with_conditions(const dt_preset_conditions_t *c, const char *operation, const int op_version, const void *params, const int params_size, const int enabled, const void *blend_params, const int blend_params_size, const int blendop_version)
Create a preset from a full condition set plus its module payload.
GList * dt_preset_repository_find_autoapply(const char *operation, const int op_version, const dt_preset_match_t *match, const char *always_name)
Names of the presets that should be applied to this image automatically.
data.presets: a module's saved parameters, with the conditions under which it auto-applies.
@ DT_PRESET_FLAG_FORMAT
@ DT_PRESET_FLAG_FILTER
@ DT_PRESET_FLAG_AUTOAPPLY
@ DT_PRESET_RANGE_FOCAL_LENGTH
@ DT_PRESET_RANGE_ISO
@ DT_PRESET_RANGE_APERTURE
@ DT_PRESET_RANGE_EXPOSURE
dt_image_t image_storage
Definition develop.h:225
GtkMenu * presets_popup_menu
char * last_preset
float exif_exposure
Definition image.h:367
float exif_iso
Definition image.h:370
char camera_maker[64]
Definition image.h:379
float exif_aperture
Definition image.h:369
float exif_focal_length
Definition image.h:371
char exif_maker[64]
Definition image.h:374
char camera_alias[64]
Definition image.h:381
char exif_lens[128]
Definition image.h:376
char exif_model[64]
Definition image.h:375
dt_iop_params_t * default_params
Definition imageop.h:333
struct dt_develop_blend_params_t * blend_params
Definition imageop.h:349
struct dt_develop_t * dev
Definition imageop.h:311
gboolean enabled
Definition imageop.h:313
struct dt_develop_blend_params_t * default_blendop_params
Definition imageop.h:349
int32_t params_size
Definition imageop.h:335
dt_dev_operation_t op
Definition imageop.h:259
dt_iop_params_t * params
Definition imageop.h:333
The facts about one image that decide whether a preset matches it.
const char * camera_maker
const char * camera_alias
#define MIN(a, b)
Definition thinplate.c:32
#define DT_GUI_BOX_SPACING
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)