Files
o3de/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp
T
Esteban Papp 2f5a39176d Gems/GraphCanvas
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
2021-08-20 18:01:28 -07:00

1093 lines
37 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <GraphCanvas/Styling/Parser.h>
#include <GraphCanvas/Styling/Style.h>
#include <GraphCanvas/Styling/SelectorImplementations.h>
#include <GraphCanvas/Styling/StyleHelper.h>
#include <GraphCanvas/Styling/StyleManager.h>
#include <GraphCanvas/Styling/definitions.h>
#include <AzCore/JSON/error/en.h>
#include <AzCore/JSON/error/error.h>
AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option")
#include <QFile>
#include <QByteArray>
#include <QColor>
#include <QFont>
#include <QFontInfo>
#include <QUrl>
#include <QRegularExpression>
#include <QScopedPointer>
#include <QResource>
#include <QDebug>
AZ_POP_DISABLE_WARNING
namespace
{
namespace Styling = GraphCanvas::Styling;
const QRegularExpression hexColor("^#([[:xdigit:]]{2}){3,4}$");
const QRegularExpression rgbColor(R"_(^rgb\(([[:digit:]]{1,3})(,\s?[[:digit:]]{1,3}){2}\)$)_");
const QRegularExpression rgbaColor(R"_(^rgba\(([[:digit:]]{1,3})(,\s?[[:digit:]]{1,3}){3}\)$)_");
const QRegularExpression percentage(R"_(^([[:digit:]]{1,3})%$)_");
const QRegularExpression hexNumber("[[:xdigit:]]{2}");
const QRegularExpression decimalNumber("[[:digit:]]{1,3}");
const QRegularExpression invalidStart(R"_(^\s*>\s*)_");
const QRegularExpression invalidEnd(R"_(\s*>\s*$)_");
const QRegularExpression splitNesting(R"_(\s*>\s*)_");
const QRegularExpression selector(R"_(^(?:(?:(\w+)?(\.\w+)?)|(#\w+)?)(:\w+)?$)_");
AZStd::string QtToAz(const QString& source)
{
QByteArray utf8 = source.toUtf8();
return AZStd::string(utf8.constData(), utf8.size());
}
Styling::Attribute AttributeFromString(const QString& attribute)
{
if (attribute == Styling::Attributes::BackgroundColor)
{
return Styling::Attribute::BackgroundColor;
}
else if (attribute == Styling::Attributes::BackgroundImage)
{
return Styling::Attribute::BackgroundImage;
}
else if (attribute == Styling::Attributes::GridMajorWidth)
{
return Styling::Attribute::GridMajorWidth;
}
else if (attribute == Styling::Attributes::GridMajorStyle)
{
return Styling::Attribute::GridMajorStyle;
}
else if (attribute == Styling::Attributes::GridMajorColor)
{
return Styling::Attribute::GridMajorColor;
}
else if (attribute == Styling::Attributes::GridMinorWidth)
{
return Styling::Attribute::GridMinorWidth;
}
else if (attribute == Styling::Attributes::GridMinorStyle)
{
return Styling::Attribute::GridMinorStyle;
}
else if (attribute == Styling::Attributes::GridMinorColor)
{
return Styling::Attribute::GridMinorColor;
}
else if (attribute == Styling::Attributes::FontFamily)
{
return Styling::Attribute::FontFamily;
}
else if (attribute == Styling::Attributes::FontSize)
{
return Styling::Attribute::FontSize;
}
else if (attribute == Styling::Attributes::FontWeight)
{
return Styling::Attribute::FontWeight;
}
else if (attribute == Styling::Attributes::FontStyle)
{
return Styling::Attribute::FontStyle;
}
else if (attribute == Styling::Attributes::FontVariant)
{
return Styling::Attribute::FontVariant;
}
else if (attribute == Styling::Attributes::Color)
{
return Styling::Attribute::Color;
}
else if (attribute == Styling::Attributes::BorderWidth)
{
return Styling::Attribute::BorderWidth;
}
else if (attribute == Styling::Attributes::BorderStyle)
{
return Styling::Attribute::BorderStyle;
}
else if (attribute == Styling::Attributes::BorderColor)
{
return Styling::Attribute::BorderColor;
}
else if (attribute == Styling::Attributes::BorderRadius)
{
return Styling::Attribute::BorderRadius;
}
else if (attribute == Styling::Attributes::LineWidth)
{
return Styling::Attribute::LineWidth;
}
else if (attribute == Styling::Attributes::LineStyle)
{
return Styling::Attribute::LineStyle;
}
else if (attribute == Styling::Attributes::LineColor)
{
return Styling::Attribute::LineColor;
}
else if (attribute == Styling::Attributes::LineCurve)
{
return Styling::Attribute::LineCurve;
}
else if (attribute == Styling::Attributes::LineSelectionPadding)
{
return Styling::Attribute::LineSelectionPadding;
}
else if (attribute == Styling::Attributes::CapStyle)
{
return Styling::Attribute::CapStyle;
}
else if (attribute == Styling::Attributes::Margin)
{
return Styling::Attribute::Margin;
}
else if (attribute == Styling::Attributes::Padding)
{
return Styling::Attribute::Padding;
}
else if (attribute == Styling::Attributes::Width)
{
return Styling::Attribute::Width;
}
else if (attribute == Styling::Attributes::Height)
{
return Styling::Attribute::Height;
}
else if (attribute == Styling::Attributes::MinWidth)
{
return Styling::Attribute::MinWidth;
}
else if (attribute == Styling::Attributes::MaxWidth)
{
return Styling::Attribute::MaxWidth;
}
else if (attribute == Styling::Attributes::MinHeight)
{
return Styling::Attribute::MinHeight;
}
else if (attribute == Styling::Attributes::MaxHeight)
{
return Styling::Attribute::MaxHeight;
}
else if (attribute == Styling::Attributes::Spacing)
{
return Styling::Attribute::Spacing;
}
else if (attribute == Styling::Attributes::Selectors)
{
return Styling::Attribute::Selectors;
}
else if (attribute == Styling::Attributes::TextAlignment)
{
return Styling::Attribute::TextAlignment;
}
else if (attribute == Styling::Attributes::TextVerticalAlignment)
{
return Styling::Attribute::TextVerticalAlignment;
}
else if (attribute == Styling::Attributes::ConnectionJut)
{
return Styling::Attribute::ConnectionJut;
}
else if (attribute == Styling::Attributes::ConnectionDragMaximumDistance)
{
return Styling::Attribute::ConnectionDragMaximumDistance;
}
else if (attribute == Styling::Attributes::ConnectionDragPercent)
{
return Styling::Attribute::ConnectionDragPercent;
}
else if (attribute == Styling::Attributes::ConnectionDragMoveBuffer)
{
return Styling::Attribute::ConnectionDragMoveBuffer;
}
else if (attribute == Styling::Attributes::ConnectionDefaultMarquee)
{
return Styling::Attribute::ConnectionDefaultMarquee;
}
else if (attribute == Styling::Attributes::PaletteStyle)
{
return Styling::Attribute::PaletteStyle;
}
else if (attribute == Styling::Attributes::MaximumStripeSize)
{
return Styling::Attribute::MaximumStripeSize;
}
else if (attribute == Styling::Attributes::MinimumStripes)
{
return Styling::Attribute::MinimumStripes;
}
else if (attribute == Styling::Attributes::StripeAngle)
{
return Styling::Attribute::StripeAngle;
}
else if (attribute == Styling::Attributes::StripeColor)
{
return Styling::Attribute::StripeColor;
}
else if (attribute == Styling::Attributes::StripeOffset)
{
return Styling::Attribute::StripeOffset;
}
else if (attribute == Styling::Attributes::PatternTemplate)
{
return Styling::Attribute::PatternTemplate;
}
else if (attribute == Styling::Attributes::PatternPalettes)
{
return Styling::Attribute::PatternPalettes;
}
else if (attribute == Styling::Attributes::OddOffsetPercent)
{
return Styling::Attribute::OddOffsetPercent;
}
else if (attribute == Styling::Attributes::EvenOffsetPercent)
{
return Styling::Attribute::EvenOffsetPercent;
}
else if (attribute == Styling::Attributes::MinimumRepetitions)
{
return Styling::Attribute::MinimumRepetitions;
}
else if (attribute == Styling::Attributes::Layer)
{
return Styling::Attribute::Layer;
}
else if (attribute == Styling::Attributes::Opacity)
{
return Styling::Attribute::Opacity;
}
else if (attribute == Styling::Attributes::Steps)
{
return Styling::Attribute::Steps;
}
return Styling::Attribute::Invalid;
}
QColor ParseColor(const QString& color)
{
QRegularExpressionMatch match;
if ((match = hexColor.match(color)).hasMatch())
{
auto number = hexNumber.globalMatch(color);
int r = number.next().captured(0).toInt(nullptr, 16);
int g = number.next().captured(0).toInt(nullptr, 16);
int b = number.next().captured(0).toInt(nullptr, 16);
int alpha = (number.hasNext()) ? number.next().captured(0).toInt(nullptr, 16) : 255;
return QColor(r, g, b, alpha);
}
else if ((match = rgbColor.match(color)).hasMatch())
{
auto number = decimalNumber.globalMatch(color);
int r = number.next().captured(0).toInt();
int g = number.next().captured(0).toInt();
int b = number.next().captured(0).toInt();
return QColor(r, g, b, 255);
}
else if ((match = rgbaColor.match(color)).hasMatch())
{
auto number = decimalNumber.globalMatch(color);
int r = number.next().captured(0).toInt();
int g = number.next().captured(0).toInt();
int b = number.next().captured(0).toInt();
int alpha = number.next().captured(0).toInt();
return QColor(r, g, b, alpha);
}
else
{
return QColor(color);
}
}
bool IsColorValid(const QString& value)
{
return ParseColor(value).isValid();
}
Qt::AlignmentFlag ParseTextAlignment(const QString& value)
{
if (QString::compare(value, QLatin1String("left"), Qt::CaseInsensitive) == 0)
{
return Qt::AlignLeft;
}
else if (QString::compare(value, QLatin1String("right"), Qt::CaseInsensitive) == 0)
{
return Qt::AlignRight;
}
else if (QString::compare(value, QLatin1String("center"), Qt::CaseInsensitive) == 0)
{
return Qt::AlignHCenter;
}
else if (QString::compare(value, QLatin1String("justify"), Qt::CaseInsensitive) == 0)
{
return Qt::AlignJustify;
}
return {};
}
Qt::AlignmentFlag ParseTextVerticalAlignment(const QString& value)
{
if (QString::compare(value, QLatin1String("top"), Qt::CaseInsensitive) == 0)
{
return Qt::AlignTop;
}
else if (QString::compare(value, QLatin1String("bottom"), Qt::CaseInsensitive) == 0)
{
return Qt::AlignBottom;
}
else if (QString::compare(value, QLatin1String("center"), Qt::CaseInsensitive) == 0)
{
return Qt::AlignVCenter;
}
return {};
}
Qt::PenStyle ParseLineStyle(const QString& value)
{
if (QString::compare(value, QLatin1String("none"), Qt::CaseInsensitive) == 0)
{
return Qt::NoPen;
}
else if (QString::compare(value, QLatin1String("solid"), Qt::CaseInsensitive) == 0)
{
return Qt::SolidLine;
}
else if (QString::compare(value, QLatin1String("dashed"), Qt::CaseInsensitive) == 0)
{
return Qt::DashLine;
}
else if (QString::compare(value, QLatin1String("dotted"), Qt::CaseInsensitive) == 0)
{
return Qt::DotLine;
}
else if (QString::compare(value, QLatin1String("dash-dotted"), Qt::CaseInsensitive) == 0)
{
return Qt::DashDotLine;
}
else if (QString::compare(value, QLatin1String("dash-dot-dotted"), Qt::CaseInsensitive) == 0)
{
return Qt::DashDotDotLine;
}
else
{
return{};
}
}
bool IsLineStyleValid(const QString& value)
{
if (QString::compare(value, QLatin1String("none"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("solid"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("dashed"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("dotted"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("dash-dotted"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("dash-dot-dotted"), Qt::CaseInsensitive) == 0)
{
return true;
}
else
{
return false;
}
}
Styling::ConnectionCurveType ParseLineCurve(const QString& value)
{
if (QString::compare(value, QLatin1String("straight"), Qt::CaseInsensitive) == 0)
{
return Styling::ConnectionCurveType::Straight;
}
else if (QString::compare(value, QLatin1String("curved"), Qt::CaseInsensitive) == 0)
{
return Styling::ConnectionCurveType::Curved;
}
else
{
return{};
}
}
Styling::PaletteStyle ParsePaletteStyle(const QString& value)
{
if (QString::compare(value, QLatin1String("solid"), Qt::CaseInsensitive) == 0)
{
return Styling::PaletteStyle::Solid;
}
else if (QString::compare(value, QLatin1String("candystripe"), Qt::CaseInsensitive) == 0)
{
return Styling::PaletteStyle::CandyStripe;
}
else if (QString::compare(value, QLatin1String("pattern-fill"), Qt::CaseInsensitive) == 0)
{
return Styling::PaletteStyle::PatternFill;
}
return Styling::PaletteStyle::Solid;
}
bool IsLineCurveValid(const QString& value)
{
if (QString::compare(value, QLatin1String("straight"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("curved"), Qt::CaseInsensitive) == 0)
{
return true;
}
else
{
return false;
}
}
Qt::PenCapStyle ParseCapStyle(const QString& value)
{
if (QString::compare(value, QLatin1String("square"), Qt::CaseInsensitive) == 0)
{
return Qt::SquareCap;
}
else if (QString::compare(value, QLatin1String("flat"), Qt::CaseInsensitive) == 0)
{
return Qt::FlatCap;
}
else if (QString::compare(value, QLatin1String("round"), Qt::CaseInsensitive) == 0)
{
return Qt::RoundCap;
}
else
{
return{};
}
}
bool IsCapStyleValid(const QString& value)
{
if (QString::compare(value, QLatin1String("square"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("flat"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("round"), Qt::CaseInsensitive) == 0)
{
return true;
}
else
{
return false;
}
}
bool IsFontVariantValid(const QString& value)
{
if (QString::compare(value, QLatin1String("normal"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("all-uppercase"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("all-lowercase"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("small-caps"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("capitalize"), Qt::CaseInsensitive) == 0)
{
return true;
}
else
{
return false;
}
}
bool IsFontStyleValid(const QString& value)
{
if (QString::compare(value, QLatin1String("normal"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("italic"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("oblique"), Qt::CaseInsensitive) == 0)
{
return true;
}
else
{
return false;
}
}
QFont::Style ParseFontStyle(const QString& value)
{
if (QString::compare(value, QLatin1String("normal"), Qt::CaseInsensitive) == 0)
{
return QFont::StyleNormal;
}
else if (QString::compare(value, QLatin1String("italic"), Qt::CaseInsensitive) == 0)
{
return QFont::StyleItalic;
}
else if (QString::compare(value, QLatin1String("oblique"), Qt::CaseInsensitive) == 0)
{
return QFont::StyleOblique;
}
else
{
return{};
}
}
bool IsFontWeightValid(const QString& value)
{
if (QString::compare(value, QLatin1String("thin"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("extra-light"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("light"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("normal"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("medium"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("demi-bold"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("bold"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("extra-bold"), Qt::CaseInsensitive) == 0 ||
QString::compare(value, QLatin1String("black"), Qt::CaseInsensitive) == 0)
{
return true;
}
else
{
return false;
}
}
QFont::Weight ParseFontWeight(const QString& value)
{
if (QString::compare(value, QLatin1String("thin"), Qt::CaseInsensitive) == 0)
{
return QFont::Thin;
}
else if (QString::compare(value, QLatin1String("extra-light"), Qt::CaseInsensitive) == 0)
{
return QFont::ExtraLight;
}
else if (QString::compare(value, QLatin1String("light"), Qt::CaseInsensitive) == 0)
{
return QFont::Light;
}
else if (QString::compare(value, QLatin1String("normal"), Qt::CaseInsensitive) == 0)
{
return QFont::Normal;
}
else if (QString::compare(value, QLatin1String("medium"), Qt::CaseInsensitive) == 0)
{
return QFont::Medium;
}
else if (QString::compare(value, QLatin1String("demi-bold"), Qt::CaseInsensitive) == 0)
{
return QFont::DemiBold;
}
else if (QString::compare(value, QLatin1String("bold"), Qt::CaseInsensitive) == 0)
{
return QFont::Bold;
}
else if (QString::compare(value, QLatin1String("extra-bold"), Qt::CaseInsensitive) == 0)
{
return QFont::ExtraBold;
}
return{};
}
} // namespace
namespace GraphCanvas
{
namespace Styling
{
void Parser::Parse(StyleManager& styleManager, const AZStd::string& json)
{
rapidjson::Document document;
QFile resource(QString::fromUtf8(json.c_str()));
if (resource.exists())
{
resource.open(QIODevice::ReadOnly);
document.Parse(resource.readAll().data());
}
else
{
document.Parse(json.c_str());
}
if (document.HasParseError())
{
qWarning() << "GraphCanvas styling: parse error: " << rapidjson::GetParseError_En(document.GetParseError());
document.Parse("[]");
}
return Parse(styleManager, document);
}
void Parser::Parse(StyleManager& styleManager, const rapidjson::Document& json)
{
Q_ASSERT(json.IsArray());
styleManager.ClearStyles();
for (rapidjson::SizeType i = 0; i < json.Size(); ++i)
{
ParseStyle(styleManager, json[i]);
}
}
void Parser::ParseStyle(StyleManager& styleManager, const rapidjson::Value& value)
{
QFont defaultFont;
QFontInfo defaultFontInfo(defaultFont);
SelectorVector selectors = ParseSelectors(value);
if (selectors.empty())
{
qWarning() << "Style has no selectors, skipping";
return;
}
QScopedPointer<Style> style(aznew Style(selectors));
for (auto member = value.MemberBegin(); member != value.MemberEnd(); ++member)
{
Attribute attribute = AttributeFromString(member->name.GetString());
switch (attribute)
{
case Attribute::BackgroundColor:
case Attribute::GridMajorColor:
case Attribute::GridMinorColor:
case Attribute::Color:
case Attribute::BorderColor:
case Attribute::LineColor:
case Attribute::StripeColor:
{
QString valueStr(member->value.GetString());
if (IsColorValid(valueStr))
{
style->SetAttribute(attribute, ParseColor(valueStr));
}
break;
}
case Attribute::BackgroundImage:
{
QString valueStr(member->value.GetString());
if (valueStr.startsWith(QStringLiteral(":/")))
{
valueStr = QString("qrc%1").arg(valueStr);
}
QUrl url(valueStr);
if (url.isValid())
{
style->SetAttribute(attribute, url);
}
break;
}
case Attribute::GridMajorWidth:
case Attribute::GridMinorWidth:
case Attribute::BorderWidth:
case Attribute::LineWidth:
case Attribute::LineSelectionPadding:
case Attribute::FontSize:
case Attribute::BorderRadius:
case Attribute::Margin:
case Attribute::Padding:
case Attribute::Width:
case Attribute::Height:
case Attribute::MinWidth:
case Attribute::MaxWidth:
case Attribute::MinHeight:
case Attribute::MaxHeight:
case Attribute::Spacing:
case Attribute::ConnectionJut:
case Attribute::ConnectionDragMaximumDistance:
case Attribute::ConnectionDragPercent:
case Attribute::ConnectionDragMoveBuffer:
case Attribute::ConnectionDefaultMarquee:
case Attribute::Layer:
case Attribute::MaximumStripeSize:
case Attribute::MinimumStripes:
case Attribute::StripeAngle:
case Attribute::StripeOffset:
case Attribute::MinimumRepetitions:
{
if (member->value.IsInt())
{
style->SetAttribute(attribute, member->value.GetInt());
}
else if (member->value.IsDouble())
{
style->SetAttribute(attribute, member->value.GetDouble());
}
else if (Attribute::FontSize == attribute)
{
QString theValue(member->value.GetString());
if (theValue == "default")
{
style->SetAttribute(attribute, defaultFontInfo.pixelSize());
}
else
{
QRegularExpressionMatch match = percentage.match(theValue);
if (match.isValid())
{
double extracted = match.captured(1).toDouble() / 100.0;
style->SetAttribute(attribute, int(double(defaultFontInfo.pixelSize() * extracted)));
}
}
}
else
{
// Handle percent cases
QString theValue(member->value.GetString());
QRegularExpressionMatch match = percentage.match(theValue);
if (match.isValid())
{
double extracted = match.captured(1).toDouble() / 100.0;
style->SetAttribute(attribute, extracted);
}
else
{
qWarning() << "Invalid number:" << member->value.GetString();
}
}
break;
}
case Attribute::Opacity:
case Attribute::OddOffsetPercent:
case Attribute::EvenOffsetPercent:
{
// Handler percent case
QString theValue(member->value.GetString());
QRegularExpressionMatch match = percentage.match(theValue);
if (match.isValid())
{
double extracted = match.captured(1).toDouble() / 100.0;
style->SetAttribute(attribute, extracted);
}
else
{
qWarning() << "Invalid number:" << member->value.GetString();
}
break;
}
case Attribute::GridMajorStyle:
case Attribute::GridMinorStyle:
case Attribute::BorderStyle:
case Attribute::LineStyle:
{
QString valueStr(member->value.GetString());
if (IsLineStyleValid(valueStr))
{
style->SetAttribute(attribute, QVariant::fromValue(ParseLineStyle(valueStr)));
}
break;
}
case Attribute::LineCurve:
{
QString valueStr(member->value.GetString());
if (IsLineCurveValid(valueStr))
{
style->SetAttribute(attribute, QVariant::fromValue(ParseLineCurve(valueStr)));
}
break;
}
case Attribute::CapStyle:
{
QString valueStr(member->value.GetString());
if (IsCapStyleValid(valueStr))
{
style->SetAttribute(attribute, QVariant::fromValue(ParseCapStyle(valueStr)));
}
break;
}
case Attribute::FontFamily:
{
QString valueStr(member->value.GetString());
if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0)
{
valueStr = defaultFontInfo.family();
}
else
{
QFont font(valueStr);
QFontInfo info(font);
if (!info.exactMatch())
{
qWarning() << "Invalid font-family:" << valueStr;
}
}
style->SetAttribute(attribute, valueStr);
}
case Attribute::FontStyle:
{
QString valueStr(member->value.GetString());
if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0)
{
style->SetAttribute(attribute, defaultFontInfo.style());
}
else
{
if (IsFontStyleValid(valueStr))
{
style->SetAttribute(attribute, ParseFontStyle(valueStr));
}
}
break;
}
case Attribute::FontWeight:
{
QString valueStr(member->value.GetString());
if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0)
{
style->SetAttribute(attribute, defaultFontInfo.weight());
}
else
{
if (IsFontWeightValid(valueStr))
{
style->SetAttribute(attribute, ParseFontWeight(valueStr));
}
}
break;
}
case Attribute::FontVariant:
{
QString valueStr(member->value.GetString());
if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0)
{
style->SetAttribute(attribute, defaultFont.capitalization());
}
else
{
if (IsFontVariantValid(valueStr))
{
style->SetAttribute(attribute, valueStr);
}
}
break;
}
case Attribute::TextAlignment:
{
if (Qt::AlignmentFlag flag = ParseTextAlignment(member->value.GetString()))
{
style->SetAttribute(attribute, QVariant::fromValue(flag));
}
break;
}
case Attribute::TextVerticalAlignment:
{
if (Qt::AlignmentFlag flag = ParseTextVerticalAlignment(member->value.GetString()))
{
style->SetAttribute(attribute, QVariant::fromValue(flag));
}
break;
}
case Attribute::Selectors:
break;
case Attribute::PaletteStyle:
{
QString valueStr(member->value.GetString());
style->SetAttribute(attribute, QVariant::fromValue(ParsePaletteStyle(valueStr)));
break;
}
case Attribute::PatternTemplate:
case Attribute::PatternPalettes:
{
QString valueStr(member->value.GetString());
style->SetAttribute(attribute, valueStr);
break;
}
case Attribute::Steps:
{
QList<QVariant> stepList;
QString valueStr(member->value.GetString());
QStringList splitValues = valueStr.split("|");
for (QString currentString : splitValues)
{
stepList.append(currentString.toInt());
}
style->SetAttribute(attribute, stepList);
break;
}
default:
qWarning() << "Invalid attribute:" << member->name.GetString();
}
}
if (style->IsEmpty())
{
qWarning() << "Style contains no rules";
return;
}
else
{
styleManager.m_styles.push_back(style.take());
}
}
SelectorVector Parser::ParseSelectors(const rapidjson::Value& value)
{
SelectorVector result;
if (!value.HasMember(Styling::Attributes::Selectors))
{
qWarning() << "Style has no selectors";
return result;
}
const rapidjson::Value& raw = value[Styling::Attributes::Selectors];
if (!raw.IsArray())
{
qWarning() << "Expected an array of strings";
return result;
}
for (auto rawSelector = raw.Begin(); rawSelector != raw.End(); ++rawSelector)
{
if (!rawSelector->IsString())
{
qWarning() << "Selectors should be strings, skipping";
continue;
}
QString candidate = QString::fromUtf8(rawSelector->GetString());
if (candidate.contains(invalidStart))
{
qWarning() << "Selectors can't start with '>', skipping";
continue;
}
if (candidate.contains(invalidEnd))
{
qWarning() << "Selectors can't end with '>', skipping";
continue;
}
const QStringList parts = candidate.split(splitNesting);
if (parts.contains(QStringLiteral("")))
{
qWarning() << "Empty nesting relation found, skipping";
continue;
}
SelectorVector nestedSelectors;
nestedSelectors.reserve(parts.size());
for (const QString& part : parts)
{
auto matches = selector.match(part);
if (!matches.hasMatch())
{
qWarning() << "Invalid selector:" << part << "in" << candidate;
nestedSelectors.clear();
break;
}
AZStd::string element = QtToAz(matches.captured(1));
AZStd::string clazz = QtToAz(matches.captured(2));
AZStd::string id = QtToAz(matches.captured(3));
AZStd::string state = QtToAz(matches.captured(4));
if (!id.empty())
{
result.emplace_back(Selector::Get(id));
continue;
}
Selector elementSelector = Selector::Get(element);
Selector clazzSelector = Selector::Get(clazz);
Selector stateSelector = Selector::Get(state);
if (matches.capturedTexts().size() == 2)
{
if (elementSelector.IsValid())
{
nestedSelectors.emplace_back(elementSelector);
}
else if (clazzSelector.IsValid())
{
nestedSelectors.emplace_back(clazzSelector);
}
else if (stateSelector.IsValid())
{
nestedSelectors.emplace_back(stateSelector);
}
}
else
{
SelectorVector bits;
if (elementSelector.IsValid())
{
bits.emplace_back(elementSelector);
}
if (clazzSelector.IsValid())
{
bits.emplace_back(clazzSelector);
}
if (stateSelector.IsValid())
{
bits.emplace_back(stateSelector);
}
nestedSelectors.emplace_back(aznew CompoundSelector(std::move(bits)));
}
}
if (nestedSelectors.size() == 1)
{
result.push_back(nestedSelectors[0]);
}
else if (nestedSelectors.empty())
{
continue;
}
else
{
Selector nested = aznew NestedSelector(std::move(nestedSelectors));
result.emplace_back(nested);
}
}
return result;
}
}
}