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