Gui: Add ParameterDefinition to Style Parameters

This adds a way to define parameters within code, that allows developers
to easily encapsulate the parameters and their default values.
This commit is contained in:
Kacper Donat
2025-08-10 23:12:52 +02:00
parent 0cce9c1261
commit 2f1d96bf44
2 changed files with 78 additions and 2 deletions

View File

@@ -37,6 +37,14 @@
#include <Base/Bitmask.h>
#include <Base/Parameter.h>
// That macro uses inline const because some older compilers to not properly support constexpr
// for std::string. It should be changed into static constepxr once we migrate to newer compiler.
#define DEFINE_STYLE_PARAMETER(_name_, _defaultValue_) \
static inline const Gui::StyleParameters::ParameterDefinition _name_ { \
.name = #_name_, \
.defaultValue = (_defaultValue_), \
}
namespace Gui::StyleParameters
{
@@ -56,7 +64,7 @@ struct Numeric
/// Numeric value of the length.
double value;
/// Unit of the length, empty if the value is dimensionless.
std::string unit;
std::string unit = "";
/**
* @name Operators
@@ -119,6 +127,33 @@ struct Value : std::variant<Numeric, Base::Color, std::string>
std::string toString() const;
};
/**
* @brief A structure to define parameters which can be referenced in the code.
*
* @tparam T The type of the parameter.
*
* This structure allows defining parameters which encapsulate a name and a corresponding
* default value. Parameters defined this way can be reused across the codebase for consistency.
* The supported value types include:
* - Numeric types.
* - Colors using `Base::Color`.
* - Strings.
*
* Example Usage:
* @code{.cpp}
* DEFINE_STYLE_PARAMETER(SomeParameter, Numeric { 10 });
* DEFINE_STYLE_PARAMETER(TextColor, Base::Color(0.5F, 0.2F, 0.8F));
* @endcode
*/
template <typename T>
struct ParameterDefinition
{
/// The name of the parameter, must be unique.
const char* name;
/// The default value of the parameter.
T defaultValue;
};
/**
* @struct Parameter
*
@@ -413,7 +448,29 @@ public:
* @param context Resolution context for handling circular references
* @return The resolved value
*/
Value resolve(const std::string& name, ResolveContext context = {}) const;
std::optional<Value> resolve(const std::string& name, ResolveContext context = {}) const;
/**
* @brief Resolves a parameter to its final value, based on definition.
*
* This method evaluates the parameter's expression and returns the computed
* value or default one from definition if the parameter is not available.
*
* @param definition Definition of the parameter to resolve
* @param context Resolution context for handling circular references
* @return The resolved value
*/
template <typename T>
T resolve(const ParameterDefinition<T>& definition, ResolveContext context = {}) const
{
auto value = resolve(definition.name, std::move(context));
if (!value || !std::holds_alternative<T>(*value)) {
return definition.defaultValue;
}
return std::get<T>(*value);
}
/**
* @brief Evaluates an expression string and returns the result.

View File

@@ -328,3 +328,22 @@ TEST_F(ParameterManagerTest, ErrorHandling)
EXPECT_TRUE(invalidResult.has_value());
EXPECT_TRUE(std::holds_alternative<std::string>(*invalidResult));
}
DEFINE_STYLE_PARAMETER(BaseSize, Numeric(8, "px"));
TEST_F(ParameterManagerTest, ResolveParameterDefinition)
{
auto result = manager.resolve(BaseSize);
EXPECT_DOUBLE_EQ(result.value, 16);
EXPECT_EQ(result.unit, "px");
}
DEFINE_STYLE_PARAMETER(MarginSize, Numeric(16, "px"));
TEST_F(ParameterManagerTest, ResolveParameterDefinitionDefault)
{
auto result = manager.resolve(MarginSize);
EXPECT_DOUBLE_EQ(result.value, 16);
EXPECT_EQ(result.unit, "px");
}