Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
edit.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2023-2025 Aurélien PIERRE.
4 Copyright (C) 2023 Luca Zulberti.
5
6 Ansel is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Ansel is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "common/darktable.h"
20#include "gui/actions/menu.h"
21#include "gui/preferences.h"
22#include "common/undo.h"
23#include "common/selection.h"
24#include "common/collection.h"
25#include "common/image_cache.h"
26#include "common/history.h"
29#include "develop/dev_history.h"
30#include "develop/develop.h"
31#include "control/control.h"
32
33
35
36static gboolean undo_sensitive_callback()
37{
40 if(IS_NULL_PTR(cv)) return FALSE;
41
42 gboolean sensitive = FALSE;
43
44 if(!strcmp(cv->module_name, "lighttable"))
46 else if(!strcmp(cv->module_name, "darkroom"))
48 else if(!strcmp(cv->module_name, "darkroom"))
50
51 return sensitive;
52}
53
54static gboolean undo_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
55{
58 if(IS_NULL_PTR(cv)) return FALSE;
59
60 if(!strcmp(cv->module_name, "lighttable"))
62 else if(!strcmp(cv->module_name, "darkroom"))
64 else if(!strcmp(cv->module_name, "map"))
66 // Beware: it needs to block callbacks declared in view, which may not be loaded.
67 // Another piece of shitty peculiar design that doesn't comply with the logic of the rest of the soft.
68 // That's what you get from ignoring modularity principles.
69 // For now we just ignore the peculiar stuff, no idea how annoying it is, seems it's only GUI candy.
70
71 return TRUE;
72}
73
74
75static gboolean redo_sensitive_callback()
76{
79 if(IS_NULL_PTR(cv)) return FALSE;
80
81 gboolean sensitive = FALSE;
82
83 if(!strcmp(cv->module_name, "lighttable"))
85 else if(!strcmp(cv->module_name, "darkroom"))
87 else if(!strcmp(cv->module_name, "darkroom"))
89
90 return sensitive;
91}
92
93
94static gboolean redo_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
95{
98 if(IS_NULL_PTR(cv)) return FALSE;
99
100 if(!strcmp(cv->module_name, "lighttable"))
102 else if(!strcmp(cv->module_name, "darkroom"))
104 else if(!strcmp(cv->module_name, "map"))
106 // see undo_callback()
107
108 return TRUE;
109}
110
111static gboolean compress_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
112{
113 GList *imgs = dt_act_on_get_images();
114 if(IS_NULL_PTR(imgs)) return FALSE;
115
116 gboolean is_darkroom_image_in_list = dt_menu_is_image_in_dev(imgs);
117
118 if(is_darkroom_image_in_list)
119 {
125
126 // Avoid running a headless compression for the current darkroom image: the history module
127 // (src/libs/history.c) compresses directly from the loaded pipeline.
128 imgs = g_list_remove(imgs, GINT_TO_POINTER(dev->image_storage.id));
129 }
130
131 if(imgs) dt_history_compress_on_list(imgs);
132
133 g_list_free(imgs);
134 imgs = NULL;
135 return TRUE;
136}
137
138static gboolean delete_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
139{
140 if(!has_active_images()) return FALSE;
141
142 GList *imgs = dt_act_on_get_images();
143 if(IS_NULL_PTR(imgs)) return FALSE;
144
145 gboolean is_darkroom_image_in_list = dt_menu_is_image_in_dev(imgs);
146
147 if(is_darkroom_image_in_list)
148 {
150 }
151
152 // We do not ask for confirmation because it can be undone by Ctrl + Z
154
155 if(is_darkroom_image_in_list)
156 {
159 }
160
162 g_list_free(imgs);
163 imgs = NULL;
164 return TRUE;
165}
166
167static gboolean copy_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
168{
169 // Allow copy only when exactly one file is selected
171 {
172 dt_control_log(_("Copy is allowed only with exactly one image selected"));
173 return FALSE;
174 }
175
177 gboolean is_darkroom_image_in_list = dt_menu_is_image_in_dev(imgs);
178 g_list_free(imgs);
179 imgs = NULL;
180
181 if(is_darkroom_image_in_list)
182 {
183 // Copy/paste reloads the source history from the database right away.
184 // Flush the current darkroom history synchronously here so the copied
185 // source matches the edit stack currently shown in the GUI.
187 }
188
190 return TRUE;
191}
192
193
194static gboolean copy_parts_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
195{
196 // Allow copy only when exactly one file is selected
198 {
199 dt_control_log(_("Copy is allowed only with exactly one image selected"));
200 return FALSE;
201 }
202
204 gboolean is_darkroom_image_in_list = dt_menu_is_image_in_dev(imgs);
205 g_list_free(imgs);
206 imgs = NULL;
207
208 if(is_darkroom_image_in_list)
209 {
210 // Selective copy opens the same immediate DB read path as full copy.
211 // Keep the persisted history in sync with the current darkroom stack
212 // before building the copy/paste state from this image.
214 }
215
217 return TRUE;
218}
219
220
222{
224}
225
226static gboolean paste_all_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
227{
229 {
230 dt_control_log(_("Paste needs selected images to work"));
231 return FALSE;
232 }
233
234 if(dt_conf_get_bool("history/paste/ask"))
235 {
236 if(!dt_gui_merge_options_dialog(_("Paste history — merge settings"),
237 "history/paste/mode",
238 "history/paste/copy_iop_order",
239 "history/paste/ask",
240 TRUE))
241 return FALSE;
242 }
243
245
246 // We don't allow pasting on darkroom image
248 imgs = g_list_remove(imgs, GINT_TO_POINTER(darktable.develop->image_storage.id));
249
250 if(imgs) dt_history_paste_on_list(imgs);
251
252 g_list_free(imgs);
253 imgs = NULL;
254 return TRUE;
255}
256
257static gboolean paste_parts_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
258{
260 {
261 dt_control_log(_("Paste needs selected images to work"));
262 return FALSE;
263 }
264
265 if(dt_conf_get_bool("history/paste/ask"))
266 {
267 if(!dt_gui_merge_options_dialog(_("Paste history (parts) — merge settings"),
268 "history/paste/mode",
269 "history/paste/copy_iop_order",
270 "history/paste/ask",
271 TRUE))
272 return FALSE;
273 }
274
276
278 {
279 g_list_free(imgs);
280 imgs = NULL;
281 return FALSE;
282 }
283
284 // We don't allow pasting on darkroom image
286 imgs = g_list_remove(imgs, GINT_TO_POINTER(darktable.develop->image_storage.id));
287
288 if(imgs) dt_history_paste_parts_on_list(imgs);
289
291 g_list_free(imgs);
292 imgs = NULL;
293 return TRUE;
294}
295
296static gboolean load_xmp_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
297{
299 if(IS_NULL_PTR(imgs)) return FALSE;
300
301 const int act_on_one = g_list_is_singleton(imgs); // list length == 1?
303 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
304 _("open sidecar file"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_OPEN,
305 _("_open"), _("_cancel"));
306 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE);
307
308 if(act_on_one)
309 {
310 //single image to load xmp to, assume we want to load from same dir
311 const int32_t imgid = GPOINTER_TO_INT(imgs->data);
312 const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r');
313 if(img && img->film_id != -1)
314 {
315 char pathname[PATH_MAX] = { 0 };
316 dt_image_film_roll_directory(img, pathname, sizeof(pathname));
317 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), pathname);
318 }
319 else
320 {
321 // handle situation where there's some problem with cache/film_id
322 // i guess that's impossible, but better safe than sorry ;)
323 dt_conf_get_folder_to_file_chooser("ui_last/import_path", GTK_FILE_CHOOSER(filechooser));
324 }
326 }
327 else
328 {
329 // multiple images, use "last import" preference
330 dt_conf_get_folder_to_file_chooser("ui_last/import_path", GTK_FILE_CHOOSER(filechooser));
331 }
332
333 GtkFileFilter *filter;
334 filter = GTK_FILE_FILTER(gtk_file_filter_new());
335 gtk_file_filter_add_pattern(filter, "*.xmp");
336 gtk_file_filter_add_pattern(filter, "*.XMP");
337 gtk_file_filter_set_name(filter, _("XMP sidecar files"));
338 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
339
340 filter = GTK_FILE_FILTER(gtk_file_filter_new());
341 gtk_file_filter_add_pattern(filter, "*");
342 gtk_file_filter_set_name(filter, _("all files"));
343 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
344
345 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
346 {
347 gchar *dtfilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
348 if(dt_history_load_and_apply_on_list(dtfilename, imgs) != 0)
349 {
350 GtkWidget *dialog
351 = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
352 GTK_BUTTONS_CLOSE, _("error loading file '%s'"), dtfilename);
353#ifdef GDK_WINDOWING_QUARTZ
355#endif
356 gtk_dialog_run(GTK_DIALOG(dialog));
357 gtk_widget_destroy(dialog);
358
359 }
360 else
361 {
363 }
364 if(!act_on_one)
365 {
366 //remember last import path if applying history to multiple images
367 dt_conf_set_folder_from_file_chooser("ui_last/import_path", GTK_FILE_CHOOSER(filechooser));
368 }
369 dt_free(dtfilename);
370 }
371
374
375 g_object_unref(filechooser);
376 g_list_free(imgs);
377 imgs = NULL;
378 return TRUE;
379}
380
381static gboolean duplicate_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
382{
384 {
387 {
388 // Duplication copies history from the source image into the new version.
389 // When the source is the current darkroom image, persist its live history
390 // before the background duplicate job reloads it from the database.
392 }
393 g_list_free(imgs);
394 imgs = NULL;
395
397 return TRUE;
398 }
399
400 dt_control_log(_("Duplication needs selected images to work"));
401 return FALSE;
402}
403
404static gboolean new_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
405{
407 {
410 {
411 // Creating a new duplicate version still starts from the current source
412 // image state, so flush the live darkroom history before duplicating it.
414 }
415 g_list_free(imgs);
416 imgs = NULL;
417
419 return TRUE;
420 }
421
422 dt_control_log(_("Creating new historys needs selected images to work"));
423 return TRUE;
424}
425
426
427static gboolean shortcuts_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
428{
430 return TRUE;
431}
432
433static gboolean history_append_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
434{
435 dt_conf_set_int("history/paste/mode", DT_HISTORY_MERGE_APPEND);
436 return TRUE;
437}
438
440{
441 return dt_conf_get_int("history/paste/mode") == DT_HISTORY_MERGE_APPEND;
442}
443
444static gboolean history_prepend_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
445{
446 dt_conf_set_int("history/paste/mode", DT_HISTORY_MERGE_PREPEND);
447 return TRUE;
448}
449
451{
452 return dt_conf_get_int("history/paste/mode") == DT_HISTORY_MERGE_PREPEND;
453}
454
455static gboolean history_replace_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval,
456 GdkModifierType mods, gpointer user_data)
457{
458 dt_conf_set_int("history/paste/mode", DT_HISTORY_MERGE_REPLACE);
459 return TRUE;
460}
461
463{
464 return dt_conf_get_int("history/paste/mode") == DT_HISTORY_MERGE_REPLACE;
465}
466
467static gboolean copy_iop_order_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
468{
469 dt_conf_set_bool("history/paste/copy_iop_order", !dt_conf_get_bool("history/paste/copy_iop_order"));
470 return TRUE;
471}
472
474{
475 return dt_conf_get_bool("history/paste/copy_iop_order");
476}
477
478static gboolean paste_ask_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
479{
480 dt_conf_set_bool("history/paste/ask", !dt_conf_get_bool("history/paste/ask"));
481 return TRUE;
482}
483
484static gboolean paste_ask_checked_callback(GtkWidget *widget)
485{
486 return dt_conf_get_bool("history/paste/ask");
487}
488
489void append_edit(GtkWidget **menus, GList **lists, const dt_menus_t index)
490{
491 add_sub_menu_entry(menus, lists, _("Undo"), index, NULL, undo_callback, NULL, NULL, undo_sensitive_callback, GDK_KEY_z, GDK_CONTROL_MASK);
492
493 add_sub_menu_entry(menus, lists, _("Redo"), index, NULL, redo_callback, NULL, NULL, redo_sensitive_callback, GDK_KEY_y, GDK_CONTROL_MASK);
494
495 add_menu_separator(menus[index]);
496
497 add_sub_menu_entry(menus, lists, _("Copy history (all)"), index, NULL, copy_callback, NULL, NULL, has_selection, GDK_KEY_c, GDK_CONTROL_MASK);
498
499 add_sub_menu_entry(menus, lists, _("Copy history (parts)..."), index, NULL, copy_parts_callback, NULL, NULL, has_selection, GDK_KEY_c, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
500
501 add_sub_menu_entry(menus, lists, _("Paste history (all)"), index, NULL, paste_all_callback, NULL, NULL,
502 paste_sensitive_callback, GDK_KEY_v, GDK_CONTROL_MASK);
503
504 add_sub_menu_entry(menus, lists, _("Paste history (parts)..."), index, NULL, paste_parts_callback, NULL, NULL,
505 paste_sensitive_callback, GDK_KEY_v, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
506
507 add_menu_separator(menus[index]);
508
509 // History merging options
510
511 add_top_submenu_entry(menus, lists, _("History pasting mode"), index);
512 GtkWidget *parent = get_last_widget(lists);
513
514 add_sub_sub_menu_entry(menus, parent, lists, _("Prepend"), index, NULL,
516 gtk_widget_set_tooltip_text(get_last_widget(lists),
517 _("Paste copied history BEFORE the current history.\n"
518 "CURRENT EDITS are applied afterwards and win conflicts."));
519
520 add_sub_sub_menu_entry(menus, parent, lists, _("Append"), index, NULL,
522 gtk_widget_set_tooltip_text(get_last_widget(lists),
523 _("Paste copied history AFTER the current history.\n"
524 "COPIED EDITS are applied afterwards and win conflicts."));
525
526 add_sub_sub_menu_entry(menus, parent, lists, _("Replace"), index, NULL,
528 gtk_widget_set_tooltip_text(get_last_widget(lists),
529 _("Discard the current history and replace it entirely with the copied history."));
530
531 add_top_submenu_entry(menus, lists, _("Nodes pasting mode"), index);
532 parent = get_last_widget(lists);
533
534 add_sub_sub_menu_entry(menus, parent, lists, _("Copy module order"), index, NULL,
536
537 add_sub_menu_entry(menus, lists, _("Ask merge settings before paste"), index, NULL,
539
540 add_menu_separator(menus[index]);
541
542 add_sub_menu_entry(menus, lists, _("Load history from XMP..."), index, NULL,
543 load_xmp_callback, NULL, NULL, has_active_images, 0, 0);
544
545 add_sub_menu_entry(menus, lists, _("Create new history"), index, NULL,
546 new_history_callback, NULL, NULL, has_active_images, GDK_KEY_n, GDK_CONTROL_MASK);
547
548 add_sub_menu_entry(menus, lists, _("Duplicate existing history"), index, NULL,
549 duplicate_callback, NULL, NULL, has_active_images, GDK_KEY_d, GDK_CONTROL_MASK);
550
551 add_sub_menu_entry(menus, lists, _("Compress history"), index, NULL,
553
554 add_sub_menu_entry(menus, lists, _("Delete history"), index, NULL,
555 delete_history_callback, NULL, NULL, has_active_images, 0, 0);
556
557 add_menu_separator(menus[index]);
558
559 add_sub_menu_entry(menus, lists, _("Preferences..."), index, NULL, GET_ACCEL_WRAPPER(dt_gui_preferences_show), NULL, NULL, NULL, 0, 0);
560 add_sub_menu_entry(menus, lists, _("Keyboard shortcuts..."), index, NULL, shortcuts_callback, NULL, NULL, NULL, 0, 0);
561}
void dt_accels_window(dt_accels_t *accels, GtkWindow *main_window)
Show the modal dialog listing all available keyboard shortcuts and letting user to set them.
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_image_film_roll_directory(const dt_image_t *img, char *pathname, size_t pathname_len)
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
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)
void dt_control_log(const char *msg,...)
Definition control.c:761
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:861
void dt_control_duplicate_images(gboolean virgin)
darktable_t darktable
Definition darktable.c:181
#define g_list_is_singleton(list)
Definition darktable.h:938
#define dt_free(ptr)
Definition darktable.h:456
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
void dt_dev_write_history(dt_develop_t *dev, gboolean async)
Thread-safe wrapper around dt_dev_write_history_ext() for dev->image_storage.id.
void dt_dev_undo_start_record(dt_develop_t *dev)
Definition develop.c:1614
void dt_dev_undo_end_record(dt_develop_t *dev)
Definition develop.c:1625
static gboolean redo_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:94
static gboolean history_prepend_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:444
static gboolean paste_sensitive_callback()
Definition edit.c:221
static gboolean delete_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:138
static gboolean new_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:404
static gboolean history_replace_checked_callback(GtkWidget *widget)
Definition edit.c:462
static gboolean undo_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:54
static gboolean compress_history_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:111
static gboolean copy_iop_order_checked_callback(GtkWidget *widget)
Definition edit.c:473
static gboolean copy_parts_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:194
static gboolean paste_all_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:226
static gboolean redo_sensitive_callback()
Definition edit.c:75
static gboolean history_append_checked_callback(GtkWidget *widget)
Definition edit.c:439
static gboolean copy_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:167
static gboolean duplicate_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:381
static gboolean paste_ask_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:478
static gboolean paste_parts_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:257
void append_edit(GtkWidget **menus, GList **lists, const dt_menus_t index)
Definition edit.c:489
static gboolean shortcuts_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:427
static gboolean history_append_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:433
static gboolean copy_iop_order_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:467
static gboolean undo_sensitive_callback()
Definition edit.c:36
static gboolean paste_ask_checked_callback(GtkWidget *widget)
Definition edit.c:484
static gboolean load_xmp_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:296
static gboolean history_prepend_checked_callback(GtkWidget *widget)
Definition edit.c:450
static gboolean history_replace_callback(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data)
Definition edit.c:455
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
gboolean dt_history_paste_on_list(const GList *list)
gboolean dt_history_copy(int32_t imgid)
gboolean dt_history_paste_parts_on_list(const GList *list)
gboolean dt_history_delete_on_list(const GList *list, gboolean undo)
gboolean dt_history_paste_parts_prepare(void)
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)
void dt_history_compress_on_image(const int32_t imgid)
@ DT_HISTORY_MERGE_REPLACE
@ DT_HISTORY_MERGE_PREPEND
@ DT_HISTORY_MERGE_APPEND
gboolean dt_gui_merge_options_dialog(const char *title, const char *mode_key, const char *iop_order_key, const char *ask_key, const gboolean iop_order_available)
Show a modal dialog to pick merge mode and pipeline order before a paste or style apply.
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
gboolean has_selection()
Definition menu.c:630
void add_sub_sub_menu_entry(GtkWidget **menus, GtkWidget *parent, GList **lists, const gchar *label, const dt_menus_t index, void *data, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gboolean(*checked_callback)(GtkWidget *widget), gboolean(*active_callback)(GtkWidget *widget), gboolean(*sensitive_callback)(GtkWidget *widget), guint key_val, GdkModifierType mods)
Definition menu.c:584
gboolean dt_menu_is_image_in_dev(GList *imgs)
Definition menu.c:660
void dt_menu_apply_dev_history_update(dt_develop_t *dev)
Reload the current darkroom history and refresh every dependent GUI.
Definition menu.c:666
GtkWidget * get_last_widget(GList **list)
Definition menu.c:618
void add_sub_menu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index, void *data, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gboolean(*checked_callback)(GtkWidget *widget), gboolean(*active_callback)(GtkWidget *widget), gboolean(*sensitive_callback)(GtkWidget *widget), guint key_val, GdkModifierType mods)
Definition menu.c:542
void add_top_submenu_entry(GtkWidget **menus, GList **lists, const gchar *label, const dt_menus_t index)
Definition menu.c:515
void add_menu_separator(GtkWidget *menu)
Definition menu.c:598
gboolean has_active_images()
Definition menu.c:636
#define GET_ACCEL_WRAPPER(cb)
Definition menu.h:244
#define MAKE_ACCEL_WRAPPER(cb)
Definition menu.h:232
dt_menus_t
Definition menu.h:42
void dt_osx_disallow_fullscreen(GtkWidget *widget)
Definition osx.mm:104
void dt_gui_preferences_show()
int32_t dt_selection_get_first_id(struct dt_selection_t *selection)
Definition selection.c:69
int dt_selection_get_length(struct dt_selection_t *selection)
Definition selection.c:179
GList * dt_selection_get_list(struct dt_selection_t *selection)
Definition selection.c:172
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_undo_t * undo
Definition darktable.h:787
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_selection_t * selection
Definition darktable.h:782
struct dt_image_cache_t * image_cache
Definition darktable.h:777
struct dt_develop_t * develop
Definition darktable.h:770
struct dt_view_manager_t * view_manager
Definition darktable.h:772
dt_image_t image_storage
Definition develop.h:259
dt_accels_t * accels
Definition gtk.h:194
dt_ui_t * ui
Definition gtk.h:164
int32_t film_id
Definition image.h:319
int32_t id
Definition image.h:319
dt_history_copy_item_t copy_paste
Definition view.h:207
char module_name[64]
Definition view.h:153
void dt_undo_do_redo(dt_undo_t *self, uint32_t filter)
Definition undo.c:272
gboolean dt_is_redo_list_populated(dt_undo_t *self, uint32_t filter)
Definition undo.c:311
void dt_undo_do_undo(dt_undo_t *self, uint32_t filter)
Definition undo.c:277
gboolean dt_is_undo_list_populated(dt_undo_t *self, uint32_t filter)
Definition undo.c:306
@ DT_UNDO_LIGHTTABLE
Definition undo.h:54
@ DT_UNDO_MAP
Definition undo.h:57
@ DT_UNDO_DEVELOP
Definition undo.h:52
const dt_view_t * dt_view_manager_get_current_view(dt_view_manager_t *vm)
Definition view.c:140