Fix #104219: Node links are sometimes created from the wrong socket #104420
|
@ -247,8 +247,24 @@ static bool compare_node_depth(const bNode *a, const bNode *b)
|
|||
return false;
|
||||
}
|
||||
|
||||
void node_sort(bNodeTree &ntree)
|
||||
void node_sort(SpaceNode &snode, bNodeTree &ntree)
|
||||
{
|
||||
/* A second operation can depend on the socket locations after nodes are reordered. Usually that
|
||||
* is fine, but occasionally there is no redraw in between to recalculate the socket positions
|
||||
* with the new node order. For example, node selection picking and the link drag operator can
|
||||
* happen without a redraw in between. For these cases, we have to reorder the socket positions
|
||||
* as well. */
|
||||
const Span<float2> old_socket_locations = snode.runtime->all_socket_locations;
|
||||
const bool copy_socket_locations = snode.edittree == &ntree && !old_socket_locations.is_empty();
|
||||
Map<const bNodeSocket *, int> old_socket_indices;
|
||||
if (copy_socket_locations) {
|
||||
ntree.ensure_topology_cache();
|
||||
old_socket_indices.reserve(ntree.all_sockets().size());
|
||||
for (const bNodeSocket *socket : ntree.all_sockets()) {
|
||||
HooglyBoogly marked this conversation as resolved
|
||||
old_socket_indices.add_new(socket, socket->index_in_tree());
|
||||
}
|
||||
}
|
||||
|
||||
Array<bNode *> sort_nodes = ntree.all_nodes();
|
||||
std::stable_sort(sort_nodes.begin(), sort_nodes.end(), compare_node_depth);
|
||||
|
||||
|
@ -267,6 +283,16 @@ void node_sort(bNodeTree &ntree)
|
|||
ntree.runtime->nodes_by_id.add_new(sort_nodes[i]);
|
||||
sort_nodes[i]->runtime->index_in_tree = i;
|
||||
}
|
||||
|
||||
if (copy_socket_locations) {
|
||||
ntree.ensure_topology_cache();
|
||||
Vector<float2> new_socket_locations(ntree.all_sockets().size());
|
||||
for (const bNodeSocket *socket : ntree.all_sockets()) {
|
||||
const float2 old_location = old_socket_locations[old_socket_indices.lookup(socket)];
|
||||
new_socket_locations[socket->index_in_tree()] = old_location;
|
||||
}
|
||||
snode.runtime->all_socket_locations = std::move(new_socket_locations);
|
||||
}
|
||||
}
|
||||
|
||||
static Array<uiBlock *> node_uiblocks_init(const bContext &C, const Span<bNode *> nodes)
|
||||
|
|
|
@ -173,7 +173,7 @@ void node_socket_add_tooltip(const bNodeTree &ntree, const bNodeSocket &sock, ui
|
|||
* Sort nodes by selection: unselected nodes first, then selected,
|
||||
* then the active node at the very end. Relative order is kept intact.
|
||||
*/
|
||||
void node_sort(bNodeTree &ntree);
|
||||
void node_sort(SpaceNode &snode, bNodeTree &ntree);
|
||||
HooglyBoogly marked this conversation as resolved
Jacques Lucke
commented
This is problematic, because the tree might be visible in multiple node editors, all of which would have to be updated. This is problematic, because the tree might be visible in multiple node editors, all of which would have to be updated.
|
||||
|
||||
void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor);
|
||||
/* DPI scaled coords */
|
||||
|
|
|
@ -1725,7 +1725,7 @@ static int node_parent_set_exec(bContext *C, wmOperator * /*op*/)
|
|||
}
|
||||
}
|
||||
|
||||
node_sort(ntree);
|
||||
node_sort(snode, ntree);
|
||||
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
@ -1812,7 +1812,7 @@ static int node_join_exec(bContext *C, wmOperator * /*op*/)
|
|||
}
|
||||
}
|
||||
|
||||
node_sort(ntree);
|
||||
node_sort(snode, ntree);
|
||||
ED_node_tree_propagate_change(C, &bmain, snode.edittree);
|
||||
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
|
||||
|
||||
|
@ -1903,7 +1903,7 @@ static int node_attach_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *e
|
|||
}
|
||||
}
|
||||
|
||||
node_sort(ntree);
|
||||
node_sort(snode, ntree);
|
||||
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
@ -1978,7 +1978,7 @@ static int node_detach_exec(bContext *C, wmOperator * /*op*/)
|
|||
}
|
||||
}
|
||||
|
||||
node_sort(ntree);
|
||||
node_sort(snode, ntree);
|
||||
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
|
|
@ -439,7 +439,7 @@ static int node_select_grouped_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
if (changed) {
|
||||
node_sort(node_tree);
|
||||
node_sort(snode, node_tree);
|
||||
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
@ -507,7 +507,7 @@ void node_select_single(bContext &C, bNode &node)
|
|||
ED_node_set_active(bmain, &snode, &node_tree, &node, &active_texture_changed);
|
||||
ED_node_set_active_viewer_key(&snode);
|
||||
|
||||
node_sort(node_tree);
|
||||
node_sort(snode, node_tree);
|
||||
if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
|
||||
DEG_id_tag_update(&node_tree.id, ID_RECALC_COPY_ON_WRITE);
|
||||
}
|
||||
|
@ -665,7 +665,7 @@ static bool node_mouse_select(bContext *C,
|
|||
viewer_path::activate_geometry_node(bmain, snode, *node);
|
||||
}
|
||||
ED_node_set_active_viewer_key(&snode);
|
||||
node_sort(node_tree);
|
||||
node_sort(snode, node_tree);
|
||||
if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) ||
|
||||
viewer_node_changed) {
|
||||
DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE);
|
||||
|
@ -794,7 +794,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
}
|
||||
|
||||
node_sort(node_tree);
|
||||
node_sort(snode, node_tree);
|
||||
|
||||
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
|
||||
|
||||
|
@ -1101,7 +1101,7 @@ static int node_select_all_exec(bContext *C, wmOperator *op)
|
|||
break;
|
||||
}
|
||||
|
||||
node_sort(node_tree);
|
||||
node_sort(snode, node_tree);
|
||||
|
||||
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
|
@ -1153,7 +1153,7 @@ static int node_select_linked_to_exec(bContext *C, wmOperator * /*op*/)
|
|||
}
|
||||
}
|
||||
|
||||
node_sort(node_tree);
|
||||
node_sort(snode, node_tree);
|
||||
|
||||
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
|
@ -1203,7 +1203,7 @@ static int node_select_linked_from_exec(bContext *C, wmOperator * /*op*/)
|
|||
}
|
||||
}
|
||||
|
||||
node_sort(node_tree);
|
||||
node_sort(snode, node_tree);
|
||||
|
||||
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
|
|
Loading…
Reference in New Issue
I think this could be implemented more efficiently (e.g. by storing something on
bNodeSocketRuntime
, or by only keeping track of the old node index which might work because the sockets of a node are consecutive inall_sockets()
).It's unlikely that this significantly impacts performance in practice though.