loom
298 строк · 7.9 Кб
1#include "BasicGraphicsScene.hpp"
2
3#include "AbstractNodeGeometry.hpp"
4#include "ConnectionGraphicsObject.hpp"
5#include "ConnectionIdUtils.hpp"
6#include "DefaultHorizontalNodeGeometry.hpp"
7#include "DefaultNodePainter.hpp"
8#include "DefaultVerticalNodeGeometry.hpp"
9#include "GraphicsView.hpp"
10#include "NodeGraphicsObject.hpp"
11
12#include <QUndoStack>
13
14#include <QtWidgets/QFileDialog>
15#include <QtWidgets/QGraphicsSceneMoveEvent>
16
17#include <QtCore/QBuffer>
18#include <QtCore/QByteArray>
19#include <QtCore/QDataStream>
20#include <QtCore/QFile>
21#include <QtCore/QJsonArray>
22#include <QtCore/QJsonDocument>
23#include <QtCore/QJsonObject>
24#include <QtCore/QtGlobal>
25
26#include <iostream>
27#include <stdexcept>
28#include <unordered_set>
29#include <utility>
30#include <queue>
31
32namespace QtNodes {
33
34BasicGraphicsScene::BasicGraphicsScene(AbstractGraphModel &graphModel, QObject *parent)
35: QGraphicsScene(parent)
36, _graphModel(graphModel)
37, _nodeGeometry(std::make_unique<DefaultHorizontalNodeGeometry>(_graphModel))
38, _nodePainter(std::make_unique<DefaultNodePainter>())
39, _nodeDrag(false)
40, _undoStack(new QUndoStack(this))
41, _orientation(Qt::Horizontal)
42{
43setItemIndexMethod(QGraphicsScene::NoIndex);
44
45connect(&_graphModel,
46&AbstractGraphModel::connectionCreated,
47this,
48&BasicGraphicsScene::onConnectionCreated);
49
50connect(&_graphModel,
51&AbstractGraphModel::connectionDeleted,
52this,
53&BasicGraphicsScene::onConnectionDeleted);
54
55connect(&_graphModel,
56&AbstractGraphModel::nodeCreated,
57this,
58&BasicGraphicsScene::onNodeCreated);
59
60connect(&_graphModel,
61&AbstractGraphModel::nodeDeleted,
62this,
63&BasicGraphicsScene::onNodeDeleted);
64
65connect(&_graphModel,
66&AbstractGraphModel::nodePositionUpdated,
67this,
68&BasicGraphicsScene::onNodePositionUpdated);
69
70connect(&_graphModel,
71&AbstractGraphModel::nodeUpdated,
72this,
73&BasicGraphicsScene::onNodeUpdated);
74
75connect(this, &BasicGraphicsScene::nodeClicked, this, &BasicGraphicsScene::onNodeClicked);
76
77connect(&_graphModel, &AbstractGraphModel::modelReset, this, &BasicGraphicsScene::onModelReset);
78
79traverseGraphAndPopulateGraphicsObjects();
80}
81
82BasicGraphicsScene::~BasicGraphicsScene() = default;
83
84AbstractGraphModel const &BasicGraphicsScene::graphModel() const
85{
86return _graphModel;
87}
88
89AbstractGraphModel &BasicGraphicsScene::graphModel()
90{
91return _graphModel;
92}
93
94AbstractNodeGeometry &BasicGraphicsScene::nodeGeometry()
95{
96return *_nodeGeometry;
97}
98
99AbstractNodePainter &BasicGraphicsScene::nodePainter()
100{
101return *_nodePainter;
102}
103
104void BasicGraphicsScene::setNodePainter(std::unique_ptr<AbstractNodePainter> newPainter)
105{
106_nodePainter = std::move(newPainter);
107}
108
109QUndoStack &BasicGraphicsScene::undoStack()
110{
111return *_undoStack;
112}
113
114std::unique_ptr<ConnectionGraphicsObject> const &BasicGraphicsScene::makeDraftConnection(
115ConnectionId const incompleteConnectionId)
116{
117_draftConnection = std::make_unique<ConnectionGraphicsObject>(*this, incompleteConnectionId);
118
119_draftConnection->grabMouse();
120
121return _draftConnection;
122}
123
124void BasicGraphicsScene::resetDraftConnection()
125{
126_draftConnection.reset();
127}
128
129void BasicGraphicsScene::clearScene()
130{
131auto const &allNodeIds = graphModel().allNodeIds();
132
133for (auto nodeId : allNodeIds) {
134graphModel().deleteNode(nodeId);
135}
136}
137
138NodeGraphicsObject *BasicGraphicsScene::nodeGraphicsObject(NodeId nodeId)
139{
140NodeGraphicsObject *ngo = nullptr;
141auto it = _nodeGraphicsObjects.find(nodeId);
142if (it != _nodeGraphicsObjects.end()) {
143ngo = it->second.get();
144}
145
146return ngo;
147}
148
149ConnectionGraphicsObject *BasicGraphicsScene::connectionGraphicsObject(ConnectionId connectionId)
150{
151ConnectionGraphicsObject *cgo = nullptr;
152auto it = _connectionGraphicsObjects.find(connectionId);
153if (it != _connectionGraphicsObjects.end()) {
154cgo = it->second.get();
155}
156
157return cgo;
158}
159
160void BasicGraphicsScene::setOrientation(Qt::Orientation const orientation)
161{
162if (_orientation != orientation) {
163_orientation = orientation;
164
165switch (_orientation) {
166case Qt::Horizontal:
167_nodeGeometry = std::make_unique<DefaultHorizontalNodeGeometry>(_graphModel);
168break;
169
170case Qt::Vertical:
171_nodeGeometry = std::make_unique<DefaultVerticalNodeGeometry>(_graphModel);
172break;
173}
174
175onModelReset();
176}
177}
178
179QMenu *BasicGraphicsScene::createSceneMenu(QPointF const scenePos)
180{
181Q_UNUSED(scenePos);
182return nullptr;
183}
184
185void BasicGraphicsScene::traverseGraphAndPopulateGraphicsObjects()
186{
187auto allNodeIds = _graphModel.allNodeIds();
188
189// First create all the nodes.
190for (NodeId const nodeId : allNodeIds) {
191_nodeGraphicsObjects[nodeId] = std::make_unique<NodeGraphicsObject>(*this, nodeId);
192}
193
194// Then for each node check output connections and insert them.
195for (NodeId const nodeId : allNodeIds) {
196unsigned int nOutPorts = _graphModel.nodeData<PortCount>(nodeId, NodeRole::OutPortCount);
197
198for (PortIndex index = 0; index < nOutPorts; ++index) {
199auto const &outConnectionIds = _graphModel.connections(nodeId, PortType::Out, index);
200
201for (auto cid : outConnectionIds) {
202_connectionGraphicsObjects[cid] = std::make_unique<ConnectionGraphicsObject>(*this,
203cid);
204}
205}
206}
207}
208
209void BasicGraphicsScene::updateAttachedNodes(ConnectionId const connectionId,
210PortType const portType)
211{
212auto node = nodeGraphicsObject(getNodeId(portType, connectionId));
213
214if (node) {
215node->update();
216}
217}
218
219void BasicGraphicsScene::onConnectionDeleted(ConnectionId const connectionId)
220{
221auto it = _connectionGraphicsObjects.find(connectionId);
222if (it != _connectionGraphicsObjects.end()) {
223_connectionGraphicsObjects.erase(it);
224}
225
226// TODO: do we need it?
227if (_draftConnection && _draftConnection->connectionId() == connectionId) {
228_draftConnection.reset();
229}
230
231updateAttachedNodes(connectionId, PortType::Out);
232updateAttachedNodes(connectionId, PortType::In);
233}
234
235void BasicGraphicsScene::onConnectionCreated(ConnectionId const connectionId)
236{
237_connectionGraphicsObjects[connectionId]
238= std::make_unique<ConnectionGraphicsObject>(*this, connectionId);
239
240updateAttachedNodes(connectionId, PortType::Out);
241updateAttachedNodes(connectionId, PortType::In);
242}
243
244void BasicGraphicsScene::onNodeDeleted(NodeId const nodeId)
245{
246auto it = _nodeGraphicsObjects.find(nodeId);
247if (it != _nodeGraphicsObjects.end()) {
248_nodeGraphicsObjects.erase(it);
249}
250}
251
252void BasicGraphicsScene::onNodeCreated(NodeId const nodeId)
253{
254_nodeGraphicsObjects[nodeId] = std::make_unique<NodeGraphicsObject>(*this, nodeId);
255}
256
257void BasicGraphicsScene::onNodePositionUpdated(NodeId const nodeId)
258{
259auto node = nodeGraphicsObject(nodeId);
260if (node) {
261node->setPos(_graphModel.nodeData(nodeId, NodeRole::Position).value<QPointF>());
262node->update();
263_nodeDrag = true;
264}
265}
266
267void BasicGraphicsScene::onNodeUpdated(NodeId const nodeId)
268{
269auto node = nodeGraphicsObject(nodeId);
270
271if (node) {
272node->setGeometryChanged();
273
274_nodeGeometry->recomputeSize(nodeId);
275
276node->update();
277node->moveConnections();
278}
279}
280
281void BasicGraphicsScene::onNodeClicked(NodeId const nodeId)
282{
283if (_nodeDrag)
284Q_EMIT nodeMoved(nodeId, _graphModel.nodeData(nodeId, NodeRole::Position).value<QPointF>());
285_nodeDrag = false;
286}
287
288void BasicGraphicsScene::onModelReset()
289{
290_connectionGraphicsObjects.clear();
291_nodeGraphicsObjects.clear();
292
293clear();
294
295traverseGraphAndPopulateGraphicsObjects();
296}
297
298} // namespace QtNodes
299