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.

492 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. #include "jucetice_GraphNodeComponent.h"
  23. //==============================================================================
  24. GraphConnectorComponent::GraphConnectorComponent (GraphNodeComponent* parentGraph_,
  25. const int connectorType_)
  26. : parentGraph (parentGraph_),
  27. relativePositionX (0),
  28. relativePositionY (0),
  29. newLink (0),
  30. currentlyDraggingOver (0),
  31. connectorID (0),
  32. connectorType (connectorType_),
  33. connectionDraggedOver (false)
  34. {
  35. leftToRight = parentGraph->isLeftToRight ();
  36. setSize (16, 16);
  37. updatePosition();
  38. setRepaintsOnMouseActivity (true);
  39. }
  40. GraphConnectorComponent::~GraphConnectorComponent()
  41. {
  42. }
  43. //==============================================================================
  44. void GraphConnectorComponent::paint (Graphics& g)
  45. {
  46. #if 0
  47. if (isMouseOverOrDragging() || connectionDraggedOver)
  48. {
  49. g.fillAll (parentGraph->getConnectorColour (this, true));
  50. }
  51. else
  52. {
  53. g.fillAll (parentGraph->getConnectorColour (this, false));
  54. }
  55. #endif
  56. const float w = (float) getWidth();
  57. const float h = (float) getHeight();
  58. if (isMouseOverOrDragging() || connectionDraggedOver)
  59. g.setColour (parentGraph->getConnectorColour (this, true));
  60. else
  61. g.setColour (parentGraph->getConnectorColour (this, false));
  62. Path p;
  63. if (leftToRight)
  64. {
  65. p.addEllipse (w * 0.25f, h * 0.25f, w * 0.5f, h * 0.5f);
  66. p.addRectangle (isInput() ? (0.5f * w) : 0.0f, h * 0.4f, w * 0.5f, h * 0.2f);
  67. }
  68. else
  69. {
  70. p.addEllipse (w * 0.25f, h * 0.25f, w * 0.5f, h * 0.5f);
  71. p.addRectangle (w * 0.4f, isInput() ? (0.5f * h) : 0.0f, w * 0.2f, h * 0.5f);
  72. }
  73. g.fillPath (p);
  74. }
  75. //==============================================================================
  76. void GraphConnectorComponent::mouseDown (const MouseEvent& e)
  77. {
  78. if (e.mods.isRightButtonDown())
  79. {
  80. if (parentGraph)
  81. parentGraph->notifyConnectorPopupMenuSelected (this);
  82. }
  83. }
  84. //==============================================================================
  85. void GraphConnectorComponent::connectionDragEnter()
  86. {
  87. connectionDraggedOver = true;
  88. repaint();
  89. }
  90. //==============================================================================
  91. void GraphConnectorComponent::connectionDragExit()
  92. {
  93. connectionDraggedOver = false;
  94. repaint();
  95. }
  96. //==============================================================================
  97. void GraphConnectorComponent::setRelativePosition (const int x, const int y)
  98. {
  99. relativePositionX = x;
  100. relativePositionY = y;
  101. updatePosition();
  102. }
  103. //==============================================================================
  104. void GraphConnectorComponent::updatePosition()
  105. {
  106. int x = parentGraph->getX() + relativePositionX;
  107. int y = parentGraph->getY() + relativePositionY;
  108. setBounds (x, y, getWidth(), getHeight());
  109. }
  110. //==============================================================================
  111. void GraphConnectorComponent::addLink (GraphLinkComponent* newLink)
  112. {
  113. links.add (newLink);
  114. if (parentGraph)
  115. parentGraph->notifyLinkConnected (newLink);
  116. }
  117. //==============================================================================
  118. void GraphConnectorComponent::removeLink (GraphLinkComponent* linkToDelete)
  119. {
  120. links.removeObject (linkToDelete);
  121. }
  122. //==============================================================================
  123. void GraphConnectorComponent::removeLinkWith (GraphConnectorComponent* connector, const bool notifyListeners)
  124. {
  125. DBG ("START >>> GraphConnectorComponent::removeLinkWith (GraphConnectorComponent* connector)");
  126. for (int i = 0; i < links.size (); i++)
  127. {
  128. if( links[i]->from == connector || links[i]->to == connector )
  129. {
  130. if (notifyListeners && parentGraph)
  131. parentGraph->notifyLinkDisconnected (links[i]);
  132. break;
  133. }
  134. }
  135. DBG ("END >>> GraphConnectorComponent::removeLinkWith (GraphConnectorComponent* connector)");
  136. }
  137. //==============================================================================
  138. void GraphConnectorComponent::removeLinkWith (GraphNodeComponent* node, const bool notifyListeners)
  139. {
  140. DBG ("START >>> GraphConnectorComponent::removeLinkWith (GraphNodeComponent* node)");
  141. for (int i = 0; i < links.size (); i++)
  142. {
  143. if ((links[i]->from && links[i]->from->getParentGraphComponent () == node)
  144. || (links[i]->to && links[i]->to->getParentGraphComponent () == node))
  145. {
  146. if (notifyListeners && parentGraph)
  147. parentGraph->notifyLinkDisconnected (links[i]);
  148. break;
  149. }
  150. }
  151. DBG ("END >>> GraphConnectorComponent::removeLinkWith (GraphNodeComponent* node)");
  152. }
  153. //==============================================================================
  154. void GraphConnectorComponent::destroyAllLinks (const bool notifyListeners)
  155. {
  156. for (int i = 0; i < links.size (); i++)
  157. {
  158. if (notifyListeners && parentGraph)
  159. parentGraph->notifyLinkDisconnected (links[i]);
  160. }
  161. }
  162. //==============================================================================
  163. bool GraphConnectorComponent::connectFrom (GraphLinkComponent* link)
  164. {
  165. if (canConnectFrom (link))
  166. {
  167. link->to = this;
  168. addLink (link);
  169. return true;
  170. }
  171. return false;
  172. }
  173. //==============================================================================
  174. bool GraphConnectorComponent::connectTo (GraphLinkComponent* link)
  175. {
  176. if (canConnectTo (link))
  177. {
  178. link->from = this;
  179. addLink (link);
  180. return true;
  181. }
  182. return false;
  183. }
  184. //==============================================================================
  185. void GraphConnectorComponent::notifyGraphChanged()
  186. {
  187. if (parentGraph)
  188. parentGraph->notifyGraphChanged ();
  189. }
  190. //==============================================================================
  191. GraphConnectorComponentInput::GraphConnectorComponentInput (GraphNodeComponent* parentGraph_,
  192. const int connectorType_)
  193. : GraphConnectorComponent (parentGraph_, connectorType_)
  194. {
  195. }
  196. void GraphConnectorComponentInput::updatePosition()
  197. {
  198. GraphConnectorComponent::updatePosition();
  199. int centre_x = getBounds ().getCentreX ();
  200. int centre_y = getBounds ().getCentreY ();
  201. // update links start points
  202. for (int i = 0; i < links.size (); i++)
  203. {
  204. links[i]->setEndPoint (centre_x, centre_y);
  205. }
  206. }
  207. bool GraphConnectorComponentInput::canConnectFrom (GraphLinkComponent* link)
  208. {
  209. // TODO - what if already connected ?
  210. bool alreadyConnected = false;
  211. Array<GraphConnectorComponent*> linked;
  212. getLinkedConnectors (linked);
  213. for (int i = 0; i < linked.size (); i++)
  214. {
  215. if (link && linked.getUnchecked (i) == link->from)
  216. {
  217. alreadyConnected = true;
  218. break;
  219. }
  220. }
  221. return link->from
  222. && (link->from->getType () == getType ())
  223. && (! alreadyConnected)
  224. && (! parentGraph->isBeforeNode (link->from->getParentGraphComponent ()));
  225. }
  226. void GraphConnectorComponentInput::getLinkedConnectors (Array<GraphConnectorComponent*>& linked)
  227. {
  228. for (int i = 0; i < links.size (); i++)
  229. {
  230. linked.add (links[i]->from);
  231. }
  232. }
  233. void GraphConnectorComponentInput::mouseDrag (const MouseEvent& e)
  234. {
  235. if (e.mods.isLeftButtonDown())
  236. {
  237. if (! newLink)
  238. {
  239. newLink = new GraphLinkComponent (leftToRight);
  240. newLink->to = this;
  241. getParentComponent()->addAndMakeVisible (newLink);
  242. int centre_x = getBounds ().getCentreX ();
  243. int centre_y = getBounds ().getCentreY ();
  244. newLink->setInterceptsMouseClicks (false, false);
  245. newLink->setEndPoint (centre_x, centre_y);
  246. newLink->toBack ();
  247. }
  248. if (newLink)
  249. {
  250. newLink->setStartPoint (getX() + e.x, getY() + e.y);
  251. Component* hitComponent = getParentComponent()->getComponentAt (getX() + e.x, getY() + e.y);
  252. GraphConnectorComponent* connector = dynamic_cast<GraphConnectorComponentOutput*> (hitComponent);
  253. if (connector != currentlyDraggingOver)
  254. {
  255. if (currentlyDraggingOver != 0)
  256. currentlyDraggingOver->connectionDragExit();
  257. currentlyDraggingOver = connector;
  258. if (connector
  259. && connector->getParentGraphComponent () != parentGraph
  260. && connector->canConnectTo (newLink))
  261. {
  262. currentlyDraggingOver->connectionDragEnter();
  263. }
  264. }
  265. }
  266. }
  267. }
  268. void GraphConnectorComponentInput::mouseUp (const MouseEvent& e)
  269. {
  270. if (newLink)
  271. {
  272. if (currentlyDraggingOver != 0)
  273. {
  274. currentlyDraggingOver->connectionDragExit();
  275. currentlyDraggingOver = 0;
  276. }
  277. Component* hitComponent = getParentComponent()->getComponentAt (getX() + e.x, getY() + e.y);
  278. GraphConnectorComponent* connector = dynamic_cast<GraphConnectorComponentOutput*> (hitComponent);
  279. if (connector)
  280. {
  281. if (connector->getParentGraphComponent () != parentGraph
  282. && connector->connectTo (newLink))
  283. {
  284. newLink->setStartPoint (connector->getX() + connector->getWidth() / 2,
  285. connector->getY() + connector->getHeight() / 2);
  286. addLink (newLink);
  287. notifyGraphChanged ();
  288. newLink->setInterceptsMouseClicks (true, false);
  289. newLink->repaint();
  290. newLink = 0;
  291. return;
  292. }
  293. }
  294. deleteAndZero (newLink);
  295. }
  296. }
  297. //==============================================================================
  298. GraphConnectorComponentOutput::GraphConnectorComponentOutput (GraphNodeComponent* parentGraph_,
  299. const int connectorType_)
  300. : GraphConnectorComponent (parentGraph_, connectorType_)
  301. {
  302. }
  303. void GraphConnectorComponentOutput::updatePosition()
  304. {
  305. GraphConnectorComponent::updatePosition();
  306. int centre_x = getBounds ().getCentreX ();
  307. int centre_y = getBounds ().getCentreY ();
  308. //update links end points
  309. for (int i = 0; i < links.size (); i++)
  310. {
  311. links[i]->setStartPoint (centre_x, centre_y);
  312. }
  313. }
  314. bool GraphConnectorComponentOutput::canConnectTo (GraphLinkComponent* link)
  315. {
  316. bool alreadyConnected = false;
  317. Array<GraphConnectorComponent*> linked;
  318. getLinkedConnectors (linked);
  319. for (int i = 0; i < linked.size (); i++)
  320. {
  321. if (link && linked.getUnchecked (i) == link->to)
  322. {
  323. alreadyConnected = true;
  324. break;
  325. }
  326. }
  327. return link->to
  328. && (link->to->getType () == getType ())
  329. && (! alreadyConnected)
  330. && (! parentGraph->isAfterNode (link->to->getParentGraphComponent ()));
  331. }
  332. void GraphConnectorComponentOutput::getLinkedConnectors(Array<GraphConnectorComponent*>& linked)
  333. {
  334. for (int i = 0; i < links.size (); i++)
  335. {
  336. linked.add (links[i]->to);
  337. }
  338. }
  339. void GraphConnectorComponentOutput::mouseDrag (const MouseEvent& e)
  340. {
  341. if (e.mods.isLeftButtonDown())
  342. {
  343. if (! newLink)
  344. {
  345. newLink = new GraphLinkComponent (leftToRight);
  346. newLink->from = this;
  347. getParentComponent()->addAndMakeVisible (newLink);
  348. int centre_x = getBounds ().getCentreX ();
  349. int centre_y = getBounds ().getCentreY ();
  350. newLink->setInterceptsMouseClicks (false, false);
  351. newLink->setStartPoint (centre_x, centre_y);
  352. newLink->toBack ();
  353. }
  354. if (newLink)
  355. {
  356. newLink->setEndPoint (getX() + e.x, getY() + e.y);
  357. Component* hitComponent = getParentComponent()->getComponentAt (getX() + e.x, getY() + e.y);
  358. GraphConnectorComponent* connector = dynamic_cast<GraphConnectorComponentInput*> (hitComponent);
  359. if (connector != currentlyDraggingOver)
  360. {
  361. if (currentlyDraggingOver != 0)
  362. currentlyDraggingOver->connectionDragExit();
  363. currentlyDraggingOver = connector;
  364. if (connector
  365. && connector->getParentGraphComponent () != parentGraph
  366. && connector->canConnectFrom (newLink))
  367. {
  368. currentlyDraggingOver->connectionDragEnter();
  369. }
  370. }
  371. }
  372. }
  373. }
  374. void GraphConnectorComponentOutput::mouseUp (const MouseEvent& e)
  375. {
  376. if (newLink)
  377. {
  378. if (currentlyDraggingOver != 0)
  379. {
  380. currentlyDraggingOver->connectionDragExit();
  381. currentlyDraggingOver = 0;
  382. }
  383. Component* hitComponent = getParentComponent()->getComponentAt (getX() + e.x, getY() + e.y);
  384. GraphConnectorComponent* connector = dynamic_cast<GraphConnectorComponentInput*> (hitComponent);
  385. if (connector)
  386. {
  387. if (connector->getParentGraphComponent () != parentGraph
  388. && connector->connectFrom (newLink))
  389. {
  390. newLink->setEndPoint (connector->getX() + connector->getWidth() / 2,
  391. connector->getY() + connector->getHeight() / 2);
  392. addLink (newLink);
  393. notifyGraphChanged ();
  394. newLink->setInterceptsMouseClicks (true, false);
  395. newLink->repaint();
  396. newLink = 0;
  397. return;
  398. }
  399. }
  400. deleteAndZero (newLink);
  401. }
  402. }
  403. END_JUCE_NAMESPACE