Changeset View
Standalone View
source/blender/editors/space_node/node_group.cc
| Show First 20 Lines • Show All 927 Lines • ▼ Show 20 Lines | for (bNode *node : nodes_to_move) { | ||||
| nodeUniqueID(&group, node); | nodeUniqueID(&group, node); | ||||
| nodeUniqueName(&group, node); | nodeUniqueName(&group, node); | ||||
| BKE_ntree_update_tag_node_removed(&ntree); | BKE_ntree_update_tag_node_removed(&ntree); | ||||
| BKE_ntree_update_tag_node_new(&group, node); | BKE_ntree_update_tag_node_new(&group, node); | ||||
| } | } | ||||
| nodeRebuildIDVector(&ntree); | nodeRebuildIDVector(&ntree); | ||||
| node_group_update(&ntree, gnode); | /* Update input and output node first, since the group node declaration can depend on them. */ | ||||
| node_group_input_update(&group, input_node); | nodes::update_node_declaration_and_sockets(group, *input_node); | ||||
| node_group_output_update(&group, output_node); | nodes::update_node_declaration_and_sockets(group, *output_node); | ||||
| /* move nodes in the group to the center */ | /* move nodes in the group to the center */ | ||||
| for (bNode *node : nodes_to_move) { | for (bNode *node : nodes_to_move) { | ||||
| if (!node->parent) { | if (!node->parent) { | ||||
| node->locx -= center[0]; | node->locx -= center[0]; | ||||
| node->locy -= center[1]; | node->locy -= center[1]; | ||||
| } | } | ||||
| } | } | ||||
| for (bNodeLink *link : internal_links_to_move) { | for (bNodeLink *link : internal_links_to_move) { | ||||
| BLI_remlink(&ntree.links, link); | BLI_remlink(&ntree.links, link); | ||||
| BLI_addtail(&group.links, link); | BLI_addtail(&group.links, link); | ||||
| BKE_ntree_update_tag_link_removed(&ntree); | BKE_ntree_update_tag_link_removed(&ntree); | ||||
| BKE_ntree_update_tag_link_added(&group, link); | BKE_ntree_update_tag_link_added(&group, link); | ||||
| } | } | ||||
| for (bNodeLink *link : links_to_remove) { | for (bNodeLink *link : links_to_remove) { | ||||
| nodeRemLink(&ntree, link); | nodeRemLink(&ntree, link); | ||||
| } | } | ||||
| /* Handle links to the new group inputs. */ | |||||
| for (const auto item : input_links.items()) { | for (const auto item : input_links.items()) { | ||||
| const char *interface_identifier = item.value.interface_socket->identifier; | const char *interface_identifier = item.value.interface_socket->identifier; | ||||
| bNodeSocket *input_socket = node_group_input_find_socket(input_node, interface_identifier); | bNodeSocket *input_socket = node_group_input_find_socket(input_node, interface_identifier); | ||||
| for (bNodeLink *link : item.value.links) { | for (bNodeLink *link : item.value.links) { | ||||
| /* Move the link into the new group, connected from the input node to the original socket. */ | /* Move the link into the new group, connected from the input node to the original socket. */ | ||||
| BLI_remlink(&ntree.links, link); | BLI_remlink(&ntree.links, link); | ||||
| BLI_addtail(&group.links, link); | BLI_addtail(&group.links, link); | ||||
| BKE_ntree_update_tag_link_removed(&ntree); | BKE_ntree_update_tag_link_removed(&ntree); | ||||
| BKE_ntree_update_tag_link_added(&group, link); | BKE_ntree_update_tag_link_added(&group, link); | ||||
| link->fromnode = input_node; | link->fromnode = input_node; | ||||
| link->fromsock = input_socket; | link->fromsock = input_socket; | ||||
| } | } | ||||
| /* Add a new link outside of the group. */ | |||||
| bNodeSocket *group_node_socket = node_group_find_input_socket(gnode, interface_identifier); | |||||
| nodeAddLink(&ntree, item.value.from_node, item.key, gnode, group_node_socket); | |||||
| } | } | ||||
| /* Handle links to new group outputs. */ | |||||
| for (const OutputLinkInfo &info : output_links) { | for (const OutputLinkInfo &info : output_links) { | ||||
| /* Create a new link inside of the group. */ | /* Create a new link inside of the group. */ | ||||
| const char *io_identifier = info.interface_socket->identifier; | const char *io_identifier = info.interface_socket->identifier; | ||||
| bNodeSocket *output_sock = node_group_output_find_socket(output_node, io_identifier); | bNodeSocket *output_sock = node_group_output_find_socket(output_node, io_identifier); | ||||
| nodeAddLink(&group, info.link->fromnode, info.link->fromsock, output_node, output_sock); | nodeAddLink(&group, info.link->fromnode, info.link->fromsock, output_node, output_sock); | ||||
| /* Reconnect the link to the group node instead of the node now inside the group. */ | |||||
| info.link->fromnode = gnode; | |||||
| info.link->fromsock = node_group_find_output_socket(gnode, io_identifier); | |||||
| } | } | ||||
| /* Handle new links inside the group. */ | |||||
| for (const NewInternalLinkInfo &info : new_internal_links) { | for (const NewInternalLinkInfo &info : new_internal_links) { | ||||
| const char *io_identifier = info.interface_socket->identifier; | const char *io_identifier = info.interface_socket->identifier; | ||||
| if (info.socket->in_out == SOCK_IN) { | if (info.socket->in_out == SOCK_IN) { | ||||
| bNodeSocket *input_socket = node_group_input_find_socket(input_node, io_identifier); | bNodeSocket *input_socket = node_group_input_find_socket(input_node, io_identifier); | ||||
| nodeAddLink(&group, input_node, input_socket, info.node, info.socket); | nodeAddLink(&group, input_node, input_socket, info.node, info.socket); | ||||
| } | } | ||||
| else { | else { | ||||
| bNodeSocket *output_socket = node_group_output_find_socket(output_node, io_identifier); | bNodeSocket *output_socket = node_group_output_find_socket(output_node, io_identifier); | ||||
| nodeAddLink(&group, info.node, info.socket, output_node, output_socket); | nodeAddLink(&group, info.node, info.socket, output_node, output_socket); | ||||
| } | } | ||||
| } | } | ||||
| bke::node_field_inferencing::update_field_inferencing(group); | |||||
JacquesLucke: Probably ok for now, but does feel a little bit fishy. It might happen that the field… | |||||
Done Inline ActionsThere's a dependency cycle that's difficult to handle here. Originally I had the same thought and called ED_node_tree_propagate_change here, giving it the group as the root tree since I only wanted to update that one. However, doing that caused the parent group ntree to update too, which can't be done yet because the group node doesn't have it's declaration, because the field inferencing isn't updated. So that's how I ended up with this. If I could call the node tree update utility without propagating the update to other trees that would do the trick. But I'm not sure that's possible? I'm curious if you have a thought about this. HooglyBoogly: There's a dependency cycle that's difficult to handle here. Originally I had the same thought… | |||||
| nodes::update_node_declaration_and_sockets(ntree, *gnode); | |||||
| /* Add new links to inputs outside of the group. */ | |||||
| for (const auto item : input_links.items()) { | |||||
| const char *interface_identifier = item.value.interface_socket->identifier; | |||||
| bNodeSocket *group_node_socket = node_group_find_input_socket(gnode, interface_identifier); | |||||
| nodeAddLink(&ntree, item.value.from_node, item.key, gnode, group_node_socket); | |||||
| } | |||||
| /* Add new links to outputs outside the group. */ | |||||
| for (const OutputLinkInfo &info : output_links) { | |||||
| /* Reconnect the link to the group node instead of the node now inside the group. */ | |||||
| info.link->fromnode = gnode; | |||||
| info.link->fromsock = node_group_find_output_socket(gnode, info.interface_socket->identifier); | |||||
| } | |||||
| ED_node_tree_propagate_change(&C, bmain, nullptr); | |||||
Not Done Inline ActionsCan also pass in null as the "root" tree. Might be better here since we are changing more than one. Passing in a root tree can really only help when only a single tree changed. JacquesLucke: Can also pass in null as the "root" tree. Might be better here since we are changing more than… | |||||
| } | } | ||||
| static bNode *node_group_make_from_nodes(const bContext &C, | static bNode *node_group_make_from_nodes(const bContext &C, | ||||
| bNodeTree &ntree, | bNodeTree &ntree, | ||||
| const VectorSet<bNode *> &nodes_to_group, | const VectorSet<bNode *> &nodes_to_group, | ||||
| const char *ntype, | const char *ntype, | ||||
| const char *ntreetype) | const char *ntreetype) | ||||
| { | { | ||||
| Show All 38 Lines | if (gnode) { | ||||
| bNodeTree *ngroup = (bNodeTree *)gnode->id; | bNodeTree *ngroup = (bNodeTree *)gnode->id; | ||||
| nodeSetActive(&ntree, gnode); | nodeSetActive(&ntree, gnode); | ||||
| if (ngroup) { | if (ngroup) { | ||||
| ED_node_tree_push(&snode, ngroup, gnode); | ED_node_tree_push(&snode, ngroup, gnode); | ||||
| } | } | ||||
| } | } | ||||
| ED_node_tree_propagate_change(C, bmain, nullptr); | |||||
| WM_event_add_notifier(C, NC_NODE | NA_ADDED, nullptr); | WM_event_add_notifier(C, NC_NODE | NA_ADDED, nullptr); | ||||
| /* We broke relations in node tree, need to rebuild them in the graphs. */ | /* We broke relations in node tree, need to rebuild them in the graphs. */ | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| Show All 36 Lines | static bool node_tree_contains_tree_recursive(const bNodeTree &ntree_to_search_in, | ||||
| return false; | return false; | ||||
| } | } | ||||
| static int node_group_insert_exec(bContext *C, wmOperator *op) | static int node_group_insert_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| SpaceNode *snode = CTX_wm_space_node(C); | SpaceNode *snode = CTX_wm_space_node(C); | ||||
| bNodeTree *ntree = snode->edittree; | bNodeTree *ntree = snode->edittree; | ||||
| const char *node_idname = node_group_idname(C); | const char *node_idname = node_group_idname(C); | ||||
| Main *bmain = CTX_data_main(C); | |||||
| ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); | ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); | ||||
| bNode *gnode = node_group_get_active(C, node_idname); | bNode *gnode = node_group_get_active(C, node_idname); | ||||
| if (!gnode || !gnode->id) { | if (!gnode || !gnode->id) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| Show All 15 Lines | static int node_group_insert_exec(bContext *C, wmOperator *op) | ||||
| if (!node_group_make_test_selected(*ntree, nodes_to_group, ngroup->idname, *op->reports)) { | if (!node_group_make_test_selected(*ntree, nodes_to_group, ngroup->idname, *op->reports)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| node_group_make_insert_selected(*C, *ntree, gnode, nodes_to_group); | node_group_make_insert_selected(*C, *ntree, gnode, nodes_to_group); | ||||
| nodeSetActive(ntree, gnode); | nodeSetActive(ntree, gnode); | ||||
| ED_node_tree_push(snode, ngroup, gnode); | ED_node_tree_push(snode, ngroup, gnode); | ||||
| ED_node_tree_propagate_change(C, bmain, nullptr); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void NODE_OT_group_insert(wmOperatorType *ot) | void NODE_OT_group_insert(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Group Insert"; | ot->name = "Group Insert"; | ||||
| Show All 14 Lines | |||||
Probably ok for now, but does feel a little bit fishy. It might happen that the field inferencing depends on nodes being updated or whatever else happens during node tree update before inferencing.
I think the more correct long term fix would be to use ED_node_tree_propagate_change, but to make sure that there are no left-over links that point to nodes that are in different node trees when the update happens.