mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-01-27 23:00:20 +08:00
Allow reroute to have in/out in different orientation
This commit is contained in:
parent
ebd7f9bf80
commit
d8c8bd1603
@ -2,6 +2,42 @@ import { app } from "../../scripts/app.js";
|
|||||||
|
|
||||||
// Node that allows you to redirect connections for cleaner graphs
|
// Node that allows you to redirect connections for cleaner graphs
|
||||||
|
|
||||||
|
// Context menu to change input/output orientation
|
||||||
|
function getOrientationMenu(value, options, e, menu, node) {
|
||||||
|
const isInput = value.options.isInput
|
||||||
|
const takenSlot = (isInput ? node.outputs[0].dir:node.inputs[0].dir) -1
|
||||||
|
|
||||||
|
let availableDir = ["Up" ,"Down", "Left", "Right"]
|
||||||
|
let availableValue = [LiteGraph.UP, LiteGraph.DOWN, LiteGraph.LEFT, LiteGraph.RIGHT]
|
||||||
|
|
||||||
|
availableDir.splice(takenSlot, 1);
|
||||||
|
availableValue.splice(takenSlot, 1);
|
||||||
|
|
||||||
|
new LiteGraph.ContextMenu(
|
||||||
|
availableDir,
|
||||||
|
{
|
||||||
|
event: e,
|
||||||
|
parentMenu: menu,
|
||||||
|
node: node,
|
||||||
|
callback: (v, options, mouse_event, menu, node) => {
|
||||||
|
if (!node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dir = availableValue[Object.values(availableDir).indexOf(v)];
|
||||||
|
|
||||||
|
if (isInput) {
|
||||||
|
node.inputs[0].dir = dir;
|
||||||
|
} else {
|
||||||
|
node.outputs[0].dir = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.applyOrientation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
app.registerExtension({
|
app.registerExtension({
|
||||||
name: "Comfy.RerouteNode",
|
name: "Comfy.RerouteNode",
|
||||||
registerCustomNodes() {
|
registerCustomNodes() {
|
||||||
@ -11,10 +47,49 @@ app.registerExtension({
|
|||||||
this.properties = {};
|
this.properties = {};
|
||||||
}
|
}
|
||||||
this.properties.showOutputText = RerouteNode.defaultVisibility;
|
this.properties.showOutputText = RerouteNode.defaultVisibility;
|
||||||
this.properties.horizontal = false;
|
|
||||||
|
|
||||||
this.addInput("", "*");
|
this.addInput("", "*", {nameLocked: true});
|
||||||
this.addOutput(this.properties.showOutputText ? "*" : "", "*");
|
this.addOutput(this.properties.showOutputText ? "*" : "", "*", {nameLocked: true});
|
||||||
|
|
||||||
|
this.inputs[0].dir = LiteGraph.LEFT;
|
||||||
|
this.outputs[0].dir = LiteGraph.RIGHT;
|
||||||
|
|
||||||
|
this.onResize = function(_) {
|
||||||
|
this.applyOrientation();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onDrawForeground = function(ctx, graphcanvas, canvas) {
|
||||||
|
if (this.properties.showOutputText && graphcanvas.ds.scale > 0.5) {
|
||||||
|
ctx.fillStyle = LiteGraph.NODE_TEXT_COLOR;
|
||||||
|
ctx.font = graphcanvas.inner_text_font;
|
||||||
|
ctx.textAlign = "center";
|
||||||
|
|
||||||
|
ctx.fillText(this.getDisplayName(), this.size[0] / 2, this.size[1] / 2+5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onConfigure = function(data) {
|
||||||
|
|
||||||
|
// update old reroute
|
||||||
|
if (!this.inputs[0].dir) { this.inputs[0].dir = LiteGraph.LEFT; }
|
||||||
|
if (!this.outputs[0].dir) { this.outputs[0].dir = LiteGraph.RIGHT; }
|
||||||
|
|
||||||
|
if (this.inputs[0].label) { this.inputs[0].label = "" }
|
||||||
|
if (this.outputs[0].label) { this.outputs[0].label = "" }
|
||||||
|
|
||||||
|
if (!this.inputs[0].nameLocked) { this.inputs[0].nameLocked = true }
|
||||||
|
if (!this.outputs[0].nameLocked) { this.outputs[0].nameLocked = true }
|
||||||
|
|
||||||
|
// handle old horizontal property
|
||||||
|
if (this.properties.horizontal) {
|
||||||
|
this.inputs[0].dir = LiteGraph.UP;
|
||||||
|
this.outputs[0].dir = LiteGraph.DOWN;
|
||||||
|
delete this.properties.horizontal;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.applyOrientation();
|
||||||
|
app.graph.setDirtyCanvas(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
this.onConnectionsChange = function (type, index, connected, link_info) {
|
this.onConnectionsChange = function (type, index, connected, link_info) {
|
||||||
this.applyOrientation();
|
this.applyOrientation();
|
||||||
@ -113,7 +188,6 @@ app.registerExtension({
|
|||||||
// This lets you change the output link to a different type and all nodes will update
|
// This lets you change the output link to a different type and all nodes will update
|
||||||
node.outputs[0].type = inputType || "*";
|
node.outputs[0].type = inputType || "*";
|
||||||
node.__outputType = displayType;
|
node.__outputType = displayType;
|
||||||
node.outputs[0].name = node.properties.showOutputText ? displayType : "";
|
|
||||||
node.size = node.computeSize();
|
node.size = node.computeSize();
|
||||||
node.applyOrientation();
|
node.applyOrientation();
|
||||||
|
|
||||||
@ -135,14 +209,18 @@ app.registerExtension({
|
|||||||
|
|
||||||
this.clone = function () {
|
this.clone = function () {
|
||||||
const cloned = RerouteNode.prototype.clone.apply(this);
|
const cloned = RerouteNode.prototype.clone.apply(this);
|
||||||
|
let dir = this.outputs[0].dir
|
||||||
cloned.removeOutput(0);
|
cloned.removeOutput(0);
|
||||||
cloned.addOutput(this.properties.showOutputText ? "*" : "", "*");
|
cloned.addOutput(this.properties.showOutputText ? "*" : "", "*", {nameLocked: true});
|
||||||
|
cloned.outputs[0].dir = dir
|
||||||
cloned.size = cloned.computeSize();
|
cloned.size = cloned.computeSize();
|
||||||
return cloned;
|
return cloned;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This node is purely frontend and does not impact the resulting prompt so should not be serialized
|
// This node is purely frontend and does not impact the resulting prompt so should not be serialized
|
||||||
this.isVirtualNode = true;
|
this.isVirtualNode = true;
|
||||||
|
|
||||||
|
this.applyOrientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
getExtraMenuOptions(_, options) {
|
getExtraMenuOptions(_, options) {
|
||||||
@ -151,11 +229,6 @@ app.registerExtension({
|
|||||||
content: (this.properties.showOutputText ? "Hide" : "Show") + " Type",
|
content: (this.properties.showOutputText ? "Hide" : "Show") + " Type",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
this.properties.showOutputText = !this.properties.showOutputText;
|
this.properties.showOutputText = !this.properties.showOutputText;
|
||||||
if (this.properties.showOutputText) {
|
|
||||||
this.outputs[0].name = this.__outputType || this.outputs[0].type;
|
|
||||||
} else {
|
|
||||||
this.outputs[0].name = "";
|
|
||||||
}
|
|
||||||
this.size = this.computeSize();
|
this.size = this.computeSize();
|
||||||
this.applyOrientation();
|
this.applyOrientation();
|
||||||
app.graph.setDirtyCanvas(true, true);
|
app.graph.setDirtyCanvas(true, true);
|
||||||
@ -168,37 +241,55 @@ app.registerExtension({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// naming is inverted with respect to LiteGraphNode.horizontal
|
content: "Input Orientation",
|
||||||
// LiteGraphNode.horizontal == true means that
|
has_submenu: true,
|
||||||
// each slot in the inputs and outputs are layed out horizontally,
|
options: {isInput: true},
|
||||||
// which is the opposite of the visual orientation of the inputs and outputs as a node
|
callback: getOrientationMenu
|
||||||
content: "Set " + (this.properties.horizontal ? "Horizontal" : "Vertical"),
|
},
|
||||||
callback: () => {
|
{
|
||||||
this.properties.horizontal = !this.properties.horizontal;
|
content: "Output Orientation",
|
||||||
this.applyOrientation();
|
has_submenu: true,
|
||||||
|
options: {isInput: false},
|
||||||
|
callback: getOrientationMenu
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyOrientation() {
|
applyOrientation() {
|
||||||
this.horizontal = this.properties.horizontal;
|
// Place inputs/outputs based on the direction
|
||||||
if (this.horizontal) {
|
function processInOut(node, slot) {
|
||||||
// we correct the input position, because LiteGraphNode.horizontal
|
if (!slot) { return; } // weird copy/paste fix
|
||||||
// doesn't account for title presence
|
|
||||||
// which reroute nodes don't have
|
const horizontal = ([LiteGraph.UP, LiteGraph.DOWN].indexOf(slot.dir) > -1);
|
||||||
this.inputs[0].pos = [this.size[0] / 2, 0];
|
const reversed = ([LiteGraph.DOWN, LiteGraph.RIGHT].indexOf(slot.dir) > -1);
|
||||||
|
|
||||||
|
if (horizontal) {
|
||||||
|
slot.pos = [node.size[0] / 2, reversed ? node.size[1]:0];
|
||||||
} else {
|
} else {
|
||||||
delete this.inputs[0].pos;
|
slot.pos = [reversed ? node.size[0]:0, node.size[1] / 2];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processInOut(this, this.inputs[0]);
|
||||||
|
processInOut(this, this.outputs[0]);
|
||||||
|
|
||||||
app.graph.setDirtyCanvas(true, true);
|
app.graph.setDirtyCanvas(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDisplayName() {
|
||||||
|
let displayName = this.__outputType;
|
||||||
|
if (this.title !== "Reroute" && this.title !== "") {
|
||||||
|
displayName = this.title;
|
||||||
|
}
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
computeSize() {
|
computeSize() {
|
||||||
return [
|
return [
|
||||||
this.properties.showOutputText && this.outputs && this.outputs.length
|
this.properties.showOutputText && this.outputs
|
||||||
? Math.max(75, LiteGraph.NODE_TEXT_SIZE * this.outputs[0].name.length * 0.6 + 40)
|
? Math.max(75, LiteGraph.NODE_TEXT_SIZE * this.getDisplayName().length * 0.6)
|
||||||
: 75,
|
: 75,
|
||||||
26,
|
25,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,4 +317,29 @@ app.registerExtension({
|
|||||||
|
|
||||||
RerouteNode.category = "utils";
|
RerouteNode.category = "utils";
|
||||||
},
|
},
|
||||||
|
setup(app) {
|
||||||
|
|
||||||
|
// adds "Add reroute" to right click canvas menu
|
||||||
|
const orig = LGraphCanvas.prototype.getCanvasMenuOptions;
|
||||||
|
LGraphCanvas.prototype.getCanvasMenuOptions = function () {
|
||||||
|
const options = orig.apply(this, arguments);
|
||||||
|
options.push(
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
content: "Add Reroute",
|
||||||
|
callback: (value, options, mouse_event, menu, node) => {
|
||||||
|
let newNode = LiteGraph.createNode("Reroute")
|
||||||
|
|
||||||
|
newNode.pos = app.canvas.convertEventToCanvasOffset(mouse_event);
|
||||||
|
newNode.pos[0] -= newNode.size[0]/2;
|
||||||
|
newNode.pos[1] -= newNode.size[1]/2;
|
||||||
|
|
||||||
|
app.graph.add(newNode);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return options;
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user