267 if(!g_main_context_is_owner(g_main_context_default()))
return;
272 GPtrArray *labels = g_ptr_array_new_with_free_func(g_free);
273 for(GList *it = g_list_first(cycle_nodes); it; it = g_list_next(it))
279 GString *cycle = g_string_new(
"");
280 for(guint
i = 0; labels &&
i < labels->len;
i++)
282 const char *s = (
const char *)g_ptr_array_index(labels,
i);
283 if(
i > 0) g_string_append(cycle,
" → ");
286 if(labels && labels->len > 0)
288 const char *first = (
const char *)g_ptr_array_index(labels, 0);
289 g_string_append(cycle,
" → ");
293 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
294 _(
"Incompatible module ordering constraints"), GTK_WINDOW(
window),
295 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, _(
"_Close"), GTK_RESPONSE_CLOSE, NULL));
296 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
298 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
301 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
302 gtk_widget_set_halign(label, GTK_ALIGN_START);
303 gtk_widget_set_valign(label, GTK_ALIGN_START);
304 gtk_label_set_selectable(GTK_LABEL(label),
TRUE);
305 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
306 gtk_label_set_max_width_chars(GTK_LABEL(label), 80);
308 GString *text = g_string_new(NULL);
309 gchar *prefix = g_markup_escape_text(
310 _(
"Module ordering constraints contain a cycle and cannot be satisfied."
311 "Merging pipeline is aborted, we default to source image pipeline order.\n\n"
312 "The next step will allow you to review and edit modules ordering manually."
313 "\n\nCycle:\n\n"), -1);
314 g_string_append(text, prefix);
316 g_string_append(text, cycle->str);
318 gtk_label_set_markup(GTK_LABEL(label), text->str);
319 gtk_box_pack_start(GTK_BOX(content_area), label,
FALSE,
FALSE, 6);
321 gtk_widget_show_all(GTK_WIDGET(dialog));
322 gtk_dialog_run(dialog);
323 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
324 gtk_widget_destroy(GTK_WIDGET(dialog));
327 if(text) g_string_free(text,
TRUE);
328 if(cycle) g_string_free(cycle,
TRUE);
329 if(labels) g_ptr_array_free(labels,
TRUE);
706 const GHashTable *mod_list_ids)
709 GHashTable *moved = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
713 if(!dest_ids || dest_ids->len == 0)
715 if(dest_ids) g_ptr_array_free(dest_ids,
TRUE);
719 GHashTable *dest_id_set = g_hash_table_new(g_str_hash, g_str_equal);
720 for(guint
i = 0;
i < dest_ids->len;
i++)
721 g_hash_table_add(dest_id_set, g_ptr_array_index(dest_ids,
i));
723 GPtrArray *src_common = g_ptr_array_new_with_free_func(g_free);
724 for(
const GList *l = g_list_first(dev_src->
iop); l; l = g_list_next(l))
729 if(g_hash_table_contains(dest_id_set,
id))
730 g_ptr_array_add(src_common,
id);
735 GHashTable *src_id_set = g_hash_table_new(g_str_hash, g_str_equal);
736 for(guint
i = 0;
i < src_common->len;
i++)
737 g_hash_table_add(src_id_set, g_ptr_array_index(src_common,
i));
739 GPtrArray *dst_common = g_ptr_array_new();
740 for(gint
i = (gint)dest_ids->len - 1;
i >= 0;
i--)
742 char *
id = (
char *)g_ptr_array_index(dest_ids,
i);
743 if(g_hash_table_contains(src_id_set,
id))
744 g_ptr_array_add(dst_common,
id);
747 const gboolean same_len = (src_common->len == dst_common->len);
748 gboolean same_order = same_len;
751 for(guint
i = 0;
i < src_common->len;
i++)
753 const char *a = (
const char *)g_ptr_array_index(src_common,
i);
754 const char *b = (
const char *)g_ptr_array_index(dst_common,
i);
765 GHashTable *src_pos = g_hash_table_new(g_str_hash, g_str_equal);
766 GHashTable *dst_pos = g_hash_table_new(g_str_hash, g_str_equal);
767 for(guint
i = 0;
i < src_common->len;
i++)
768 g_hash_table_insert(src_pos, g_ptr_array_index(src_common,
i), GINT_TO_POINTER((
int)
i));
769 for(guint
i = 0;
i < dst_common->len;
i++)
770 g_hash_table_insert(dst_pos, g_ptr_array_index(dst_common,
i), GINT_TO_POINTER((
int)
i));
772 for(guint
i = 0;
i < src_common->len;
i++)
774 const char *
id = (
const char *)g_ptr_array_index(src_common,
i);
775 const gpointer sp = g_hash_table_lookup(src_pos,
id);
776 const gpointer dp = g_hash_table_lookup(dst_pos,
id);
777 if(sp && dp && GPOINTER_TO_INT(sp) != GPOINTER_TO_INT(dp))
778 g_hash_table_replace(moved, g_strdup(
id), GINT_TO_POINTER(1));
781 g_hash_table_destroy(src_pos);
782 g_hash_table_destroy(dst_pos);
785 g_hash_table_destroy(src_id_set);
786 g_hash_table_destroy(dest_id_set);
787 g_ptr_array_free(src_common,
TRUE);
788 g_ptr_array_free(dst_common,
TRUE);
789 g_ptr_array_free(dest_ids,
TRUE);
1062 GtkSelectionData *selection_data, guint info, guint time,
1068 const guchar *data = gtk_selection_data_get_data(selection_data);
1070 gchar *src_path_str = g_strdup((
const gchar *)data);
1073 GtkTreePath *src_path = gtk_tree_path_new_from_string(src_path_str);
1077 GtkTreePath *dst_path = NULL;
1078 GtkTreeViewDropPosition pos;
1079 if(!gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),
x, y, &dst_path, &pos))
1081 gtk_tree_path_free(src_path);
1085 if(gtk_tree_path_compare(src_path, dst_path) == 0)
1087 gtk_tree_path_free(src_path);
1088 gtk_tree_path_free(dst_path);
1092 GtkTreeIter src_iter;
1093 GtkTreeIter dst_iter;
1094 if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(ctx->
store), &src_iter, src_path)
1095 || !gtk_tree_model_get_iter(GTK_TREE_MODEL(ctx->
store), &dst_iter, dst_path))
1097 gtk_tree_path_free(src_path);
1098 gtk_tree_path_free(dst_path);
1102 gboolean src_input =
FALSE;
1103 gboolean dst_input =
FALSE;
1104 gchar *src_dst_id = NULL;
1109 if(src_input || !src_dst_id || src_dst_id[0] ==
'\0')
1112 gtk_tree_path_free(src_path);
1113 gtk_tree_path_free(dst_path);
1117 GPtrArray *dest_rows = g_ptr_array_new();
1118 GPtrArray *dest_ids = g_ptr_array_new();
1120 gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ctx->
store), &iter);
1124 gboolean is_input =
FALSE;
1128 if(!is_input &&
id &&
id[0] !=
'\0')
1130 g_ptr_array_add(dest_rows, GINT_TO_POINTER(row_index));
1131 g_ptr_array_add(dest_ids,
id);
1137 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(ctx->
store), &iter);
1141 int src_row_index = gtk_tree_path_get_indices(src_path)[0];
1142 int dst_row_index = gtk_tree_path_get_indices(dst_path)[0];
1145 for(guint
i = 0;
i < dest_rows->len;
i++)
1147 if(GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i)) == src_row_index)
1157 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1158 g_ptr_array_free(dest_ids,
TRUE);
1159 g_ptr_array_free(dest_rows,
TRUE);
1160 gtk_tree_path_free(src_path);
1161 gtk_tree_path_free(dst_path);
1168 target_pos = (int)dest_ids->len;
1172 for(guint
i = 0;
i < dest_rows->len;
i++)
1174 const int row = GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i));
1175 if(
row < dst_row_index) target_pos++;
1177 if(pos == GTK_TREE_VIEW_DROP_AFTER || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
1181 if(target_pos > (
int)dest_ids->len) target_pos = (int)dest_ids->len;
1183 if(target_pos == src_pos || target_pos == src_pos + 1)
1186 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1187 g_ptr_array_free(dest_ids,
TRUE);
1188 g_ptr_array_free(dest_rows,
TRUE);
1189 gtk_tree_path_free(src_path);
1190 gtk_tree_path_free(dst_path);
1194 gchar *moved_id = (gchar *)g_ptr_array_index(dest_ids, src_pos);
1195 g_ptr_array_remove_index(dest_ids, src_pos);
1196 if(target_pos > src_pos) target_pos--;
1197 g_ptr_array_insert(dest_ids, target_pos, moved_id);
1199 for(guint
i = 0;
i < dest_rows->len &&
i < dest_ids->len;
i++)
1201 const int row = GPOINTER_TO_INT(g_ptr_array_index(dest_rows,
i));
1202 GtkTreeIter row_iter;
1203 if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(ctx->
store), &row_iter, NULL,
row))
1205 (
const char *)g_ptr_array_index(dest_ids,
i), -1);
1210 for(guint
i = 0;
i < dest_ids->len;
i++)
dt_free(g_ptr_array_index(dest_ids,
i));
1211 g_ptr_array_free(dest_ids,
TRUE);
1212 g_ptr_array_free(dest_rows,
TRUE);
1215 gtk_tree_path_free(src_path);
1216 gtk_tree_path_free(dst_path);
1273 const gboolean merge_iop_order,
const gboolean used_source_order,
1275 GHashTable *dst_last_before_by_id,
const GPtrArray *orig_labels,
1276 const GPtrArray *orig_styles,
const GHashTable *orig_ids,
1277 const GHashTable *mod_list_ids,
const char *source_label,
1282 if(!g_main_context_is_owner(g_main_context_default()))
return FALSE;
1287 const char *merge_mode = merge_iop_order ? _(
"merge") : _(
"destination");
1288 const char *strategy_name
1294 = g_strdup_printf(_(
"Copy, merging pipeline in %s and history in <b>%s</b> mode."), merge_mode, strategy_name);
1296 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
1297 _(
"History merge report"), GTK_WINDOW(
window),
1298 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, _(
"_Revert"), GTK_RESPONSE_ACCEPT, _(
"_Accept"),
1299 GTK_RESPONSE_CLOSE, NULL));
1301 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1304 gtk_label_set_markup(GTK_LABEL(label), title_text);
1305 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1306 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
1307 gtk_label_set_max_width_chars(GTK_LABEL(label), 100);
1308 gtk_box_pack_start(GTK_BOX(content_area), label,
FALSE,
FALSE, 6);
1310 const char *order_text = used_source_order ? _(
"Source pipeline order was used")
1311 : _(
"Destination pipeline order was used");
1312 const char *fallback_text = (used_source_order != merge_iop_order)
1313 ? _(
" as a fallback because we could not resolve positionning constraints with source order.")
1315 gchar *order_label_text = g_strdup_printf(
"%s%s", order_text, fallback_text);
1316 GtkWidget *order_label = gtk_label_new(order_label_text);
1317 gtk_label_set_xalign(GTK_LABEL(order_label), 0.0f);
1318 gtk_label_set_line_wrap(GTK_LABEL(order_label),
TRUE);
1319 gtk_label_set_max_width_chars(GTK_LABEL(order_label), 100);
1320 gtk_box_pack_start(GTK_BOX(content_area), order_label,
FALSE,
FALSE, 6);
1324 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(
scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1325 gtk_widget_set_size_request(
scrolled, 740, 420);
1330 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
1331 G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING,
1332 G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1334 GtkWidget *tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
store));
1335 g_object_unref(
store);
1336 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree),
TRUE);
1337 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), GTK_SELECTION_NONE);
1342 gchar *orig_title = g_strdup_printf(_(
"Original: %d %s"), dev_dest->
image_storage.
id, dst_base);
1343 gchar *src_title = !
IS_NULL_PTR(source_label) && source_label[0] !=
'\0'
1344 ? g_strdup_printf(_(
"Source: %s"), source_label)
1345 : (dev_src ? g_strdup_printf(_(
"Source: %d %s"), dev_src->
image_storage.
id, src_base)
1346 : g_strdup(_(
"Source")));
1347 gchar *dst_title = g_strdup_printf(_(
"Destination: %d %s"), dev_dest->
image_storage.
id, dst_base);
1349 GtkCellRenderer *r_orig = gtk_cell_renderer_text_new();
1350 g_object_set(r_orig,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1351 GtkTreeViewColumn *c_orig = gtk_tree_view_column_new_with_attributes(orig_title, r_orig,
"text",
1355 gtk_tree_view_column_set_expand(c_orig,
TRUE);
1356 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_orig);
1358 GtkCellRenderer *r_filet = gtk_cell_renderer_text_new();
1359 g_object_set(r_filet,
"xalign", 0.5f,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1360 GtkTreeViewColumn *c_filet = gtk_tree_view_column_new_with_attributes(
"", r_filet,
"text",
1362 gtk_tree_view_column_set_alignment(c_filet, 0.5f);
1363 gtk_tree_view_column_set_sizing(c_filet, GTK_TREE_VIEW_COLUMN_FIXED);
1364 gtk_tree_view_column_set_fixed_width(c_filet, 16);
1365 gtk_tree_view_column_set_expand(c_filet,
FALSE);
1366 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_filet);
1368 GtkCellRenderer *r_src = gtk_cell_renderer_text_new();
1369 g_object_set(r_src,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1370 GtkTreeViewColumn *c_src = gtk_tree_view_column_new_with_attributes(src_title, r_src,
"text",
1375 gtk_tree_view_column_set_expand(c_src,
TRUE);
1376 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_src);
1378 GtkCellRenderer *r_arrow = gtk_cell_renderer_text_new();
1379 g_object_set(r_arrow,
"xalign", 0.5f,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1380 GtkTreeViewColumn *c_arrow = gtk_tree_view_column_new_with_attributes(_(
"Override"), r_arrow,
"markup",
1382 gtk_tree_view_column_set_alignment(c_arrow, 0.5f);
1383 gtk_tree_view_column_set_expand(c_arrow,
FALSE);
1384 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_arrow);
1386 GtkCellRenderer *r_dst = gtk_cell_renderer_text_new();
1387 g_object_set(r_dst,
"fixed-height-from-font", 1,
"ypad", 0, NULL);
1388 GtkTreeViewColumn *c_dst = gtk_tree_view_column_new_with_attributes(dst_title, r_dst,
"text",
1394 gtk_tree_view_column_set_expand(c_dst,
TRUE);
1395 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), c_dst);
1397 gtk_container_add(GTK_CONTAINER(
scrolled), tree);
1399 GtkWidget *legend_content = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1400 gtk_widget_set_halign(legend_content, GTK_ALIGN_START);
1404 gtk_widget_set_halign(legend, GTK_ALIGN_START);
1406 gchar *txt_color = g_strdup_printf(
"<span foreground='%s'> %s </span> ",
HM_REPORT_DISABLED_FG, _(
"Module"));
1410 const gchar *symbol;
1411 const gchar *definition;
1412 gboolean symbol_markup;
1414 { _(
"[ Module ]"), _(
"inserted module"),
FALSE },
1415 {
" Module *", _(
"module uses masks"),
FALSE },
1416 { _(
"<b> Module </b>"), _(
"moved module"),
TRUE },
1417 { txt_color, _(
"disabled module (shown only if copied)"),
TRUE },
1418 {
"→", _(
"parameters overridden on the same row"),
FALSE },
1419 {
"↗ / ↘", _(
"parameters overridden on an adjacent row"),
FALSE },
1420 {
"↴", _(
"parameters overridden on a farther row"),
FALSE },
1421 {
"→*", _(
"masks overridden"),
FALSE },
1425 for(
int row = 0;
row < (int)G_N_ELEMENTS(legend_rows);
row++)
1427 GtkWidget *legend_symbol = gtk_label_new(NULL);
1428 gtk_label_set_xalign(GTK_LABEL(legend_symbol), 0.5f);
1430 if(legend_rows[
row].symbol_markup)
1431 gtk_label_set_markup(GTK_LABEL(legend_symbol), legend_rows[
row].symbol);
1433 gtk_label_set_text(GTK_LABEL(legend_symbol), legend_rows[
row].symbol);
1435 GtkWidget *legend_definition = gtk_label_new(legend_rows[
row].definition);
1436 gtk_label_set_xalign(GTK_LABEL(legend_definition), 0.0f);
1439 gtk_grid_attach(GTK_GRID(legend), legend_symbol, 0,
row, 1, 1);
1440 gtk_grid_attach(GTK_GRID(legend), legend_definition, 1,
row, 1, 1);
1444 GtkWidget *drag_label = gtk_label_new(_(
"Drag and drop modules in the “Destination” column to reorder the pipeline."));
1445 gtk_label_set_xalign(GTK_LABEL(drag_label), 0.0f);
1446 gtk_label_set_yalign(GTK_LABEL(drag_label), 0.0f);
1447 gtk_widget_set_valign(drag_label, GTK_ALIGN_START);
1448 gtk_label_set_line_wrap(GTK_LABEL(drag_label),
TRUE);
1449 gtk_label_set_max_width_chars(GTK_LABEL(drag_label), 36);
1451 gtk_box_pack_start(GTK_BOX(legend_content), legend,
FALSE,
FALSE, 0);
1452 gtk_box_pack_start(GTK_BOX(legend_content), drag_label,
FALSE,
FALSE, 0);
1453 gtk_box_pack_start(GTK_BOX(content_area), legend_content,
FALSE,
FALSE, 6);
1455 const int orig_len = orig_labels ? orig_labels->len : 0;
1458 GHashTable *dst_last_by_id = NULL;
1462 drag_hint_align.
legend = legend;
1463 drag_hint_align.
hint = drag_label;
1471 const int src_len = src_mods->len;
1472 const int dst_len = dst_mods->len;
1473 const int rows =
MAX(orig_len,
MAX(src_len, dst_len));
1474 const int orig_offset = rows - orig_len;
1475 const int src_offset = rows - src_len;
1476 const int dst_offset = rows - dst_len;
1481 reorder_ctx->
dev_src = dev_src;
1489 for(
int r = 0;
r < rows;
r++)
1491 const int orig_idx =
r - orig_offset;
1492 const int src_idx =
r - src_offset;
1493 const int dst_idx =
r - dst_offset;
1495 const char *orig_txt = (orig_idx >= 0 && !
IS_NULL_PTR(orig_labels))
1496 ? (
const char *)g_ptr_array_index((GPtrArray *)orig_labels, orig_idx)
1498 const gboolean orig_disabled = (orig_idx >= 0 && !
IS_NULL_PTR(orig_styles))
1499 && (GPOINTER_TO_INT(g_ptr_array_index((GPtrArray *)orig_styles, orig_idx))
1500 == PANGO_STYLE_ITALIC);
1515 gchar *tmp = g_strdup_printf(
"%s *", src_txt);
1521 const char *arrow =
"";
1524 gtk_list_store_append(
store, &iter);
1527 && !g_hash_table_contains((GHashTable *)orig_ids, dst_id);
1535 && g_hash_table_contains((GHashTable *)
override, dst_id);
1536 const gboolean dst_plain_existing = dst_existing && !dst_disabled && !dst_masked && !dst_overridden;
1537 const gboolean dst_dimmed_existing = dst_existing && !dst_overridden;
1539 const gboolean dst_fg_set = dst_disabled || dst_dimmed_existing;
1558 gchar *input_label = g_strdup_printf(
"%4s %s",
"0", _(
"Input image"));
1560 gtk_list_store_append(
store, &iter);
1576 GtkTargetEntry targets[] = { {
"DT_HISTORY_MERGE_DST_ROW", GTK_TARGET_SAME_WIDGET, 0 } };
1577 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(tree), GDK_BUTTON1_MASK, targets, 1, GDK_ACTION_MOVE);
1578 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(tree), targets, 1, GDK_ACTION_MOVE);
1580 gulong drag_begin_handler =
1582 gulong drag_get_handler =
1584 gulong drag_recv_handler =
1590 batch_check = gtk_check_button_new_with_label(_(
"Don't ask again for this batch"));
1591 gtk_widget_set_tooltip_text(batch_check,
1592 _(
"When checked, the chosen action (Accept or Revert) is applied silently\n"
1593 "to all remaining images in this batch without showing this report again."));
1594 gtk_box_pack_start(GTK_BOX(content_area), batch_check,
FALSE,
FALSE, 6);
1597 gtk_widget_show_all(GTK_WIDGET(dialog));
1598 const int res = gtk_dialog_run(dialog);
1600 if(batch && batch_check && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(batch_check)))
1602 if(res == GTK_RESPONSE_ACCEPT)
1604 else if(res == GTK_RESPONSE_CLOSE)
1609 g_signal_handler_disconnect(tree, drag_begin_handler);
1610 g_signal_handler_disconnect(tree, drag_get_handler);
1611 g_signal_handler_disconnect(tree, drag_recv_handler);
1615 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1616 gtk_widget_destroy(GTK_WIDGET(dialog));
1619 g_hash_table_destroy(
override);
1620 g_ptr_array_free(src_mods,
TRUE);
1621 g_ptr_array_free(dst_mods,
TRUE);
1622 if(dst_last_by_id) g_hash_table_destroy(dst_last_by_id);
1631 return (res == GTK_RESPONSE_ACCEPT || res == GTK_RESPONSE_DELETE_EVENT);
1635 const char *iop_order_key,
const char *ask_key,
1636 const gboolean iop_order_available)
1639 if(!g_main_context_is_owner(g_main_context_default()))
return TRUE;
1647 GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(
1648 title, GTK_WINDOW(
window),
1649 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1650 _(
"_Cancel"), GTK_RESPONSE_CANCEL,
1651 _(
"_Apply"), GTK_RESPONSE_OK,
1653 gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
1654 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
1656 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1657 gtk_container_set_border_width(GTK_CONTAINER(content), 12);
1658 gtk_box_set_spacing(GTK_BOX(content), 6);
1661 GtkWidget *mode_label = gtk_label_new(_(
"Where should source edits be placed relative to destination ones?"));
1662 gtk_label_set_xalign(GTK_LABEL(mode_label), 0.0f);
1663 gtk_label_set_line_wrap(GTK_LABEL(mode_label),
TRUE);
1664 gtk_box_pack_start(GTK_BOX(content), mode_label,
FALSE,
FALSE, 4);
1666 GtkWidget *radio_prepend = gtk_radio_button_new_with_label(NULL,
1667 _(
"Below (prepend) — incoming (source) is the base ; on conflicts, the original wins."));
1668 gtk_widget_set_tooltip_text(radio_prepend,
1669 _(
"Incoming edits are applied BEFORE yours in the processing stack.\n"
1670 "When the same module exists in both, your version wins."));
1671 gtk_box_pack_start(GTK_BOX(content), radio_prepend,
FALSE,
FALSE, 0);
1673 GtkWidget *radio_append = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_prepend),
1674 _(
"Above (append) — the original is the base ; on conflicts, incoming (source) wins."));
1675 gtk_widget_set_tooltip_text(radio_append,
1676 _(
"Incoming edits are applied AFTER yours in the processing stack.\n"
1677 "When the same module exists in both, the incoming version wins."));
1678 gtk_box_pack_start(GTK_BOX(content), radio_append,
FALSE,
FALSE, 0);
1680 GtkWidget *radio_replace = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_prepend),
1681 _(
"Replace — discard original edits entirely."));
1682 gtk_widget_set_tooltip_text(radio_replace,
1683 _(
"Your current edits are discarded and replaced entirely by the incoming history."));
1684 gtk_box_pack_start(GTK_BOX(content), radio_replace,
FALSE,
FALSE, 0);
1690 default: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_prepend),
TRUE);
break;
1693 gtk_box_pack_start(GTK_BOX(content), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
FALSE,
FALSE, 6);
1696 GtkWidget *iop_check = gtk_check_button_new_with_label(_(
"Use incoming (source) pipeline order"));
1697 if(iop_order_available)
1699 gtk_widget_set_tooltip_text(iop_check,
1700 _(
"When checked, the module processing order from the incoming source replaces yours.\n"
1701 "When unchecked, your current pipeline order is preserved."));
1702 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iop_check), cur_iop_order);
1706 gtk_widget_set_tooltip_text(iop_check,
1707 _(
"This source has no saved pipeline order — your current pipeline order will be kept."));
1708 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iop_check),
FALSE);
1709 gtk_widget_set_sensitive(iop_check,
FALSE);
1711 gtk_box_pack_start(GTK_BOX(content), iop_check,
FALSE,
FALSE, 0);
1713 gtk_box_pack_start(GTK_BOX(content), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
FALSE,
FALSE, 6);
1716 GtkWidget *ask_check = gtk_check_button_new_with_label(_(
"Ask every time"));
1717 gtk_widget_set_tooltip_text(ask_check,
1718 _(
"When unchecked, the current settings are used silently without showing this dialog.\n"
1719 "You can still change the defaults from the menu."));
1720 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ask_check),
TRUE);
1721 gtk_box_pack_start(GTK_BOX(content), ask_check,
FALSE,
FALSE, 0);
1723 gtk_widget_show_all(GTK_WIDGET(dialog));
1724 const int res = gtk_dialog_run(dialog);
1726 if(res == GTK_RESPONSE_OK)
1729 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_append)))
1731 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_replace)))
1735 if(iop_order_available)
1736 dt_conf_set_bool(iop_order_key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(iop_check)));
1737 dt_conf_set_bool(ask_key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ask_check)));
1740 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1741 gtk_widget_destroy(GTK_WIDGET(dialog));
1743 return res == GTK_RESPONSE_OK;