Merge pull request #23019 from kadet1090/transparent-previews-theming

Gui: Add theming abilities to Transparent Previews
This commit is contained in:
Benjamin Nauck
2025-08-13 00:08:35 +02:00
committed by GitHub
13 changed files with 381 additions and 235 deletions

View File

@@ -34,13 +34,6 @@ using namespace Base;
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
Color::Color(float red, float green, float blue, float alpha)
: r(red)
, g(green)
, b(blue)
, a(alpha)
{}
Color::Color(uint32_t rgba)
: Color {}
{

View File

@@ -93,7 +93,12 @@ public:
* Defines the color as (R,G,B,A) whereas all values are in the range [0,1].
* \a A defines the alpha value.
*/
explicit Color(float R = 0.0, float G = 0.0, float B = 0.0, float A = 1.0);
constexpr explicit Color(float R = 0.0, float G = 0.0, float B = 0.0, float A = 1.0)
: r(R)
, g(G)
, b(B)
, a(A)
{}
/**
* Does basically the same as the constructor above unless that (R,G,B,A) is

View File

@@ -30,6 +30,7 @@
#include "ui_DlgThemeEditor.h"
#include "BitmapFactory.h"
#include <Utilities.h>
#include <Base/ServiceProvider.h>
#include <Base/Tools.h>
@@ -64,10 +65,10 @@ QString typeOfTokenValue(const Gui::StyleParameters::Value& value)
[](const std::string&) {
return QWidget::tr("Generic");
},
[](const Gui::StyleParameters::Length&) {
return QWidget::tr("Length");
[](const Gui::StyleParameters::Numeric&) {
return QWidget::tr("Numeric");
},
[](const QColor&) {
[](const Base::Color&) {
return QWidget::tr("Color");
}
},
@@ -513,6 +514,10 @@ QVariant StyleParametersModel::data(const QModelIndex& index, int role) const
const auto& [name, token, _] = *parameterItem;
const auto& value = manager->resolve(name.toStdString());
if (!value) {
return {};
}
if (role == Qt::DisplayRole) {
if (index.column() == ParameterName) {
return name;
@@ -521,16 +526,16 @@ QVariant StyleParametersModel::data(const QModelIndex& index, int role) const
return QString::fromStdString(token.value);
}
if (index.column() == ParameterType) {
return typeOfTokenValue(value);
return typeOfTokenValue(*value);
}
if (index.column() == ParameterPreview) {
return QString::fromStdString(value.toString());
return QString::fromStdString(value->toString());
}
}
if (role == Qt::DecorationRole) {
if (index.column() == ParameterPreview && std::holds_alternative<QColor>(value)) {
return colorPreview(std::get<QColor>(value));
if (index.column() == ParameterPreview && std::holds_alternative<Base::Color>(*value)) {
return colorPreview(std::get<Base::Color>(*value).asValue<QColor>());
}
}
}

View File

@@ -31,30 +31,31 @@
#include <QRegularExpression>
#include <QString>
#include <ranges>
#include <utility>
#include <variant>
#endif
namespace Gui::StyleParameters
{
Length Length::operator+(const Length& rhs) const
Numeric Numeric::operator+(const Numeric& rhs) const
{
ensureEqualUnits(rhs);
return {value + rhs.value, unit};
}
Length Length::operator-(const Length& rhs) const
Numeric Numeric::operator-(const Numeric& rhs) const
{
ensureEqualUnits(rhs);
return {value - rhs.value, unit};
}
Length Length::operator-() const
Numeric Numeric::operator-() const
{
return {-value, unit};
}
Length Length::operator/(const Length& rhs) const
Numeric Numeric::operator/(const Numeric& rhs) const
{
if (rhs.value == 0) {
THROWM(Base::RuntimeError, "Division by zero");
@@ -68,7 +69,7 @@ Length Length::operator/(const Length& rhs) const
return {value / rhs.value, unit};
}
Length Length::operator*(const Length& rhs) const
Numeric Numeric::operator*(const Numeric& rhs) const
{
if (rhs.unit.empty() || unit.empty()) {
return {value * rhs.value, unit};
@@ -78,7 +79,7 @@ Length Length::operator*(const Length& rhs) const
return {value * rhs.value, unit};
}
void Length::ensureEqualUnits(const Length& rhs) const
void Numeric::ensureEqualUnits(const Numeric& rhs) const
{
if (unit != rhs.unit) {
THROWM(Base::RuntimeError,
@@ -90,14 +91,14 @@ void Length::ensureEqualUnits(const Length& rhs) const
std::string Value::toString() const
{
if (std::holds_alternative<Length>(*this)) {
auto [value, unit] = std::get<Length>(*this);
if (std::holds_alternative<Numeric>(*this)) {
auto [value, unit] = std::get<Numeric>(*this);
return fmt::format("{}{}", value, unit);
}
if (std::holds_alternative<QColor>(*this)) {
auto color = std::get<QColor>(*this);
return fmt::format("#{:0>6x}", 0xFFFFFF & color.rgb()); // NOLINT(*-magic-numbers)
if (std::holds_alternative<Base::Color>(*this)) {
auto color = std::get<Base::Color>(*this);
return fmt::format("#{:0>6x}", color.getPackedRGB() >> 8); // NOLINT(*-magic-numbers)
}
return std::get<std::string>(*this);
@@ -259,12 +260,16 @@ std::string ParameterManager::replacePlaceholders(const std::string& expression,
QString::fromStdString(expression),
[&](const QRegularExpressionMatch& match) {
auto tokenName = match.captured(1).toStdString();
auto tokenValue = resolve(tokenName, context);
context.visited.erase(tokenName);
return QString::fromStdString(tokenValue.toString());
}
if (!tokenValue) {
Base::Console().warning("Requested non-existent style parameter token '%s'.\n", tokenName);
return QStringLiteral("");
}
context.visited.erase(tokenName);
return QString::fromStdString(tokenValue->toString());
}
).toStdString();
// clang-format on
}
@@ -292,18 +297,18 @@ std::optional<std::string> ParameterManager::expression(const std::string& name)
return {};
}
Value ParameterManager::resolve(const std::string& name, ResolveContext context) const
std::optional<Value> ParameterManager::resolve(const std::string& name,
ResolveContext context) const
{
std::optional<Parameter> maybeParameter = this->parameter(name);
if (!maybeParameter) {
Base::Console().warning("Requested non-existent design token '%s'.\n", name);
return std::string {};
return std::nullopt;
}
if (context.visited.contains(name)) {
Base::Console().warning("The design token '%s' contains circular-reference.\n", name);
return expression(name).value_or(std::string {});
Base::Console().warning("The style parameter '%s' contains circular-reference.\n", name);
return expression(name);
}
const Parameter& token = *maybeParameter;

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
{
@@ -51,12 +59,12 @@ class Parser;
* represents a dimensionless length that can be used as a scalar. This struct does not care about
* unit conversions as its uses do not require it.
*/
struct Length
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
@@ -66,11 +74,11 @@ struct Length
* and hence act as a scalar.
*
* @code{c++}
* Length a { 10, "px" };
* Length b { 5, "px" };
* Numeric a { 10, "px" };
* Numeric b { 5, "px" };
*
* Length differentUnit { 3, "rem" }
* Length scalar { 2, "" };
* Numeric differentUnit { 3, "rem" }
* Numeric scalar { 2, "" };
*
* // basic operations with the same unit are allowed
* auto sum = a + b; // 15 px
@@ -85,16 +93,16 @@ struct Length
* @endcode
* @{
*/
Length operator+(const Length& rhs) const;
Length operator-(const Length& rhs) const;
Length operator-() const;
Numeric operator+(const Numeric& rhs) const;
Numeric operator-(const Numeric& rhs) const;
Numeric operator-() const;
Length operator/(const Length& rhs) const;
Length operator*(const Length& rhs) const;
Numeric operator/(const Numeric& rhs) const;
Numeric operator*(const Numeric& rhs) const;
/// @}
private:
void ensureEqualUnits(const Length& rhs) const;
void ensureEqualUnits(const Numeric& rhs) const;
};
/**
@@ -107,9 +115,9 @@ private:
*
* As a rule, operations can be only performed over values of the same type.
*/
struct Value : std::variant<Length, QColor, std::string>
struct Value : std::variant<Numeric, Base::Color, std::string>
{
using std::variant<Length, QColor, std::string>::variant;
using std::variant<Numeric, Base::Color, std::string>::variant;
/**
* Converts the object into its string representation.
@@ -119,6 +127,33 @@ struct Value : std::variant<Length, QColor, 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

@@ -26,6 +26,7 @@
#include "Parser.h"
#include "ParameterManager.h"
#include <Utilities.h>
#include <Base/Tools.h>
#ifndef _PreComp_
@@ -41,7 +42,7 @@ namespace Gui::StyleParameters
Value ParameterReference::evaluate(const EvaluationContext& context) const
{
return context.manager->resolve(name, context.context);
return context.manager->resolve(name, context.context).value_or("@" + name);
}
Value Number::evaluate([[maybe_unused]] const EvaluationContext& context) const
@@ -67,26 +68,26 @@ Value FunctionCall::evaluate(const EvaluationContext& context) const
auto colorArg = arguments[0]->evaluate(context);
auto amountArg = arguments[1]->evaluate(context);
if (!std::holds_alternative<QColor>(colorArg)) {
if (!std::holds_alternative<Base::Color>(colorArg)) {
THROWM(Base::ExpressionError,
fmt::format("'{}' is not supported for colors", functionName));
}
auto color = std::get<QColor>(colorArg);
auto color = std::get<Base::Color>(colorArg).asValue<QColor>();
// In Qt if you want to make color 20% darker or lighter, you need to pass 120 as the value
// we, however, want users to pass only the relative difference, hence we need to add the
// 100 required by Qt.
//
// NOLINTNEXTLINE(*-magic-numbers)
auto amount = 100 + static_cast<int>(std::get<Length>(amountArg).value);
auto amount = 100 + static_cast<int>(std::get<Numeric>(amountArg).value);
if (functionName == "lighten") {
return color.lighter(amount);
return Base::Color::fromValue(color.lighter(amount));
}
if (functionName == "darken") {
return color.darker(amount);
return Base::Color::fromValue(color.darker(amount));
}
return {};
@@ -104,25 +105,25 @@ Value FunctionCall::evaluate(const EvaluationContext& context) const
auto secondColorArg = arguments[1]->evaluate(context);
auto amountArg = arguments[2]->evaluate(context);
if (!std::holds_alternative<QColor>(firstColorArg)) {
if (!std::holds_alternative<Base::Color>(firstColorArg)) {
THROWM(Base::ExpressionError,
fmt::format("first argument of '{}' must be color", functionName));
}
if (!std::holds_alternative<QColor>(secondColorArg)) {
if (!std::holds_alternative<Base::Color>(secondColorArg)) {
THROWM(Base::ExpressionError,
fmt::format("second argument of '{}' must be color", functionName));
}
auto firstColor = std::get<QColor>(firstColorArg);
auto secondColor = std::get<QColor>(secondColorArg);
auto firstColor = std::get<Base::Color>(firstColorArg);
auto secondColor = std::get<Base::Color>(secondColorArg);
auto amount = Base::fromPercent(std::get<Length>(amountArg).value);
auto amount = Base::fromPercent(static_cast<long>(std::get<Numeric>(amountArg).value));
return QColor::fromRgbF(
(1 - amount) * firstColor.redF() + amount * secondColor.redF(),
(1 - amount) * firstColor.greenF() + amount * secondColor.greenF(),
(1 - amount) * firstColor.blueF() + amount * secondColor.blueF()
return Base::Color(
(1 - amount) * firstColor.r + amount * secondColor.r,
(1 - amount) * firstColor.g + amount * secondColor.g,
(1 - amount) * firstColor.b + amount * secondColor.b
);
};
@@ -145,12 +146,12 @@ Value BinaryOp::evaluate(const EvaluationContext& context) const
Value lval = left->evaluate(context);
Value rval = right->evaluate(context);
if (!std::holds_alternative<Length>(lval) || !std::holds_alternative<Length>(rval)) {
if (!std::holds_alternative<Numeric>(lval) || !std::holds_alternative<Numeric>(rval)) {
THROWM(Base::ExpressionError, "Math operations are supported only on lengths");
}
auto lhs = std::get<Length>(lval);
auto rhs = std::get<Length>(rval);
auto lhs = std::get<Numeric>(lval);
auto rhs = std::get<Numeric>(rval);
switch (op) {
case Operator::Add:
@@ -169,11 +170,11 @@ Value BinaryOp::evaluate(const EvaluationContext& context) const
Value UnaryOp::evaluate(const EvaluationContext& context) const
{
Value val = operand->evaluate(context);
if (std::holds_alternative<QColor>(val)) {
if (std::holds_alternative<Base::Color>(val)) {
THROWM(Base::ExpressionError, "Unary operations on colors are not supported");
}
auto v = std::get<Length>(val);
auto v = std::get<Numeric>(val);
switch (op) {
case Operator::Add:
return v;
@@ -286,7 +287,7 @@ std::unique_ptr<Expr> Parser::parseColor()
int b = std::stoi(input.substr(pos, 2), nullptr, hexadecimalBase);
pos += 2;
return std::make_unique<Color>(QColor(r, g, b));
return std::make_unique<Color>(Base::Color(r / 255.0, g / 255.0, b / 255.0));
};
const auto parseFunctionStyleColor = [&]() {
@@ -313,7 +314,7 @@ std::unique_ptr<Expr> Parser::parseColor()
if (!match(')')) {
THROWM(Base::ParserError, fmt::format("Expected ')' after color arguments, got '{}'", input[pos]));
}
return std::make_unique<Color>(QColor(r, g, b, a));
return std::make_unique<Color>(Base::Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0));
};
skipWhitespace();

View File

@@ -72,7 +72,7 @@ struct GuiExport ParameterReference: public Expr
struct GuiExport Number: public Expr
{
Length value;
Numeric value;
Number(double value, std::string unit)
: value({value, std::move(unit)})
@@ -83,9 +83,9 @@ struct GuiExport Number: public Expr
struct GuiExport Color: public Expr
{
QColor color;
Base::Color color;
explicit Color(QColor color)
explicit Color(Base::Color color)
: color(std::move(color))
{}

View File

@@ -217,6 +217,7 @@ SET(PartDesignGuiModule_SRCS
PreCompiled.h
SketchWorkflow.cpp
SketchWorkflow.h
StyleParameters.h
Utils.cpp
Utils.h
Workbench.cpp

View File

@@ -0,0 +1,43 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2025 Kacper Donat <kacper@kadet.net> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef STYLEPARAMETERS_H
#define STYLEPARAMETERS_H
#include <Gui/StyleParameters/ParameterManager.h>
namespace PartDesignGui::StyleParameters {
DEFINE_STYLE_PARAMETER(PreviewAdditiveColor, Base::Color(0.0F, 1.0F, 0.6F));
DEFINE_STYLE_PARAMETER(PreviewSubtractiveColor, Base::Color(1.0F, 0.0F, 0.0F));
DEFINE_STYLE_PARAMETER(PreviewDressUpColor, Base::Color(1.0F, 0.0F, 1.0F));
DEFINE_STYLE_PARAMETER(PreviewErrorColor, Base::Color(1.0F, 0.0F, 0.0F));
DEFINE_STYLE_PARAMETER(PreviewErrorTransparency, Gui::StyleParameters::Numeric(0.95));
DEFINE_STYLE_PARAMETER(PreviewToolTransparency, Gui::StyleParameters::Numeric(0.95));
DEFINE_STYLE_PARAMETER(PreviewShapeTransparency, Gui::StyleParameters::Numeric(0.8));
DEFINE_STYLE_PARAMETER(PreviewLineWidth, Gui::StyleParameters::Numeric(2));
}
#endif //STYLEPARAMETERS_H

View File

@@ -33,6 +33,7 @@
#endif
#include <Base/Exception.h>
#include <Base/ServiceProvider.h>
#include <App/Document.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
@@ -51,6 +52,7 @@
#include <Mod/Part/Gui/ViewProviderPreviewExtension.h>
#include "TaskFeatureParameters.h"
#include "StyleParameters.h"
#include "ViewProvider.h"
#include "ViewProviderPy.h"
@@ -78,13 +80,14 @@ void ViewProvider::attach(App::DocumentObject* pcObject)
{
ViewProviderPart::attach(pcObject);
if (auto addSubFeature = getObject<PartDesign::FeatureAddSub>()) {
const Base::Color green(0.0F, 1.0F, 0.6F);
const Base::Color red(1.0F, 0.0F, 0.0F);
auto* styleParameterManager = Base::provideService<Gui::StyleParameters::ParameterManager>();
if (auto addSubFeature = getObject<PartDesign::FeatureAddSub>()) {
bool isAdditive = addSubFeature->getAddSubType() == PartDesign::FeatureAddSub::Additive;
PreviewColor.setValue(isAdditive ? green : red);
PreviewColor.setValue(
isAdditive ? styleParameterManager->resolve(StyleParameters::PreviewAdditiveColor)
: styleParameterManager->resolve(StyleParameters::PreviewSubtractiveColor));
}
}
@@ -217,8 +220,12 @@ void ViewProvider::attachPreview()
{
ViewProviderPreviewExtension::attachPreview();
auto* styleParameterManager = Base::provideService<Gui::StyleParameters::ParameterManager>();
pcPreviewShape->lineWidth = styleParameterManager->resolve(StyleParameters::PreviewLineWidth).value;
pcToolPreview = new PartGui::SoPreviewShape;
pcToolPreview->transparency = 0.95F;
pcToolPreview->transparency = styleParameterManager->resolve(StyleParameters::PreviewToolTransparency).value;
pcToolPreview->color.connectFrom(&pcPreviewShape->color);
pcPreviewRoot->addChild(pcToolPreview);

View File

@@ -37,8 +37,11 @@
#include <Mod/PartDesign/App/FeatureDressUp.h>
#include "ViewProviderDressUp.h"
#include "StyleParameters.h"
#include "TaskDressUpParameters.h"
#include <Base/ServiceProvider.h>
#include <Gui/Utilities.h>
using namespace PartDesignGui;
@@ -50,8 +53,8 @@ void ViewProviderDressUp::attach(App::DocumentObject* pcObject)
{
ViewProvider::attach(pcObject);
const Base::Color magenta(1.0F, 0.0F, 1.0F);
PreviewColor.setValue(magenta);
auto* styleParameterManager = Base::provideService<Gui::StyleParameters::ParameterManager>();
PreviewColor.setValue(styleParameterManager->resolve(StyleParameters::PreviewDressUpColor));
setErrorState(false);
}
@@ -135,11 +138,14 @@ void ViewProviderDressUp::highlightReferences(const bool on)
void ViewProviderDressUp::setErrorState(bool error)
{
const Base::Color red(1.0, 0.0, 0.0);
auto* styleParameterManager = Base::provideService<Gui::StyleParameters::ParameterManager>();
constexpr float errorTransparency = 0.95F;
pcPreviewShape->transparency = error ? errorTransparency : PartGui::SoPreviewShape::defaultTransparency;
pcPreviewShape->color = Base::convertTo<SbColor>(error ? red : PreviewColor.getValue());
pcPreviewShape->transparency = styleParameterManager
->resolve(error ? StyleParameters::PreviewErrorTransparency
: StyleParameters::PreviewShapeTransparency)
.value;
pcPreviewShape->color = error
? styleParameterManager->resolve(StyleParameters::PreviewErrorColor).asValue<SbColor>()
: PreviewColor.getValue().asValue<SbColor>();
}

View File

@@ -24,6 +24,7 @@
#include <gtest/gtest.h>
#include <Gui/Application.h>
#include <Gui/Utilities.h>
#include <Gui/StyleParameters/ParameterManager.h>
using namespace Gui::StyleParameters;
@@ -65,28 +66,31 @@ TEST_F(ParameterManagerTest, BasicParameterResolution)
{
{
auto result = manager.resolve("BaseSize");
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(result.has_value());
EXPECT_TRUE(std::holds_alternative<Numeric>(*result));
auto length = std::get<Numeric>(*result);
EXPECT_DOUBLE_EQ(length.value, 16.0); // Should get value from source2 (later source)
EXPECT_EQ(length.unit, "px");
}
{
auto result = manager.resolve("PrimaryColor");
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 255);
EXPECT_EQ(color.green(), 0);
EXPECT_EQ(color.blue(), 0);
EXPECT_TRUE(result.has_value());
EXPECT_TRUE(std::holds_alternative<Base::Color>(*result));
auto color = std::get<Base::Color>(*result);
EXPECT_EQ(color.r, 1);
EXPECT_EQ(color.g, 0);
EXPECT_EQ(color.b, 0);
}
{
auto result = manager.resolve("SecondaryColor");
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 0);
EXPECT_EQ(color.green(), 255);
EXPECT_EQ(color.blue(), 0);
EXPECT_TRUE(result.has_value());
EXPECT_TRUE(std::holds_alternative<Base::Color>(*result));
auto color = std::get<Base::Color>(*result);
EXPECT_EQ(color.r, 0);
EXPECT_EQ(color.g, 1);
EXPECT_EQ(color.b, 0);
}
}
@@ -95,16 +99,16 @@ TEST_F(ParameterManagerTest, ParameterReferences)
{
{
auto result = manager.resolve("Margin");
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(*result));
auto length = std::get<Numeric>(*result);
EXPECT_DOUBLE_EQ(length.value, 32.0); // @BaseSize * 2 = 16 * 2 = 32
EXPECT_EQ(length.unit, "px");
}
{
auto result = manager.resolve("Padding");
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(*result));
auto length = std::get<Numeric>(*result);
EXPECT_DOUBLE_EQ(length.value, 8.0); // @BaseSize / 2 = 16 / 2 = 8
EXPECT_EQ(length.unit, "px");
}
@@ -115,15 +119,15 @@ TEST_F(ParameterManagerTest, Caching)
{
// First resolution should cache the result
auto result1 = manager.resolve("BaseSize");
EXPECT_TRUE(std::holds_alternative<Length>(result1));
EXPECT_TRUE(std::holds_alternative<Numeric>(*result1));
// Second resolution should use cached value
auto result2 = manager.resolve("BaseSize");
EXPECT_TRUE(std::holds_alternative<Length>(result2));
EXPECT_TRUE(std::holds_alternative<Numeric>(*result2));
// Results should be identical
auto length1 = std::get<Length>(result1);
auto length2 = std::get<Length>(result2);
auto length1 = std::get<Numeric>(*result1);
auto length2 = std::get<Numeric>(*result2);
EXPECT_DOUBLE_EQ(length1.value, length2.value);
EXPECT_EQ(length1.unit, length2.unit);
}
@@ -133,8 +137,8 @@ TEST_F(ParameterManagerTest, CacheInvalidation)
{
// Initial resolution
auto result1 = manager.resolve("BaseSize");
EXPECT_TRUE(std::holds_alternative<Length>(result1));
auto length1 = std::get<Length>(result1);
EXPECT_TRUE(std::holds_alternative<Numeric>(*result1));
auto length1 = std::get<Numeric>(*result1);
EXPECT_DOUBLE_EQ(length1.value, 16.0);
// Reload should clear cache
@@ -142,8 +146,8 @@ TEST_F(ParameterManagerTest, CacheInvalidation)
// Resolution after reload should work the same
auto result2 = manager.resolve("BaseSize");
EXPECT_TRUE(std::holds_alternative<Length>(result2));
auto length2 = std::get<Length>(result2);
EXPECT_TRUE(std::holds_alternative<Numeric>(*result2));
auto length2 = std::get<Numeric>(*result2);
EXPECT_DOUBLE_EQ(length2.value, 16.0);
EXPECT_EQ(length1.unit, length2.unit);
}
@@ -163,8 +167,8 @@ TEST_F(ParameterManagerTest, SourcePriority)
// Should get value from the latest source (highest priority)
auto result = manager.resolve("BaseSize");
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(*result));
auto length = std::get<Numeric>(*result);
EXPECT_DOUBLE_EQ(length.value, 24.0);
EXPECT_EQ(length.unit, "px");
}
@@ -258,7 +262,7 @@ TEST_F(ParameterManagerTest, CircularReferenceDetection)
// Should handle circular reference gracefully
auto result = manager.resolve("A");
// Should return the expression string as fallback
EXPECT_TRUE(std::holds_alternative<std::string>(result));
EXPECT_TRUE(std::holds_alternative<std::string>(*result));
}
// Test complex expressions
@@ -278,26 +282,26 @@ TEST_F(ParameterManagerTest, ComplexExpressions)
{
auto result = manager.resolve("ComplexMargin");
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(*result));
auto length = std::get<Numeric>(*result);
EXPECT_DOUBLE_EQ(length.value, 40.0); // (16 + 4) * 2 = 20 * 2 = 40
EXPECT_EQ(length.unit, "px");
}
{
auto result = manager.resolve("ComplexPadding");
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(*result));
auto length = std::get<Numeric>(*result);
EXPECT_DOUBLE_EQ(length.value, 7.0); // (16 - 2) / 2 = 14 / 2 = 7
EXPECT_EQ(length.unit, "px");
}
{
auto result = manager.resolve("ColorWithFunction");
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_TRUE(std::holds_alternative<Base::Color>(*result));
auto color = std::get<Base::Color>(*result).asValue<QColor>();
// Should be lighter than the original red
EXPECT_GT(color.lightness(), QColor("#ff0000").lightness());
EXPECT_GT(color.lightness(), QColor(0xff0000).lightness());
}
}
@@ -306,8 +310,7 @@ TEST_F(ParameterManagerTest, ErrorHandling)
{
// Test non-existent parameter
auto result = manager.resolve("NonExistent");
EXPECT_TRUE(std::holds_alternative<std::string>(result));
EXPECT_EQ(std::get<std::string>(result), "");
EXPECT_FALSE(result.has_value());
// Test invalid expression
auto invalidSource = std::make_unique<InMemoryParameterSource>(
@@ -322,5 +325,25 @@ TEST_F(ParameterManagerTest, ErrorHandling)
// Should handle invalid expression gracefully
auto invalidResult = manager.resolve("Invalid");
// Should return the expression string as fallback
EXPECT_TRUE(std::holds_alternative<std::string>(invalidResult));
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");
}

View File

@@ -23,7 +23,7 @@
#include <gtest/gtest.h>
#include <QColor>
#include <Gui/Utilities.h>
#include <Gui/StyleParameters/Parser.h>
#include <Gui/StyleParameters/ParameterManager.h>
@@ -59,8 +59,8 @@ TEST_F(ParserTest, ParseNumbers)
Parser parser("42");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 42.0);
EXPECT_EQ(length.unit, "");
}
@@ -69,8 +69,8 @@ TEST_F(ParserTest, ParseNumbers)
Parser parser("10.5px");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 10.5);
EXPECT_EQ(length.unit, "px");
}
@@ -79,8 +79,8 @@ TEST_F(ParserTest, ParseNumbers)
Parser parser("2.5em");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 2.5);
EXPECT_EQ(length.unit, "em");
}
@@ -89,8 +89,8 @@ TEST_F(ParserTest, ParseNumbers)
Parser parser("100%");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 100.0);
EXPECT_EQ(length.unit, "%");
}
@@ -103,56 +103,56 @@ TEST_F(ParserTest, ParseColors)
Parser parser("#ff0000");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 255);
EXPECT_EQ(color.green(), 0);
EXPECT_EQ(color.blue(), 0);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result);
EXPECT_EQ(color.r, 1);
EXPECT_EQ(color.g, 0);
EXPECT_EQ(color.b, 0);
}
{
Parser parser("#00ff00");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 0);
EXPECT_EQ(color.green(), 255);
EXPECT_EQ(color.blue(), 0);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result);
EXPECT_EQ(color.r, 0);
EXPECT_EQ(color.g, 1);
EXPECT_EQ(color.b, 0);
}
{
Parser parser("#0000ff");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 0);
EXPECT_EQ(color.green(), 0);
EXPECT_EQ(color.blue(), 255);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result);
EXPECT_EQ(color.r, 0);
EXPECT_EQ(color.g, 0);
EXPECT_EQ(color.b, 1);
}
{
Parser parser("rgb(255, 0, 0)");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 255);
EXPECT_EQ(color.green(), 0);
EXPECT_EQ(color.blue(), 0);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result);
EXPECT_EQ(color.r, 1);
EXPECT_EQ(color.g, 0);
EXPECT_EQ(color.b, 0);
}
{
Parser parser("rgba(255, 0, 0, 128)");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 255);
EXPECT_EQ(color.green(), 0);
EXPECT_EQ(color.blue(), 0);
EXPECT_EQ(color.alpha(), 128);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result);
EXPECT_DOUBLE_EQ(color.r, 1);
EXPECT_DOUBLE_EQ(color.g, 0);
EXPECT_DOUBLE_EQ(color.b, 0);
EXPECT_NEAR(color.a, 128 / 255.0, 1e-6);
}
}
@@ -163,8 +163,8 @@ TEST_F(ParserTest, ParseParameterReferences)
Parser parser("@TestParam");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 10.0);
EXPECT_EQ(length.unit, "px");
}
@@ -173,19 +173,19 @@ TEST_F(ParserTest, ParseParameterReferences)
Parser parser("@TestColor");
auto expr = parser.parse();
auto result = expr->evaluate({.manager = &manager, .context = {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 255);
EXPECT_EQ(color.green(), 0);
EXPECT_EQ(color.blue(), 0);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result);
EXPECT_EQ(color.r, 1);
EXPECT_EQ(color.g, 0);
EXPECT_EQ(color.b, 0);
}
{
Parser parser("@TestNumber");
auto expr = parser.parse();
auto result = expr->evaluate({.manager = &manager, .context = {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 5.0);
EXPECT_EQ(length.unit, "");
}
@@ -198,8 +198,8 @@ TEST_F(ParserTest, ParseArithmeticOperations)
Parser parser("10 + 5");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 15.0);
EXPECT_EQ(length.unit, "");
}
@@ -208,8 +208,8 @@ TEST_F(ParserTest, ParseArithmeticOperations)
Parser parser("10px + 5px");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 15.0);
EXPECT_EQ(length.unit, "px");
}
@@ -218,8 +218,8 @@ TEST_F(ParserTest, ParseArithmeticOperations)
Parser parser("10 - 5");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 5.0);
EXPECT_EQ(length.unit, "");
}
@@ -228,8 +228,8 @@ TEST_F(ParserTest, ParseArithmeticOperations)
Parser parser("10px - 5px");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 5.0);
EXPECT_EQ(length.unit, "px");
}
@@ -238,8 +238,8 @@ TEST_F(ParserTest, ParseArithmeticOperations)
Parser parser("10 * 5");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 50.0);
EXPECT_EQ(length.unit, "");
}
@@ -248,8 +248,8 @@ TEST_F(ParserTest, ParseArithmeticOperations)
Parser parser("10px * 2");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 20.0);
EXPECT_EQ(length.unit, "px");
}
@@ -258,8 +258,8 @@ TEST_F(ParserTest, ParseArithmeticOperations)
Parser parser("10 / 2");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 5.0);
EXPECT_EQ(length.unit, "");
}
@@ -268,8 +268,8 @@ TEST_F(ParserTest, ParseArithmeticOperations)
Parser parser("10px / 2");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 5.0);
EXPECT_EQ(length.unit, "px");
}
@@ -282,8 +282,8 @@ TEST_F(ParserTest, ParseComplexExpressions)
Parser parser("(10 + 5) * 2");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 30.0);
EXPECT_EQ(length.unit, "");
}
@@ -292,8 +292,8 @@ TEST_F(ParserTest, ParseComplexExpressions)
Parser parser("(10px + 5px) * 2");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 30.0);
EXPECT_EQ(length.unit, "px");
}
@@ -302,8 +302,8 @@ TEST_F(ParserTest, ParseComplexExpressions)
Parser parser("@TestParam + 5px");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 15.0);
EXPECT_EQ(length.unit, "px");
}
@@ -312,8 +312,8 @@ TEST_F(ParserTest, ParseComplexExpressions)
Parser parser("@TestParam * @TestNumber");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 50.0);
EXPECT_EQ(length.unit, "px");
}
@@ -326,8 +326,8 @@ TEST_F(ParserTest, ParseUnaryOperations)
Parser parser("+10");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 10.0);
EXPECT_EQ(length.unit, "");
}
@@ -336,8 +336,8 @@ TEST_F(ParserTest, ParseUnaryOperations)
Parser parser("-10");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, -10.0);
EXPECT_EQ(length.unit, "");
}
@@ -346,8 +346,8 @@ TEST_F(ParserTest, ParseUnaryOperations)
Parser parser("-10px");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, -10.0);
EXPECT_EQ(length.unit, "px");
}
@@ -360,30 +360,30 @@ TEST_F(ParserTest, ParseFunctionCalls)
Parser parser("lighten(#ff0000, 20)");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result).asValue<QColor>();
// The result should be lighter than the original red
EXPECT_GT(color.lightness(), QColor("#ff0000").lightness());
EXPECT_GT(color.lightness(), QColor(0xff0000).lightness());
}
{
Parser parser("darken(#ff0000, 20)");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result).asValue<QColor>();
// The result should be darker than the original red
EXPECT_LT(color.lightness(), QColor("#ff0000").lightness());
EXPECT_LT(color.lightness(), QColor(0xff0000).lightness());
}
{
Parser parser("lighten(@TestColor, 20)");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result).asValue<QColor>();
// The result should be lighter than the original red
EXPECT_GT(color.lightness(), QColor("#ff0000").lightness());
EXPECT_GT(color.lightness(), QColor(0xff0000).lightness());
}
}
@@ -476,8 +476,8 @@ TEST_F(ParserTest, ParseWhitespace)
Parser parser(" 10 + 5 ");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 15.0);
EXPECT_EQ(length.unit, "");
}
@@ -486,8 +486,8 @@ TEST_F(ParserTest, ParseWhitespace)
Parser parser("10px+5px");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 15.0);
EXPECT_EQ(length.unit, "px");
}
@@ -496,11 +496,11 @@ TEST_F(ParserTest, ParseWhitespace)
Parser parser("rgb(255,0,0)");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 255);
EXPECT_EQ(color.green(), 0);
EXPECT_EQ(color.blue(), 0);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result);
EXPECT_EQ(color.r, 1);
EXPECT_EQ(color.g, 0);
EXPECT_EQ(color.b, 0);
}
}
@@ -528,8 +528,8 @@ TEST_F(ParserTest, ParseEdgeCases)
Parser parser("42");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 42.0);
EXPECT_EQ(length.unit, "");
}
@@ -539,11 +539,11 @@ TEST_F(ParserTest, ParseEdgeCases)
Parser parser("#ff0000");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<QColor>(result));
auto color = std::get<QColor>(result);
EXPECT_EQ(color.red(), 255);
EXPECT_EQ(color.green(), 0);
EXPECT_EQ(color.blue(), 0);
EXPECT_TRUE(std::holds_alternative<Base::Color>(result));
auto color = std::get<Base::Color>(result);
EXPECT_EQ(color.r, 1);
EXPECT_EQ(color.g, 0);
EXPECT_EQ(color.b, 0);
}
// Single parameter reference
@@ -551,8 +551,8 @@ TEST_F(ParserTest, ParseEdgeCases)
Parser parser("@TestParam");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 10.0);
EXPECT_EQ(length.unit, "px");
}
@@ -565,8 +565,8 @@ TEST_F(ParserTest, ParseOperatorPrecedence)
Parser parser("2 + 3 * 4");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 14.0); // 2 + (3 * 4) = 2 + 12 = 14
EXPECT_EQ(length.unit, "");
}
@@ -575,8 +575,8 @@ TEST_F(ParserTest, ParseOperatorPrecedence)
Parser parser("10 - 3 * 2");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 4.0); // 10 - (3 * 2) = 10 - 6 = 4
EXPECT_EQ(length.unit, "");
}
@@ -585,8 +585,8 @@ TEST_F(ParserTest, ParseOperatorPrecedence)
Parser parser("20 / 4 + 3");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 8.0); // (20 / 4) + 3 = 5 + 3 = 8
EXPECT_EQ(length.unit, "");
}
@@ -599,8 +599,8 @@ TEST_F(ParserTest, ParseNestedParentheses)
Parser parser("((2 + 3) * 4)");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 20.0); // (5) * 4 = 20
EXPECT_EQ(length.unit, "");
}
@@ -609,8 +609,8 @@ TEST_F(ParserTest, ParseNestedParentheses)
Parser parser("(10 - (3 + 2)) * 2");
auto expr = parser.parse();
auto result = expr->evaluate({&manager, {}});
EXPECT_TRUE(std::holds_alternative<Length>(result));
auto length = std::get<Length>(result);
EXPECT_TRUE(std::holds_alternative<Numeric>(result));
auto length = std::get<Numeric>(result);
EXPECT_DOUBLE_EQ(length.value, 10.0); // (10 - 5) * 2 = 5 * 2 = 10
EXPECT_EQ(length.unit, "");
}