#include "BasicGraphicsScene.hpp" #include "AbstractNodeGeometry.hpp" #include "ConnectionGraphicsObject.hpp" #include "ConnectionIdUtils.hpp" #include "DefaultHorizontalNodeGeometry.hpp" #include "DefaultNodePainter.hpp" #include "DefaultVerticalNodeGeometry.hpp" #include "GraphicsView.hpp" #include "NodeGraphicsObject.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace QtNodes { BasicGraphicsScene::BasicGraphicsScene(AbstractGraphModel &graphModel, QObject *parent) : QGraphicsScene(parent) , _graphModel(graphModel) , _nodeGeometry(std::make_unique(_graphModel)) , _nodePainter(std::make_unique()) , _nodeDrag(false) , _undoStack(new QUndoStack(this)) , _orientation(Qt::Horizontal) { setItemIndexMethod(QGraphicsScene::NoIndex); connect(&_graphModel, &AbstractGraphModel::connectionCreated, this, &BasicGraphicsScene::onConnectionCreated); connect(&_graphModel, &AbstractGraphModel::connectionDeleted, this, &BasicGraphicsScene::onConnectionDeleted); connect(&_graphModel, &AbstractGraphModel::nodeCreated, this, &BasicGraphicsScene::onNodeCreated); connect(&_graphModel, &AbstractGraphModel::nodeDeleted, this, &BasicGraphicsScene::onNodeDeleted); connect(&_graphModel, &AbstractGraphModel::nodePositionUpdated, this, &BasicGraphicsScene::onNodePositionUpdated); connect(&_graphModel, &AbstractGraphModel::nodeUpdated, this, &BasicGraphicsScene::onNodeUpdated); connect(this, &BasicGraphicsScene::nodeClicked, this, &BasicGraphicsScene::onNodeClicked); connect(&_graphModel, &AbstractGraphModel::modelReset, this, &BasicGraphicsScene::onModelReset); traverseGraphAndPopulateGraphicsObjects(); } BasicGraphicsScene::~BasicGraphicsScene() = default; AbstractGraphModel const &BasicGraphicsScene::graphModel() const { return _graphModel; } AbstractGraphModel &BasicGraphicsScene::graphModel() { return _graphModel; } AbstractNodeGeometry &BasicGraphicsScene::nodeGeometry() { return *_nodeGeometry; } AbstractNodePainter &BasicGraphicsScene::nodePainter() { return *_nodePainter; } void BasicGraphicsScene::setNodePainter(std::unique_ptr newPainter) { _nodePainter = std::move(newPainter); } QUndoStack &BasicGraphicsScene::undoStack() { return *_undoStack; } std::unique_ptr const &BasicGraphicsScene::makeDraftConnection( ConnectionId const incompleteConnectionId) { _draftConnection = std::make_unique(*this, incompleteConnectionId); _draftConnection->grabMouse(); return _draftConnection; } void BasicGraphicsScene::resetDraftConnection() { _draftConnection.reset(); } void BasicGraphicsScene::clearScene() { auto const &allNodeIds = graphModel().allNodeIds(); for (auto nodeId : allNodeIds) { graphModel().deleteNode(nodeId); } } NodeGraphicsObject *BasicGraphicsScene::nodeGraphicsObject(NodeId nodeId) { NodeGraphicsObject *ngo = nullptr; auto it = _nodeGraphicsObjects.find(nodeId); if (it != _nodeGraphicsObjects.end()) { ngo = it->second.get(); } return ngo; } ConnectionGraphicsObject *BasicGraphicsScene::connectionGraphicsObject(ConnectionId connectionId) { ConnectionGraphicsObject *cgo = nullptr; auto it = _connectionGraphicsObjects.find(connectionId); if (it != _connectionGraphicsObjects.end()) { cgo = it->second.get(); } return cgo; } void BasicGraphicsScene::setOrientation(Qt::Orientation const orientation) { if (_orientation != orientation) { _orientation = orientation; switch (_orientation) { case Qt::Horizontal: _nodeGeometry = std::make_unique(_graphModel); break; case Qt::Vertical: _nodeGeometry = std::make_unique(_graphModel); break; } onModelReset(); } } QMenu *BasicGraphicsScene::createSceneMenu(QPointF const scenePos) { Q_UNUSED(scenePos); return nullptr; } void BasicGraphicsScene::traverseGraphAndPopulateGraphicsObjects() { auto allNodeIds = _graphModel.allNodeIds(); // First create all the nodes. for (NodeId const nodeId : allNodeIds) { _nodeGraphicsObjects[nodeId] = std::make_unique(*this, nodeId); } // Then for each node check output connections and insert them. for (NodeId const nodeId : allNodeIds) { unsigned int nOutPorts = _graphModel.nodeData(nodeId, NodeRole::OutPortCount); for (PortIndex index = 0; index < nOutPorts; ++index) { auto const &outConnectionIds = _graphModel.connections(nodeId, PortType::Out, index); for (auto cid : outConnectionIds) { _connectionGraphicsObjects[cid] = std::make_unique(*this, cid); } } } } void BasicGraphicsScene::updateAttachedNodes(ConnectionId const connectionId, PortType const portType) { auto node = nodeGraphicsObject(getNodeId(portType, connectionId)); if (node) { node->update(); } } void BasicGraphicsScene::onConnectionDeleted(ConnectionId const connectionId) { auto it = _connectionGraphicsObjects.find(connectionId); if (it != _connectionGraphicsObjects.end()) { _connectionGraphicsObjects.erase(it); } // TODO: do we need it? if (_draftConnection && _draftConnection->connectionId() == connectionId) { _draftConnection.reset(); } updateAttachedNodes(connectionId, PortType::Out); updateAttachedNodes(connectionId, PortType::In); } void BasicGraphicsScene::onConnectionCreated(ConnectionId const connectionId) { _connectionGraphicsObjects[connectionId] = std::make_unique(*this, connectionId); updateAttachedNodes(connectionId, PortType::Out); updateAttachedNodes(connectionId, PortType::In); } void BasicGraphicsScene::onNodeDeleted(NodeId const nodeId) { auto it = _nodeGraphicsObjects.find(nodeId); if (it != _nodeGraphicsObjects.end()) { _nodeGraphicsObjects.erase(it); } } void BasicGraphicsScene::onNodeCreated(NodeId const nodeId) { _nodeGraphicsObjects[nodeId] = std::make_unique(*this, nodeId); } void BasicGraphicsScene::onNodePositionUpdated(NodeId const nodeId) { auto node = nodeGraphicsObject(nodeId); if (node) { node->setPos(_graphModel.nodeData(nodeId, NodeRole::Position).value()); node->update(); _nodeDrag = true; } } void BasicGraphicsScene::onNodeUpdated(NodeId const nodeId) { auto node = nodeGraphicsObject(nodeId); if (node) { node->setGeometryChanged(); _nodeGeometry->recomputeSize(nodeId); node->update(); node->moveConnections(); } } void BasicGraphicsScene::onNodeClicked(NodeId const nodeId) { if (_nodeDrag) Q_EMIT nodeMoved(nodeId, _graphModel.nodeData(nodeId, NodeRole::Position).value()); _nodeDrag = false; } void BasicGraphicsScene::onModelReset() { _connectionGraphicsObjects.clear(); _nodeGraphicsObjects.clear(); clear(); traverseGraphAndPopulateGraphicsObjects(); } } // namespace QtNodes