Files
effector/src/core/params.cpp
T
simonandClaude Opus 5.5 ef8f728126 Show Tile swap's Swap rate as a slider, and let it go slower
A new ParamSpec::slider() marks an Int or Double param to be shown in
the interface as a Gtk::Scale with its minimum and maximum marked under
the ends, rather than a spin button; the command line and the project
file are unchanged. Swap rate uses it, and now runs from 0 to 5 in
steps of 0.01 (was 0 to 30 in steps of 0.1): with every tile swapping
on its own, even 0.1 swapped the canvas many times a second.

Version 0.8.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:44:27 +02:00

232 lines
7.2 KiB
C++

#include "core/params.hpp"
#include <algorithm>
namespace effector {
std::string ParamSpec::flag() const {
std::string flag = "--" + key;
std::replace(flag.begin(), flag.end(), '_', '-');
return flag;
}
ParamSpec ParamSpec::styled() const {
ParamSpec copy = *this;
copy.inStyle = true;
return copy;
}
ParamSpec ParamSpec::slider() const {
ParamSpec copy = *this;
copy.onSlider = 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;
spec.type = Type::Int;
spec.key = std::move(key);
spec.label = std::move(label);
spec.help = std::move(help);
spec.defaultValue = static_cast<double>(defaultValue);
spec.minimum = static_cast<double>(minimum);
spec.maximum = static_cast<double>(maximum);
spec.step = static_cast<double>(step);
return spec;
}
ParamSpec ParamSpec::makeDouble(std::string key, std::string label, double defaultValue,
double minimum, double maximum, std::string help, double step,
int digits) {
ParamSpec spec;
spec.type = Type::Double;
spec.key = std::move(key);
spec.label = std::move(label);
spec.help = std::move(help);
spec.defaultValue = defaultValue;
spec.minimum = minimum;
spec.maximum = maximum;
spec.step = step;
spec.digits = digits;
return spec;
}
ParamSpec ParamSpec::makeBool(std::string key, std::string label, bool defaultValue,
std::string help) {
ParamSpec spec;
spec.type = Type::Bool;
spec.key = std::move(key);
spec.label = std::move(label);
spec.help = std::move(help);
spec.defaultValue = defaultValue ? 1.0 : 0.0;
return spec;
}
ParamSpec ParamSpec::makeChoice(std::string key, std::string label, std::string defaultChoice,
std::vector<std::string> choices, std::string help) {
ParamSpec spec;
spec.type = Type::Choice;
spec.key = std::move(key);
spec.label = std::move(label);
spec.help = std::move(help);
spec.defaultChoice = std::move(defaultChoice);
spec.choices = std::move(choices);
return spec;
}
ParamSpec ParamSpec::makePath(std::string key, std::string label, std::string help) {
ParamSpec spec;
spec.type = Type::Path;
spec.key = std::move(key);
spec.label = std::move(label);
spec.help = std::move(help);
return spec;
}
ParamSpec ParamSpec::makeText(std::string key, std::string label, std::string defaultText,
std::string help) {
ParamSpec spec;
spec.type = Type::Text;
spec.key = std::move(key);
spec.label = std::move(label);
spec.help = std::move(help);
spec.defaultChoice = std::move(defaultText);
return spec;
}
ParamSpec ParamSpec::makeColor(std::string key, std::string label, std::string defaultColor,
std::string help) {
ParamSpec spec;
spec.type = Type::Color;
spec.key = std::move(key);
spec.label = std::move(label);
spec.help = std::move(help);
spec.defaultChoice = std::move(defaultColor);
return spec;
}
ParamSpec ParamSpec::makeFont(std::string key, std::string label, std::string defaultFamily,
std::string help) {
ParamSpec spec;
spec.type = Type::Font;
spec.key = std::move(key);
spec.label = std::move(label);
spec.help = std::move(help);
spec.defaultChoice = std::move(defaultFamily);
return spec;
}
namespace {
const ParamValue* find(const ParamValues& values, const std::string& key) {
const auto it = values.find(key);
return it == values.end() ? nullptr : &it->second;
}
} // 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:
case ParamSpec::Type::Font:
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;
if (const auto* v = std::get_if<double>(value)) return static_cast<long>(*v);
if (const auto* v = std::get_if<bool>(value)) return *v ? 1 : 0;
}
return fallback;
}
double paramDouble(const ParamValues& values, const std::string& key, double fallback) {
if (const auto* value = find(values, key)) {
if (const auto* v = std::get_if<double>(value)) return *v;
if (const auto* v = std::get_if<long>(value)) return static_cast<double>(*v);
}
return fallback;
}
bool paramBool(const ParamValues& values, const std::string& key, bool fallback) {
if (const auto* value = find(values, key)) {
if (const auto* v = std::get_if<bool>(value)) return *v;
if (const auto* v = std::get_if<long>(value)) return *v != 0;
}
return fallback;
}
std::string paramChoice(const ParamValues& values, const std::string& key,
const std::string& fallback) {
return paramText(values, key, fallback);
}
std::string paramText(const ParamValues& values, const std::string& key,
const std::string& fallback) {
if (const auto* value = find(values, key)) {
if (const auto* v = std::get_if<std::string>(value)) return *v;
}
return fallback;
}
namespace {
int hexDigit(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
}
} // namespace
bool parseColor(const std::string& text, std::uint8_t rgb[3]) {
std::string digits = text;
if (!digits.empty() && digits.front() == '#') digits.erase(digits.begin());
if (digits.size() != 3 && digits.size() != 6) return false;
int parsed[6];
for (std::size_t i = 0; i < digits.size(); ++i) {
parsed[i] = hexDigit(digits[i]);
if (parsed[i] < 0) return false;
}
for (int c = 0; c < 3; ++c) {
// "#abc" is the usual shorthand for "#aabbcc".
const int value = digits.size() == 3 ? parsed[c] * 17 : parsed[c * 2] * 16 + parsed[c * 2 + 1];
rgb[c] = static_cast<std::uint8_t>(value);
}
return true;
}
std::string formatColor(const std::uint8_t rgb[3]) {
static const char* const kDigits = "0123456789abcdef";
std::string text = "#";
for (int c = 0; c < 3; ++c) {
text += kDigits[rgb[c] >> 4];
text += kDigits[rgb[c] & 0x0F];
}
return text;
}
void paramColor(const ParamValues& values, const std::string& key, const std::string& fallback,
std::uint8_t rgb[3]) {
if (parseColor(paramText(values, key, fallback), rgb)) return;
if (parseColor(fallback, rgb)) return;
rgb[0] = rgb[1] = rgb[2] = 0;
}
} // namespace effector