Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
history_actions.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel 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 Ansel 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 Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
20
21#include "common/act_on.h"
22#include "common/collection.h"
23#include "common/darktable.h"
24#include "common/debug.h"
25#include "common/exif.h"
26#include "common/history.h"
28#include "common/image.h"
29#include "common/image_cache.h"
30#include "common/mipmap_cache.h"
31#include "common/styles.h"
32#include "common/tags.h"
33#include "common/undo.h"
34#include "control/conf.h"
35#include "control/control.h"
36#include "develop/dev_history.h"
37#include "develop/develop.h"
38#include "develop/imageop.h"
39#include "dtgtk/thumbtable.h"
40#include "gui/actions/menu.h"
41#include "gui/gtk.h"
42#include "gui/hist_dialog.h"
43
44#ifdef GDK_WINDOWING_QUARTZ
45#include "osx/osx.h"
46#endif
47
48static void _history_action_finalize_list(const GList *list, const gboolean changed)
49{
50 if(!changed) return;
51
54}
55
56typedef gboolean (*dt_history_action_fn)(const int32_t imgid, void *user_data);
57
58static gboolean _history_action_on_list_with_undo(const GList *list, dt_history_action_fn action, void *user_data,
59 const gboolean use_undo)
60{
61 if(IS_NULL_PTR(list)) return FALSE;
62
64 gboolean changed = FALSE;
65 for(const GList *l = list; l; l = g_list_next(l))
66 {
67 const int32_t imgid = GPOINTER_TO_INT(l->data);
68 changed |= action(imgid, user_data);
69 }
70 if(use_undo) dt_undo_end_group(darktable.undo);
71
72 _history_action_finalize_list(list, changed);
73 return changed;
74}
75
76static gboolean _history_action_on_list(const GList *list, dt_history_action_fn action, void *user_data)
77{
78 return _history_action_on_list_with_undo(list, action, user_data, TRUE);
79}
80
91static GList *_get_user_mod_list(dt_develop_t *dev_src, GList *ops, gboolean copy_full)
92{
93 GList *mod_list = NULL;
94
95 if(ops)
96 {
97 dt_print(DT_DEBUG_PARAMS, "[_history_copy_and_paste_on_image_merge] pasting selected IOP\n");
98
99 // copy only selected history entries
100 for(const GList *l = g_list_last(ops); l; l = g_list_previous(l))
101 {
102 const unsigned int num = GPOINTER_TO_UINT(l->data);
103 const dt_dev_history_item_t *hist = NULL;
104 for(GList *h = g_list_last(dev_src->history); h; h = g_list_previous(h))
105 {
106 const dt_dev_history_item_t *item = (dt_dev_history_item_t *)h->data;
107 if(item && item->num == (int)num)
108 {
109 hist = item;
110 break;
111 }
112 }
113
114 if(hist)
115 {
116 dt_iop_module_t *mod = hist->module;
117 if(mod && !dt_iop_is_hidden(mod))
118 {
119 dt_print(DT_DEBUG_HISTORY, "selected for copy/pasting : module %20s, multiprio %i", mod->op, mod->multi_priority);
120
121 mod_list = g_list_prepend(mod_list, mod);
122 }
123 }
124 }
125 }
126 else
127 {
128 dt_print(DT_DEBUG_PARAMS, "[_history_copy_and_paste_on_image_merge] pasting all IOP\n");
129
130 // we will copy all modules
131 for(GList *modules_src = g_list_first(dev_src->iop); modules_src; modules_src = g_list_next(modules_src))
132 {
133 dt_iop_module_t *mod_src = (dt_iop_module_t *)(modules_src->data);
134
135 // copy from history only if
136 if((dt_dev_history_get_first_item_by_module(dev_src->history, mod_src) != NULL) // module is in history of source image
137 && !dt_iop_is_hidden(mod_src) // hidden modules are technical and special
138 && (copy_full || !dt_history_module_skip_copy(mod_src->flags()))
139 )
140 {
141 // Note: we prepend to GList because it's more efficient
142 mod_list = g_list_prepend(mod_list, mod_src);
143 }
144 }
145 }
146
147 return g_list_reverse(mod_list);
148}
149
162static int _history_copy_and_paste_on_image_merge(int32_t imgid, int32_t dest_imgid, GList *ops,
163 const gboolean copy_full, const dt_history_merge_strategy_t mode,
164 const gboolean copy_iop_order, dt_hm_batch_state_t *batch)
165{
166 // Init source history + pipeline
167 dt_develop_t _dev_src = { 0 };
168 dt_develop_t *dev_src = &_dev_src;
169 dt_dev_init(dev_src, FALSE);
170 dt_dev_reload_history_items(dev_src, imgid);
171
172 int ret_val = 0;
173
174 if(mode == DT_HISTORY_MERGE_REPLACE)
175 {
176 // Dumb mode : keep dev_src intact but swap destination imgid and image info into it.
177 //
178 // NOTE: when pasting from LDR/JPEG onto RAW images, the source iop-order list might not be compatible
179 // with the destination pipeline. We need to re-init the iop-order list for the destination image and
180 // reload module defaults for the destination image, but we must not apply auto-presets.
181 ret_val = dt_dev_replace_history_on_image(dev_src, dest_imgid, TRUE, "_history_copy_and_paste_on_image_merge");
182 }
183 else
184 {
185 // Merge
186 GList *mod_list = _get_user_mod_list(dev_src, ops, copy_full);
187 ret_val = dt_dev_merge_history_into_image(dev_src, dest_imgid, mod_list,
188 copy_iop_order, mode,
189 dt_conf_get_bool("history/paste_instances"), NULL, batch);
190 g_list_free(mod_list);
191 mod_list = NULL;
192 }
193 dt_dev_cleanup(dev_src);
194
195 return ret_val;
196}
197
198gboolean dt_history_copy_and_paste_on_image(const int32_t imgid, const int32_t dest_imgid, GList *ops,
199 const gboolean copy_full, const dt_history_merge_strategy_t mode,
200 const gboolean copy_iop_order, dt_hm_batch_state_t *batch)
201{
202 if(imgid == dest_imgid) return 1;
203
204 if(imgid == UNKNOWN_IMAGE)
205 {
206 dt_control_log(_("you need to copy history from an image before you paste it onto another"));
207 return 1;
208 }
209
211 hist->imgid = dest_imgid;
213
214 int ret_val = _history_copy_and_paste_on_image_merge(imgid, dest_imgid, ops, copy_full, mode, copy_iop_order,
215 batch);
216
220
221 return ret_val;
222}
223
224gboolean dt_history_copy(int32_t imgid)
225{
226 // note that this routine does not copy anything, it just setup the copy_paste proxy
227 // with the needed information that will be used while pasting.
228
229 if(imgid <= 0) return FALSE;
230
232
233 return TRUE;
234}
235
236gboolean dt_history_copy_parts(int32_t imgid)
237{
238 if(dt_history_copy(imgid))
239 {
240 // run dialog, it will insert into selops the selected moduel
241
242 if(dt_gui_hist_dialog_new(&(darktable.view_manager->copy_paste), imgid, TRUE) == GTK_RESPONSE_CANCEL)
243 return FALSE;
244 return TRUE;
245 }
246 else
247 return FALSE;
248}
249
254
255static gboolean _history_paste_apply(const int32_t imgid, void *user_data)
256{
257 _paste_action_ctx_t *ctx = (_paste_action_ctx_t *)user_data;
259 if(imgid <= 0) return FALSE;
260
262 imgid,
264 FALSE,
265 dt_conf_get_int("history/paste/mode"),
266 dt_conf_get_bool("history/paste/copy_iop_order"),
267 ctx ? &ctx->batch : NULL) == 0;
268 return pasted;
269}
270
271gboolean dt_history_paste_on_image(const int32_t imgid)
272{
273 return _history_paste_apply(imgid, NULL); // NULL batch → always show report popup
274}
275
276gboolean dt_history_paste_on_list(const GList *list)
277{
279 _paste_action_ctx_t ctx = { 0 };
280 const gboolean changed = _history_action_on_list(list, _history_paste_apply, &ctx);
282 return changed;
283}
284
286{
288
289 // we launch the dialog
292
293 if(res != GTK_RESPONSE_OK)
294 {
295 return FALSE;
296 }
297
298 return TRUE;
299}
300
301static gboolean _history_paste_parts_apply(const int32_t imgid, void *user_data)
302{
303 _paste_action_ctx_t *ctx = (_paste_action_ctx_t *)user_data;
306 if(imgid <= 0) return FALSE;
307
309 imgid,
311 FALSE,
312 dt_conf_get_int("history/paste/mode"),
313 dt_conf_get_bool("history/paste/copy_iop_order"),
314 ctx ? &ctx->batch : NULL) == 0;
315 return pasted;
316}
317
318gboolean dt_history_paste_parts_on_image(const int32_t imgid)
319{
320 return _history_paste_parts_apply(imgid, NULL); // NULL batch → always show report popup
321}
322
323gboolean dt_history_paste_parts_on_list(const GList *list)
324{
327 return FALSE;
328 _paste_action_ctx_t ctx = { 0 };
329 const gboolean changed = _history_action_on_list(list, _history_paste_parts_apply, &ctx);
331 return changed;
332}
333
334static gboolean _history_compress_apply(const int32_t imgid, void *user_data)
335{
336 (void)user_data;
337 dt_print(DT_DEBUG_HISTORY, "[dt_history_compress_on_image] compressing history for image %i\n", imgid);
338 if(imgid <= 0) return FALSE;
339
340 dt_develop_t dev;
341 dt_dev_init(&dev, FALSE);
342 dt_dev_reload_history_items(&dev, imgid);
344 dt_dev_write_history_ext(&dev, imgid);
345 dt_dev_cleanup(&dev);
346 return TRUE;
347}
348
349void dt_history_compress_on_image(const int32_t imgid)
350{
351 _history_compress_apply(imgid, NULL);
352}
353
354int dt_history_compress_on_list(const GList *imgs)
355{
357 return 0;
358}
359
365
366static gboolean _history_load_and_apply_apply(const int32_t imgid, void *user_data)
367{
370 if(IS_NULL_PTR(img)) return FALSE;
371
373 hist->imgid = imgid;
375
376 if(dt_exif_xmp_read(img, params->filename, params->history_only))
377 {
379 // ugly but if not history_only => called from crawler - do not write the xmp
380 params->history_only ? DT_IMAGE_CACHE_SAFE : DT_IMAGE_CACHE_RELAXED);
381 return FALSE;
382 }
383
387
389 // ugly but if not history_only => called from crawler - do not write the xmp
390 params->history_only ? DT_IMAGE_CACHE_SAFE : DT_IMAGE_CACHE_RELAXED);
391
392 // Loading an XMP rewrites the image history straight into the DB and image cache, bypassing
393 // the darkroom/paste path that goes through dt_dev_history_notify_change(). Nothing invalidates
394 // the rendered thumbnail, so it keeps showing the pre-XMP development (issue #861).
395 // The cached metadata (history_items, ratings...) is refreshed by the DT_SIGNAL_IMAGE_INFO_CHANGED
396 // raised in _history_action_finalize_list(), but the pixels are not: reload metadata, invalidate
397 // the mipmap and refresh the thumbnail (lighttable context, so refresh the filmstrip too).
399
400 return TRUE;
401}
402
403int dt_history_load_and_apply(const int32_t imgid, gchar *filename, int history_only)
404{
405 dt_history_load_params_t params = { .filename = filename, .history_only = history_only };
406 return _history_load_and_apply_apply(imgid, &params) ? 0 : 1;
407}
408
409int dt_history_load_and_apply_on_image(int32_t imgid, gchar *filename, int history_only)
410{
411 return dt_history_load_and_apply(imgid, filename, history_only);
412}
413
414int dt_history_load_and_apply_on_list(gchar *filename, const GList *list)
415{
416 dt_history_load_params_t params = { .filename = filename, .history_only = 1 };
417 const gboolean changed = _history_action_on_list(list, _history_load_and_apply_apply, &params);
418 return changed ? 0 : 1;
419}
420
425
426static gboolean _history_delete_apply(const int32_t imgid, void *user_data)
427{
428 if(imgid <= 0) return FALSE;
429
430 const dt_history_delete_params_t *params = (dt_history_delete_params_t *)user_data;
431 const gboolean undo = params ? params->undo : TRUE;
432
433 dt_undo_lt_history_t *hist = NULL;
434 if(undo)
435 {
437 hist->imgid = imgid;
439 }
440
442
443 if(undo)
444 {
448 }
449
450 return TRUE;
451}
452
453gboolean dt_history_delete_on_list(const GList *list, gboolean undo)
454{
455 dt_history_delete_params_t params = { .undo = undo };
456 return _history_action_on_list_with_undo(list, _history_delete_apply, &params, undo);
457}
458
459gboolean delete_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
460{
461 if(!has_active_images()) return FALSE;
462
463 GList *imgs = dt_act_on_get_images();
464 if(IS_NULL_PTR(imgs)) return FALSE;
465
466 if(dt_conf_get_bool("ask_before_discard"))
467 {
468 const int img_count = g_list_length(imgs);
470 GtkWidget *dialog = gtk_message_dialog_new(
471 GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
472 ngettext("Do you really want to clear history of %d image?",
473 "Do you really want to clear history of %d images?", img_count),
474 img_count);
475#ifdef GDK_WINDOWING_QUARTZ
477#endif
478 gtk_window_set_title(GTK_WINDOW(dialog), ngettext("Delete image's history?", "Delete images' history?", img_count));
479
480 GtkWidget *message_area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog));
481 GtkWidget *ask_check = gtk_check_button_new_with_label(_("Always ask"));
482 gtk_widget_set_tooltip_text(ask_check,
483 _("when unchecked, history will be deleted silently from now on without this confirmation.\n"
484 "you can turn it back on from preferences."));
485 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ask_check), TRUE);
486 gtk_box_pack_start(GTK_BOX(message_area), ask_check, FALSE, FALSE, 6);
487 gtk_widget_show(ask_check);
488
489 const gint res = gtk_dialog_run(GTK_DIALOG(dialog));
490 dt_conf_set_bool("ask_before_discard", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ask_check)));
491 gtk_widget_destroy(dialog);
492 dt_gui_refocus_parent(GTK_WINDOW(win));
493 if(res != GTK_RESPONSE_YES)
494 {
495 g_list_free(imgs);
496 return TRUE;
497 }
498 }
499
500 gboolean is_darkroom_image_in_list = dt_dev_history_is_image_in_dev(imgs);
501
502 if(is_darkroom_image_in_list)
503 {
505 }
506
508
509 if(is_darkroom_image_in_list)
510 {
513 }
514
516 g_list_free(imgs);
517 imgs = NULL;
518 return TRUE;
519}
520
529
530static gboolean _history_style_apply(const int32_t imgid, void *user_data)
531{
533 if(IS_NULL_PTR(params) || params->style_id == 0 || IS_NULL_PTR(params->name) || !*params->name) return FALSE;
534
535 int32_t newimgid = imgid;
536 if(params->duplicate)
537 {
538 // Defer exposing the duplicate to the collection/lighttable grid until its history is
539 // copied below -- otherwise the grid can generate and cache a thumbnail from the
540 // still-historyless row before the copy ever runs.
541 newimgid = dt_image_duplicate_no_reload(imgid);
542 if(newimgid == UNKNOWN_IMAGE) return FALSE;
543
544 // Structural copy of original history into the duplicate; no merge report needed here.
545 const gboolean pasted = dt_history_copy_and_paste_on_image(imgid, newimgid, NULL, TRUE, params->mode,
546 dt_conf_get_bool("history/style/copy_iop_order"),
547 NULL) == 0;
548
550
551 return pasted;
552 }
553
555 hist->imgid = newimgid;
557
558 const int ret_val = dt_styles_apply_to_image_merge(params->name, params->style_id, newimgid, params->mode,
559 &params->batch);
560
564
565 const gboolean changed = (ret_val == 0);
566 return changed;
567}
568
569gboolean dt_history_style_on_image(const int32_t imgid, const char *name, const gboolean duplicate)
570{
571 if(IS_NULL_PTR(name) || !*name) return FALSE;
572
574 .name = name,
575 .style_id = dt_styles_get_id_by_name(name),
576 .duplicate = duplicate,
577 .mode = dt_conf_get_int("history/style/mode"),
578 .batch = { .decision = DT_HM_BATCH_UNDECIDED },
579 };
580 if(params.style_id == 0) return FALSE;
581
582 const gboolean changed = _history_style_apply(imgid, &params);
583 dt_hm_batch_state_cleanup(&params.batch);
584 return changed;
585}
586
587gboolean dt_history_style_on_list(const GList *list, const char *name, const gboolean duplicate)
588{
589 if(IS_NULL_PTR(name) || !*name) return FALSE;
590
592 .name = name,
593 .style_id = dt_styles_get_id_by_name(name),
594 .duplicate = duplicate,
595 .mode = dt_conf_get_int("history/style/mode"),
596 .batch = { .decision = DT_HM_BATCH_UNDECIDED },
597 };
598 if(params.style_id == 0) return FALSE;
599
600 const gboolean changed = _history_action_on_list(list, _history_style_apply, &params);
601 dt_hm_batch_state_cleanup(&params.batch);
602 return changed;
603}
GList * dt_act_on_get_images()
Definition act_on.c:39
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_collection_update_query(const dt_collection_t *collection, dt_collection_change_t query_change, dt_collection_properties_t changed_property, GList *list)
@ DT_COLLECTION_PROP_UNDEF
Definition collection.h:142
@ DT_COLLECTION_CHANGE_RELOAD
Definition collection.h:151
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_history_delete_on_image_ext(int32_t imgid, gboolean undo)
int32_t dt_image_duplicate_no_reload(const int32_t imgid)
void dt_image_history_changed(const int32_t imgid, const gboolean refresh_filmstrip)
char * name
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
int dt_conf_get_int(const char *name)
void dt_control_log(const char *msg,...)
Definition control.c:777
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:877
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
#define UNKNOWN_IMAGE
Definition darktable.h:194
@ DT_DEBUG_HISTORY
Definition darktable.h:762
@ DT_DEBUG_PARAMS
Definition darktable.h:758
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:293
void dt_apply_dev_history_update(dt_develop_t *dev)
Reload the current darkroom history and refresh every dependent GUI.
int dt_dev_replace_history_on_image(dt_develop_t *dev_src, const int32_t dest_imgid, const gboolean reload_defaults, const char *msg)
Replace an image history with the content of dev_src.
gboolean dt_dev_history_is_image_in_dev(GList *imgs)
Check whether any image of the list is the one currently loaded in the darkroom.
int dt_dev_merge_history_into_image(dt_develop_t *dev_src, int32_t dest_imgid, const GList *mod_list, gboolean merge_iop_order, const dt_history_merge_strategy_t mode, const gboolean paste_instances, const char *source_label, dt_hm_batch_state_t *batch)
Merge a list of modules into a destination image history via dt_history_merge().
void dt_dev_history_compress_or_truncate(dt_develop_t *dev)
Compress history if history_end is at top, otherwise truncate.
gboolean dt_history_module_skip_copy(const int flags)
Determine whether a module should be skipped during history copy.
void dt_dev_write_history_ext(dt_develop_t *dev, const int32_t imgid)
Write dev->history to DB and XMP for a given image id.
gboolean dt_dev_reload_history_items(dt_develop_t *dev, const int32_t imgid)
Reload history from DB and rebuild pipelines/GUI state.
dt_dev_history_item_t * dt_dev_history_get_first_item_by_module(GList *history_list, dt_iop_module_t *module)
Find the first history item referencing a module.
void dt_dev_cleanup(dt_develop_t *dev)
Definition develop.c:225
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
Definition develop.c:128
void dt_dev_undo_start_record(dt_develop_t *dev)
Definition develop.c:1678
void dt_dev_undo_end_record(dt_develop_t *dev)
Definition develop.c:1689
int dt_exif_xmp_read(dt_image_t *img, const char *filename, const int history_only)
Definition exif.cc:3109
void dt_gui_refocus_parent(GtkWindow *parent)
Definition gtk.c:1936
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
int dt_gui_hist_dialog_new(dt_history_copy_item_t *d, int32_t imgid, gboolean iscopy)
static gboolean _history_action_on_list_with_undo(const GList *list, dt_history_action_fn action, void *user_data, const gboolean use_undo)
gboolean dt_history_paste_on_list(const GList *list)
static gboolean _history_paste_apply(const int32_t imgid, void *user_data)
int dt_history_load_and_apply(const int32_t imgid, gchar *filename, int history_only)
gboolean dt_history_copy(int32_t imgid)
static gboolean _history_style_apply(const int32_t imgid, void *user_data)
gboolean dt_history_paste_parts_on_list(const GList *list)
static gboolean _history_paste_parts_apply(const int32_t imgid, void *user_data)
static GList * _get_user_mod_list(dt_develop_t *dev_src, GList *ops, gboolean copy_full)
Build a module list to copy based on selected history indices.
int dt_history_load_and_apply_on_image(int32_t imgid, gchar *filename, int history_only)
gboolean delete_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
static gboolean _history_action_on_list(const GList *list, dt_history_action_fn action, void *user_data)
gboolean dt_history_delete_on_list(const GList *list, gboolean undo)
gboolean dt_history_paste_on_image(const int32_t imgid)
gboolean dt_history_style_on_image(const int32_t imgid, const char *name, const gboolean duplicate)
static gboolean _history_load_and_apply_apply(const int32_t imgid, void *user_data)
static int _history_copy_and_paste_on_image_merge(int32_t imgid, int32_t dest_imgid, GList *ops, const gboolean copy_full, const dt_history_merge_strategy_t mode, const gboolean copy_iop_order, dt_hm_batch_state_t *batch)
Copy/merge history between images using the merge pipeline.
gboolean dt_history_paste_parts_prepare(void)
static void _history_action_finalize_list(const GList *list, const gboolean changed)
int dt_history_load_and_apply_on_list(gchar *filename, const GList *list)
int dt_history_compress_on_list(const GList *imgs)
gboolean dt_history_copy_parts(int32_t imgid)
static gboolean _history_delete_apply(const int32_t imgid, void *user_data)
gboolean dt_history_paste_parts_on_image(const int32_t imgid)
gboolean dt_history_copy_and_paste_on_image(const int32_t imgid, const int32_t dest_imgid, GList *ops, const gboolean copy_full, const dt_history_merge_strategy_t mode, const gboolean copy_iop_order, dt_hm_batch_state_t *batch)
static gboolean _history_compress_apply(const int32_t imgid, void *user_data)
void dt_history_compress_on_image(const int32_t imgid)
gboolean dt_history_style_on_list(const GList *list, const char *name, const gboolean duplicate)
gboolean(* dt_history_action_fn)(const int32_t imgid, void *user_data)
void dt_hm_batch_state_cleanup(dt_hm_batch_state_t *batch)
Release resources held by a batch state (the cached order). Safe to call on a zeroed state.
@ DT_HM_BATCH_UNDECIDED
dt_history_merge_strategy_t
@ DT_HISTORY_MERGE_REPLACE
void dt_history_snapshot_undo_create(const int32_t imgid, int *snap_id, int *history_end)
void dt_history_snapshot_undo_lt_history_data_free(gpointer data)
dt_undo_lt_history_t * dt_history_snapshot_item_init(void)
void dt_history_snapshot_undo_pop(gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, dt_undo_action_t action, GList **imgs)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
void dt_image_cache_write_release(dt_image_cache_t *cache, dt_image_t *img, dt_image_cache_write_mode_t mode)
@ DT_IMAGE_CACHE_RELAXED
Definition image_cache.h:51
@ DT_IMAGE_CACHE_SAFE
Definition image_cache.h:49
gboolean dt_iop_is_hidden(dt_iop_module_t *module)
Definition imageop.c:1133
gboolean has_active_images()
Definition menu.c:635
void dt_osx_disallow_fullscreen(GtkWidget *widget)
Definition osx.mm:104
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:366
@ DT_SIGNAL_IMAGE_INFO_CHANGED
This signal is raised when any of image info has changed
Definition signal.h:144
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
Definition signal.h:130
struct _GtkWidget GtkWidget
Definition splash.h:29
int dt_styles_apply_to_image_merge(const char *name, const int style_id, const int32_t newimgid, const dt_history_merge_strategy_t mode, dt_hm_batch_state_t *batch)
int32_t dt_styles_get_id_by_name(const char *name)
dt_hm_batch_state_t batch
struct dt_undo_t * undo
Definition darktable.h:815
struct dt_gui_gtk_t * gui
Definition darktable.h:803
struct dt_collection_t * collection
Definition darktable.h:809
struct dt_control_signal_t * signals
Definition darktable.h:802
struct dt_image_cache_t * image_cache
Definition darktable.h:805
struct dt_develop_t * develop
Definition darktable.h:798
struct dt_view_manager_t * view_manager
Definition darktable.h:800
GList * iop
Definition develop.h:285
GList * history
Definition develop.h:275
dt_ui_t * ui
Definition gtk.h:165
dt_history_merge_strategy_t mode
dt_hm_batch_state_t batch
GModule *dt_dev_operation_t op
Definition imageop.h:286
dt_history_copy_item_t copy_paste
Definition view.h:208
A widget to manage and display image thumbnails in Ansel's lighttable and filmstrip views.
void dt_undo_end_group(dt_undo_t *self)
Definition undo.c:149
void dt_undo_start_group(dt_undo_t *self, dt_undo_type_t type)
Definition undo.c:134
void dt_undo_record(dt_undo_t *self, gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, void(*undo)(gpointer user_data, dt_undo_type_t type, dt_undo_data_t item, dt_undo_action_t action, GList **imgs), void(*free_data)(gpointer data))
Definition undo.c:163
@ DT_UNDO_LT_HISTORY
Definition undo.h:48
void * dt_undo_data_t
Definition undo.h:67