Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_node/node_relationships.cc
| Show First 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "NOD_node_declaration.hh" | #include "NOD_node_declaration.hh" | ||||
| #include "NOD_node_tree_ref.hh" | #include "NOD_node_tree_ref.hh" | ||||
| #include "node_intern.hh" /* own include */ | #include "node_intern.hh" /* own include */ | ||||
| using namespace blender::nodes::node_tree_ref_types; | using namespace blender::nodes::node_tree_ref_types; | ||||
| using blender::Vector; | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Relations Helpers | /** \name Relations Helpers | ||||
| * \{ */ | * \{ */ | ||||
| static bool ntree_has_drivers(bNodeTree *ntree) | static bool ntree_has_drivers(bNodeTree *ntree) | ||||
| { | { | ||||
| const AnimData *adt = BKE_animdata_from_id(&ntree->id); | const AnimData *adt = BKE_animdata_from_id(&ntree->id); | ||||
| ▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | |||||
| static void clear_picking_highlight(ListBase *links) | static void clear_picking_highlight(ListBase *links) | ||||
| { | { | ||||
| LISTBASE_FOREACH (bNodeLink *, link, links) { | LISTBASE_FOREACH (bNodeLink *, link, links) { | ||||
| link->flag &= ~NODE_LINK_TEMP_HIGHLIGHT; | link->flag &= ~NODE_LINK_TEMP_HIGHLIGHT; | ||||
| } | } | ||||
| } | } | ||||
| static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock) | static bNodeLink *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock) | ||||
| { | { | ||||
| LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); | |||||
| bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); | bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); | ||||
| linkdata->data = oplink; | |||||
| if (sock->in_out == SOCK_OUT) { | if (sock->in_out == SOCK_OUT) { | ||||
| oplink->fromnode = node; | oplink->fromnode = node; | ||||
| oplink->fromsock = sock; | oplink->fromsock = sock; | ||||
| } | } | ||||
| else { | else { | ||||
| oplink->tonode = node; | oplink->tonode = node; | ||||
| oplink->tosock = sock; | oplink->tosock = sock; | ||||
| } | } | ||||
| oplink->flag |= NODE_LINK_VALID; | oplink->flag |= NODE_LINK_VALID; | ||||
| oplink->flag &= ~NODE_LINK_TEST; | oplink->flag &= ~NODE_LINK_TEST; | ||||
| if (node_connected_to_output(bmain, snode->edittree, node)) { | if (node_connected_to_output(bmain, snode->edittree, node)) { | ||||
| oplink->flag |= NODE_LINK_TEST; | oplink->flag |= NODE_LINK_TEST; | ||||
| } | } | ||||
| oplink->flag |= NODE_LINK_DRAGGED; | oplink->flag |= NODE_LINK_DRAGGED; | ||||
| return linkdata; | return oplink; | ||||
| } | } | ||||
| static void pick_link(const bContext *C, | static void pick_link(const bContext *C, | ||||
| wmOperator *op, | wmOperator *op, | ||||
| bNodeLinkDrag *nldrag, | bNodeLinkDrag *nldrag, | ||||
| SpaceNode *snode, | SpaceNode *snode, | ||||
| bNode *node, | bNode *node, | ||||
| bNodeLink *link_to_pick) | bNodeLink *link_to_pick) | ||||
| { | { | ||||
| clear_picking_highlight(&snode->edittree->links); | clear_picking_highlight(&snode->edittree->links); | ||||
| RNA_boolean_set(op->ptr, "has_link_picked", true); | RNA_boolean_set(op->ptr, "has_link_picked", true); | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| LinkData *linkdata = create_drag_link( | bNodeLink *link = create_drag_link(bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock); | ||||
| bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock); | |||||
| BLI_addtail(&nldrag->links, linkdata); | nldrag->links.append(link); | ||||
| nodeRemLink(snode->edittree, link_to_pick); | nodeRemLink(snode->edittree, link_to_pick); | ||||
| BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != nullptr); | BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != nullptr); | ||||
| sort_multi_input_socket_links( | sort_multi_input_socket_links( | ||||
| snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, nullptr); | snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, nullptr); | ||||
| /* Send changed event to original link->tonode. */ | /* Send changed event to original link->tonode. */ | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | if (link_to_pick) { | ||||
| ED_area_tag_redraw(CTX_wm_area(C)); | ED_area_tag_redraw(CTX_wm_area(C)); | ||||
| if (!node_find_indicated_socket(snode, &node, &socket, cursor, SOCK_IN)) { | if (!node_find_indicated_socket(snode, &node, &socket, cursor, SOCK_IN)) { | ||||
| pick_link(C, op, nldrag, snode, node, link_to_pick); | pick_link(C, op, nldrag, snode, node, link_to_pick); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static int sort_nodes_locx(const void *a, const void *b) | |||||
| { | |||||
| const bNodeListItem *nli1 = (const bNodeListItem *)a; | |||||
| const bNodeListItem *nli2 = (const bNodeListItem *)b; | |||||
| const bNode *node1 = nli1->node; | |||||
| const bNode *node2 = nli2->node; | |||||
| if (node1->locx > node2->locx) { | |||||
| return 1; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used) | static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used) | ||||
| { | { | ||||
| if (nodeSocketIsHidden(sock)) { | if (nodeSocketIsHidden(sock)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (!allow_used && (sock->flag & SOCK_IN_USE)) { | if (!allow_used && (sock->flag & SOCK_IN_USE)) { | ||||
| return false; | return false; | ||||
| ▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static void snode_autoconnect(Main *bmain, | static void snode_autoconnect(Main *bmain, | ||||
| SpaceNode *snode, | SpaceNode *snode, | ||||
| const bool allow_multiple, | const bool allow_multiple, | ||||
| const bool replace) | const bool replace) | ||||
| { | { | ||||
| bNodeTree *ntree = snode->edittree; | bNodeTree *ntree = snode->edittree; | ||||
| ListBase *nodelist = (ListBase *)MEM_callocN(sizeof(ListBase), "items_list"); | Vector<bNode *> sorted_nodes; | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->flag & NODE_SELECT) { | if (node->flag & NODE_SELECT) { | ||||
| bNodeListItem *nli = (bNodeListItem *)MEM_mallocN(sizeof(bNodeListItem), | sorted_nodes.append(node); | ||||
| "temporary node list item"); | |||||
| nli->node = node; | |||||
| BLI_addtail(nodelist, nli); | |||||
| } | } | ||||
| } | } | ||||
| /* sort nodes left to right */ | /* Sort nodes left to right. */ | ||||
| BLI_listbase_sort(nodelist, sort_nodes_locx); | std::sort(sorted_nodes.begin(), sorted_nodes.end(), [](const bNode *a, const bNode *b) { | ||||
| return a->locx < b->locx; | |||||
| }); | |||||
| int numlinks = 0; | int numlinks = 0; | ||||
| LISTBASE_FOREACH (bNodeListItem *, nli, nodelist) { | for (const int i : sorted_nodes.as_mutable_span().drop_back(1).index_range()) { | ||||
| bool has_selected_inputs = false; | bool has_selected_inputs = false; | ||||
| if (nli->next == nullptr) { | bNode *node_fr = sorted_nodes[i]; | ||||
| break; | bNode *node_to = sorted_nodes[i + 1]; | ||||
| } | |||||
| bNode *node_fr = nli->node; | |||||
| bNode *node_to = nli->next->node; | |||||
| /* corner case: input/output node aligned the wrong way around (T47729) */ | /* corner case: input/output node aligned the wrong way around (T47729) */ | ||||
| if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) { | if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) { | ||||
| SWAP(bNode *, node_fr, node_to); | SWAP(bNode *, node_fr, node_to); | ||||
| } | } | ||||
| /* if there are selected sockets, connect those */ | /* if there are selected sockets, connect those */ | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock_to, &node_to->inputs) { | LISTBASE_FOREACH (bNodeSocket *, sock_to, &node_to->inputs) { | ||||
| if (sock_to->flag & SELECT) { | if (sock_to->flag & SELECT) { | ||||
| Show All 39 Lines | if (!has_selected_inputs) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (numlinks > 0) { | if (numlinks > 0) { | ||||
| ntreeUpdateTree(bmain, ntree); | ntreeUpdateTree(bmain, ntree); | ||||
| } | } | ||||
| BLI_freelistN(nodelist); | |||||
| MEM_freeN(nodelist); | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Link Viewer Operator | /** \name Link Viewer Operator | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 388 Lines • ▼ Show 20 Lines | static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) | ||||
| bNodeTree *ntree = snode->edittree; | bNodeTree *ntree = snode->edittree; | ||||
| bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; | bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; | ||||
| bool do_tag_update = false; | bool do_tag_update = false; | ||||
| /* View will be reset if no links connect. */ | /* View will be reset if no links connect. */ | ||||
| bool reset_view = true; | bool reset_view = true; | ||||
| /* avoid updates while applying links */ | /* avoid updates while applying links */ | ||||
| ntree->is_updating = true; | ntree->is_updating = true; | ||||
| LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { | for (bNodeLink *link : nldrag->links) { | ||||
| bNodeLink *link = (bNodeLink *)linkdata->data; | |||||
| /* See note below, but basically TEST flag means that the link | /* See note below, but basically TEST flag means that the link | ||||
| * was connected to output (or to a node which affects the | * was connected to output (or to a node which affects the | ||||
| * output). | * output). | ||||
| */ | */ | ||||
| do_tag_update |= (link->flag & NODE_LINK_TEST) != 0; | do_tag_update |= (link->flag & NODE_LINK_TEST) != 0; | ||||
| link->flag &= ~NODE_LINK_DRAGGED; | link->flag &= ~NODE_LINK_DRAGGED; | ||||
| Show All 36 Lines | static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) | ||||
| if (do_tag_update) { | if (do_tag_update) { | ||||
| snode_dag_update(C, snode); | snode_dag_update(C, snode); | ||||
| } | } | ||||
| if (reset_view) { | if (reset_view) { | ||||
| UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); | UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); | ||||
| } | } | ||||
| BLI_remlink(&snode->runtime->linkdrag, nldrag); | snode->runtime->linkdrag.reset(); | ||||
| /* links->data pointers are either held by the tree or freed already */ | |||||
| BLI_freelistN(&nldrag->links); | |||||
| MEM_freeN(nldrag); | |||||
| } | } | ||||
| static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) | static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) | ||||
| { | { | ||||
| SpaceNode *snode = CTX_wm_space_node(C); | SpaceNode *snode = CTX_wm_space_node(C); | ||||
| bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; | bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; | ||||
| if (nldrag->in_out == SOCK_OUT) { | if (nldrag->in_out == SOCK_OUT) { | ||||
| bNode *tnode; | bNode *tnode; | ||||
| bNodeSocket *tsock = nullptr; | bNodeSocket *tsock = nullptr; | ||||
| if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { | if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { | ||||
| LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { | for (bNodeLink *link : nldrag->links) { | ||||
| bNodeLink *link = (bNodeLink *)linkdata->data; | |||||
| /* skip if socket is on the same node as the fromsock */ | /* skip if socket is on the same node as the fromsock */ | ||||
| if (tnode && link->fromnode == tnode) { | if (tnode && link->fromnode == tnode) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Skip if tsock is already linked with this output. */ | /* Skip if tsock is already linked with this output. */ | ||||
| bNodeLink *existing_link_connected_to_fromsock = nullptr; | bNodeLink *existing_link_connected_to_fromsock = nullptr; | ||||
| LISTBASE_FOREACH (bNodeLink *, existing_link, &snode->edittree->links) { | LISTBASE_FOREACH (bNodeLink *, existing_link, &snode->edittree->links) { | ||||
| Show All 13 Lines | if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) { | if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) { | ||||
| sort_multi_input_socket_links(snode, tnode, link, cursor); | sort_multi_input_socket_links(snode, tnode, link, cursor); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { | for (bNodeLink *link : nldrag->links) { | ||||
| bNodeLink *link = (bNodeLink *)linkdata->data; | |||||
| if (nldrag->last_node_hovered_while_dragging_a_link) { | if (nldrag->last_node_hovered_while_dragging_a_link) { | ||||
| sort_multi_input_socket_links( | sort_multi_input_socket_links( | ||||
| snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, cursor); | snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, cursor); | ||||
| } | } | ||||
| link->tonode = nullptr; | link->tonode = nullptr; | ||||
| link->tosock = nullptr; | link->tosock = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| bNode *tnode; | bNode *tnode; | ||||
| bNodeSocket *tsock = nullptr; | bNodeSocket *tsock = nullptr; | ||||
| if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) { | if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) { | ||||
| LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { | for (bNodeLink *link : nldrag->links) { | ||||
| bNodeLink *link = (bNodeLink *)linkdata->data; | |||||
| /* skip if this is already the target socket */ | /* skip if this is already the target socket */ | ||||
| if (link->fromsock == tsock) { | if (link->fromsock == tsock) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* skip if socket is on the same node as the fromsock */ | /* skip if socket is on the same node as the fromsock */ | ||||
| if (tnode && link->tonode == tnode) { | if (tnode && link->tonode == tnode) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* attach links to the socket */ | /* attach links to the socket */ | ||||
| link->fromnode = tnode; | link->fromnode = tnode; | ||||
| link->fromsock = tsock; | link->fromsock = tsock; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { | for (bNodeLink *link : nldrag->links) { | ||||
| bNodeLink *link = (bNodeLink *)linkdata->data; | |||||
| link->fromnode = nullptr; | link->fromnode = nullptr; | ||||
| link->fromsock = nullptr; | link->fromsock = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Loop that adds a node-link, called by function below. */ | /* Loop that adds a node-link, called by function below. */ | ||||
| Show All 35 Lines | case MIDDLEMOUSE: { | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| /* return 1 when socket clicked */ | static std::unique_ptr<bNodeLinkDrag> node_link_init(Main *bmain, | ||||
| static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor[2], bool detach) | SpaceNode *snode, | ||||
| float cursor[2], | |||||
| bool detach) | |||||
| { | { | ||||
| bNodeLinkDrag *nldrag = nullptr; | |||||
| /* output indicated? */ | /* output indicated? */ | ||||
| bNode *node; | bNode *node; | ||||
| bNodeSocket *sock; | bNodeSocket *sock; | ||||
| if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { | if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { | ||||
| nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); | std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); | ||||
| const int num_links = nodeCountSocketLinks(snode->edittree, sock); | const int num_links = nodeCountSocketLinks(snode->edittree, sock); | ||||
| int link_limit = nodeSocketLinkLimit(sock); | int link_limit = nodeSocketLinkLimit(sock); | ||||
| if (num_links > 0 && (num_links >= link_limit || detach)) { | if (num_links > 0 && (num_links >= link_limit || detach)) { | ||||
| /* dragged links are fixed on input side */ | /* dragged links are fixed on input side */ | ||||
| nldrag->in_out = SOCK_IN; | nldrag->in_out = SOCK_IN; | ||||
| /* detach current links and store them in the operator data */ | /* detach current links and store them in the operator data */ | ||||
| LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) { | LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) { | ||||
| if (link->fromsock == sock) { | if (link->fromsock == sock) { | ||||
| LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); | |||||
| bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); | bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); | ||||
| linkdata->data = oplink; | |||||
| *oplink = *link; | *oplink = *link; | ||||
| oplink->next = oplink->prev = nullptr; | oplink->next = oplink->prev = nullptr; | ||||
| oplink->flag |= NODE_LINK_VALID; | oplink->flag |= NODE_LINK_VALID; | ||||
| oplink->flag |= NODE_LINK_DRAGGED; | oplink->flag |= NODE_LINK_DRAGGED; | ||||
| /* The link could be disconnected and in that case we | /* The link could be disconnected and in that case we | ||||
| * wouldn't be able to check whether tag update is | * wouldn't be able to check whether tag update is | ||||
| * needed or not when releasing mouse button. So we | * needed or not when releasing mouse button. So we | ||||
| * cache whether the link affects output or not here | * cache whether the link affects output or not here | ||||
| * using TEST flag. | * using TEST flag. | ||||
| */ | */ | ||||
| oplink->flag &= ~NODE_LINK_TEST; | oplink->flag &= ~NODE_LINK_TEST; | ||||
| if (node_connected_to_output(bmain, snode->edittree, link->tonode)) { | if (node_connected_to_output(bmain, snode->edittree, link->tonode)) { | ||||
| oplink->flag |= NODE_LINK_TEST; | oplink->flag |= NODE_LINK_TEST; | ||||
| } | } | ||||
| BLI_addtail(&nldrag->links, linkdata); | nldrag->links.append(oplink); | ||||
| nodeRemLink(snode->edittree, link); | nodeRemLink(snode->edittree, link); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* dragged links are fixed on output side */ | /* dragged links are fixed on output side */ | ||||
| nldrag->in_out = SOCK_OUT; | nldrag->in_out = SOCK_OUT; | ||||
| /* create a new link */ | /* create a new link */ | ||||
| LinkData *linkdata = create_drag_link(bmain, snode, node, sock); | nldrag->links.append(create_drag_link(bmain, snode, node, sock)); | ||||
| BLI_addtail(&nldrag->links, linkdata); | |||||
| } | } | ||||
| return nldrag; | |||||
| } | } | ||||
| /* or an input? */ | /* or an input? */ | ||||
| else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { | if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { | ||||
| nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); | std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); | ||||
| nldrag->last_node_hovered_while_dragging_a_link = node; | nldrag->last_node_hovered_while_dragging_a_link = node; | ||||
| const int num_links = nodeCountSocketLinks(snode->edittree, sock); | const int num_links = nodeCountSocketLinks(snode->edittree, sock); | ||||
| if (num_links > 0) { | if (num_links > 0) { | ||||
| /* dragged links are fixed on output side */ | /* dragged links are fixed on output side */ | ||||
| nldrag->in_out = SOCK_OUT; | nldrag->in_out = SOCK_OUT; | ||||
| /* detach current links and store them in the operator data */ | /* detach current links and store them in the operator data */ | ||||
| bNodeLink *link_to_pick; | bNodeLink *link_to_pick; | ||||
| LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) { | LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) { | ||||
| if (link->tosock == sock) { | if (link->tosock == sock) { | ||||
| if (sock->flag & SOCK_MULTI_INPUT) { | if (sock->flag & SOCK_MULTI_INPUT) { | ||||
| nldrag->from_multi_input_socket = true; | nldrag->from_multi_input_socket = true; | ||||
| } | } | ||||
| link_to_pick = link; | link_to_pick = link; | ||||
| } | } | ||||
| } | } | ||||
| if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) { | if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) { | ||||
| LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); | |||||
| bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); | bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); | ||||
| linkdata->data = oplink; | |||||
| *oplink = *link_to_pick; | *oplink = *link_to_pick; | ||||
| oplink->next = oplink->prev = nullptr; | oplink->next = oplink->prev = nullptr; | ||||
| oplink->flag |= NODE_LINK_VALID; | oplink->flag |= NODE_LINK_VALID; | ||||
| oplink->flag |= NODE_LINK_DRAGGED; | oplink->flag |= NODE_LINK_DRAGGED; | ||||
| oplink->flag &= ~NODE_LINK_TEST; | oplink->flag &= ~NODE_LINK_TEST; | ||||
| if (node_connected_to_output(bmain, snode->edittree, link_to_pick->tonode)) { | if (node_connected_to_output(bmain, snode->edittree, link_to_pick->tonode)) { | ||||
| oplink->flag |= NODE_LINK_TEST; | oplink->flag |= NODE_LINK_TEST; | ||||
| } | } | ||||
| BLI_addtail(&nldrag->links, linkdata); | nldrag->links.append(oplink); | ||||
| nodeRemLink(snode->edittree, link_to_pick); | nodeRemLink(snode->edittree, link_to_pick); | ||||
| /* send changed event to original link->tonode */ | /* send changed event to original link->tonode */ | ||||
| if (node) { | if (node) { | ||||
| snode_update(snode, node); | snode_update(snode, node); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* dragged links are fixed on input side */ | /* dragged links are fixed on input side */ | ||||
| nldrag->in_out = SOCK_IN; | nldrag->in_out = SOCK_IN; | ||||
| /* create a new link */ | /* create a new link */ | ||||
| LinkData *linkdata = create_drag_link(bmain, snode, node, sock); | nldrag->links.append(create_drag_link(bmain, snode, node, sock)); | ||||
| BLI_addtail(&nldrag->links, linkdata); | |||||
| } | } | ||||
| return nldrag; | |||||
| } | } | ||||
| return nldrag; | return {}; | ||||
| } | } | ||||
| static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| SpaceNode *snode = CTX_wm_space_node(C); | SpaceNode *snode = CTX_wm_space_node(C); | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| bool detach = RNA_boolean_get(op->ptr, "detach"); | bool detach = RNA_boolean_get(op->ptr, "detach"); | ||||
| float cursor[2]; | float cursor[2]; | ||||
| UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]); | UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]); | ||||
| RNA_float_set_array(op->ptr, "drag_start", cursor); | RNA_float_set_array(op->ptr, "drag_start", cursor); | ||||
| RNA_boolean_set(op->ptr, "has_link_picked", false); | RNA_boolean_set(op->ptr, "has_link_picked", false); | ||||
| ED_preview_kill_jobs(CTX_wm_manager(C), bmain); | ED_preview_kill_jobs(CTX_wm_manager(C), bmain); | ||||
| bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach); | std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach); | ||||
| if (nldrag) { | if (nldrag) { | ||||
| UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op); | UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op); | ||||
| op->customdata = nldrag; | snode->runtime->linkdrag = std::move(nldrag); | ||||
| BLI_addtail(&snode->runtime->linkdrag, nldrag); | op->customdata = snode->runtime->linkdrag.get(); | ||||
| /* add modal handler */ | /* add modal handler */ | ||||
| WM_event_add_modal_handler(C, op); | WM_event_add_modal_handler(C, op); | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; | return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; | ||||
| } | } | ||||
| static void node_link_cancel(bContext *C, wmOperator *op) | static void node_link_cancel(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| SpaceNode *snode = CTX_wm_space_node(C); | SpaceNode *snode = CTX_wm_space_node(C); | ||||
| bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; | bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; | ||||
| BLI_remlink(&snode->runtime->linkdrag, nldrag); | |||||
| UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); | UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); | ||||
| BLI_freelistN(&nldrag->links); | snode->runtime->linkdrag.reset(); | ||||
| MEM_freeN(nldrag); | |||||
| clear_picking_highlight(&snode->edittree->links); | clear_picking_highlight(&snode->edittree->links); | ||||
| } | } | ||||
| void NODE_OT_link(wmOperatorType *ot) | void NODE_OT_link(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Link Nodes"; | ot->name = "Link Nodes"; | ||||
| ot->idname = "NODE_OT_link"; | ot->idname = "NODE_OT_link"; | ||||
| ▲ Show 20 Lines • Show All 1,266 Lines • Show Last 20 Lines | |||||