Home Reference Source

cables_dev/cables/src/core/core_link.js

  1. import { Events } from "cables-shared-client";
  2. import { Patch } from "./core_patch.js";
  3. import { Port } from "./core_port.js";
  4. /**
  5. * @namespace external:CABLES#Link
  6. * @description a link is a connection between two ops/ports -> one input and one output port
  7. * @hideconstructor
  8. * @class
  9. */
  10. export class Link extends Events
  11. {
  12. /**
  13. * @param {Patch} p
  14. */
  15. constructor(p)
  16. {
  17. super();
  18. this.id = CABLES.simpleId();
  19. /**
  20. * @type {Port}
  21. */
  22. this.portIn = null;
  23. /**
  24. * @type {Port}
  25. */
  26. this.portOut = null;
  27. /**
  28. * @type {Patch}
  29. */
  30. this._patch = p;
  31. this.activityCounter = 0;
  32. this.ignoreInSerialize = false;
  33. }
  34. /**
  35. * @param {any} v
  36. */
  37. setValue(v)
  38. {
  39. if (v === undefined) this._setValue();
  40. else this.portIn.set(v);
  41. }
  42. activity()
  43. {
  44. this.activityCounter++;
  45. }
  46. _setValue()
  47. {
  48. if (!this.portOut)
  49. {
  50. this.remove();
  51. return;
  52. }
  53. const v = this.portOut.get();
  54. if (v == v) // NaN is the only JavaScript value that is treated as unequal to itself
  55. {
  56. if (this.portIn.type != Port.TYPE_FUNCTION) this.activity();
  57. if (this.portIn.get() !== v)
  58. {
  59. this.portIn.set(v);
  60. }
  61. else
  62. {
  63. if (this.portIn.changeAlways) this.portIn.set(v);
  64. if (this.portOut.forceRefChange) this.portIn.forceChange();
  65. }
  66. }
  67. }
  68. /**
  69. * @function getOtherPort
  70. * @memberof Link
  71. * @instance
  72. * @param {Port} p port
  73. * @description returns the port of the link, which is not port
  74. */
  75. getOtherPort(p)
  76. {
  77. if (p == this.portIn) return this.portOut;
  78. return this.portIn;
  79. }
  80. /**
  81. * @function remove
  82. * @memberof Link
  83. * @instance
  84. * @description unlink/remove this link from all ports
  85. */
  86. remove()
  87. {
  88. if (this.portIn) this.portIn.removeLink(this);
  89. if (this.portOut) this.portOut.removeLink(this);
  90. if (this._patch)
  91. {
  92. this._patch.emitEvent("onUnLink", this.portIn, this.portOut, this);
  93. }
  94. if (this.portIn && (this.portIn.type == Port.TYPE_OBJECT || this.portIn.type == Port.TYPE_ARRAY))
  95. {
  96. this.portIn.set(null);
  97. if (this.portIn.links.length > 0) this.portIn.set(this.portIn.links[0].getOtherPort(this.portIn).get());
  98. }
  99. if (this.portIn) this.portIn.op._checkLinksNeededToWork();
  100. if (this.portOut) this.portOut.op._checkLinksNeededToWork();
  101. this.portIn = null;
  102. this.portOut = null;
  103. this._patch = null;
  104. }
  105. /**
  106. * @function link
  107. * @memberof Link
  108. * @instance
  109. * @description link those two ports
  110. * @param {Port} p1 port1
  111. * @param {Port} p2 port2
  112. */
  113. link(p1, p2)
  114. {
  115. if (!Link.canLink(p1, p2))
  116. {
  117. console.warn("[core_link] cannot link ports!", p1, p2);
  118. return false;
  119. }
  120. if (p1.direction == Port.DIR_IN)
  121. {
  122. this.portIn = p1;
  123. this.portOut = p2;
  124. }
  125. else
  126. {
  127. this.portIn = p2;
  128. this.portOut = p1;
  129. }
  130. p1.addLink(this);
  131. p2.addLink(this);
  132. this.setValue();
  133. p1.op._checkLinksNeededToWork();
  134. p2.op._checkLinksNeededToWork();
  135. }
  136. getSerialized()
  137. {
  138. const obj = {};
  139. obj.portIn = this.portIn.getName();
  140. obj.portOut = this.portOut.getName();
  141. obj.objIn = this.portIn.op.id;
  142. obj.objOut = this.portOut.op.id;
  143. return obj;
  144. }
  145. /**
  146. * return a text message with human readable reason if ports can not be linked, or can be
  147. *
  148. * @param {Port} p1 port1
  149. * @param {Port} p2 port2
  150. */
  151. static canLinkText(p1, p2)
  152. {
  153. if (p1.direction == p2.direction)
  154. {
  155. let txt = "(out)";
  156. if (p2.direction == Port.DIR_IN) txt = "(in)";
  157. return "can not link: same direction " + txt;
  158. }
  159. if (p1.op == p2.op) return "can not link: same op";
  160. if (p1.type != Port.TYPE_DYNAMIC && p2.type != Port.TYPE_DYNAMIC)
  161. {
  162. if (p1.type != p2.type) return "can not link: different type";
  163. }
  164. if (CABLES.UI && p1.type == Port.TYPE_OBJECT && p2.type == Port.TYPE_OBJECT)
  165. {
  166. if (p1.uiAttribs.objType && p2.uiAttribs.objType)
  167. if (p1.uiAttribs.objType != p2.uiAttribs.objType)
  168. return "incompatible objects";
  169. }
  170. if (!p1) return "can not link: port 1 invalid";
  171. if (!p2) return "can not link: port 2 invalid";
  172. if (p1.direction == Port.DIR_IN && p1.isAnimated()) return "can not link: is animated";
  173. if (p2.direction == Port.DIR_IN && p2.isAnimated()) return "can not link: is animated";
  174. if (p1.isLinkedTo(p2)) return "ports already linked";
  175. if ((p1.canLink && !p1.canLink(p2)) || (p2.canLink && !p2.canLink(p1))) return "Incompatible";
  176. return "can link";
  177. }
  178. /**
  179. * return true if ports can be linked
  180. *
  181. * @param {Port} p1 port1
  182. * @param {Port} p2 port2
  183. * @returns {Boolean}
  184. */
  185. static canLink(p1, p2)
  186. {
  187. if (!p1) return false;
  188. if (!p2) return false;
  189. if (p1.direction == Port.DIR_IN && p1.isAnimated()) return false;
  190. if (p2.direction == Port.DIR_IN && p2.isAnimated()) return false;
  191. if (p1.isHidden() || p2.isHidden()) return false;
  192. if (p1.isLinkedTo(p2)) return false;
  193. if (p1.direction == p2.direction) return false;
  194. if (CABLES.UI && p1.type == Port.TYPE_OBJECT && p2.type == Port.TYPE_OBJECT)
  195. {
  196. if (p1.uiAttribs.objType && p2.uiAttribs.objType)
  197. {
  198. if (p1.uiAttribs.objType.indexOf("sg_") == 0 && p2.uiAttribs.objType.indexOf("sg_") == 0) return true;
  199. if (p1.uiAttribs.objType != p2.uiAttribs.objType)
  200. return false;
  201. }
  202. }
  203. if (p1.type != p2.type && (p1.type != Port.TYPE_DYNAMIC && p2.type != Port.TYPE_DYNAMIC)) return false;
  204. if (p1.type == Port.TYPE_DYNAMIC || p2.type == Port.TYPE_DYNAMIC) return true;
  205. if (p1.op == p2.op) return false;
  206. if (p1.canLink && !p1.canLink(p2)) return false;
  207. if (p2.canLink && !p2.canLink(p1)) return false;
  208. return true;
  209. }
  210. }
  211. // --------------------------------------------