ConnectionPainter.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #include "ConnectionPainter.hpp"
  2. #include <QtGui/QIcon>
  3. #include "AbstractGraphModel.hpp"
  4. #include "ConnectionGraphicsObject.hpp"
  5. #include "ConnectionState.hpp"
  6. #include "Definitions.hpp"
  7. #include "NodeData.hpp"
  8. #include "StyleCollection.hpp"
  9. #include <QtMath>
  10. namespace QtNodes {
  11. static QPainterPath arrowPath(QPainterPath const &cubic)
  12. {
  13. QPainterPath arrow;
  14. // 绘制箭头
  15. double ctrlPercent = 0.9;
  16. if (cubic.length() > 100) {
  17. ctrlPercent = cubic.percentAtLength(cubic.length() - 10);
  18. } else if (cubic.length() < 10) {
  19. ctrlPercent = 0.5;
  20. }
  21. QPointF end = cubic.pointAtPercent(1);
  22. QPointF ctrlPoint = cubic.pointAtPercent(ctrlPercent);
  23. double angle = cubic.angleAtPercent(ctrlPercent);
  24. QLineF lineBottom;
  25. lineBottom.setP1(ctrlPoint);
  26. lineBottom.setAngle(angle + 90);
  27. // double scale = 0.05 - ctrlPercent / 50;
  28. // qreal lineLength = cubic.length() * scale;
  29. // if (lineLength < 5) {
  30. // lineLength = 5;
  31. // } else if (lineLength > 10) {
  32. // lineLength = 10;
  33. // }
  34. qreal lineLength = 5;
  35. lineBottom.setLength(lineLength);
  36. QPointF arrowLeft = lineBottom.p2();
  37. lineBottom.setAngle(lineBottom.angle() + 180);
  38. QPointF arrowRight = lineBottom.p2();
  39. arrow.moveTo(end);
  40. arrow.lineTo(arrowLeft);
  41. arrow.lineTo(arrowRight);
  42. arrow.lineTo(end);
  43. return arrow;
  44. }
  45. static QPainterPath cubicPath(ConnectionGraphicsObject const &connection)
  46. {
  47. QPointF const &in = connection.endPoint(PortType::In);
  48. QPointF const &out = connection.endPoint(PortType::Out);
  49. auto const c1c2 = connection.pointsC1C2();
  50. // cubic spline
  51. QPainterPath cubic(out);
  52. cubic.cubicTo(c1c2.first, c1c2.second, in);
  53. return cubic;
  54. }
  55. QPainterPath ConnectionPainter::getPainterStroke(ConnectionGraphicsObject const &connection)
  56. {
  57. auto cubic = cubicPath(connection);
  58. QPointF const &out = connection.endPoint(PortType::Out);
  59. QPainterPath result(out);
  60. unsigned segments = 20;
  61. for (auto i = 0ul; i < segments; ++i) {
  62. double ratio = double(i + 1) / segments;
  63. result.lineTo(cubic.pointAtPercent(ratio));
  64. }
  65. QPainterPathStroker stroker;
  66. stroker.setWidth(10.0);
  67. return stroker.createStroke(result);
  68. }
  69. #ifdef NODE_DEBUG_DRAWING
  70. static void debugDrawing(QPainter *painter, ConnectionGraphicsObject const &cgo)
  71. {
  72. Q_UNUSED(painter);
  73. {
  74. QPointF const &in = cgo.endPoint(PortType::In);
  75. QPointF const &out = cgo.endPoint(PortType::Out);
  76. auto const points = cgo.pointsC1C2();
  77. painter->setPen(Qt::red);
  78. painter->setBrush(Qt::red);
  79. painter->drawLine(QLineF(out, points.first));
  80. painter->drawLine(QLineF(points.first, points.second));
  81. painter->drawLine(QLineF(points.second, in));
  82. painter->drawEllipse(points.first, 3, 3);
  83. painter->drawEllipse(points.second, 3, 3);
  84. painter->setBrush(Qt::NoBrush);
  85. painter->drawPath(cubicPath(cgo));
  86. }
  87. {
  88. painter->setPen(Qt::yellow);
  89. painter->drawRect(cgo.boundingRect());
  90. }
  91. }
  92. #endif
  93. static void drawSketchLine(QPainter *painter, ConnectionGraphicsObject const &cgo)
  94. {
  95. ConnectionState const &state = cgo.connectionState();
  96. if (state.requiresPort()) {
  97. auto const &connectionStyle = QtNodes::StyleCollection::connectionStyle();
  98. QPen pen;
  99. pen.setWidth(connectionStyle.constructionLineWidth());
  100. pen.setColor(connectionStyle.constructionColor());
  101. pen.setStyle(Qt::DashLine);
  102. painter->setPen(pen);
  103. painter->setBrush(Qt::NoBrush);
  104. auto cubic = cubicPath(cgo);
  105. // cubic spline
  106. painter->drawPath(cubic);
  107. // arrow line
  108. auto arrow = arrowPath(cubic);
  109. painter->setBrush(pen.color());
  110. painter->drawPath(arrow);
  111. }
  112. }
  113. static void drawHoveredOrSelected(QPainter *painter, ConnectionGraphicsObject const &cgo)
  114. {
  115. bool const hovered = cgo.connectionState().hovered();
  116. bool const selected = cgo.isSelected();
  117. // drawn as a fat background
  118. if (hovered || selected) {
  119. auto const &connectionStyle = QtNodes::StyleCollection::connectionStyle();
  120. double const lineWidth = connectionStyle.lineWidth();
  121. QPen pen;
  122. pen.setWidth(2 * lineWidth);
  123. pen.setColor(selected ? connectionStyle.selectedHaloColor() : connectionStyle.hoveredColor());
  124. painter->setPen(pen);
  125. painter->setBrush(Qt::NoBrush);
  126. // cubic spline
  127. auto const cubic = cubicPath(cgo);
  128. painter->drawPath(cubic);
  129. // arrow line
  130. auto arrow = arrowPath(cubic);
  131. painter->setBrush(pen.color());
  132. painter->drawPath(arrow);
  133. }
  134. }
  135. static void drawNormalLine(QPainter *painter, ConnectionGraphicsObject const &cgo)
  136. {
  137. ConnectionState const &state = cgo.connectionState();
  138. if (state.requiresPort())
  139. return;
  140. // colors
  141. auto const &connectionStyle = QtNodes::StyleCollection::connectionStyle();
  142. QColor normalColorOut = connectionStyle.normalColor();
  143. QColor normalColorIn = connectionStyle.normalColor();
  144. QColor selectedColor = connectionStyle.selectedColor();
  145. bool useGradientColor = false;
  146. AbstractGraphModel const &graphModel = cgo.graphModel();
  147. if (connectionStyle.useDataDefinedColors()) {
  148. using QtNodes::PortType;
  149. auto const cId = cgo.connectionId();
  150. auto dataTypeOut = graphModel.portData(cId.outNodeId, PortType::Out, cId.outPortIndex, PortRole::DataType)
  151. .value<NodeDataType>();
  152. auto dataTypeIn = graphModel.portData(cId.inNodeId, PortType::In, cId.inPortIndex, PortRole::DataType)
  153. .value<NodeDataType>();
  154. useGradientColor = (dataTypeOut.id != dataTypeIn.id);
  155. normalColorOut = connectionStyle.normalColor(dataTypeOut.id);
  156. normalColorIn = connectionStyle.normalColor(dataTypeIn.id);
  157. selectedColor = normalColorOut.darker(200);
  158. }
  159. // geometry
  160. double const lineWidth = connectionStyle.lineWidth();
  161. // draw normal line
  162. QPen p;
  163. p.setWidth(lineWidth);
  164. bool const selected = cgo.isSelected();
  165. auto cubic = cubicPath(cgo);
  166. if (useGradientColor) {
  167. painter->setBrush(Qt::NoBrush);
  168. QColor cOut = normalColorOut;
  169. if (selected)
  170. cOut = cOut.darker(200);
  171. p.setColor(cOut);
  172. painter->setPen(p);
  173. unsigned int const segments = 60;
  174. for (unsigned int i = 0ul; i < segments; ++i) {
  175. double ratioPrev = double(i) / segments;
  176. double ratio = double(i + 1) / segments;
  177. if (i == segments / 2) {
  178. QColor cIn = normalColorIn;
  179. if (selected)
  180. cIn = cIn.darker(200);
  181. p.setColor(cIn);
  182. painter->setPen(p);
  183. }
  184. painter->drawLine(cubic.pointAtPercent(ratioPrev), cubic.pointAtPercent(ratio));
  185. }
  186. // arrow line
  187. auto arrow = arrowPath(cubic);
  188. painter->setBrush(p.color());
  189. painter->drawPath(arrow);
  190. {
  191. QIcon icon(":convert.png");
  192. QPixmap pixmap = icon.pixmap(QSize(22, 22));
  193. painter->drawPixmap(cubic.pointAtPercent(0.50) - QPoint(pixmap.width() / 2, pixmap.height() / 2), pixmap);
  194. }
  195. } else {
  196. p.setColor(normalColorOut);
  197. if (selected) {
  198. p.setColor(selectedColor);
  199. }
  200. painter->setPen(p);
  201. painter->setBrush(Qt::NoBrush);
  202. painter->drawPath(cubic);
  203. // arrow line
  204. auto arrow = arrowPath(cubic);
  205. painter->setBrush(p.color());
  206. painter->drawPath(arrow);
  207. }
  208. }
  209. void ConnectionPainter::paint(QPainter *painter, ConnectionGraphicsObject const &cgo)
  210. {
  211. drawHoveredOrSelected(painter, cgo);
  212. drawSketchLine(painter, cgo);
  213. drawNormalLine(painter, cgo);
  214. #ifdef NODE_DEBUG_DRAWING
  215. debugDrawing(painter, cgo);
  216. #endif
  217. // draw end points
  218. return;
  219. auto const &connectionStyle = QtNodes::StyleCollection::connectionStyle();
  220. double const pointDiameter = connectionStyle.pointDiameter();
  221. painter->setPen(connectionStyle.constructionColor());
  222. painter->setBrush(connectionStyle.constructionColor());
  223. double const pointRadius = pointDiameter / 2.0;
  224. painter->drawEllipse(cgo.out(), pointRadius, pointRadius);
  225. painter->drawEllipse(cgo.in(), pointRadius, pointRadius);
  226. }
  227. } // namespace QtNodes