Home Reference Source

cables_dev/cables/src/core/core_link.js

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