DefaultNodePainter.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include "DefaultNodePainter.hpp"
  2. #include <cmath>
  3. #include <QtCore/QMargins>
  4. #include "AbstractGraphModel.hpp"
  5. #include "AbstractNodeGeometry.hpp"
  6. #include "BasicGraphicsScene.hpp"
  7. #include "ConnectionGraphicsObject.hpp"
  8. #include "ConnectionIdUtils.hpp"
  9. #include "NodeGraphicsObject.hpp"
  10. #include "NodeState.hpp"
  11. #include "StyleCollection.hpp"
  12. namespace QtNodes {
  13. void DefaultNodePainter::paint(QPainter *painter, NodeGraphicsObject &ngo) const
  14. {
  15. // TODO?
  16. // AbstractNodeGeometry & geometry = ngo.nodeScene()->nodeGeometry();
  17. // geometry.recomputeSizeIfFontChanged(painter->font());
  18. drawNodeRect(painter, ngo);
  19. // drawConnectionPoints(painter, ngo);
  20. // drawFilledConnectionPoints(painter, ngo);
  21. drawNodeCaption(painter, ngo);
  22. drawEntryLabels(painter, ngo);
  23. drawResizeRect(painter, ngo);
  24. }
  25. void DefaultNodePainter::drawNodeRect(QPainter *painter, NodeGraphicsObject &ngo) const
  26. {
  27. AbstractGraphModel &model = ngo.graphModel();
  28. NodeId const nodeId = ngo.nodeId();
  29. AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
  30. QSize size = geometry.size(nodeId);
  31. QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
  32. NodeStyle nodeStyle(json.object());
  33. auto color = ngo.isSelected() ? nodeStyle.SelectedBoundaryColor : nodeStyle.NormalBoundaryColor;
  34. if (ngo.nodeState().hovered()) {
  35. QPen p(color, nodeStyle.HoveredPenWidth);
  36. painter->setPen(p);
  37. } else {
  38. QPen p(color, nodeStyle.PenWidth);
  39. painter->setPen(p);
  40. }
  41. QLinearGradient gradient(QPointF(0.0, 0.0), QPointF(2.0, size.height()));
  42. gradient.setColorAt(0.0, nodeStyle.GradientColor0);
  43. gradient.setColorAt(0.10, nodeStyle.GradientColor1);
  44. gradient.setColorAt(0.90, nodeStyle.GradientColor2);
  45. gradient.setColorAt(1.0, nodeStyle.GradientColor3);
  46. painter->setBrush(gradient);
  47. QRectF boundary(0, 0, size.width(), size.height());
  48. double const radius = 3.0;
  49. painter->drawRoundedRect(boundary, radius, radius);
  50. }
  51. void DefaultNodePainter::drawConnectionPoints(QPainter *painter, NodeGraphicsObject &ngo) const
  52. {
  53. AbstractGraphModel &model = ngo.graphModel();
  54. NodeId const nodeId = ngo.nodeId();
  55. AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
  56. QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
  57. NodeStyle nodeStyle(json.object());
  58. auto const &connectionStyle = StyleCollection::connectionStyle();
  59. float diameter = nodeStyle.ConnectionPointDiameter;
  60. auto reducedDiameter = diameter * 0.6;
  61. for (PortType portType : { PortType::Out, PortType::In }) {
  62. size_t const n =
  63. model.nodeData(nodeId, (portType == PortType::Out) ? NodeRole::OutPortCount : NodeRole::InPortCount)
  64. .toUInt();
  65. for (PortIndex portIndex = 0; portIndex < n; ++portIndex) {
  66. QPointF p = geometry.portPosition(nodeId, portType, portIndex);
  67. auto const &dataType =
  68. model.portData(nodeId, portType, portIndex, PortRole::DataType).value<NodeDataType>();
  69. double r = 1.0;
  70. NodeState const &state = ngo.nodeState();
  71. if (auto const *cgo = state.connectionForReaction()) {
  72. PortType requiredPort = cgo->connectionState().requiredPort();
  73. if (requiredPort == portType) {
  74. ConnectionId possibleConnectionId =
  75. makeCompleteConnectionId(cgo->connectionId(), nodeId, portIndex);
  76. bool const possible = model.connectionPossible(possibleConnectionId);
  77. auto cp = cgo->sceneTransform().map(cgo->endPoint(requiredPort));
  78. cp = ngo.sceneTransform().inverted().map(cp);
  79. auto diff = cp - p;
  80. double dist = std::sqrt(QPointF::dotProduct(diff, diff));
  81. if (possible) {
  82. double const thres = 40.0;
  83. r = (dist < thres) ? (2.0 - dist / thres) : 1.0;
  84. } else {
  85. double const thres = 80.0;
  86. r = (dist < thres) ? (dist / thres) : 1.0;
  87. }
  88. }
  89. }
  90. if (connectionStyle.useDataDefinedColors()) {
  91. painter->setBrush(connectionStyle.normalColor(dataType.id));
  92. } else {
  93. painter->setBrush(nodeStyle.ConnectionPointColor);
  94. }
  95. painter->drawEllipse(p, reducedDiameter * r, reducedDiameter * r);
  96. }
  97. }
  98. if (ngo.nodeState().connectionForReaction()) {
  99. ngo.nodeState().resetConnectionForReaction();
  100. }
  101. }
  102. void DefaultNodePainter::drawFilledConnectionPoints(QPainter *painter, NodeGraphicsObject &ngo) const
  103. {
  104. AbstractGraphModel &model = ngo.graphModel();
  105. NodeId const nodeId = ngo.nodeId();
  106. AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
  107. QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
  108. NodeStyle nodeStyle(json.object());
  109. auto diameter = nodeStyle.ConnectionPointDiameter;
  110. for (PortType portType : { PortType::Out, PortType::In }) {
  111. size_t const n =
  112. model.nodeData(nodeId, (portType == PortType::Out) ? NodeRole::OutPortCount : NodeRole::InPortCount)
  113. .toUInt();
  114. for (PortIndex portIndex = 0; portIndex < n; ++portIndex) {
  115. QPointF p = geometry.portPosition(nodeId, portType, portIndex);
  116. auto const &connected = model.connections(nodeId, portType, portIndex);
  117. if (!connected.empty()) {
  118. auto const &dataType =
  119. model.portData(nodeId, portType, portIndex, PortRole::DataType).value<NodeDataType>();
  120. auto const &connectionStyle = StyleCollection::connectionStyle();
  121. if (connectionStyle.useDataDefinedColors()) {
  122. QColor const c = connectionStyle.normalColor(dataType.id);
  123. painter->setPen(c);
  124. painter->setBrush(c);
  125. } else {
  126. painter->setPen(nodeStyle.FilledConnectionPointColor);
  127. painter->setBrush(nodeStyle.FilledConnectionPointColor);
  128. }
  129. painter->drawEllipse(p, diameter * 0.4, diameter * 0.4);
  130. }
  131. }
  132. }
  133. }
  134. void DefaultNodePainter::drawNodeCaption(QPainter *painter, NodeGraphicsObject &ngo) const
  135. {
  136. AbstractGraphModel &model = ngo.graphModel();
  137. NodeId const nodeId = ngo.nodeId();
  138. AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
  139. if (!model.nodeData(nodeId, NodeRole::CaptionVisible).toBool())
  140. return;
  141. QString const name = model.nodeData(nodeId, NodeRole::Caption).toString();
  142. QFont f = painter->font();
  143. f.setBold(true);
  144. QPointF position = geometry.captionPosition(nodeId);
  145. QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
  146. NodeStyle nodeStyle(json.object());
  147. painter->setFont(f);
  148. painter->setPen(nodeStyle.FontColor);
  149. painter->drawText(position, name);
  150. f.setBold(false);
  151. painter->setFont(f);
  152. }
  153. void DefaultNodePainter::drawEntryLabels(QPainter *painter, NodeGraphicsObject &ngo) const
  154. {
  155. AbstractGraphModel &model = ngo.graphModel();
  156. NodeId const nodeId = ngo.nodeId();
  157. AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
  158. QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
  159. NodeStyle nodeStyle(json.object());
  160. for (PortType portType : { PortType::Out, PortType::In }) {
  161. unsigned int n = model.nodeData<unsigned int>(
  162. nodeId, (portType == PortType::Out) ? NodeRole::OutPortCount : NodeRole::InPortCount);
  163. for (PortIndex portIndex = 0; portIndex < n; ++portIndex) {
  164. auto const &connected = model.connections(nodeId, portType, portIndex);
  165. QPointF p = geometry.portTextPosition(nodeId, portType, portIndex);
  166. if (connected.empty())
  167. painter->setPen(nodeStyle.FontColorFaded);
  168. else
  169. painter->setPen(nodeStyle.FontColor);
  170. QString s;
  171. if (model.portData<bool>(nodeId, portType, portIndex, PortRole::CaptionVisible)) {
  172. s = model.portData<QString>(nodeId, portType, portIndex, PortRole::Caption);
  173. } else {
  174. auto portData = model.portData(nodeId, portType, portIndex, PortRole::DataType);
  175. s = portData.value<NodeDataType>().name;
  176. }
  177. painter->drawText(p, s);
  178. }
  179. }
  180. }
  181. void DefaultNodePainter::drawResizeRect(QPainter *painter, NodeGraphicsObject &ngo) const
  182. {
  183. AbstractGraphModel &model = ngo.graphModel();
  184. NodeId const nodeId = ngo.nodeId();
  185. AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
  186. if (model.nodeFlags(nodeId) & NodeFlag::Resizable) {
  187. painter->setBrush(Qt::gray);
  188. painter->drawEllipse(geometry.resizeHandleRect(nodeId));
  189. }
  190. }
  191. } // namespace QtNodes