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/space_node/node_relationships.c
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/space_node/node_relationships.c')
-rw-r--r--source/blender/editors/space_node/node_relationships.c186
1 files changed, 163 insertions, 23 deletions
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 ***************** */