#pragma once #include #include #include #include #include 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 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 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; using ParamValues = std::map; // 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