Files
effector/src/core/project.hpp
T
SiandClaude Opus 5 3aade6f361 Let several text stages share one named look
A picture with a title, a caption and a credit meant typing the same
font, size and colour into every text stage, and changing the look meant
typing them all again. A project now holds named styles: a stage follows
one, and editing it moves every stage that follows it at once.

The front-ends learn nothing effect-specific. A ParamSpec can be marked
.styled(), saying a style carries it rather than the stage, and
Effect::styleKind() names the pool it comes from -- so styleSpecs(kind)
is to a style what params() is to a stage, and a second text-ish effect
would slot into the styles that already exist. The look is what a style
carries; the words and the placement stay on the stage, which is what
lets two stages share a typography in two different corners.

stageValues() resolves one in a single place, and a stage keeps a full
set of values of its own beside the style, so switching it to Custom,
dropping the style, or opening the project in a build that does not know
it renders exactly the same picture. A style moves stages together; it
never holds the only copy of anything.

The command line builds no styles and passes none, so it renders what it
always did.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 21:55:55 +02:00

55 lines
2.2 KiB
C++

#pragma once
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
#include "core/canvas.hpp"
#include "core/chain.hpp"
#include "core/params.hpp"
#include "core/style.hpp"
namespace effector {
// Everything needed to recreate a render: which images went in, the cascade
// with its settings, the canvas and the seed. Deliberately no pixels — a
// project is a small text file that points at the sources on disk.
struct Project {
std::vector<std::string> sources; // absolute paths
std::vector<ChainStage> stages;
// The named looks the stages draw their formatting from. Kept beside the
// chain rather than inside it because that is the whole point of a style:
// several stages share one, and editing it moves all of them at once.
StyleSet styles;
int width = 1920;
int height = 1080;
// The named format the canvas came from, empty for a custom pixel size.
// The pixels above stay the truth for the render; this is what the
// interface puts back in its dropdown, and what a print format needs its
// resolution for.
std::string format;
int dpi = kDefaultDpi;
std::optional<std::uint64_t> seed;
};
// JSON, written for humans: two-space indent, one source path per line, and
// the params of a stage spelled with the same keys the effect declares.
// Source paths are written relative to `directory` when they live under it, so
// a project folder can be moved or shared whole.
std::string projectToJson(const Project& project, const std::string& directory = {});
// Throws EffectError on malformed JSON, an unknown effect or a missing chain.
// Relative source paths are resolved against `directory`; params the effect
// does not declare are dropped, and missing ones keep the effect's default. A
// style of an unknown kind, or a stage naming a style the file does not hold,
// is dropped the same way: the stage keeps its own values and still renders.
Project projectFromJson(const std::string& text, const std::string& directory = {});
// Both throw EffectError: the file is the user's, so failures are reported
// rather than silently swallowed.
void saveProject(const std::string& path, const Project& project);
Project loadProject(const std::string& path);
} // namespace effector