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>
87 lines
4.0 KiB
C++
87 lines
4.0 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <string>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
namespace effector {
|
|
|
|
// Declarative description of one effect knob. The GUI turns these into widgets
|
|
// and the CLI turns them into flags, so neither knows about any effect.
|
|
struct ParamSpec {
|
|
enum class Type { Int, Double, Bool, Choice, Path, Text, Color };
|
|
|
|
Type type = Type::Int;
|
|
std::string key;
|
|
std::string label;
|
|
std::string help;
|
|
double defaultValue = 0.0;
|
|
double minimum = 0.0;
|
|
double maximum = 0.0;
|
|
double step = 1.0;
|
|
int digits = 2;
|
|
std::string defaultChoice;
|
|
std::vector<std::string> choices;
|
|
// Whether a named style carries this param rather than the stage it sits
|
|
// on: see core/style.hpp.
|
|
bool inStyle = false;
|
|
|
|
std::string flag() const; // "strip_height" -> "--strip-height"
|
|
|
|
// A copy of this spec marked as carried by a style, so that a declaration
|
|
// reads makeDouble("font_size", ...).styled() and the factories keep the
|
|
// signatures they have.
|
|
ParamSpec styled() const;
|
|
|
|
static ParamSpec makeInt(std::string key, std::string label, long defaultValue, long minimum,
|
|
long maximum, std::string help = {}, long step = 1);
|
|
static ParamSpec makeDouble(std::string key, std::string label, double defaultValue,
|
|
double minimum, double maximum, std::string help = {},
|
|
double step = 0.05, int digits = 2);
|
|
static ParamSpec makeBool(std::string key, std::string label, bool defaultValue,
|
|
std::string help = {});
|
|
static ParamSpec makeChoice(std::string key, std::string label, std::string defaultChoice,
|
|
std::vector<std::string> choices, std::string help = {});
|
|
// A path to a file on disk, empty by default: a chooser in the interface, a
|
|
// flag taking any string on the command line, written relative to the
|
|
// project folder so that a folder still opens after it is moved.
|
|
static ParamSpec makePath(std::string key, std::string label, std::string help = {});
|
|
// Free-form text the user types: an entry in the interface, a flag taking
|
|
// any string on the command line.
|
|
static ParamSpec makeText(std::string key, std::string label, std::string defaultText,
|
|
std::string help = {});
|
|
// A colour written "#rrggbb": a colour button in the interface, the same
|
|
// spelling as a flag value.
|
|
static ParamSpec makeColor(std::string key, std::string label, std::string defaultColor,
|
|
std::string help = {});
|
|
};
|
|
|
|
using ParamValue = std::variant<long, double, bool, std::string>;
|
|
using ParamValues = std::map<std::string, ParamValue>;
|
|
|
|
// The value a spec stands for when nothing has been set: one place, so that
|
|
// an effect's defaults and a style's are filled the same way.
|
|
ParamValue paramDefault(const ParamSpec& spec);
|
|
|
|
long paramInt(const ParamValues& values, const std::string& key, long fallback);
|
|
double paramDouble(const ParamValues& values, const std::string& key, double fallback);
|
|
bool paramBool(const ParamValues& values, const std::string& key, bool fallback);
|
|
std::string paramChoice(const ParamValues& values, const std::string& key,
|
|
const std::string& fallback);
|
|
std::string paramText(const ParamValues& values, const std::string& key,
|
|
const std::string& fallback);
|
|
|
|
// Reads "#rgb" or "#rrggbb" (the leading hash optional) into three bytes.
|
|
// Returns false and leaves `rgb` untouched for anything else, so a malformed
|
|
// value falls back to the default rather than painting an arbitrary colour.
|
|
bool parseColor(const std::string& text, std::uint8_t rgb[3]);
|
|
std::string formatColor(const std::uint8_t rgb[3]);
|
|
|
|
// The colour of a param, or `fallback` when the value does not parse.
|
|
void paramColor(const ParamValues& values, const std::string& key, const std::string& fallback,
|
|
std::uint8_t rgb[3]);
|
|
|
|
} // namespace effector
|