115 return g_strdup_printf(
"%s|%s", op, multi_name);
121 g_list_free(
n->previous);
163 const char *sep = strchr(
id,
'|');
171 memcpy(op,
id, op_len);
193 const char *prev_id = NULL;
195 for(
const GList *l = ids; l; l = g_list_next(l))
197 const char *
id = (
const char *)l->data;
199 if(prev_id) g_hash_table_replace(prev, g_strdup(
id), g_strdup(prev_id));
221 const char *prev_id = NULL;
223 for(
const GList *l = ids; l; l = g_list_next(l))
225 const char *
id = (
const char *)l->data;
227 if(prev_id) g_hash_table_replace(next, g_strdup(prev_id), g_strdup(
id));
246 for(
const GList *
p = g_list_first(
n->previous);
p;
p = g_list_next(
p))
247 if(
p->data == pred)
return TRUE;
259 GList *link = g_list_find(
n->previous, pred);
260 if(link)
n->previous = g_list_delete_link(
n->previous, link);
299 GHashTable *map = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
303 for(GList *l = g_list_first(history); l && idx < history_end; l = g_list_next(l), idx++)
311 "[_hm_build_last_history_by_id_from_history] history_end=%d scanned=%d entries=%d\n",
312 history_end, idx, g_hash_table_size(map));
324 GHashTable *last_by_id = NULL;
331 g_hash_table_destroy(last_by_id);
336 "[_hm_backup_dest] imgid=%d history_end=%d history_len=%d iop_order=%d labels=%u selected=%d\n",
339 mod_list_ids ? g_hash_table_size((GHashTable *)mod_list_ids) : 0);
346 "[_hm_restore_dest_from_backup] imgid=%d history_end=%d history_len=%d iop_order=%d\n",
394 GHashTable *map = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
398 for(GList *modules = g_list_first(dev->
iop); modules; modules = g_list_next(modules))
407 "[_hm_build_last_history_by_id] imgid=%d history_end=%d iop=%d entries=%d\n",
415 GHashTable *ids = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
417 for(
const GList *l = g_list_first((GList *)mod_list); l; l = g_list_next(l))
424 g_list_length((GList *)mod_list), g_hash_table_size(ids));
457 "[_hm_id_info_upsert] %s input node \n",
460 g_hash_table_insert(id_ht,
id, info);
467 info->
flags |= origin;
468 if(mod_list) info->
mod_list = mod_list;
487 for(
const GList *l = iop; l; l = g_list_next(l))
493 if(info && (info->
flags & keep_mask))
494 ids = g_list_append(ids,
id);
519 for(
const GList *l = ids; l; l = g_list_next(l))
521 const char *
id = (
const char *)l->data;
531 n->tag = g_strdup(tag);
540 if(prev)
n->previous = g_list_append(
n->previous, prev);
542 nodes = g_list_append(nodes,
n);
566 for(
const GList *l = ids; l; l = g_list_next(l))
568 const char *
id = (
const char *)l->data;
578 n->tag = g_strdup(tag);
589 const gboolean keep_edge = !focus || g_hash_table_contains((GHashTable *)focus, prev->
id)
590 || g_hash_table_contains((GHashTable *)focus,
n->id);
591 if(keep_edge)
n->previous = g_list_append(
n->previous, prev);
594 nodes = g_list_append(nodes,
n);
605 for(
const GList *l = g_list_first((GList *)modules); l; l = g_list_next(l))
619 n->tag = g_strdup(tag);
628 nodes = g_list_append(nodes,
n);
637 const char *tag, GList **out_nodes)
641 for(
const GList *l = g_list_first((GList *)modules); l; l = g_list_next(l))
652 if(!(user_info && (user_info->
flags & keep_mask) && prod_info && (prod_info->
flags & keep_mask)))
670 prod->
tag = g_strdup(tag);
671 user->
tag = g_strdup(tag);
682 nodes = g_list_append(nodes, prod);
683 nodes = g_list_append(nodes, user);
702 GList *iop_rules = NULL;
709 char next_id[256], prev_id[256];
710 snprintf(next_id,
sizeof(next_id),
"%s|", rule->op_next);
711 snprintf(prev_id,
sizeof(prev_id),
"%s|", rule->op_prev);
722 next->
tag = g_strdup(
"rule");
723 prev->
tag = g_strdup(
"rule");
732 iop_rules = g_list_append(iop_rules, next);
733 iop_rules = g_list_append(iop_rules, prev);
735 *out_nodes = iop_rules;
798 if(ctx->
id_ht) g_hash_table_destroy(ctx->
id_ht);
810 const GList *mod_list)
826 for(
const GList *l = g_list_first((GList *)mod_list); l; l = g_list_next(l))
833 for(
const GList *l = g_list_first(dev_src->
iop); l; l = g_list_next(l))
840 for(
const GList *l = g_list_first(dev_dest->
iop); l; l = g_list_next(l))
859 const GList *mod_list,
const gboolean merge_iop_order)
877 for(
const GList *l = g_list_first((GList *)mod_list); l; l = g_list_next(l))
885 if(merge_iop_order || !exists_in_dest) g_hash_table_add(ctx->
src_focus_ids, g_strdup(
id));
900 "[dt_history_merge_module_list_into_image_topological] iop-order solve: merge_iop_order=%d mod_list=%d "
902 "dst_iop=%d keep(dst+mod+rules) dest_constraints=%d src_constraints=%d focus=%d\n",
903 merge_iop_order, g_list_length((GList *)mod_list), g_list_length(dev_src->
iop),
904 g_list_length(dev_dest->
iop), g_list_length(ctx->
dest_ids), g_list_length(ctx->
src_ids),
912 const GList *dest_ids);
927 GList *dest_nodes = NULL;
928 GList *src_nodes = NULL;
929 GList *mod_nodes = NULL;
930 GList *dst_raster_nodes = NULL;
931 GList *src_raster_nodes = NULL;
932 GList *rule_nodes = NULL;
933 GHashTable *dest_rank = NULL;
953 dest_rank = g_hash_table_new(g_str_hash, g_str_equal);
957 for(
const GList *
d = g_list_first(ctx->
dest_ids);
d;
d = g_list_next(
d), rank++)
958 g_hash_table_insert(dest_rank,
d->data, GINT_TO_POINTER(rank));
960 for(
const GList *l = g_list_first(ctx->
src_ids); l; l = g_list_next(l))
962 const char *
id = (
const char *)l->data;
967 const char *lower_id = NULL;
968 const char *upper_id = NULL;
969 const char *prev_focus_id = NULL;
970 const char *next_focus_id = NULL;
972 const GList *prev_link = g_list_previous((GList *)l);
973 if(prev_link && g_hash_table_contains(ctx->
src_focus_ids, prev_link->data))
974 prev_focus_id = (
const char *)prev_link->data;
975 const GList *next_link = g_list_next(l);
976 if(next_link && g_hash_table_contains(ctx->
src_focus_ids, next_link->data))
977 next_focus_id = (
const char *)next_link->data;
980 for(
const GList *
p = g_list_first(ctx->
src_ids);
p &&
p != l;
p = g_list_next(
p))
982 const char *candidate_id = (
const char *)
p->data;
983 const int candidate_rank = GPOINTER_TO_INT(g_hash_table_lookup(dest_rank, candidate_id));
984 if(candidate_rank > lower_rank)
986 lower_rank = candidate_rank;
987 lower_id = candidate_id;
992 for(
const GList *
n = g_list_next(l);
n;
n = g_list_next(
n))
994 const char *candidate_id = (
const char *)
n->data;
995 const int candidate_rank = GPOINTER_TO_INT(g_hash_table_lookup(dest_rank, candidate_id));
996 if(candidate_rank <= lower_rank)
continue;
997 if(upper_rank == 0 || candidate_rank < upper_rank)
999 upper_rank = candidate_rank;
1000 upper_id = candidate_id;
1006 src_nodes = g_list_append(src_nodes, cur);
1013 src_nodes = g_list_append(src_nodes, lower);
1020 src_nodes = g_list_append(src_nodes, prev_focus);
1033 next_focus->
previous = g_list_append(next_focus->
previous, next_focus_prev);
1034 src_nodes = g_list_append(src_nodes, next_focus_prev);
1035 src_nodes = g_list_append(src_nodes, next_focus);
1048 src_nodes = g_list_append(src_nodes, upper_prev);
1049 src_nodes = g_list_append(src_nodes, upper);
1053 "[_hm_topo_flatten_constraints] destination slot: %s after %s%s%s before %s%s%s\n",
1054 id, lower_id ? lower_id :
"(none)", (lower_id && prev_focus_id) ?
", " :
"",
1055 prev_focus_id ? prev_focus_id :
"", upper_id ? upper_id :
"(end)",
1056 (upper_id && next_focus_id) ?
", " :
"", next_focus_id ? next_focus_id :
"");
1058 g_hash_table_destroy(dest_rank);
1072 const int dest_nodes_len = g_list_length(dest_nodes);
1073 const int src_nodes_len = g_list_length(src_nodes);
1074 const int mod_nodes_len = g_list_length(mod_nodes);
1075 const int dst_raster_nodes_len = g_list_length(dst_raster_nodes);
1076 const int src_raster_nodes_len = g_list_length(src_raster_nodes);
1077 const int rule_nodes_len = g_list_length(rule_nodes);
1080 g_list_concat(g_list_concat(dest_nodes, src_nodes),
1081 g_list_concat(mod_nodes, g_list_concat(dst_raster_nodes, src_raster_nodes))),
1084 "[_hm_topo_flatten_constraints] input nodes: dst=%d src=%d mod=%d dst-raster=%d src-raster=%d "
1085 "rules=%d total=%d\n",
1086 dest_nodes_len, src_nodes_len, mod_nodes_len, dst_raster_nodes_len, src_raster_nodes_len,
1092 "[dt_history_merge_module_list_into_image_topological] iop-order merge: flatten failed\n");
1102 if(dest_rank) g_hash_table_destroy(dest_rank);
1104 "[_hm_topo_flatten_constraints] failed while building input nodes: dst=%d src=%d mod=%d "
1105 "dst-raster=%d src-raster=%d rules=%d\n",
1106 g_list_length(dest_nodes), g_list_length(src_nodes), g_list_length(mod_nodes),
1107 g_list_length(dst_raster_nodes), g_list_length(src_raster_nodes), g_list_length(rule_nodes));
1118 const GList *dest_ids)
1132 GList *_hm_cycles = NULL;
1133 GHashTable *seen_cycles = NULL;
1135 GHashTable *src_prev = NULL;
1136 GHashTable *src_next = NULL;
1137 GHashTable *dst_prev = NULL;
1138 GHashTable *dst_next = NULL;
1139 const char *cleanup_reason = NULL;
1140 int cleanup_line = 0;
1143 cleanup_reason =
"_hm_build_prev_map_from_ids(src_ids)";
1144 cleanup_line = __LINE__;
1149 cleanup_reason =
"_hm_build_next_map_from_ids(src_ids)";
1150 cleanup_line = __LINE__;
1155 cleanup_reason =
"_hm_build_prev_map_from_ids(dest_ids)";
1156 cleanup_line = __LINE__;
1161 cleanup_reason =
"_hm_build_next_map_from_ids(dest_ids)";
1162 cleanup_line = __LINE__;
1176 seen_cycles = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
1179 cleanup_reason =
"g_hash_table_new_full(seen_cycles)";
1180 cleanup_line = __LINE__;
1185 for(GList *it = g_list_first(flat); it; it = g_list_next(it))
1190 for(GList *
p = g_list_first(a->
previous);
p;
p = g_list_next(
p))
1197 const char *id1 = a->
id;
1198 const char *id2 = b->id;
1199 if(strcmp(id1, id2) > 0)
1205 gchar *
key = g_strdup_printf(
"%s<->%s", id1, id2);
1208 cleanup_reason =
"g_strdup_printf(cycle key)";
1209 cleanup_line = __LINE__;
1212 if(g_hash_table_contains(seen_cycles,
key))
1217 g_hash_table_add(seen_cycles,
key);
1219 _hm_cycle_t *c = g_new0(_hm_cycle_t, 1);
1222 cleanup_reason =
"g_new0(_hm_cycle_t)";
1223 cleanup_line = __LINE__;
1235 _hm_cycles = g_list_append(_hm_cycles, c);
1242 const _hm_cycle_t *first = (
const _hm_cycle_t *)_hm_cycles->data;
1245 const char *sp = (faulty && src_prev) ? (
const char *)g_hash_table_lookup(src_prev, faulty->
id) : NULL;
1246 const char *sn = (faulty && src_next) ? (
const char *)g_hash_table_lookup(src_next, faulty->
id) : NULL;
1247 const char *dp = (faulty && dst_prev) ? (
const char *)g_hash_table_lookup(dst_prev, faulty->
id) : NULL;
1248 const char *dn = (faulty && dst_next) ? (
const char *)g_hash_table_lookup(dst_next, faulty->
id) : NULL;
1252 "[dt_history_merge_module_list_into_image_topological] incompatible constraints: found %d 2-cycle(s)\n",
1253 g_list_length(_hm_cycles));
1259 "[dt_history_merge_module_list_into_image_topological] incompatible constraints choice: %s\n",
1262 for(GList *l = _hm_cycles; l; l = g_list_next(l))
1264 _hm_cycle_t *c = (_hm_cycle_t *)l->data;
1270 const char *want_prev_a = NULL;
1271 const char *want_prev_b = NULL;
1275 want_prev_a = src_prev ? (
const char *)g_hash_table_lookup(src_prev, a->
id) : NULL;
1276 want_prev_b = src_prev ? (
const char *)g_hash_table_lookup(src_prev, b->id) : NULL;
1281 want_prev_a = dst_prev ? (
const char *)g_hash_table_lookup(dst_prev, a->
id) : NULL;
1282 want_prev_b = dst_prev ? (
const char *)g_hash_table_lookup(dst_prev, b->id) : NULL;
1285 if(want_prev_a && !strcmp(want_prev_a, b->id))
1290 else if(want_prev_b && !strcmp(want_prev_b, a->
id))
1298 const char *dpa = dst_prev ? (
const char *)g_hash_table_lookup(dst_prev, a->
id) : NULL;
1299 const char *dpb = dst_prev ? (
const char *)g_hash_table_lookup(dst_prev, b->id) : NULL;
1300 if(dpa && !strcmp(dpa, b->id))
1302 else if(dpb && !strcmp(dpb, a->
id))
1312 g_hash_table_destroy(seen_cycles);
1313 g_hash_table_destroy(src_prev);
1314 g_hash_table_destroy(src_next);
1315 g_hash_table_destroy(dst_prev);
1316 g_hash_table_destroy(dst_next);
1321 "[_hm_topo_resolve_incompatible_constraints] cleanup from line %d: %s\n",
1322 cleanup_line, cleanup_reason ? cleanup_reason :
"unknown");
1323 if(seen_cycles) g_hash_table_destroy(seen_cycles);
1324 if(src_prev) g_hash_table_destroy(src_prev);
1325 if(src_next) g_hash_table_destroy(src_next);
1326 if(dst_prev) g_hash_table_destroy(dst_prev);
1327 if(dst_next) g_hash_table_destroy(dst_next);
1345 GList *cycle_nodes = NULL;
1350 "unsatisfiable constraints (cycle)\n");
1354 g_list_free(cycle_nodes);
1362 g_list_free(cycle_nodes);
1385 GList *ordered_modules = NULL;
1390 for(
const GList *l = g_list_first(ctx->
sorted); l; l = g_list_next(l))
1420 ordered_modules = g_list_append(ordered_modules, mod_dest);
1427 g_list_free(ordered_modules);
1428 ordered_modules = NULL;
1433 "[dt_history_merge_module_list_into_image_topological] iop-order solve: created=%d copied=%d\n",
1439 const GList *mod_list,
const gboolean merge_iop_order)
1455 "[_hm_try_merge_iop_order_topologically] start merge_iop_order=%d modules=%d dst_iop=%d src_iop=%d\n",
1456 merge_iop_order, g_list_length((GList *)mod_list), g_list_length(dev_dest->
iop),
1457 g_list_length(dev_src->
iop));
1495 "[_hm_try_merge_iop_order_topologically] success merge_iop_order=%d dst_iop=%d order=%d\n",
1496 merge_iop_order, g_list_length(dev_dest->
iop), g_list_length(dev_dest->
iop_order_list));
1511 for(GList *it = g_list_first(history); it; it = g_list_next(it), idx++)
1530 const int history_len = g_list_length(dev_dest->
history);
1532 if(history_end >= history_len)
1535 "[_hm_truncate_dest_redo_tail] no redo tail: imgid=%d end=%d len=%d\n",
1541 "[dt_history_merge_module_list_into_image_advanced] truncating destination redo tail: end=%d len=%d\n",
1542 history_end, history_len);
1547 GList *link = g_list_nth(dev_dest->
history, history_end);
1551 GList *next = g_list_next(link);
1559 const GList *mod_list,
const gboolean merge_iop_order,
1583 if(dest_imgid <= 0)
return 1;
1589 gboolean used_source_order = merge_iop_order;
1590 gboolean revert =
FALSE;
1591 GHashTable *mod_list_ids = NULL;
1592 GHashTable *src_last_by_id = NULL;
1593 GHashTable *dst_last_before_by_id = NULL;
1595 const char *cleanup_reason = NULL;
1596 int cleanup_line = 0;
1601 cleanup_reason =
"_hm_build_id_set_from_mod_list(mod_list)";
1602 cleanup_line = __LINE__;
1607 cleanup_reason =
"_hm_backup_dest(dev_dest)";
1608 cleanup_line = __LINE__;
1613 cleanup_reason =
"_hm_build_last_history_by_id(dev_src)";
1614 cleanup_line = __LINE__;
1619 cleanup_reason =
"_hm_build_last_history_by_id(dev_dest)";
1620 cleanup_line = __LINE__;
1624 if(force_new_modules)
1626 "temporarily unsupported, ignoring\n");
1629 "[dt_history_merge] imgid=%d merge_iop_order=%d strategy=%d "
1630 "force_new=%d modules=%d\n",
1631 dest_imgid, merge_iop_order, strategy, force_new_modules, g_list_length((GList *)mod_list));
1645 used_source_order =
FALSE;
1651 cleanup_reason =
"_hm_try_merge_iop_order_topologically() retry";
1652 cleanup_line = __LINE__;
1661 GList *temp_history = NULL;
1663 for(
const GList *l = g_list_first((GList *)mod_list); l; l = g_list_next(l))
1682 "[dt_history_merge] build temp history: src=%s multi='%s' priority=%d hist=%s dest=%s dest_priority=%d\n",
1684 hist_src ?
"yes" :
"no", mod_dest ?
"yes" :
"no",
1688 cleanup_reason =
"dt_dev_history_item_from_source_history_item()";
1689 cleanup_line = __LINE__;
1693 temp_history = g_list_append(temp_history, hist);
1698 dev_dest->
history = g_list_concat(dev_dest->
history, temp_history);
1700 dev_dest->
history = g_list_concat(temp_history, dev_dest->
history);
1714 src_last_by_id, dst_last_before_by_id, backup.
orig_labels,
1721 cleanup_reason =
"_hm_show_merge_report_popup() revert";
1722 cleanup_line = __LINE__;
1734 cleanup_line, cleanup_reason);
1735 if(src_last_by_id) g_hash_table_destroy(src_last_by_id);
1736 if(dst_last_before_by_id) g_hash_table_destroy(dst_last_before_by_id);
1737 if(mod_list_ids) g_hash_table_destroy(mod_list_ids);
static void error(char *msg)
void cleanup(dt_imageio_module_format_t *self)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_print(dt_debug_thread_t thread, const char *msg,...)
static void dt_free_gpointer(gpointer ptr)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
dt_iop_module_t * dt_dev_get_module_instance(dt_develop_t *dev, const char *op, const char *multi_name, const int multi_priority)
Find a module instance by op name and instance metadata.
void dt_dev_free_history_item(gpointer data)
Free a single history item (used as GList free callback).
dt_iop_module_t * dt_dev_create_module_instance(dt_develop_t *dev, const char *op, const char *multi_name, const int multi_priority, gboolean use_next_priority)
Create a new module instance from an existing base .so.
int dt_dev_copy_module_contents(dt_develop_t *dev_dest, dt_develop_t *dev_src, dt_iop_module_t *mod_dest, const dt_iop_module_t *mod_src)
void dt_dev_history_free_history(dt_develop_t *dev)
Free the whole history list attached to dev->history.
void dt_dev_pop_history_items_ext(dt_develop_t *dev)
Apply history items to module params up to dev->history_end.
int dt_dev_history_item_from_source_history_item(dt_develop_t *dev_dest, dt_develop_t *dev_src, const dt_dev_history_item_t *hist_src, dt_iop_module_t *mod_dest, dt_dev_history_item_t **out_hist)
dt_dev_history_item_t * dt_dev_history_get_last_item_by_module(GList *history_list, dt_iop_module_t *module, int history_end)
Find the last history item referencing a module up to history_end.
void dt_dev_write_history_ext(dt_develop_t *dev, const int32_t imgid)
Write dev->history to DB and XMP for a given image id.
void dt_dev_set_history_end_ext(struct dt_develop_t *dev, const uint32_t index)
Set the history end index (GUI perspective).
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
GList * dt_history_duplicate(GList *hist)
Deep-copy a history list.
static int _hm_build_last_history_by_id_from_history(GList *history, const int history_end, GHashTable **out_map)
static void _hm_free_input_nodes(GList *input_nodes)
static int _hm_topo_resolve_incompatible_constraints(GList *flat, GHashTable *id_ht, const GList *src_ids, const GList *dest_ids)
static void _hm_truncate_dest_redo_tail(dt_develop_t *dev_dest)
void _hm_id_to_op_name(const char *id, char *op, char *name)
static void _hm_backup_cleanup(_hm_dest_backup_t *backup)
int dt_history_merge(dt_develop_t *dev_dest, dt_develop_t *dev_src, const int32_t dest_imgid, const GList *mod_list, const gboolean merge_iop_order, const dt_history_merge_strategy_t strategy, const gboolean force_new_modules, const char *source_label, dt_hm_batch_state_t *batch)
Merge a list of modules into a destination image, solving pipeline topologies for proper insertion of...
int _hm_build_last_history_by_id(const dt_develop_t *dev, GHashTable **out_map)
static int _hm_topo_build_id_info_table(_hm_topo_merge_ctx_t *ctx, dt_develop_t *dev_dest, dt_develop_t *dev_src, const GList *mod_list)
char * _hm_make_node_id(const char *op, const char *multi_name)
static int _hm_topo_build_constraint_ids(_hm_topo_merge_ctx_t *ctx, dt_develop_t *dev_dest, dt_develop_t *dev_src, const GList *mod_list, const gboolean merge_iop_order)
static gboolean _hm_node_has_predecessor(const dt_digraph_node_t *n, const dt_digraph_node_t *pred)
static int _hm_build_input_nodes_from_ids(const GList *ids, const char *tag, GList **out_nodes)
static void _hm_remove_predecessor(dt_digraph_node_t *n, const dt_digraph_node_t *pred)
static _hm_id_info_t * _hm_id_info_upsert(GHashTable *id_ht, const char *op, const char *multi_name, const _hm_id_origin_t origin, const dt_iop_module_t *mod_list, const dt_iop_module_t *src_iop, dt_iop_module_t *dst_iop)
static void _hm_topo_merge_cleanup(_hm_topo_merge_ctx_t *ctx)
static int _hm_build_raster_mask_nodes_from_modules(const GList *modules, GHashTable *id_ht, const guint keep_mask, const char *tag, GList **out_nodes)
static int _hm_topo_apply_solution(_hm_topo_merge_ctx_t *ctx, dt_develop_t *dev_dest, dt_develop_t *dev_src)
static void _hm_free_input_node(dt_digraph_node_t *n)
static int _hm_topo_flatten_constraints(_hm_topo_merge_ctx_t *ctx)
static int _hm_try_merge_iop_order_topologically(dt_develop_t *dev_dest, dt_develop_t *dev_src, const GList *mod_list, const gboolean merge_iop_order)
static int _hm_build_input_nodes_from_ids_filtered(const GList *ids, const char *tag, const GHashTable *focus, GList **out_nodes)
static int _hm_ids_from_iop_list(GList *iop, GHashTable *id_ht, const guint keep_mask, GList **out_ids)
static int _hm_backup_dest(const dt_develop_t *dev_dest, const GHashTable *mod_list_ids, _hm_dest_backup_t *backup)
static int _hm_build_prev_map_from_ids(const GList *ids, GHashTable **out_prev)
static int _hm_build_next_map_from_ids(const GList *ids, GHashTable **out_next)
static int _hm_build_isolated_nodes_from_modules(const GList *modules, const char *tag, GList **out_nodes)
static int _hm_topo_sort_constraints(_hm_topo_merge_ctx_t *ctx)
static int _hm_build_id_set_from_mod_list(const GList *mod_list, GHashTable **out_ids)
static void _hm_renumber_history(GList *history)
static int _iop_rules(GHashTable *keep, GList **out_nodes)
static void _hm_restore_dest_from_backup(dt_develop_t *dev_dest, _hm_dest_backup_t *backup)
dt_history_merge_strategy_t
@ DT_HISTORY_MERGE_APPEND
gboolean _hm_show_merge_report_popup(dt_develop_t *dev_dest, dt_develop_t *dev_src, const gboolean merge_iop_order, const gboolean used_source_order, const dt_history_merge_strategy_t strategy, GHashTable *src_last_by_id, GHashTable *dst_last_before_by_id, const GPtrArray *orig_labels, const GPtrArray *orig_styles, const GHashTable *orig_ids, const GHashTable *mod_list_ids, const char *source_label, dt_hm_batch_state_t *batch)
gboolean _hm_warn_missing_raster_producers(const GList *mod_list)
void _hm_show_toposort_cycle_popup(GList *cycle_nodes, GHashTable *id_ht)
dt_hm_constraint_choice_t _hm_ask_user_constraints_choice(GHashTable *id_ht, const char *faulty_id, const char *src_prev, const char *src_next, const char *dst_prev, const char *dst_next)
GPtrArray * _hm_collect_labels_from_history_map(GHashTable *last_by_id, const GHashTable *mod_list_ids, GPtrArray **out_styles)
dt_hm_constraint_choice_t
@ DT_HM_CONSTRAINTS_PREFER_SRC
dt_iop_module_t * dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
void dt_ioppr_rebuild_iop_order_from_modules(struct dt_develop_t *dev, GList *ordered_modules)
Rebuild dev->iop_order_list from a list of ordered modules.
GList * dt_ioppr_iop_order_copy_deep(GList *iop_order_list)
Deep-copy an order list.
void dt_ioppr_resync_pipeline(dt_develop_t *dev, const int32_t imgid, const char *msg, gboolean check_duplicates)
Resynchronize pipeline order and related structures.
const dt_iop_module_t * src_iop
dt_iop_module_t * dst_iop
const dt_iop_module_t * mod_list
gboolean copy_module_contents
GHashTable * src_focus_ids
gboolean source_iop_order
dt_hm_batch_decision_t decision
struct dt_iop_module_t::@31 raster_mask
struct dt_iop_module_t::@31::@32 source
GModule *dt_dev_operation_t op
struct dt_iop_module_t::@31::@33 sink
void dt_digraph_cleanup_full(GList *nodes, GHashTable *node_ht, dt_node_user_data_destroy_t user_destroy)
Free a canonical graph (nodes, constraints, ids) in one call.
int flatten_nodes(GList *input_nodes, GList **out_nodes)
Canonicalize / merge duplicated nodes by id.
dt_digraph_node_t * dt_digraph_node_new(const char *id)
Allocate and initialize a new digraph node with the given id.
int topological_sort(GList *nodes, GList **sorted, GList **cycle_out)
Perform a topological sort using depth-first search (DFS).
Small directed-graph helper for constraint aggregation and topological sorting.