cables_dev/cables/src/core/core_port_multi.js
import { CONSTANTS } from "./constants.js";
import { Port } from "./core_port.js";
const MIN_NUM_PORTS = 2;
class MultiPort extends Port
{
constructor(__parent, name, type, dir, uiAttribs, uiAttribsPorts)
{
super(__parent, name, CONSTANTS.OP.OP_PORT_TYPE_ARRAY, uiAttribs);
this.setUiAttribs({ "multiPort": true, "group": this.name, "order": -1 });
this.ports = [];
this.direction = dir;
this._uiAttribsPorts = uiAttribsPorts;
// console.log("uiattribs", uiAttribs);
const updateArray = () =>
{
const arr = [];
let ll = 1;
if (this.uiAttribs.multiPortManual)ll = 0;
for (let i = 0; i < this.ports.length - ll; i++)
arr[i] = this.ports[i];
this.setRef(arr);
};
const updateUi = () =>
{
let grey = !this.uiAttribs.multiPortManual || undefined;
if (this.direction == CONSTANTS.PORT.PORT_DIR_OUT)grey = false;
for (let i = 0; i < this.ports.length; i++)
{
let lp; // undefined to remove/not set it
// let opacity;// undefined to remove/not set it
// let grey;// undefined to remove/not set it
let addPort = false;
let title;
let o = {};
// console.log("this.op.preservedPortTitles", this.op.preservedPortTitles, this.op.preservedPortTitles[po.name], po.name);
if (this.op.preservedPortTitles && this.op.preservedPortTitles[this.ports[i].name]) title = this.op.preservedPortTitles[this.ports[i].name];
// if (!this.uiAttribs.multiPortManual)grey = true;
if (i == 0) lp = this.ports.length;
if (!this.uiAttribs.multiPortManual)
if (i == this.ports.length - 1)
{
title = "add port";
addPort = true;
grey = true;
}
for (const attin in this._uiAttribsPorts)
{
o[attin] = this._uiAttribsPorts[attin];
}
o.addPort = addPort;
o.longPort = lp;
o.title = title;
o.greyout = grey;
o.group = this.name;
this.ports[i].setUiAttribs(o);
}
};
this.removeInvalidPorts = () =>
{
for (let i = 0; i < this.ports.length; i++)
{
if (!this.ports[i]) this.ports.splice(i, 1);
}
if (!this.uiAttribs.multiPortManual)
{
if (this.ports.length > MIN_NUM_PORTS)
for (let i = this.ports.length - 1; i > 1; i--)
{
if (!this.ports[i].isLinked()) this.uiAttribs.multiPortNum = i;
else break;
}
}
updateArray();
};
this.countPorts = () =>
{
if (CABLES.UI && !gui.isRemoteClient && gui.patchView && gui.patchView.patchRenderer && gui.patchView.patchRenderer.isDraggingPort())
{
clearTimeout(this.retryTo);
this.retryTo = setTimeout(this.countPorts.bind(this));
return;
}
this.retryTo = null;
let redo = false;
this.removeListeners();
this.removeInvalidPorts();
for (let i = 0; i < this.ports.length; i++)
{
if (this.ports[i] && this.ports[i].links.length > 1)
{
const po = this.ports[i + 1];
const otherPort = this.ports[i].links[0].getOtherPort(this.ports[i]);
if (!po || !otherPort)
{
this._log.warn("no port found?");
}
else
{
this.ports[i].links[0].remove();
this.op.patch.link(this.op, po.name, otherPort.op, otherPort.name);
redo = true;
}
break;
}
}
if (!this.uiAttribs.multiPortManual)
{
let foundHole = true;
while (foundHole)
{
// console.log("search holes...");
foundHole = false;
for (let i = this.ports.length - 1; i > 1; i--)
{
if (this.ports[i] && this.ports[i].links.length > 0 && this.ports[i - 1].links.length == 0)
{
// console.log("found hole!");
// found hole
const otherPort = this.ports[i].links[0].getOtherPort(this.ports[i]);
this.ports[i].links[0].remove();
const po = this.ports[i - 1];
if (po && this.ports[i])
{
// console.log("move ", this.ports[i].name, "to", po.name);
this.op.patch.link(this.op, po.name, otherPort.op, otherPort.name);
foundHole = true;
redo = true;
break;
}
}
}
// this.checkNum();
}
// this.removeInvalidPorts();
}
if (!this.uiAttribs.multiPortManual) // if auto
{
while (this.ports.length > MIN_NUM_PORTS && !this.ports[this.ports.length - 1].isLinked() && !this.ports[this.ports.length - 2].isLinked())
{
let i = this.ports.length - 1;
if (!this.ports[i].isLinked() && this.ports[i - 1] && !this.ports[i - 1].isLinked())
{
this.ports[i].setUiAttribs({ "removed": true });
this.ports[i].remove();
// this.ports[i] = null;
this.ports.splice(i, 1);
}
}
}
this.removeInvalidPorts();
if (!this.uiAttribs.multiPortManual && this.ports.length > 0 && this.ports[this.ports.length - 1].isLinked()) this.newPort();
updateArray();
updateUi();
if (redo) this.countPorts();
else this.addListeners();
};
this.removeListeners = () =>
{
for (let i = 0; i < this.ports.length; i++)
{
const po = this.ports[i];
po.multiPortChangeListener = po.off(po.multiPortChangeListener);
po.multiLinkChangeListener = po.off(po.multiLinkChangeListener);
}
};
this.addListeners = () =>
{
for (let i = 0; i < this.ports.length; i++)
{
const po = this.ports[i];
const idx = i;
if (po.multiPortChangeListener)po.multiPortChangeListener = po.off(po.multiPortChangeListener);
po.multiPortChangeListener = po.on("change", updateArray.bind(this));
if (po.multiPortTriggerListener)po.multiPortTriggerListener = po.off(po.multiPortTriggerListener);
po.multiPortTriggerListener = po.on("trigger", () => { this._onTriggered(idx); });
// if (po.multiPortTriggerListener)po.multiPortTriggerListener = po.off(po.multiPortTriggerListener);
// po.multiPortTriggerListener = po.on("trigger", this.trigger());
if (po.multiLinkChangeListener)po.multiLinkChangeListener = po.off(po.multiLinkChangeListener);
po.multiLinkChangeListener = po.on("onLinkChanged", () =>
{
this.countPorts();
this.emitEvent("onLinkChanged");
});
if (po.multiLinkRemoveListener)po.multiLinkRemoveListener = po.off(po.multiLinkRemoveListener);
po.multiLinkRemoveListener = po.on("onLinkRemoved", () =>
{
// this.removeInvalidPorts();
// this.checkNum();
// this.countPorts();
updateUi();
this.emitEvent("onLinkChanged");
// this.countPorts.bind(this);
});
}
};
this.newPort = () =>
{
const attrs = {};
// if (type == CABLES.OP_PORT_TYPE_STRING) attrs.type = "string";
attrs.type = type;
const po = new Port(this.op, name + "_" + this.ports.length, type, attrs);
po.direction = dir;
this.ports.push(po);
// console.log("CONSTANTS.PORT_DIR_OUT", CONSTANTS.PORT.PORT_DIR_OUT, this.direction);
if (this.direction == CONSTANTS.PORT.PORT_DIR_OUT) this.op.addOutPort(po);
else this.op.addInPort(po);
if (type == CONSTANTS.OP.OP_PORT_TYPE_NUMBER) po.setInitialValue(0);
else if (type == CONSTANTS.OP.OP_PORT_TYPE_STRING) po.setInitialValue("");
this.addListeners();
updateUi();
updateArray();
this.emitEvent("onLinkChanged");
// console.log("this.op.preservedPortTitles", this.op.preservedPortTitles, this.op.preservedPortTitles[po.name], po.name);
if (this.op.preservedPortTitles && this.op.preservedPortTitles[po.name]) po.setUiAttribs({ "title": this.op.preservedPortTitles[po.name] });
return po;
};
this.initPorts = () =>
{
for (let i = 0; i < MIN_NUM_PORTS; i++) this.newPort();
updateArray();
updateUi();
};
this.checkNum = () =>
{
this.uiAttribs.multiPortNum = Math.max(MIN_NUM_PORTS, this.uiAttribs.multiPortNum);
while (this.ports.length < this.uiAttribs.multiPortNum) this.newPort();
while (this.ports.length > this.uiAttribs.multiPortNum) if (this.ports[this.ports.length - 1]) this.ports.pop().remove();
this.removeInvalidPorts();
};
this.incDec = (incDir) =>
{
this.uiAttribs.multiPortNum = this.uiAttribs.multiPortNum || MIN_NUM_PORTS;
// console.log("this.uiAttribs.multiPortNum", this.uiAttribs.multiPortNum, this.uiAttribs.multiPortNum + incDir);
this.setUiAttribs({ "multiPortNum": this.uiAttribs.multiPortNum + incDir });
this.checkNum();
updateUi();
};
this.toggleManual = () =>
{
this.setUiAttribs({ "multiPortManual": !this.uiAttribs.multiPortManual });
this.op.refreshParams();
};
this.on("onUiAttrChange", (attribs) =>
{
if (attribs.hasOwnProperty("multiPortManual"))
{
updateUi();
this.removeInvalidPorts();
this.checkNum();
this.countPorts();
updateUi();
}
});
this.on("onUiAttrChange", this.checkNum.bind(this));
this.checkNum();
this.countPorts();
this.removeInvalidPorts();
updateUi();
}
}
export { MultiPort };