#include "ApplicationSetup.hpp"
#include "TestGraphModel.hpp"
#include <catch2/catch.hpp>
#include <QtNodes/internal/BasicGraphicsScene.hpp>
#include <QtNodes/internal/GraphicsView.hpp>
#include <QtNodes/internal/NodeGraphicsObject.hpp>
#include <QSignalSpy>
#include <QTest>
using QtNodes::BasicGraphicsScene;
using QtNodes::GraphicsView;
using QtNodes::NodeId;
using QtNodes::NodeRole;
TEST_CASE("GraphicsView scale range", "[zoom]")
{
auto app = applicationSetup();
auto model = std::make_shared<TestGraphModel>();
BasicGraphicsScene scene(*model);
GraphicsView view(&scene);
view.resize(800, 600);
view.show();
REQUIRE(QTest::qWaitForWindowExposed(&view));
SECTION("Default scale range allows unlimited zoom")
{
double initialScale = view.getScale();
CHECK(initialScale > 0);
for (int i = 0; i < 10; ++i) {
view.scaleUp();
}
CHECK(view.getScale() > initialScale);
}
SECTION("Scale range can be set with minimum and maximum")
{
view.setScaleRange(0.5, 2.0);
view.setupScale(1.0);
CHECK(view.getScale() == Approx(1.0).epsilon(0.01));
view.setupScale(0.1);
CHECK(view.getScale() >= 0.5);
view.setupScale(5.0);
CHECK(view.getScale() <= 2.0);
}
SECTION("Scale range can be set with ScaleRange struct")
{
GraphicsView::ScaleRange range{0.25, 4.0};
view.setScaleRange(range);
view.setupScale(0.1);
CHECK(view.getScale() >= 0.25);
view.setupScale(10.0);
CHECK(view.getScale() <= 4.0);
}
}
TEST_CASE("scaleChanged signal", "[zoom]")
{
auto app = applicationSetup();
auto model = std::make_shared<TestGraphModel>();
BasicGraphicsScene scene(*model);
GraphicsView view(&scene);
view.resize(800, 600);
view.show();
REQUIRE(QTest::qWaitForWindowExposed(&view));
SECTION("Signal emitted on scale change")
{
QSignalSpy spy(&view, &GraphicsView::scaleChanged);
view.scaleUp();
QCoreApplication::processEvents();
CHECK(spy.count() >= 1);
if (spy.count() > 0) {
QList<QVariant> arguments = spy.takeFirst();
double scale = arguments.at(0).toDouble();
CHECK(scale > 0);
}
}
SECTION("Signal emitted with correct scale value")
{
QSignalSpy spy(&view, &GraphicsView::scaleChanged);
view.setupScale(1.5);
QCoreApplication::processEvents();
CHECK(spy.count() >= 1);
if (spy.count() > 0) {
QList<QVariant> arguments = spy.takeLast();
double scale = arguments.at(0).toDouble();
CHECK(scale == Approx(1.5).epsilon(0.01));
}
}
}
TEST_CASE("Zoom fit operations", "[zoom]")
{
auto app = applicationSetup();
auto model = std::make_shared<TestGraphModel>();
BasicGraphicsScene scene(*model);
GraphicsView view(&scene);
view.resize(800, 600);
view.show();
REQUIRE(QTest::qWaitForWindowExposed(&view));
SECTION("zoomFitAll with nodes")
{
NodeId node1 = model->addNode("Node1");
model->setNodeData(node1, NodeRole::Position, QPointF(-500, -500));
NodeId node2 = model->addNode("Node2");
model->setNodeData(node2, NodeRole::Position, QPointF(500, 500));
QCoreApplication::processEvents();
double scaleBefore = view.getScale();
view.zoomFitAll();
QCoreApplication::processEvents();
double scaleAfter = view.getScale();
CHECK(scaleAfter > 0);
}
SECTION("zoomFitSelected with selected nodes")
{
NodeId node1 = model->addNode("Node1");
model->setNodeData(node1, NodeRole::Position, QPointF(0, 0));
NodeId node2 = model->addNode("Node2");
model->setNodeData(node2, NodeRole::Position, QPointF(200, 200));
QCoreApplication::processEvents();
auto *nodeGraphics = scene.nodeGraphicsObject(node1);
REQUIRE(nodeGraphics != nullptr);
nodeGraphics->setSelected(true);
QCoreApplication::processEvents();
view.zoomFitSelected();
QCoreApplication::processEvents();
CHECK(view.getScale() > 0);
}
SECTION("zoomFitAll with empty scene")
{
view.zoomFitAll();
QCoreApplication::processEvents();
CHECK(view.getScale() > 0);
}
SECTION("zoomFitSelected with no selection")
{
NodeId node1 = model->addNode("Node1");
model->setNodeData(node1, NodeRole::Position, QPointF(0, 0));
QCoreApplication::processEvents();
view.zoomFitSelected();
QCoreApplication::processEvents();
CHECK(view.getScale() > 0);
}
}