forked from paceholder/nodeeditor
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBasicGraphicsScene.hpp
More file actions
321 lines (264 loc) · 11 KB
/
BasicGraphicsScene.hpp
File metadata and controls
321 lines (264 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#pragma once
#include "AbstractGraphModel.hpp"
#include "AbstractNodeGeometry.hpp"
#include "ConnectionIdHash.hpp"
#include "Definitions.hpp"
#include "Export.hpp"
#include "GroupGraphicsObject.hpp"
#include "NodeGroup.hpp"
#include "QUuidStdHash.hpp"
#include "UndoCommands.hpp"
#include <QtCore/QJsonObject>
#include <QtCore/QUuid>
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/QMenu>
#include <functional>
#include <memory>
#include <tuple>
#include <unordered_map>
class QUndoStack;
namespace QtNodes {
class AbstractConnectionPainter;
class AbstractGraphModel;
class AbstractNodePainter;
class ConnectionGraphicsObject;
class NodeGraphicsObject;
class NodeStyle;
class DeleteCommand;
class CopyCommand;
class NodeGroup;
class GroupGraphicsObject;
struct ConnectionId;
/// An instance of QGraphicsScene , holds connections and nodes.
class NODE_EDITOR_PUBLIC BasicGraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
BasicGraphicsScene(AbstractGraphModel &graphModel, QObject *parent = nullptr);
// Scenes without models are not supported
BasicGraphicsScene() = delete;
~BasicGraphicsScene();
public:
/// @returns associated AbstractGraphModel.
AbstractGraphModel const &graphModel() const;
AbstractGraphModel &graphModel();
AbstractNodeGeometry const &nodeGeometry() const;
AbstractNodeGeometry &nodeGeometry();
AbstractNodePainter &nodePainter();
AbstractConnectionPainter &connectionPainter();
void setNodePainter(std::unique_ptr<AbstractNodePainter> newPainter);
void setConnectionPainter(std::unique_ptr<AbstractConnectionPainter> newPainter);
void setNodeGeometry(std::unique_ptr<AbstractNodeGeometry> newGeom);
QUndoStack &undoStack();
/**
* @brief Setter for the _groupingEnabled flag.
* @param boolean to set or not the flag.
*/
void setGroupingEnabled(bool enabled);
/**
* @brief Getter for the _groupingEnabled flag.
*/
bool groupingEnabled() const { return _groupingEnabled; }
public:
/**
* @brief Creates a "draft" instance of ConnectionGraphicsObject.
*
* The scene caches a "draft" connection which has one loose end.
* After attachment the "draft" instance is deleted and instead a
* normal "full" connection is created.
* Function @returns the "draft" instance for further geometry
* manipulations.
*/
std::unique_ptr<ConnectionGraphicsObject> const &makeDraftConnection(
ConnectionId const newConnectionId);
/**
* @brief Deletes "draft" connection.
*
* The function is called when user releases the mouse button during
* the construction of the new connection without attaching it to any
* node.
*/
void resetDraftConnection();
/// Deletes all the nodes. Connections are removed automatically.
void clearScene();
/**
* @brief Creates a list of the connections that are incident only to nodes within a
* given group.
* @param groupID ID of the desired group.
* @return List of (pointers of) connections whose both endpoints belong to members of
* the specified group.
*/
std::vector<std::shared_ptr<ConnectionId>> connectionsWithinGroup(GroupId groupID);
/**
* @brief Creates a group in the scene containing the given nodes.
* @param nodes Reference to the list of nodes to be included in the group.
* @param name Group's name.
* @param groupId Group's id.
* @return Pointer to the newly-created group.
*/
std::weak_ptr<NodeGroup> createGroup(std::vector<NodeGraphicsObject *> &nodes,
QString name = QStringLiteral(""),
GroupId groupId = InvalidGroupId);
/**
* @brief Creates a group in the scene containing the currently selected nodes.
* @param name Group's name
* @return Pointer to the newly-created group.
*/
std::weak_ptr<NodeGroup> createGroupFromSelection(QString groupName = QStringLiteral(""));
/**
* @brief Restores a group from a JSON object.
* @param groupJson JSON object containing the group data.
* @return Pair consisting of a pointer to the newly-created group and the mapping
* between old and new nodes.
*/
std::pair<std::weak_ptr<NodeGroup>, std::unordered_map<GroupId, GroupId>> restoreGroup(
QJsonObject const &groupJson);
/**
* @brief Returns a const reference to the mapping of existing groups.
*/
std::unordered_map<GroupId, std::shared_ptr<NodeGroup>> const &groups() const;
/**
* @brief Loads a group from a file specified by the user.
* @return Pointer to the newly-created group.
*/
std::weak_ptr<NodeGroup> loadGroupFile();
/**
* @brief Saves a group in a .group file.
* @param groupID Group's id.
*/
void saveGroupFile(GroupId groupID);
/**
* @brief Calculates the selected nodes.
* @return Vector containing the NodeGraphicsObject pointers related to the selected nodes.
*/
std::vector<NodeGraphicsObject *> selectedNodes() const;
/**
* @brief Calculates the selected groups.
* @return Vector containing the GroupGraphicsObject pointers related to the selected groups.
*/
std::vector<GroupGraphicsObject *> selectedGroups() const;
/**
* @brief Adds a node to a group, if both node and group exists.
* @param nodeId Node's id.
* @param groupId Group's id.
*/
void addNodeToGroup(NodeId nodeId, GroupId groupId);
/**
* @brief Removes a node from a group, if the node exists and is within a group.
* @param nodeId Node's id.
*/
void removeNodeFromGroup(NodeId nodeId);
public:
/**
* @returns NodeGraphicsObject associated with the given nodeId.
* @returns nullptr when the object is not found.
*/
NodeGraphicsObject *nodeGraphicsObject(NodeId nodeId);
/**
* @returns ConnectionGraphicsObject corresponding to `connectionId`.
* @returns `nullptr` when the object is not found.
*/
ConnectionGraphicsObject *connectionGraphicsObject(ConnectionId connectionId);
Qt::Orientation orientation() const { return _orientation; }
void setOrientation(Qt::Orientation const orientation);
public:
/**
* Can @return an instance of the scene context menu in subclass.
* Default implementation returns `nullptr`.
*/
virtual QMenu *createSceneMenu(QPointF const scenePos);
/**
* @brief Freezes and unfreezes the model and connections of the selected nodes.
* @param isFreeze reference for freezing or unfreezing the model and connections of the selected nodes.
*/
void freezeModelAndConnections(bool isFreeze);
/**
* @brief Creates the default menu when a node is selected.
*/
QMenu *createStdMenu(QPointF const scenePos);
/**
* @brief Creates the menu when a group is selected.
* @param groupGo reference to the GroupGraphicsObject related to the selected group.
*/
QMenu *createGroupMenu(QPointF const scenePos, GroupGraphicsObject *groupGo);
Q_SIGNALS:
void modified(BasicGraphicsScene *);
void nodeMoved(NodeId const nodeId, QPointF const &newLocation);
void nodeClicked(NodeId const nodeId);
void nodeSelected(NodeId const nodeId);
void nodeDoubleClicked(NodeId const nodeId);
void nodeHovered(NodeId const nodeId, QPoint const screenPos);
void nodeHoverLeft(NodeId const nodeId);
void connectionHovered(ConnectionId const connectionId, QPoint const screenPos);
void connectionHoverLeft(ConnectionId const connectionId);
/// Signal allows showing custom context menu upon clicking a node.
void nodeContextMenu(NodeId const nodeId, QPointF const pos);
/// Signals to call Graphics View's zoomFit methods
void zoomFitAllClicked();
void zoomFitSelectedClicked();
private:
/**
* @brief Creates Node and Connection graphics objects.
*
* Function is used to populate an empty scene in the constructor. We
* perform depth-first AbstractGraphModel traversal. The connections are
* created by checking non-empty node `Out` ports.
*/
void traverseGraphAndPopulateGraphicsObjects();
/// Redraws adjacent nodes for given `connectionId`
void updateAttachedNodes(ConnectionId const connectionId, PortType const portType);
/**
* @brief Loads a JSON object that represents a node, with the option
* to keep the stored node id or generate a new one.
* @param nodeJson The JSON object representing a node.
* @param keepOriginalId If true, the loaded node will have the same id as the one stored in
* the file; otherwise, a new id will be generated
* @return A reference to the NodeGraphicsObject related to the loaded node.
*/
NodeGraphicsObject &loadNodeToMap(QJsonObject nodeJson, bool keepOriginalId = false);
/**
* @brief Loads a connection between nodes from a JSON file.
* @param connectionJson JSON object that stores the connection's endpoints.
* @param nodeIdMap Map of nodes (i.e. all possible endpoints).
*/
void loadConnectionToMap(QJsonObject const &connectionJson,
std::unordered_map<NodeId, NodeId> const &nodeIdMap);
public Q_SLOTS:
/// Slot called when the `connectionId` is erased form the AbstractGraphModel.
virtual void onConnectionDeleted(ConnectionId const connectionId);
/// Slot called when the `connectionId` is created in the AbstractGraphModel.
virtual void onConnectionCreated(ConnectionId const connectionId);
virtual void onNodeDeleted(NodeId const nodeId);
virtual void onNodeCreated(NodeId const nodeId);
virtual void onNodePositionUpdated(NodeId const nodeId);
virtual void onNodeUpdated(NodeId const nodeId);
virtual void onNodeClicked(NodeId const nodeId);
virtual void onModelReset();
/**
* @brief Slot called to trigger the copy command action.
*/
void onCopySelectedObjects() { undoStack().push(new CopyCommand(this)); }
/**
* @brief Slot called to trigger the delete command action.
*/
void onDeleteSelectedObjects() { undoStack().push(new DeleteCommand(this)); }
private:
AbstractGraphModel &_graphModel;
using UniqueNodeGraphicsObject = std::unique_ptr<NodeGraphicsObject>;
using UniqueConnectionGraphicsObject = std::unique_ptr<ConnectionGraphicsObject>;
using SharedGroup = std::shared_ptr<NodeGroup>;
std::unordered_map<NodeId, UniqueNodeGraphicsObject> _nodeGraphicsObjects;
std::unordered_map<ConnectionId, UniqueConnectionGraphicsObject> _connectionGraphicsObjects;
GroupId nextGroupId();
std::unordered_map<GroupId, SharedGroup> _groups{};
GroupId _nextGroupId{0};
std::unique_ptr<ConnectionGraphicsObject> _draftConnection;
std::unique_ptr<AbstractNodeGeometry> _nodeGeometry;
std::unique_ptr<AbstractNodePainter> _nodePainter;
std::unique_ptr<AbstractConnectionPainter> _connectionPainter;
bool _nodeDrag;
QUndoStack *_undoStack;
Qt::Orientation _orientation;
bool _groupingEnabled;
};
} // namespace QtNodes