Files
OmaPhoto/tests/CameraRawCanvasTests.cpp
T

225 lines
9.1 KiB
C++

#include "MenuFixtures.h"
#include "SelectionCanvasFixtures.h"
#include "UI/CameraRawControls.h"
#include "UI/FilterSheet.h"
#include <QLabel>
#include <QToolButton>
// Camera Raw's tools on the canvas, and its docked panel.
namespace {
struct Raw : Canvas {
Raw()
{
QImage image(400, 300, QImage::Format_RGBA8888_Premultiplied);
image.fill(QColor(200, 120, 60));
for (int y = 0; y < 300; ++y)
for (int x = 200; x < 400; ++x)
image.setPixelColor(x, y, QColor(60, 180, 90));
session.insert(ImportedImage(image, image, QStringLiteral("Two")));
session.beginFilter(FilterKind::cameraRaw);
canvas->synchronizeDisplay();
}
const CameraRawPanel &panel() const { return session.filterEdit().value().rawPanel; }
const CameraRawSettings &raw() const { return session.filterEdit().value().settings.cameraRaw; }
void arm(const std::function<void(CameraRawPanel &)> &change)
{
CameraRawPanel copy = panel();
change(copy);
session.setCameraRawPanel(copy);
canvas->synchronizeDisplay();
}
};
QWidget *topLevel(const QString &name)
{
for (QWidget *widget : QApplication::topLevelWidgets()) {
if (widget->objectName() == name && widget->isVisible())
return widget;
}
return nullptr;
}
}
class CameraRawCanvasTests : public QObject {
Q_OBJECT
private slots:
void aHoverReadsThePixelAndLeavingClearsIt();
void eachEyedropperSamplesAndThePressGoesNoFurther();
void aGuideIsDrawnByDragging();
void aTargetedDragEndsOnReleaseOrWhenTheReleaseIsLost();
void samplingToolsShowTheEyedropperAndSpacePans();
void thePanelDocksInTheWindowAndCancelsLikeAPanel();
};
void CameraRawCanvasTests::aHoverReadsThePixelAndLeavingClearsIt()
{
Raw raw;
raw.hover(QPointF(50, 50));
QCOMPARE(raw.panel().readout, std::optional(std::array{200, 120, 60}));
raw.hover(QPointF(300, 50));
QCOMPARE(raw.panel().readout, std::optional(std::array{60, 180, 90}));
// A drag reads nothing: Swift's mouseMoved alone reads.
raw.move(QPointF(50, 50));
QCOMPARE(raw.panel().readout, std::optional(std::array{60, 180, 90}));
QEvent leave(QEvent::Leave);
QApplication::sendEvent(raw.canvas, &leave);
QVERIFY(!raw.panel().readout);
// Another filter reads nothing.
raw.session.cancelFilter();
raw.session.beginFilter(FilterKind::gaussianBlur);
raw.hover(QPointF(50, 50));
QVERIFY(!raw.session.filterEdit().value().rawPanel.readout);
}
void CameraRawCanvasTests::eachEyedropperSamplesAndThePressGoesNoFurther()
{
Raw raw;
raw.arm([](CameraRawPanel &panel) { panel.samplesWhiteBalance = true; });
raw.click(QPointF(50, 50));
QVERIFY(raw.raw().temperature != 0 && !raw.session.lassoDraft() && !raw.session.selection());
raw.arm([](CameraRawPanel &panel) {
panel.samplesWhiteBalance = false;
panel.samplesPointColor = true;
});
raw.click(QPointF(300, 50));
QCOMPARE(raw.raw().mixer.points.size(), size_t(1));
QVERIFY(std::abs(raw.raw().mixer.points[0].hue - 135) < 1);
raw.arm([](CameraRawPanel &panel) {
panel.samplesPointColor = false;
panel.samplesDefringe = true;
});
raw.click(QPointF(300, 50));
QCOMPARE(raw.raw().optics.greenAmount, 50.0);
QVERIFY(!raw.session.selection());
}
void CameraRawCanvasTests::aGuideIsDrawnByDragging()
{
Raw raw;
raw.arm([](CameraRawPanel &panel) { panel.drawingGeometryGuide = true; });
raw.press(QPointF(40, 30));
QVERIFY(raw.panel().guideDraft);
raw.move(QPointF(360, 60));
raw.release(QPointF(360, 60));
QVERIFY(!raw.panel().guideDraft);
QCOMPARE(raw.raw().geometry.guides.size(), size_t(1));
const CameraRawGeometryGuide guide = raw.raw().geometry.guides[0];
QVERIFY(std::abs(guide.startX - 0.1) < 1e-6 && std::abs(guide.startY - 0.1) < 1e-6);
QVERIFY(std::abs(guide.endX - 0.9) < 1e-6 && std::abs(guide.endY - 0.2) < 1e-6);
QVERIFY(raw.raw().geometry.upright == CameraRawUprightMode::guided);
// A lost release: the next move without the button commits.
raw.press(QPointF(100, 30));
raw.move(QPointF(100, 270));
raw.hover(QPointF(120, 270));
QVERIFY(!raw.panel().guideDraft);
QCOMPARE(raw.raw().geometry.guides.size(), size_t(2));
}
void CameraRawCanvasTests::aTargetedDragEndsOnReleaseOrWhenTheReleaseIsLost()
{
Raw raw;
raw.arm([](CameraRawPanel &panel) { panel.targetsCurve = true; });
raw.press(QPointF(50, 150));
QVERIFY(raw.panel().drag);
raw.move(QPointF(50, 50));
QCOMPARE(raw.raw().curve.lights, 35.0);
raw.release(QPointF(50, 50));
QVERIFY(!raw.panel().drag);
// A move after the release changes nothing.
raw.move(QPointF(50, 0));
QCOMPARE(raw.raw().curve.lights, 35.0);
raw.press(QPointF(50, 150));
raw.hover(QPointF(50, 100));
QVERIFY(!raw.panel().drag);
QCOMPARE(raw.raw().curve.lights, 35.0);
}
void CameraRawCanvasTests::samplingToolsShowTheEyedropperAndSpacePans()
{
Raw raw;
const QCursor eyedropper = CanvasView::eyedropperCursor(raw.canvas->devicePixelRatio());
raw.hover(QPointF(50, 50));
QVERIFY(!raw.shows(eyedropper));
for (const auto &change : std::vector<std::function<void(CameraRawPanel &)>>{
[](CameraRawPanel &panel) { panel.samplesWhiteBalance = true; }, [](CameraRawPanel &panel) { panel.samplesPointColor = true; },
[](CameraRawPanel &panel) { panel.samplesDefringe = true; }, [](CameraRawPanel &panel) { panel.drawingGeometryGuide = true; }}) {
raw.arm([](CameraRawPanel &panel) { panel = CameraRawPanel(); });
raw.hover(QPointF(50, 50));
QVERIFY(!raw.shows(eyedropper));
raw.arm(change);
raw.hover(QPointF(52, 50));
QVERIFY(raw.shows(eyedropper));
}
// With Space held a press pans and samples nothing.
raw.arm([](CameraRawPanel &panel) {
panel = CameraRawPanel();
panel.samplesWhiteBalance = true;
});
raw.canvas->setFocus();
QTest::keyPress(raw.canvas, Qt::Key_Space);
raw.press(QPointF(50, 50));
raw.release(QPointF(50, 50));
QTest::keyRelease(raw.canvas, Qt::Key_Space);
QCOMPARE(raw.raw().temperature, 0.0);
}
void CameraRawCanvasTests::thePanelDocksInTheWindowAndCancelsLikeAPanel()
{
Bar bar;
bar.window.resize(1200, 800);
bar.window.show();
QVERIFY(QTest::qWaitForWindowActive(&bar.window));
bar.session().createDocument(8, 8, true);
QImage image(8, 8, QImage::Format_RGBA8888_Premultiplied);
image.fill(QColor(200, 120, 60));
bar.session().insert(ImportedImage(image, image, QStringLiteral("Warm")));
// A floating filter panel, moved, then closed.
bar.session().beginFilter(FilterKind::gaussianBlur);
QWidget *floating = topLevel(QStringLiteral("filterPanel"));
QVERIFY(floating);
floating->move(40, 60);
const QPoint parked = floating->pos();
bar.session().cancelFilter();
// Camera Raw fills the window's right slot instead.
bar.session().beginFilter(FilterKind::cameraRaw);
auto *dock = bar.window.findChild<QWidget *>(QStringLiteral("panelDock"));
QVERIFY(dock && dock->isVisible() && !topLevel(QStringLiteral("filterPanel")));
QCOMPARE(dock->width(), 440);
auto *docked = dock->findChild<QWidget *>(QStringLiteral("filterPanel"));
QVERIFY(docked && !docked->isWindow() && docked->findChild<CameraRawControls *>());
QCOMPARE(docked->findChild<QLabel *>(QStringLiteral("dockedTitle"))->text(), QString("Camera Raw Filter"));
QTRY_VERIFY(docked->height() > 600);
// Shown, it takes the keys, Swift's makeKeyAndOrderFront.
QVERIFY(docked->hasFocus());
// At the right edge; a taller window, a taller panel.
QCOMPARE(dock->mapTo(&bar.window, dock->rect().topRight()).x(), bar.window.centralWidget()->mapTo(&bar.window, bar.window.centralWidget()->rect().topRight()).x());
const int height = docked->height();
bar.window.resize(1200, 900);
QTRY_COMPARE(docked->height(), height + 100);
// A sample hands the keys back to the docked panel.
auto *canvas = bar.window.findChild<CanvasView *>();
CameraRawPanel panel = bar.session().filterEdit().value().rawPanel;
panel.samplesWhiteBalance = true;
bar.session().setCameraRawPanel(panel);
canvas->setFocus();
const QPointF at = bar.session().viewport.viewPoint(QPointF(4, 4), QSizeF(8, 8));
QTest::mouseClick(canvas, Qt::LeftButton, {}, at.toPoint());
QVERIFY(docked->isAncestorOf(QApplication::focusWidget()) || QApplication::focusWidget() == docked);
// Its close button cancels; Escape inside it too.
docked->findChild<QToolButton *>(QStringLiteral("dockedClose"))->click();
QVERIFY(!bar.session().filterEdit() && !dock->isVisible());
bar.session().beginFilter(FilterKind::cameraRaw);
QVERIFY(dock->isVisible());
docked->setFocus();
QTest::keyClick(docked, Qt::Key_Escape);
QVERIFY(!bar.session().filterEdit() && !dock->isVisible());
// The floating filters reopen where they were left.
bar.session().beginFilter(FilterKind::gaussianBlur);
QCOMPARE(topLevel(QStringLiteral("filterPanel"))->pos(), parked);
QVERIFY(!dock->isVisible());
bar.session().cancelFilter();
}
QTEST_MAIN(CameraRawCanvasTests)
#include "CameraRawCanvasTests.moc"