Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Schempp <fabian_schempp>2021-02-11 10:16:17 +0300
committerHans Goudey <h.goudey@me.com>2021-02-11 10:16:17 +0300
commit8f707a72e81833bb835324ddc635b29dfbe87a9f (patch)
tree6628941c09c3a46be9b1c0f36751ed8c6669feee /source/blender/editors
parent9a9e19fdcc48622dba8f98c9afb10a6750ff22b0 (diff)
UI: Multi-input node socket spacing and interaction
This commit makes links connected to multi-input sockets spread verticaly along the socket. Sockets grow if more links are connected and the node layout updates accordingly. Links are sorted by their incoming angle to avoid crossing links. Also, link picking is updated to work with spread links and bezier links. Currently the multi-input sockets are used in the join geometry node. The mutli-input sockets look like a vertical rounded rectangle. Currently they do not support the other custom socket shapes. Reviewed By Hans Goudey, with cleanup and additional edits Differential Revision: https://developer.blender.org/D10181
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/space_node/drawnode.c21
-rw-r--r--source/blender/editors/space_node/node_draw.c154
-rw-r--r--source/blender/editors/space_node/node_edit.c45
-rw-r--r--source/blender/editors/space_node/node_intern.h8
-rw-r--r--source/blender/editors/space_node/node_relationships.c186
5 files changed, 383 insertions, 31 deletions
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 2d65302c656..4716f1c29ea 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -3560,10 +3560,10 @@ void draw_nodespace_back_pix(const bContext *C,
}
/* return quadratic beziers points for a given nodelink and clip if v2d is not NULL. */
-static bool node_link_bezier_handles(const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link,
- float vec[4][2])
+bool node_link_bezier_handles(const View2D *v2d,
+ const SpaceNode *snode,
+ const bNodeLink *link,
+ float vec[4][2])
{
float cursor[2] = {0.0f, 0.0f};
@@ -3591,6 +3591,9 @@ static bool node_link_bezier_handles(const View2D *v2d,
if (link->tosock) {
vec[3][0] = link->tosock->locx;
vec[3][1] = link->tosock->locy;
+ if (!(link->tonode->flag & NODE_HIDDEN) && link->tosock->flag & SOCK_MULTI_INPUT) {
+ node_link_calculate_multi_input_position(link, vec[3]);
+ }
toreroute = (link->tonode && link->tonode->type == NODE_REROUTE);
}
else {
@@ -3902,7 +3905,7 @@ void node_draw_link_bezier(const View2D *v2d,
int th_col3)
{
float vec[4][2];
-
+ const bool highlighted = link->flag & NODE_LINK_TEMP_HIGHLIGHT;
if (node_link_bezier_handles(v2d, snode, link, vec)) {
int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
(link->fromnode && (link->fromnode->type == NODE_REROUTE)));
@@ -3911,7 +3914,7 @@ void node_draw_link_bezier(const View2D *v2d,
nodelink_batch_init();
}
- if (g_batch_link.enabled) {
+ if (g_batch_link.enabled && !highlighted) {
/* Add link to batch. */
nodelink_batch_add_link(
snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow);
@@ -3925,6 +3928,12 @@ void node_draw_link_bezier(const View2D *v2d,
UI_GetThemeColor4fv(th_col1, colors[1]);
UI_GetThemeColor4fv(th_col2, colors[2]);
+ if (highlighted) {
+ float link_preselection_highlight_color[4];
+ UI_GetThemeColor4fv(TH_SELECT, link_preselection_highlight_color);
+ copy_v4_v4(colors[2], link_preselection_highlight_color);
+ }
+
GPUBatch *batch = g_batch_link.batch_single;
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec);
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 4dd945c4cf1..9ef914af75b 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -22,6 +22,8 @@
* \brief higher level node drawing for the node editor.
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
@@ -500,6 +502,16 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
PointerRNA sockptr;
RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
+ /* Add the half the height of a multi-input socket to cursor Y
+ * to account for the increased height of the taller sockets. */
+ float multi_input_socket_offset = 0.0f;
+ if (nsock->flag & SOCK_MULTI_INPUT) {
+ if (nsock->total_inputs > 2) {
+ multi_input_socket_offset = (nsock->total_inputs - 2) * NODE_MULTI_INPUT_LINK_GAP;
+ }
+ }
+ dy -= multi_input_socket_offset * 0.5f;
+
uiLayout *layout = UI_block_layout(node->block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
@@ -533,7 +545,7 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
/* place the socket circle in the middle of the layout */
nsock->locy = 0.5f * (dy + buty);
- dy = buty;
+ dy = buty - multi_input_socket_offset * 0.5;
if (nsock->next) {
dy -= NODE_SOCKDY;
}
@@ -751,6 +763,27 @@ static void node_socket_draw(const bNodeSocket *sock,
immVertex2f(pos_id, locx, locy);
}
+static void node_socket_draw_multi_input(const float color[4],
+ const float color_outline[4],
+ const float width,
+ const float height,
+ const int locx,
+ const int locy)
+{
+ const float outline_width = 1.0f;
+ /* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width. */
+ const rctf rect = {
+ .xmin = locx - width + outline_width * 0.5f,
+ .xmax = locx + width - outline_width * 0.5f,
+ .ymin = locy - height + outline_width * 0.5f,
+ .ymax = locy + height - outline_width * 0.5f,
+ };
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv_ex(
+ &rect, color, NULL, 1.0f, color_outline, outline_width, width - outline_width * 0.5f);
+}
+
static void node_socket_outline_color_get(bool selected, float r_outline_color[4])
{
if (selected) {
@@ -1006,6 +1039,10 @@ void node_draw_sockets(const View2D *v2d,
selected_input_len++;
continue;
}
+ /* Don't draw multi-input sockets here since they are drawn in a different batch. */
+ if (sock->flag & SOCK_MULTI_INPUT) {
+ continue;
+ }
node_socket_draw_nested(C,
ntree,
@@ -1115,6 +1152,28 @@ void node_draw_sockets(const View2D *v2d,
GPU_program_point_size(false);
GPU_blend(GPU_BLEND_NONE);
+
+ /* Draw multi-nput sockets after the others because they are drawn with "UI_roundbox"
+ * rather than with GL_POINT. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (nodeSocketIsHidden(socket)) {
+ continue;
+ }
+ if (!(socket->flag & SOCK_MULTI_INPUT)) {
+ continue;
+ }
+
+ const bool is_node_hidden = (node->flag & NODE_HIDDEN);
+ const float width = NODE_SOCKSIZE;
+ float height = is_node_hidden ? width : node_socket_calculate_height(socket) - width;
+
+ float color[4];
+ float outline_color[4];
+ node_socket_color_get((bContext *)C, ntree, &node_ptr, socket, color);
+ node_socket_outline_color_get(selected, outline_color);
+
+ node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy);
+ }
}
static void node_draw_basis(const bContext *C,
@@ -1590,17 +1649,67 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
}
}
+static void count_mutli_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (struct bNodeSocket *, socket, &node->inputs) {
+ if (socket->flag & SOCK_MULTI_INPUT) {
+ socket->total_inputs = 0;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tosock == socket) {
+ socket->total_inputs++;
+ }
+ }
+ /* Count temporary links going into this socket. */
+ LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
+ LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
+ bNodeLink *link = (bNodeLink *)linkdata->data;
+ if (link->tosock == socket) {
+ socket->total_inputs++;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
void node_update_nodetree(const bContext *C, bNodeTree *ntree)
{
/* make sure socket "used" tags are correct, for displaying value buttons */
+ SpaceNode *snode = CTX_wm_space_node(C);
ntreeTagUsedSockets(ntree);
+ count_mutli_input_socket_links(ntree, snode);
+
/* update nodes front to back, so children sizes get updated before parents */
LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
node_update(C, ntree, node);
}
}
+static int compare_link_by_angle_to_node(const void *a, const void *b)
+{
+ const bNodeLink *link_a = *(const bNodeLink **)a;
+ const bNodeLink *link_b = *(const bNodeLink **)b;
+
+ BLI_assert(link_a->tosock == link_b->tosock);
+ const float socket_location[2] = {link_a->tosock->locx, link_a->tosock->locy};
+ const float up_direction[2] = {0.0f, 1.0f};
+
+ float delta_a[2] = {link_a->fromsock->locx - socket_location[0],
+ link_a->fromsock->locy - socket_location[1]};
+ normalize_v2(delta_a);
+ const float angle_a = angle_normalized_v2v2(up_direction, delta_a);
+
+ float delta_b[2] = {link_b->fromsock->locx - socket_location[0],
+ link_b->fromsock->locy - socket_location[1]};
+ normalize_v2(delta_b);
+ const float angle_b = angle_normalized_v2v2(up_direction, delta_b);
+
+ return angle_a < angle_b ? 1 : -1;
+}
+
static void node_draw(const bContext *C,
ARegion *region,
SpaceNode *snode,
@@ -1615,6 +1724,46 @@ static void node_draw(const bContext *C,
#define USE_DRAW_TOT_UPDATE
+/**
+ * Automatically sort the input links to multi-input sockets to avoid crossing noodles.
+ */
+static void sort_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (socket->flag & SOCK_MULTI_INPUT) {
+ /* The total is calculated in #node_update_nodetree, which runs before this draw step. */
+ const int total_inputs = socket->total_inputs;
+ bNodeLink **input_links = MEM_malloc_arrayN(total_inputs, sizeof(bNodeLink *), __func__);
+
+ int index = 0;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tosock == socket) {
+ input_links[index] = (bNodeLink *)link;
+ index++;
+ }
+ }
+ LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
+ LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
+ bNodeLink *link = (bNodeLink *)linkdata->data;
+ if (link->tosock == socket) {
+ input_links[index] = (bNodeLink *)link;
+ index++;
+ }
+ }
+ }
+
+ qsort(input_links, total_inputs, sizeof(bNodeLink *), compare_link_by_angle_to_node);
+ for (int i = 0; i < total_inputs; i++) {
+ input_links[i]->multi_input_socket_index = i;
+ }
+
+ MEM_freeN(input_links);
+ }
+ }
+ }
+}
+
void node_draw_nodetree(const bContext *C,
ARegion *region,
SpaceNode *snode,
@@ -1650,6 +1799,9 @@ void node_draw_nodetree(const bContext *C,
/* node lines */
GPU_blend(GPU_BLEND_ALPHA);
nodelink_batch_start(snode);
+
+ sort_multi_input_socket_links(ntree, snode);
+
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (!nodeLinkIsHidden(link)) {
node_draw_link(&region->v2d, snode, link);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index c006889f0f7..04787748937 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -98,6 +98,25 @@ typedef struct CompoJob {
float *progress;
} CompoJob;
+float node_socket_calculate_height(const bNodeSocket *socket)
+{
+ float sock_height = NODE_SOCKSIZE * 2.0f;
+ if (socket->flag & SOCK_MULTI_INPUT) {
+ sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket->total_inputs, NODE_SOCKSIZE);
+ }
+ return sock_height;
+}
+
+void node_link_calculate_multi_input_position(const bNodeLink *link, float r[2])
+{
+ float offset = (link->tosock->total_inputs * NODE_MULTI_INPUT_LINK_GAP -
+ NODE_MULTI_INPUT_LINK_GAP) *
+ 0.5;
+ r[0] = link->tosock->locx - NODE_SOCKSIZE * 0.5f;
+ r[1] = link->tosock->locy - offset +
+ (link->multi_input_socket_index * NODE_MULTI_INPUT_LINK_GAP);
+}
+
static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
{
LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) {
@@ -1104,6 +1123,21 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
}
/* checks snode->mouse position, and returns found node/socket */
+static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket *socket)
+{
+ const float node_socket_height = node_socket_calculate_height(socket);
+ const rctf multi_socket_rect = {
+ .xmin = socket->locx - NODE_SOCKSIZE * 4,
+ .xmax = socket->locx + NODE_SOCKSIZE,
+ .ymin = socket->locy - node_socket_height * 0.5 - NODE_SOCKSIZE * 2.0f,
+ .ymax = socket->locy + node_socket_height * 0.5 + NODE_SOCKSIZE * 2.0f,
+ };
+ if (BLI_rctf_isect_pt(&multi_socket_rect, cursor[0], cursor[1])) {
+ return true;
+ }
+ return false;
+}
+
/* type is SOCK_IN and/or SOCK_OUT */
int node_find_indicated_socket(
SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out)
@@ -1132,7 +1166,16 @@ int node_find_indicated_socket(
if (in_out & SOCK_IN) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (!nodeSocketIsHidden(sock)) {
- if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
+ if (sock->flag & SOCK_MULTI_INPUT && !(node->flag & NODE_HIDDEN)) {
+ if (cursor_isect_multi_input_socket(cursor, sock)) {
+ if (node == visible_node(snode, &rect)) {
+ *nodep = node;
+ *sockp = sock;
+ return 1;
+ }
+ }
+ }
+ else if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
if (node == visible_node(snode, &rect)) {
*nodep = node;
*sockp = sock;
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 51333fd5a09..2f3fa6996af 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -78,6 +78,9 @@ typedef struct SpaceNode_Runtime {
void space_node_group_offset(struct SpaceNode *snode, float *x, float *y);
/* node_draw.c */
+float node_socket_calculate_height(const bNodeSocket *socket);
+void node_link_calculate_multi_input_position(const bNodeLink *link, float r[2]);
+
int node_get_colorid(struct bNode *node);
int node_get_resize_cursor(int directions);
void node_draw_shadow(const struct SpaceNode *snode,
@@ -178,6 +181,10 @@ bool node_link_bezier_points(const struct View2D *v2d,
const struct bNodeLink *link,
float coord_array[][2],
const int resol);
+bool node_link_bezier_handles(const struct View2D *v2d,
+ const struct SpaceNode *snode,
+ const struct bNodeLink *link,
+ float vec[4][2]);
void draw_nodespace_back_pix(const struct bContext *C,
struct ARegion *region,
struct SpaceNode *snode,
@@ -290,6 +297,7 @@ extern const char *node_context_dir[];
#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC)
#define NODE_MARGIN_X (1.10f * U.widget_unit)
#define NODE_SOCKSIZE (0.25f * U.widget_unit)
+#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit)
#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
#define NODE_LINK_RESOL 12
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index f3ce60bbcd9..93accad319f 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -32,6 +32,7 @@
#include "BKE_anim_data.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -179,6 +180,137 @@ typedef struct NodeInsertOfsData {
float offset_x; /* offset to apply to node chain */
} NodeInsertOfsData;
+static void clear_picking_highlight(ListBase *links)
+{
+ LISTBASE_FOREACH (bNodeLink *, link, links) {
+ link->flag &= ~NODE_LINK_TEMP_HIGHLIGHT;
+ }
+}
+
+static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock)
+{
+ LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
+ bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
+ linkdata->data = oplink;
+ if (sock->in_out == SOCK_OUT) {
+ oplink->fromnode = node;
+ oplink->fromsock = sock;
+ }
+ else {
+ oplink->tonode = node;
+ oplink->tosock = sock;
+ }
+ oplink->flag |= NODE_LINK_VALID;
+ oplink->flag &= ~NODE_LINK_TEST;
+ if (node_connected_to_output(bmain, snode->edittree, node)) {
+ oplink->flag |= NODE_LINK_TEST;
+ }
+ return linkdata;
+}
+
+static void pick_link(const bContext *C,
+ wmOperator *op,
+ bNodeLinkDrag *nldrag,
+ SpaceNode *snode,
+ bNode *node,
+ bNodeLink *link_to_pick)
+{
+ clear_picking_highlight(&snode->edittree->links);
+ RNA_boolean_set(op->ptr, "has_link_picked", true);
+
+ Main *bmain = CTX_data_main(C);
+ LinkData *linkdata = create_drag_link(
+ bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock);
+
+ BLI_addtail(&nldrag->links, linkdata);
+ nodeRemLink(snode->edittree, link_to_pick);
+ /* Send changed event to original link->tonode. */
+ if (node) {
+ snode_update(snode, node);
+ }
+}
+
+static void pick_input_link_by_link_intersect(const bContext *C,
+ wmOperator *op,
+ bNodeLinkDrag *nldrag,
+ const float *cursor)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ const ARegion *region = CTX_wm_region(C);
+ const View2D *v2d = &region->v2d;
+
+ float drag_start[2];
+ 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);
+
+ const float trigger_drag_distance = 25.0f;
+ const float cursor_link_touch_distance = 25.0f;
+
+ const float socket_height = node_socket_calculate_height(socket);
+
+ float cursor_to_socket_relative[2];
+ float socket_position[2] = {socket->locx, socket->locy};
+ sub_v2_v2v2(cursor_to_socket_relative, cursor, socket_position);
+ float distance_from_socket_v2[2] = {
+ max_ff(0, fabs(cursor_to_socket_relative[0]) - NODE_SOCKSIZE * 0.5),
+ max_ff(0, fabs(cursor_to_socket_relative[1]) - socket_height)};
+ const float distance_from_socket = len_v2(distance_from_socket_v2);
+
+ const int resolution = NODE_LINK_RESOL;
+
+ bNodeLink *link_to_pick = NULL;
+ 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. */
+ float vec[4][2];
+ node_link_bezier_handles(v2d, snode, link, vec);
+
+ float data[NODE_LINK_RESOL * 2 + 2];
+ BKE_curve_forward_diff_bezier(
+ vec[0][0], vec[1][0], vec[2][0], vec[3][0], data, resolution, sizeof(float[2]));
+ BKE_curve_forward_diff_bezier(
+ vec[0][1], vec[1][1], vec[2][1], vec[3][1], data + 1, resolution, sizeof(float[2]));
+
+ for (int i = 0; i < resolution * 2; i += 2) {
+ float *l1 = &data[i];
+ float *l2 = &data[i + 2];
+ float distance = dist_squared_to_line_segment_v2(cursor, l1, l2);
+ if (distance < cursor_link_touch_distance) {
+ link_to_pick = link;
+ RNA_int_set(op->ptr, "last_picked_link_index", link->multi_input_socket_index);
+ }
+ }
+ }
+ }
+
+ /* If no linked was picked in this call, try using the one picked in the previous call.
+ * Not essential for the basic behavior, but can make interaction feel a bit better if
+ * the mouse moves to the right and loses the "selection." */
+ if (!link_to_pick) {
+ int last_picked_link_index = RNA_int_get(op->ptr, "last_picked_link_index");
+ if (last_picked_link_index > -1) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ if (link->multi_input_socket_index == last_picked_link_index) {
+ link_to_pick = link;
+ }
+ }
+ }
+ }
+
+ if (link_to_pick) {
+ /* Highlight is set here and cleared in the next iteration or if the operation finishes. */
+ link_to_pick->flag |= NODE_LINK_TEMP_HIGHLIGHT;
+ ED_area_tag_redraw(CTX_wm_area(C));
+
+ if (distance_from_socket > trigger_drag_distance) {
+ pick_link(C, op, nldrag, snode, node, link_to_pick);
+ }
+ }
+}
+
static int sort_nodes_locx(const void *a, const void *b)
{
const bNodeListItem *nli1 = a;
@@ -600,6 +732,13 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
tlink = NULL;
to_count--;
}
+ /* Also remove link if it comes from the same output. */
+ if (tlink->fromsock == from) {
+ nodeRemLink(ntree, tlink);
+ tlink = NULL;
+ to_count--;
+ from_count--;
+ }
}
}
}
@@ -748,10 +887,15 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE:
- node_link_find_socket(C, op, cursor);
+ if (nldrag->from_multi_input_socket && !RNA_boolean_get(op->ptr, "has_link_picked")) {
+ pick_input_link_by_link_intersect(C, op, nldrag, cursor);
+ }
+ else {
+ node_link_find_socket(C, op, cursor);
- node_link_update_header(C, nldrag);
- ED_region_tag_redraw(region);
+ node_link_update_header(C, nldrag);
+ ED_region_tag_redraw(region);
+ }
break;
case LEFTMOUSE:
@@ -762,6 +906,8 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_workspace_status_text(C, NULL);
ED_region_tag_redraw(region);
+ SpaceNode *snode = CTX_wm_space_node(C);
+ clear_picking_highlight(&snode->edittree->links);
return OPERATOR_FINISHED;
}
break;
@@ -817,16 +963,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* create a new link */
- LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
- bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
- oplink->fromnode = node;
- oplink->fromsock = sock;
- oplink->flag |= NODE_LINK_VALID;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, node)) {
- oplink->flag |= NODE_LINK_TEST;
- }
+ LinkData *linkdata = create_drag_link(bmain, snode, node, sock);
BLI_addtail(&nldrag->links, linkdata);
}
@@ -875,16 +1012,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* create a new link */
- LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
- bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
- oplink->tonode = node;
- oplink->tosock = sock;
- oplink->flag |= NODE_LINK_VALID;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, node)) {
- oplink->flag |= NODE_LINK_TEST;
- }
+ LinkData *linkdata = create_drag_link(bmain, snode, node, sock);
BLI_addtail(&nldrag->links, linkdata);
}
@@ -904,6 +1032,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
float cursor[2];
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
RNA_float_set_array(op->ptr, "drag_start", cursor);
+ RNA_int_set(op->ptr, "last_picked_link_index", -1);
RNA_boolean_set(op->ptr, "has_link_picked", false);
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
@@ -931,6 +1060,7 @@ static void node_link_cancel(bContext *C, wmOperator *op)
BLI_freelistN(&nldrag->links);
MEM_freeN(nldrag);
+ clear_picking_highlight(&snode->edittree->links);
}
void NODE_OT_link(wmOperatorType *ot)
@@ -972,6 +1102,16 @@ void NODE_OT_link(wmOperatorType *ot)
-UI_PRECISION_FLOAT_MAX,
UI_PRECISION_FLOAT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_int(ot->srna,
+ "last_picked_link_index",
+ -1,
+ -1,
+ 4095,
+ "Last Picked Link Index",
+ "The index of the last picked link on a multi-input socket",
+ -1,
+ 4095);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* ********************** Make Link operator ***************** */