Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion src/common/history.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/common/history.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
70 changes: 30 additions & 40 deletions src/gui/hist_dialog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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));
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
{
Expand All @@ -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));
Expand All @@ -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);
Expand All @@ -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
Expand Down