1060 lines
32 KiB
C++
1060 lines
32 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
#include <AzCore/PlatformDef.h>
|
|
|
|
AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option")
|
|
#include <QBitmap>
|
|
#include <QPainter>
|
|
AZ_POP_DISABLE_WARNING
|
|
|
|
#include <AzCore/Asset/AssetManagerBus.h>
|
|
#include <AzCore/Asset/AssetManager.h>
|
|
#include <AzCore/IO/FileIO.h>
|
|
#include <AzCore/RTTI/RTTI.h>
|
|
#include <AzCore/RTTI/TypeInfo.h>
|
|
#include <AzCore/Serialization/Utils.h>
|
|
#include <AzCore/Serialization/SerializeContext.h>
|
|
#include <AzCore/Math/Color.h>
|
|
#include <AzCore/Math/Transform.h>
|
|
#include <AzCore/Math/Vector3.h>
|
|
#include <AzCore/Math/Vector4.h>
|
|
|
|
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
|
|
|
#include <GraphCanvas/Styling/StyleManager.h>
|
|
|
|
#include <GraphCanvas/Editor/GraphCanvasProfiler.h>
|
|
#include <GraphCanvas/Styling/Style.h>
|
|
#include <GraphCanvas/Styling/StyleHelper.h>
|
|
#include <GraphCanvas/Styling/Parser.h>
|
|
#include <GraphCanvas/Utils/QtDrawingUtils.h>
|
|
#include <GraphCanvas/Utils/QtVectorMath.h>
|
|
|
|
namespace
|
|
{
|
|
struct StyleMatch
|
|
{
|
|
GraphCanvas::Styling::Style* style;
|
|
int complexity;
|
|
|
|
bool operator<(const StyleMatch& o) const
|
|
{
|
|
if (complexity > 0 && o.complexity > 0)
|
|
{
|
|
return complexity > o.complexity;
|
|
}
|
|
else if (complexity < 0 && o.complexity < 0)
|
|
{
|
|
return complexity < o.complexity;
|
|
}
|
|
else if (complexity < 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
};
|
|
|
|
class HexagonIcon
|
|
: public GraphCanvas::TintableIcon
|
|
{
|
|
public:
|
|
AZ_CLASS_ALLOCATOR(HexagonIcon, AZ::SystemAllocator, 0);
|
|
|
|
HexagonIcon()
|
|
{
|
|
m_paletteSwatches.push_back(QColor(0, 0, 0));
|
|
m_sourcePixmap = new QPixmap(16, 16);
|
|
m_sourcePixmap->fill(Qt::transparent);
|
|
|
|
QPainter painter(m_sourcePixmap);
|
|
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
|
|
|
|
QPen pen;
|
|
pen.setWidth(4);
|
|
pen.setColor(QColor(0, 0, 0));
|
|
|
|
painter.setPen(pen);
|
|
painter.drawLine(QPointF(0, 16), QPointF(8, 10));
|
|
painter.drawLine(QPointF(16, 16), QPointF(8, 10));
|
|
painter.drawLine(QPointF(8, 0), QPointF(8, 10));
|
|
}
|
|
|
|
AZ::Crc32 GetIconId() const override { return AZ_CRC("HexagonIcon", 0x34053842); }
|
|
};
|
|
|
|
class CheckerboardIcon
|
|
: public GraphCanvas::TintableIcon
|
|
{
|
|
public:
|
|
AZ_CLASS_ALLOCATOR(CheckerboardIcon, AZ::SystemAllocator, 0);
|
|
|
|
CheckerboardIcon()
|
|
{
|
|
m_paletteSwatches.push_back(QColor(0, 0, 0));
|
|
|
|
m_sourcePixmap = new QPixmap(16, 16);
|
|
m_sourcePixmap->fill(Qt::transparent);
|
|
|
|
QPainter painter(m_sourcePixmap);
|
|
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
|
|
|
|
painter.fillRect(QRectF(0, 0, 8, 8), QColor(0, 0, 0));
|
|
painter.fillRect(QRectF(8, 8, 8, 8), QColor(0, 0, 0));
|
|
}
|
|
|
|
AZ::Crc32 GetIconId() const override { return AZ_CRC("CheckerboardIcon", 0x782adcad); }
|
|
};
|
|
|
|
class TriColorCheckerboardIcon
|
|
: public GraphCanvas::TintableIcon
|
|
{
|
|
public:
|
|
AZ_CLASS_ALLOCATOR(TriColorCheckerboardIcon, AZ::SystemAllocator, 0);
|
|
|
|
TriColorCheckerboardIcon()
|
|
{
|
|
m_paletteSwatches.push_back(QColor(0, 0, 0));
|
|
m_paletteSwatches.push_back(QColor(1, 1, 1));
|
|
|
|
m_sourcePixmap = new QPixmap(16, 16);
|
|
m_sourcePixmap->fill(Qt::transparent);
|
|
|
|
QPainter painter(m_sourcePixmap);
|
|
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
|
|
|
|
painter.fillRect(QRectF(0, 0, 8, 8), QColor(0, 0, 0));
|
|
painter.fillRect(QRectF(8, 8, 8, 8), QColor(1, 1, 1));
|
|
}
|
|
|
|
AZ::Crc32 GetIconId() const override { return AZ_CRC("TriColorCheckerboardIcon", 0x9f93d99d); }
|
|
};
|
|
}
|
|
|
|
namespace GraphCanvas
|
|
{
|
|
////////////////////////
|
|
// StyleSheetComponent
|
|
////////////////////////
|
|
|
|
namespace Deprecated
|
|
{
|
|
void StyleSheetComponent::Reflect(AZ::ReflectContext* context)
|
|
{
|
|
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
|
if (!serializeContext)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Styling::Style::Reflect(context);
|
|
|
|
serializeContext->Class<StyleSheetComponent, AZ::Component>()
|
|
->Version(3)
|
|
;
|
|
}
|
|
}
|
|
|
|
/////////////////
|
|
// TintableIcon
|
|
/////////////////
|
|
|
|
QPixmap* TintableIcon::CreatePixmap(const AZStd::vector< QColor >& colors) const
|
|
{
|
|
if (m_sourcePixmap == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
QPixmap* pixmap = new QPixmap(m_sourcePixmap->size());
|
|
pixmap->fill(Qt::transparent);
|
|
|
|
if (colors.empty())
|
|
{
|
|
pixmap->fromImage(m_sourcePixmap->toImage());
|
|
return pixmap;
|
|
}
|
|
|
|
QRectF drawRect = QRectF(0, 0, pixmap->width(), pixmap->height());
|
|
|
|
QPainter painter(pixmap);
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
|
|
for (int i = 0; i < m_paletteSwatches.size(); ++i)
|
|
{
|
|
QBitmap mask = m_sourcePixmap->createMaskFromColor(m_paletteSwatches[i], Qt::MaskOutColor);
|
|
painter.setClipRegion(QRegion(mask));
|
|
|
|
painter.fillRect(drawRect, colors[i % colors.size()]);
|
|
}
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
QPixmap* TintableIcon::CreatePixmap(const AZStd::vector< QBrush >& brushes) const
|
|
{
|
|
if (m_sourcePixmap == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
QPixmap* pixmap = new QPixmap(m_sourcePixmap->size());
|
|
pixmap->fill(Qt::transparent);
|
|
|
|
if (brushes.empty())
|
|
{
|
|
pixmap->fromImage(m_sourcePixmap->toImage());
|
|
return pixmap;
|
|
}
|
|
|
|
QRectF drawRect = QRectF(0, 0, pixmap->width(), pixmap->height());
|
|
|
|
QPainter painter(pixmap);
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
|
|
for (int i=0; i < m_paletteSwatches.size(); ++i)
|
|
{
|
|
QBitmap mask = m_sourcePixmap->createMaskFromColor(m_paletteSwatches[i], Qt::MaskOutColor);
|
|
painter.setClipRegion(QRegion(mask));
|
|
|
|
painter.fillRect(drawRect, brushes[i % brushes.size()]);
|
|
}
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
QPixmap* TintableIcon::CreatePixmap(const AZStd::vector< Styling::StyleHelper* >& palettes) const
|
|
{
|
|
if (m_sourcePixmap == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
QPixmap* pixmap = new QPixmap(m_sourcePixmap->size());
|
|
pixmap->fill(Qt::transparent);
|
|
|
|
if (palettes.empty())
|
|
{
|
|
pixmap->fromImage(m_sourcePixmap->toImage());
|
|
return pixmap;
|
|
}
|
|
|
|
QRectF drawRect = QRectF(0, 0, pixmap->width(), pixmap->height());
|
|
|
|
QPainter painter(pixmap);
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
|
|
for (int i = 0; i < m_paletteSwatches.size(); ++i)
|
|
{
|
|
QBitmap mask = m_sourcePixmap->createMaskFromColor(m_paletteSwatches[i], Qt::MaskOutColor);
|
|
painter.setClipRegion(QRegion(mask));
|
|
|
|
QtDrawingUtils::FillArea(painter, drawRect, (*palettes[i%palettes.size()]));
|
|
}
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
/////////////////
|
|
// StyleManager
|
|
/////////////////
|
|
|
|
StyleManager::StyleManager(const EditorId& editorId, AZStd::string_view assetPath)
|
|
: m_editorId(editorId)
|
|
, m_assetPath(assetPath)
|
|
{
|
|
StyleManagerRequestBus::Handler::BusConnect(m_editorId);
|
|
|
|
AZ::Data::AssetInfo assetInfo;
|
|
AZStd::string watchFolder;
|
|
|
|
bool foundInfo = false;
|
|
|
|
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundInfo, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, m_assetPath.c_str(), assetInfo, watchFolder);
|
|
|
|
if (foundInfo)
|
|
{
|
|
m_styleAssetId = assetInfo.m_assetId;
|
|
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
|
}
|
|
|
|
LoadStyleSheet();
|
|
PopulateDataPaletteMapping();
|
|
|
|
AddPatternIcon(aznew HexagonIcon());
|
|
AddPatternIcon(aznew CheckerboardIcon());
|
|
AddPatternIcon(aznew TriColorCheckerboardIcon());
|
|
|
|
RefreshColorPalettes();
|
|
}
|
|
|
|
StyleManager::~StyleManager()
|
|
{
|
|
for (auto& mapPair : m_styleTypeHelpers)
|
|
{
|
|
delete mapPair.second;
|
|
}
|
|
|
|
ClearCache();
|
|
ClearStyles();
|
|
}
|
|
|
|
void StyleManager::OnCatalogAssetChanged(const AZ::Data::AssetId& asset)
|
|
{
|
|
if (asset == m_styleAssetId)
|
|
{
|
|
LoadStyleSheet();
|
|
}
|
|
}
|
|
|
|
void StyleManager::LoadStyleSheet()
|
|
{
|
|
AZStd::string file = AZStd::string::format("@assets@/%s", m_assetPath.c_str());
|
|
|
|
AZ::IO::FileIOBase* fileBase = AZ::IO::FileIOBase::GetInstance();
|
|
|
|
if (fileBase->Exists(file.c_str()))
|
|
{
|
|
AZ::IO::FileIOStream fileStream;
|
|
|
|
fileStream.Open(file.c_str(), AZ::IO::OpenMode::ModeRead);
|
|
|
|
if (fileStream.IsOpen())
|
|
{
|
|
AZ::u64 fileSize = fileStream.GetLength();
|
|
|
|
AZStd::vector<char> buffer;
|
|
buffer.resize(fileSize + 1);
|
|
|
|
if (fileStream.Read(fileSize, buffer.data()))
|
|
{
|
|
rapidjson::Document styleSheet;
|
|
styleSheet.Parse(buffer.data());
|
|
|
|
if (styleSheet.HasParseError())
|
|
{
|
|
rapidjson::ParseErrorCode errCode = styleSheet.GetParseError();
|
|
QString errMessage = QString("Parse Error: %1 at offset: %2").arg(errCode).arg(styleSheet.GetErrorOffset());
|
|
|
|
AZ_Warning("GraphCanvas", false, "%s", errMessage.toUtf8().data());
|
|
}
|
|
else
|
|
{
|
|
m_widthStepHelper.clear();
|
|
m_heightStepHelper.clear();
|
|
|
|
Styling::Parser::Parse((*this), styleSheet);
|
|
RefreshColorPalettes();
|
|
ClearCache();
|
|
StyleManagerNotificationBus::Event(m_editorId, &StyleManagerNotifications::OnStylesLoaded);
|
|
|
|
{
|
|
Styling::StyleHelper* helper = FindCreateStyleHelper("Sizing_WidthSteps");
|
|
|
|
if (helper != nullptr)
|
|
{
|
|
m_widthStepHelper = helper->GetAttribute(Styling::Attribute::Steps, QList<QVariant>());
|
|
}
|
|
}
|
|
|
|
{
|
|
Styling::StyleHelper* helper = FindCreateStyleHelper("Sizing_HeightSteps");
|
|
|
|
if (helper != nullptr)
|
|
{
|
|
m_heightStepHelper = helper->GetAttribute(Styling::Attribute::Steps, QList<QVariant>());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AZ_Error("GraphCanvas", false, "Failed to read StyleSheet at path(%s)", file.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AZ_Error("GraphCanvas", false, "Failed to load StyleSheet at path(%s).", file.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AZ_Error("GraphCanvas", false, "Could not find StyleSheet at path(%s)", file.c_str());
|
|
}
|
|
}
|
|
|
|
AZ::EntityId StyleManager::ResolveStyles(const AZ::EntityId& object) const
|
|
{
|
|
GRAPH_CANVAS_DETAILED_PROFILE_FUNCTION();
|
|
|
|
Styling::SelectorVector selectors;
|
|
StyledEntityRequestBus::EventResult(selectors, object, &StyledEntityRequests::GetStyleSelectors);
|
|
|
|
QVector<StyleMatch> matches;
|
|
for (const auto& style : m_styles)
|
|
{
|
|
GRAPH_CANVAS_DETAILED_PROFILE_SCOPE("StyleManager::ResolveStyles::StyleMatching");
|
|
int complexity = style->Matches(object);
|
|
if (complexity != 0)
|
|
{
|
|
matches.push_back({ style, complexity });
|
|
}
|
|
}
|
|
|
|
{
|
|
GRAPH_CANVAS_DETAILED_PROFILE_SCOPE("StyleManager::ResolveStyles::Sorting");
|
|
std::stable_sort(matches.begin(), matches.end());
|
|
}
|
|
Styling::StyleVector result;
|
|
result.reserve(matches.size());
|
|
const auto& constMatches = matches;
|
|
for (auto& match : constMatches)
|
|
{
|
|
GRAPH_CANVAS_DETAILED_PROFILE_SCOPE("StyleManager::ResolveStyles::ResultConstruction");
|
|
result.push_back(match.style);
|
|
}
|
|
|
|
auto computed = new Styling::ComputedStyle(m_editorId, selectors, std::move(result));
|
|
|
|
AZ::Entity* entity = new AZ::Entity;
|
|
entity->AddComponent(computed);
|
|
entity->Init();
|
|
entity->Activate();
|
|
|
|
return entity->GetId();
|
|
}
|
|
|
|
void StyleManager::RegisterDataPaletteStyle(const AZ::Uuid& dataType, const AZStd::string& palette)
|
|
{
|
|
m_dataPaletteMapping[dataType] = palette;
|
|
}
|
|
|
|
AZStd::string StyleManager::GetDataPaletteStyle(const AZ::Uuid& dataType) const
|
|
{
|
|
if (dataType.IsNull())
|
|
{
|
|
return "UnknownDataColorPalette";
|
|
}
|
|
else
|
|
{
|
|
auto mapIter = m_dataPaletteMapping.find(dataType);
|
|
|
|
if (mapIter == m_dataPaletteMapping.end())
|
|
{
|
|
return "ObjectDataColorPalette";
|
|
}
|
|
else
|
|
{
|
|
return mapIter->second;
|
|
}
|
|
}
|
|
}
|
|
|
|
const Styling::StyleHelper* StyleManager::FindDataColorPalette(const AZ::Uuid& dataType)
|
|
{
|
|
return FindCreateStyleHelper(GetDataPaletteStyle(dataType));
|
|
}
|
|
|
|
QColor StyleManager::GetDataTypeColor(const AZ::Uuid& dataType)
|
|
{
|
|
Styling::StyleHelper* style = FindCreateStyleHelper(GetDataPaletteStyle(dataType));
|
|
QColor color = style->GetAttribute(Styling::Attribute::BackgroundColor, QColor());
|
|
|
|
return color;
|
|
}
|
|
|
|
const QPixmap* StyleManager::GetDataTypeIcon(const AZ::Uuid& dataType)
|
|
{
|
|
AZStd::string paletteStyle = GetDataPaletteStyle(dataType);
|
|
|
|
PaletteIconConfiguration configuration;
|
|
configuration.m_iconPalette = "DataTypeIcon";
|
|
configuration.AddColorPalette(paletteStyle);
|
|
|
|
return GetConfiguredPaletteIcon(configuration);
|
|
}
|
|
|
|
const QPixmap* StyleManager::GetMultiDataTypeIcon(const AZStd::vector<AZ::Uuid>& dataTypes)
|
|
{
|
|
PaletteIconConfiguration configuration;
|
|
configuration.m_iconPalette = "DataTypeIcon";
|
|
configuration.ReservePalettes(dataTypes.size());
|
|
|
|
for (const AZ::Uuid& dataType : dataTypes)
|
|
{
|
|
AZStd::string paletteStyle = GetDataPaletteStyle(dataType);
|
|
configuration.AddColorPalette(paletteStyle);
|
|
}
|
|
|
|
return GetConfiguredPaletteIcon(configuration);
|
|
}
|
|
|
|
const Styling::StyleHelper* StyleManager::FindColorPalette(const AZStd::string& paletteString)
|
|
{
|
|
return FindCreateStyleHelper(paletteString);
|
|
}
|
|
|
|
QColor StyleManager::GetPaletteColor(const AZStd::string& palette)
|
|
{
|
|
Styling::StyleHelper* style = FindCreateStyleHelper(palette);
|
|
QColor color = style->GetAttribute(Styling::Attribute::BackgroundColor, QColor());
|
|
|
|
return color;
|
|
}
|
|
|
|
const QPixmap* StyleManager::GetPaletteIcon(const AZStd::string& iconStyle, const AZStd::string& palette)
|
|
{
|
|
PaletteIconConfiguration configuration;
|
|
configuration.m_iconPalette = iconStyle;
|
|
configuration.AddColorPalette(palette);
|
|
|
|
return GetConfiguredPaletteIcon(configuration);
|
|
}
|
|
|
|
const QPixmap* StyleManager::GetConfiguredPaletteIcon(const PaletteIconConfiguration& paletteConfiguration)
|
|
{
|
|
Styling::StyleHelper* iconStyleHelper = FindCreateStyleHelper(paletteConfiguration.m_iconPalette);
|
|
|
|
if (!iconStyleHelper)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
const QPixmap* pixmap = FindCachedIcon(paletteConfiguration);
|
|
|
|
if (pixmap == nullptr)
|
|
{
|
|
pixmap = CreateAndCacheIcon(paletteConfiguration);
|
|
}
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
const Styling::StyleHelper* StyleManager::FindPaletteIconStyleHelper(const PaletteIconConfiguration& paletteConfiguration)
|
|
{
|
|
auto colorPalettes = paletteConfiguration.GetColorPalettes();
|
|
|
|
if (colorPalettes.size() == 1)
|
|
{
|
|
return FindCreateStyleHelper(colorPalettes.front());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QPixmap* StyleManager::CreateIcon(const QColor& color, const AZStd::string& iconStyle)
|
|
{
|
|
QColor drawColor = color;
|
|
drawColor.setAlpha(255);
|
|
|
|
QBrush brush(drawColor);
|
|
|
|
return CreateIcon(brush, iconStyle);
|
|
}
|
|
|
|
QPixmap* StyleManager::CreateIconFromConfiguration(const PaletteIconConfiguration& paletteConfiguration)
|
|
{
|
|
const AZStd::vector< AZStd::string >& colorPalettes = paletteConfiguration.GetColorPalettes();
|
|
|
|
if (colorPalettes.size() == 1)
|
|
{
|
|
Styling::StyleHelper* colorStyleHelper = FindCreateStyleHelper(colorPalettes.front());
|
|
|
|
if (colorStyleHelper)
|
|
{
|
|
return CreateIcon((*colorStyleHelper), paletteConfiguration.m_iconPalette);
|
|
}
|
|
}
|
|
else if (!paletteConfiguration.GetColorPalettes().empty())
|
|
{
|
|
AZStd::vector<QColor> colors;
|
|
colors.reserve(colorPalettes.size());
|
|
|
|
for (const AZStd::string& colorPalette : colorPalettes)
|
|
{
|
|
Styling::StyleHelper* colorHelper = FindCreateStyleHelper(colorPalette);
|
|
colors.push_back(colorHelper->GetColor(Styling::Attribute::BackgroundColor));
|
|
}
|
|
|
|
return CreateMultiColoredIcon(colors, paletteConfiguration.m_transitionPercent, paletteConfiguration.m_iconPalette);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QPixmap* StyleManager::CreateMultiColoredIcon(const AZStd::vector<QColor>& colors, float transitionPercent, const AZStd::string& iconStyle)
|
|
{
|
|
Styling::StyleHelper* iconStyleHelper = FindCreateStyleHelper(iconStyle);
|
|
|
|
if (!iconStyleHelper || colors.empty())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
qreal width = iconStyleHelper->GetAttribute(Styling::Attribute::Width, 12.0);
|
|
qreal height = iconStyleHelper->GetAttribute(Styling::Attribute::Height, 8.0);
|
|
qreal margin = iconStyleHelper->GetAttribute(Styling::Attribute::Margin, 2.0);
|
|
|
|
QPainter painter;
|
|
QPainterPath path;
|
|
|
|
qreal borderWidth = iconStyleHelper->GetAttribute(Styling::Attribute::BorderWidth, 1.0);
|
|
|
|
QRectF rect(margin, margin, width, height);
|
|
QRectF adjusted = rect.marginsRemoved(QMarginsF(borderWidth / 2.0, borderWidth / 2.0, borderWidth / 2.0, borderWidth / 2.0));
|
|
|
|
QPointF startPoint = adjusted.bottomLeft();
|
|
QPointF endPoint = adjusted.topRight();
|
|
|
|
QPointF slope = QtVectorMath::Transpose(endPoint - startPoint);
|
|
slope = QtVectorMath::Normalize(slope);
|
|
slope *= adjusted.width() * sin(atan(adjusted.height() / adjusted.width()));
|
|
|
|
QLinearGradient fillGradient = QLinearGradient(adjusted.center() + slope, adjusted.center() - slope);
|
|
|
|
double transition = transitionPercent * (1.0 / colors.size());
|
|
|
|
fillGradient.setColorAt(0, colors[0]);
|
|
|
|
for (size_t i = 1; i < colors.size(); ++i)
|
|
{
|
|
double transitionStart = AZStd::max(0.0, ((double)i / colors.size()) - (transition * 0.5));
|
|
double transitionEnd = AZStd::min(1.0, ((double)i / colors.size()) + (transition * 0.5));
|
|
|
|
fillGradient.setColorAt(transitionStart, colors[i-1]);
|
|
fillGradient.setColorAt(transitionEnd, colors[i]);
|
|
}
|
|
|
|
fillGradient.setColorAt(1, colors[colors.size() - 1]);
|
|
QBrush brush(fillGradient);
|
|
|
|
return CreateIcon(brush, iconStyle);
|
|
}
|
|
|
|
QPixmap* StyleManager::CreateColoredPatternPixmap(const AZStd::vector<QColor>& colorTypes, const AZStd::string& patternName)
|
|
{
|
|
const TintableIcon* icon = FindPatternIcon(AZ::Crc32(patternName.c_str()));
|
|
|
|
if (icon)
|
|
{
|
|
return icon->CreatePixmap(colorTypes);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const QPixmap* StyleManager::CreatePatternPixmap(const AZStd::vector< AZStd::string>& palettes, const AZStd::string& patternName)
|
|
{
|
|
AZ::Crc32 iconKey = AZ::Crc32(patternName.c_str());
|
|
AZ::Crc32 cacheKey = iconKey;
|
|
|
|
for (const AZStd::string& paletteString : palettes)
|
|
{
|
|
cacheKey.Add(paletteString.c_str());
|
|
}
|
|
|
|
const QPixmap* cachePixmap = FindPatternCache(cacheKey);
|
|
|
|
if (cachePixmap)
|
|
{
|
|
return cachePixmap;
|
|
}
|
|
|
|
const TintableIcon* icon = FindPatternIcon(iconKey);
|
|
|
|
AZStd::vector< Styling::StyleHelper* > styleHelpers;
|
|
styleHelpers.reserve(palettes.size());
|
|
|
|
for (const AZStd::string& palette : palettes)
|
|
{
|
|
styleHelpers.push_back(FindCreateStyleHelper(palette));
|
|
}
|
|
|
|
QPixmap* newPixmap = icon->CreatePixmap(styleHelpers);
|
|
|
|
AddPatternCache(cacheKey, newPixmap);
|
|
|
|
return newPixmap;
|
|
}
|
|
|
|
AZStd::vector<AZStd::string> StyleManager::GetColorPaletteStyles() const
|
|
{
|
|
AZStd::vector<AZStd::string> loadedPaletteNames;
|
|
for (const auto& styleHelperPair : m_styleTypeHelpers)
|
|
{
|
|
loadedPaletteNames.push_back(styleHelperPair.first);
|
|
}
|
|
|
|
return loadedPaletteNames;
|
|
}
|
|
|
|
QPixmap* StyleManager::FindPixmap(const AZ::Crc32& key)
|
|
{
|
|
auto cacheIter = m_pixmapCache.find(key);
|
|
|
|
if (cacheIter != m_pixmapCache.end())
|
|
{
|
|
return cacheIter->second;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void StyleManager::CachePixmap(const AZ::Crc32& key, QPixmap* pixmap)
|
|
{
|
|
auto cacheIter = m_pixmapCache.find(key);
|
|
|
|
if (cacheIter != m_pixmapCache.end())
|
|
{
|
|
delete cacheIter->second;
|
|
}
|
|
|
|
m_pixmapCache[key] = pixmap;
|
|
}
|
|
|
|
int StyleManager::FindLayer(AZStd::string_view layer)
|
|
{
|
|
AZ::Crc32 layerId(layer.data());
|
|
|
|
Styling::StyleHelper* styleHelper = FindCreateStyleHelper(layer);
|
|
|
|
return styleHelper->GetAttribute(GraphCanvas::Styling::Attribute::Layer, 0);
|
|
}
|
|
|
|
int StyleManager::GetSteppedWidth(int gridSteps)
|
|
{
|
|
int result = gridSteps;
|
|
|
|
for (QVariant variantStep : m_widthStepHelper)
|
|
{
|
|
int currentStep = variantStep.toInt();
|
|
|
|
if (result < currentStep)
|
|
{
|
|
result = currentStep;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int StyleManager::GetSteppedHeight(int gridSteps)
|
|
{
|
|
int result = gridSteps;
|
|
|
|
for (QVariant variantStep : m_heightStepHelper)
|
|
{
|
|
int currentStep = variantStep.toInt();
|
|
|
|
if (result < currentStep)
|
|
{
|
|
result = currentStep;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
QPixmap* StyleManager::CreateIcon(QBrush& brush, const AZStd::string& iconStyle)
|
|
{
|
|
Styling::StyleHelper* iconStyleHelper = FindCreateStyleHelper(iconStyle);
|
|
|
|
if (!iconStyleHelper)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
qreal width = iconStyleHelper->GetAttribute(Styling::Attribute::Width, 12.0);
|
|
qreal height = iconStyleHelper->GetAttribute(Styling::Attribute::Height, 8.0);
|
|
qreal margin = iconStyleHelper->GetAttribute(Styling::Attribute::Margin, 2.0);
|
|
|
|
QPixmap* icon = new QPixmap(aznumeric_cast<int>(width + 2 * margin), aznumeric_cast<int>(height + 2 * margin));
|
|
icon->fill(Qt::transparent);
|
|
|
|
QPainter painter;
|
|
QPainterPath path;
|
|
|
|
qreal borderWidth = iconStyleHelper->GetAttribute(Styling::Attribute::BorderWidth, 1.0);
|
|
qreal borderRadius = iconStyleHelper->GetAttribute(Styling::Attribute::BorderRadius, 1.0);
|
|
|
|
QRectF rect(margin, margin, width, height);
|
|
QRectF adjusted = rect.marginsRemoved(QMarginsF(borderWidth / 2.0, borderWidth / 2.0, borderWidth / 2.0, borderWidth / 2.0));
|
|
|
|
path.addRoundedRect(adjusted, borderRadius, borderRadius);
|
|
|
|
QColor borderColor = iconStyleHelper->GetAttribute(Styling::Attribute::BorderColor, QColor());
|
|
Qt::PenStyle borderStyle = iconStyleHelper->GetAttribute(Styling::Attribute::BorderStyle, Qt::PenStyle());
|
|
|
|
QPen pen(borderColor, borderWidth);
|
|
pen.setStyle(borderStyle);
|
|
|
|
painter.begin(icon);
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
painter.setPen(pen);
|
|
painter.fillPath(path, brush);
|
|
painter.drawRoundedRect(adjusted, borderRadius, borderRadius);
|
|
|
|
painter.end();
|
|
|
|
return icon;
|
|
}
|
|
|
|
QPixmap* StyleManager::CreateIcon(const Styling::StyleHelper& styleHelper, const AZStd::string& iconStyle)
|
|
{
|
|
Styling::StyleHelper* iconStyleHelper = FindCreateStyleHelper(iconStyle);
|
|
|
|
if (!iconStyleHelper)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
qreal width = iconStyleHelper->GetAttribute(Styling::Attribute::Width, 12.0);
|
|
qreal height = iconStyleHelper->GetAttribute(Styling::Attribute::Height, 8.0);
|
|
qreal margin = iconStyleHelper->GetAttribute(Styling::Attribute::Margin, 2.0);
|
|
|
|
QPixmap* icon = new QPixmap(aznumeric_cast<int>(width + 2 * margin), aznumeric_cast<int>(height + 2 * margin));
|
|
icon->fill(Qt::transparent);
|
|
|
|
QPainter painter;
|
|
QPainterPath path;
|
|
|
|
qreal borderWidth = iconStyleHelper->GetAttribute(Styling::Attribute::BorderWidth, 1.0);
|
|
qreal borderRadius = iconStyleHelper->GetAttribute(Styling::Attribute::BorderRadius, 1.0);
|
|
|
|
QRectF rect(margin, margin, width, height);
|
|
QRectF adjusted = rect.marginsRemoved(QMarginsF(borderWidth / 2.0, borderWidth / 2.0, borderWidth / 2.0, borderWidth / 2.0));
|
|
|
|
path.addRoundedRect(adjusted, borderRadius, borderRadius);
|
|
|
|
QPen borderPen = iconStyleHelper->GetPen(Styling::Attribute::BorderWidth, Styling::Attribute::BorderStyle, Styling::Attribute::BorderColor, Styling::Attribute::CapStyle);
|
|
|
|
painter.begin(icon);
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
painter.setPen(borderPen);
|
|
|
|
painter.save();
|
|
painter.setClipPath(path);
|
|
QtDrawingUtils::FillArea(painter, path.boundingRect(), styleHelper);
|
|
painter.restore();
|
|
|
|
painter.drawRoundedRect(adjusted, borderRadius, borderRadius);
|
|
painter.end();
|
|
|
|
return icon;
|
|
}
|
|
|
|
void StyleManager::ClearStyles()
|
|
{
|
|
StyleManagerNotificationBus::Event(m_editorId, &StyleManagerNotifications::OnStylesUnloaded);
|
|
|
|
for (auto style : m_styles)
|
|
{
|
|
delete style;
|
|
}
|
|
|
|
m_styles.clear();
|
|
}
|
|
|
|
void StyleManager::ClearCache()
|
|
{
|
|
for (auto& mapPair : m_iconMapping)
|
|
{
|
|
for (auto& pixmapIter : mapPair.second)
|
|
{
|
|
delete pixmapIter.second;
|
|
}
|
|
}
|
|
|
|
m_iconMapping.clear();
|
|
|
|
for (auto& mapPair : m_patternCache)
|
|
{
|
|
delete mapPair.second;
|
|
}
|
|
|
|
m_patternCache.clear();
|
|
}
|
|
|
|
void StyleManager::RefreshColorPalettes()
|
|
{
|
|
for (auto& mapPair : m_styleTypeHelpers)
|
|
{
|
|
mapPair.second->SetEditorId(m_editorId);
|
|
mapPair.second->SetStyle(mapPair.first);
|
|
}
|
|
}
|
|
|
|
void StyleManager::PopulateDataPaletteMapping()
|
|
{
|
|
// Boolean
|
|
m_dataPaletteMapping[azrtti_typeid<bool>()] = "BooleanDataColorPalette";
|
|
|
|
// String
|
|
m_dataPaletteMapping[azrtti_typeid<AZStd::string>()] = "StringDataColorPalette";
|
|
|
|
// EntityId
|
|
m_dataPaletteMapping[azrtti_typeid<AZ::EntityId>()] = "EntityIdDataColorPalette";
|
|
|
|
// Numbers
|
|
for (const AZ::Uuid& numberType : { azrtti_typeid<char>()
|
|
, azrtti_typeid<AZ::s8>()
|
|
, azrtti_typeid<short>()
|
|
, azrtti_typeid<int>()
|
|
, azrtti_typeid<long>()
|
|
, azrtti_typeid<AZ::s64>()
|
|
, azrtti_typeid<unsigned char>()
|
|
, azrtti_typeid<unsigned short>()
|
|
, azrtti_typeid<unsigned int>()
|
|
, azrtti_typeid<unsigned long>()
|
|
, azrtti_typeid<AZ::u64>()
|
|
, azrtti_typeid<float>()
|
|
, azrtti_typeid<double>()
|
|
}
|
|
)
|
|
{
|
|
m_dataPaletteMapping[numberType] = "NumberDataColorPalette";
|
|
}
|
|
|
|
// VectorTypes
|
|
for (const AZ::Uuid& vectorType : { azrtti_typeid<AZ::Vector2>()
|
|
, azrtti_typeid<AZ::Vector3>()
|
|
, azrtti_typeid<AZ::Vector4>()
|
|
}
|
|
)
|
|
{
|
|
m_dataPaletteMapping[vectorType] = "VectorDataColorPalette";
|
|
}
|
|
|
|
// ColorType
|
|
m_dataPaletteMapping[azrtti_typeid<AZ::Color>()] = "ColorDataColorPalette";
|
|
|
|
// TransformType
|
|
m_dataPaletteMapping[azrtti_typeid<AZ::Transform>()] = "TransformDataColorPalette";
|
|
}
|
|
|
|
const TintableIcon* StyleManager::FindPatternIcon(AZ::Crc32 patternIcon) const
|
|
{
|
|
auto patternIter = m_patternIcons.find(patternIcon);
|
|
|
|
if (patternIter == m_patternIcons.end())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
return patternIter->second;
|
|
}
|
|
|
|
void StyleManager::AddPatternIcon(TintableIcon* icon)
|
|
{
|
|
auto patternIter = m_patternIcons.find(icon->GetIconId());
|
|
|
|
if (patternIter == m_patternIcons.end())
|
|
{
|
|
m_patternIcons[icon->GetIconId()] = icon;
|
|
}
|
|
else
|
|
{
|
|
AZ_Warning("GraphCanvas", false, "Pattern Id %llu already in use", icon->GetIconId());
|
|
}
|
|
}
|
|
|
|
Styling::StyleHelper* StyleManager::FindCreateStyleHelper(const AZStd::string& paletteString)
|
|
{
|
|
Styling::StyleHelper* styleHelper = nullptr;
|
|
|
|
auto styleHelperIter = m_styleTypeHelpers.find(paletteString);
|
|
|
|
if (styleHelperIter == m_styleTypeHelpers.end())
|
|
{
|
|
styleHelper = aznew Styling::StyleHelper();
|
|
styleHelper->SetEditorId(m_editorId);
|
|
styleHelper->SetStyle(paletteString);
|
|
|
|
m_styleTypeHelpers[paletteString] = styleHelper;
|
|
}
|
|
else
|
|
{
|
|
styleHelper = styleHelperIter->second;
|
|
}
|
|
|
|
return styleHelper;
|
|
}
|
|
|
|
const QPixmap* StyleManager::CreateAndCacheIcon(const PaletteIconConfiguration& configuration)
|
|
{
|
|
auto iconIter = m_iconMapping.find(configuration.m_iconPalette);
|
|
|
|
if (iconIter != m_iconMapping.end())
|
|
{
|
|
auto paletteIter = iconIter->second.find(configuration.GetPaletteCrc());
|
|
|
|
if (paletteIter != iconIter->second.end())
|
|
{
|
|
delete paletteIter->second;
|
|
iconIter->second.erase(paletteIter);
|
|
}
|
|
}
|
|
|
|
QPixmap* icon = CreateIconFromConfiguration(configuration);
|
|
|
|
m_iconMapping[configuration.m_iconPalette][configuration.GetPaletteCrc()] = icon;
|
|
|
|
return icon;
|
|
}
|
|
|
|
const QPixmap* StyleManager::FindCachedIcon(const PaletteIconConfiguration& configuration)
|
|
{
|
|
auto iconIter = m_iconMapping.find(configuration.m_iconPalette);
|
|
|
|
if (iconIter != m_iconMapping.end())
|
|
{
|
|
auto paletteIter = iconIter->second.find(configuration.GetPaletteCrc());
|
|
|
|
if (paletteIter != iconIter->second.end())
|
|
{
|
|
return paletteIter->second;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const QPixmap* StyleManager::FindPatternCache(const AZ::Crc32& patternCache) const
|
|
{
|
|
auto patternIter = m_patternCache.find(patternCache);
|
|
|
|
if (patternIter == m_patternCache.end())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
return patternIter->second;
|
|
}
|
|
|
|
void StyleManager::AddPatternCache(const AZ::Crc32& patternCache, QPixmap* pixmap)
|
|
{
|
|
auto patternIter = m_patternCache.find(patternCache);
|
|
|
|
if (patternIter != m_patternCache.end())
|
|
{
|
|
delete patternIter->second;
|
|
}
|
|
|
|
m_patternCache[patternCache] = pixmap;
|
|
}
|
|
}
|