OmaPhoto 1.0.0: the Linux port of Compositor
Release / deb (push) Canceled after 0s
Release / rpm (push) Canceled after 0s
Release / arch (push) Canceled after 0s
Release / publish (push) Canceled after 0s

A layered image editor for Linux and Omarchy, ported from Compositor
(github.com/robbietilton/Compositor), whose Swift source is its
specification. It reads and writes Compositor's .comp projects.

Packages for Ubuntu, Fedora and Arch come from the release workflow;
scripts/install/ holds one install script per distribution family,
and flake.nix serves NixOS.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
雷电芽衣andClaude committed 2026-09-26 00:44:52 -04:00
commit c864304695
564 files changed
+100804

No files matched your search

+163
View File
@@ -0,0 +1,163 @@
#include "DialogDesk.h"
#include "IO/ProjectController.h"
#include "UI/CanvasSizeSheet.h"
#include "UI/ColorPickerSheet.h"
#include "UI/ImageSizeSheet.h"
#include <QDialog>
#include <QPushButton>
#include <QtTest>
// The controller's Canvas Size and Image Size: sheet, resize, step.
class ProjectResizeTests : public QObject {
Q_OBJECT
private slots:
void theCanvasSizeSheetResizesTheCanvasAsOneStep();
void aCancelledOrRefusedSheetChangesNothing();
void theImageSizeSheetScalesThePixelsAsOneStep();
void aResizeThatFailsIsExplained();
};
namespace {
struct Desk {
EditorSession session;
ProjectController controller{session};
QWidget window;
bool done = false;
Desk()
{
session.createDocument(100, 50);
session.insert(ImportedImage(QImage(10, 10, QImage::Format_RGBA8888_Premultiplied), QImage(), "Image"), QPointF(45, 25));
window.resize(600, 400);
window.show();
controller.window = &window;
}
QDialog &dialog()
{
auto *shown = window.findChild<QDialog *>();
if (!shown)
throw std::runtime_error("no sheet shown");
return *shown;
}
// Typed, then Return: the field commits, then the default button.
void type(const char *name, const QString &text)
{
auto *field = dialog().findChild<PickerField *>(QString::fromLatin1(name));
if (!field)
throw std::runtime_error(std::string("no field named ") + name);
field->setFocus();
field->selectAll();
QTest::keyClicks(field, text);
QTest::keyClick(field, Qt::Key_Return);
}
std::function<void()> finished()
{
done = false;
return [this] { done = true; };
}
};
}
void ProjectResizeTests::theCanvasSizeSheetResizesTheCanvasAsOneStep()
{
Desk desk;
const int steps = desk.session.history.undoCount();
desk.controller.canvasSize(desk.finished());
// The sheet holds the window; the project is busy meanwhile.
QVERIFY(desk.session.isProjectBusy());
QCOMPARE(desk.dialog().windowTitle(), QString("Canvas Size"));
QVERIFY(desk.dialog().isVisible() && desk.dialog().windowModality() == Qt::WindowModal);
QCOMPARE(desk.dialog().minimumSize(), desk.dialog().maximumSize());
QVERIFY(desk.dialog().findChild<CanvasSizeSheet *>());
desk.type("canvasWidth", "200");
QTRY_VERIFY(desk.done);
QCOMPARE(desk.session.document().value().width, 200);
QCOMPARE(desk.session.document().value().height, 50);
// Centred: the layer moves half the growth to the right.
QCOMPARE(desk.session.activeLayer().value().origin(), QPointF(90, 20));
QCOMPARE(desk.session.history.undoCount(), steps + 1);
QCOMPARE(desk.session.history.undoName(), QString("Canvas Size"));
QVERIFY(!desk.session.isProjectBusy());
QTRY_VERIFY(!desk.window.findChild<QDialog *>());
}
void ProjectResizeTests::aCancelledOrRefusedSheetChangesNothing()
{
Desk desk;
const CanvasDocument before = desk.session.document().value();
// Escape and Cancel close the sheet; the project frees.
desk.controller.canvasSize(desk.finished());
QTest::keyClick(&desk.dialog(), Qt::Key_Escape);
QTRY_VERIFY(desk.done);
QVERIFY(!desk.session.isProjectBusy());
desk.controller.imageSize(desk.finished());
desk.dialog().findChild<QPushButton *>(QStringLiteral("imageCancel"))->click();
QTRY_VERIFY(desk.done);
QVERIFY(desk.session.document().value() == before);
QVERIFY(!desk.session.isProjectBusy());
QTRY_VERIFY(!desk.window.findChild<QDialog *>());
// Busy, or without a window, no sheet opens.
desk.session.setIsProjectBusy(true);
desk.controller.canvasSize(desk.finished());
QTRY_VERIFY(desk.done);
QVERIFY(!desk.window.findChild<QDialog *>());
desk.session.setIsProjectBusy(false);
desk.controller.window = nullptr;
desk.controller.imageSize(desk.finished());
QTRY_VERIFY(desk.done);
desk.controller.canvasSize(desk.finished());
QTRY_VERIFY(desk.done);
QVERIFY(!desk.session.isProjectBusy());
QVERIFY(desk.session.document().value() == before);
}
void ProjectResizeTests::theImageSizeSheetScalesThePixelsAsOneStep()
{
Desk desk;
desk.controller.imageSize(desk.finished());
QCOMPARE(desk.dialog().windowTitle(), QString("Image Size"));
QVERIFY(desk.dialog().findChild<ImageSizeSheet *>());
desk.type("imageWidth", "50");
QTRY_VERIFY(desk.done);
QCOMPARE(desk.session.document().value().width, 50);
QCOMPARE(desk.session.document().value().height, 25);
QCOMPARE(desk.session.activeLayer().value().transform.size, QSizeF(5, 5));
QCOMPARE(desk.session.history.undoName(), QString("Image Size"));
QVERIFY(!desk.session.isProjectBusy());
}
void ProjectResizeTests::aResizeThatFailsIsExplained()
{
Desk desk;
// Stretched past what twice the size may hold.
LayerTransform wide = desk.session.activeLayer().value().transform;
wide.size = QSizeF(20'000, 10);
desk.session.beginTransform();
desk.session.previewTransform(wide);
desk.session.commitTransform();
const CanvasDocument before = desk.session.document().value();
DialogDesk alerts;
alerts.replies = {"OK"};
alerts.note = [&] { return QStringLiteral("busy %1").arg(desk.session.isProjectBusy()); };
desk.controller.imageSize(desk.finished());
desk.type("imageWidth", "200");
QTRY_VERIFY(desk.done);
QCOMPARE(alerts.seen, (QStringList{QStringLiteral("alert|2|Couldn’t resize the image|%1|OK|busy 1")
.arg(QString::fromUtf8(ProjectError(ProjectError::Kind::tooLarge).what()))}));
QVERIFY(desk.session.document().value() == before);
QVERIFY(!desk.session.isProjectBusy());
// The canvas's own failure, alike, under its own title.
alerts.replies = {"OK"};
wide.origin = QPointF(999'000, 0);
wide.size = QSizeF(10, 10);
desk.session.beginTransform();
desk.session.previewTransform(wide);
desk.session.commitTransform();
desk.controller.canvasSize(desk.finished());
desk.type("canvasWidth", "5000");
QTRY_VERIFY(desk.done);
QCOMPARE(alerts.seen.size(), 2);
QVERIFY(alerts.seen.last().startsWith("alert|2|Couldn’t change canvas size|"));
}
QTEST_MAIN(ProjectResizeTests)
#include "ProjectResizeTests.moc"