You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

521 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCETICE project - Copyright 2009 by Lucio Asnaghi.
  4. JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions"
  5. Copyright 2007 by Julian Storer.
  6. ------------------------------------------------------------------------------
  7. JUCE and JUCETICE can be redistributed and/or modified under the terms of
  8. the GNU General Public License, as published by the Free Software Foundation;
  9. either version 2 of the License, or (at your option) any later version.
  10. JUCE and JUCETICE are distributed in the hope that they will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to
  16. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  17. Boston, MA 02111-1307 USA
  18. ==============================================================================
  19. */
  20. BEGIN_JUCE_NAMESPACE
  21. #include "jucetice_GraphLinkComponent.h"
  22. //==============================================================================
  23. GraphNodeComponent::GraphNodeComponent ()
  24. : listener (0),
  25. userData (0),
  26. uniqueID (0),
  27. nodeColour (Colours::grey),
  28. leftToRight (true),
  29. hasBeenLocked (false),
  30. originalX (0),
  31. originalY (0),
  32. lastX (0),
  33. lastY (0)/*,
  34. dropShadower (0.5f, 0, 1, 2.0f)*/
  35. {
  36. setBufferedToImage (false);
  37. setOpaque (true);
  38. toFront (true);
  39. constrainer.setMinimumOnscreenAmounts (9999,9999,9999,9999);
  40. //dropShadower.setOwner (this);
  41. }
  42. GraphNodeComponent::~GraphNodeComponent()
  43. {
  44. }
  45. //==============================================================================
  46. void GraphNodeComponent::moved()
  47. {
  48. updateConnectors();
  49. // update last position
  50. lastX = getX ();
  51. lastY = getY ();
  52. }
  53. void GraphNodeComponent::resized()
  54. {
  55. updateConnectors();
  56. }
  57. void GraphNodeComponent::mouseDoubleClick (const MouseEvent& e)
  58. {
  59. // notify listener
  60. if (listener)
  61. listener->nodeDoubleClicked (this, e);
  62. }
  63. void GraphNodeComponent::mouseDown (const MouseEvent& e)
  64. {
  65. if (listener)
  66. listener->nodeSelected (this);
  67. if (e.mods.isRightButtonDown())
  68. {
  69. if (listener)
  70. listener->nodePopupMenuSelected (this);
  71. }
  72. else if (e.mods.isLeftButtonDown())
  73. {
  74. if (! hasBeenLocked)
  75. {
  76. originalX = getX();
  77. originalY = getY();
  78. }
  79. }
  80. }
  81. void GraphNodeComponent::mouseDrag (const MouseEvent& e)
  82. {
  83. if (! hasBeenLocked && e.mods.isLeftButtonDown())
  84. {
  85. int x = originalX + e.getDistanceFromDragStartX();
  86. int y = originalY + e.getDistanceFromDragStartY();
  87. int w = getWidth();
  88. int h = getHeight();
  89. const Component* const parentComp = getParentComponent();
  90. Rectangle<int> limits;
  91. limits.setSize (parentComp->getWidth(), parentComp->getHeight());
  92. Rectangle<int> bounds (x, y, w, h);
  93. constrainer.checkBounds (bounds,
  94. getBounds(), limits,
  95. false, false, false, false);
  96. if (listener)
  97. listener->nodeMoved (this, x - lastX, y - lastY);
  98. constrainer.applyBoundsToComponent (*this, bounds);
  99. }
  100. }
  101. //==============================================================================
  102. void GraphNodeComponent::paint (Graphics& g)
  103. {
  104. if (listener)
  105. listener->nodePaint (this, g);
  106. }
  107. //==============================================================================
  108. void GraphNodeComponent::addInputConnector (const int connectorType)
  109. {
  110. GraphConnectorComponentInput* connector =
  111. new GraphConnectorComponentInput (this, connectorType);
  112. connector->setConnectorID (graphInputs.size());
  113. getParentComponent()->addAndMakeVisible (connector);
  114. graphInputs.add (connector);
  115. updateConnectors();
  116. }
  117. void GraphNodeComponent::addOutputConnector (const int connectorType)
  118. {
  119. GraphConnectorComponentOutput* connector =
  120. new GraphConnectorComponentOutput (this, connectorType);
  121. connector->setConnectorID (graphOutputs.size());
  122. getParentComponent()->addAndMakeVisible (connector);
  123. graphOutputs.add (connector);
  124. updateConnectors();
  125. }
  126. //==============================================================================
  127. GraphConnectorComponentInput* GraphNodeComponent::getInputConnector (const int connectorID)
  128. {
  129. for (int i = 0; i < graphInputs.size(); i++)
  130. {
  131. GraphConnectorComponentInput* input = graphInputs.getUnchecked (i);
  132. if (input && (input->getConnectorID() == connectorID))
  133. {
  134. return input;
  135. }
  136. }
  137. return 0;
  138. }
  139. GraphConnectorComponentOutput* GraphNodeComponent::getOutputConnector (const int connectorID)
  140. {
  141. for (int i = 0; i < graphOutputs.size(); i++)
  142. {
  143. GraphConnectorComponentOutput* output = graphOutputs.getUnchecked (i);
  144. if (output && (output->getConnectorID() == connectorID))
  145. {
  146. return output;
  147. }
  148. }
  149. return 0;
  150. }
  151. //==============================================================================
  152. int GraphNodeComponent::getFirstInputOfType (const int connectorType)
  153. {
  154. for (int i = 0; i < graphInputs.size(); i++)
  155. {
  156. GraphConnectorComponentInput* input = graphInputs.getUnchecked (i);
  157. if (input && (input->getType() == connectorType))
  158. {
  159. return i;
  160. }
  161. }
  162. return -1;
  163. }
  164. int GraphNodeComponent::getFirstOutputOfType (const int connectorType)
  165. {
  166. for (int i = 0; i < graphOutputs.size(); i++)
  167. {
  168. GraphConnectorComponentOutput* output = graphOutputs.getUnchecked (i);
  169. if (output && (output->getType() == connectorType))
  170. {
  171. return i;
  172. }
  173. }
  174. return -1;
  175. }
  176. //==============================================================================
  177. int GraphNodeComponent::getInputLinksCount () const
  178. {
  179. int linksCount = 0;
  180. Array<GraphConnectorComponent*> links;
  181. for (int i = 0; i < graphInputs.size(); i++)
  182. {
  183. graphInputs.getUnchecked (i)->getLinkedConnectors (links);
  184. linksCount += links.size ();
  185. }
  186. return linksCount;
  187. }
  188. int GraphNodeComponent::getOutputLinksCount () const
  189. {
  190. int linksCount = 0;
  191. Array<GraphConnectorComponent*> links;
  192. for (int i = 0; i < graphOutputs.size(); i++)
  193. {
  194. graphOutputs.getUnchecked (i)->getLinkedConnectors (links);
  195. linksCount += links.size ();
  196. }
  197. return linksCount;
  198. }
  199. //==============================================================================
  200. void GraphNodeComponent::deleteConnectors (const bool freeConnectors)
  201. {
  202. breakAllLinks (false);
  203. if (freeConnectors) {
  204. for (int i = 0; i < graphInputs.size(); i++)
  205. delete graphInputs.getUnchecked (i);
  206. }
  207. if (freeConnectors) {
  208. for (int i = 0; i < graphOutputs.size(); i++)
  209. delete graphOutputs.getUnchecked (i);
  210. }
  211. graphInputs.clear ();
  212. graphOutputs.clear ();
  213. }
  214. //==============================================================================
  215. void GraphNodeComponent::breakAllLinks (const bool notifyListeners)
  216. {
  217. for (int i = 0; i < graphInputs.size(); i++)
  218. graphInputs.getUnchecked (i)->destroyAllLinks (notifyListeners);
  219. for (int i = 0; i < graphOutputs.size(); i++)
  220. graphOutputs.getUnchecked (i)->destroyAllLinks (notifyListeners);
  221. if (notifyListeners)
  222. notifyGraphChanged ();
  223. }
  224. void GraphNodeComponent::breakInputLinks (const bool notifyListeners)
  225. {
  226. for (int i = 0; i < graphInputs.size(); i++)
  227. graphInputs.getUnchecked (i)->destroyAllLinks (notifyListeners);
  228. if (notifyListeners)
  229. notifyGraphChanged ();
  230. }
  231. void GraphNodeComponent::breakOutputLinks (const bool notifyListeners)
  232. {
  233. for (int i = 0; i < graphOutputs.size(); i++)
  234. graphOutputs.getUnchecked (i)->destroyAllLinks (notifyListeners);
  235. if (notifyListeners)
  236. notifyGraphChanged ();
  237. }
  238. //==============================================================================
  239. void GraphNodeComponent::setNodeListener (GraphNodeListener* const listener_)
  240. {
  241. listener = listener_;
  242. }
  243. void GraphNodeComponent::notifyConnectorPopupMenuSelected (GraphConnectorComponent* changedConnector)
  244. {
  245. if (listener)
  246. listener->connectorPopupMenuSelected (changedConnector);
  247. }
  248. void GraphNodeComponent::notifyLinkPopupMenuSelected (GraphLinkComponent* changedLink)
  249. {
  250. if (listener)
  251. listener->linkPopupMenuSelected (changedLink);
  252. }
  253. void GraphNodeComponent::notifyLinkConnected (GraphLinkComponent* changedLink)
  254. {
  255. if (listener)
  256. listener->linkConnected (changedLink);
  257. }
  258. void GraphNodeComponent::notifyLinkDisconnected (GraphLinkComponent* changedLink)
  259. {
  260. if (listener)
  261. listener->linkDisconnected (changedLink);
  262. }
  263. void GraphNodeComponent::notifyGraphChanged ()
  264. {
  265. if (listener)
  266. listener->graphChanged ();
  267. }
  268. Colour GraphNodeComponent::getConnectorColour (GraphConnectorComponent* connector,
  269. const bool isSelected)
  270. {
  271. if (listener)
  272. return listener->getConnectorColour (connector, isSelected);
  273. return Colours::black;
  274. }
  275. //==============================================================================
  276. bool GraphNodeComponent::connectToNode (const int sourcePort,
  277. GraphNodeComponent* destinationNode,
  278. const int destinationPort,
  279. const bool notifyListeners)
  280. {
  281. GraphConnectorComponentOutput* out = getOutputConnector (sourcePort);
  282. GraphConnectorComponentInput* in = destinationNode->getInputConnector (destinationPort);
  283. if (out != 0 && in != 0)
  284. {
  285. GraphLinkComponent* newLink = new GraphLinkComponent (leftToRight);
  286. newLink->from = out;
  287. if (in->canConnectFrom (newLink))
  288. {
  289. int startX = out->getBounds ().getCentreX ();
  290. int startY = out->getBounds ().getCentreY ();
  291. int endX = in->getBounds ().getCentreX ();
  292. int endY = in->getBounds ().getCentreY ();
  293. newLink->setStartPoint (startX, startY);
  294. newLink->setEndPoint (endX, endY);
  295. if (in->connectFrom (newLink))
  296. {
  297. out->addLink (newLink);
  298. if (notifyListeners)
  299. notifyGraphChanged ();
  300. getParentComponent()->addAndMakeVisible (newLink);
  301. newLink->toBack ();
  302. newLink->repaint();
  303. return true;
  304. }
  305. }
  306. deleteAndZero (newLink);
  307. }
  308. return false;
  309. }
  310. //==============================================================================
  311. bool GraphNodeComponent::isAfterNode (GraphNodeComponent* nodeBefore)
  312. {
  313. bool findConnector = false;
  314. for (int j = getInputConnectorCount (); --j >= 0;)
  315. {
  316. GraphConnectorComponent* connector = getInputConnector (j);
  317. if (connector)
  318. {
  319. Array <GraphConnectorComponent*> linked;
  320. connector->getLinkedConnectors (linked);
  321. for (int c = linked.size (); --c >= 0;)
  322. {
  323. GraphConnectorComponent* other = linked.getUnchecked (c);
  324. if (other)
  325. {
  326. if (other->getParentGraphComponent() == nodeBefore)
  327. {
  328. return true;
  329. }
  330. else
  331. {
  332. findConnector = other->getParentGraphComponent()->isAfterNode (nodeBefore);
  333. }
  334. }
  335. if (findConnector)
  336. return true;
  337. }
  338. }
  339. }
  340. return findConnector;
  341. }
  342. bool GraphNodeComponent::isBeforeNode (GraphNodeComponent* nodeAfter)
  343. {
  344. bool findConnector = false;
  345. for (int j = getOutputConnectorCount (); --j >= 0;)
  346. {
  347. GraphConnectorComponent* connector = getOutputConnector (j);
  348. if (connector)
  349. {
  350. Array <GraphConnectorComponent*> linked;
  351. connector->getLinkedConnectors (linked);
  352. for (int c = linked.size (); --c >= 0;)
  353. {
  354. GraphConnectorComponent* other = linked.getUnchecked (c);
  355. if (other)
  356. {
  357. if (other->getParentGraphComponent() == nodeAfter)
  358. {
  359. return true;
  360. }
  361. else
  362. {
  363. findConnector = other->getParentGraphComponent()->isBeforeNode (nodeAfter);
  364. }
  365. }
  366. if (findConnector)
  367. return true;
  368. }
  369. }
  370. }
  371. return findConnector;
  372. }
  373. //==============================================================================
  374. void GraphNodeComponent::updateConnectors()
  375. {
  376. float x_pos, y_pos, y_pos_step;
  377. float height, width;
  378. if (leftToRight)
  379. {
  380. height = (float) getHeight();
  381. width = (float) getWidth();
  382. }
  383. else
  384. {
  385. width = (float) getHeight();
  386. height = (float) getWidth();
  387. }
  388. if (graphInputs.size() > 0)
  389. {
  390. y_pos_step = height / (float) graphInputs.size();
  391. x_pos = 0.0;
  392. y_pos = (height / 2) - (((float)y_pos_step * ((float) graphInputs.size() - 1.0f)) / 2.0f);
  393. for (int i = 0; i < graphInputs.size(); i++)
  394. {
  395. if (leftToRight)
  396. graphInputs[i]->setRelativePosition ((int) (x_pos - graphInputs[i]->getWidth()),
  397. (int) (y_pos - graphInputs[i]->getWidth() / 2));
  398. else
  399. graphInputs[i]->setRelativePosition ((int) (y_pos - graphInputs[i]->getWidth() / 2),
  400. (int) (x_pos - graphInputs[i]->getWidth()));
  401. y_pos += y_pos_step;
  402. }
  403. }
  404. if (graphOutputs.size() > 0)
  405. {
  406. y_pos_step = height / (float) graphOutputs.size();
  407. x_pos = width;
  408. y_pos = (height / 2) - (((float)y_pos_step * ((float) graphOutputs.size() - 1.0f)) / 2.0f);
  409. for(int i = 0; i < graphOutputs.size(); i++)
  410. {
  411. if (leftToRight)
  412. graphOutputs[i]->setRelativePosition ((int) (x_pos),
  413. (int) (y_pos - graphOutputs[i]->getWidth() / 2));
  414. else
  415. graphOutputs[i]->setRelativePosition ((int) (y_pos - graphOutputs[i]->getWidth() / 2),
  416. (int) (x_pos));
  417. y_pos += y_pos_step;
  418. }
  419. }
  420. }
  421. END_JUCE_NAMESPACE