Home Reference Source

cables_dev/cables_ui/src/ui/components/opparampanel/op_parampanel.js

  1. import { Logger, ele, Events } from "cables-shared-client";
  2. import { Op, Port, utils } from "cables";
  3. import { getHandleBarHtml } from "../../utils/handlebars.js";
  4. import { GuiText } from "../../text.js";
  5. import { PortHtmlGenerator } from "./op_params_htmlgen.js";
  6. import ParamsListener from "./params_listener.js";
  7. import gluiconfig from "../../glpatch/gluiconfig.js";
  8. import { notify } from "../../elements/notification.js";
  9. import namespace from "../../namespaceutils.js";
  10. import Gui, { gui } from "../../gui.js";
  11. import { platform } from "../../platform.js";
  12. import { contextMenu } from "../../elements/contextmenu.js";
  13. import { userSettings } from "../usersettings.js";
  14. import { CmdOps } from "../../commands/cmd_op.js";
  15. import uiconfig from "../../uiconfig.js";
  16. import { UiOp } from "../../core_extend_op.js";
  17. /**
  18. * op parameter panel
  19. *
  20. * @class OpParampanel
  21. * @extends {Events}
  22. */
  23. class OpParampanel extends Events
  24. {
  25. /**
  26. * @param {string} eleid
  27. */
  28. constructor(eleid = null)
  29. {
  30. super();
  31. this.panelId = utils.simpleId();
  32. this._eleId = eleid;
  33. this._log = new Logger("OpParampanel");
  34. this._htmlGen = new PortHtmlGenerator(this.panelId);
  35. /** @type {Op} */
  36. this._currentOp = null;
  37. this._eventPrefix = utils.shortId();
  38. this._isPortLineDragDown = false;
  39. /** @type {Array<Port>} */
  40. this._portsIn = [];
  41. /** @type {Array<Port>} */
  42. this._portsOut = [];
  43. this._paramsListener = new ParamsListener(this.panelId);
  44. this._portUiAttrListeners = [];
  45. this._startedGlobalListeners = false;
  46. this.reloadListener = null;
  47. }
  48. get op()
  49. {
  50. return this._currentOp;
  51. }
  52. setParentElementId(eleid)
  53. {
  54. this._eleId = eleid;
  55. }
  56. dispose()
  57. {
  58. this._stopListeners();
  59. }
  60. clear()
  61. {
  62. this._stopListeners();
  63. this._currentOp = null;
  64. }
  65. refresh()
  66. {
  67. this.show(this._currentOp);
  68. }
  69. /**
  70. * @param {import("cables/src/core/core_patch.js").OpUiAttribs} attr
  71. */
  72. _onUiAttrChangeOp(attr)
  73. {
  74. if (attr.hasOwnProperty("uierrors")) this.updateUiErrors();
  75. }
  76. /**
  77. * @param {object} attr
  78. * @param {Port} port
  79. */
  80. _onUiAttrChangePort(attr, port)
  81. {
  82. if (!attr) return;
  83. if (attr.hasOwnProperty("greyout")) this.refreshDelayed();
  84. // todo: only update this part of the html
  85. if (attr.hasOwnProperty("hover"))
  86. {
  87. const portParamRow = ele.byClass("paramport_1_" + port.id);
  88. if (portParamRow)
  89. {
  90. if (attr.hover) portParamRow.classList.add("hoverPort");
  91. else portParamRow.classList.remove("hoverPort");
  92. }
  93. }
  94. }
  95. /**
  96. * @param {Op<any>} [op]
  97. */
  98. _stopListeners(op)
  99. {
  100. op = op || this._currentOp;
  101. if (!op) return;
  102. for (let i = 0; i < this._portUiAttrListeners.length; i++)
  103. {
  104. const listener = this._portUiAttrListeners[i];
  105. listener.port.off(listener.listenId);
  106. }
  107. this._portUiAttrListeners.length = 0;
  108. this.onOpUiAttrChange = op.off(this.onOpUiAttrChange);
  109. }
  110. /**
  111. * @param {Op<any>} op
  112. */
  113. _startListeners(op)
  114. {
  115. if (!op)
  116. {
  117. this._stopListeners();
  118. return;
  119. }
  120. if (!this.hasExposeListener)
  121. {
  122. this.hasExposeListener = gui.corePatch().on("subpatchExpose",
  123. (subpatchid) =>
  124. {
  125. if (
  126. op &&
  127. op.storage && op.storage.subPatchVer &&
  128. op.patchId.get() === subpatchid
  129. )
  130. {
  131. op.refreshParams();
  132. }
  133. });
  134. }
  135. this.onOpUiAttrChange = op.on(Op.EVENT_UIATTR_CHANGE, this._onUiAttrChangeOp.bind(this));
  136. for (let i = 0; i < this._portsIn.length; i++)
  137. {
  138. const listenId = this._portsIn[i].on(
  139. Port.EVENT_UIATTRCHANGE,
  140. this._onUiAttrChangePort.bind(this),
  141. this._eventPrefix);
  142. this._portUiAttrListeners.push({ "listenId": listenId, "port": this._portsIn[i] });
  143. }
  144. }
  145. refreshDelayed()
  146. {
  147. clearTimeout(this.refreshTimeout);
  148. this.refreshTimeout = setTimeout(() =>
  149. {
  150. this.show(this._currentOp);
  151. }, 50);
  152. }
  153. /**
  154. * @param {Port} port
  155. */
  156. _checkPortTypes(port)
  157. {
  158. if (port.type == Port.TYPE_NUMBER && typeof port.get() == "string")
  159. {
  160. this.op.setUiError("typeerr", "Wrong type! String in number " + port.name, 0);
  161. }
  162. }
  163. /**
  164. * @param {Op|String} op
  165. */
  166. show(op)
  167. {
  168. if (!gui.finishedLoading()) return;
  169. if (!this._startedGlobalListeners)
  170. {
  171. this._startedGlobalListeners = true;
  172. gui.corePatch().on("bookmarkschanged", () => { gui.bookmarks.needRefreshSubs = true; this._startedGlobalListeners = true; if (!this._currentOp) gui.patchParamPanel.show(true); });
  173. gui.corePatch().on("subpatchesChanged", () => { gui.bookmarks.needRefreshSubs = true; this._startedGlobalListeners = true; if (!this._currentOp) gui.patchParamPanel.show(true); });
  174. gui.corePatch().on("subpatchCreated", () => { gui.bookmarks.needRefreshSubs = true; this._startedGlobalListeners = true; if (!this._currentOp) gui.patchParamPanel.show(true); });
  175. gui.corePatch().on("patchLoadEnd", () => { gui.bookmarks.needRefreshSubs = true; this._startedGlobalListeners = true; if (!this._currentOp) gui.patchParamPanel.show(true); });
  176. }
  177. if (this.reloadListener)
  178. this.reloadListener = gui.corePatch().on("opReloaded", () =>
  179. {
  180. this.refreshDelayed();
  181. });
  182. const perf = gui.uiProfiler.start("[opparampanel] show");
  183. if (typeof op == "string") op = gui.corePatch().getOpById(op);
  184. if (!gui.showingtwoMetaPanel && gui.metaTabs.getActiveTab() && gui.metaTabs.getActiveTab().title != "op")
  185. gui.metaTabs.activateTabByName("op");
  186. if (this._currentOp) this._stopListeners();
  187. this._currentOp = op;
  188. if (!op) return;
  189. op.setUiError("typeerr", null);
  190. this._portsIn = op.portsIn;
  191. this._portsOut = op.portsOut;
  192. if (op.storage && op.storage.subPatchVer && op.patchId)
  193. {
  194. const ports = gui.patchView.getSubPatchExposedPorts(op.patchId.get());
  195. for (let i = 0; i < ports.length; i++)
  196. {
  197. if (ports[i].direction === Port.DIR_IN && this._portsIn.indexOf(ports[i]) == -1) this._portsIn.push(ports[i]);
  198. if (ports[i].direction === Port.DIR_OUT && this._portsOut.indexOf(ports[i]) == -1) this._portsOut.push(ports[i]);
  199. }
  200. }
  201. this._startListeners(this._currentOp);
  202. op.emitEvent("uiParamPanel", op);
  203. const perfHtml = gui.uiProfiler.start("[opparampanel] build html ");
  204. gui.opHistory.push(op.id);
  205. gui.setTransformGizmo(null);
  206. gui.emitEvent(Gui.EVENT_OP_SELECTIONCHANGED, op);
  207. this.emitEvent("opSelected", op);
  208. op.isServerOp = gui.serverOps.isServerOp(op.objName);
  209. /*
  210. * show first anim in timeline
  211. * if (self.timeLine)
  212. * {
  213. * let foundAnim = false;
  214. * for (let i = 0; i < this._portsIn.length; i++)
  215. * {
  216. * if (this._portsIn[i].isAnimated())
  217. * {
  218. * self.timeLine.setAnim(this._portsIn[i].anim, {
  219. * "name": this._portsIn[i].name,
  220. * });
  221. * foundAnim = true;
  222. * continue;
  223. * }
  224. * }
  225. * if (!foundAnim) self.timeLine.setAnim(null);
  226. * }
  227. */
  228. this._portsIn.sort(function (a, b) { return (a.uiAttribs.order || 0) - (b.uiAttribs.order || 0); });
  229. let html = this._htmlGen.getHtmlOpHeader(op);
  230. gui.showInfo(GuiText.patchSelectedOp);
  231. if (this._portsIn.length > 0)
  232. {
  233. const perfLoop = gui.uiProfiler.start("[opparampanel] _showOpParamsLOOP IN");
  234. html += this._htmlGen.getHtmlHeaderPorts("in", "Input");
  235. html += this._htmlGen.getHtmlInputPorts(this._portsIn);
  236. perfLoop.finish();
  237. }
  238. if (this._portsOut.length > 0)
  239. {
  240. html += this._htmlGen.getHtmlHeaderPorts("out", "Output");
  241. const perfLoopOut = gui.uiProfiler.start("[opparampanel] _showOpParamsLOOP OUT");
  242. html += this._htmlGen.getHtmlOutputPorts(this._portsOut);
  243. perfLoopOut.finish();
  244. }
  245. html += getHandleBarHtml("params_op_foot", { "commentColors": uiconfig.commentColors, "op": op, "showDevInfos": userSettings.get("devinfos") });
  246. const el = document.getElementById(this._eleId || gui.getParamPanelEleId());
  247. if (el) el.innerHTML = html;
  248. else return;
  249. this._paramsListener.init({ "op": op, "element": el });
  250. perfHtml.finish();
  251. this.updateUiAttribs();
  252. for (let i = 0; i < this._portsIn.length; i++)
  253. {
  254. this._checkPortTypes(this._portsIn[i]);
  255. if (this._portsIn[i].uiAttribs.display && this._portsIn[i].uiAttribs.display == "file")
  256. {
  257. let shortName = String(this._portsIn[i].get() || "Open Filemanager");
  258. if (shortName.indexOf("/") > -1) shortName = shortName.substr(shortName.lastIndexOf("/") + 1);
  259. if (op.getSubPatch())
  260. {
  261. const subouterOp = op.patch.getSubPatchOuterOp(op.getSubPatch());
  262. if (subouterOp)
  263. {
  264. const subOuterName = subouterOp.objName;
  265. if (!namespace.isPatchOp(subOuterName) &&
  266. this._portsIn[i].get() &&
  267. namespace.isCoreOp(subOuterName) &&
  268. namespace.isExtensionOp(subOuterName) &&
  269. String(this._portsIn[i].get()).startsWith("/assets/") &&
  270. !this._portsIn[i].isLinked())
  271. this._portsIn[i].op.setUiError("nonpatchopassets", "This Operator uses assets from a patch, this file will probably not be found when exporting the patch or using in standalone etc.!", 1);
  272. }
  273. }
  274. let eleOpen = ele.byId("portOpenAsset_" + i);
  275. let srcEle = ele.byId("portFilename_" + i + "_src");
  276. let buttonOpensFilemanager = true;
  277. if (srcEle)
  278. {
  279. let src = "";
  280. let fn = this._portsIn[i].get() || "";
  281. if (fn == "" || fn == 0)src = "";
  282. else if (!fn.startsWith("/")) src = "relative";
  283. if (fn.startsWith("/")) src = "abs";
  284. if (fn.startsWith("./")) src = "current dir";
  285. if (fn.startsWith("file:")) src = "file";
  286. if (fn.startsWith("data:")) src = "dataUrl";
  287. let openSrc = "";
  288. let openOnClick = "";
  289. if (fn.startsWith("http://") || fn.startsWith("https://"))
  290. {
  291. buttonOpensFilemanager = false;
  292. const parts = fn.split("/");
  293. if (parts && parts.length > 1) src = "ext: " + parts[2];
  294. openSrc = fn;
  295. }
  296. if ((fn.startsWith("file:") || fn.startsWith("/") || fn.startsWith("./")) && platform.isElectron())
  297. {
  298. openOnClick = "CABLES.CMD.ELECTRON.openFileManager('" + fn + "')";
  299. }
  300. if (fn.startsWith("/assets/" + gui.project()._id)) src = "this patch";
  301. if (fn.startsWith("/assets/") && !fn.startsWith("/assets/" + gui.project()._id))
  302. {
  303. const parts = fn.split("/");
  304. if (parts && parts.length > 1)
  305. {
  306. src = "<a target=\"_blank\" class=\"link\" href=\"" + platform.getCablesUrl() + "/edit/" + parts[2] + "\">other patch</a>";
  307. src += " <a target=\"_blank\" class=\"button-small\" id=\"copyToPatch" + i + "\">copy</a>";
  308. }
  309. }
  310. if (fn.startsWith("/assets/"))
  311. openSrc = platform.getCablesUrl() + "/asset/patches/?filename=" + fn;
  312. if (fn.startsWith("/assets/library/")) src = "lib";
  313. if (src != "") src = "[ " + src + " ]";
  314. if (eleOpen)
  315. {
  316. if (openOnClick) eleOpen.setAttribute("onclick", openOnClick);
  317. if (openSrc) eleOpen.setAttribute("href", openSrc);
  318. if (!openOnClick && !openSrc) eleOpen.remove();
  319. }
  320. srcEle.innerHTML = src;
  321. ele.clickable(ele.byId("copyToPatch" + i), () =>
  322. {
  323. gui.getFileManager(null, true).copyFileToPatch(fn);
  324. });
  325. }
  326. const filenameButton = ele.byId("portFilename_" + i);
  327. if (filenameButton)
  328. {
  329. filenameButton.innerHTML = "<span class=\"button-small tt\" data-tt=\"" + this._portsIn[i].get() + "\" style=\"text-transform:none;\"><span style=\"pointer-events:none;\" class=\"icon icon-file\"></span>" + shortName + "</span>";
  330. filenameButton.addEventListener("pointerdown", () =>
  331. {
  332. if (buttonOpensFilemanager)
  333. {
  334. // open filemananger
  335. ele.byId("portFilename_" + i + "_src").innerHTML = "";
  336. ele.byId("fileInputContainer_" + i).classList.remove("hidden");
  337. filenameButton.classList.add("hidden");
  338. CABLES.platform.showFileSelect(".portFileVal_" + i, this._portsIn[i].uiAttribs.filter || null, op.id, "portFileVal_" + i + "_preview");
  339. }
  340. else
  341. {
  342. // edit url
  343. ele.byId("portFilenameButton_" + i).classList.toggle("hidden");
  344. ele.byId("fileInputContainer_" + i).classList.toggle("hidden");
  345. }
  346. });
  347. }
  348. else
  349. {
  350. // no filenamebutton, probably because port is linked...
  351. }
  352. }
  353. const f = (e) =>
  354. {
  355. if (!this._isPortLineDragDown) return;
  356. if (gui.patchView._patchRenderer.getOp)
  357. {
  358. const glOp = gui.patchView._patchRenderer.getOp(op.id);
  359. if (glOp && this._portsIn[i])
  360. {
  361. const glPort = glOp.getGlPort(this._portsIn[i].name);
  362. if (this._portsIn[i].name == this._portLineDraggedName)
  363. gui.patchView._patchRenderer.emitEvent("mouseDownOverPort", glPort, glOp.id, this._portsIn[i].name, e);
  364. }
  365. }
  366. };
  367. document.getElementById("portLineTitle_in_" + i).addEventListener("pointerup", () => { this._isPortLineDragDown = false; this._portLineDraggedName = null; }, { "passive": false });
  368. document.getElementById("portLineTitle_in_" + i).addEventListener("pointerdown", (e) => { this._isPortLineDragDown = true; this._portLineDraggedName = e.target.dataset.portname; }, { "passive": false });
  369. if (document.getElementById("patchviews")) document.getElementById("patchviews").addEventListener("pointerenter", f);
  370. }
  371. for (const ipo in this._portsOut)
  372. {
  373. this._checkPortTypes(this._portsOut[ipo]);
  374. this._showOpParamsCbPortDelete(ipo, op);
  375. (function (index)
  376. {
  377. const elem = ele.byId("portTitle_out_" + index);
  378. if (elem)elem.addEventListener("click", (e) =>
  379. {
  380. const p = this._portsOut[index];
  381. if (!p.uiAttribs.hidePort)
  382. gui.opSelect().show({ "x": p.parent.uiAttribs.translate.x + index * (gluiconfig.portWidth + gluiconfig.portPadding), "y": p.op.uiAttribs.translate.y + 50 }, op, p);
  383. }, { "passive": false });
  384. else this._log.warn("ele not found: portTitle_out_" + index);
  385. }.bind(this)(ipo));
  386. document.getElementById("portLineTitle_out_" + ipo).addEventListener("pointerup", () => { this._isPortLineDragDown = false; this._portLineDraggedName = null; }, { "passive": false });
  387. document.getElementById("portLineTitle_out_" + ipo).addEventListener("pointerdown", (e) => { this._isPortLineDragDown = true; this._portLineDraggedName = e.target.dataset.portname; }, { "passive": false });
  388. if (document.getElementById("patchviews")) document.getElementById("patchviews").addEventListener("pointerenter", (e) =>
  389. {
  390. if (!this._isPortLineDragDown) return;
  391. if (gui.patchView._patchRenderer.getOp)
  392. {
  393. const glOp = gui.patchView._patchRenderer.getOp(op.id);
  394. if (glOp && this._portsOut[ipo])
  395. {
  396. const glPort = glOp.getGlPort(this._portsOut[ipo].name);
  397. if (this._portsOut[ipo].name == this._portLineDraggedName)
  398. gui.patchView._patchRenderer.emitEvent("mouseDownOverPort", glPort, glOp.id, this._portsOut[ipo].name, e);
  399. }
  400. }
  401. }, { "passive": false });
  402. }
  403. ele.clickable(ele.byId("parampanel_manage_op"), () => { CABLES.CMD.OP.manageOp(op.opId); });
  404. ele.clickable(ele.byId("parampanel_edit_op"), CABLES.CMD.OP.editOp);
  405. ele.clickable(ele.byId("watchOpSerialized"), CABLES.CMD.DEBUG.watchOpSerialized);
  406. ele.clickable(ele.byId("watchOpUiAttribs"), CABLES.CMD.DEBUG.watchOpUiAttribs);
  407. ele.clickable(ele.byId("watchOpDocsJson"), CABLES.CMD.DEBUG.watchOpDocsJson);
  408. ele.forEachClass("portCopyClipboard", (ell) =>
  409. {
  410. ell.addEventListener("click", (e) =>
  411. {
  412. if (!navigator.clipboard) return;
  413. const cop = gui.corePatch().getOpById(e.target.dataset.opid);
  414. const port = cop.getPortByName(e.target.dataset.portname);
  415. navigator.clipboard
  416. .writeText(String(port.get()))
  417. .then(() =>
  418. {
  419. notify("Copied value to clipboard");
  420. })
  421. .catch((err) =>
  422. {
  423. this._log.warn("copy to clipboard failed", err);
  424. });
  425. e.preventDefault();
  426. }, { "passive": false });
  427. });
  428. if (gui.serverOps.opIdsChangedOnServer[op.opId])
  429. {
  430. ele.clickable(ele.byId("parampanel_loadchangedop_" + op.opId), () =>
  431. {
  432. gui.serverOps.execute(op.opId, () =>
  433. {
  434. delete gui.serverOps.opIdsChangedOnServer[op.opId];
  435. this.refresh();
  436. });
  437. });
  438. }
  439. perf.finish();
  440. }
  441. updateUiErrors()
  442. {
  443. if (!this._currentOp) return;
  444. const el = document.getElementById("op_params_uierrors");
  445. if (!this._currentOp.uiAttribs.uierrors || this._currentOp.uiAttribs.uierrors.length == 0)
  446. {
  447. if (el)el.innerHTML = "";
  448. return;
  449. }
  450. else
  451. if (document.getElementsByClassName("warning-error") != this._currentOp.uiAttribs.uierrors.length)
  452. {
  453. if (el) el.innerHTML = "";
  454. }
  455. if (!el)
  456. {
  457. this._log.warn("no uiErrors html ele?!");
  458. }
  459. else
  460. {
  461. for (let i = 0; i < this._currentOp.uiAttribs.uierrors.length; i++)
  462. {
  463. const err = this._currentOp.uiAttribs.uierrors[i];
  464. let div = document.getElementById("uierror_" + err.id);
  465. let str = "";
  466. if (err.level == 0) str += "<b>Hint: </b>";
  467. if (err.level == 1) str += "<b>Warning: </b>";
  468. if (err.level == 2) str += "<b>Error: </b>";
  469. if (err.level == 3) str += "<b>Not working: </b>";
  470. str += err.txt;
  471. if (err.options)
  472. {
  473. if (err.options.button)
  474. str += "&nbsp;<a class=\"button-small\" id=\"err_button_" + err.id + "\">" + err.options.button + "</a>";
  475. }
  476. if (!div)
  477. {
  478. div = document.createElement("div");
  479. div.id = "uierror_" + err.id;
  480. div.classList.add("warning-error");
  481. if (utils.isNumeric(err.level))
  482. div.classList.add("warning-error-level" + err.level);
  483. else
  484. {
  485. console.error("err level not numeric", err.level);
  486. console.log((new Error().stack));
  487. }
  488. el.appendChild(div);
  489. }
  490. div.innerHTML = str;
  491. }
  492. gui.patchView.checkPatchErrors();
  493. }
  494. for (let i = 0; i < this._currentOp.uiAttribs.uierrors.length; i++)
  495. {
  496. if (this._currentOp.uiAttribs.uierrors[i].options.button)
  497. ele.clickable(ele.byId("err_button_" + this._currentOp.uiAttribs.uierrors[i].id), () =>
  498. {
  499. if (this._currentOp.uiAttribs.uierrors[i].options.buttonCb) this._currentOp.uiAttribs.uierrors[i].options.buttonCb();
  500. else this._log.log("uierror button has no callback");
  501. });
  502. }
  503. }
  504. updateUiAttribs()
  505. {
  506. if (gui.patchView.isPasting) return;
  507. if (!this._currentOp) return;
  508. this._uiAttrFpsLast = this._uiAttrFpsLast || performance.now();
  509. this._uiAttrFpsCount++;
  510. if (performance.now() - this._uiAttrFpsLast > 1000)
  511. {
  512. this._uiAttrFpsLast = performance.now();
  513. if (this._uiAttrFpsCount >= 10) this._log.log("many ui attr updates! ", this._uiAttrFpsCount, this._currentOp.name);
  514. this._uiAttrFpsCount = 0;
  515. }
  516. const perf = gui.uiProfiler.start("[opparampanel] updateUiAttribs");
  517. let el = null;
  518. el = document.getElementById("options_warning");
  519. if (el)
  520. {
  521. if (!this._currentOp.uiAttribs.warning || this._currentOp.uiAttribs.warning.length === 0) el.style.display = "none";
  522. else
  523. {
  524. el.style.display = "block";
  525. if (el) el.innerHTML = this._currentOp.uiAttribs.warning;
  526. }
  527. }
  528. el = document.getElementById("options_hint");
  529. if (el)
  530. {
  531. if (!this._currentOp.uiAttribs.hint || this._currentOp.uiAttribs.hint.length === 0) el.style.display = "none";
  532. else
  533. {
  534. el.style.display = "block";
  535. if (el) el.innerHTML = this._currentOp.uiAttribs.hint;
  536. }
  537. }
  538. el = document.getElementById("options_error");
  539. if (el)
  540. {
  541. if (!this._currentOp.uiAttribs.error || this._currentOp.uiAttribs.error.length === 0) el.style.display = "none";
  542. else
  543. {
  544. el.style.display = "block";
  545. if (el) el.innerHTML = this._currentOp.uiAttribs.error;
  546. }
  547. }
  548. el = document.getElementById("options_info");
  549. if (el)
  550. {
  551. if (!this._currentOp.uiAttribs.info) el.style.display = "none";
  552. else
  553. {
  554. el.style.display = "block";
  555. el.innerHTML = "<div class=\"panelhead\">info</div><div class=\"panel\">" + this._currentOp.uiAttribs.info + "</div>";
  556. }
  557. }
  558. this.updateUiErrors();
  559. perf.finish();
  560. }
  561. _showOpParamsCbPortDelete(index, op)
  562. {
  563. const el = ele.byId("portdelete_out_" + index);
  564. if (el)el.addEventListener("click", (e) =>
  565. {
  566. this._portsOut[index].removeLinks();
  567. this.show(op);
  568. });
  569. }
  570. setCurrentOpTags(t)
  571. {
  572. if (this._currentOp)
  573. {
  574. console.log(t.split(","));
  575. this._currentOp.tags = t.split(",");
  576. }
  577. else
  578. {
  579. this._log.warn("no current op tags");
  580. }
  581. }
  582. setCurrentOpComment(v)
  583. {
  584. if (this._currentOp)
  585. {
  586. this._currentOp.uiAttr({ "comment": v });
  587. if (v.length == 0) this._currentOp.uiAttr({ "comment": null });
  588. this._currentOp.patch.emitEvent("commentChanged");
  589. // gui.setStateUnsaved({ "op": this._currentOp });
  590. gui.savedState.setUnSaved("op comment", this._currentOp.uiAttribs.subPatch);
  591. }
  592. else
  593. {
  594. this._log.warn("no current op comment");
  595. }
  596. }
  597. setCurrentOpTitle(t)
  598. {
  599. if (this._currentOp) this._currentOp.setTitle(t);
  600. if (this._currentOp && this._currentOp.storage && this._currentOp.storage.subPatchVer)
  601. this._currentOp.patch.emitEvent("subpatchesChanged");
  602. }
  603. isCurrentOp(op)
  604. {
  605. return this._currentOp == op;
  606. }
  607. isCurrentOpId(opid)
  608. {
  609. if (!this._currentOp) return false;
  610. return this._currentOp.id == opid;
  611. }
  612. // OLD SUBPATCH LIST!!!!!! REMOVE
  613. subPatchContextMenu(el)
  614. {
  615. const outer = gui.patchView.getSubPatchOuterOp(el.dataset.id);
  616. const items = [];
  617. if (outer && outer.storage && outer.storage.blueprint)
  618. {
  619. items.push({
  620. "title": "Goto Blueprint Op",
  621. "func": function ()
  622. {
  623. // gui.patchView.focusSubpatchOp(el.dataset.id);
  624. }
  625. });
  626. items.push({
  627. "title": "Update Blueprint",
  628. "func": function ()
  629. {
  630. const bp = gui.patchView.getBlueprintOpFromBlueprintSubpatchId(el.dataset.id);
  631. if (bp) gui.patchView.updateBlueprints([bp]);
  632. }
  633. });
  634. items.push({
  635. "title": "Open Patch",
  636. "iconClass": "icon icon-external",
  637. "func": function ()
  638. {
  639. const url = platform.getCablesUrl() + "/edit/" + outer.storage.blueprint.patchId;
  640. window.open(url, "_blank");
  641. }
  642. });
  643. }
  644. else
  645. {
  646. items.push({
  647. "title": "Rename",
  648. "func": function ()
  649. {
  650. gui.patchView.focusSubpatchOp(el.dataset.id);
  651. CABLES.CMD.PATCH.setOpTitle();
  652. }
  653. });
  654. items.push({
  655. "title": "Goto Subpatch Op",
  656. "func": function ()
  657. {
  658. gui.patchView.focusSubpatchOp(el.dataset.id);
  659. }
  660. });
  661. if (el.dataset.subpatchver == "2" && el.dataset.blueprintver != 2)
  662. items.push({
  663. "title": "Create op from subpatch",
  664. "func": function ()
  665. {
  666. gui.serverOps.createBlueprint2Op(el.dataset.id);
  667. // gui.patchView.focusSubpatchOp(el.dataset.id);
  668. }
  669. });
  670. if (el.dataset.blueprintver == 2)
  671. {
  672. items.push({
  673. "title": "Save Blueprint Op",
  674. "func": function ()
  675. {
  676. const op = gui.patchView.getSubPatchOuterOp(el.dataset.id);
  677. gui.serverOps.updateSubPatchOpAttachment(op, { "oldSubId": el.dataset.id });
  678. // gui.patchView.focusSubpatchOp(el.dataset.id);
  679. }
  680. });
  681. }
  682. }
  683. contextMenu.show({ "items": items }, el);
  684. }
  685. /**
  686. * @param {HTMLElement} el
  687. */
  688. opContextMenu(el)
  689. {
  690. const items = [];
  691. const opname = this._currentOp.objName;
  692. const opid = this._currentOp.id;
  693. items.push({
  694. "title": "Set title",
  695. "func": CABLES.CMD.PATCH.setOpTitle
  696. });
  697. items.push({
  698. "title": "Set default values",
  699. "func": function ()
  700. {
  701. gui.patchView.resetOpValues(opid);
  702. }
  703. });
  704. items.push({
  705. "title": "Bookmark",
  706. "func": function ()
  707. {
  708. gui.bookmarks.add();
  709. }
  710. });
  711. items.push({
  712. "title": "Manage Op Code",
  713. "func": function ()
  714. {
  715. CmdOps.manageOp();
  716. }
  717. });
  718. items.push({
  719. "title": "Clone Op",
  720. "func": function ()
  721. {
  722. CmdOps.cloneSelectedOp();
  723. }
  724. });
  725. contextMenu.show({ "items": items }, el);
  726. }
  727. getCurrentOp()
  728. {
  729. return this._currentOp;
  730. }
  731. hidePorts(arr)
  732. {
  733. // console.log("arrrrrr", arr);
  734. // for (let i = 0; i < arr.length; i++)
  735. // {
  736. // const p = this.op.getPort(arr[i]);
  737. // p.setUiAttribs({ "hidePort": true });
  738. // }
  739. }
  740. }
  741. export default OpParampanel;