Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
preset_repository.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 darktable is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 darktable is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with darktable. If not, see <http://www.gnu.org/licenses/>.
17*/
18
20
21#include "database/database.h"
22#include "database/sql_debug.h"
23#include "system/macros.h"
24#include "system/mem_alloc.h"
25
26#include <float.h>
27#include <math.h>
28#include <sqlite3.h>
29#include <string.h>
30
32{
33 if(IS_NULL_PTR(preset)) return;
34
35 dt_free(preset->name);
36 dt_free(preset->description);
37 dt_free(preset->operation);
38 dt_free(preset->model);
39 dt_free(preset->maker);
40 dt_free(preset->lens);
41 dt_free(preset->multi_name);
42 dt_free(preset->op_params);
43 dt_free(preset->blendop_params);
45}
46
47/* Never NULL: the callers format these with "%s" and bind them with strlen(). */
48static gchar *_column_text(sqlite3_stmt *stmt, const int col)
49{
50 const char *v = (const char *)sqlite3_column_text(stmt, col);
51 return g_strdup(v ? v : "");
52}
53
54/* Unlike _column_text(), a NULL column comes back as NULL. For callers that pass the value
55 * on to something which distinguishes "no value" from "the empty string". */
56static gchar *_column_text_or_null(sqlite3_stmt *stmt, const int col)
57{
58 const char *v = (const char *)sqlite3_column_text(stmt, col);
59 return v ? g_strdup(v) : NULL;
60}
61
62static void *_column_blob(sqlite3_stmt *stmt, const int col, int *size)
63{
64 const int n = sqlite3_column_bytes(stmt, col);
65 const void *src = sqlite3_column_blob(stmt, col);
66 *size = 0;
67 if(n <= 0 || IS_NULL_PTR(src)) return NULL;
68
69 void *copy = g_malloc(n);
70 if(IS_NULL_PTR(copy)) return NULL;
71
72 memcpy(copy, src, n);
73 *size = n;
74 return copy;
75}
76
78{
80 // clang-format off
82 "SELECT op_params, blendop_params, name, description, operation,"
83 " autoapply, model, maker, lens, iso_min, iso_max, exposure_min,"
84 " exposure_max, aperture_min, aperture_max, focal_length_min,"
85 " focal_length_max, op_version, blendop_version, enabled,"
86 " multi_priority, multi_name, filter, def, format "
87 " FROM data.presets"
88 " WHERE rowid = ?1",
89 -1, &stmt, NULL);
90 // clang-format on
92
95 {
96 p = (dt_preset_t *)g_malloc0(sizeof(dt_preset_t));
97 if(p)
98 {
99 p->op_params = _column_blob(stmt, 0, &p->op_params_size);
100 p->blendop_params = _column_blob(stmt, 1, &p->blendop_params_size);
101 p->name = _column_text(stmt, 2);
102 p->description = _column_text(stmt, 3);
103 p->operation = _column_text(stmt, 4);
104 p->autoapply = sqlite3_column_int(stmt, 5);
105 p->model = _column_text(stmt, 6);
106 p->maker = _column_text(stmt, 7);
107 p->lens = _column_text(stmt, 8);
108 p->iso_min = sqlite3_column_double(stmt, 9);
109 p->iso_max = sqlite3_column_double(stmt, 10);
110 p->exposure_min = sqlite3_column_double(stmt, 11);
111 p->exposure_max = sqlite3_column_double(stmt, 12);
112 p->aperture_min = sqlite3_column_double(stmt, 13);
113 p->aperture_max = sqlite3_column_double(stmt, 14);
114 /* REAL columns read as int, as they always have been */
115 p->focal_length_min = sqlite3_column_double(stmt, 15);
116 p->focal_length_max = sqlite3_column_double(stmt, 16);
117 p->op_version = sqlite3_column_int(stmt, 17);
118 p->blendop_version = sqlite3_column_int(stmt, 18);
119 p->enabled = sqlite3_column_int(stmt, 19);
120 p->multi_priority = sqlite3_column_int(stmt, 20);
121 p->multi_name = _column_text(stmt, 21);
122 p->filter = sqlite3_column_double(stmt, 22);
123 p->def = sqlite3_column_double(stmt, 23);
124 p->format = sqlite3_column_double(stmt, 24);
125 }
126 }
128 return p;
129}
130
131/* Bind a string that may legitimately be NULL. The previous code called strlen() on these
132 * unguarded, so a preset file missing an element -- which the XML reader answers with NULL
133 * rather than "" -- crashed on import instead of importing an empty field. */
134static void _bind_text(sqlite3_stmt *stmt, const int idx, const char *value)
135{
136 const char *v = value ? value : "";
138}
139
141{
142 if(IS_NULL_PTR(preset)) return FALSE;
143
145 // clang-format off
147 "INSERT OR REPLACE"
148 " INTO data.presets"
149 " (name, description, operation, autoapply,"
150 " model, maker, lens, iso_min, iso_max, exposure_min, exposure_max,"
151 " aperture_min, aperture_max, focal_length_min, focal_length_max,"
152 " op_params, op_version, blendop_params, blendop_version, enabled,"
153 " multi_priority, multi_name, filter, def, format, writeprotect)"
154 " VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, "
155 " ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, 0)",
156 -1, &stmt, NULL);
157 // clang-format on
158
159 _bind_text(stmt, 1, preset->name);
160 _bind_text(stmt, 2, preset->description);
161 _bind_text(stmt, 3, preset->operation);
162 DT_DEBUG_SQLITE3_BIND_INT(stmt, 4, preset->autoapply);
163 _bind_text(stmt, 5, preset->model);
164 _bind_text(stmt, 6, preset->maker);
165 _bind_text(stmt, 7, preset->lens);
168 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 10, preset->exposure_min);
169 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 11, preset->exposure_max);
170 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 12, preset->aperture_min);
171 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 13, preset->aperture_max);
172 DT_DEBUG_SQLITE3_BIND_INT(stmt, 14, preset->focal_length_min);
173 DT_DEBUG_SQLITE3_BIND_INT(stmt, 15, preset->focal_length_max);
174 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 16, preset->op_params, preset->op_params_size, SQLITE_TRANSIENT);
175 DT_DEBUG_SQLITE3_BIND_INT(stmt, 17, preset->op_version);
176 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 18, preset->blendop_params, preset->blendop_params_size, SQLITE_TRANSIENT);
177 DT_DEBUG_SQLITE3_BIND_INT(stmt, 19, preset->blendop_version);
179 DT_DEBUG_SQLITE3_BIND_INT(stmt, 21, preset->multi_priority);
180 _bind_text(stmt, 22, preset->multi_name);
184
185 const gboolean ok = (sqlite3_step(stmt) == SQLITE_DONE);
187 return ok;
188}
189
190
191/* ---------------------------------------------------------------------------------------
192 * Module presets
193 * ------------------------------------------------------------------------------------- */
194
195/* Three of these run on every preset-menu popup, so they keep their statements, as
196 * libs/lib.c did before. The rest are one per user action. */
197
198/* The two inserts below differ in ONE digit of exposure_max -- 1e8 for a preset created
199 * from the menu, 1e7 for one registered by a module at startup -- and have since they were
200 * written. Reproduced rather than unified: with autoapply=0 the bound is never consulted,
201 * but the edit dialog opens on a just-created preset and shows it, so unifying them is a
202 * user-visible data change and belongs in its own commit. */
203#define _PRESET_COLUMNS \
204 "(name, description, operation, op_version, op_params, blendop_params, " \
205 " blendop_version, enabled, model, maker, lens, iso_min, iso_max, exposure_min, " \
206 " exposure_max, aperture_min, aperture_max, focal_length_min, focal_length_max, " \
207 " writeprotect, autoapply, filter, def, format)"
208
209void dt_module_preset_free(gpointer data)
210{
212 if(IS_NULL_PTR(p)) return;
213 dt_free(p->name);
214 dt_free(p->description);
215 dt_free(p->op_params);
216 // The IOP readers fill this one; a lib preset leaves it NULL. Missing it leaked the blend
217 // blob of every IOP preset row listed by gui/presets.c and libs/lib.c.
218 dt_free(p->blendop_params);
219 dt_free(p);
220}
221
222GList *dt_preset_repository_list_for_module(const char *operation, const int op_version,
223 const gboolean with_description,
224 const gboolean shipped_first)
225{
227 gchar *query = NULL;
228
230 {
231 // clang-format off
232 query = g_strdup_printf("SELECT name, op_params, writeprotect, description"
233 " FROM data.presets"
234 " WHERE operation=?1 AND op_version=?2"
235 " ORDER BY writeprotect %s, LOWER(name), rowid",
236 shipped_first ? "DESC" : "ASC");
237 // clang-format on
239 }
240 else
241 {
242 // clang-format off
244 "SELECT name, op_params, writeprotect FROM data.presets"
245 " WHERE operation=?1 AND op_version=?2",
246 -1, &stmt, NULL);
247 // clang-format on
248 }
249 if(IS_NULL_PTR(stmt))
250 {
251 dt_free(query);
252 return NULL;
253 }
254
256 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, op_version);
257
258 GList *presets = NULL;
259 while(sqlite3_step(stmt) == SQLITE_ROW)
260 {
262 if(p)
263 {
264 p->name = _column_text(stmt, 0);
265 p->op_params = _column_blob(stmt, 1, &p->op_params_size);
266 p->writeprotect = sqlite3_column_int(stmt, 2) != 0;
267 p->description = with_description ? _column_text(stmt, 3) : g_strdup("");
268 p->op_version = op_version;
269 p->rowid = -1;
270 presets = g_list_prepend(presets, p);
271 }
272 }
273
275 dt_free(query); // NULL in the plain branch; dt_free is NULL-safe
276
277 return g_list_reverse(presets); // the ORDER BY is the point; keep it
278}
279
281{
283 // clang-format off
285 "SELECT rowid, op_version, op_params, name FROM data.presets"
286 " WHERE operation=?1"
287 " ORDER BY writeprotect DESC, LOWER(name), rowid",
288 -1, &stmt, NULL);
289 // clang-format on
291
292 GList *presets = NULL;
293 while(sqlite3_step(stmt) == SQLITE_ROW)
294 {
296 if(p)
297 {
298 p->rowid = sqlite3_column_int(stmt, 0);
299 p->op_version = sqlite3_column_int(stmt, 1);
300 p->op_params = _column_blob(stmt, 2, &p->op_params_size);
301 p->name = _column_text(stmt, 3);
302 p->description = g_strdup("");
303 presets = g_list_prepend(presets, p);
304 }
305 }
307
308 /* Reversed so the caller iterates in the order the rows came back, which is what it did
309 * when it stepped the statement itself. */
310 return g_list_reverse(presets);
311}
312
313GList *dt_preset_repository_list_for_version(const char *operation, const int op_version)
314{
316 // clang-format off
318 "SELECT rowid, op_version, op_params, name FROM data.presets"
319 " WHERE operation=?1 AND op_version=?2"
320 " ORDER BY writeprotect DESC, LOWER(name), rowid",
321 -1, &stmt, NULL);
322 // clang-format on
324 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, op_version);
325
326 GList *presets = NULL;
327 while(sqlite3_step(stmt) == SQLITE_ROW)
328 {
330 if(p)
331 {
332 p->rowid = sqlite3_column_int(stmt, 0);
333 p->op_version = sqlite3_column_int(stmt, 1);
334 p->op_params = _column_blob(stmt, 2, &p->op_params_size);
335 p->name = _column_text(stmt, 3);
336 p->description = g_strdup("");
337 presets = g_list_prepend(presets, p);
338 }
339 }
341
342 /* Reversed so the caller iterates in the order the rows came back, which is what it did
343 * when it stepped the statement itself. */
344 return g_list_reverse(presets);
345}
346
347gboolean dt_preset_repository_module_preset_exists(const char *operation, const int op_version,
348 const char *name)
349{
351 // clang-format off
353 "SELECT name FROM data.presets"
354 " WHERE operation = ?1 AND op_version = ?2 AND name = ?3",
355 -1, &stmt, NULL);
356 // clang-format on
358 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, op_version);
360
361 const gboolean found = (sqlite3_step(stmt) == SQLITE_ROW);
363 return found;
364}
365
366int dt_preset_repository_find_rowid(const char *operation, const int op_version, const char *name)
367{
369 // clang-format off
371 "SELECT rowid FROM data.presets"
372 " WHERE name = ?1 AND operation = ?2 AND op_version = ?3",
373 -1, &stmt, NULL);
374 // clang-format on
377 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, op_version);
378
379 int rowid = -1;
382 return rowid;
383}
384
385dt_module_preset_t *dt_preset_repository_get_module_preset(const char *operation, const int op_version,
386 const char *name)
387{
389 // clang-format off
391 "SELECT op_params, writeprotect FROM data.presets"
392 " WHERE operation = ?1 AND op_version = ?2 AND name = ?3",
393 -1, &stmt, NULL);
394 // clang-format on
396 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, op_version);
398
401 {
402 p = g_malloc0(sizeof(dt_module_preset_t));
403 if(p)
404 {
405 p->op_params = _column_blob(stmt, 0, &p->op_params_size);
406 p->writeprotect = sqlite3_column_int(stmt, 1) != 0;
407 p->name = g_strdup(name);
408 p->description = g_strdup("");
409 p->op_version = op_version;
410 p->rowid = -1;
411 }
412 }
414 return p;
415}
416
417void dt_preset_repository_add_module_preset(const char *name, const char *operation,
418 const int op_version, const void *params,
419 const int params_size)
420{
422 // clang-format off
424 "INSERT INTO data.presets " _PRESET_COLUMNS
425 " VALUES (?1, '', ?2, ?3, ?4, NULL, 0, 1, '%', '%', '%', 0, "
426 " 340282346638528859812000000000000000000, 0, 100000000, 0, 100000000, "
427 " 0, 1000, 0, 0, 0, 0, 0)",
428 -1, &stmt, NULL);
429 // clang-format on
432 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, op_version);
436}
437
438void dt_preset_repository_add_shipped_preset(const char *name, const char *operation,
439 const int op_version, const void *params,
440 const int params_size, const int writeprotect)
441{
443 // clang-format off
445 "INSERT INTO data.presets " _PRESET_COLUMNS
446 " VALUES (?1, '', ?2, ?3, ?4, NULL, 0, 1, '%', '%', '%', 0, "
447 " 340282346638528859812000000000000000000, 0, 10000000, 0, 100000000, "
448 " 0, 1000, ?5, 0, 0, 0, 0)",
449 -1, &stmt, NULL);
450 // clang-format on
451 if(IS_NULL_PTR(stmt)) return;
452
455 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, op_version);
457 DT_DEBUG_SQLITE3_BIND_INT(stmt, 5, writeprotect);
460}
461
462void dt_preset_repository_update_module_params(const char *operation, const char *name,
463 const int op_version, const void *params,
464 const int params_size)
465{
467 // clang-format off
469 "UPDATE data.presets SET op_version=?2, op_params=?3"
470 " WHERE name=?4 AND operation=?1",
471 -1, &stmt, NULL);
472 // clang-format on
474 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, op_version);
479}
480
481void dt_preset_repository_set_module_version(const char *operation, const char *name,
482 const int op_version)
483{
486 "UPDATE data.presets SET op_version=?1 WHERE operation=?2 AND name=?3",
487 -1, &stmt, NULL);
488 if(IS_NULL_PTR(stmt)) return;
489
490 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, op_version);
495}
496
497void dt_preset_repository_set_blend_params(const char *operation, const char *name,
498 const int blendop_version, const void *blend_params,
499 const int blend_params_size)
500{
502 // clang-format off
504 "SET blendop_version=?1, blendop_params=?2 "
505 "WHERE operation=?3 AND name=?4",
506 -1, &stmt, NULL);
507 // clang-format on
508 if(IS_NULL_PTR(stmt)) return;
509
510 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, blendop_version);
516}
517
519{
521 // clang-format off
524 "SELECT name, op_version, op_params, blendop_version, blendop_params FROM data.presets WHERE operation = ?1",
525 -1, &stmt, NULL);
526 // clang-format on
527 if(IS_NULL_PTR(stmt)) return NULL;
528
530
531 GList *presets = NULL;
532 while(sqlite3_step(stmt) == SQLITE_ROW)
533 {
535 if(IS_NULL_PTR(p)) break;
536 p->name = _column_text(stmt, 0);
537 p->op_version = sqlite3_column_int(stmt, 1);
538 p->op_params = _column_blob(stmt, 2, &p->op_params_size);
539 p->blendop_version = sqlite3_column_int(stmt, 3);
540 p->blendop_params = _column_blob(stmt, 4, &p->blendop_params_size);
541 p->description = g_strdup("");
542 presets = g_list_prepend(presets, p);
543 }
545
546 return g_list_reverse(presets); // row order, as the cursor loop this replaced saw it
547}
548
549void dt_preset_repository_rename_module_preset(const char *operation, const int op_version,
550 const char *old_name, const char *new_name,
551 const char *description, const void *params,
552 const int params_size)
553{
555 // clang-format off
557 "UPDATE data.presets SET name = ?1, description = ?2, op_params = ?3"
558 " WHERE operation = ?4 AND op_version = ?5 AND name = ?6",
559 -1, &stmt, NULL);
560 // clang-format on
565 DT_DEBUG_SQLITE3_BIND_INT(stmt, 5, op_version);
569}
570
571void dt_preset_repository_duplicate_module_preset(const char *operation, const int op_version,
572 const char *name, const char *new_name)
573{
575 // clang-format off
577 "INSERT INTO data.presets " _PRESET_COLUMNS
578 " SELECT ?1, description, operation, op_version, op_params, blendop_params,"
579 " blendop_version, enabled, model, maker, lens, iso_min, iso_max,"
580 " exposure_min, exposure_max, aperture_min, aperture_max,"
581 " focal_length_min, focal_length_max, 0, autoapply, filter, def, format"
582 " FROM data.presets"
583 " WHERE operation = ?2 AND op_version = ?3 AND name = ?4",
584 -1, &stmt, NULL);
585 // clang-format on
588 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, op_version);
592}
593
594void dt_preset_repository_delete_module_preset(const char *operation, const int op_version,
595 const char *name)
596{
598 // clang-format off
600 "DELETE FROM data.presets"
601 " WHERE name=?1 AND operation=?2 AND op_version=?3 AND writeprotect=0",
602 -1, &stmt, NULL);
603 // clang-format on
604 if(IS_NULL_PTR(stmt)) return;
605
608 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, op_version);
611}
612
614{
616 // clang-format off
618 "DELETE FROM data.presets WHERE operation=?1",
619 -1, &stmt, NULL);
620 // clang-format on
621 if(IS_NULL_PTR(stmt)) return;
622
626}
627
628void dt_preset_repository_update_params_by_rowid(const int rowid, const int op_version,
629 const void *params, const int params_size)
630{
632 // clang-format off
634 "UPDATE data.presets SET op_version=?1, op_params=?2 WHERE rowid=?3",
635 -1, &stmt, NULL);
636 // clang-format on
637 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, op_version);
642}
643
645{
647 // clang-format off
649 "DELETE FROM data.presets WHERE rowid=?1", -1, &stmt, NULL);
650 // clang-format on
654}
655
656
657/* ---------------------------------------------------------------------------------------
658 * Auto-apply conditions
659 * ------------------------------------------------------------------------------------- */
660
661/* One literal query per column, indexed by the enum rather than assembled, so
662 * `grep "iso_min" src/database` still finds the one that writes it. Prepared per call:
663 * the cached statements these replaced were unlocked cross-thread shared state. */
664
665static const char *const _range_query[DT_PRESET_RANGE_LAST] = {
666 [DT_PRESET_RANGE_ISO] = "UPDATE data.presets"
667 " SET iso_min=?1, iso_max=?2"
668 " WHERE operation=?3 AND op_version=?4 AND name=?5",
669 [DT_PRESET_RANGE_APERTURE] = "UPDATE data.presets"
670 " SET aperture_min=?1, aperture_max=?2"
671 " WHERE operation=?3 AND op_version=?4 AND name=?5",
672 [DT_PRESET_RANGE_EXPOSURE] = "UPDATE data.presets"
673 " SET exposure_min=?1, exposure_max=?2"
674 " WHERE operation=?3 AND op_version=?4 AND name=?5",
675 [DT_PRESET_RANGE_FOCAL_LENGTH] = "UPDATE data.presets"
676 " SET focal_length_min=?1, focal_length_max=?2"
677 " WHERE operation=?3 AND op_version=?4 AND name=?5",
678};
679
680static const char *const _flag_query[DT_PRESET_FLAG_LAST] = {
681 [DT_PRESET_FLAG_FORMAT] = "UPDATE data.presets"
682 " SET format=?1"
683 " WHERE operation=?2 AND op_version=?3 AND name=?4",
684 [DT_PRESET_FLAG_AUTOAPPLY] = "UPDATE data.presets"
685 " SET autoapply=?1"
686 " WHERE operation=?2 AND op_version=?3 AND name=?4",
687 [DT_PRESET_FLAG_FILTER] = "UPDATE data.presets"
688 " SET filter=?1"
689 " WHERE operation=?2 AND op_version=?3 AND name=?4",
690};
691
692void dt_preset_repository_update_range(const char *operation, const int op_version, const char *name,
693 const dt_preset_range_t range,
694 const double min, const double max)
695{
697
700 -1, &stmt, NULL);
701 if(IS_NULL_PTR(stmt)) return;
702
706 DT_DEBUG_SQLITE3_BIND_INT(stmt, 4, op_version);
710}
711
712void dt_preset_repository_update_flag(const char *operation, const int op_version, const char *name,
713 const dt_preset_flag_t flag, const int value)
714{
716
719 -1, &stmt, NULL);
720 if(IS_NULL_PTR(stmt)) return;
721
724 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, op_version);
728}
729
730void dt_preset_repository_update_camera(const char *operation, const int op_version, const char *name,
731 const char *maker, const char *model, const char *lens)
732{
734 // clang-format off
736 "UPDATE data.presets"
737 " SET maker='%' || ?1 || '%', model=?2, lens=?3"
738 " WHERE operation=?4 AND op_version=?5 AND name=?6",
739 -1, &stmt, NULL);
740 // clang-format on
741 if(IS_NULL_PTR(stmt)) return;
742
743 /* An empty model or lens means "any", and the auto-apply query matches with LIKE, so it
744 * has to be stored as the wildcard rather than as "". */
747 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, (lens && *lens) ? lens : "%", -1, SQLITE_TRANSIENT);
749 DT_DEBUG_SQLITE3_BIND_INT(stmt, 5, op_version);
753}
754
755
756/* ---------------------------------------------------------------------------------------
757 * IOP presets
758 * ------------------------------------------------------------------------------------- */
759
760/* The predicate shared by the menu and the auto-apply query: does this preset's stored
761 * camera/exposure/format match the image? Bound parameters ?2..?12 throughout, so the
762 * three call sites bind identically. */
763#define _PRESET_MATCH_PREDICATE \
764 "((?2 LIKE model AND ?3 LIKE maker) OR (?4 LIKE model AND ?5 LIKE maker))" \
765 " AND ?6 LIKE lens" \
766 " AND ?7 BETWEEN iso_min AND iso_max" \
767 " AND ?8 BETWEEN exposure_min AND exposure_max" \
768 " AND ?9 BETWEEN aperture_min AND aperture_max" \
769 " AND ?10 BETWEEN focal_length_min AND focal_length_max" \
770 " AND (format = 0 OR (format&?11 != 0 AND ~format&?12 != 0))"
771
772static void _bind_match(sqlite3_stmt *stmt, const dt_preset_match_t *m, const gboolean clamp)
773{
776 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, m->camera_alias, -1, SQLITE_TRANSIENT);
777 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 5, m->camera_maker, -1, SQLITE_TRANSIENT);
779
780 /* The auto-apply path clamps these and the menu path does not. That difference is
781 * inherited and kept: a NaN or an infinity from a broken EXIF block makes every BETWEEN
782 * false, which silently applies nothing -- so the path that decides an image's initial
783 * history guards against it and the one that only draws a menu never bothered. */
784 if(clamp)
785 {
787 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, fmax(0.0, fmin(1000000.0, m->exposure)));
788 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, fmax(0.0, fmin(1000000.0, m->aperture)));
789 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 10, fmax(0.0, fmin(1000000.0, m->focal_length)));
790 }
791 else
792 {
794 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, m->exposure);
795 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, m->aperture);
796 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 10, m->focal_length);
797 }
798
799 DT_DEBUG_SQLITE3_BIND_INT(stmt, 11, m->format);
800 DT_DEBUG_SQLITE3_BIND_INT(stmt, 12, m->excluded);
801}
802
803/* Read the seven-column menu row, or the five-column list row when `description` and the
804 * trailing columns are absent. */
806{
808 if(IS_NULL_PTR(p)) return NULL;
809
810 p->rowid = -1;
811 p->name = _column_text(stmt, 0);
812 p->op_params = _column_blob(stmt, 1, &p->op_params_size);
813 p->writeprotect = sqlite3_column_int(stmt, 2) != 0;
814
816 {
817 p->description = _column_text(stmt, 3);
818 p->blendop_params = _column_blob(stmt, 4, &p->blendop_params_size);
819 p->op_version = sqlite3_column_int(stmt, 5);
820 p->enabled = sqlite3_column_int(stmt, 6);
821 }
822 else
823 {
824 p->description = g_strdup("");
825 p->blendop_params = _column_blob(stmt, 3, &p->blendop_params_size);
826 p->enabled = sqlite3_column_int(stmt, 4);
827 }
828 return p;
829}
830
831void dt_preset_repository_add_iop_preset(const char *name, const char *operation, const int op_version,
832 const void *params, const int params_size,
833 const void *blend_params, const int blend_params_size,
834 const int blendop_version, const int enabled)
835{
837 // clang-format off
839 "INSERT OR REPLACE"
840 " INTO data.presets (name, description, operation, op_version, op_params, enabled,"
841 " blendop_params, blendop_version, multi_priority, multi_name,"
842 " model, maker, lens, iso_min, iso_max, exposure_min, exposure_max,"
843 " aperture_min, aperture_max, focal_length_min, focal_length_max,"
844 " writeprotect, autoapply, filter, def, format)"
845 " VALUES (?1, '', ?2, ?3, ?4, ?5, ?6, ?7, 0, '', '%', '%', '%', 0,"
846 " 340282346638528859812000000000000000000, 0, 10000000, 0, 100000000, 0,"
847 " 1000, 1, 0, 0, 0, 0)",
848 -1, &stmt, NULL);
849 // clang-format on
850 if(IS_NULL_PTR(stmt)) return;
851
854 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, op_version);
856 DT_DEBUG_SQLITE3_BIND_INT(stmt, 5, enabled);
858 DT_DEBUG_SQLITE3_BIND_INT(stmt, 7, blendop_version);
861}
862
863GList *dt_preset_repository_list_for_iop(const char *operation, const int op_version)
864{
866 /* writeprotect ASC, not DESC: a user's copy of a shipped preset must resolve to the
867 * copy, otherwise the name that comes back is the write-protected one and the caller
868 * cannot delete it. */
869 // clang-format off
871 "SELECT name, op_params, writeprotect, blendop_params, enabled"
872 " FROM data.presets"
873 " WHERE operation=?1 AND op_version=?2"
874 " ORDER BY writeprotect ASC, LOWER(name), rowid",
875 -1, &stmt, NULL);
876 // clang-format on
878 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, op_version);
879
880 GList *presets = NULL;
881 while(sqlite3_step(stmt) == SQLITE_ROW)
882 {
884 if(p)
885 {
886 p->op_version = op_version;
887 presets = g_list_prepend(presets, p);
888 }
889 }
891 return g_list_reverse(presets);
892}
893
894GList *dt_preset_repository_list_for_menu(const char *operation, const dt_preset_match_t *match,
895 const gboolean shipped_first)
896{
898 gchar *query = NULL;
899
900 if(match)
901 {
902 // clang-format off
904 "SELECT name, op_params, writeprotect, description, blendop_params, "
905 " op_version, enabled"
906 " FROM data.presets"
907 " WHERE operation=?1"
908 " AND (filter=0"
909 " OR"
911 " ORDER BY writeprotect %s, LOWER(name), rowid",
912 shipped_first ? "DESC" : "ASC");
913 // clang-format on
914 }
915 else
916 {
917 // don't know for which image. show all we got:
918 // clang-format off
920 "SELECT name, op_params, writeprotect, "
921 " description, blendop_params, op_version, enabled"
922 " FROM data.presets"
923 " WHERE operation=?1"
924 " ORDER BY writeprotect %s, LOWER(name), rowid",
925 shipped_first ? "DESC" : "ASC");
926 // clang-format on
927 }
928
931 if(match) _bind_match(stmt, match, FALSE);
932 dt_free(query);
933
934 GList *presets = NULL;
935 while(sqlite3_step(stmt) == SQLITE_ROW)
936 {
938 if(p) presets = g_list_prepend(presets, p);
939 }
941 return g_list_reverse(presets);
942}
943
944dt_module_preset_t *dt_preset_repository_get_iop_preset(const char *operation, const int op_version,
945 const char *name)
946{
948 // clang-format off
950 "SELECT op_params, enabled, blendop_params, blendop_version, writeprotect"
951 " FROM data.presets"
952 " WHERE operation = ?1 AND op_version = ?2 AND name = ?3",
953 -1, &stmt, NULL);
954 // clang-format on
956 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, op_version);
958
961 {
962 p = g_malloc0(sizeof(dt_module_preset_t));
963 if(p)
964 {
965 p->rowid = -1;
966 p->name = g_strdup(name);
967 p->description = g_strdup("");
968 p->op_version = op_version;
969 p->op_params = _column_blob(stmt, 0, &p->op_params_size);
970 p->enabled = sqlite3_column_int(stmt, 1);
971 p->blendop_params = _column_blob(stmt, 2, &p->blendop_params_size);
972 p->blendop_version = sqlite3_column_int(stmt, 3);
973 p->writeprotect = sqlite3_column_int(stmt, 4) != 0;
974 }
975 }
977 return p;
978}
979
980GList *dt_preset_repository_find_autoapply(const char *operation, const int op_version,
981 const dt_preset_match_t *match, const char *always_name)
982{
983 if(IS_NULL_PTR(match)) return NULL;
984
986 /* A plain literal. This was assembled with snprintf() into a 2024-byte buffer despite
987 * having no format specifier in it -- a copy that did nothing, and a `%` away from being
988 * a bug. */
989 // clang-format off
991 "SELECT name"
992 " FROM data.presets"
993 " WHERE operation = ?1"
994 " AND ((autoapply=1"
996 " AND operation NOT IN"
997 " ('ioporder', 'metadata', 'export', 'tagging', 'collect', 'basecurve'))"
998 " OR (name = ?13)) AND op_version = ?14",
999 -1, &stmt, NULL);
1000 // clang-format on
1002 _bind_match(stmt, match, TRUE);
1004 DT_DEBUG_SQLITE3_BIND_INT(stmt, 14, op_version);
1005
1006 GList *names = NULL;
1007 while(sqlite3_step(stmt) == SQLITE_ROW)
1010 return g_list_reverse(names);
1011}
1012
1013
1014/* ---------------------------------------------------------------------------------------
1015 * The preset edit dialog
1016 * ------------------------------------------------------------------------------------- */
1017
1019{
1020 if(IS_NULL_PTR(c)) return;
1021 dt_free(c->name);
1022 dt_free(c->description);
1023 dt_free(c->model);
1024 dt_free(c->maker);
1025 dt_free(c->lens);
1026}
1027
1028gboolean dt_preset_repository_get_conditions(const char *operation, const int op_version,
1029 const char *name, dt_preset_conditions_t *c, int *rowid)
1030{
1031 if(IS_NULL_PTR(c) || IS_NULL_PTR(rowid)) return FALSE;
1032 *rowid = -1;
1033
1035 // clang-format off
1037 "SELECT rowid, description, model, maker, lens, iso_min, iso_max, "
1038 " exposure_min, exposure_max, aperture_min, aperture_max, focal_length_min, "
1039 " focal_length_max, autoapply, filter, format"
1040 " FROM data.presets"
1041 " WHERE name = ?1 AND operation = ?2 AND op_version = ?3",
1042 -1, &stmt, NULL);
1043 // clang-format on
1046 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, op_version);
1047
1048 gboolean found = FALSE;
1050 {
1051 found = TRUE;
1052 *rowid = sqlite3_column_int(stmt, 0);
1053 c->name = g_strdup(name);
1054 c->description = _column_text(stmt, 1);
1055 c->model = _column_text(stmt, 2);
1056 c->maker = _column_text(stmt, 3);
1057 c->lens = _column_text(stmt, 4);
1058 c->iso_min = sqlite3_column_double(stmt, 5);
1059 c->iso_max = sqlite3_column_double(stmt, 6);
1060 c->exposure_min = sqlite3_column_double(stmt, 7);
1061 c->exposure_max = sqlite3_column_double(stmt, 8);
1062 c->aperture_min = sqlite3_column_double(stmt, 9);
1063 c->aperture_max = sqlite3_column_double(stmt, 10);
1064 c->focal_length_min = sqlite3_column_double(stmt, 11);
1065 c->focal_length_max = sqlite3_column_double(stmt, 12);
1066 c->autoapply = sqlite3_column_int(stmt, 13);
1067 c->filter = sqlite3_column_int(stmt, 14);
1068 c->format = sqlite3_column_int(stmt, 15);
1069 }
1071 return found;
1072}
1073
1074/* Bind the sixteen condition columns, which the update and the insert share in the same
1075 * order. */
1077{
1078 _bind_text(stmt, 1, c->name);
1079 _bind_text(stmt, 2, c->description);
1080 _bind_text(stmt, 3, c->model);
1081 _bind_text(stmt, 4, c->maker);
1082 _bind_text(stmt, 5, c->lens);
1083 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 6, c->iso_min);
1084 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 7, c->iso_max);
1085 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, c->exposure_min);
1086 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, c->exposure_max);
1087 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 10, c->aperture_min);
1088 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 11, c->aperture_max);
1089 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 12, c->focal_length_min);
1090 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 13, c->focal_length_max);
1091 DT_DEBUG_SQLITE3_BIND_INT(stmt, 14, c->autoapply);
1092 DT_DEBUG_SQLITE3_BIND_INT(stmt, 15, c->filter);
1093 DT_DEBUG_SQLITE3_BIND_INT(stmt, 16, c->format);
1094}
1095
1097{
1098 if(IS_NULL_PTR(c)) return;
1099
1101 /* rowid is bound as ?17. It used to be pasted in with g_strdup_printf("... rowid=%d"),
1102 * which meant building the query text on every save for a value that is an integer from
1103 * the database. */
1104 // clang-format off
1106 "UPDATE data.presets "
1107 "SET"
1108 " name=?1, description=?2,"
1109 " model=?3, maker=?4, lens=?5, iso_min=?6, iso_max=?7, exposure_min=?8,"
1110 " exposure_max=?9, aperture_min=?10,"
1111 " aperture_max=?11, focal_length_min=?12, focal_length_max=?13, autoapply=?14,"
1112 " filter=?15, format=?16 "
1113 "WHERE rowid=?17",
1114 -1, &stmt, NULL);
1115 // clang-format on
1117 DT_DEBUG_SQLITE3_BIND_INT(stmt, 17, rowid);
1120}
1121
1123 const char *operation, const int op_version,
1124 const void *params, const int params_size,
1125 const int enabled,
1126 const void *blend_params, const int blend_params_size,
1127 const int blendop_version)
1128{
1129 if(IS_NULL_PTR(c)) return;
1130
1132 // clang-format off
1134 "INSERT INTO data.presets"
1135 " (name, description, "
1136 " model, maker, lens, iso_min, iso_max, exposure_min, exposure_max, aperture_min,"
1137 " aperture_max, focal_length_min, focal_length_max, autoapply,"
1138 " filter, format, def, writeprotect, operation, op_version, op_params, enabled,"
1139 " blendop_params, blendop_version, multi_priority, multi_name) "
1140 "VALUES"
1141 " (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, 0, 0, ?17,"
1142 " ?18, ?19, ?20, ?21, ?22, 0, '')",
1143 -1, &stmt, NULL);
1144 // clang-format on
1147 DT_DEBUG_SQLITE3_BIND_INT(stmt, 18, op_version);
1149 DT_DEBUG_SQLITE3_BIND_INT(stmt, 20, enabled);
1151 DT_DEBUG_SQLITE3_BIND_INT(stmt, 22, blendop_version);
1154}
1155
1156gboolean dt_preset_repository_get_identity(const int rowid, gchar **operation, int *op_version)
1157{
1158 if(IS_NULL_PTR(operation) || IS_NULL_PTR(op_version)) return FALSE;
1159 *operation = NULL;
1160 *op_version = 0;
1161
1163 // clang-format off
1165 "SELECT operation, op_version FROM data.presets WHERE rowid = ?1",
1166 -1, &stmt, NULL);
1167 // clang-format on
1169
1170 gboolean found = FALSE;
1172 {
1173 found = TRUE;
1174 *operation = _column_text(stmt, 0);
1175 *op_version = sqlite3_column_int(stmt, 1);
1176 }
1178 return found;
1179}
1180
1181void dt_preset_repository_update_iop_params(const char *operation, const char *name,
1182 const int op_version,
1183 const void *params, const int params_size,
1184 const int enabled,
1185 const void *blend_params, const int blend_params_size,
1186 const int blendop_version)
1187{
1189 // clang-format off
1191 "UPDATE data.presets"
1192 " SET op_version=?2, op_params=?3, enabled=?4,"
1193 " blendop_params=?5, blendop_version=?6"
1194 " WHERE name=?7 AND operation=?1",
1195 -1, &stmt, NULL);
1196 // clang-format on
1198 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, op_version);
1200 DT_DEBUG_SQLITE3_BIND_INT(stmt, 4, enabled);
1202 DT_DEBUG_SQLITE3_BIND_INT(stmt, 6, blendop_version);
1206}
1207
1209{
1211 // clang-format off
1213 "DELETE FROM data.presets WHERE rowid=?1 AND writeprotect=0",
1214 -1, &stmt, NULL);
1215 // clang-format on
1219}
1220
1222{
1224 "DELETE FROM data.presets WHERE writeprotect = 1", NULL, NULL, NULL);
1225}
1226
1227void dt_preset_row_free(gpointer data)
1228{
1230 if(IS_NULL_PTR(row)) return;
1231 dt_free(row->name);
1232 dt_free(row->operation);
1233 dt_free(row->model);
1234 dt_free(row->maker);
1235 dt_free(row->lens);
1236 dt_free(row);
1237}
1238
1240{
1241 GList *rows = NULL;
1243 // clang-format off
1245 "SELECT rowid, name, operation, autoapply, model, maker, lens, iso_min, "
1246 "iso_max, exposure_min, exposure_max, aperture_min, aperture_max, "
1247 "focal_length_min, focal_length_max, writeprotect FROM data.presets ORDER BY "
1248 "operation, name",
1249 -1, &stmt, NULL);
1250 // clang-format on
1251 if(IS_NULL_PTR(stmt)) return NULL;
1252
1253 while(sqlite3_step(stmt) == SQLITE_ROW)
1254 {
1256 if(IS_NULL_PTR(row)) break;
1258 // NULL is preserved rather than normalised to "" by _column_text(): the caller passes
1259 // these straight to g_strcmp0()/g_strdup() and into a GtkTreeStore, all of which treat
1260 // the two differently, and the loop this replaced handed them the raw column.
1261 row->name = _column_text_or_null(stmt, 1);
1262 row->operation = _column_text_or_null(stmt, 2);
1263 row->autoapply = (sqlite3_column_int(stmt, 3) == 0 ? FALSE : TRUE);
1264 row->model = _column_text_or_null(stmt, 4);
1265 row->maker = _column_text_or_null(stmt, 5);
1266 row->lens = _column_text_or_null(stmt, 6);
1267 row->iso_min = sqlite3_column_double(stmt, 7);
1268 row->iso_max = sqlite3_column_double(stmt, 8);
1269 row->exposure_min = sqlite3_column_double(stmt, 9);
1270 row->exposure_max = sqlite3_column_double(stmt, 10);
1271 row->aperture_min = sqlite3_column_double(stmt, 11);
1272 row->aperture_max = sqlite3_column_double(stmt, 12);
1273 row->focal_length_min = sqlite3_column_double(stmt, 13);
1274 row->focal_length_max = sqlite3_column_double(stmt, 14);
1275 row->writeprotect = (sqlite3_column_int(stmt, 15) == 0 ? FALSE : TRUE);
1276 rows = g_list_prepend(rows, row);
1277 }
1279
1280 // Row order, not reverse-row: the caller walks it once and starts a new module node every
1281 // time `operation` changes, which only works in the ORDER BY's own order.
1282 return g_list_reverse(rows);
1283}
1284
1285void dt_preset_identity_free(gpointer data)
1286{
1288 if(IS_NULL_PTR(row)) return;
1289 dt_free(row->name);
1290 dt_free(row->operation);
1291 dt_free(row);
1292}
1293
1295{
1296 GList *rows = NULL;
1299 "SELECT rowid, name, operation FROM data.presets WHERE writeprotect = 0",
1300 -1, &stmt, NULL);
1301 if(IS_NULL_PTR(stmt)) return NULL;
1302
1303 while(sqlite3_step(stmt) == SQLITE_ROW)
1304 {
1306 if(IS_NULL_PTR(row)) break;
1308 row->name = _column_text_or_null(stmt, 1);
1309 row->operation = _column_text_or_null(stmt, 2);
1310 rows = g_list_prepend(rows, row);
1311 }
1313
1314 return g_list_reverse(rows); // row order: the caller writes one file per row, in order
1315}
1316
1318{
1319 /* Nothing cached any more: every statement in this file is prepared and finalised per
1320 * call. Kept because the connection's close order calls every repository's cleanup. */
1321}
1322
1323// clang-format off
1324// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1325// vim: shiftwidth=2 expandtab tabstop=2 cindent
1326// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1327// clang-format on
const char ** description(struct dt_iop_module_t *self)
Definition ashift.c:166
#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
#define m
Definition basecurve.c:282
const float v
static const float const float const float min
const float max
static const int row
sqlite3 * dt_database_get_sqlite3_global(void)
Definition database.c:3753
const char flag
Definition image.h:285
struct dt_iop_tonecurve_params_t preset
const char * maker
const char * model
#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:65
#define dt_free(ptr)
Definition mem_alloc.h:97
size_t size
Definition mipmap_cache.c:3
static float clamp(float f, float m, float M)
const char * name
Definition pdf.h:90
gboolean dt_preset_repository_insert(const dt_preset_t *preset)
Insert preset, replacing any row that collides with it.
void dt_preset_repository_delete_module_preset(const char *operation, const int op_version, const char *name)
Delete (operation, op_version, name) unless it is write-protected.
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().
#define _PRESET_COLUMNS
GList * dt_preset_repository_list_all(void)
Every preset, ordered by (operation, name) – the grouping the tree relies on to start a new module no...
GList * dt_preset_repository_list_all_versions(const char *operation)
Every preset of operation at ANY version, with rowid and op_version filled in, SHIPPED FIRST then by ...
static dt_module_preset_t * _iop_row(sqlite3_stmt *stmt, const gboolean with_description)
static gchar * _column_text_or_null(sqlite3_stmt *stmt, const int col)
void dt_preset_row_free(gpointer data)
Free one dt_preset_row_t. Suits g_list_free_full().
static void * _column_blob(sqlite3_stmt *stmt, const int col, int *size)
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).
GList * dt_preset_repository_list_for_module(const char *operation, const int op_version, const gboolean with_description, const gboolean shipped_first)
Every preset of (operation, op_version).
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.
dt_preset_t * dt_preset_repository_get_by_rowid(const int rowid)
The preset at rowid, or NULL when there is none. Free with dt_preset_free().
dt_module_preset_t * dt_preset_repository_get_module_preset(const char *operation, const int op_version, const char *name)
One preset by name, or NULL. Free with dt_module_preset_free().
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.
GList * dt_preset_repository_list_editable(void)
Every preset the user may edit (writeprotect = 0), in row order.
void dt_preset_repository_update_params_by_rowid(const int rowid, const int op_version, const void *params, const int params_size)
Replace the parameters of one row, by rowid.
GList * dt_preset_repository_list_for_upgrade(const char *operation)
Every preset of operation at any version, with both parameter blobs.
int dt_preset_repository_find_rowid(const char *operation, const int op_version, const char *name)
rowid of (operation, op_version, name), or -1.
static gchar * _column_text(sqlite3_stmt *stmt, const int col)
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).
void dt_preset_repository_update_module_params(const char *operation, const char *name, const int op_version, const void *params, const int params_size)
Replace the parameters (and version) of (operation, name).
static const char *const _flag_query[DT_PRESET_FLAG_LAST]
void dt_preset_identity_free(gpointer data)
Free one dt_preset_identity_t. Suits g_list_free_full().
void dt_preset_repository_add_module_preset(const char *name, const char *operation, const int op_version, const void *params, const int params_size)
Create an empty user preset holding params, as the "new preset" menu item does.
GList * dt_preset_repository_list_for_version(const char *operation, const int op_version)
As above, restricted to one op_version. Same columns, same order.
void dt_preset_repository_delete_by_rowid(const int rowid)
Delete one row by rowid.
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).
static void _bind_conditions(sqlite3_stmt *stmt, const dt_preset_conditions_t *c)
static void _bind_text(sqlite3_stmt *stmt, const int idx, const char *value)
void dt_preset_repository_delete_all_for_module(const char *operation)
Delete every preset of operation, whatever its version or protection.
void dt_preset_free(dt_preset_t *preset)
Release a dt_preset_t and everything it owns. NULL-safe.
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_rename_module_preset(const char *operation, const int op_version, const char *old_name, const char *new_name, const char *description, const void *params, const int params_size)
Replace name, description and parameters of (operation, op_version, old_name).
void dt_preset_repository_set_module_version(const char *operation, const char *name, const int op_version)
Set ONLY the version of (operation, name), leaving the parameters alone.
void dt_preset_repository_set_blend_params(const char *operation, const char *name, const int blendop_version, const void *blend_params, const int blend_params_size)
Replace the blend parameters (and blend version) of (operation, name), at any version....
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_add_shipped_preset(const char *name, const char *operation, const int op_version, const void *params, const int params_size, const int writeprotect)
Create a preset from code rather than from the menu – the built-in presets a module registers at star...
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).
static const char *const _range_query[DT_PRESET_RANGE_LAST]
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.
void dt_preset_repository_duplicate_module_preset(const char *operation, const int op_version, const char *name, const char *new_name)
Copy (operation, op_version, name) to new_name, unprotected.
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.
#define _PRESET_MATCH_PREDICATE
static void _bind_match(sqlite3_stmt *stmt, const dt_preset_match_t *m, const gboolean clamp)
data.presets: a module's saved parameters, with the conditions under which it auto-applies.
dt_preset_flag_t
@ DT_PRESET_FLAG_FORMAT
@ DT_PRESET_FLAG_FILTER
@ DT_PRESET_FLAG_LAST
@ DT_PRESET_FLAG_AUTOAPPLY
dt_preset_range_t
@ DT_PRESET_RANGE_FOCAL_LENGTH
@ DT_PRESET_RANGE_ISO
@ DT_PRESET_RANGE_APERTURE
@ DT_PRESET_RANGE_LAST
@ DT_PRESET_RANGE_EXPOSURE
void copy(TYPE *dest, TYPE *source, size_t num_el)
Copy a flat buffer used to initialize test matrices.
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
Checked wrappers around the sqlite3_* calls: trace the statement, assert the return code,...
#define DT_DEBUG_SQLITE3_EXEC(a, b, c, d, e)
Definition sql_debug.h:129
#define DT_DEBUG_SQLITE3_BIND_BLOB(a, b, c, d, e)
Definition sql_debug.h:149
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition sql_debug.h:137
#define DT_DEBUG_SQLITE3_BIND_TEXT(a, b, c, d, e)
Definition sql_debug.h:148
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
Definition sql_debug.h:145
#define DT_DEBUG_SQLITE3_BIND_DOUBLE(a, b, c)
Definition sql_debug.h:147
Identity of one preset, for callers listing rather than loading.
The facts about one image that decide whether a preset matches it.
One row of the Preferences preset tree, with its auto-apply conditions.
One row of data.presets, owned by the caller.