273 if(!g_main_context_is_owner(g_main_context_default()))
return;
278 GPtrArray *labels = g_ptr_array_new_with_free_func(g_free);
279 for(GList *it = g_list_first(cycle_nodes); it; it = g_list_next(it))
285 GString *cycle = g_string_new(
"");
286 for(guint
i = 0; labels &&
i < labels->len;
i++)
288 const char *s = (
const char *)g_ptr_array_index(labels,
i);
289 if(
i > 0) g_string_append(cycle,
" → ");
292 if(labels && labels->len > 0)
294 const char *first = (
const char *)g_ptr_array_index(labels, 0);
295 g_string_append(cycle,
" → ");
299 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
300 _(
"Incompatible module ordering constraints"), GTK_WINDOW(
window),
301 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, _(
"_Close"), GTK_RESPONSE_CLOSE, NULL));
302 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
304 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
307 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
308 gtk_widget_set_halign(label, GTK_ALIGN_START);
309 gtk_widget_set_valign(label, GTK_ALIGN_START);
310 gtk_label_set_selectable(GTK_LABEL(label),
TRUE);
311 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
312 gtk_label_set_max_width_chars(GTK_LABEL(label), 80);
314 GString *text = g_string_new(NULL);
315 gchar *prefix = g_markup_escape_text(
316 _(
"Module ordering constraints contain a cycle and cannot be satisfied."
317 "Merging pipeline is aborted, we default to source image pipeline order.\n\n"
318 "The next step will allow you to review and edit modules ordering manually."
319 "\n\nCycle:\n\n"), -1);
320 g_string_append(text, prefix);
322 g_string_append(text, cycle->str);
324 gtk_label_set_markup(GTK_LABEL(label), text->str);
325 gtk_box_pack_start(GTK_BOX(content_area), label,
FALSE,
FALSE, 6);
327 gtk_widget_show_all(GTK_WIDGET(dialog));
328 gtk_dialog_run(dialog);
329 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
330 gtk_widget_destroy(GTK_WIDGET(dialog));
333 if(text) g_string_free(text,
TRUE);
334 if(cycle) g_string_free(cycle,
TRUE);
335 if(labels) g_ptr_array_free(labels,
TRUE);
715 const GHashTable *mod_list_ids)
718 GHashTable *moved = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
722 if(!dest_ids || dest_ids->len == 0)
724 if(dest_ids) g_ptr_array_free(dest_ids,
TRUE);
728 GHashTable *dest_id_set = g_hash_table_new(g_str_hash, g_str_equal);
729 for(guint
i = 0;
i < dest_ids->len;
i++)
730 g_hash_table_add(dest_id_set, g_ptr_array_index(dest_ids,
i));
732 GPtrArray *src_common = g_ptr_array_new_with_free_func(g_free);
733 for(
const GList *l = g_list_first(dev_src->
iop); l; l = g_list_next(l))
738 if(g_hash_table_contains(dest_id_set,
id))
739 g_ptr_array_add(src_common,
id);
744 GHashTable *src_id_set = g_hash_table_new(g_str_hash, g_str_equal);
745 for(guint
i = 0;
i < src_common->len;
i++)
746 g_hash_table_add(src_id_set, g_ptr_array_index(src_common,
i));
748 GPtrArray *dst_common = g_ptr_array_new();
749 for(gint
i = (gint)dest_ids->len - 1;
i >= 0;
i--)
751 char *
id = (
char *)g_ptr_array_index(dest_ids,
i);
752 if(g_hash_table_contains(src_id_set,
id))
753 g_ptr_array_add(dst_common,
id);
756 const gboolean same_len = (src_common->len == dst_common->len);
757 gboolean same_order = same_len;
760 for(guint
i = 0;
i < src_common->len;
i++)
762 const char *a = (
const char *)g_ptr_array_index(src_common,
i);
763 const char *b = (
const char *)g_ptr_array_index(dst_common,
i);
774 GHashTable *src_pos = g_hash_table_new(g_str_hash, g_str_equal);
775 GHashTable *dst_pos = g_hash_table_new(g_str_hash, g_str_equal);
776 for(guint
i = 0;
i < src_common->len;
i++)
777 g_hash_table_insert(src_pos, g_ptr_array_index(src_common,
i), GINT_TO_POINTER((
int)
i));
778 for(guint
i = 0;
i < dst_common->len;
i++)
779 g_hash_table_insert(dst_pos, g_ptr_array_index(dst_common,
i), GINT_TO_POINTER((
int)
i));
781 for(guint
i = 0;
i < src_common->len;
i++)
783 const char *
id = (
const char *)g_ptr_array_index(src_common,
i);
784 const gpointer sp = g_hash_table_lookup(src_pos,
id);
785 const gpointer dp = g_hash_table_lookup(dst_pos,
id);
786 if(sp && dp && GPOINTER_TO_INT(sp) != GPOINTER_TO_INT(dp))
787 g_hash_table_replace(moved, g_strdup(
id), GINT_TO_POINTER(1));
790 g_hash_table_destroy(src_pos);
791 g_hash_table_destroy(dst_pos);
794 g_hash_table_destroy(src_id_set);
795 g_hash_table_destroy(dest_id_set);
796 g_ptr_array_free(src_common,
TRUE);
797 g_ptr_array_free(dst_common,
TRUE);
798 g_ptr_array_free(dest_ids,
TRUE);
1071 GtkSelectionData *selection_data, guint info, guint time,
1077 const guchar *data = gtk_selection_data_get_data(selection_data);
1079 gchar *src_path_str = g_strdup((
const gchar *)data);
1082 GtkTreePath *src_path = gtk_tree_path_new_from_string(src_path_str);
1086 GtkTreePath *dst_path = NULL;
1087 GtkTreeViewDropPosition pos;
1088 if(!gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),
x, y, &dst_path, &pos))
1090 gtk_tree_path_free(src_path);
1094 if(gtk_tree_path_compare(src_path, dst_path) == 0)
1096 gtk_tree_path_free(src_path);
1097 gtk_tree_path_free(dst_path);
1101 GtkTreeIter src_iter;
1102 GtkTreeIter dst_iter;
1103 if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(ctx->
store), &src_iter, src_path)
1104 || !gtk_tree_model_get_iter(GTK_TREE_MODEL(ctx->
store), &dst_iter, dst_path))
1106 gtk_tree_path_free(src_path);
1107 gtk_tree_path_free(dst_path);
1111 gboolean src_input =
FALSE;
1112 gboolean dst_input =
FALSE;
1113 gchar *src_dst_id = NULL;
1118 if(src_input || !src_dst_id || src_dst_id[0] ==
'\0')
1121 gtk_tree_path_free(src_path);
1122 gtk_tree_path_free(dst_path);
1126 GPtrArray *dest_rows = g_ptr_array_new();
1127 GPtrArray *dest_ids = g_ptr_array_new();
1129 gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ctx->
store), &iter);
1133 gboolean is_input =
FALSE;
1137 if(!is_input &&
id &&
id[0] !=
'\0')
1139 g_ptr_array_add(dest_rows, GINT_TO_POINTER(row_index));
1140 g_ptr_array_add(dest_ids,
id);
1146 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(ctx->
store), &iter);
1150 int src_row_index = gtk_tree_path_get_indices(src_path)[0];
1151 int dst_row_index = gtk_tree_path_get_indices(dst_path)[0];
1154 for(guint
i = 0;
i < dest_rows->len;
i++)
1156 if(GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i)) == src_row_index)
1166 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1167 g_ptr_array_free(dest_ids,
TRUE);
1168 g_ptr_array_free(dest_rows,
TRUE);
1169 gtk_tree_path_free(src_path);
1170 gtk_tree_path_free(dst_path);
1177 target_pos = (int)dest_ids->len;
1181 for(guint
i = 0;
i < dest_rows->len;
i++)
1183 const int row = GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i));
1184 if(
row < dst_row_index) target_pos++;
1186 if(pos == GTK_TREE_VIEW_DROP_AFTER || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
1190 if(target_pos > (
int)dest_ids->len) target_pos = (int)dest_ids->len;
1192 if(target_pos == src_pos || target_pos == src_pos + 1)
1195 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1196 g_ptr_array_free(dest_ids,
TRUE);
1197 g_ptr_array_free(dest_rows,
TRUE);
1198 gtk_tree_path_free(src_path);
1199 gtk_tree_path_free(dst_path);
1203 gchar *moved_id = (gchar *)g_ptr_array_index(dest_ids, src_pos);
1204 g_ptr_array_remove_index(dest_ids, src_pos);
1205 if(target_pos > src_pos) target_pos--;
1206 g_ptr_array_insert(dest_ids, target_pos, moved_id);
1208 for(guint
i = 0;
i < dest_rows->len &&
i < dest_ids->len;
i++)
1210 const int row = GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i));
1211 GtkTreeIter row_iter;
1212 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(ctx->
store), &row_iter, NULL,
row))
1214 (
const char *)g_ptr_array_index(dest_ids,
i), -1);
1219 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1220 g_ptr_array_free(dest_ids,
TRUE);
1221 g_ptr_array_free(dest_rows,
TRUE);
1224 gtk_tree_path_free(src_path);
1225 gtk_tree_path_free(dst_path);
1282 const gboolean merge_iop_order,
const gboolean used_source_order,
1284 GHashTable *dst_last_before_by_id,
const GHashTable *orig_ids,
1285 const GHashTable *mod_list_ids,
const char *source_label,
1290 if(!g_main_context_is_owner(g_main_context_default()))
return FALSE;
1298 GPtrArray *orig_styles = NULL;
1299 GPtrArray *orig_labels
1303 if(orig_labels) g_ptr_array_free(orig_labels,
TRUE);
1304 if(orig_styles) g_ptr_array_free(orig_styles,
TRUE);
1308 const char *merge_mode = merge_iop_order ? _(
"merge") : _(
"destination");
1309 const char *strategy_name
1315 = g_strdup_printf(_(
"Copy, merging pipeline in %s and history in <b>%s</b> mode."), merge_mode, strategy_name);
1317 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
1318 _(
"History merge report"), GTK_WINDOW(
window),
1319 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, _(
"_Revert"), GTK_RESPONSE_ACCEPT, _(
"_Accept"),
1320 GTK_RESPONSE_CLOSE, NULL));
1322 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1325 gtk_label_set_markup(GTK_LABEL(label), title_text);
1326 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1327 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
1328 gtk_label_set_max_width_chars(GTK_LABEL(label), 100);
1329 gtk_box_pack_start(GTK_BOX(content_area), label,
FALSE,
FALSE, 6);
1331 const char *order_text = used_source_order ? _(
"Source pipeline order was used")
1332 : _(
"Destination pipeline order was used");
1333 const char *fallback_text = (used_source_order != merge_iop_order)
1334 ? _(
" as a fallback because we could not resolve positionning constraints with source order.")
1336 gchar *order_label_text = g_strdup_printf(
"%s%s", order_text, fallback_text);
1337 GtkWidget *order_label = gtk_label_new(order_label_text);
1338 gtk_label_set_xalign(GTK_LABEL(order_label), 0.0f);
1339 gtk_label_set_line_wrap(GTK_LABEL(order_label),
TRUE);
1340 gtk_label_set_max_width_chars(GTK_LABEL(order_label), 100);
1341 gtk_box_pack_start(GTK_BOX(content_area), order_label,
FALSE,
FALSE, 6);
1345 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(
scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1346 gtk_widget_set_size_request(
scrolled, 740, 420);
1351 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
1352 G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING,
1353 G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1355 GtkWidget *tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
store));
1356 g_object_unref(
store);
1357 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree),
TRUE);
1358 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), GTK_SELECTION_NONE);
1363 gchar *orig_title = g_strdup_printf(_(
"Original: %d %s"), dev_dest->
image_storage.
id, dst_base);
1364 gchar *src_title = !
IS_NULL_PTR(source_label) && source_label[0] !=
'\0'
1365 ? g_strdup_printf(_(
"Source: %s"), source_label)
1366 : (dev_src ? g_strdup_printf(_(
"Source: %d %s"), dev_src->
image_storage.
id, src_base)
1367 : g_strdup(_(
"Source")));
1368 gchar *dst_title = g_strdup_printf(_(
"Destination: %d %s"), dev_dest->
image_storage.
id, dst_base);
1370 GtkCellRenderer *r_orig = gtk_cell_renderer_text_new();
1371 g_object_set(r_orig,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1372 GtkTreeViewColumn *c_orig = gtk_tree_view_column_new_with_attributes(orig_title, r_orig,
"text",
1376 gtk_tree_view_column_set_expand(c_orig,
TRUE);
1377 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_orig);
1379 GtkCellRenderer *r_filet = gtk_cell_renderer_text_new();
1380 g_object_set(r_filet,
"xalign", 0.5f,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1381 GtkTreeViewColumn *c_filet = gtk_tree_view_column_new_with_attributes(
"", r_filet,
"text",
1383 gtk_tree_view_column_set_alignment(c_filet, 0.5f);
1384 gtk_tree_view_column_set_sizing(c_filet, GTK_TREE_VIEW_COLUMN_FIXED);
1385 gtk_tree_view_column_set_fixed_width(c_filet, 16);
1386 gtk_tree_view_column_set_expand(c_filet,
FALSE);
1387 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_filet);
1389 GtkCellRenderer *r_src = gtk_cell_renderer_text_new();
1390 g_object_set(r_src,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1391 GtkTreeViewColumn *c_src = gtk_tree_view_column_new_with_attributes(src_title, r_src,
"text",
1396 gtk_tree_view_column_set_expand(c_src,
TRUE);
1397 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_src);
1399 GtkCellRenderer *r_arrow = gtk_cell_renderer_text_new();
1400 g_object_set(r_arrow,
"xalign", 0.5f,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1401 GtkTreeViewColumn *c_arrow = gtk_tree_view_column_new_with_attributes(_(
"Override"), r_arrow,
"markup",
1403 gtk_tree_view_column_set_alignment(c_arrow, 0.5f);
1404 gtk_tree_view_column_set_expand(c_arrow,
FALSE);
1405 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_arrow);
1407 GtkCellRenderer *r_dst = gtk_cell_renderer_text_new();
1408 g_object_set(r_dst,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1409 GtkTreeViewColumn *c_dst = gtk_tree_view_column_new_with_attributes(dst_title, r_dst,
"text",
1415 gtk_tree_view_column_set_expand(c_dst,
TRUE);
1416 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_dst);
1418 gtk_container_add(GTK_CONTAINER(
scrolled), tree);
1420 GtkWidget *legend_content = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1421 gtk_widget_set_halign(legend_content, GTK_ALIGN_START);
1425 gtk_widget_set_halign(legend, GTK_ALIGN_START);
1427 gchar *txt_color = g_strdup_printf(
"<span foreground='%s'> %s </span> ",
HM_REPORT_DISABLED_FG, _(
"Module"));
1431 const gchar *symbol;
1432 const gchar *definition;
1433 gboolean symbol_markup;
1435 { _(
"[ Module ]"), _(
"inserted module"),
FALSE },
1436 {
" Module *", _(
"module uses masks"),
FALSE },
1437 { _(
"<b> Module </b>"), _(
"moved module"),
TRUE },
1438 { txt_color, _(
"disabled module (shown only if copied)"),
TRUE },
1439 {
"→", _(
"parameters overridden on the same row"),
FALSE },
1440 {
"↗ / ↘", _(
"parameters overridden on an adjacent row"),
FALSE },
1441 {
"↴", _(
"parameters overridden on a farther row"),
FALSE },
1442 {
"→*", _(
"masks overridden"),
FALSE },
1446 for(
int row = 0;
row < (int)G_N_ELEMENTS(legend_rows);
row++)
1448 GtkWidget *legend_symbol = gtk_label_new(NULL);
1449 gtk_label_set_xalign(GTK_LABEL(legend_symbol), 0.5f);
1451 if(legend_rows[
row].symbol_markup)
1452 gtk_label_set_markup(GTK_LABEL(legend_symbol), legend_rows[
row].symbol);
1454 gtk_label_set_text(GTK_LABEL(legend_symbol), legend_rows[
row].symbol);
1456 GtkWidget *legend_definition = gtk_label_new(legend_rows[
row].definition);
1457 gtk_label_set_xalign(GTK_LABEL(legend_definition), 0.0f);
1460 gtk_grid_attach(GTK_GRID(legend), legend_symbol, 0,
row, 1, 1);
1461 gtk_grid_attach(GTK_GRID(legend), legend_definition, 1,
row, 1, 1);
1465 GtkWidget *drag_label = gtk_label_new(_(
"Drag and drop modules in the “Destination” column to reorder the pipeline."));
1466 gtk_label_set_xalign(GTK_LABEL(drag_label), 0.0f);
1467 gtk_label_set_yalign(GTK_LABEL(drag_label), 0.0f);
1468 gtk_widget_set_valign(drag_label, GTK_ALIGN_START);
1469 gtk_label_set_line_wrap(GTK_LABEL(drag_label),
TRUE);
1470 gtk_label_set_max_width_chars(GTK_LABEL(drag_label), 36);
1472 gtk_box_pack_start(GTK_BOX(legend_content), legend,
FALSE,
FALSE, 0);
1473 gtk_box_pack_start(GTK_BOX(legend_content), drag_label,
FALSE,
FALSE, 0);
1474 gtk_box_pack_start(GTK_BOX(content_area), legend_content,
FALSE,
FALSE, 6);
1476 const int orig_len = orig_labels ? orig_labels->len : 0;
1479 GHashTable *dst_last_by_id = NULL;
1483 drag_hint_align.
legend = legend;
1484 drag_hint_align.
hint = drag_label;
1492 const int src_len = src_mods->len;
1493 const int dst_len = dst_mods->len;
1494 const int rows =
MAX(orig_len,
MAX(src_len, dst_len));
1495 const int orig_offset = rows - orig_len;
1496 const int src_offset = rows - src_len;
1497 const int dst_offset = rows - dst_len;
1502 reorder_ctx->
dev_src = dev_src;
1510 for(
int r = 0;
r < rows;
r++)
1512 const int orig_idx =
r - orig_offset;
1513 const int src_idx =
r - src_offset;
1514 const int dst_idx =
r - dst_offset;
1516 const char *orig_txt = (orig_idx >= 0 && !
IS_NULL_PTR(orig_labels))
1517 ? (
const char *)g_ptr_array_index((GPtrArray *)orig_labels, orig_idx)
1519 const gboolean orig_disabled = (orig_idx >= 0 && !
IS_NULL_PTR(orig_styles))
1520 && (GPOINTER_TO_INT(g_ptr_array_index((GPtrArray *)orig_styles, orig_idx))
1521 == PANGO_STYLE_ITALIC);
1536 gchar *tmp = g_strdup_printf(
"%s *", src_txt);
1542 const char *arrow =
"";
1545 gtk_list_store_append(
store, &iter);
1548 && !g_hash_table_contains((GHashTable *)orig_ids, dst_id);
1556 && g_hash_table_contains((GHashTable *)
override, dst_id);
1557 const gboolean dst_plain_existing = dst_existing && !dst_disabled && !dst_masked && !dst_overridden;
1558 const gboolean dst_dimmed_existing = dst_existing && !dst_overridden;
1560 const gboolean dst_fg_set = dst_disabled || dst_dimmed_existing;
1579 gchar *input_label = g_strdup_printf(
"%4s %s",
"0", _(
"Input image"));
1581 gtk_list_store_append(
store, &iter);
1597 GtkTargetEntry targets[] = { {
"DT_HISTORY_MERGE_DST_ROW", GTK_TARGET_SAME_WIDGET, 0 } };
1598 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(tree), GDK_BUTTON1_MASK, targets, 1, GDK_ACTION_MOVE);
1599 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(tree), targets, 1, GDK_ACTION_MOVE);
1601 gulong drag_begin_handler =
1603 gulong drag_get_handler =
1605 gulong drag_recv_handler =
1611 batch_check = gtk_check_button_new_with_label(_(
"Don't ask again for this batch"));
1612 gtk_widget_set_tooltip_text(batch_check,
1613 _(
"When checked, the chosen action (Accept or Revert) is applied silently\n"
1614 "to all remaining images in this batch without showing this report again."));
1615 gtk_box_pack_start(GTK_BOX(content_area), batch_check,
FALSE,
FALSE, 6);
1618 gtk_widget_show_all(GTK_WIDGET(dialog));
1619 const int res = gtk_dialog_run(dialog);
1621 if(batch && batch_check && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(batch_check)))
1623 if(
res == GTK_RESPONSE_ACCEPT)
1625 else if(
res == GTK_RESPONSE_CLOSE)
1630 g_signal_handler_disconnect(tree, drag_begin_handler);
1631 g_signal_handler_disconnect(tree, drag_get_handler);
1632 g_signal_handler_disconnect(tree, drag_recv_handler);
1636 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1637 gtk_widget_destroy(GTK_WIDGET(dialog));
1640 g_hash_table_destroy(
override);
1641 g_ptr_array_free(src_mods,
TRUE);
1642 g_ptr_array_free(dst_mods,
TRUE);
1643 if(dst_last_by_id) g_hash_table_destroy(dst_last_by_id);
1653 g_ptr_array_free(orig_labels,
TRUE);
1654 g_ptr_array_free(orig_styles,
TRUE);
1656 return (
res == GTK_RESPONSE_ACCEPT ||
res == GTK_RESPONSE_DELETE_EVENT);
1660 const char *iop_order_key,
const char *ask_key,
1661 const gboolean iop_order_available)
1664 if(!g_main_context_is_owner(g_main_context_default()))
return TRUE;
1672 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
1673 title, GTK_WINDOW(
window),
1674 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1675 _(
"_Cancel"), GTK_RESPONSE_CANCEL,
1676 _(
"_Apply"), GTK_RESPONSE_OK,
1678 gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
1679 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
1681 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1682 gtk_container_set_border_width(GTK_CONTAINER(content), 12);
1683 gtk_box_set_spacing(GTK_BOX(content), 6);
1686 GtkWidget *mode_label = gtk_label_new(_(
"Where should source edits be placed relative to destination ones?"));
1687 gtk_label_set_xalign(GTK_LABEL(mode_label), 0.0f);
1688 gtk_label_set_line_wrap(GTK_LABEL(mode_label),
TRUE);
1689 gtk_box_pack_start(GTK_BOX(content), mode_label,
FALSE,
FALSE, 4);
1691 GtkWidget *radio_prepend = gtk_radio_button_new_with_label(NULL,
1692 _(
"Below (prepend) — incoming (source) is the base ; on conflicts, the original wins."));
1693 gtk_widget_set_tooltip_text(radio_prepend,
1694 _(
"Incoming edits are applied BEFORE yours in the processing stack.\n"
1695 "When the same module exists in both, your version wins."));
1696 gtk_box_pack_start(GTK_BOX(content), radio_prepend,
FALSE,
FALSE, 0);
1698 GtkWidget *radio_append = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_prepend),
1699 _(
"Above (append) — the original is the base ; on conflicts, incoming (source) wins."));
1700 gtk_widget_set_tooltip_text(radio_append,
1701 _(
"Incoming edits are applied AFTER yours in the processing stack.\n"
1702 "When the same module exists in both, the incoming version wins."));
1703 gtk_box_pack_start(GTK_BOX(content), radio_append,
FALSE,
FALSE, 0);
1705 GtkWidget *radio_replace = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_prepend),
1706 _(
"Replace — discard original edits entirely."));
1707 gtk_widget_set_tooltip_text(radio_replace,
1708 _(
"Your current edits are discarded and replaced entirely by the incoming history."));
1709 gtk_box_pack_start(GTK_BOX(content), radio_replace,
FALSE,
FALSE, 0);
1715 default: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_prepend),
TRUE);
break;
1718 gtk_box_pack_start(GTK_BOX(content), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
FALSE,
FALSE, 6);
1721 GtkWidget *iop_check = gtk_check_button_new_with_label(_(
"Use incoming (source) pipeline order"));
1722 if(iop_order_available)
1724 gtk_widget_set_tooltip_text(iop_check,
1725 _(
"When checked, the module processing order from the incoming source replaces yours.\n"
1726 "When unchecked, your current pipeline order is preserved."));
1727 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iop_check), cur_iop_order);
1731 gtk_widget_set_tooltip_text(iop_check,
1732 _(
"This source has no saved pipeline order — your current pipeline order will be kept."));
1733 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iop_check),
FALSE);
1734 gtk_widget_set_sensitive(iop_check,
FALSE);
1736 gtk_box_pack_start(GTK_BOX(content), iop_check,
FALSE,
FALSE, 0);
1738 gtk_box_pack_start(GTK_BOX(content), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
FALSE,
FALSE, 6);
1741 GtkWidget *ask_check = gtk_check_button_new_with_label(_(
"Ask every time"));
1742 gtk_widget_set_tooltip_text(ask_check,
1743 _(
"When unchecked, the current settings are used silently without showing this dialog.\n"
1744 "You can still change the defaults from the menu."));
1745 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ask_check),
TRUE);
1746 gtk_box_pack_start(GTK_BOX(content), ask_check,
FALSE,
FALSE, 0);
1748 gtk_widget_show_all(GTK_WIDGET(dialog));
1749 const int res = gtk_dialog_run(dialog);
1751 if(
res == GTK_RESPONSE_OK)
1754 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_append)))
1756 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_replace)))
1760 if(iop_order_available)
1761 dt_conf_set_bool(iop_order_key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(iop_check)));
1762 dt_conf_set_bool(ask_key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ask_check)));
1765 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1766 gtk_widget_destroy(GTK_WIDGET(dialog));
1768 return res == GTK_RESPONSE_OK;