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>
This commit is contained in:
Si
2026-09-19 21:55:55 +02:00
co-authored by Claude Opus 5
parent eb417bb41a
commit 3aade6f361
17 changed files with 890 additions and 131 deletions
+23
View File
@@ -10,6 +10,12 @@ std::string ParamSpec::flag() const {
return flag;
}
ParamSpec ParamSpec::styled() const {
ParamSpec copy = *this;
copy.inStyle = true;
return copy;
}
ParamSpec ParamSpec::makeInt(std::string key, std::string label, long defaultValue, long minimum,
long maximum, std::string help, long step) {
ParamSpec spec;
@@ -103,6 +109,23 @@ const ParamValue* find(const ParamValues& values, const std::string& key) {
} // namespace
ParamValue paramDefault(const ParamSpec& spec) {
switch (spec.type) {
case ParamSpec::Type::Int:
return static_cast<long>(spec.defaultValue);
case ParamSpec::Type::Double:
return spec.defaultValue;
case ParamSpec::Type::Bool:
return spec.defaultValue != 0.0;
case ParamSpec::Type::Choice:
case ParamSpec::Type::Path:
case ParamSpec::Type::Text:
case ParamSpec::Type::Color:
break;
}
return spec.defaultChoice;
}
long paramInt(const ParamValues& values, const std::string& key, long fallback) {
if (const auto* value = find(values, key)) {
if (const auto* v = std::get_if<long>(value)) return *v;