Merge branch 'port-c'

# Conflicts:
#	AGENTS.md
This commit is contained in:
ZacharyZhang-NY committed 2026-10-01 23:02:04 -04:00
commit cf0ec57095
4 files changed
+87 -4

No files matched your search

+52
View File
@@ -18,6 +18,8 @@ private slots:
void aPlacedOrDisabledMaskShowsAlone();
void theBadgeNamesTheMaskAndTakesItsOwnClicks();
void altClickOnTheThumbnailTogglesItAndOutlinesItWhite();
void theViewOutlastsUndoRedoAndTargetingTheMaskAgain();
void aPendingGradientElsewhereStaysOutOfTheView();
};
namespace {
@@ -294,5 +296,55 @@ void MaskAloneTests::altClickOnTheThumbnailTogglesItAndOutlinesItWhite()
QCOMPARE(accent, thumbnail->palette().color(QPalette::Highlight));
}
void MaskAloneTests::theViewOutlastsUndoRedoAndTargetingTheMaskAgain()
{
QUuid id;
const auto session = maskedSession(id);
session->toggleMaskAlone(id);
// A plain click on the shown mask targets it again.
session->selectLayerTarget(id, true);
QCOMPARE(session->maskAloneLayer().value().id, id);
// A stroke on it, undone and redone, keeps the view.
session->selectTool(NavigationTool::brush);
session->setBrushSettings(brush(20, 1, 0, 0, 0));
session->beginBrush(QPointF(50, 50));
QVERIFY(session->finishBrushImmediately());
QCOMPARE(session->history.undoName(), QString("Paint Mask"));
session->undo();
QCOMPARE(session->maskAloneLayer().value().id, id);
session->redo();
QCOMPARE(session->maskAloneLayer().value().id, id);
}
void MaskAloneTests::aPendingGradientElsewhereStaysOutOfTheView()
{
Canvas shown;
EditorSession &session = shown.session;
session.setForegroundColor(PaletteColor{0, 0, 1});
session.selectTool(NavigationTool::gradient);
// The layer's own pixels take a blue gradient, still pending.
session.selectLayerTarget(shown.id, false);
session.beginGradient(QPointF(0, 80));
session.moveGradient(std::nullopt, QPointF(200, 80));
QVERIFY(session.gradientEdit().has_value() && !session.gradientEdit()->raster->isMask);
session.toggleMaskAlone(shown.id);
// The commit is posted: the pixels' raster lingers, unshown.
QVERIFY(session.maskAloneLayer().has_value() && session.gradientEdit().has_value());
QVERIFY(gray(shown.at(QPointF(50, 50)), 255) && gray(shown.at(QPointF(150, 50)), 0));
QTRY_VERIFY(!session.gradientEdit().has_value());
// Another layer's mask gradient stays out of this view.
session.addBlankLayer();
const QUuid other = session.activeLayerID().value();
session.addLayerMask();
session.beginGradient(QPointF(0, 80));
session.moveGradient(std::nullopt, QPointF(200, 80));
QVERIFY(session.gradientEdit().has_value() && session.gradientEdit()->raster->isMask && session.gradientEdit()->raster->layer.id == other);
session.toggleMaskAlone(shown.id);
QCOMPARE(session.maskAloneLayer().value().id, shown.id);
QVERIFY(session.gradientEdit().has_value());
QVERIFY(gray(shown.at(QPointF(50, 50)), 255) && gray(shown.at(QPointF(150, 50)), 0));
QTRY_VERIFY(!session.gradientEdit().has_value());
}
QTEST_MAIN(MaskAloneTests)
#include "MaskAloneTests.moc"
+28
View File
@@ -8,6 +8,7 @@ private slots:
void eachRefusalSaysWhy();
void theGradientAndTheSmearSayWhyToo();
void aBusyEditorOrAnotherToolSaysNothing();
void theEarlierReasonWinsAtEverySeam();
};
namespace {
@@ -144,5 +145,32 @@ void PaintRefusalTests::aBusyEditorOrAnotherToolSaysNothing()
QCOMPARE(session->brushError(), std::optional<QString>("Earlier"));
}
void PaintRefusalTests::theEarlierReasonWinsAtEverySeam()
{
const auto session = makeSession();
const QUuid layer = session->activeLayerID().value();
// A hidden folder's pixels: the folder, not the hiding.
session->addGroup();
const QUuid folder = session->activeLayerID().value();
session->toggleLayerVisibility(folder);
QCOMPARE(pressed(*session), std::optional<QString>("“Folder 1” is a folder, which has no pixels of its own. Paint on a layer inside it, or on the "
"folder’s mask."));
session->toggleLayerVisibility(folder);
// A hidden layer's mask turned off: the hiding.
session->selectLayer(layer);
session->addLayerMask();
session->toggleLayerMask();
session->toggleLayerVisibility(layer);
QCOMPARE(pressed(*session), std::optional<QString>("“Layer 1” is hidden, or inside a hidden folder. Show it to paint on it."));
session->toggleLayerVisibility(layer);
session->toggleLayerMask();
// An adjustment's pixels in an empty selection: the adjustment.
session->addAdjustment(AdjustmentKind::levels);
session->setAdjustmentEditingID(std::nullopt);
session->selectLayerTarget(session->activeLayerID().value(), false);
emptySelection(*session);
QCOMPARE(pressed(*session), std::optional<QString>("“Levels” is an adjustment layer, with no pixels to paint. Paint on its mask instead."));
}
QTEST_GUILESS_MAIN(PaintRefusalTests)
#include "PaintRefusalTests.moc"
+3
View File
@@ -346,6 +346,9 @@ void SelectionCanvasTests::shiftKeepsMovedPixelsOnALine()
// Lengths, not signs: left beats a shorter down.
shown.move(QPointF(0, 50), Qt::ControlModifier | Qt::ShiftModifier);
QCOMPARE(box(), QRectF(-20, 20, 40, 40));
// And up beats a shorter right.
shown.move(QPointF(45, 0), Qt::ControlModifier | Qt::ShiftModifier);
QCOMPARE(box(), QRectF(20, -20, 40, 40));
// Without Shift both ways.
shown.move(QPointF(60, 55), Qt::ControlModifier);
QCOMPARE(box(), QRectF(40, 35, 40, 40));