Refactor: Nodes: allow passing already unique name/identifier to node copy function

This is useful when the src node name is not unique, but the caller can provide
a unique name more efficiently then if the function has to compute the name
automatically.
This commit is contained in:
Jacques Lucke
2025-08-02 11:02:10 +02:00
parent 252b983c0c
commit 5b73f798d0
5 changed files with 38 additions and 17 deletions

View File

@@ -964,14 +964,15 @@ void node_rebuild_id_vector(bNodeTree &node_tree);
/**
* \note keeps socket list order identical, for copying links.
* \param use_unique: If true, make sure the node's identifier and name are unique in the new
* tree. Must be *true* if the \a dst_tree had nodes that weren't in the source node's tree.
* Must be *false* when simply copying a node tree, so that identifiers don't change.
* \param dst_name: The name of the copied node. This is expected to be unique in the destination
* tree if provided. If not provided, the src name is used and made unique.
* \param dst_identifier: Same ad dst_name, but for the identifier.
*/
bNode *node_copy_with_mapping(bNodeTree *dst_tree,
const bNode &node_src,
int flag,
bool use_unique,
std::optional<StringRefNull> dst_unique_name,
std::optional<int> dst_unique_identifier,
Map<const bNodeSocket *, bNodeSocket *> &new_socket_map);
bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, int flag, bool use_unique);

View File

@@ -162,7 +162,7 @@ static void ntree_copy_data(Main * /*bmain*/,
LISTBASE_FOREACH_INDEX (const bNode *, src_node, &ntree_src->nodes, i) {
/* Don't find a unique name for every node, since they should have valid names already. */
bNode *new_node = node_copy_with_mapping(
ntree_dst, *src_node, flag_subdata, false, socket_map);
ntree_dst, *src_node, flag_subdata, src_node->name, src_node->identifier, socket_map);
dst_runtime.nodes_by_id.add_new(new_node);
new_node->runtime->index_in_tree = i;
}
@@ -3353,20 +3353,28 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
bNode *node_copy_with_mapping(bNodeTree *dst_tree,
const bNode &node_src,
const int flag,
const bool use_unique,
const std::optional<StringRefNull> dst_unique_name,
const std::optional<int> dst_unique_identifier,
Map<const bNodeSocket *, bNodeSocket *> &socket_map)
{
bNode *node_dst = MEM_mallocN<bNode>(__func__);
*node_dst = node_src;
node_dst->runtime = MEM_new<bNodeRuntime>(__func__);
if (dst_unique_name) {
STRNCPY_UTF8(node_dst->name, dst_unique_name->c_str());
}
else if (dst_tree) {
node_unique_name(*dst_tree, *node_dst);
}
if (dst_unique_identifier) {
node_dst->identifier = *dst_unique_identifier;
}
else if (dst_tree) {
node_unique_id(*dst_tree, *node_dst);
}
/* Can be called for nodes outside a node tree (e.g. clipboard). */
if (dst_tree) {
if (use_unique) {
node_unique_name(*dst_tree, *node_dst);
node_unique_id(*dst_tree, *node_dst);
}
BLI_addtail(&dst_tree->nodes, node_dst);
}
@@ -3566,7 +3574,13 @@ void node_socket_move_default_value(Main & /*bmain*/,
bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, const int flag, const bool use_unique)
{
Map<const bNodeSocket *, bNodeSocket *> socket_map;
return node_copy_with_mapping(dst_tree, src_node, flag, use_unique, socket_map);
return node_copy_with_mapping(
dst_tree,
src_node,
flag,
use_unique ? std::nullopt : std::make_optional<StringRefNull>(src_node.name),
use_unique ? std::nullopt : std::make_optional(src_node.identifier),
socket_map);
}
static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)

View File

@@ -227,8 +227,13 @@ struct NodeClipboard {
{
/* No ID reference-counting, this node is virtual,
* detached from any actual Blender data currently. */
bNode *new_node = bke::node_copy_with_mapping(
nullptr, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN, false, socket_map);
bNode *new_node = bke::node_copy_with_mapping(nullptr,
node,
LIB_ID_CREATE_NO_USER_REFCOUNT |
LIB_ID_CREATE_NO_MAIN,
node.name,
node.identifier,
socket_map);
node_map.add_new(&node, new_node);
/* Find a new valid ID pointer for all ID usages in given node. */
@@ -387,7 +392,7 @@ static wmOperatorStatus node_clipboard_paste_exec(bContext *C, wmOperator *op)
/* Do not access referenced ID pointers here, as they are still the old ones, which may be
* invalid. */
bNode *new_node = bke::node_copy_with_mapping(
&tree, node, LIB_ID_CREATE_NO_USER_REFCOUNT, true, socket_map);
&tree, node, LIB_ID_CREATE_NO_USER_REFCOUNT, std::nullopt, std::nullopt, socket_map);
/* Update the newly copied node's ID references. */
clipboard.paste_update_node_id_references(*new_node);
/* Reset socket shape in case a node is copied to a different tree type. */

View File

@@ -1425,7 +1425,7 @@ static wmOperatorStatus node_duplicate_exec(bContext *C, wmOperator *op)
for (bNode *node : get_selected_nodes(*ntree)) {
bNode *new_node = bke::node_copy_with_mapping(
ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
ntree, *node, LIB_ID_COPY_DEFAULT, std::nullopt, std::nullopt, socket_map);
node_map.add_new(node, new_node);
if (node->id && dupli_node_tree) {

View File

@@ -531,7 +531,8 @@ static bool node_group_separate_selected(
for (bNode *node : nodes_to_move) {
bNode *newnode;
if (make_copy) {
newnode = bke::node_copy_with_mapping(&ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
newnode = bke::node_copy_with_mapping(
&ntree, *node, LIB_ID_COPY_DEFAULT, std::nullopt, std::nullopt, socket_map);
node_identifier_map.add(node->identifier, newnode->identifier);
}
else {