diff --git a/include/QtNodes/internal/BasicGraphicsScene.hpp b/include/QtNodes/internal/BasicGraphicsScene.hpp index 94f94823f..48de6e00f 100644 --- a/include/QtNodes/internal/BasicGraphicsScene.hpp +++ b/include/QtNodes/internal/BasicGraphicsScene.hpp @@ -115,6 +115,10 @@ class NODE_EDITOR_PUBLIC BasicGraphicsScene : public QGraphicsScene void nodeHoverLeft(NodeId const nodeId); + void connectionSelected(ConnectionId const connectionId); + + void connectionDoubleClicked(ConnectionId const connectionId); + void connectionHovered(ConnectionId const connectionId, QPoint const screenPos); void connectionHoverLeft(ConnectionId const connectionId); diff --git a/include/QtNodes/internal/ConnectionGraphicsObject.hpp b/include/QtNodes/internal/ConnectionGraphicsObject.hpp index f0e569d74..d103b2dc2 100644 --- a/include/QtNodes/internal/ConnectionGraphicsObject.hpp +++ b/include/QtNodes/internal/ConnectionGraphicsObject.hpp @@ -1,7 +1,12 @@ #pragma once -#include +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif +#include +#include +#include #include #include @@ -48,6 +53,7 @@ class ConnectionGraphicsObject : public QGraphicsObject QPointF in() const { return _in; } std::pair pointsC1C2() const; + QPolygonF arrow(QPainterPath target, qreal delta = M_PI / 8) const; void setEndPoint(PortType portType, QPointF const &point); @@ -69,6 +75,8 @@ class ConnectionGraphicsObject : public QGraphicsObject void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; + void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; diff --git a/include/QtNodes/internal/ConnectionIdUtils.hpp b/include/QtNodes/internal/ConnectionIdUtils.hpp index 7f70a1b4b..34be7af76 100644 --- a/include/QtNodes/internal/ConnectionIdUtils.hpp +++ b/include/QtNodes/internal/ConnectionIdUtils.hpp @@ -132,7 +132,7 @@ inline QJsonObject toJson(ConnectionId const &connId) connJson["outNodeId"] = static_cast(connId.outNodeId); connJson["outPortIndex"] = static_cast(connId.outPortIndex); - connJson["intNodeId"] = static_cast(connId.inNodeId); + connJson["inNodeId"] = static_cast(connId.inNodeId); connJson["inPortIndex"] = static_cast(connId.inPortIndex); return connJson; @@ -142,7 +142,7 @@ inline ConnectionId fromJson(QJsonObject const &connJson) { ConnectionId connId{static_cast(connJson["outNodeId"].toInt(InvalidNodeId)), static_cast(connJson["outPortIndex"].toInt(InvalidPortIndex)), - static_cast(connJson["intNodeId"].toInt(InvalidNodeId)), + static_cast((connJson.contains("inNodeId") ? connJson["inNodeId"] : connJson["intNodeId"]).toInt(InvalidNodeId)), static_cast(connJson["inPortIndex"].toInt(InvalidPortIndex))}; return connId; diff --git a/include/QtNodes/internal/ConnectionStyle.hpp b/include/QtNodes/internal/ConnectionStyle.hpp index b718bcfae..69d1afa10 100644 --- a/include/QtNodes/internal/ConnectionStyle.hpp +++ b/include/QtNodes/internal/ConnectionStyle.hpp @@ -37,6 +37,7 @@ class NODE_EDITOR_PUBLIC ConnectionStyle : public Style float pointDiameter() const; bool useDataDefinedColors() const; + bool withArrow() const; private: QColor ConstructionColor; @@ -50,5 +51,6 @@ class NODE_EDITOR_PUBLIC ConnectionStyle : public Style float PointDiameter; bool UseDataDefinedColors; + bool WithArrow; }; } // namespace QtNodes diff --git a/include/QtNodes/internal/DataFlowGraphModel.hpp b/include/QtNodes/internal/DataFlowGraphModel.hpp index 268800202..8c529d7d0 100644 --- a/include/QtNodes/internal/DataFlowGraphModel.hpp +++ b/include/QtNodes/internal/DataFlowGraphModel.hpp @@ -25,11 +25,18 @@ class NODE_EDITOR_PUBLIC DataFlowGraphModel : public AbstractGraphModel, public QPointF pos; }; + enum CtlOption { + None, + NoSceneMenu, + }; + public: DataFlowGraphModel(std::shared_ptr registry); std::shared_ptr dataModelRegistry() { return _registry; } + virtual bool is(CtlOption ctl); + public: std::unordered_set allNodeIds() const override; @@ -130,6 +137,8 @@ private Q_SLOTS: std::unordered_set _connectivity; mutable std::unordered_map _nodeGeometryData; + + mutable std::unordered_map> _styles; }; } // namespace QtNodes diff --git a/include/QtNodes/internal/NodeGraphicsObject.hpp b/include/QtNodes/internal/NodeGraphicsObject.hpp index ef042f769..e39b2719a 100644 --- a/include/QtNodes/internal/NodeGraphicsObject.hpp +++ b/include/QtNodes/internal/NodeGraphicsObject.hpp @@ -50,6 +50,8 @@ class NodeGraphicsObject : public QGraphicsObject /// Repaints the node once with reacting ports. void reactToConnection(ConnectionGraphicsObject const *cgo); + void nodeFlagsUpdated(NodeId const nodeId); + protected: void paint(QPainter *painter, QStyleOptionGraphicsItem const *option, @@ -73,10 +75,11 @@ class NodeGraphicsObject : public QGraphicsObject void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; + private: void embedQWidget(); - void setLockedState(); + void setLockedState(NodeFlags flags); private: NodeId _nodeId; diff --git a/include/QtNodes/internal/NodeStyle.hpp b/include/QtNodes/internal/NodeStyle.hpp index 5eca74924..a2aff540a 100644 --- a/include/QtNodes/internal/NodeStyle.hpp +++ b/include/QtNodes/internal/NodeStyle.hpp @@ -42,6 +42,7 @@ class NODE_EDITOR_PUBLIC NodeStyle : public Style QColor WarningColor; QColor ErrorColor; + QColor FillColor; float PenWidth; float HoveredPenWidth; @@ -49,5 +50,6 @@ class NODE_EDITOR_PUBLIC NodeStyle : public Style float ConnectionPointDiameter; float Opacity; + float CornerRadius; }; } // namespace QtNodes diff --git a/include/QtNodes/internal/Style.hpp b/include/QtNodes/internal/Style.hpp index f878083e2..4f8262692 100644 --- a/include/QtNodes/internal/Style.hpp +++ b/include/QtNodes/internal/Style.hpp @@ -7,6 +7,60 @@ #include #include +#define X_VALUE_EXISTS(v) \ + (v.type() != QJsonValue::Undefined && v.type() != QJsonValue::Null) + +#define X_STYLE_READ_COLOR(values, variable) \ + { \ + auto valueRef = values[#variable]; \ + if (X_VALUE_EXISTS(valueRef)) { \ + if (valueRef.isArray()) { \ + auto colorArray = valueRef.toArray(); \ + std::vector rgb; \ + rgb.reserve(3); \ + int alpha = 255; \ + for (auto it = colorArray.begin(); it != colorArray.end(); ++it) { \ + rgb.push_back((*it).toInt()); \ + } \ + if (colorArray.size() > 3) \ + alpha = colorArray[3].toInt(); \ + variable = QColor(rgb[0], rgb[1], rgb[2], alpha); \ + } else { \ + variable = QColor(valueRef.toString()); \ + } \ + } \ + } + +#define X_STYLE_WRITE_COLOR(values, variable) \ + { \ + values[#variable] = variable.name(QColor::HexArgb); \ + } + +#define X_STYLE_READ_FLOAT(values, variable) \ + { \ + auto valueRef = values[#variable]; \ + if (X_VALUE_EXISTS(valueRef)) \ + variable = valueRef.toDouble(); \ + } + +#define X_STYLE_WRITE_FLOAT(values, variable) \ + { \ + values[#variable] = variable; \ + } + +#define X_STYLE_READ_BOOL(values, variable) \ + { \ + auto valueRef = values[#variable]; \ + if (X_VALUE_EXISTS(valueRef)) \ + variable = valueRef.toBool(); \ + } + +#define X_STYLE_WRITE_BOOL(values, variable) \ + { \ + values[#variable] = variable; \ + } + + namespace QtNodes { class Style // : public QObject diff --git a/resources/DefaultStyle.json b/resources/DefaultStyle.json index da8dfe84c..7b1a181e1 100644 --- a/resources/DefaultStyle.json +++ b/resources/DefaultStyle.json @@ -18,13 +18,15 @@ "FilledConnectionPointColor": "cyan", "ErrorColor": "red", "WarningColor": [128, 128, 0], + "FillColor": "none", "PenWidth": 1.0, "HoveredPenWidth": 1.5, "ConnectionPointDiameter": 8.0, - "Opacity": 0.8 + "Opacity": 0.8, + "CornerRadius": 3.0 }, "ConnectionStyle": { "ConstructionColor": "gray", @@ -37,6 +39,7 @@ "ConstructionLineWidth": 2.0, "PointDiameter": 10.0, - "UseDataDefinedColors": false + "UseDataDefinedColors": false, + "WithArrow": false } } diff --git a/src/ConnectionGraphicsObject.cpp b/src/ConnectionGraphicsObject.cpp index 6a871c0ed..86f3392e7 100644 --- a/src/ConnectionGraphicsObject.cpp +++ b/src/ConnectionGraphicsObject.cpp @@ -203,6 +203,9 @@ void ConnectionGraphicsObject::paint(QPainter *painter, void ConnectionGraphicsObject::mousePressEvent(QGraphicsSceneMouseEvent *event) { + if (!isSelected()) { + Q_EMIT nodeScene()->connectionSelected(connectionId()); + } QGraphicsItem::mousePressEvent(event); } @@ -263,6 +266,13 @@ void ConnectionGraphicsObject::mouseReleaseEvent(QGraphicsSceneMouseEvent *event } } +void ConnectionGraphicsObject::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + QGraphicsItem::mouseDoubleClickEvent(event); + Q_EMIT nodeScene()->connectionDoubleClicked(connectionId()); +} + + void ConnectionGraphicsObject::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { _connectionState.setHovered(true); @@ -377,4 +387,23 @@ std::pair ConnectionGraphicsObject::pointsC1C2Vertical() const return std::make_pair(c1, c2); } +QPolygonF ConnectionGraphicsObject::arrow(QPainterPath target, qreal delta) const +{ + QPointF const &in = endPoint(PortType::In); + QPointF const &out = endPoint(PortType::In); + + QPointF first = in, second, third; + int z = 16; + qreal angle = target.angleAtPercent((z*2.0/3)*cos(delta) / target.length()) * M_PI / 180.0; + if ((nodeScene()->orientation() == Qt::Horizontal && in.x() < out.x()) + || (nodeScene()->orientation() == Qt::Vertical && in.y() < out.y()) ) { + z = -16; + } + second = QPointF(in.x() - z * cos(angle - delta), in.y() + z * sin(angle - delta)); + third = QPointF(in.x() - z * cos(angle + delta), in.y() + z * sin(angle + delta)); + QPolygonF poly; + poly << first << second << third << first; + return poly; +} + } // namespace QtNodes diff --git a/src/ConnectionPainter.cpp b/src/ConnectionPainter.cpp index 97002ef79..d760dc46b 100644 --- a/src/ConnectionPainter.cpp +++ b/src/ConnectionPainter.cpp @@ -177,8 +177,8 @@ static void drawNormalLine(QPainter *painter, ConnectionGraphicsObject const &cg p.setWidth(lineWidth); bool const selected = cgo.isSelected(); - auto cubic = cubicPath(cgo); + if (useGradientColor) { painter->setBrush(Qt::NoBrush); @@ -225,6 +225,19 @@ static void drawNormalLine(QPainter *painter, ConnectionGraphicsObject const &cg painter->drawPath(cubic); } + + if (connectionStyle.withArrow()) { + bool hovered = cgo.connectionState().hovered(); + painter->setBrush(selected + ? connectionStyle.selectedHaloColor() + : (hovered + ? connectionStyle.hoveredColor() + : normalColorIn)); + painter->setPen(Qt::NoPen); + + QPolygonF poly = cgo.arrow(cubic); + painter->drawPolygon(poly); + } } void ConnectionPainter::paint(QPainter *painter, ConnectionGraphicsObject const &cgo) diff --git a/src/ConnectionStyle.cpp b/src/ConnectionStyle.cpp index 812658989..b8968e2d3 100644 --- a/src/ConnectionStyle.cpp +++ b/src/ConnectionStyle.cpp @@ -27,9 +27,8 @@ ConnectionStyle::ConnectionStyle() loadJsonFile(":DefaultStyle.json"); } -ConnectionStyle::ConnectionStyle(QString jsonText) +ConnectionStyle::ConnectionStyle(QString jsonText): ConnectionStyle() { - loadJsonFile(":DefaultStyle.json"); loadJsonText(jsonText); } @@ -40,103 +39,42 @@ void ConnectionStyle::setConnectionStyle(QString jsonText) StyleCollection::setConnectionStyle(style); } -#ifdef STYLE_DEBUG -#define CONNECTION_STYLE_CHECK_UNDEFINED_VALUE(v, variable) \ - { \ - if (v.type() == QJsonValue::Undefined || v.type() == QJsonValue::Null) \ - qWarning() << "Undefined value for parameter:" << #variable; \ - } -#else -#define CONNECTION_STYLE_CHECK_UNDEFINED_VALUE(v, variable) -#endif - -#define CONNECTION_VALUE_EXISTS(v) \ - (v.type() != QJsonValue::Undefined && v.type() != QJsonValue::Null) - -#define CONNECTION_STYLE_READ_COLOR(values, variable) \ - { \ - auto valueRef = values[#variable]; \ - CONNECTION_STYLE_CHECK_UNDEFINED_VALUE(valueRef, variable) \ - if (CONNECTION_VALUE_EXISTS(valueRef)) { \ - if (valueRef.isArray()) { \ - auto colorArray = valueRef.toArray(); \ - std::vector rgb; \ - rgb.reserve(3); \ - for (auto it = colorArray.begin(); it != colorArray.end(); ++it) { \ - rgb.push_back((*it).toInt()); \ - } \ - variable = QColor(rgb[0], rgb[1], rgb[2]); \ - } else { \ - variable = QColor(valueRef.toString()); \ - } \ - } \ - } - -#define CONNECTION_STYLE_WRITE_COLOR(values, variable) \ - { \ - values[#variable] = variable.name(); \ - } - -#define CONNECTION_STYLE_READ_FLOAT(values, variable) \ - { \ - auto valueRef = values[#variable]; \ - CONNECTION_STYLE_CHECK_UNDEFINED_VALUE(valueRef, variable) \ - if (CONNECTION_VALUE_EXISTS(valueRef)) \ - variable = valueRef.toDouble(); \ - } - -#define CONNECTION_STYLE_WRITE_FLOAT(values, variable) \ - { \ - values[#variable] = variable; \ - } - -#define CONNECTION_STYLE_READ_BOOL(values, variable) \ - { \ - auto valueRef = values[#variable]; \ - CONNECTION_STYLE_CHECK_UNDEFINED_VALUE(valueRef, variable) \ - if (CONNECTION_VALUE_EXISTS(valueRef)) \ - variable = valueRef.toBool(); \ - } - -#define CONNECTION_STYLE_WRITE_BOOL(values, variable) \ - { \ - values[#variable] = variable; \ - } - void ConnectionStyle::loadJson(QJsonObject const &json) { QJsonValue nodeStyleValues = json["ConnectionStyle"]; QJsonObject obj = nodeStyleValues.toObject(); - CONNECTION_STYLE_READ_COLOR(obj, ConstructionColor); - CONNECTION_STYLE_READ_COLOR(obj, NormalColor); - CONNECTION_STYLE_READ_COLOR(obj, SelectedColor); - CONNECTION_STYLE_READ_COLOR(obj, SelectedHaloColor); - CONNECTION_STYLE_READ_COLOR(obj, HoveredColor); + X_STYLE_READ_COLOR(obj, ConstructionColor); + X_STYLE_READ_COLOR(obj, NormalColor); + X_STYLE_READ_COLOR(obj, SelectedColor); + X_STYLE_READ_COLOR(obj, SelectedHaloColor); + X_STYLE_READ_COLOR(obj, HoveredColor); - CONNECTION_STYLE_READ_FLOAT(obj, LineWidth); - CONNECTION_STYLE_READ_FLOAT(obj, ConstructionLineWidth); - CONNECTION_STYLE_READ_FLOAT(obj, PointDiameter); + X_STYLE_READ_FLOAT(obj, LineWidth); + X_STYLE_READ_FLOAT(obj, ConstructionLineWidth); + X_STYLE_READ_FLOAT(obj, PointDiameter); - CONNECTION_STYLE_READ_BOOL(obj, UseDataDefinedColors); + X_STYLE_READ_BOOL(obj, UseDataDefinedColors); + X_STYLE_READ_BOOL(obj, WithArrow); } QJsonObject ConnectionStyle::toJson() const { QJsonObject obj; - CONNECTION_STYLE_WRITE_COLOR(obj, ConstructionColor); - CONNECTION_STYLE_WRITE_COLOR(obj, NormalColor); - CONNECTION_STYLE_WRITE_COLOR(obj, SelectedColor); - CONNECTION_STYLE_WRITE_COLOR(obj, SelectedHaloColor); - CONNECTION_STYLE_WRITE_COLOR(obj, HoveredColor); + X_STYLE_WRITE_COLOR(obj, ConstructionColor); + X_STYLE_WRITE_COLOR(obj, NormalColor); + X_STYLE_WRITE_COLOR(obj, SelectedColor); + X_STYLE_WRITE_COLOR(obj, SelectedHaloColor); + X_STYLE_WRITE_COLOR(obj, HoveredColor); - CONNECTION_STYLE_WRITE_FLOAT(obj, LineWidth); - CONNECTION_STYLE_WRITE_FLOAT(obj, ConstructionLineWidth); - CONNECTION_STYLE_WRITE_FLOAT(obj, PointDiameter); + X_STYLE_WRITE_FLOAT(obj, LineWidth); + X_STYLE_WRITE_FLOAT(obj, ConstructionLineWidth); + X_STYLE_WRITE_FLOAT(obj, PointDiameter); - CONNECTION_STYLE_WRITE_BOOL(obj, UseDataDefinedColors); + X_STYLE_WRITE_BOOL(obj, UseDataDefinedColors); + X_STYLE_WRITE_BOOL(obj, WithArrow); QJsonObject root; root["ConnectionStyle"] = obj; @@ -203,3 +141,8 @@ bool ConnectionStyle::useDataDefinedColors() const { return UseDataDefinedColors; } + +bool ConnectionStyle::withArrow() const +{ + return WithArrow; +} diff --git a/src/DataFlowGraphModel.cpp b/src/DataFlowGraphModel.cpp index a5ba8734f..4942e5fe6 100644 --- a/src/DataFlowGraphModel.cpp +++ b/src/DataFlowGraphModel.cpp @@ -20,6 +20,11 @@ std::unordered_set DataFlowGraphModel::allNodeIds() const return nodeIds; } +bool DataFlowGraphModel::is(CtlOption ctl) { + Q_UNUSED(ctl); + return false; +} + std::unordered_set DataFlowGraphModel::allConnectionIds(NodeId const nodeId) const { std::unordered_set result; @@ -212,7 +217,11 @@ QVariant DataFlowGraphModel::nodeData(NodeId nodeId, NodeRole role) const case NodeRole::Style: { auto style = StyleCollection::nodeStyle(); - result = style.toJson().toVariantMap(); + QVariantMap m = style.toJson().toVariantMap(); + if (!_styles.empty() && _styles.find(nodeId) != _styles.end()) { + m.insert(QVariantMap{{"NodeStyle",_styles.at(nodeId).get()->toVariantMap()}}); + } + result = m; } break; case NodeRole::InternalData: { @@ -282,6 +291,7 @@ bool DataFlowGraphModel::setNodeData(NodeId nodeId, NodeRole role, QVariant valu break; case NodeRole::Style: + _styles[nodeId] = std::make_shared(value.value()); break; case NodeRole::InternalData: @@ -402,6 +412,8 @@ bool DataFlowGraphModel::deleteNode(NodeId const nodeId) _nodeGeometryData.erase(nodeId); _models.erase(nodeId); + if (!_styles.empty() && _styles.find(nodeId) != _styles.end()) + _styles.erase(nodeId); Q_EMIT nodeDeleted(nodeId); @@ -482,6 +494,11 @@ void DataFlowGraphModel::loadNode(QJsonObject const &nodeJson) setNodeData(restoredNodeId, NodeRole::Position, pos); + if (nodeJson.contains("style")) { + QJsonObject styleJson = nodeJson["style"].toObject(); + setNodeData(restoredNodeId, NodeRole::Style, styleJson); + } + _models[restoredNodeId]->load(internalDataJson); } else { throw std::logic_error(std::string("No registered model with name ") diff --git a/src/DataFlowGraphicsScene.cpp b/src/DataFlowGraphicsScene.cpp index e300ba86e..614138cb6 100644 --- a/src/DataFlowGraphicsScene.cpp +++ b/src/DataFlowGraphicsScene.cpp @@ -59,6 +59,9 @@ std::vector DataFlowGraphicsScene::selectedNodes() const QMenu *DataFlowGraphicsScene::createSceneMenu(QPointF const scenePos) { + if (_graphModel.is(DataFlowGraphModel::CtlOption::NoSceneMenu)) { + return nullptr; + } QMenu *modelMenu = new QMenu(); // Add filterbox to the context menu diff --git a/src/DefaultNodePainter.cpp b/src/DefaultNodePainter.cpp index 8febe4cb1..10b099785 100644 --- a/src/DefaultNodePainter.cpp +++ b/src/DefaultNodePainter.cpp @@ -45,7 +45,6 @@ void DefaultNodePainter::drawNodeRect(QPainter *painter, NodeGraphicsObject &ngo QSize size = geometry.size(nodeId); QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style)); - NodeStyle nodeStyle(json.object()); auto color = ngo.isSelected() ? nodeStyle.SelectedBoundaryColor : nodeStyle.NormalBoundaryColor; @@ -58,19 +57,22 @@ void DefaultNodePainter::drawNodeRect(QPainter *painter, NodeGraphicsObject &ngo painter->setPen(p); } - QLinearGradient gradient(QPointF(0.0, 0.0), QPointF(2.0, size.height())); + if (nodeStyle.FillColor.value()) { + painter->setBrush(nodeStyle.FillColor); + } else { + QLinearGradient gradient(QPointF(0.0, 0.0), QPointF(2.0, size.height())); - gradient.setColorAt(0.0, nodeStyle.GradientColor0); - gradient.setColorAt(0.10, nodeStyle.GradientColor1); - gradient.setColorAt(0.90, nodeStyle.GradientColor2); - gradient.setColorAt(1.0, nodeStyle.GradientColor3); + gradient.setColorAt(0.0, nodeStyle.GradientColor0); + gradient.setColorAt(0.10, nodeStyle.GradientColor1); + gradient.setColorAt(0.90, nodeStyle.GradientColor2); + gradient.setColorAt(1.0, nodeStyle.GradientColor3); - painter->setBrush(gradient); + painter->setBrush(gradient); + } QRectF boundary(0, 0, size.width(), size.height()); - double const radius = 3.0; - + double const radius = nodeStyle.CornerRadius >= 0 ? nodeStyle.CornerRadius : 3.0; painter->drawRoundedRect(boundary, radius, radius); } diff --git a/src/GraphicsView.cpp b/src/GraphicsView.cpp index 1ffa8f58b..aed482f30 100644 --- a/src/GraphicsView.cpp +++ b/src/GraphicsView.cpp @@ -151,7 +151,8 @@ void GraphicsView::centerScene() if (scene()) { scene()->setSceneRect(QRectF()); - QRectF sceneRect = scene()->sceneRect(); + QRectF rect = scene()->itemsBoundingRect(); + QRectF sceneRect = QRectF(0, 0, rect.left() * 2 + rect.width(), rect.top() * 2 + rect.height()); if (sceneRect.width() > this->rect().width() || sceneRect.height() > this->rect().height()) { fitInView(sceneRect, Qt::KeepAspectRatio); diff --git a/src/NodeGraphicsObject.cpp b/src/NodeGraphicsObject.cpp index aa727cdaa..ee9a81c33 100644 --- a/src/NodeGraphicsObject.cpp +++ b/src/NodeGraphicsObject.cpp @@ -29,7 +29,7 @@ NodeGraphicsObject::NodeGraphicsObject(BasicGraphicsScene &scene, NodeId nodeId) setFlag(QGraphicsItem::ItemDoesntPropagateOpacityToChildren, true); setFlag(QGraphicsItem::ItemIsFocusable, true); - setLockedState(); + setLockedState(_graphModel.nodeFlags(_nodeId)); setCacheMode(QGraphicsItem::DeviceCoordinateCache); @@ -60,10 +60,19 @@ NodeGraphicsObject::NodeGraphicsObject(BasicGraphicsScene &scene, NodeId nodeId) setPos(pos); - connect(&_graphModel, &AbstractGraphModel::nodeFlagsUpdated, [this](NodeId const nodeId) { - if (_nodeId == nodeId) - setLockedState(); - }); + connect(&_graphModel, &AbstractGraphModel::nodeFlagsUpdated, this, &NodeGraphicsObject::nodeFlagsUpdated); +} + +void NodeGraphicsObject::nodeFlagsUpdated(NodeId const nodeId) { + if (_nodeId != nodeId) + return; + QObject *obj = sender(); + if (!obj) + return; + AbstractGraphModel *ptr = qobject_cast(obj); + if (!ptr) + return; + setLockedState(ptr->nodeFlags(nodeId)); } AbstractGraphModel &NodeGraphicsObject::graphModel() const @@ -108,10 +117,8 @@ void NodeGraphicsObject::embedQWidget() } } -void NodeGraphicsObject::setLockedState() +void NodeGraphicsObject::setLockedState(NodeFlags flags) { - NodeFlags flags = _graphModel.nodeFlags(_nodeId); - bool const locked = flags.testFlag(NodeFlag::Locked); setFlag(QGraphicsItem::ItemIsMovable, !locked); @@ -215,7 +222,8 @@ void NodeGraphicsObject::mousePressEvent(QGraphicsSceneMouseEvent *event) ConnectionId const incompleteConnectionId = makeIncompleteConnectionId(_nodeId, portToCheck, portIndex); - + if (!_graphModel.detachPossible(incompleteConnectionId)) + continue; nodeScene()->makeDraftConnection(incompleteConnectionId); } } @@ -226,7 +234,9 @@ void NodeGraphicsObject::mousePressEvent(QGraphicsSceneMouseEvent *event) _nodeState.setResizing(hit); } - QGraphicsObject::mousePressEvent(event); + if (!event->isAccepted()) { + QGraphicsObject::mousePressEvent(event); + } if (isSelected()) { Q_EMIT nodeScene()->nodeSelected(_nodeId); @@ -287,7 +297,9 @@ void NodeGraphicsObject::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { _nodeState.setResizing(false); - QGraphicsObject::mouseReleaseEvent(event); + if (!event->isAccepted()) { + QGraphicsObject::mouseReleaseEvent(event); + } // position connections precisely after fast node move moveConnections(); diff --git a/src/NodeStyle.cpp b/src/NodeStyle.cpp index a82bf8fe2..f215d7e80 100644 --- a/src/NodeStyle.cpp +++ b/src/NodeStyle.cpp @@ -27,12 +27,12 @@ NodeStyle::NodeStyle() loadJsonFile(":DefaultStyle.json"); } -NodeStyle::NodeStyle(QString jsonText) +NodeStyle::NodeStyle(QString jsonText): NodeStyle() { loadJsonText(jsonText); } -NodeStyle::NodeStyle(QJsonObject const &json) +NodeStyle::NodeStyle(QJsonObject const &json): NodeStyle() { loadJson(json); } @@ -44,100 +44,60 @@ void NodeStyle::setNodeStyle(QString jsonText) StyleCollection::setNodeStyle(style); } -#ifdef STYLE_DEBUG -#define NODE_STYLE_CHECK_UNDEFINED_VALUE(v, variable) \ - { \ - if (v.type() == QJsonValue::Undefined || v.type() == QJsonValue::Null) \ - qWarning() << "Undefined value for parameter:" << #variable; \ - } -#else -#define NODE_STYLE_CHECK_UNDEFINED_VALUE(v, variable) -#endif - -#define NODE_STYLE_READ_COLOR(values, variable) \ - { \ - auto valueRef = values[#variable]; \ - NODE_STYLE_CHECK_UNDEFINED_VALUE(valueRef, variable) \ - if (valueRef.isArray()) { \ - auto colorArray = valueRef.toArray(); \ - std::vector rgb; \ - rgb.reserve(3); \ - for (auto it = colorArray.begin(); it != colorArray.end(); ++it) { \ - rgb.push_back((*it).toInt()); \ - } \ - variable = QColor(rgb[0], rgb[1], rgb[2]); \ - } else { \ - variable = QColor(valueRef.toString()); \ - } \ - } - -#define NODE_STYLE_WRITE_COLOR(values, variable) \ - { \ - values[#variable] = variable.name(); \ - } - -#define NODE_STYLE_READ_FLOAT(values, variable) \ - { \ - auto valueRef = values[#variable]; \ - NODE_STYLE_CHECK_UNDEFINED_VALUE(valueRef, variable) \ - variable = valueRef.toDouble(); \ - } - -#define NODE_STYLE_WRITE_FLOAT(values, variable) \ - { \ - values[#variable] = variable; \ - } - void NodeStyle::loadJson(QJsonObject const &json) { QJsonValue nodeStyleValues = json["NodeStyle"]; QJsonObject obj = nodeStyleValues.toObject(); - NODE_STYLE_READ_COLOR(obj, NormalBoundaryColor); - NODE_STYLE_READ_COLOR(obj, SelectedBoundaryColor); - NODE_STYLE_READ_COLOR(obj, GradientColor0); - NODE_STYLE_READ_COLOR(obj, GradientColor1); - NODE_STYLE_READ_COLOR(obj, GradientColor2); - NODE_STYLE_READ_COLOR(obj, GradientColor3); - NODE_STYLE_READ_COLOR(obj, ShadowColor); - NODE_STYLE_READ_COLOR(obj, FontColor); - NODE_STYLE_READ_COLOR(obj, FontColorFaded); - NODE_STYLE_READ_COLOR(obj, ConnectionPointColor); - NODE_STYLE_READ_COLOR(obj, FilledConnectionPointColor); - NODE_STYLE_READ_COLOR(obj, WarningColor); - NODE_STYLE_READ_COLOR(obj, ErrorColor); - - NODE_STYLE_READ_FLOAT(obj, PenWidth); - NODE_STYLE_READ_FLOAT(obj, HoveredPenWidth); - NODE_STYLE_READ_FLOAT(obj, ConnectionPointDiameter); - - NODE_STYLE_READ_FLOAT(obj, Opacity); + X_STYLE_READ_COLOR(obj, NormalBoundaryColor); + X_STYLE_READ_COLOR(obj, SelectedBoundaryColor); + X_STYLE_READ_COLOR(obj, GradientColor0); + X_STYLE_READ_COLOR(obj, GradientColor1); + X_STYLE_READ_COLOR(obj, GradientColor2); + X_STYLE_READ_COLOR(obj, GradientColor3); + X_STYLE_READ_COLOR(obj, ShadowColor); + X_STYLE_READ_COLOR(obj, FontColor); + X_STYLE_READ_COLOR(obj, FontColorFaded); + X_STYLE_READ_COLOR(obj, ConnectionPointColor); + X_STYLE_READ_COLOR(obj, FilledConnectionPointColor); + X_STYLE_READ_COLOR(obj, WarningColor); + X_STYLE_READ_COLOR(obj, ErrorColor); + X_STYLE_READ_COLOR(obj, FillColor); + + X_STYLE_READ_FLOAT(obj, PenWidth); + X_STYLE_READ_FLOAT(obj, HoveredPenWidth); + X_STYLE_READ_FLOAT(obj, ConnectionPointDiameter); + + X_STYLE_READ_FLOAT(obj, Opacity); + X_STYLE_READ_FLOAT(obj, CornerRadius); } QJsonObject NodeStyle::toJson() const { QJsonObject obj; - NODE_STYLE_WRITE_COLOR(obj, NormalBoundaryColor); - NODE_STYLE_WRITE_COLOR(obj, SelectedBoundaryColor); - NODE_STYLE_WRITE_COLOR(obj, GradientColor0); - NODE_STYLE_WRITE_COLOR(obj, GradientColor1); - NODE_STYLE_WRITE_COLOR(obj, GradientColor2); - NODE_STYLE_WRITE_COLOR(obj, GradientColor3); - NODE_STYLE_WRITE_COLOR(obj, ShadowColor); - NODE_STYLE_WRITE_COLOR(obj, FontColor); - NODE_STYLE_WRITE_COLOR(obj, FontColorFaded); - NODE_STYLE_WRITE_COLOR(obj, ConnectionPointColor); - NODE_STYLE_WRITE_COLOR(obj, FilledConnectionPointColor); - NODE_STYLE_WRITE_COLOR(obj, WarningColor); - NODE_STYLE_WRITE_COLOR(obj, ErrorColor); - - NODE_STYLE_WRITE_FLOAT(obj, PenWidth); - NODE_STYLE_WRITE_FLOAT(obj, HoveredPenWidth); - NODE_STYLE_WRITE_FLOAT(obj, ConnectionPointDiameter); - - NODE_STYLE_WRITE_FLOAT(obj, Opacity); + X_STYLE_WRITE_COLOR(obj, NormalBoundaryColor); + X_STYLE_WRITE_COLOR(obj, SelectedBoundaryColor); + X_STYLE_WRITE_COLOR(obj, GradientColor0); + X_STYLE_WRITE_COLOR(obj, GradientColor1); + X_STYLE_WRITE_COLOR(obj, GradientColor2); + X_STYLE_WRITE_COLOR(obj, GradientColor3); + X_STYLE_WRITE_COLOR(obj, ShadowColor); + X_STYLE_WRITE_COLOR(obj, FontColor); + X_STYLE_WRITE_COLOR(obj, FontColorFaded); + X_STYLE_WRITE_COLOR(obj, ConnectionPointColor); + X_STYLE_WRITE_COLOR(obj, FilledConnectionPointColor); + X_STYLE_WRITE_COLOR(obj, WarningColor); + X_STYLE_WRITE_COLOR(obj, ErrorColor); + X_STYLE_WRITE_COLOR(obj, FillColor); + + X_STYLE_WRITE_FLOAT(obj, PenWidth); + X_STYLE_WRITE_FLOAT(obj, HoveredPenWidth); + X_STYLE_WRITE_FLOAT(obj, ConnectionPointDiameter); + + X_STYLE_WRITE_FLOAT(obj, Opacity); + X_STYLE_WRITE_FLOAT(obj, CornerRadius); QJsonObject root; root["NodeStyle"] = obj;