Add output multi-link move using shift-click (#32)

When an output connects to multiple inputs, and you'd like to move all of those links to another node, you are currently required to drag each new link one by one.

This commit adds the ability to move everything at once, using Shift + Click (and drag).

It -does not- currently work with the drop to blank space + search for new node.  It will j ust rewire the first.  This can probably be fixed easily enough.

It -does- function with reroute nodes, however it requires that they are dropped onto the new output directly, not just anywhere on the node.  This is expected, really.
This commit is contained in:
filtered
2024-07-29 11:15:13 +10:00
committed by GitHub
parent 053caa4ccb
commit 3175828350

View File

@@ -5341,6 +5341,7 @@ LGraphNode.prototype.executeAction = function(action)
this.last_mouse_position = [0, 0];
this.visible_area = this.ds.visible_area;
this.visible_links = [];
this.connecting_links = null; // Explicitly null-checked
this.viewport = options.viewport || null; //to constraint render area to a portion of the canvas
@@ -5393,7 +5394,7 @@ LGraphNode.prototype.executeAction = function(action)
this.node_dragged = null;
this.node_over = null;
this.node_capturing_input = null;
this.connecting_node = null;
this.connecting_links = null;
this.highlighted_links = {};
this.dragging_canvas = false;
@@ -5950,7 +5951,7 @@ LGraphNode.prototype.executeAction = function(action)
} //if it wasn't selected?
//not dragging mouse to connect two slots
if ( this.allow_interaction && !this.connecting_node && !node.flags.collapsed && !this.live_mode ) {
if ( this.allow_interaction && !this.connecting_links && !node.flags.collapsed && !this.live_mode ) {
//Search for corner for resize
if ( !skip_action &&
node.resizable !== false && node.inResizeCorner(e.canvasX, e.canvasY)
@@ -5975,11 +5976,42 @@ LGraphNode.prototype.executeAction = function(action)
20
)
) {
this.connecting_node = node;
this.connecting_output = output;
this.connecting_output.slot_index = i;
this.connecting_pos = node.getConnectionPos( false, i );
this.connecting_slot = i;
// Drag multiple output links
if (e.shiftKey) {
if (output.links?.length > 0) {
this.connecting_links = [];
for (const linkId of output.links) {
const link = this.graph.links[linkId];
const slot = link.target_slot;
const linked_node = this.graph._nodes_by_id[link.target_id];
const input = linked_node.inputs[slot];
const pos = linked_node.getConnectionPos(true, slot);
this.connecting_links.push({
node: linked_node,
slot: slot,
input: input,
output: null,
pos: pos,
});
}
skip_action = true;
break;
}
}
output.slot_index = i;
this.connecting_links = [
{
node: node,
slot: i,
input: null,
output: output,
pos: link_pos,
}
]
if (LiteGraph.shift_click_do_break_link_from){
if (e.shiftKey) {
@@ -6046,15 +6078,17 @@ LGraphNode.prototype.executeAction = function(action)
if (!LiteGraph.click_do_break_link_to){
node.disconnectInput(i);
}
this.connecting_node = this.graph._nodes_by_id[
link_info.origin_id
];
this.connecting_slot =
link_info.origin_slot;
this.connecting_output = this.connecting_node.outputs[
this.connecting_slot
];
this.connecting_pos = this.connecting_node.getConnectionPos( false, this.connecting_slot );
const linked_node = this.graph._nodes_by_id[link_info.origin_id];
const slot = link_info.origin_slot;
this.connecting_links = [
{
node: linked_node,
slot: slot,
input: null,
output: linked_node.outputs[slot],
pos: linked_node.getConnectionPos( false, slot ),
}
]
this.dirty_bgcanvas = true;
skip_action = true;
@@ -6069,11 +6103,15 @@ LGraphNode.prototype.executeAction = function(action)
if (!skip_action){
// connect from in to out, from to to from
this.connecting_node = node;
this.connecting_input = input;
this.connecting_input.slot_index = i;
this.connecting_pos = node.getConnectionPos( true, i );
this.connecting_slot = i;
this.connecting_links = [
{
node: node,
slot: i,
input: input,
output: null,
pos: link_pos,
}
]
this.dirty_bgcanvas = true;
skip_action = true;
@@ -6221,7 +6259,7 @@ LGraphNode.prototype.executeAction = function(action)
if (node && this.allow_interaction && !skip_action && !this.read_only){
//not dragging mouse to connect two slots
if (
!this.connecting_node &&
!this.connecting_links &&
!node.flags.collapsed &&
!this.live_mode
) {
@@ -6427,7 +6465,7 @@ LGraphNode.prototype.executeAction = function(action)
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
} else if ((this.allow_interaction || (node && node.flags.allow_interaction)) && !this.read_only) {
if (this.connecting_node) {
if (this.connecting_links) {
this.dirty_canvas = true;
}
@@ -6468,9 +6506,10 @@ LGraphNode.prototype.executeAction = function(action)
}
//if dragging a link
if (this.connecting_node) {
if (this.connecting_links) {
const firstLink = this.connecting_links[0];
if (this.connecting_output){
if (firstLink.output) {
var pos = this._highlight_input || [0, 0]; //to store the output of isOverNodeInput
@@ -6482,7 +6521,7 @@ LGraphNode.prototype.executeAction = function(action)
var slot = this.isOverNodeInput( node, e.canvasX, e.canvasY, pos );
if (slot != -1 && node.inputs[slot]) {
var slot_type = node.inputs[slot].type;
if ( LiteGraph.isValidConnection( this.connecting_output.type, slot_type ) ) {
if ( LiteGraph.isValidConnection( firstLink.output.type, slot_type ) ) {
this._highlight_input = pos;
this._highlight_input_slot = node.inputs[slot]; // XXX CHECK THIS
}
@@ -6492,7 +6531,7 @@ LGraphNode.prototype.executeAction = function(action)
}
}
}else if(this.connecting_input){
}else if(firstLink.input){
var pos = this._highlight_output || [0, 0]; //to store the output of isOverNodeOutput
@@ -6504,7 +6543,7 @@ LGraphNode.prototype.executeAction = function(action)
var slot = this.isOverNodeOutput( node, e.canvasX, e.canvasY, pos );
if (slot != -1 && node.outputs[slot]) {
var slot_type = node.outputs[slot].type;
if ( LiteGraph.isValidConnection( this.connecting_input.type, slot_type ) ) {
if ( LiteGraph.isValidConnection( firstLink.input.type, slot_type ) ) {
this._highlight_output = pos;
}
} else {
@@ -6728,34 +6767,33 @@ LGraphNode.prototype.executeAction = function(action)
}
this.dragging_rectangle = null;
} else if (this.connecting_node) {
//dragging a connection
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
var connInOrOut = this.connecting_output || this.connecting_input;
var connType = connInOrOut.type;
} else if (this.connecting_links) {
//node below mouse
if (node) {
/* no need to condition on event type.. just another type
if (
connType == LiteGraph.EVENT &&
this.isOverNodeBox(node, e.canvasX, e.canvasY)
) {
for (const link of this.connecting_links) {
//dragging a connection
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
this.connecting_node.connect(
this.connecting_slot,
node,
LiteGraph.EVENT
);
} else {*/
/* no need to condition on event type.. just another type
if (
connType == LiteGraph.EVENT &&
this.isOverNodeBox(node, e.canvasX, e.canvasY)
) {
this.connecting_node.connect(
this.connecting_slot,
node,
LiteGraph.EVENT
);
} else {*/
//slot below mouse? connect
if (this.connecting_output){
if (link.output){
var slot = this.isOverNodeInput(
node,
@@ -6763,13 +6801,13 @@ LGraphNode.prototype.executeAction = function(action)
e.canvasY
);
if (slot != -1) {
this.connecting_node.connect(this.connecting_slot, node, slot);
link.node.connect(link.slot, node, slot);
} else {
//not on top of an input
// look for a good slot
this.connecting_node.connectByType(this.connecting_slot,node,connType);
link.node.connectByType(link.slot, node, link.output.type);
}
} else if (this.connecting_input) {
} else if (link.input) {
var slot = this.isOverNodeOutput(
node,
e.canvasX,
@@ -6777,14 +6815,17 @@ LGraphNode.prototype.executeAction = function(action)
);
if (slot != -1) {
node.connect(slot, this.connecting_node, this.connecting_slot); // this is inverted has output-input nature like
node.connect(slot, link.node, link.slot); // this is inverted has output-input nature like
} else {
//not on top of an input
// look for a good slot
this.connecting_node.connectByTypeOutput(this.connecting_slot,node,connType);
link.node.connectByTypeOutput(link.slot, node, link.input.type);
}
}
}
} else {
const firstLink = this.connecting_links[0];
const linkReleaseContext = this.connecting_output ? {
node_from: this.connecting_node,
slot_from: this.connecting_output,
@@ -6812,20 +6853,16 @@ LGraphNode.prototype.executeAction = function(action)
this.showSearchBox(e, linkReleaseContext);
}
}else{
if(this.connecting_output){
this.showConnectionMenu({nodeFrom: this.connecting_node, slotFrom: this.connecting_output, e: e});
}else if(this.connecting_input){
this.showConnectionMenu({nodeTo: this.connecting_node, slotTo: this.connecting_input, e: e});
if(firstLink.output){
this.showConnectionMenu({nodeFrom: firstLink.node, slotFrom: firstLink.output, e: e});
}else if(firstLink.input){
this.showConnectionMenu({nodeTo: firstLink.node, slotTo: firstLink.input, e: e});
}
}
}
}
this.connecting_output = null;
this.connecting_input = null;
this.connecting_pos = null;
this.connecting_node = null;
this.connecting_slot = -1;
this.connecting_links = null;
} //not dragging connection
else if (this.resizing_node) {
this.dirty_canvas = true;
@@ -7870,127 +7907,129 @@ LGraphNode.prototype.executeAction = function(action)
}
}
//current connection (the one being dragged by the mouse)
if (this.connecting_pos != null) {
ctx.lineWidth = this.connections_width;
var link_color = null;
var connInOrOut = this.connecting_output || this.connecting_input;
if (this.connecting_links) {
//current connection (the one being dragged by the mouse)
for (const link of this.connecting_links) {
ctx.lineWidth = this.connections_width;
var link_color = null;
var connInOrOut = link.output || link.input;
var connType = connInOrOut.type;
var connDir = connInOrOut.dir;
if(connDir == null)
{
if (this.connecting_output)
connDir = this.connecting_node.horizontal ? LiteGraph.DOWN : LiteGraph.RIGHT;
else
connDir = this.connecting_node.horizontal ? LiteGraph.UP : LiteGraph.LEFT;
}
var connShape = connInOrOut.shape;
switch (connType) {
case LiteGraph.EVENT:
link_color = LiteGraph.EVENT_LINK_COLOR;
break;
default:
link_color = LiteGraph.CONNECTING_LINK_COLOR;
}
var connType = connInOrOut.type;
var connDir = connInOrOut.dir;
if(connDir == null)
{
if (link.output)
connDir = link.node.horizontal ? LiteGraph.DOWN : LiteGraph.RIGHT;
else
connDir = link.node.horizontal ? LiteGraph.UP : LiteGraph.LEFT;
}
var connShape = connInOrOut.shape;
switch (connType) {
case LiteGraph.EVENT:
link_color = LiteGraph.EVENT_LINK_COLOR;
break;
default:
link_color = LiteGraph.CONNECTING_LINK_COLOR;
}
//the connection being dragged by the mouse
this.renderLink(
ctx,
this.connecting_pos,
[this.graph_mouse[0], this.graph_mouse[1]],
null,
false,
null,
link_color,
connDir,
LiteGraph.CENTER
);
//the connection being dragged by the mouse
this.renderLink(
ctx,
link.pos,
[this.graph_mouse[0], this.graph_mouse[1]],
null,
false,
null,
link_color,
connDir,
LiteGraph.CENTER
);
ctx.beginPath();
if (
connType === LiteGraph.EVENT ||
connShape === LiteGraph.BOX_SHAPE
) {
ctx.rect(
this.connecting_pos[0] - 6 + 0.5,
this.connecting_pos[1] - 5 + 0.5,
14,
10
);
ctx.fill();
ctx.beginPath();
ctx.rect(
this.graph_mouse[0] - 6 + 0.5,
this.graph_mouse[1] - 5 + 0.5,
14,
10
);
} else if (connShape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(this.connecting_pos[0] + 8, this.connecting_pos[1] + 0.5);
ctx.lineTo(this.connecting_pos[0] - 4, this.connecting_pos[1] + 6 + 0.5);
ctx.lineTo(this.connecting_pos[0] - 4, this.connecting_pos[1] - 6 + 0.5);
ctx.closePath();
}
else {
ctx.arc(
this.connecting_pos[0],
this.connecting_pos[1],
4,
0,
Math.PI * 2
);
ctx.fill();
ctx.beginPath();
ctx.arc(
this.graph_mouse[0],
this.graph_mouse[1],
4,
0,
Math.PI * 2
);
}
ctx.fill();
ctx.fillStyle = "#ffcc00";
if (this._highlight_input) {
ctx.beginPath();
var shape = this._highlight_input_slot.shape;
if (shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(this._highlight_input[0] + 8, this._highlight_input[1] + 0.5);
ctx.lineTo(this._highlight_input[0] - 4, this._highlight_input[1] + 6 + 0.5);
ctx.lineTo(this._highlight_input[0] - 4, this._highlight_input[1] - 6 + 0.5);
if (
connType === LiteGraph.EVENT ||
connShape === LiteGraph.BOX_SHAPE
) {
ctx.rect(
link.pos[0] - 6 + 0.5,
link.pos[1] - 5 + 0.5,
14,
10
);
ctx.fill();
ctx.beginPath();
ctx.rect(
this.graph_mouse[0] - 6 + 0.5,
this.graph_mouse[1] - 5 + 0.5,
14,
10
);
} else if (connShape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(link.pos[0] + 8, link.pos[1] + 0.5);
ctx.lineTo(link.pos[0] - 4, link.pos[1] + 6 + 0.5);
ctx.lineTo(link.pos[0] - 4, link.pos[1] - 6 + 0.5);
ctx.closePath();
} else {
}
else {
ctx.arc(
this._highlight_input[0],
this._highlight_input[1],
6,
link.pos[0],
link.pos[1],
4,
0,
Math.PI * 2
);
ctx.fill();
ctx.beginPath();
ctx.arc(
this.graph_mouse[0],
this.graph_mouse[1],
4,
0,
Math.PI * 2
);
}
ctx.fill();
}
if (this._highlight_output) {
ctx.beginPath();
if (shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(this._highlight_output[0] + 8, this._highlight_output[1] + 0.5);
ctx.lineTo(this._highlight_output[0] - 4, this._highlight_output[1] + 6 + 0.5);
ctx.lineTo(this._highlight_output[0] - 4, this._highlight_output[1] - 6 + 0.5);
ctx.closePath();
} else {
ctx.arc(
this._highlight_output[0],
this._highlight_output[1],
6,
0,
Math.PI * 2
);
ctx.fillStyle = "#ffcc00";
if (this._highlight_input) {
ctx.beginPath();
var shape = this._highlight_input_slot.shape;
if (shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(this._highlight_input[0] + 8, this._highlight_input[1] + 0.5);
ctx.lineTo(this._highlight_input[0] - 4, this._highlight_input[1] + 6 + 0.5);
ctx.lineTo(this._highlight_input[0] - 4, this._highlight_input[1] - 6 + 0.5);
ctx.closePath();
} else {
ctx.arc(
this._highlight_input[0],
this._highlight_input[1],
6,
0,
Math.PI * 2
);
}
ctx.fill();
}
if (this._highlight_output) {
ctx.beginPath();
if (shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(this._highlight_output[0] + 8, this._highlight_output[1] + 0.5);
ctx.lineTo(this._highlight_output[0] - 4, this._highlight_output[1] + 6 + 0.5);
ctx.lineTo(this._highlight_output[0] - 4, this._highlight_output[1] - 6 + 0.5);
ctx.closePath();
} else {
ctx.arc(
this._highlight_output[0],
this._highlight_output[1],
6,
0,
Math.PI * 2
);
}
ctx.fill();
}
ctx.fill();
}
}
@@ -8577,8 +8616,8 @@ LGraphNode.prototype.executeAction = function(action)
var render_text = !low_quality;
var out_slot = this.connecting_output;
var in_slot = this.connecting_input;
var out_slot = this.connecting_links ? this.connecting_links[0].output : null;
var in_slot = this.connecting_links ? this.connecting_links[0].input : null;
ctx.lineWidth = 1;
var max_y = 0;
@@ -8596,7 +8635,7 @@ LGraphNode.prototype.executeAction = function(action)
ctx.globalAlpha = editor_alpha;
//change opacity of incompatible slots when dragging a connection
if ( this.connecting_output && !LiteGraph.isValidConnection( slot.type , out_slot.type) ) {
if ( out_slot && !LiteGraph.isValidConnection( slot.type , out_slot.type) ) {
ctx.globalAlpha = 0.4 * editor_alpha;
}
@@ -8695,7 +8734,7 @@ LGraphNode.prototype.executeAction = function(action)
var slot_shape = slot.shape;
//change opacity of incompatible slots when dragging a connection
if (this.connecting_input && !LiteGraph.isValidConnection( slot_type , in_slot.type) ) {
if (in_slot && !LiteGraph.isValidConnection( slot_type , in_slot.type) ) {
ctx.globalAlpha = 0.4 * editor_alpha;
}