Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_node/node_relationships.c
| Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "node_intern.h" /* own include */ | #include "node_intern.h" /* own include */ | ||||
| /* ****************** Relations helpers *********************** */ | /* ****************** Relations helpers *********************** */ | ||||
| static bool ntree_has_drivers(bNodeTree *ntree) | static bool ntree_has_drivers(bNodeTree *ntree) | ||||
| { | { | ||||
| AnimData *adt = BKE_animdata_from_id(&ntree->id); | const AnimData *adt = BKE_animdata_from_id(&ntree->id); | ||||
| if (adt == NULL) { | if (adt == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return !BLI_listbase_is_empty(&adt->drivers); | return !BLI_listbase_is_empty(&adt->drivers); | ||||
| } | } | ||||
| static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode *to) | static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode *to) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 588 Lines • ▼ Show 20 Lines | static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) | ||||
| do_tag_update |= ED_node_is_geometry(snode); | do_tag_update |= ED_node_is_geometry(snode); | ||||
| ntreeUpdateTree(bmain, ntree); | ntreeUpdateTree(bmain, ntree); | ||||
| snode_notify(C, snode); | snode_notify(C, snode); | ||||
| if (do_tag_update) { | if (do_tag_update) { | ||||
| snode_dag_update(C, snode); | snode_dag_update(C, snode); | ||||
| } | } | ||||
| BLI_remlink(&snode->linkdrag, nldrag); | BLI_remlink(&snode->runtime->linkdrag, nldrag); | ||||
| /* links->data pointers are either held by the tree or freed already */ | /* links->data pointers are either held by the tree or freed already */ | ||||
| BLI_freelistN(&nldrag->links); | BLI_freelistN(&nldrag->links); | ||||
| MEM_freeN(nldrag); | 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); | ||||
| ▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | else { | ||||
| BLI_addtail(&nldrag->links, linkdata); | BLI_addtail(&nldrag->links, linkdata); | ||||
| } | } | ||||
| } | } | ||||
| /* or an input? */ | /* or an input? */ | ||||
| else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { | else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { | ||||
| nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); | nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); | ||||
| const int num_links = nodeCountSocketLinks(snode->edittree, sock); | const int num_links = nodeCountSocketLinks(snode->edittree, sock); | ||||
| int link_limit = nodeSocketLinkLimit(sock); | if (num_links > 0) { | ||||
| if (num_links > 0 && (num_links >= link_limit || detach)) { | |||||
| /* 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; | |||||
| 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) { | |||||
| nldrag->from_multi_input_socket = true; | |||||
| } | |||||
| link_to_pick = link; | |||||
| } | |||||
| } | |||||
| if (link_to_pick != NULL && !nldrag->from_multi_input_socket) { | |||||
| LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data"); | LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data"); | ||||
| bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); | bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); | ||||
| linkdata->data = oplink; | linkdata->data = oplink; | ||||
| *oplink = *link; | *oplink = *link_to_pick; | ||||
| oplink->next = oplink->prev = NULL; | oplink->next = oplink->prev = NULL; | ||||
| 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, link->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); | BLI_addtail(&nldrag->links, linkdata); | ||||
| nodeRemLink(snode->edittree, link); | 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 = MEM_callocN(sizeof(LinkData), "drag link op link data"); | LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data"); | ||||
| bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); | bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); | ||||
| linkdata->data = oplink; | linkdata->data = oplink; | ||||
| oplink->tonode = node; | oplink->tonode = node; | ||||
| Show All 16 Lines | 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_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); | bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach); | ||||
| if (nldrag) { | if (nldrag) { | ||||
| op->customdata = nldrag; | op->customdata = nldrag; | ||||
| BLI_addtail(&snode->linkdrag, nldrag); | BLI_addtail(&snode->runtime->linkdrag, nldrag); | ||||
| /* 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 = op->customdata; | bNodeLinkDrag *nldrag = op->customdata; | ||||
| BLI_remlink(&snode->linkdrag, nldrag); | BLI_remlink(&snode->runtime->linkdrag, nldrag); | ||||
| BLI_freelistN(&nldrag->links); | BLI_freelistN(&nldrag->links); | ||||
| MEM_freeN(nldrag); | MEM_freeN(nldrag); | ||||
| } | } | ||||
| 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"; | ||||
| ot->description = "Use the mouse to create a link between two nodes"; | ot->description = "Use the mouse to create a link between two nodes"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->invoke = node_link_invoke; | ot->invoke = node_link_invoke; | ||||
| ot->modal = node_link_modal; | ot->modal = node_link_modal; | ||||
| // ot->exec = node_link_exec; | // ot->exec = node_link_exec; | ||||
| ot->poll = ED_operator_node_editable; | ot->poll = ED_operator_node_editable; | ||||
| ot->cancel = node_link_cancel; | ot->cancel = node_link_cancel; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; | ||||
| PropertyRNA *prop; | |||||
| RNA_def_boolean(ot->srna, "detach", false, "Detach", "Detach and redirect existing links"); | RNA_def_boolean(ot->srna, "detach", false, "Detach", "Detach and redirect existing links"); | ||||
| prop = RNA_def_boolean( | |||||
| ot->srna, | |||||
| "has_link_picked", | |||||
| false, | |||||
| "Has Link Picked", | |||||
| "The operation has placed a link. Only used for multi-input sockets, where the " | |||||
| "link is picked later"); | |||||
| RNA_def_property_flag(prop, PROP_HIDDEN); | |||||
| RNA_def_float_array(ot->srna, | |||||
| "drag_start", | |||||
| 2, | |||||
| 0, | |||||
| -UI_PRECISION_FLOAT_MAX, | |||||
| UI_PRECISION_FLOAT_MAX, | |||||
| "Drag Start", | |||||
| "The position of the mouse cursor at the start of the operation", | |||||
| -UI_PRECISION_FLOAT_MAX, | |||||
| UI_PRECISION_FLOAT_MAX); | |||||
| RNA_def_property_flag(prop, PROP_HIDDEN); | |||||
| } | } | ||||
| /* ********************** Make Link operator ***************** */ | /* ********************** Make Link operator ***************** */ | ||||
| /* makes a link between selected output and input sockets */ | /* makes a link between selected output and input sockets */ | ||||
| static int node_make_link_exec(bContext *C, wmOperator *op) | static int node_make_link_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| ▲ Show 20 Lines • Show All 840 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** | /** | ||||
| * Modal handler for insert offset animation | * Modal handler for insert offset animation | ||||
| */ | */ | ||||
| static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) | static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) | ||||
| { | { | ||||
| SpaceNode *snode = CTX_wm_space_node(C); | SpaceNode *snode = CTX_wm_space_node(C); | ||||
| NodeInsertOfsData *iofsd = snode->iofsd; | NodeInsertOfsData *iofsd = snode->runtime->iofsd; | ||||
| bool redraw = false; | bool redraw = false; | ||||
| if (!snode || event->type != TIMER || iofsd == NULL || iofsd->anim_timer != event->customdata) { | if (!snode || event->type != TIMER || iofsd == NULL || iofsd->anim_timer != event->customdata) { | ||||
| return OPERATOR_PASS_THROUGH; | return OPERATOR_PASS_THROUGH; | ||||
| } | } | ||||
| const float duration = (float)iofsd->anim_timer->duration; | const float duration = (float)iofsd->anim_timer->duration; | ||||
| Show All 22 Lines | static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) | ||||
| /* end timer + free insert offset data */ | /* end timer + free insert offset data */ | ||||
| if (duration > NODE_INSOFS_ANIM_DURATION) { | if (duration > NODE_INSOFS_ANIM_DURATION) { | ||||
| WM_event_remove_timer(CTX_wm_manager(C), NULL, iofsd->anim_timer); | WM_event_remove_timer(CTX_wm_manager(C), NULL, iofsd->anim_timer); | ||||
| LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { | LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { | ||||
| node->anim_init_locx = node->anim_ofsx = 0.0f; | node->anim_init_locx = node->anim_ofsx = 0.0f; | ||||
| } | } | ||||
| snode->iofsd = NULL; | snode->runtime->iofsd = NULL; | ||||
| MEM_freeN(iofsd); | MEM_freeN(iofsd); | ||||
| return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); | return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); | ||||
| } | } | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| #undef NODE_INSOFS_ANIM_DURATION | #undef NODE_INSOFS_ANIM_DURATION | ||||
| static int node_insert_offset_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int node_insert_offset_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| const SpaceNode *snode = CTX_wm_space_node(C); | const SpaceNode *snode = CTX_wm_space_node(C); | ||||
| NodeInsertOfsData *iofsd = snode->iofsd; | NodeInsertOfsData *iofsd = snode->runtime->iofsd; | ||||
| if (!iofsd || !iofsd->insert) { | if (!iofsd || !iofsd->insert) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| BLI_assert((snode->flag & SNODE_SKIP_INSOFFSET) == 0); | BLI_assert((snode->flag & SNODE_SKIP_INSOFFSET) == 0); | ||||
| iofsd->ntree = snode->edittree; | iofsd->ntree = snode->edittree; | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | if (best_input && best_output) { | ||||
| /* set up insert offset data, it needs stuff from here */ | /* set up insert offset data, it needs stuff from here */ | ||||
| if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { | if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { | ||||
| NodeInsertOfsData *iofsd = MEM_callocN(sizeof(NodeInsertOfsData), __func__); | NodeInsertOfsData *iofsd = MEM_callocN(sizeof(NodeInsertOfsData), __func__); | ||||
| iofsd->insert = select; | iofsd->insert = select; | ||||
| iofsd->prev = link->fromnode; | iofsd->prev = link->fromnode; | ||||
| iofsd->next = node; | iofsd->next = node; | ||||
| snode->iofsd = iofsd; | snode->runtime->iofsd = iofsd; | ||||
| } | } | ||||
| ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */ | ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */ | ||||
| snode_update(snode, select); | snode_update(snode, select); | ||||
| ED_node_tag_update_id((ID *)snode->edittree); | ED_node_tag_update_id((ID *)snode->edittree); | ||||
| ED_node_tag_update_id(snode->id); | ED_node_tag_update_id(snode->id); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||