Cleanup: Simplify node editor socket picking
The main change is returning a socket pointer instead of using two return arguments. Also use the topology cache instead of linked lists, references over pointers, and slightly adjust whitespace.
This commit is contained in:
parent
a6355a4542
commit
e091291b5b
Notes:
blender-bot
2023-02-14 06:46:23 +01:00
Referenced by commit2ab72f6db8
, Fix T103964: Assert on mouse hover of empty node editor Referenced by commit20b2d6fc71
, Fix T103624: Last node is skipped for cursor and link picking Referenced by issue #103637, Nodes can no longer be connected in node editors Referenced by issue #103624, Regression: Nodes created by the "Use Nodes" button initially can't accept inputs
|
@ -2610,6 +2610,18 @@ int node_get_resize_cursor(NodeResizeDirection directions)
|
|||
return WM_CURSOR_EDIT;
|
||||
}
|
||||
|
||||
static const bNode *find_node_under_cursor(SpaceNode &snode, const float2 &cursor)
|
||||
{
|
||||
/* Check nodes front to back. */
|
||||
const Span<bNode *> nodes = snode.edittree->all_nodes();
|
||||
for (int i = nodes.index_range().last(); i > 0; i--) {
|
||||
if (BLI_rctf_isect_pt(&nodes[i]->runtime->totr, cursor[0], cursor[1])) {
|
||||
return nodes[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor)
|
||||
{
|
||||
const bNodeTree *ntree = snode.edittree;
|
||||
|
@ -2617,36 +2629,28 @@ void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor)
|
|||
WM_cursor_set(&win, WM_CURSOR_DEFAULT);
|
||||
return;
|
||||
}
|
||||
|
||||
bNode *node;
|
||||
bNodeSocket *sock;
|
||||
int wmcursor = WM_CURSOR_DEFAULT;
|
||||
|
||||
if (node_find_indicated_socket(
|
||||
snode, &node, &sock, cursor, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
|
||||
if (node_find_indicated_socket(snode, cursor, SOCK_IN | SOCK_OUT)) {
|
||||
WM_cursor_set(&win, WM_CURSOR_DEFAULT);
|
||||
return;
|
||||
}
|
||||
const bNode *node = find_node_under_cursor(snode, cursor);
|
||||
if (!node) {
|
||||
WM_cursor_set(&win, WM_CURSOR_DEFAULT);
|
||||
return;
|
||||
}
|
||||
const NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
|
||||
if (node->is_frame() && dir == NODE_RESIZE_NONE) {
|
||||
/* Indicate that frame nodes can be moved/selected on their borders. */
|
||||
const rctf frame_inside = node_frame_rect_inside(*node);
|
||||
if (!BLI_rctf_isect_pt(&frame_inside, cursor[0], cursor[1])) {
|
||||
WM_cursor_set(&win, WM_CURSOR_NSEW_SCROLL);
|
||||
return;
|
||||
}
|
||||
WM_cursor_set(&win, WM_CURSOR_DEFAULT);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check nodes front to back. */
|
||||
for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
|
||||
if (BLI_rctf_isect_pt(&node->runtime->totr, cursor[0], cursor[1])) {
|
||||
break; /* First hit on node stops. */
|
||||
}
|
||||
}
|
||||
if (node) {
|
||||
NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
|
||||
wmcursor = node_get_resize_cursor(dir);
|
||||
/* We want to indicate that Frame nodes can be moved/selected on their borders. */
|
||||
if (node->type == NODE_FRAME && dir == NODE_RESIZE_NONE) {
|
||||
const rctf frame_inside = node_frame_rect_inside(*node);
|
||||
if (!BLI_rctf_isect_pt(&frame_inside, cursor[0], cursor[1])) {
|
||||
wmcursor = WM_CURSOR_NSEW_SCROLL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WM_cursor_set(&win, wmcursor);
|
||||
WM_cursor_set(&win, node_get_resize_cursor(dir));
|
||||
}
|
||||
|
||||
static void count_multi_input_socket_links(bNodeTree &ntree, SpaceNode &snode)
|
||||
|
|
|
@ -1205,24 +1205,21 @@ static bool cursor_isect_multi_input_socket(const float2 &cursor, const bNodeSoc
|
|||
return false;
|
||||
}
|
||||
|
||||
bool node_find_indicated_socket(SpaceNode &snode,
|
||||
bNode **nodep,
|
||||
bNodeSocket **sockp,
|
||||
const float2 &cursor,
|
||||
const eNodeSocketInOut in_out)
|
||||
bNodeSocket *node_find_indicated_socket(SpaceNode &snode,
|
||||
const float2 &cursor,
|
||||
const eNodeSocketInOut in_out)
|
||||
{
|
||||
rctf rect;
|
||||
|
||||
const float size_sock_padded = NODE_SOCKSIZE + 4;
|
||||
|
||||
*nodep = nullptr;
|
||||
*sockp = nullptr;
|
||||
snode.edittree->ensure_topology_cache();
|
||||
|
||||
const Span<bNode *> nodes = snode.edittree->all_nodes();
|
||||
for (int i = nodes.index_range().last(); i > 0; i--) {
|
||||
bNode &node = *nodes[i];
|
||||
|
||||
/* check if we click in a socket */
|
||||
LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode.edittree->nodes) {
|
||||
BLI_rctf_init_pt_radius(&rect, cursor, size_sock_padded);
|
||||
|
||||
if (!(node->flag & NODE_HIDDEN)) {
|
||||
if (!(node.flag & NODE_HIDDEN)) {
|
||||
/* extra padding inside and out - allow dragging on the text areas too */
|
||||
if (in_out == SOCK_IN) {
|
||||
rect.xmax += NODE_SOCKSIZE;
|
||||
|
@ -1235,37 +1232,31 @@ bool node_find_indicated_socket(SpaceNode &snode,
|
|||
}
|
||||
|
||||
if (in_out & SOCK_IN) {
|
||||
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
|
||||
for (bNodeSocket *sock : node.input_sockets()) {
|
||||
if (sock->is_visible()) {
|
||||
const float2 location(sock->runtime->locx, sock->runtime->locy);
|
||||
if (sock->flag & SOCK_MULTI_INPUT && !(node->flag & NODE_HIDDEN)) {
|
||||
if (sock->flag & SOCK_MULTI_INPUT && !(node.flag & NODE_HIDDEN)) {
|
||||
if (cursor_isect_multi_input_socket(cursor, *sock)) {
|
||||
if (!socket_is_occluded(location, *node, snode)) {
|
||||
*nodep = node;
|
||||
*sockp = sock;
|
||||
return true;
|
||||
if (!socket_is_occluded(location, node, snode)) {
|
||||
return sock;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (BLI_rctf_isect_pt(&rect, location.x, location.y)) {
|
||||
if (!socket_is_occluded(location, *node, snode)) {
|
||||
*nodep = node;
|
||||
*sockp = sock;
|
||||
return true;
|
||||
if (!socket_is_occluded(location, node, snode)) {
|
||||
return sock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (in_out & SOCK_OUT) {
|
||||
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
|
||||
for (bNodeSocket *sock : node.output_sockets()) {
|
||||
if (sock->is_visible()) {
|
||||
const float2 location(sock->runtime->locx, sock->runtime->locy);
|
||||
if (BLI_rctf_isect_pt(&rect, location.x, location.y)) {
|
||||
if (!socket_is_occluded(location, *node, snode)) {
|
||||
*nodep = node;
|
||||
*sockp = sock;
|
||||
return true;
|
||||
if (!socket_is_occluded(location, node, snode)) {
|
||||
return sock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1273,7 +1264,7 @@ bool node_find_indicated_socket(SpaceNode &snode,
|
|||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -311,12 +311,9 @@ bool composite_node_editable(bContext *C);
|
|||
bool node_has_hidden_sockets(bNode *node);
|
||||
void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set);
|
||||
int node_render_changed_exec(bContext *, wmOperator *);
|
||||
/** Type is #SOCK_IN and/or #SOCK_OUT. */
|
||||
bool node_find_indicated_socket(SpaceNode &snode,
|
||||
bNode **nodep,
|
||||
bNodeSocket **sockp,
|
||||
const float2 &cursor,
|
||||
eNodeSocketInOut in_out);
|
||||
bNodeSocket *node_find_indicated_socket(SpaceNode &snode,
|
||||
const float2 &cursor,
|
||||
eNodeSocketInOut in_out);
|
||||
float node_link_dim_factor(const View2D &v2d, const bNodeLink &link);
|
||||
bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link);
|
||||
|
||||
|
|
|
@ -124,27 +124,24 @@ static void pick_input_link_by_link_intersect(const bContext &C,
|
|||
|
||||
float2 drag_start;
|
||||
RNA_float_get_array(op.ptr, "drag_start", drag_start);
|
||||
bNode *node;
|
||||
bNodeSocket *socket;
|
||||
node_find_indicated_socket(*snode, &node, &socket, drag_start, SOCK_IN);
|
||||
bNodeSocket *socket = node_find_indicated_socket(*snode, drag_start, SOCK_IN);
|
||||
bNode &node = socket->owner_node();
|
||||
|
||||
/* Distance to test overlapping of cursor on link. */
|
||||
const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC;
|
||||
|
||||
bNodeLink *link_to_pick = nullptr;
|
||||
clear_picking_highlight(&snode->edittree->links);
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
|
||||
if (link->tosock == socket) {
|
||||
/* Test if the cursor is near a link. */
|
||||
std::array<float2, NODE_LINK_RESOL + 1> coords;
|
||||
node_link_bezier_points_evaluated(*link, coords);
|
||||
for (bNodeLink *link : socket->directly_linked_links()) {
|
||||
/* Test if the cursor is near a link. */
|
||||
std::array<float2, NODE_LINK_RESOL + 1> coords;
|
||||
node_link_bezier_points_evaluated(*link, coords);
|
||||
|
||||
for (const int i : IndexRange(coords.size() - 1)) {
|
||||
const float distance = dist_squared_to_line_segment_v2(cursor, coords[i], coords[i + 1]);
|
||||
if (distance < cursor_link_touch_distance) {
|
||||
link_to_pick = link;
|
||||
nldrag.last_picked_multi_input_socket_link = link_to_pick;
|
||||
}
|
||||
for (const int i : IndexRange(coords.size() - 1)) {
|
||||
const float distance = dist_squared_to_line_segment_v2(cursor, coords[i], coords[i + 1]);
|
||||
if (distance < cursor_link_touch_distance) {
|
||||
link_to_pick = link;
|
||||
nldrag.last_picked_multi_input_socket_link = link_to_pick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,8 +161,8 @@ static void pick_input_link_by_link_intersect(const bContext &C,
|
|||
link_to_pick->flag |= NODE_LINK_TEMP_HIGHLIGHT;
|
||||
ED_area_tag_redraw(CTX_wm_area(&C));
|
||||
|
||||
if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) {
|
||||
pick_link(nldrag, *snode, node, *link_to_pick);
|
||||
if (!node_find_indicated_socket(*snode, cursor, SOCK_IN)) {
|
||||
pick_link(nldrag, *snode, &node, *link_to_pick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -952,13 +949,11 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
|
|||
bNodeLinkDrag &nldrag = *static_cast<bNodeLinkDrag *>(op.customdata);
|
||||
|
||||
if (nldrag.in_out == SOCK_OUT) {
|
||||
bNode *tnode;
|
||||
bNodeSocket *tsock = nullptr;
|
||||
snode.edittree->ensure_topology_cache();
|
||||
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) {
|
||||
if (bNodeSocket *tsock = node_find_indicated_socket(snode, cursor, SOCK_IN)) {
|
||||
bNode &tnode = tsock->owner_node();
|
||||
for (bNodeLink &link : nldrag.links) {
|
||||
/* skip if socket is on the same node as the fromsock */
|
||||
if (tnode && link.fromnode == tnode) {
|
||||
if (link.fromnode == &tnode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -972,16 +967,16 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
|
|||
}
|
||||
|
||||
/* attach links to the socket */
|
||||
link.tonode = tnode;
|
||||
link.tonode = &tnode;
|
||||
link.tosock = tsock;
|
||||
nldrag.last_node_hovered_while_dragging_a_link = tnode;
|
||||
nldrag.last_node_hovered_while_dragging_a_link = &tnode;
|
||||
if (existing_link_connected_to_fromsock) {
|
||||
link.multi_input_socket_index =
|
||||
existing_link_connected_to_fromsock->multi_input_socket_index;
|
||||
continue;
|
||||
}
|
||||
if (link.tosock && link.tosock->flag & SOCK_MULTI_INPUT) {
|
||||
sort_multi_input_socket_links_with_drag(*tnode, link, cursor);
|
||||
sort_multi_input_socket_links_with_drag(tnode, link, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -997,21 +992,20 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
|
|||
}
|
||||
}
|
||||
else {
|
||||
bNode *tnode;
|
||||
bNodeSocket *tsock = nullptr;
|
||||
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) {
|
||||
if (bNodeSocket *tsock = node_find_indicated_socket(snode, cursor, SOCK_OUT)) {
|
||||
bNode &node = tsock->owner_node();
|
||||
for (bNodeLink &link : nldrag.links) {
|
||||
/* skip if this is already the target socket */
|
||||
if (link.fromsock == tsock) {
|
||||
continue;
|
||||
}
|
||||
/* skip if socket is on the same node as the fromsock */
|
||||
if (tnode && link.tonode == tnode) {
|
||||
if (link.tonode == &node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* attach links to the socket */
|
||||
link.fromnode = tnode;
|
||||
link.fromnode = &node;
|
||||
link.fromsock = tsock;
|
||||
}
|
||||
}
|
||||
|
@ -1094,12 +1088,11 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode,
|
|||
const float2 cursor,
|
||||
const bool detach)
|
||||
{
|
||||
/* output indicated? */
|
||||
bNode *node;
|
||||
bNodeSocket *sock;
|
||||
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
|
||||
if (bNodeSocket *sock = node_find_indicated_socket(snode, cursor, SOCK_OUT)) {
|
||||
bNode &node = sock->owner_node();
|
||||
|
||||
std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
|
||||
nldrag->start_node = node;
|
||||
nldrag->start_node = &node;
|
||||
nldrag->start_socket = sock;
|
||||
nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
|
||||
int link_limit = nodeSocketLinkLimit(sock);
|
||||
|
@ -1121,16 +1114,16 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode,
|
|||
else {
|
||||
/* dragged links are fixed on output side */
|
||||
nldrag->in_out = SOCK_OUT;
|
||||
nldrag->links.append(create_drag_link(*node, *sock));
|
||||
nldrag->links.append(create_drag_link(node, *sock));
|
||||
}
|
||||
return nldrag;
|
||||
}
|
||||
|
||||
/* or an input? */
|
||||
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
|
||||
if (bNodeSocket *sock = node_find_indicated_socket(snode, cursor, SOCK_IN)) {
|
||||
bNode &node = sock->owner_node();
|
||||
std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
|
||||
nldrag->last_node_hovered_while_dragging_a_link = node;
|
||||
nldrag->start_node = node;
|
||||
nldrag->last_node_hovered_while_dragging_a_link = &node;
|
||||
nldrag->start_node = &node;
|
||||
nldrag->start_socket = sock;
|
||||
|
||||
nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
|
||||
|
@ -1154,15 +1147,13 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode,
|
|||
nodeRemLink(snode.edittree, link_to_pick);
|
||||
|
||||
/* send changed event to original link->tonode */
|
||||
if (node) {
|
||||
BKE_ntree_update_tag_node_property(snode.edittree, node);
|
||||
}
|
||||
BKE_ntree_update_tag_node_property(snode.edittree, &node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* dragged links are fixed on input side */
|
||||
nldrag->in_out = SOCK_IN;
|
||||
nldrag->links.append(create_drag_link(*node, *sock));
|
||||
nldrag->links.append(create_drag_link(node, *sock));
|
||||
}
|
||||
return nldrag;
|
||||
}
|
||||
|
|
|
@ -175,14 +175,9 @@ static bool is_position_over_node_or_socket(SpaceNode &snode, const float2 &mous
|
|||
if (node_under_mouse_tweak(*snode.edittree, mouse)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bNode *node;
|
||||
bNodeSocket *sock;
|
||||
if (node_find_indicated_socket(
|
||||
snode, &node, &sock, mouse, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
|
||||
if (node_find_indicated_socket(snode, mouse, SOCK_IN | SOCK_OUT)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -532,9 +527,8 @@ static bool node_mouse_select(bContext *C,
|
|||
const Object *ob = CTX_data_active_object(C);
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const wmWindowManager *wm = CTX_wm_manager(C);
|
||||
bNode *node;
|
||||
bNode *node = nullptr;
|
||||
bNodeSocket *sock = nullptr;
|
||||
bNodeSocket *tsock;
|
||||
|
||||
/* always do socket_select when extending selection. */
|
||||
const bool socket_select = (params->sel_op == SEL_OP_XOR) ||
|
||||
|
@ -551,7 +545,9 @@ static bool node_mouse_select(bContext *C,
|
|||
if (socket_select) {
|
||||
/* NOTE: unlike nodes #SelectPick_Params isn't fully supported. */
|
||||
const bool extend = (params->sel_op == SEL_OP_XOR);
|
||||
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
|
||||
sock = node_find_indicated_socket(snode, cursor, SOCK_IN);
|
||||
if (sock) {
|
||||
node = &sock->owner_node();
|
||||
found = true;
|
||||
node_was_selected = node->flag & SELECT;
|
||||
|
||||
|
@ -560,41 +556,43 @@ static bool node_mouse_select(bContext *C,
|
|||
node_socket_toggle(node, *sock, true);
|
||||
changed = true;
|
||||
}
|
||||
else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
|
||||
found = true;
|
||||
node_was_selected = node->flag & SELECT;
|
||||
if (!changed) {
|
||||
sock = node_find_indicated_socket(snode, cursor, SOCK_OUT);
|
||||
if (sock) {
|
||||
node = &sock->owner_node();
|
||||
found = true;
|
||||
node_was_selected = node->flag & SELECT;
|
||||
|
||||
if (sock->flag & SELECT) {
|
||||
if (extend) {
|
||||
node_socket_deselect(node, *sock, true);
|
||||
changed = true;
|
||||
if (sock->flag & SELECT) {
|
||||
if (extend) {
|
||||
node_socket_deselect(node, *sock, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Only allow one selected output per node, for sensible linking.
|
||||
* Allow selecting outputs from different nodes though, if extend is true. */
|
||||
if (node) {
|
||||
for (tsock = (bNodeSocket *)node->outputs.first; tsock; tsock = tsock->next) {
|
||||
else {
|
||||
/* Only allow one selected output per node, for sensible linking.
|
||||
* Allow selecting outputs from different nodes though, if extend is true. */
|
||||
for (bNodeSocket *tsock : node->output_sockets()) {
|
||||
if (tsock == sock) {
|
||||
continue;
|
||||
}
|
||||
node_socket_deselect(node, *tsock, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (!extend) {
|
||||
for (bNode *tnode : node_tree.all_nodes()) {
|
||||
if (tnode == node) {
|
||||
continue;
|
||||
}
|
||||
for (tsock = (bNodeSocket *)tnode->outputs.first; tsock; tsock = tsock->next) {
|
||||
node_socket_deselect(tnode, *tsock, true);
|
||||
changed = true;
|
||||
if (!extend) {
|
||||
for (bNode *tnode : node_tree.all_nodes()) {
|
||||
if (tnode == node) {
|
||||
continue;
|
||||
}
|
||||
for (bNodeSocket *tsock : tnode->output_sockets()) {
|
||||
node_socket_deselect(tnode, *tsock, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
node_socket_select(node, *sock);
|
||||
changed = true;
|
||||
}
|
||||
node_socket_select(node, *sock);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,6 +254,7 @@ typedef enum eNodeSocketInOut {
|
|||
SOCK_IN = 1 << 0,
|
||||
SOCK_OUT = 1 << 1,
|
||||
} eNodeSocketInOut;
|
||||
ENUM_OPERATORS(eNodeSocketInOut, SOCK_OUT);
|
||||
|
||||
/** #bNodeSocket.flag, first bit is selection. */
|
||||
typedef enum eNodeSocketFlag {
|
||||
|
|
Loading…
Reference in New Issue