Nodes: avoid removing link when inserting incompatible node
Previously, when dropping a node on a link with incompatible sockets, the link would be removed. While sometimes useful in super simple setup, it is generally useless for most work. Even worse, users might not notice that they accidentally removed a link (this has been reported in the recent geometry nodes workshop). This patch changes this behavior in two ways: * A node can't be inserted onto an incompatible link anymore. * A link will be dimmed while dragging a node over it, if it is incompatible or if alt is pressed. Pull Request: https://projects.blender.org/blender/blender/pulls/121975
This commit is contained in:
@@ -27,7 +27,7 @@ namespace blender::ed::space_node {
|
||||
|
||||
VectorSet<bNode *> 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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user