diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 4effd3e034..3d7022a437 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -153,6 +153,10 @@ changes (where available). - Added a "copy to clipboard" export storage, which places the exported images on the system clipboard. +- In the "select parts to copy" and "select parts to paste" history + dialogs, the module order is now a check box below the item list + instead of a last entry in the list itself. + ## Performance Improvements - Replaced quadratic XMP history writes with a linear algorithm. @@ -457,6 +461,9 @@ changes (where available). results depending on the number of CPU threads, and occasionally wrong colors near the left or right image edge. +- Copying a whole history stack no longer carries over the module order + that was selected in an earlier "copy parts of the history" dialog. + ## Lua ### API Version diff --git a/src/common/history.c b/src/common/history.c index 60a3e90e2f..4f3bfec4f8 100644 --- a/src/common/history.c +++ b/src/common/history.c @@ -1951,8 +1951,14 @@ gboolean dt_history_copy(const dt_imgid_t imgid) if(!dt_is_valid_imgid(imgid)) return FALSE; darktable.view_manager->copy_paste.copied_imageid = imgid; + // a plain copy of the whole stack still has to skip the modules flagged as + // unsafe to copy, see dt_history_module_skip_copy(). Only a duplicate of the + // same image, where copy_full is passed explicitly, copies everything. darktable.view_manager->copy_paste.full_copy = FALSE; + // in full copy mode, we also copy the module iop order + darktable.view_manager->copy_paste.copy_iop_order = TRUE; + if(darktable.view_manager->copy_paste.selops) { g_list_free(darktable.view_manager->copy_paste.selops); @@ -1970,7 +1976,8 @@ gboolean dt_history_copy_parts(const dt_imgid_t imgid) { if(dt_history_copy(imgid)) { - // we want to copy all history and let user select the parts needed + // the user picks the modules in the dialog, so let anything they + // tick through. darktable.view_manager->copy_paste.full_copy = TRUE; // run dialog, it will insert into selops the selected module diff --git a/src/common/history.h b/src/common/history.h index 93fc6e5da4..8f53fefcce 100644 --- a/src/common/history.h +++ b/src/common/history.h @@ -64,7 +64,8 @@ typedef struct dt_history_copy_item_t GList *selops; GtkTreeView *items; dt_imgid_t copied_imageid; - gboolean full_copy; + gboolean full_copy; // bypass some IOP flags like IOP_FLAGS_UNSAFE_COPY + // and IOP_FLAGS_HIDDEN, this is used for duplicate images. gboolean copy_iop_order; dt_history_copy_mode_t paste_mode; } dt_history_copy_item_t; diff --git a/src/gui/hist_dialog.c b/src/gui/hist_dialog.c index 8166661ca1..1806a43392 100644 --- a/src/gui/hist_dialog.c +++ b/src/gui/hist_dialog.c @@ -41,29 +41,12 @@ typedef enum _style_items_columns_t DT_HIST_ITEMS_NUM_COLS } _styles_columns_t; -static gboolean _gui_hist_is_copy_module_order_set(dt_history_copy_item_t *d) +static void _gui_hist_iop_order_toggled(GtkToggleButton *button, + gpointer data) { - /* iterate through TreeModel to find if module order was copied - * (num=-1 and active) */ - GtkTreeIter iter; - GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(d->items)); - - gboolean active = FALSE; - gboolean module_order_was_copied = FALSE; - gint num = 0; - - gtk_tree_model_get_iter_first(model, &iter); - do - { - gtk_tree_model_get(model, &iter, - DT_HIST_ITEMS_COL_ENABLED, &active, - DT_HIST_ITEMS_COL_NUM, &num, - -1); - if(active && (num == -1)) module_order_was_copied = TRUE; - } - while(gtk_tree_model_iter_next(model, &iter)); + dt_history_copy_item_t *d = (dt_history_copy_item_t *)data; - return module_order_was_copied; + d->copy_iop_order = gtk_toggle_button_get_active(button); } static GList *_gui_hist_get_active_items(dt_history_copy_item_t *d) @@ -86,7 +69,7 @@ static GList *_gui_hist_get_active_items(dt_history_copy_item_t *d) DT_HIST_ITEMS_COL_NUM, &num, -1); - if(active && num >= 0) + if(active) result = g_list_prepend(result, GINT_TO_POINTER(autoinit ? -num : num)); } while(gtk_tree_model_iter_next(model, &iter)); @@ -130,13 +113,11 @@ static void _gui_hist_copy_response(GtkDialog *dialog, case GTK_RESPONSE_OK: g->selops = _gui_hist_get_active_items(g); - g->copy_iop_order = _gui_hist_is_copy_module_order_set(g); g->paste_mode = DT_HISTORY_COPY_APPEND; break; case GTK_RESPONSE_APPLY: g->selops = _gui_hist_get_active_items(g); - g->copy_iop_order = _gui_hist_is_copy_module_order_set(g); g->paste_mode = DT_HISTORY_COPY_OVERWRITE; break; } @@ -221,7 +202,9 @@ int dt_gui_hist_dialog_new(dt_history_copy_item_t *d, const dt_imgid_t imgid, const gboolean iscopy) { - int res; + // keep previous state of the dialog + const dt_history_copy_item_t old_d = *d; + GtkWidget *window = dt_ui_main_window(darktable.gui->ui); GtkDialog *dialog = NULL; @@ -352,21 +335,6 @@ int dt_gui_hist_dialog_new(dt_history_copy_item_t *d, } } g_list_free_full(items, dt_history_item_free); - - /* last item is for copying the module order, or if paste and was selected */ - if(iscopy || d->copy_iop_order) - { - const dt_iop_order_t order = dt_ioppr_get_iop_order_version(imgid); - char *label = g_strdup_printf("%s (%s)", _("module order"), - dt_iop_order_string(order)); - gtk_list_store_insert_with_values(liststore, NULL, -1, - DT_HIST_ITEMS_COL_ENABLED, d->copy_iop_order, - DT_HIST_ITEMS_COL_ISACTIVE, is_active_pb, - DT_HIST_ITEMS_COL_NAME, label, - DT_HIST_ITEMS_COL_NUM, -1, - -1); - g_free(label); - } } else { @@ -378,10 +346,23 @@ int dt_gui_hist_dialog_new(dt_history_copy_item_t *d, G_CALLBACK(tree_on_row_activated), GTK_WIDGET(dialog)); g_object_unref(liststore); + // the module order travels as a whole, not as one of the items above + const dt_iop_order_t order = dt_ioppr_get_iop_order_version(imgid); + char *label = g_strdup_printf("%s (%s)", _("module order"), + dt_iop_order_string(order)); + GtkWidget *iop_order = gtk_check_button_new_with_label(label); + g_free(label); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iop_order), d->copy_iop_order); + g_signal_connect(iop_order, "toggled", G_CALLBACK(_gui_hist_iop_order_toggled), d); + dt_gui_dialog_add(GTK_DIALOG(dialog), iop_order); + g_signal_connect(dialog, "response", G_CALLBACK(_gui_hist_copy_response), d); gtk_widget_show_all(GTK_WIDGET(dialog)); + int res = GTK_RESPONSE_CANCEL; + while(1) { res = gtk_dialog_run(GTK_DIALOG(dialog)); @@ -391,6 +372,13 @@ int dt_gui_hist_dialog_new(dt_history_copy_item_t *d, || res == GTK_RESPONSE_APPLY) break; } + // restore previous state if needed + if(res == GTK_RESPONSE_CANCEL || res == GTK_RESPONSE_DELETE_EVENT) + { + // restore previous state if needed + *d = old_d; + } + gtk_widget_destroy(GTK_WIDGET(dialog)); g_object_unref(is_active_pb); @@ -404,6 +392,8 @@ void dt_gui_hist_dialog_init(dt_history_copy_item_t *d) d->selops = NULL; d->copied_imageid = NO_IMGID; d->copy_iop_order = FALSE; + d->full_copy = FALSE; + d->paste_mode = DT_HISTORY_COPY_APPEND; } // clang-format off