#include "ApplicationSetup.hpp"
#include "TestGraphModel.hpp"
#include "UITestHelper.hpp"
#include <catch2/catch.hpp>
#include <QtNodes/internal/AbstractConnectionPainter.hpp>
#include <QtNodes/internal/AbstractNodePainter.hpp>
#include <QtNodes/internal/BasicGraphicsScene.hpp>
#include <QtNodes/internal/ConnectionGraphicsObject.hpp>
#include <QtNodes/internal/GraphicsView.hpp>
#include <QtNodes/internal/NodeGraphicsObject.hpp>
#include <QImage>
#include <QPainter>
#include <QPixmap>
#include <QTest>
using QtNodes::AbstractConnectionPainter;
using QtNodes::AbstractNodePainter;
using QtNodes::BasicGraphicsScene;
using QtNodes::ConnectionGraphicsObject;
using QtNodes::ConnectionId;
using QtNodes::GraphicsView;
using QtNodes::NodeGraphicsObject;
using QtNodes::NodeId;
using QtNodes::NodeRole;
class TestNodePainter : public AbstractNodePainter
{
public:
mutable int paintCallCount = 0;
mutable NodeId lastPaintedNodeId = 0;
void paint(QPainter *painter, NodeGraphicsObject &ngo) const override
{
paintCallCount++;
lastPaintedNodeId = ngo.nodeId();
painter->setBrush(Qt::blue);
painter->drawRect(0, 0, 100, 50);
}
};
class TestConnectionPainter : public AbstractConnectionPainter
{
public:
mutable int paintCallCount = 0;
void paint(QPainter *painter, ConnectionGraphicsObject const &cgo) const override
{
paintCallCount++;
QPen pen(Qt::red, 2);
painter->setPen(pen);
painter->drawLine(cgo.endPoint(QtNodes::PortType::Out), cgo.endPoint(QtNodes::PortType::In));
}
QPainterPath getPainterStroke(ConnectionGraphicsObject const &cgo) const override
{
QPainterPath path;
path.moveTo(cgo.endPoint(QtNodes::PortType::Out));
path.lineTo(cgo.endPoint(QtNodes::PortType::In));
QPainterPathStroker stroker;
stroker.setWidth(10.0);
return stroker.createStroke(path);
}
};
TEST_CASE("Custom painters registration", "[painters]")
{
auto app = applicationSetup();
TestGraphModel model;
BasicGraphicsScene scene(model);
SECTION("Scene has default painters initially")
{
AbstractNodePainter &nodePainter = scene.nodePainter();
AbstractConnectionPainter &connPainter = scene.connectionPainter();
CHECK(&nodePainter != nullptr);
CHECK(&connPainter != nullptr);
}
SECTION("Custom node painter can be registered")
{
auto customPainter = std::make_unique<TestNodePainter>();
TestNodePainter *painterPtr = customPainter.get();
scene.setNodePainter(std::move(customPainter));
AbstractNodePainter ¤tPainter = scene.nodePainter();
CHECK(¤tPainter == painterPtr);
}
SECTION("Custom connection painter can be registered")
{
auto customPainter = std::make_unique<TestConnectionPainter>();
TestConnectionPainter *painterPtr = customPainter.get();
scene.setConnectionPainter(std::move(customPainter));
AbstractConnectionPainter ¤tPainter = scene.connectionPainter();
CHECK(¤tPainter == painterPtr);
}
SECTION("Painter replacement")
{
auto painter1 = std::make_unique<TestNodePainter>();
auto painter2 = std::make_unique<TestNodePainter>();
TestNodePainter *ptr2 = painter2.get();
scene.setNodePainter(std::move(painter1));
scene.setNodePainter(std::move(painter2));
AbstractNodePainter ¤tPainter = scene.nodePainter();
CHECK(¤tPainter == ptr2);
}
}
TEST_CASE("Custom painter with scene operations", "[painters]")
{
auto app = applicationSetup();
auto model = std::make_shared<TestGraphModel>();
BasicGraphicsScene scene(*model);
auto customNodePainter = std::make_unique<TestNodePainter>();
TestNodePainter *nodePainterPtr = customNodePainter.get();
scene.setNodePainter(std::move(customNodePainter));
SECTION("Custom painter persists after node creation and view operations")
{
GraphicsView view(&scene);
view.resize(800, 600);
view.show();
REQUIRE(QTest::qWaitForWindowExposed(&view));
NodeId nodeId = model->addNode("TestNode");
model->setNodeData(nodeId, NodeRole::Position, QPointF(100, 100));
QCoreApplication::processEvents();
auto *ngo = scene.nodeGraphicsObject(nodeId);
REQUIRE(ngo != nullptr);
CHECK(&scene.nodePainter() == nodePainterPtr);
}
SECTION("Custom painter persists through multiple node lifecycle events")
{
NodeId node1 = model->addNode("TestNode1");
NodeId node2 = model->addNode("TestNode2");
model->setNodeData(node1, NodeRole::Position, QPointF(0, 0));
model->setNodeData(node2, NodeRole::Position, QPointF(200, 0));
QCoreApplication::processEvents();
model->deleteNode(node1);
QCoreApplication::processEvents();
CHECK(&scene.nodePainter() == nodePainterPtr);
}
}