diff --git a/sources/undocommand/mirrorselectioncommand.cpp b/sources/undocommand/mirrorselectioncommand.cpp index 46dd64078..0f32b0f44 100644 --- a/sources/undocommand/mirrorselectioncommand.cpp +++ b/sources/undocommand/mirrorselectioncommand.cpp @@ -83,15 +83,17 @@ MirrorSelectionCommand::MirrorSelectionCommand(const QList &elements, //The mirror is about the element's hotspot, which is often a //corner of the symbol: move it so that it stays where it was, - //centre on centre, and on the grid + //centre on centre. The move is snapped to the grid, not the new + //position: an element on the grid stays on it, one off the grid + //keeps its offset, and a second mirror moves it exactly back. QPointF centre = element->boundingRect().center(); centre = QTransform::fromScale(new_horizontal ? -1 : 1, new_vertical ? -1 : 1) .map(centre); centre = QTransform().rotate(element->rotation()).map(centre); const QPointF old_pos = element->pos(); - const QPointF new_pos = Diagram::snapToGrid( - element->mapToScene(element->boundingRect().center()) - centre); + const QPointF new_pos = old_pos + Diagram::snapToGrid( + element->mapToScene(element->boundingRect().center()) - centre - old_pos); if (new_pos != old_pos) new QPropertyUndoCommand(element, "pos", old_pos, new_pos, this); } diff --git a/tests/qttest/tst_scriptmirror.cpp b/tests/qttest/tst_scriptmirror.cpp index 338b5e19d..a75d10aa2 100644 --- a/tests/qttest/tst_scriptmirror.cpp +++ b/tests/qttest/tst_scriptmirror.cpp @@ -191,6 +191,48 @@ private slots: r.value(QStringLiteral("v")).toArray()); } + /** + Mirroring a symbol twice the same way puts it back where it was, + for every symbol of the project, including those that do not sit + on the grid. Before, the second mirror snapped such a symbol onto + the grid, a few pixels away. Which symbol mirrorBackAndSave() + picks changes from run to run, so this checks them all. + */ + void mirrorTwiceComesBack_data() + { + QTest::addColumn("vertical"); + QTest::newRow("horizontal") << false; + QTest::newRow("vertical") << true; + } + + void mirrorTwiceComesBack() + { + QFETCH(bool, vertical); + const QJsonObject r = run(script(QStringLiteral( + "var out = {count: 0, moved: []};\n" + "for (var f = 0; f < qet.folioCount(); f++) {\n" + " var els = qet.elementUuids(f);\n" + " for (var e = 0; e < els.length; e++) {\n" + " var before = JSON.stringify(terms(f, els[e]));\n" + " qet.mirrorElement(f, els[e], %1);\n" + " qet.mirrorElement(f, els[e], %1);\n" + " var after = JSON.stringify(terms(f, els[e]));\n" + " out.count++;\n" + " if (after !== before) out.moved.push(els[e] + ' ' + before + ' -> ' + after);\n" + " }\n" + "}\n" + "qet.log('PROBE ' + JSON.stringify(out));\n") + .arg(vertical ? QStringLiteral("true") : QStringLiteral("false"))), + QStringLiteral(QET_EXAMPLES_DIR "/perceuse.qet")); + + QVERIFY2(!r.isEmpty(), "the script logged nothing"); + QVERIFY(r.value(QStringLiteral("count")).toInt() > 0); + const QJsonArray moved = r.value(QStringLiteral("moved")).toArray(); + for (const QJsonValue &m : moved) + qWarning("moved: %s", qPrintable(m.toString())); + QCOMPARE(moved.size(), 0); + } + /** On a turned symbol a mirror of the folio is the other mirror of the symbol itself, and its rotation does not change: a label kept