Files
OmaPhoto/tests/LiveTextDoubleClickTests.cpp

189 lines
9.3 KiB
C++

#include "SelectionCanvasFixtures.h"
#include "Rendering/TextLayout.h"
#include <QFontMetricsF>
// Swift 1.2.10 (a5721b2): the Move tool's double click opens text.
namespace {
// Live text whose box covers `box`, made in one step.
QUuid addText(EditorSession &session, const QString &content, QRectF box)
{
session.selectTool(NavigationTool::type);
session.beginText(box);
TextDraft draft = session.textDraft().value();
draft.style.content = content;
if (!session.applyText(draft))
throw std::runtime_error("the text was refused");
return session.activeLayerID().value();
}
// Opaque red pixels, as a layer's.
QImage redPixels(int width, int height)
{
QImage image = BrushRaster::context(width, height, false);
image.fill(Qt::red);
return image;
}
// A document point on the canvas's view.
QPointF viewPoint(Canvas &shown, QPointF pixel)
{
return shown.session.viewport.viewPoint(pixel, shown.documentSize());
}
}
class LiveTextDoubleClickTests : public QObject {
Q_OBJECT
private slots:
void theTopmostShownTextOpens();
void otherPressesKeepTheMoveTool();
void anOpenDragAndPreviewEndFirst();
void theCaretWaitsAfterTheText();
void zoomAndTurnsPlaceThePress();
};
void LiveTextDoubleClickTests::theTopmostShownTextOpens()
{
// No display sync: the gesture opens the editor itself.
Canvas shown;
const QUuid lower = addText(shown.session, QStringLiteral("Lower"), QRectF(20, 20, 200, 100));
const QUuid upper = addText(shown.session, QStringLiteral("Upper"), QRectF(100, 60, 200, 100));
shown.session.addBlankLayer();
const QUuid blank = shown.session.activeLayerID().value();
shown.session.selectTool(NavigationTool::move);
// Where both lie, the upper opens, in the Type tool.
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(150, 90)).toPoint());
QCOMPARE(shown.session.tool(), NavigationTool::type);
QCOMPARE(shown.session.activeLayerID(), std::optional(upper));
QCOMPARE(shown.session.textDraft().value().layerID, std::optional(upper));
QVERIFY(shown.canvas->inlineTextEditor());
shown.session.cancelText();
// A hidden text is passed over for the one below.
shown.session.selectTool(NavigationTool::move);
shown.session.toggleLayerVisibility(upper);
shown.session.selectLayer(blank);
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(150, 90)).toPoint());
QCOMPARE(shown.session.textDraft().value().layerID, std::optional(lower));
QCOMPARE(shown.session.activeLayerID(), std::optional(lower));
shown.session.cancelText();
// A text in a hidden folder is passed over too.
shown.session.selectTool(NavigationTool::move);
shown.session.toggleLayerVisibility(upper);
shown.session.selectLayer(upper);
shown.session.groupSelectedLayers();
const QUuid folder = shown.session.activeLayerID().value();
QCOMPARE(layerWith(shown.session, upper).parentID, std::optional(folder));
shown.session.toggleLayerVisibility(folder);
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(150, 90)).toPoint());
QCOMPARE(shown.session.textDraft().value().layerID, std::optional(lower));
}
void LiveTextDoubleClickTests::anOpenDragAndPreviewEndFirst()
{
// On the text already active, Swift's commitTransform still cleans up.
Canvas shown;
const QUuid text = addText(shown.session, QStringLiteral("Words"), QRectF(20, 20, 200, 100));
shown.session.selectTool(NavigationTool::move);
shown.session.beginOpacityEdit();
shown.session.setLayerOpacity(0.5);
shown.session.previewBlendMode(LayerBlendMode::multiply, text);
QVERIFY(!shown.session.canUndo());
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(60, 60)).toPoint());
QCOMPARE(shown.session.textDraft().value().layerID, std::optional(text));
QVERIFY(shown.session.displayedBlendMode(layerWith(shown.session, text)) == LayerBlendMode::normal);
shown.session.cancelText();
QVERIFY(shown.session.canUndo());
}
void LiveTextDoubleClickTests::otherPressesKeepTheMoveTool()
{
Canvas shown;
QObject::connect(&shown.session, &EditorSession::changed, shown.canvas, [&shown] { shown.canvas->synchronizeDisplay(); });
const QUuid text = addText(shown.session, QStringLiteral("Words"), QRectF(20, 20, 200, 100));
shown.session.selectTool(NavigationTool::move);
// One click moves; it opens nothing.
shown.click(viewPoint(shown, QPointF(60, 60)));
QVERIFY(!shown.session.textDraft());
QCOMPARE(shown.session.tool(), NavigationTool::move);
// Off the text, a double click is the Move tool's.
shown.session.addPixelLayer(redPixels(60, 40), QPointF(260, 220), QStringLiteral("Red"), QStringLiteral("Add"));
const QUuid red = shown.session.activeLayerID().value();
shown.session.selectLayer(text);
shown.session.setTransformAutoSelect(true);
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(280, 240)).toPoint());
QVERIFY(!shown.session.textDraft());
QCOMPARE(shown.session.tool(), NavigationTool::move);
QCOMPARE(shown.session.activeLayerID(), std::optional(red));
// While a layer is renamed, layers rest: nothing opens.
shown.session.setRenamingLayerID(red);
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(60, 60)).toPoint());
QVERIFY(!shown.session.textDraft());
QCOMPARE(shown.session.activeLayerID(), std::optional(red));
shown.session.setRenamingLayerID(std::nullopt);
// A busy project opens nothing.
shown.session.setIsProjectBusy(true);
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(60, 60)).toPoint());
QVERIFY(!shown.session.textDraft());
shown.session.setIsProjectBusy(false);
// Other tools' double clicks are theirs.
shown.session.selectTool(NavigationTool::marquee);
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(60, 60)).toPoint());
QVERIFY(!shown.session.textDraft());
QCOMPARE(shown.session.activeLayerID(), std::optional(red));
}
void LiveTextDoubleClickTests::theCaretWaitsAfterTheText()
{
Canvas shown;
QObject::connect(&shown.session, &EditorSession::changed, shown.canvas, [&shown] { shown.canvas->synchronizeDisplay(); });
addText(shown.session, QStringLiteral("Word"), QRectF(20, 20, 300, 150));
shown.session.selectTool(NavigationTool::move);
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(60, 60)).toPoint());
QTRY_COMPARE(shown.canvas->inlineTextEditor()->caretPosition(), 4);
QCOMPARE(shown.canvas->inlineTextEditor()->anchor(), 4);
QTest::keyClicks(shown.canvas, QStringLiteral("X"));
QCOMPARE(shown.session.textDraft().value().style.content, QString("WordX"));
// A caret a click placed stays where it was put.
shown.session.cancelText();
shown.session.selectTool(NavigationTool::type);
const LayerTextStyle style = layerWith(shown.session, shown.session.activeLayerID().value()).liveText().value().style;
const QFontMetricsF metrics(TextLayout::font(style));
const double padding = LayerTextStyle::padding;
const QPointF at = viewPoint(shown, QPointF(20 + padding + metrics.horizontalAdvance(QStringLiteral("Wo")), 20 + padding + style.lineHeight() / 2));
shown.click(at);
QCOMPARE(shown.canvas->inlineTextEditor()->caretPosition(), 2);
QCoreApplication::processEvents();
QCOMPARE(shown.canvas->inlineTextEditor()->caretPosition(), 2);
QCOMPARE(shown.canvas->inlineTextEditor()->anchor(), 2);
// New text keeps its caret, despite opened text's queued step.
shown.session.cancelText();
shown.session.editActiveText();
shown.session.cancelText();
TextDraft fresh{.documentID = shown.session.document().value().id, .layerID = std::nullopt, .origin = QPointF(20, 200), .style = style, .selection = TextSpan()};
fresh.style.content = QStringLiteral("New");
shown.session.setTextDraft(fresh);
QCoreApplication::processEvents();
QCOMPARE(shown.session.textDraft().value().id, fresh.id);
QCOMPARE(shown.canvas->inlineTextEditor()->caretPosition(), 0);
QCOMPARE(shown.canvas->inlineTextEditor()->anchor(), 0);
}
void LiveTextDoubleClickTests::zoomAndTurnsPlaceThePress()
{
Canvas shown;
const QUuid text = addText(shown.session, QStringLiteral("Turned"), QRectF(100, 100, 160, 60));
rewrite(shown.session, [&](ProjectSnapshot &snapshot) { record(snapshot, text).transform.rotation = 90; });
shown.session.selectTool(NavigationTool::move);
shown.session.zoom(1.5);
QVERIFY(shown.session.viewport.viewPoint(QPointF(180, 70), shown.documentSize()) != QPointF(180, 70));
// Outside the turned box, inside the upright one: nothing.
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(110, 130)).toPoint());
QVERIFY(!shown.session.textDraft());
shown.release(viewPoint(shown, QPointF(110, 130)));
// Inside the turned box only: the text opens.
QTest::mouseDClick(shown.canvas, Qt::LeftButton, Qt::NoModifier, viewPoint(shown, QPointF(180, 70)).toPoint());
QCOMPARE(shown.session.textDraft().value().layerID, std::optional(text));
}
QTEST_MAIN(LiveTextDoubleClickTests)
#include "LiveTextDoubleClickTests.moc"