GraphicsView.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. #include "GraphicsView.hpp"
  2. #include "BasicGraphicsScene.hpp"
  3. #include "ConnectionGraphicsObject.hpp"
  4. #include "NodeGraphicsObject.hpp"
  5. #include "StyleCollection.hpp"
  6. #include "UndoCommands.hpp"
  7. #include <QtWidgets/QGraphicsScene>
  8. #include <QtGui/QBrush>
  9. #include <QtGui/QPen>
  10. #include <QtWidgets/QMenu>
  11. #include <QtCore/QDebug>
  12. #include <QtCore/QPointF>
  13. #include <QtCore/QRectF>
  14. #include <QtOpenGL>
  15. #include <QtWidgets>
  16. #include <cmath>
  17. #include <iostream>
  18. using QtNodes::BasicGraphicsScene;
  19. using QtNodes::GraphicsView;
  20. GraphicsView::GraphicsView(QWidget *parent)
  21. : QGraphicsView(parent),
  22. _clearSelectionAction(Q_NULLPTR),
  23. _deleteSelectionAction(Q_NULLPTR),
  24. _duplicateSelectionAction(Q_NULLPTR),
  25. _copySelectionAction(Q_NULLPTR),
  26. _pasteAction(Q_NULLPTR)
  27. {
  28. setDragMode(QGraphicsView::ScrollHandDrag);
  29. setRenderHint(QPainter::Antialiasing);
  30. auto const &flowViewStyle = StyleCollection::flowViewStyle();
  31. setBackgroundBrush(flowViewStyle.BackgroundColor);
  32. setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  33. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  34. setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
  35. setCacheMode(QGraphicsView::CacheBackground);
  36. setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
  37. setScaleRange(0.3, 2);
  38. // Sets the scene rect to its maximum possible ranges to avoid autu scene range
  39. // re-calculation when expanding the all QGraphicsItems common rect.
  40. int maxSize = 32767;
  41. setSceneRect(-maxSize, -maxSize, (maxSize * 2), (maxSize * 2));
  42. }
  43. GraphicsView::GraphicsView(BasicGraphicsScene *scene, QWidget *parent) : GraphicsView(parent)
  44. {
  45. setScene(scene);
  46. }
  47. QAction *GraphicsView::clearSelectionAction() const
  48. {
  49. return _clearSelectionAction;
  50. }
  51. QAction *GraphicsView::deleteSelectionAction() const
  52. {
  53. return _deleteSelectionAction;
  54. }
  55. void GraphicsView::setScene(BasicGraphicsScene *scene)
  56. {
  57. QGraphicsView::setScene(scene);
  58. {
  59. // setup actions
  60. delete _clearSelectionAction;
  61. _clearSelectionAction = new QAction(QStringLiteral("Clear Selection"), this);
  62. _clearSelectionAction->setShortcut(Qt::Key_Escape);
  63. connect(_clearSelectionAction, &QAction::triggered, scene, &QGraphicsScene::clearSelection);
  64. addAction(_clearSelectionAction);
  65. }
  66. {
  67. delete _deleteSelectionAction;
  68. _deleteSelectionAction = new QAction(QStringLiteral("Delete Selection"), this);
  69. _deleteSelectionAction->setShortcutContext(Qt::ShortcutContext::WidgetShortcut);
  70. _deleteSelectionAction->setShortcut(QKeySequence(QKeySequence::Delete));
  71. connect(_deleteSelectionAction, &QAction::triggered, this, &GraphicsView::onDeleteSelectedObjects);
  72. addAction(_deleteSelectionAction);
  73. }
  74. {
  75. delete _duplicateSelectionAction;
  76. _duplicateSelectionAction = new QAction(QStringLiteral("Duplicate Selection"), this);
  77. _duplicateSelectionAction->setShortcutContext(Qt::ShortcutContext::WidgetShortcut);
  78. _duplicateSelectionAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D));
  79. connect(_duplicateSelectionAction, &QAction::triggered, this, &GraphicsView::onDuplicateSelectedObjects);
  80. addAction(_duplicateSelectionAction);
  81. }
  82. {
  83. delete _copySelectionAction;
  84. _copySelectionAction = new QAction(QStringLiteral("Copy Selection"), this);
  85. _copySelectionAction->setShortcutContext(Qt::ShortcutContext::WidgetShortcut);
  86. _copySelectionAction->setShortcut(QKeySequence(QKeySequence::Copy));
  87. connect(_copySelectionAction, &QAction::triggered, this, &GraphicsView::onCopySelectedObjects);
  88. addAction(_copySelectionAction);
  89. }
  90. {
  91. delete _pasteAction;
  92. _pasteAction = new QAction(QStringLiteral("Copy Selection"), this);
  93. _pasteAction->setShortcutContext(Qt::ShortcutContext::WidgetShortcut);
  94. _pasteAction->setShortcut(QKeySequence(QKeySequence::Paste));
  95. connect(_pasteAction, &QAction::triggered, this, &GraphicsView::onPasteObjects);
  96. addAction(_pasteAction);
  97. }
  98. auto undoAction = scene->undoStack().createUndoAction(this, tr("&Undo"));
  99. undoAction->setShortcuts(QKeySequence::Undo);
  100. addAction(undoAction);
  101. auto redoAction = scene->undoStack().createRedoAction(this, tr("&Redo"));
  102. redoAction->setShortcuts(QKeySequence::Redo);
  103. addAction(redoAction);
  104. }
  105. void GraphicsView::centerScene()
  106. {
  107. if (scene()) {
  108. scene()->setSceneRect(QRectF());
  109. QRectF sceneRect = scene()->sceneRect();
  110. if (sceneRect.width() > this->rect().width() || sceneRect.height() > this->rect().height()) {
  111. fitInView(sceneRect, Qt::KeepAspectRatio);
  112. }
  113. centerOn(sceneRect.center());
  114. }
  115. }
  116. void GraphicsView::contextMenuEvent(QContextMenuEvent *event)
  117. {
  118. if (itemAt(event->pos())) {
  119. QGraphicsView::contextMenuEvent(event);
  120. return;
  121. }
  122. auto const scenePos = mapToScene(event->pos());
  123. QMenu *menu = nodeScene()->createSceneMenu(scenePos);
  124. if (menu) {
  125. menu->exec(event->globalPos());
  126. }
  127. }
  128. void GraphicsView::wheelEvent(QWheelEvent *event)
  129. {
  130. QPoint delta = event->angleDelta();
  131. if (delta.y() == 0) {
  132. event->ignore();
  133. return;
  134. }
  135. double const d = delta.y() / std::abs(delta.y());
  136. if (d > 0.0)
  137. scaleUp();
  138. else
  139. scaleDown();
  140. }
  141. double GraphicsView::getScale() const
  142. {
  143. return transform().m11();
  144. }
  145. void GraphicsView::setScaleRange(double minimum, double maximum)
  146. {
  147. if (maximum < minimum)
  148. std::swap(minimum, maximum);
  149. minimum = std::max(0.0, minimum);
  150. maximum = std::max(0.0, maximum);
  151. _scaleRange = { minimum, maximum };
  152. setupScale(transform().m11());
  153. }
  154. void GraphicsView::setScaleRange(ScaleRange range)
  155. {
  156. setScaleRange(range.minimum, range.maximum);
  157. }
  158. void GraphicsView::scaleUp()
  159. {
  160. double const step = 1.2;
  161. double const factor = std::pow(step, 1.0);
  162. if (_scaleRange.maximum > 0) {
  163. QTransform t = transform();
  164. t.scale(factor, factor);
  165. if (t.m11() >= _scaleRange.maximum) {
  166. setupScale(t.m11());
  167. return;
  168. }
  169. }
  170. scale(factor, factor);
  171. Q_EMIT scaleChanged(transform().m11());
  172. }
  173. void GraphicsView::scaleDown()
  174. {
  175. double const step = 1.2;
  176. double const factor = std::pow(step, -1.0);
  177. if (_scaleRange.minimum > 0) {
  178. QTransform t = transform();
  179. t.scale(factor, factor);
  180. if (t.m11() <= _scaleRange.minimum) {
  181. setupScale(t.m11());
  182. return;
  183. }
  184. }
  185. scale(factor, factor);
  186. Q_EMIT scaleChanged(transform().m11());
  187. }
  188. void GraphicsView::setupScale(double scale)
  189. {
  190. scale = std::max(_scaleRange.minimum, std::min(_scaleRange.maximum, scale));
  191. if (scale <= 0)
  192. return;
  193. if (scale == transform().m11())
  194. return;
  195. QTransform matrix;
  196. matrix.scale(scale, scale);
  197. setTransform(matrix, false);
  198. Q_EMIT scaleChanged(scale);
  199. }
  200. void GraphicsView::onDeleteSelectedObjects()
  201. {
  202. // nodeScene()->undoStack().push(new DeleteCommand(nodeScene()));
  203. }
  204. void GraphicsView::onDuplicateSelectedObjects()
  205. {
  206. QPointF const pastePosition = scenePastePosition();
  207. nodeScene()->undoStack().push(new CopyCommand(nodeScene()));
  208. nodeScene()->undoStack().push(new PasteCommand(nodeScene(), pastePosition));
  209. }
  210. void GraphicsView::onCopySelectedObjects()
  211. {
  212. nodeScene()->undoStack().push(new CopyCommand(nodeScene()));
  213. }
  214. void GraphicsView::onPasteObjects()
  215. {
  216. QPointF const pastePosition = scenePastePosition();
  217. nodeScene()->undoStack().push(new PasteCommand(nodeScene(), pastePosition));
  218. }
  219. void GraphicsView::keyPressEvent(QKeyEvent *event)
  220. {
  221. switch (event->key()) {
  222. case Qt::Key_Shift:
  223. setDragMode(QGraphicsView::RubberBandDrag);
  224. break;
  225. default:
  226. break;
  227. }
  228. QGraphicsView::keyPressEvent(event);
  229. }
  230. void GraphicsView::keyReleaseEvent(QKeyEvent *event)
  231. {
  232. switch (event->key()) {
  233. case Qt::Key_Shift:
  234. setDragMode(QGraphicsView::ScrollHandDrag);
  235. break;
  236. default:
  237. break;
  238. }
  239. QGraphicsView::keyReleaseEvent(event);
  240. }
  241. void GraphicsView::mousePressEvent(QMouseEvent *event)
  242. {
  243. QGraphicsView::mousePressEvent(event);
  244. if (event->button() == Qt::LeftButton) {
  245. _clickPos = mapToScene(event->pos());
  246. }
  247. }
  248. void GraphicsView::mouseMoveEvent(QMouseEvent *event)
  249. {
  250. QGraphicsView::mouseMoveEvent(event);
  251. if (scene()->mouseGrabberItem() == nullptr && event->buttons() == Qt::LeftButton) {
  252. // Make sure shift is not being pressed
  253. if ((event->modifiers() & Qt::ShiftModifier) == 0) {
  254. QPointF difference = _clickPos - mapToScene(event->pos());
  255. setSceneRect(sceneRect().translated(difference.x(), difference.y()));
  256. }
  257. }
  258. }
  259. void GraphicsView::drawBackground(QPainter *painter, const QRectF &r)
  260. {
  261. QGraphicsView::drawBackground(painter, r);
  262. auto drawGrid = [&](double gridStep) {
  263. QRect windowRect = rect();
  264. QPointF tl = mapToScene(windowRect.topLeft());
  265. QPointF br = mapToScene(windowRect.bottomRight());
  266. double left = std::floor(tl.x() / gridStep - 0.5);
  267. double right = std::floor(br.x() / gridStep + 1.0);
  268. double bottom = std::floor(tl.y() / gridStep - 0.5);
  269. double top = std::floor(br.y() / gridStep + 1.0);
  270. // vertical lines
  271. for (int xi = int(left); xi <= int(right); ++xi) {
  272. QLineF line(xi * gridStep, bottom * gridStep, xi * gridStep, top * gridStep);
  273. painter->drawLine(line);
  274. }
  275. // horizontal lines
  276. for (int yi = int(bottom); yi <= int(top); ++yi) {
  277. QLineF line(left * gridStep, yi * gridStep, right * gridStep, yi * gridStep);
  278. painter->drawLine(line);
  279. }
  280. };
  281. auto const &flowViewStyle = StyleCollection::flowViewStyle();
  282. QPen pfine(flowViewStyle.FineGridColor, 1.0);
  283. painter->setPen(pfine);
  284. drawGrid(15);
  285. QPen p(flowViewStyle.CoarseGridColor, 1.0);
  286. painter->setPen(p);
  287. drawGrid(150);
  288. }
  289. void GraphicsView::showEvent(QShowEvent *event)
  290. {
  291. QGraphicsView::showEvent(event);
  292. centerScene();
  293. }
  294. BasicGraphicsScene *GraphicsView::nodeScene()
  295. {
  296. return dynamic_cast<BasicGraphicsScene *>(scene());
  297. }
  298. QPointF GraphicsView::scenePastePosition()
  299. {
  300. QPoint origin = mapFromGlobal(QCursor::pos());
  301. QRect const viewRect = rect();
  302. if (!viewRect.contains(origin))
  303. origin = viewRect.center();
  304. return mapToScene(origin);
  305. }