Merge branch 'port-d'
# Conflicts: # AGENTS.md
This commit is contained in:
commit
8204e6a28b
14 files changed
+231
-101
No files matched your search
@@ -345,6 +345,12 @@ void BrushControlsTests::blurHasItsOwnRadius()
|
||||
QTest::keyClick(&field, Qt::Key_Return);
|
||||
QCOMPARE(session.brushSettings().blurRadius, 0.5);
|
||||
QCOMPARE(field.text(), QString("0.5"));
|
||||
// A number not finite takes 5, as Swift's binding.
|
||||
type(field, "inf");
|
||||
QTest::keyClick(&field, Qt::Key_Return);
|
||||
QCOMPARE(session.brushSettings().blurRadius, 5.0);
|
||||
type(field, "0");
|
||||
QTest::keyClick(&field, Qt::Key_Return);
|
||||
type(field, "abc");
|
||||
QTest::keyClick(&field, Qt::Key_Return);
|
||||
QCOMPARE(session.brushSettings().blurRadius, 0.5);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "MovePressFixtures.h"
|
||||
#include "UI/TransformInspector.h"
|
||||
#include <QLineEdit>
|
||||
|
||||
// The Move bar's value and a folder, under real presses.
|
||||
class MoveBarPressTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void aTypedValueThenAPressDragsTheActiveLayer();
|
||||
void ctrlKeepsAFolderAsAutoSelectPicksElsewhere();
|
||||
};
|
||||
|
||||
// Swift picks before focus moves: the active layer drags.
|
||||
void MoveBarPressTests::aTypedValueThenAPressDragsTheActiveLayer()
|
||||
{
|
||||
Canvas shown;
|
||||
EditorSession &session = shown.session;
|
||||
session.insert(filled(60, 60, qRgba(0, 0, 255, 255), "Blue"), QPointF(320, 20));
|
||||
const QUuid blue = session.activeLayerID().value();
|
||||
session.selectLayer(shown.red);
|
||||
session.setTransformAutoSelect(true);
|
||||
shown.window.resize(400, 350);
|
||||
TransformInspector bar(session, &shown.window);
|
||||
bar.setGeometry(0, 300, 400, 42);
|
||||
bar.show();
|
||||
QLineEdit *x = bar.findChild<QLineEdit *>(QStringLiteral("transformX"));
|
||||
QVERIFY(x);
|
||||
x->setFocus();
|
||||
QTRY_VERIFY(x->hasFocus());
|
||||
x->selectAll();
|
||||
QTest::keyClicks(x, "160");
|
||||
QVERIFY(session.transformEdit().value().fromFields);
|
||||
const int steps = session.history.undoCount();
|
||||
// A real press over Blue: focus moves, the canvas picks.
|
||||
QWindow *window = shown.window.windowHandle();
|
||||
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(330, 30));
|
||||
QTest::mouseMove(window, QPoint(337, 30));
|
||||
QTest::mouseMove(window, QPoint(343, 30));
|
||||
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(343, 30));
|
||||
QCoreApplication::processEvents();
|
||||
QVERIFY(!x->hasFocus());
|
||||
QCOMPARE(session.activeLayerID(), std::optional(shown.red));
|
||||
QCOMPARE(layerWith(session, blue).transform.origin, QPointF(290, -10));
|
||||
QCOMPARE(shown.origin(), QPointF(173, 100));
|
||||
// Two steps: the typed value, then the drag.
|
||||
QCOMPARE(session.history.undoCount(), steps + 2);
|
||||
session.undo();
|
||||
QCOMPARE(shown.origin(), QPointF(160, 100));
|
||||
}
|
||||
|
||||
void MoveBarPressTests::ctrlKeepsAFolderAsAutoSelectPicksElsewhere()
|
||||
{
|
||||
Canvas shown;
|
||||
EditorSession &session = shown.session;
|
||||
session.insert(filled(60, 60, qRgba(0, 0, 255, 255), "Blue"), QPointF(320, 20));
|
||||
const QUuid blue = session.activeLayerID().value();
|
||||
session.selectLayers({shown.red}, shown.red);
|
||||
session.groupSelectedLayers();
|
||||
const QUuid folder = session.activeLayerID().value();
|
||||
QVERIFY(folder != shown.red && session.transformsAsGroup());
|
||||
session.setTransformAutoSelect(true);
|
||||
// Over Blue, past the folder's box: Ctrl drags the folder.
|
||||
shown.drag(QPointF(330, 30), QPointF(343, 30), Qt::ControlModifier);
|
||||
QCOMPARE(session.activeLayerID(), std::optional(folder));
|
||||
QCOMPARE(shown.origin(), QPointF(163, 100));
|
||||
QCOMPARE(layerWith(session, blue).transform.origin, QPointF(290, -10));
|
||||
// Without Ctrl, Auto Select picks Blue.
|
||||
shown.drag(QPointF(330, 30), QPointF(343, 30));
|
||||
QCOMPARE(session.activeLayerID(), std::optional(blue));
|
||||
}
|
||||
|
||||
QTEST_MAIN(MoveBarPressTests)
|
||||
#include "MoveBarPressTests.moc"
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include "CanvasFixtures.h"
|
||||
|
||||
// A red square filling the canvas: view points are pixels.
|
||||
struct Canvas : Shown {
|
||||
QUuid red;
|
||||
Canvas() : Shown(QSize(400, 300), QSize(400, 300))
|
||||
{
|
||||
settle();
|
||||
session.zoom(1);
|
||||
session.insert(filled(100, 100, qRgba(255, 0, 0, 255), "Red"));
|
||||
red = session.activeLayerID().value();
|
||||
session.selectTool(NavigationTool::move);
|
||||
canvas->synchronizeDisplay();
|
||||
if (session.viewport.viewPoint(QPointF(0, 0), documentSize()) != QPointF(0, 0))
|
||||
throw std::runtime_error("the document does not fill the canvas");
|
||||
}
|
||||
QPointF origin() const { return layerWith(session, red).transform.origin; }
|
||||
void press(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier) { QTest::mousePress(canvas, Qt::LeftButton, modifiers, at.toPoint()); }
|
||||
void move(QPointF to, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
QMouseEvent event(QEvent::MouseMove, to, to, canvas->mapToGlobal(to.toPoint()), Qt::NoButton, Qt::LeftButton, modifiers);
|
||||
QApplication::sendEvent(canvas, &event);
|
||||
}
|
||||
void release(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier) { QTest::mouseRelease(canvas, Qt::LeftButton, modifiers, at.toPoint()); }
|
||||
void drag(QPointF from, QPointF to, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
press(from, modifiers);
|
||||
move((from + to) / 2, modifiers);
|
||||
move(to, modifiers);
|
||||
release(to, modifiers);
|
||||
}
|
||||
void click(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
press(at, modifiers);
|
||||
release(at, modifiers);
|
||||
}
|
||||
};
|
||||
@@ -1,48 +1,11 @@
|
||||
#include "CanvasFixtures.h"
|
||||
#include "MovePressFixtures.h"
|
||||
|
||||
// Swift's resize snapping on the canvas: handles, Ctrl, Shift.
|
||||
namespace {
|
||||
// The document fills the canvas: view points are pixels.
|
||||
struct Canvas : Shown {
|
||||
QUuid red;
|
||||
Canvas() : Shown(QSize(400, 300), QSize(400, 300))
|
||||
{
|
||||
settle();
|
||||
session.zoom(1);
|
||||
session.insert(filled(100, 100, qRgba(255, 0, 0, 255), "Red"));
|
||||
red = session.activeLayerID().value();
|
||||
session.selectTool(NavigationTool::move);
|
||||
canvas->synchronizeDisplay();
|
||||
if (session.viewport.viewPoint(QPointF(0, 0), documentSize()) != QPointF(0, 0))
|
||||
throw std::runtime_error("the document does not fill the canvas");
|
||||
}
|
||||
QPointF origin() const { return layerWith(session, red).transform.origin; }
|
||||
void press(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier) { QTest::mousePress(canvas, Qt::LeftButton, modifiers, at.toPoint()); }
|
||||
void move(QPointF to, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
QMouseEvent event(QEvent::MouseMove, to, to, canvas->mapToGlobal(to.toPoint()), Qt::NoButton, Qt::LeftButton, modifiers);
|
||||
QApplication::sendEvent(canvas, &event);
|
||||
}
|
||||
void release(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier) { QTest::mouseRelease(canvas, Qt::LeftButton, modifiers, at.toPoint()); }
|
||||
void drag(QPointF from, QPointF to, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
press(from, modifiers);
|
||||
move((from + to) / 2, modifiers);
|
||||
move(to, modifiers);
|
||||
release(to, modifiers);
|
||||
}
|
||||
void click(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
press(at, modifiers);
|
||||
release(at, modifiers);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class ResizeSnapCanvasTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void resizedEdgesSnapUnlessCtrl();
|
||||
void altResizesFromTheCentreAndSnaps();
|
||||
};
|
||||
|
||||
void ResizeSnapCanvasTests::resizedEdgesSnapUnlessCtrl()
|
||||
@@ -81,5 +44,21 @@ void ResizeSnapCanvasTests::resizedEdgesSnapUnlessCtrl()
|
||||
shown.release(QPointF(397, 349));
|
||||
}
|
||||
|
||||
// Swift's "resizing from the center with Option snaps too".
|
||||
void ResizeSnapCanvasTests::altResizesFromTheCentreAndSnaps()
|
||||
{
|
||||
Canvas shown;
|
||||
EditorSession &session = shown.session;
|
||||
session.setLocksTransformRatio(false);
|
||||
// Right edge to 396, left to 4: 396 snaps.
|
||||
shown.press(QPointF(250, 150), Qt::AltModifier);
|
||||
shown.move(QPointF(396, 150), Qt::AltModifier);
|
||||
QCOMPARE(session.transformEdit().value().draft, (LayerTransform{.origin = {0, 100}, .size = {400, 100}}));
|
||||
QCOMPARE(session.snapGuides, (SnapGuides{{400}, {}}));
|
||||
shown.release(QPointF(396, 150), Qt::AltModifier);
|
||||
QCOMPARE(layerWith(session, shown.red).transform, (LayerTransform{.origin = {0, 100}, .size = {400, 100}}));
|
||||
QCOMPARE(int(session.document().value().layers.size()), 1);
|
||||
}
|
||||
|
||||
QTEST_MAIN(ResizeSnapCanvasTests)
|
||||
#include "ResizeSnapCanvasTests.moc"
|
||||
@@ -41,6 +41,8 @@ private slots:
|
||||
void aTurnedLayerDoesntSnap();
|
||||
void eachEdgeSnapsOnItsOwn();
|
||||
void theDraggedSideAloneSnaps();
|
||||
void aLongDragSnapsTheEdgeItCarries();
|
||||
void aTieTakesTheLowEdge();
|
||||
void snappingOffOrAnotherDragLeavesThePoint();
|
||||
};
|
||||
|
||||
@@ -141,6 +143,31 @@ void ResizeSnapTests::theDraggedSideAloneSnaps()
|
||||
QCOMPARE(resized.session.snapGuides, (SnapGuides{{}, {150}}));
|
||||
}
|
||||
|
||||
// Dragged past the anchor, the moved edge is the left.
|
||||
void ResizeSnapTests::aLongDragSnapsTheEdgeItCarries()
|
||||
{
|
||||
Resized resized;
|
||||
const LayerTransform flipped = resized.resize(3, QPointF(110, 60), QPointF(-3, 60), false);
|
||||
QCOMPARE(flipped.origin.x(), 0.0);
|
||||
QCOMPARE(flipped.size.width(), 10.0);
|
||||
QVERIFY(flipped.flipX);
|
||||
QCOMPARE(resized.session.snapGuides, (SnapGuides{{0}, {}}));
|
||||
}
|
||||
|
||||
// Half a pixel from the anchor: one pixel, pointer mid-way.
|
||||
void ResizeSnapTests::aTieTakesTheLowEdge()
|
||||
{
|
||||
Resized resized;
|
||||
resized.place(QPointF(13, 150), QSizeF(20, 20));
|
||||
resized.session.selectLayer(resized.layer);
|
||||
const TransformDrag drag{layerWith(resized.session, resized.layer).transform, QPointF(110, 60), {TransformDrag::Kind::resize, 3}, std::nullopt};
|
||||
QCOMPARE(drag.updated(QPointF(10.5, 60), false, false).size.width(), 1.0);
|
||||
// The anchor's edge, which no step moves: the pointer stays.
|
||||
QCOMPARE(resized.session.snappedResizePoint(QPointF(10.5, 60), drag, false, {resized.layer}, 5, [&](QPointF to) { return drag.updated(to, false, false); }),
|
||||
QPointF(10.5, 60));
|
||||
QCOMPARE(resized.session.snapGuides, (SnapGuides{{13}, {}}));
|
||||
}
|
||||
|
||||
void ResizeSnapTests::snappingOffOrAnotherDragLeavesThePoint()
|
||||
{
|
||||
Resized resized;
|
||||
|
||||
@@ -230,6 +230,7 @@ compositor_test(TransformInspectorTests)
|
||||
compositor_test(TransformSnapTests)
|
||||
compositor_test(ResizeSnapTests)
|
||||
compositor_test(ResizeSnapCanvasTests)
|
||||
compositor_test(MoveBarPressTests)
|
||||
compositor_test(CursorTests)
|
||||
compositor_test(DistortCanvasTests)
|
||||
compositor_test(DistortMaskTests)
|
||||
|
||||
@@ -1,44 +1,6 @@
|
||||
#include "CanvasFixtures.h"
|
||||
#include "MovePressFixtures.h"
|
||||
|
||||
// The Move tool on the canvas: drags, handles, snapping.
|
||||
namespace {
|
||||
// The document fills the canvas: view points are pixels.
|
||||
struct Canvas : Shown {
|
||||
QUuid red;
|
||||
Canvas() : Shown(QSize(400, 300), QSize(400, 300))
|
||||
{
|
||||
settle();
|
||||
session.zoom(1);
|
||||
session.insert(filled(100, 100, qRgba(255, 0, 0, 255), "Red"));
|
||||
red = session.activeLayerID().value();
|
||||
session.selectTool(NavigationTool::move);
|
||||
canvas->synchronizeDisplay();
|
||||
if (session.viewport.viewPoint(QPointF(0, 0), documentSize()) != QPointF(0, 0))
|
||||
throw std::runtime_error("the document does not fill the canvas");
|
||||
}
|
||||
QPointF origin() const { return layerWith(session, red).transform.origin; }
|
||||
void press(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier) { QTest::mousePress(canvas, Qt::LeftButton, modifiers, at.toPoint()); }
|
||||
void move(QPointF to, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
QMouseEvent event(QEvent::MouseMove, to, to, canvas->mapToGlobal(to.toPoint()), Qt::NoButton, Qt::LeftButton, modifiers);
|
||||
QApplication::sendEvent(canvas, &event);
|
||||
}
|
||||
void release(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier) { QTest::mouseRelease(canvas, Qt::LeftButton, modifiers, at.toPoint()); }
|
||||
void drag(QPointF from, QPointF to, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
press(from, modifiers);
|
||||
move((from + to) / 2, modifiers);
|
||||
move(to, modifiers);
|
||||
release(to, modifiers);
|
||||
}
|
||||
void click(QPointF at, Qt::KeyboardModifiers modifiers = Qt::NoModifier)
|
||||
{
|
||||
press(at, modifiers);
|
||||
release(at, modifiers);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class TransformPressTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
|
||||
@@ -17,6 +17,7 @@ private slots:
|
||||
void liquifyStaysSharp();
|
||||
void liquifyDrawsFromTheUntouchedLayer();
|
||||
void smudgeLeavesOneFadingTrail();
|
||||
void aCommitKeepsATwentiethAndTheLastPoint();
|
||||
};
|
||||
|
||||
// Pushed across and back, the layer ends nearly unchanged.
|
||||
@@ -94,5 +95,23 @@ void WarpStrokeTests::smudgeLeavesOneFadingTrail()
|
||||
QVERIFY2(row.front() > row.back() + 20, qPrintable(QString("%1 to %2").arg(row.front()).arg(row.back())));
|
||||
}
|
||||
|
||||
// Swift's thinning: a twentieth of the brush apart, last kept.
|
||||
void WarpStrokeTests::aCommitKeepsATwentiethAndTheLastPoint()
|
||||
{
|
||||
QImage image = BrushRaster::context(80, 20, false);
|
||||
image.fill(Qt::red);
|
||||
WarpStroke stroke = warp(image, BlurToolMode::liquify, brush(100, 0.5, 0, 0, 0, 1));
|
||||
stroke.append(QPointF(0, 10));
|
||||
stroke.append(QPointF(51, 10));
|
||||
QCOMPARE(int(stroke.points().size()), 21);
|
||||
const std::vector<QPointF> kept = stroke.committedPoints();
|
||||
QCOMPARE(int(kept.size()), 8);
|
||||
QCOMPARE(kept.front(), stroke.points().front());
|
||||
QCOMPARE(kept[1], stroke.points()[3]);
|
||||
QCOMPARE(kept[6], stroke.points()[18]);
|
||||
// Two and a half from the previous, kept as last.
|
||||
QCOMPARE(kept.back(), QPointF(51, 10));
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(WarpStrokeTests)
|
||||
#include "WarpStrokeTests.moc"
|
||||
Reference in new issue
Block a user