NodeConnectionInteraction.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "NodeConnectionInteraction.hpp"
  2. #include "AbstractNodeGeometry.hpp"
  3. #include "BasicGraphicsScene.hpp"
  4. #include "ConnectionGraphicsObject.hpp"
  5. #include "ConnectionIdUtils.hpp"
  6. #include "NodeGraphicsObject.hpp"
  7. #include "UndoCommands.hpp"
  8. #include <QtCore/QDebug>
  9. #include <QUndoStack>
  10. namespace QtNodes {
  11. NodeConnectionInteraction::NodeConnectionInteraction(NodeGraphicsObject &ngo,
  12. ConnectionGraphicsObject &cgo,
  13. BasicGraphicsScene &scene)
  14. : _ngo(ngo)
  15. , _cgo(cgo)
  16. , _scene(scene)
  17. {}
  18. bool NodeConnectionInteraction::canConnect(PortIndex *portIndex) const
  19. {
  20. // 1. Connection requires a port.
  21. PortType requiredPort = _cgo.connectionState().requiredPort();
  22. if (requiredPort == PortType::None) {
  23. return false;
  24. }
  25. NodeId connectedNodeId = getNodeId(oppositePort(requiredPort), _cgo.connectionId());
  26. // 2. Forbid connecting the node to itself.
  27. if (_ngo.nodeId() == connectedNodeId)
  28. return false;
  29. // 3. Connection loose end is above the node port.
  30. QPointF connectionPoint = _cgo.sceneTransform().map(_cgo.endPoint(requiredPort));
  31. *portIndex = nodePortIndexUnderScenePoint(requiredPort, connectionPoint);
  32. if (*portIndex == InvalidPortIndex) {
  33. return false;
  34. }
  35. // 4. Model allows connection.
  36. AbstractGraphModel &model = _ngo.nodeScene()->graphModel();
  37. ConnectionId connectionId = makeCompleteConnectionId(_cgo.connectionId(), // incomplete
  38. _ngo.nodeId(), // missing node id
  39. *portIndex); // missing port index
  40. return model.connectionPossible(connectionId);
  41. }
  42. bool NodeConnectionInteraction::tryConnect() const
  43. {
  44. // 1. Check conditions from 'canConnect'.
  45. PortIndex targetPortIndex = InvalidPortIndex;
  46. if (!canConnect(&targetPortIndex)) {
  47. return false;
  48. }
  49. // 2. Create new connection.
  50. ConnectionId incompleteConnectionId = _cgo.connectionId();
  51. ConnectionId newConnectionId = makeCompleteConnectionId(incompleteConnectionId,
  52. _ngo.nodeId(),
  53. targetPortIndex);
  54. _ngo.nodeScene()->resetDraftConnection();
  55. _ngo.nodeScene()->undoStack().push(new ConnectCommand(_ngo.nodeScene(), newConnectionId));
  56. return true;
  57. }
  58. bool NodeConnectionInteraction::disconnect(PortType portToDisconnect) const
  59. {
  60. ConnectionId connectionId = _cgo.connectionId();
  61. _scene.undoStack().push(new DisconnectCommand(&_scene, connectionId));
  62. AbstractNodeGeometry &geometry = _scene.nodeGeometry();
  63. QPointF scenePos = geometry.portScenePosition(_ngo.nodeId(),
  64. portToDisconnect,
  65. getPortIndex(portToDisconnect, connectionId),
  66. _ngo.sceneTransform());
  67. // Converted to "draft" connection with the new incomplete id.
  68. ConnectionId incompleteConnectionId = makeIncompleteConnectionId(connectionId, portToDisconnect);
  69. // Grabs the mouse
  70. auto const &draftConnection = _scene.makeDraftConnection(incompleteConnectionId);
  71. QPointF const looseEndPos = draftConnection->mapFromScene(scenePos);
  72. draftConnection->setEndPoint(portToDisconnect, looseEndPos);
  73. // Repaint connection points.
  74. NodeId connectedNodeId = getNodeId(oppositePort(portToDisconnect), connectionId);
  75. _scene.nodeGraphicsObject(connectedNodeId)->update();
  76. NodeId disconnectedNodeId = getNodeId(portToDisconnect, connectionId);
  77. _scene.nodeGraphicsObject(disconnectedNodeId)->update();
  78. return true;
  79. }
  80. // ------------------ util functions below
  81. PortType NodeConnectionInteraction::connectionRequiredPort() const
  82. {
  83. auto const &state = _cgo.connectionState();
  84. return state.requiredPort();
  85. }
  86. QPointF NodeConnectionInteraction::nodePortScenePosition(PortType portType,
  87. PortIndex portIndex) const
  88. {
  89. AbstractNodeGeometry &geometry = _scene.nodeGeometry();
  90. QPointF p = geometry.portScenePosition(_ngo.nodeId(),
  91. portType,
  92. portIndex,
  93. _ngo.sceneTransform());
  94. return p;
  95. }
  96. PortIndex NodeConnectionInteraction::nodePortIndexUnderScenePoint(PortType portType,
  97. QPointF const &scenePoint) const
  98. {
  99. AbstractNodeGeometry &geometry = _scene.nodeGeometry();
  100. QTransform sceneTransform = _ngo.sceneTransform();
  101. QPointF nodePoint = sceneTransform.inverted().map(scenePoint);
  102. return geometry.checkPortHit(_ngo.nodeId(), portType, nodePoint);
  103. }
  104. } // namespace QtNodes