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

+84
View File
@@ -0,0 +1,84 @@
#pragma once
#include "Document/EditorSession.h"
#include "IO/ImageExporter.h"
#include <QList>
#include <QPointer>
#include <QUrl>
#include <QWidget>
#include <deque>
#include <functional>
#include <optional>
class ProjectWorkspace;
class QDialog;
// One project's file operations: save, open, close, drops.
class ProjectController : public QObject {
Q_OBJECT
public:
explicit ProjectController(EditorSession &session);
// Its owner declares the session first: it outlives this.
EditorSession &session;
// Dialogs open over it; without one they stand alone.
QPointer<QWidget> window;
// With one, opening and closing are the workspace's to do.
QPointer<ProjectWorkspace> workspace;
static bool isProject(const QUrl &url);
// One place on disk, whatever links lead to it.
static bool samePlace(const std::optional<QString> &path, const QString &other);
bool canStart() const;
// Each `done` runs from the event loop, never inline.
void save(bool asNew = false, std::function<void(bool)> done = {});
void open(std::optional<QString> path = std::nullopt, std::function<void(bool)> done = {});
void newCanvas();
void close(QWidget *closing);
void confirmQuit(std::function<void(bool)> done);
void receive(const QList<QUrl> &urls, std::optional<QPointF> point = std::nullopt, std::function<void()> done = {});
// Swift's sheets over the window; resizes off the UI thread.
void canvasSize(std::function<void()> done = {});
void imageSize(std::function<void()> done = {});
void exportPNG(std::function<void()> done = {});
void exportJPEG(std::function<void()> done = {});
private:
struct Incoming {
QList<QUrl> urls;
std::optional<QPointF> point;
std::function<void()> done;
};
struct Loaded {
std::optional<ProjectSnapshot> snapshot;
QString failure;
};
using Resized = Loaded;
struct Rendered {
std::optional<ExportRaster> raster;
QString failure;
};
bool begin();
void finish(const std::function<void(bool)> &done, bool value);
void saveCurrent(bool asNew, std::function<void(bool)> then);
void write(const ProjectSnapshot &snapshot, const QString &destination, std::function<void(bool)> then);
void load(const QString &path, std::function<void(Loaded)> then);
void confirmReplacement(std::function<void(bool)> then);
void showError(const QString &title, const QString &message, std::function<void()> then);
// Swift's beginSheet: window-modal over the window; Escape cancels.
QDialog *sheet(const QString &title);
// Off the UI thread, then landed or explained; freed after.
void resizeProject(std::function<ProjectSnapshot(const ProjectSnapshot &)> resize, std::function<void(const ProjectSnapshot &)> land,
const QString &failure, std::function<void()> done);
void exportPanel(const QString &title, const QString &filter, const QStringList &suffixes, const QString &name, const QString &failure,
std::function<void(std::optional<QString>)> then);
void exportWork(std::function<void()> work, const QString &failure, std::function<void()> end);
void drainIncoming();
void handle(const Incoming &request);
std::optional<QUuid> ownTab() const;
int m_saveGeneration = 0;
std::deque<Incoming> m_incoming;
bool m_processing = false;
};