263 if(!g_main_context_is_owner(g_main_context_default()))
return;
268 GPtrArray *labels = g_ptr_array_new_with_free_func(g_free);
269 for(GList *it = g_list_first(cycle_nodes); it; it = g_list_next(it))
275 GString *cycle = g_string_new(
"");
276 for(guint
i = 0; labels &&
i < labels->len;
i++)
278 const char *s = (
const char *)g_ptr_array_index(labels,
i);
279 if(
i > 0) g_string_append(cycle,
" → ");
282 if(labels && labels->len > 0)
284 const char *first = (
const char *)g_ptr_array_index(labels, 0);
285 g_string_append(cycle,
" → ");
289 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
290 _(
"Incompatible module ordering constraints"), GTK_WINDOW(window),
291 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, _(
"_Close"), GTK_RESPONSE_CLOSE, NULL));
292 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
294 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
297 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
298 gtk_widget_set_halign(label, GTK_ALIGN_START);
299 gtk_widget_set_valign(label, GTK_ALIGN_START);
300 gtk_label_set_selectable(GTK_LABEL(label),
TRUE);
301 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
302 gtk_label_set_max_width_chars(GTK_LABEL(label), 80);
304 GString *text = g_string_new(NULL);
305 gchar *prefix = g_markup_escape_text(
306 _(
"Module ordering constraints contain a cycle and cannot be satisfied.\n\nCycle:\n\n"), -1);
307 g_string_append(text, prefix);
309 g_string_append(text, cycle->str);
311 gtk_label_set_markup(GTK_LABEL(label), text->str);
312 gtk_box_pack_start(GTK_BOX(content_area), label,
FALSE,
FALSE, 6);
314 gtk_widget_show_all(GTK_WIDGET(dialog));
315 gtk_dialog_run(dialog);
316 gtk_widget_destroy(GTK_WIDGET(dialog));
318 if(text) g_string_free(text,
TRUE);
319 if(cycle) g_string_free(cycle,
TRUE);
320 if(labels) g_ptr_array_free(labels,
TRUE);
697 const GHashTable *mod_list_ids)
700 GHashTable *moved = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
704 if(!dest_ids || dest_ids->len == 0)
706 if(dest_ids) g_ptr_array_free(dest_ids,
TRUE);
710 GHashTable *dest_id_set = g_hash_table_new(g_str_hash, g_str_equal);
711 for(guint
i = 0;
i < dest_ids->len;
i++)
712 g_hash_table_add(dest_id_set, g_ptr_array_index(dest_ids,
i));
714 GPtrArray *src_common = g_ptr_array_new_with_free_func(g_free);
715 for(
const GList *l = g_list_first(dev_src->
iop); l; l = g_list_next(l))
720 if(g_hash_table_contains(dest_id_set,
id))
721 g_ptr_array_add(src_common,
id);
726 GHashTable *src_id_set = g_hash_table_new(g_str_hash, g_str_equal);
727 for(guint
i = 0;
i < src_common->len;
i++)
728 g_hash_table_add(src_id_set, g_ptr_array_index(src_common,
i));
730 GPtrArray *dst_common = g_ptr_array_new();
731 for(gint
i = (gint)dest_ids->len - 1;
i >= 0;
i--)
733 char *
id = (
char *)g_ptr_array_index(dest_ids,
i);
734 if(g_hash_table_contains(src_id_set,
id))
735 g_ptr_array_add(dst_common,
id);
738 const gboolean same_len = (src_common->len == dst_common->len);
739 gboolean same_order = same_len;
742 for(guint
i = 0;
i < src_common->len;
i++)
744 const char *a = (
const char *)g_ptr_array_index(src_common,
i);
745 const char *b = (
const char *)g_ptr_array_index(dst_common,
i);
756 GHashTable *src_pos = g_hash_table_new(g_str_hash, g_str_equal);
757 GHashTable *dst_pos = g_hash_table_new(g_str_hash, g_str_equal);
758 for(guint
i = 0;
i < src_common->len;
i++)
759 g_hash_table_insert(src_pos, g_ptr_array_index(src_common,
i), GINT_TO_POINTER((
int)
i));
760 for(guint
i = 0;
i < dst_common->len;
i++)
761 g_hash_table_insert(dst_pos, g_ptr_array_index(dst_common,
i), GINT_TO_POINTER((
int)
i));
763 for(guint
i = 0;
i < src_common->len;
i++)
765 const char *
id = (
const char *)g_ptr_array_index(src_common,
i);
766 const gpointer sp = g_hash_table_lookup(src_pos,
id);
767 const gpointer dp = g_hash_table_lookup(dst_pos,
id);
768 if(sp && dp && GPOINTER_TO_INT(sp) != GPOINTER_TO_INT(dp))
769 g_hash_table_replace(moved, g_strdup(
id), GINT_TO_POINTER(1));
772 g_hash_table_destroy(src_pos);
773 g_hash_table_destroy(dst_pos);
776 g_hash_table_destroy(src_id_set);
777 g_hash_table_destroy(dest_id_set);
778 g_ptr_array_free(src_common,
TRUE);
779 g_ptr_array_free(dst_common,
TRUE);
780 g_ptr_array_free(dest_ids,
TRUE);
1053 GtkSelectionData *selection_data, guint info, guint time,
1059 const guchar *data = gtk_selection_data_get_data(selection_data);
1061 gchar *src_path_str = g_strdup((
const gchar *)data);
1064 GtkTreePath *src_path = gtk_tree_path_new_from_string(src_path_str);
1068 GtkTreePath *dst_path = NULL;
1069 GtkTreeViewDropPosition pos;
1070 if(!gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),
x, y, &dst_path, &pos))
1072 gtk_tree_path_free(src_path);
1076 if(gtk_tree_path_compare(src_path, dst_path) == 0)
1078 gtk_tree_path_free(src_path);
1079 gtk_tree_path_free(dst_path);
1083 GtkTreeIter src_iter;
1084 GtkTreeIter dst_iter;
1085 if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(ctx->
store), &src_iter, src_path)
1086 || !gtk_tree_model_get_iter(GTK_TREE_MODEL(ctx->
store), &dst_iter, dst_path))
1088 gtk_tree_path_free(src_path);
1089 gtk_tree_path_free(dst_path);
1093 gboolean src_input =
FALSE;
1094 gboolean dst_input =
FALSE;
1095 gchar *src_dst_id = NULL;
1100 if(src_input || !src_dst_id || src_dst_id[0] ==
'\0')
1103 gtk_tree_path_free(src_path);
1104 gtk_tree_path_free(dst_path);
1108 GPtrArray *dest_rows = g_ptr_array_new();
1109 GPtrArray *dest_ids = g_ptr_array_new();
1111 gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ctx->
store), &iter);
1115 gboolean is_input =
FALSE;
1119 if(!is_input &&
id &&
id[0] !=
'\0')
1121 g_ptr_array_add(dest_rows, GINT_TO_POINTER(row_index));
1122 g_ptr_array_add(dest_ids,
id);
1128 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(ctx->
store), &iter);
1132 int src_row_index = gtk_tree_path_get_indices(src_path)[0];
1133 int dst_row_index = gtk_tree_path_get_indices(dst_path)[0];
1136 for(guint
i = 0;
i < dest_rows->len;
i++)
1138 if(GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i)) == src_row_index)
1148 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1149 g_ptr_array_free(dest_ids,
TRUE);
1150 g_ptr_array_free(dest_rows,
TRUE);
1151 gtk_tree_path_free(src_path);
1152 gtk_tree_path_free(dst_path);
1159 target_pos = (int)dest_ids->len;
1163 for(guint
i = 0;
i < dest_rows->len;
i++)
1165 const int row = GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i));
1166 if(
row < dst_row_index) target_pos++;
1168 if(pos == GTK_TREE_VIEW_DROP_AFTER || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
1172 if(target_pos > (
int)dest_ids->len) target_pos = (int)dest_ids->len;
1174 if(target_pos == src_pos || target_pos == src_pos + 1)
1177 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1178 g_ptr_array_free(dest_ids,
TRUE);
1179 g_ptr_array_free(dest_rows,
TRUE);
1180 gtk_tree_path_free(src_path);
1181 gtk_tree_path_free(dst_path);
1185 gchar *moved_id = (gchar *)g_ptr_array_index(dest_ids, src_pos);
1186 g_ptr_array_remove_index(dest_ids, src_pos);
1187 if(target_pos > src_pos) target_pos--;
1188 g_ptr_array_insert(dest_ids, target_pos, moved_id);
1190 for(guint
i = 0;
i < dest_rows->len &&
i < dest_ids->len;
i++)
1192 const int row = GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i));
1193 GtkTreeIter row_iter;
1194 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(ctx->
store), &row_iter, NULL,
row))
1196 (
const char *)g_ptr_array_index(dest_ids,
i), -1);
1201 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1202 g_ptr_array_free(dest_ids,
TRUE);
1203 g_ptr_array_free(dest_rows,
TRUE);
1206 gtk_tree_path_free(src_path);
1207 gtk_tree_path_free(dst_path);
1264 const gboolean merge_iop_order,
const gboolean used_source_order,
1266 GHashTable *dst_last_before_by_id,
const GPtrArray *orig_labels,
1267 const GPtrArray *orig_styles,
const GHashTable *orig_ids,
1268 const GHashTable *mod_list_ids,
const char *source_label,
1273 if(!g_main_context_is_owner(g_main_context_default()))
return FALSE;
1278 const char *merge_mode = merge_iop_order ? _(
"merge") : _(
"destination");
1279 const char *strategy_name
1285 = g_strdup_printf(_(
"Copy, merging pipeline in %s and history in <b>%s</b> mode."), merge_mode, strategy_name);
1287 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
1288 _(
"History merge report"), GTK_WINDOW(window),
1289 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, _(
"_Revert"), GTK_RESPONSE_ACCEPT, _(
"_Accept"),
1290 GTK_RESPONSE_CLOSE, NULL));
1292 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1295 gtk_label_set_markup(GTK_LABEL(label), title_text);
1296 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1297 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
1298 gtk_label_set_max_width_chars(GTK_LABEL(label), 100);
1299 gtk_box_pack_start(GTK_BOX(content_area), label,
FALSE,
FALSE, 6);
1301 const char *order_text = used_source_order ? _(
"Source pipeline order was used")
1302 : _(
"Destination pipeline order was used");
1303 const char *fallback_text = (used_source_order != merge_iop_order)
1304 ? _(
" as a fallback because we could not resolve positionning constraints with source order.")
1306 gchar *order_label_text = g_strdup_printf(
"%s%s", order_text, fallback_text);
1307 GtkWidget *order_label = gtk_label_new(order_label_text);
1308 gtk_label_set_xalign(GTK_LABEL(order_label), 0.0f);
1309 gtk_label_set_line_wrap(GTK_LABEL(order_label),
TRUE);
1310 gtk_label_set_max_width_chars(GTK_LABEL(order_label), 100);
1311 gtk_box_pack_start(GTK_BOX(content_area), order_label,
FALSE,
FALSE, 6);
1315 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(
scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1316 gtk_widget_set_size_request(
scrolled, 740, 420);
1321 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
1322 G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING,
1323 G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1325 GtkWidget *tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
store));
1326 g_object_unref(
store);
1327 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree),
TRUE);
1328 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), GTK_SELECTION_NONE);
1333 gchar *orig_title = g_strdup_printf(_(
"Original: %d %s"), dev_dest->
image_storage.
id, dst_base);
1334 gchar *src_title = !
IS_NULL_PTR(source_label) && source_label[0] !=
'\0'
1335 ? g_strdup_printf(_(
"Source: %s"), source_label)
1336 : (dev_src ? g_strdup_printf(_(
"Source: %d %s"), dev_src->
image_storage.
id, src_base)
1337 : g_strdup(_(
"Source")));
1338 gchar *dst_title = g_strdup_printf(_(
"Destination: %d %s"), dev_dest->
image_storage.
id, dst_base);
1340 GtkCellRenderer *r_orig = gtk_cell_renderer_text_new();
1341 g_object_set(r_orig,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1342 GtkTreeViewColumn *c_orig = gtk_tree_view_column_new_with_attributes(orig_title, r_orig,
"text",
1346 gtk_tree_view_column_set_expand(c_orig,
TRUE);
1347 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_orig);
1349 GtkCellRenderer *r_filet = gtk_cell_renderer_text_new();
1350 g_object_set(r_filet,
"xalign", 0.5f,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1351 GtkTreeViewColumn *c_filet = gtk_tree_view_column_new_with_attributes(
"", r_filet,
"text",
1353 gtk_tree_view_column_set_alignment(c_filet, 0.5f);
1354 gtk_tree_view_column_set_sizing(c_filet, GTK_TREE_VIEW_COLUMN_FIXED);
1355 gtk_tree_view_column_set_fixed_width(c_filet, 16);
1356 gtk_tree_view_column_set_expand(c_filet,
FALSE);
1357 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_filet);
1359 GtkCellRenderer *r_src = gtk_cell_renderer_text_new();
1360 g_object_set(r_src,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1361 GtkTreeViewColumn *c_src = gtk_tree_view_column_new_with_attributes(src_title, r_src,
"text",
1366 gtk_tree_view_column_set_expand(c_src,
TRUE);
1367 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_src);
1369 GtkCellRenderer *r_arrow = gtk_cell_renderer_text_new();
1370 g_object_set(r_arrow,
"xalign", 0.5f,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1371 GtkTreeViewColumn *c_arrow = gtk_tree_view_column_new_with_attributes(_(
"Override"), r_arrow,
"markup",
1373 gtk_tree_view_column_set_alignment(c_arrow, 0.5f);
1374 gtk_tree_view_column_set_expand(c_arrow,
FALSE);
1375 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_arrow);
1377 GtkCellRenderer *r_dst = gtk_cell_renderer_text_new();
1378 g_object_set(r_dst,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1379 GtkTreeViewColumn *c_dst = gtk_tree_view_column_new_with_attributes(dst_title, r_dst,
"text",
1385 gtk_tree_view_column_set_expand(c_dst,
TRUE);
1386 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_dst);
1388 gtk_container_add(GTK_CONTAINER(
scrolled), tree);
1390 GtkWidget *legend_content = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1391 gtk_widget_set_halign(legend_content, GTK_ALIGN_START);
1395 gtk_widget_set_halign(legend, GTK_ALIGN_START);
1397 gchar *txt_color = g_strdup_printf(
"<span foreground='%s'> %s </span> ",
HM_REPORT_DISABLED_FG, _(
"Module"));
1401 const gchar *symbol;
1402 const gchar *definition;
1403 gboolean symbol_markup;
1405 { _(
"[ Module ]"), _(
"inserted module"),
FALSE },
1406 {
" Module *", _(
"module uses masks"),
FALSE },
1407 { _(
"<b> Module </b>"), _(
"moved module"),
TRUE },
1408 { txt_color, _(
"disabled module (shown only if copied)"),
TRUE },
1409 {
"→", _(
"parameters overridden on the same row"),
FALSE },
1410 {
"↗ / ↘", _(
"parameters overridden on an adjacent row"),
FALSE },
1411 {
"↴", _(
"parameters overridden on a farther row"),
FALSE },
1412 {
"→*", _(
"masks overridden"),
FALSE },
1416 for(
int row = 0;
row < (int)G_N_ELEMENTS(legend_rows);
row++)
1418 GtkWidget *legend_symbol = gtk_label_new(NULL);
1419 gtk_label_set_xalign(GTK_LABEL(legend_symbol), 0.5f);
1421 if(legend_rows[
row].symbol_markup)
1422 gtk_label_set_markup(GTK_LABEL(legend_symbol), legend_rows[
row].symbol);
1424 gtk_label_set_text(GTK_LABEL(legend_symbol), legend_rows[
row].symbol);
1426 GtkWidget *legend_definition = gtk_label_new(legend_rows[
row].definition);
1427 gtk_label_set_xalign(GTK_LABEL(legend_definition), 0.0f);
1430 gtk_grid_attach(GTK_GRID(legend), legend_symbol, 0,
row, 1, 1);
1431 gtk_grid_attach(GTK_GRID(legend), legend_definition, 1,
row, 1, 1);
1435 GtkWidget *drag_label = gtk_label_new(_(
"Drag and drop modules in the “Destination” column to reorder the pipeline."));
1436 gtk_label_set_xalign(GTK_LABEL(drag_label), 0.0f);
1437 gtk_label_set_yalign(GTK_LABEL(drag_label), 0.0f);
1438 gtk_widget_set_valign(drag_label, GTK_ALIGN_START);
1439 gtk_label_set_line_wrap(GTK_LABEL(drag_label),
TRUE);
1440 gtk_label_set_max_width_chars(GTK_LABEL(drag_label), 36);
1442 gtk_box_pack_start(GTK_BOX(legend_content), legend,
FALSE,
FALSE, 0);
1443 gtk_box_pack_start(GTK_BOX(legend_content), drag_label,
FALSE,
FALSE, 0);
1444 gtk_box_pack_start(GTK_BOX(content_area), legend_content,
FALSE,
FALSE, 6);
1446 const int orig_len = orig_labels ? orig_labels->len : 0;
1449 GHashTable *dst_last_by_id = NULL;
1453 drag_hint_align.
legend = legend;
1454 drag_hint_align.
hint = drag_label;
1462 const int src_len = src_mods->len;
1463 const int dst_len = dst_mods->len;
1464 const int rows =
MAX(orig_len,
MAX(src_len, dst_len));
1465 const int orig_offset = rows - orig_len;
1466 const int src_offset = rows - src_len;
1467 const int dst_offset = rows - dst_len;
1472 reorder_ctx->
dev_src = dev_src;
1480 for(
int r = 0;
r < rows;
r++)
1482 const int orig_idx =
r - orig_offset;
1483 const int src_idx =
r - src_offset;
1484 const int dst_idx =
r - dst_offset;
1486 const char *orig_txt = (orig_idx >= 0 && !
IS_NULL_PTR(orig_labels))
1487 ? (
const char *)g_ptr_array_index((GPtrArray *)orig_labels, orig_idx)
1489 const gboolean orig_disabled = (orig_idx >= 0 && !
IS_NULL_PTR(orig_styles))
1490 && (GPOINTER_TO_INT(g_ptr_array_index((GPtrArray *)orig_styles, orig_idx))
1491 == PANGO_STYLE_ITALIC);
1506 gchar *tmp = g_strdup_printf(
"%s *", src_txt);
1512 const char *arrow =
"";
1515 gtk_list_store_append(
store, &iter);
1518 && !g_hash_table_contains((GHashTable *)orig_ids, dst_id);
1526 && g_hash_table_contains((GHashTable *)
override, dst_id);
1527 const gboolean dst_plain_existing = dst_existing && !dst_disabled && !dst_masked && !dst_overridden;
1528 const gboolean dst_dimmed_existing = dst_existing && !dst_overridden;
1530 const gboolean dst_fg_set = dst_disabled || dst_dimmed_existing;
1549 gchar *input_label = g_strdup_printf(
"%4s %s",
"0", _(
"Input image"));
1551 gtk_list_store_append(
store, &iter);
1567 GtkTargetEntry targets[] = { {
"DT_HISTORY_MERGE_DST_ROW", GTK_TARGET_SAME_WIDGET, 0 } };
1568 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(tree), GDK_BUTTON1_MASK, targets, 1, GDK_ACTION_MOVE);
1569 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(tree), targets, 1, GDK_ACTION_MOVE);
1571 gulong drag_begin_handler =
1573 gulong drag_get_handler =
1575 gulong drag_recv_handler =
1581 batch_check = gtk_check_button_new_with_label(_(
"Don't ask again for this batch"));
1582 gtk_widget_set_tooltip_text(batch_check,
1583 _(
"When checked, the chosen action (Accept or Revert) is applied silently\n"
1584 "to all remaining images in this batch without showing this report again."));
1585 gtk_box_pack_start(GTK_BOX(content_area), batch_check,
FALSE,
FALSE, 6);
1588 gtk_widget_show_all(GTK_WIDGET(dialog));
1589 const int res = gtk_dialog_run(dialog);
1591 if(batch && batch_check && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(batch_check)))
1593 if(res == GTK_RESPONSE_ACCEPT)
1595 else if(res == GTK_RESPONSE_CLOSE)
1600 g_signal_handler_disconnect(tree, drag_begin_handler);
1601 g_signal_handler_disconnect(tree, drag_get_handler);
1602 g_signal_handler_disconnect(tree, drag_recv_handler);
1606 gtk_widget_destroy(GTK_WIDGET(dialog));
1608 g_hash_table_destroy(
override);
1609 g_ptr_array_free(src_mods,
TRUE);
1610 g_ptr_array_free(dst_mods,
TRUE);
1611 if(dst_last_by_id) g_hash_table_destroy(dst_last_by_id);
1620 return (res == GTK_RESPONSE_ACCEPT || res == GTK_RESPONSE_DELETE_EVENT);
1624 const char *iop_order_key,
const char *ask_key,
1625 const gboolean iop_order_available)
1628 if(!g_main_context_is_owner(g_main_context_default()))
return TRUE;
1636 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
1637 title, GTK_WINDOW(window),
1638 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1639 _(
"_Cancel"), GTK_RESPONSE_CANCEL,
1640 _(
"_Apply"), GTK_RESPONSE_OK,
1642 gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
1643 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
1645 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1646 gtk_container_set_border_width(GTK_CONTAINER(content), 12);
1647 gtk_box_set_spacing(GTK_BOX(content), 6);
1650 GtkWidget *mode_label = gtk_label_new(_(
"Where should source edits be placed relative to destination ones?"));
1651 gtk_label_set_xalign(GTK_LABEL(mode_label), 0.0f);
1652 gtk_label_set_line_wrap(GTK_LABEL(mode_label),
TRUE);
1653 gtk_box_pack_start(GTK_BOX(content), mode_label,
FALSE,
FALSE, 4);
1655 GtkWidget *radio_prepend = gtk_radio_button_new_with_label(NULL,
1656 _(
"Below (prepend) — incoming (source) is the base ; on conflicts, the original wins."));
1657 gtk_widget_set_tooltip_text(radio_prepend,
1658 _(
"Incoming edits are applied BEFORE yours in the processing stack.\n"
1659 "When the same module exists in both, your version wins."));
1660 gtk_box_pack_start(GTK_BOX(content), radio_prepend,
FALSE,
FALSE, 0);
1662 GtkWidget *radio_append = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_prepend),
1663 _(
"Above (append) — the original is the base ; on conflicts, incoming (source) wins."));
1664 gtk_widget_set_tooltip_text(radio_append,
1665 _(
"Incoming edits are applied AFTER yours in the processing stack.\n"
1666 "When the same module exists in both, the incoming version wins."));
1667 gtk_box_pack_start(GTK_BOX(content), radio_append,
FALSE,
FALSE, 0);
1669 GtkWidget *radio_replace = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_prepend),
1670 _(
"Replace — discard original edits entirely."));
1671 gtk_widget_set_tooltip_text(radio_replace,
1672 _(
"Your current edits are discarded and replaced entirely by the incoming history."));
1673 gtk_box_pack_start(GTK_BOX(content), radio_replace,
FALSE,
FALSE, 0);
1679 default: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_prepend),
TRUE);
break;
1682 gtk_box_pack_start(GTK_BOX(content), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
FALSE,
FALSE, 6);
1685 GtkWidget *iop_check = gtk_check_button_new_with_label(_(
"Use incoming (source) pipeline order"));
1686 if(iop_order_available)
1688 gtk_widget_set_tooltip_text(iop_check,
1689 _(
"When checked, the module processing order from the incoming source replaces yours.\n"
1690 "When unchecked, your current pipeline order is preserved."));
1691 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iop_check), cur_iop_order);
1695 gtk_widget_set_tooltip_text(iop_check,
1696 _(
"This source has no saved pipeline order — your current pipeline order will be kept."));
1697 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iop_check),
FALSE);
1698 gtk_widget_set_sensitive(iop_check,
FALSE);
1700 gtk_box_pack_start(GTK_BOX(content), iop_check,
FALSE,
FALSE, 0);
1702 gtk_box_pack_start(GTK_BOX(content), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
FALSE,
FALSE, 6);
1705 GtkWidget *ask_check = gtk_check_button_new_with_label(_(
"Ask every time"));
1706 gtk_widget_set_tooltip_text(ask_check,
1707 _(
"When unchecked, the current settings are used silently without showing this dialog.\n"
1708 "You can still change the defaults from the menu."));
1709 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ask_check),
TRUE);
1710 gtk_box_pack_start(GTK_BOX(content), ask_check,
FALSE,
FALSE, 0);
1712 gtk_widget_show_all(GTK_WIDGET(dialog));
1713 const int res = gtk_dialog_run(dialog);
1715 if(res == GTK_RESPONSE_OK)
1718 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_append)))
1720 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_replace)))
1724 if(iop_order_available)
1725 dt_conf_set_bool(iop_order_key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(iop_check)));
1726 dt_conf_set_bool(ask_key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ask_check)));
1729 gtk_widget_destroy(GTK_WIDGET(dialog));
1730 return res == GTK_RESPONSE_OK;