diff --git a/source/blender/editors/include/ED_node.hh b/source/blender/editors/include/ED_node.hh index 411d4e25884..686ca24277f 100644 --- a/source/blender/editors/include/ED_node.hh +++ b/source/blender/editors/include/ED_node.hh @@ -27,7 +27,7 @@ namespace blender::ed::space_node { VectorSet get_selected_nodes(bNodeTree &node_tree); -void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion); +void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion, bool attach_enabled); /** * Assumes link with #NODE_LINK_INSERT_TARGET set. diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index fba73bcb604..ddfa6251f7a 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -2323,7 +2323,7 @@ void node_draw_link(const bContext &C, if (link.flag & NODE_LINK_VALID) { /* special indicated link, on drop-node */ - if (link.flag & NODE_LINK_INSERT_TARGET) { + if (link.flag & NODE_LINK_INSERT_TARGET && !(link.flag & NODE_LINK_INSERT_TARGET_INVALID)) { th_col1 = th_col2 = TH_ACTIVE; } else if (link.flag & NODE_LINK_MUTED) { diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 5c83ef18ffe..db64a5aede2 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -1283,6 +1283,9 @@ float node_link_dim_factor(const View2D &v2d, const bNodeLink &link) if (link.fromsock == nullptr || link.tosock == nullptr) { return 1.0f; } + if (link.flag & NODE_LINK_INSERT_TARGET_INVALID) { + return 0.2f; + } const float2 from = link.fromsock->runtime->location; const float2 to = link.tosock->runtime->location; diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index cf1c1679177..e45d2d9636c 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -2108,7 +2108,32 @@ static bNode *get_selected_node_for_insertion(bNodeTree &node_tree) return selected_node; } -void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion) +static bool node_can_be_inserted_on_link(bNodeTree &tree, bNode &node, const bNodeLink &link) +{ + const bNodeSocket *main_input = get_main_socket(tree, node, SOCK_IN); + const bNodeSocket *main_output = get_main_socket(tree, node, SOCK_IN); + if (ELEM(nullptr, main_input, main_output)) { + return false; + } + if (!tree.typeinfo->validate_link) { + return true; + } + if (!tree.typeinfo->validate_link(eNodeSocketDatatype(link.fromsock->type), + eNodeSocketDatatype(main_input->type))) + { + return false; + } + if (!tree.typeinfo->validate_link(eNodeSocketDatatype(main_output->type), + eNodeSocketDatatype(link.tosock->type))) + { + return false; + } + return true; +} + +void node_insert_on_link_flags_set(SpaceNode &snode, + const ARegion ®ion, + const bool attach_enabled) { bNodeTree &node_tree = *snode.edittree; node_tree.ensure_topology_cache(); @@ -2156,13 +2181,16 @@ void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion) if (selink) { selink->flag |= NODE_LINK_INSERT_TARGET; + if (!attach_enabled || !node_can_be_inserted_on_link(node_tree, *node_to_insert, *selink)) { + selink->flag |= NODE_LINK_INSERT_TARGET_INVALID; + } } } void node_insert_on_link_flags_clear(bNodeTree &node_tree) { LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) { - link->flag &= ~NODE_LINK_INSERT_TARGET; + link->flag &= ~(NODE_LINK_INSERT_TARGET | NODE_LINK_INSERT_TARGET_INVALID); } } @@ -2180,16 +2208,17 @@ void node_insert_on_link_flags(Main &bmain, SpaceNode &snode) bNodeLink *old_link = nullptr; LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { if (link->flag & NODE_LINK_INSERT_TARGET) { - old_link = link; + if (!(link->flag & NODE_LINK_INSERT_TARGET_INVALID)) { + old_link = link; + } break; } } + node_insert_on_link_flags_clear(node_tree); if (old_link == nullptr) { return; } - old_link->flag &= ~NODE_LINK_INSERT_TARGET; - bNodeSocket *best_input = get_main_socket(ntree, *node_to_insert, SOCK_IN); bNodeSocket *best_output = get_main_socket(ntree, *node_to_insert, SOCK_OUT); diff --git a/source/blender/editors/transform/transform_convert_node.cc b/source/blender/editors/transform/transform_convert_node.cc index c0cad31607e..6a28990ebe9 100644 --- a/source/blender/editors/transform/transform_convert_node.cc +++ b/source/blender/editors/transform/transform_convert_node.cc @@ -110,12 +110,7 @@ static void createTransNodeData(bContext * /*C*/, TransInfo *t) NODE_EDGE_PAN_ZOOM_INFLUENCE); customdata->viewrect_prev = customdata->edgepan_data.initial_rect; - if (t->modifiers & MOD_NODE_ATTACH) { - space_node::node_insert_on_link_flags_set(*snode, *t->region); - } - else { - space_node::node_insert_on_link_flags_clear(*snode->edittree); - } + space_node::node_insert_on_link_flags_set(*snode, *t->region, t->modifiers & MOD_NODE_ATTACH); t->custom.type.data = customdata; t->custom.type.use_free = true; @@ -243,12 +238,8 @@ static void flushTransNodes(TransInfo *t) /* Handle intersection with noodles. */ if (tc->data_len == 1) { - if (t->modifiers & MOD_NODE_ATTACH) { - space_node::node_insert_on_link_flags_set(*snode, *t->region); - } - else { - space_node::node_insert_on_link_flags_clear(*snode->edittree); - } + space_node::node_insert_on_link_flags_set( + *snode, *t->region, t->modifiers & MOD_NODE_ATTACH); } } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 8fd34f36310..c0090f94370 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -627,6 +627,11 @@ enum { NODE_LINK_TEMP_HIGHLIGHT = 1 << 3, /** Link is muted. */ NODE_LINK_MUTED = 1 << 4, + /** + * The dragged node would be inserted here, but this link is ignored because it's not compatible + * with the node. + */ + NODE_LINK_INSERT_TARGET_INVALID = 1 << 5, }; typedef struct bNestedNodePath {