Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,469 @@
/*
* 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 "precompiled.h"
#include <GraphCanvas/Components/GridBus.h>
#include <GraphCanvas/Components/Nodes/Comment/CommentBus.h>
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/Slots/Data/DataSlotBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <GraphCanvas/Editor/EditorTypes.h>
#include <GraphCanvas/GraphCanvasBus.h>
#include <GraphCanvas/Widgets/GraphCanvasGraphicsView/GraphCanvasGraphicsView.h>
#include <GraphCanvas/Widgets/NodePalette/TreeItems/NodePaletteTreeItem.h>
#include <Editor/View/Widgets/NodePalette/CreateNodeMimeEvent.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Core/GraphBus.h>
#include <ScriptCanvas/Core/Node.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <Editor/Include/ScriptCanvas/Bus/NodeIdPair.h>
#include <Editor/Include/ScriptCanvas/GraphCanvas/MappingBus.h>
#include <ScriptCanvasDeveloperEditor/AutomationActions/DynamicSlotFullCreation.h>
#include <ScriptCanvasDeveloperEditor/DeveloperUtils.h>
namespace ScriptCanvasDeveloperEditor
{
namespace DynamicSlotFullCreation
{
class DynamicSlotFullCreationInterface
: public ProcessNodePaletteInterface
{
public:
void SetupInterface(const AZ::EntityId& activeGraphCanvasGraphId, const ScriptCanvas::ScriptCanvasId& scriptCanvasId)
{
m_graphCanvasGraphId = activeGraphCanvasGraphId;
m_scriptCanvasId = scriptCanvasId;
GraphCanvas::SceneRequestBus::EventResult(m_viewId, activeGraphCanvasGraphId, &GraphCanvas::SceneRequests::GetViewId);
GraphCanvas::SceneRequestBus::EventResult(m_gridId, activeGraphCanvasGraphId, &GraphCanvas::SceneRequests::GetGrid);
GraphCanvas::GridRequestBus::EventResult(m_minorPitch, m_gridId, &GraphCanvas::GridRequests::GetMinorPitch);
GraphCanvas::ViewRequestBus::EventResult(m_nodeCreationPos, m_viewId, &GraphCanvas::ViewRequests::GetViewSceneCenter);
GraphCanvas::GraphCanvasGraphicsView* graphicsView = nullptr;
GraphCanvas::ViewRequestBus::EventResult(graphicsView, m_viewId, &GraphCanvas::ViewRequests::AsGraphicsView);
m_viewportRectangle = graphicsView->mapToScene(graphicsView->viewport()->geometry()).boundingRect();
ScriptCanvas::GraphRequestBus::EventResult(m_graph, m_scriptCanvasId, &ScriptCanvas::GraphRequests::GetGraph);
ScriptCanvas::GraphVariableManagerRequests* variableRequests = ScriptCanvas::GraphVariableManagerRequestBus::FindFirstHandler(m_scriptCanvasId);
if (variableRequests)
{
const ScriptCanvas::GraphVariableMapping* mapping = variableRequests->GetVariables();
AZStd::unordered_set< ScriptCanvas::Data::Type > dataTypes;
for (const auto& variablePair : (*mapping))
{
auto insertResult = dataTypes.insert(variablePair.second.GetDataType());
if (insertResult.second)
{
m_availableVariableIds.emplace_back(variablePair.first);
m_variableTypeMapping[variablePair.first] = variablePair.second.GetDataType();
}
}
}
}
bool ShouldProcessItem([[maybe_unused]] const GraphCanvas::NodePaletteTreeItem* nodePaletteTreeItem) const
{
return !m_availableVariableIds.empty();
}
void ProcessItem(const GraphCanvas::NodePaletteTreeItem* nodePaletteTreeItem)
{
AZStd::unordered_set<ScriptCanvasEditor::NodeIdPair> createdPairs;
GraphCanvas::GraphCanvasMimeEvent* mimeEvent = nodePaletteTreeItem->CreateMimeEvent();
AZStd::unordered_set< AZ::EntityId > nodesToDelete;
if (ScriptCanvasEditor::MultiCreateNodeMimeEvent* multiCreateMimeEvent = azrtti_cast<ScriptCanvasEditor::MultiCreateNodeMimeEvent*>(mimeEvent))
{
AZStd::vector< GraphCanvas::GraphCanvasMimeEvent* > mimeEvents = multiCreateMimeEvent->CreateMimeEvents();
for (GraphCanvas::GraphCanvasMimeEvent* currentEvent : mimeEvents)
{
ScriptCanvasEditor::NodeIdPair processPair = ProcessMimeEvent(currentEvent);
nodesToDelete.insert(GraphCanvas::GraphUtils::FindOutermostNode(processPair.m_graphCanvasId));
delete currentEvent;
}
}
else if (mimeEvent)
{
ScriptCanvasEditor::NodeIdPair processPair = ProcessMimeEvent(mimeEvent);
nodesToDelete.insert(GraphCanvas::GraphUtils::FindOutermostNode(processPair.m_graphCanvasId));
}
delete mimeEvent;
GraphCanvas::SceneRequestBus::Event(m_graphCanvasGraphId, &GraphCanvas::SceneRequests::Delete, nodesToDelete);
}
private:
bool HasDynamicSlots(ScriptCanvasEditor::NodeIdPair creationPair) const
{
ScriptCanvas::Node* node = m_graph->FindNode(creationPair.m_scriptCanvasId);
if (node)
{
for (const ScriptCanvas::Slot* slot : node->GetAllSlots())
{
if (slot->IsDynamicSlot())
{
return true;
}
}
}
return false;
}
void PopulateSlots(GraphCanvas::GraphCanvasMimeEvent* currentEvent, const ScriptCanvasEditor::NodeIdPair& prototypeNode)
{
int origWidth = m_widthOffset;
int origHeight = m_heightOffset;
int origRowHeight = m_maxRowHeight;
// Creating enough data to do a brute-force lexographical ordering of all availble
// variable types to all slots. In every combination.
//
// Create a mapping of available types to each slot.
// Along with an order or the slots.
// Will consume data from the outermost slot, and as it empties, will continue to consume downward.
// With each empty consumption triggering a refilling of all the after slots.
AZStd::vector<ScriptCanvas::SlotId> slotOrdering;
AZStd::unordered_map<ScriptCanvas::SlotId, AZStd::vector<ScriptCanvas::VariableId> > groupDataTypes;
AZStd::unordered_set<AZ::Crc32> usedSlotGroups;
AZStd::unordered_map<ScriptCanvas::SlotId, ScriptCanvas::TransientSlotIdentifier> prototypeIdentifiers;
int tempWidth = m_widthOffset;
int tempHeight = m_heightOffset;
int tempRowHeight = m_maxRowHeight;
// Generate a prototype node which will we scrape for data.
ScriptCanvas::Node* protoTypeNode = m_graph->FindNode(prototypeNode.m_scriptCanvasId);
for (const ScriptCanvas::Slot* slot : protoTypeNode->GetAllSlots())
{
prototypeIdentifiers[slot->GetId()] = slot->GetTransientIdentifier();
if (slot->IsDynamicSlot())
{
AZ::Crc32 dynamicGroup = slot->GetDynamicGroup();
if (usedSlotGroups.find(dynamicGroup) != usedSlotGroups.end())
{
continue;
}
slotOrdering.emplace_back(slot->GetId());
groupDataTypes.insert_key(slot->GetId());
if (dynamicGroup != AZ::Crc32())
{
usedSlotGroups.insert(dynamicGroup);
}
}
}
// Populate all of the groups with all the data types they need to have.
for (auto& keyPair : groupDataTypes)
{
keyPair.second = m_availableVariableIds;
}
AZStd::vector<AZ::EntityId> usedGraphCanvasNodeIds;
// Construct a single node to use, until we need to swap it out for a new one.
// Then we can just delete this node at the end.
auto nodeIdPair = DeveloperUtils::HandleMimeEvent(currentEvent, m_graphCanvasGraphId, m_viewportRectangle, tempWidth, tempHeight, tempRowHeight, m_minorPitch);
ScriptCanvas::Node* node = m_graph->FindNode(nodeIdPair.m_scriptCanvasId);
// Begin brute force lexical permutations!
while (node)
{
int i = 0;
// Attempt to assign the current set of variable types.
for (; i < slotOrdering.size(); ++i)
{
const ScriptCanvas::SlotId& prototypeId = slotOrdering[i];
auto groupDataIter = groupDataTypes.find(slotOrdering[i]);
auto transientSlotIter = prototypeIdentifiers.find(slotOrdering[i]);
if (transientSlotIter != prototypeIdentifiers.end())
{
ScriptCanvas::TransientSlotIdentifier slotIdentifier = transientSlotIter->second;
ScriptCanvas::Slot* slot = node->GetSlotByTransientId(slotIdentifier);
const ScriptCanvas::VariableId nextVariableId = groupDataIter->second.front();
auto variableTypeIter = m_variableTypeMapping.find(nextVariableId);
if (variableTypeIter == m_variableTypeMapping.end() || !slot->IsTypeMatchFor(variableTypeIter->second))
{
break;
}
if (!slot->IsVariableReference())
{
GraphCanvas::Endpoint endpoint = ConvertToGraphCanvasEndpoint(slot->GetEndpoint());
bool canConvertToReference = false;
GraphCanvas::DataSlotRequestBus::EventResult(canConvertToReference, endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::CanConvertToReference);
if (canConvertToReference)
{
GraphCanvas::DataSlotRequestBus::Event(endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference);
}
}
if (!slot->IsVariableReference())
{
break;
}
node->SetSlotVariableId(slot->GetId(), nextVariableId);
}
}
// If we succeeded, we need to update our offsets, and create a new node.
if (i >= slotOrdering.size())
{
usedGraphCanvasNodeIds.emplace_back(nodeIdPair.m_graphCanvasId);
DeveloperUtils::UpdateViewportPositionOffsetForNode(nodeIdPair.m_graphCanvasId, m_viewportRectangle, m_widthOffset, m_heightOffset, m_maxRowHeight, m_minorPitch);
tempWidth = m_widthOffset;
tempHeight = m_heightOffset;
tempRowHeight = m_maxRowHeight;
nodeIdPair = DeveloperUtils::HandleMimeEvent(currentEvent, m_graphCanvasGraphId, m_viewportRectangle, tempWidth, tempHeight, tempRowHeight, m_minorPitch);
node = m_graph->FindNode(nodeIdPair.m_scriptCanvasId);
i = aznumeric_cast<int>(slotOrdering.size()) - 1;
}
else
{
// Reset all of the previous variable ids if we failed.
for (int r = 0; r < i; ++r)
{
const ScriptCanvas::SlotId& prototypeId = slotOrdering[r];
auto transientSlotIter = prototypeIdentifiers.find(slotOrdering[r]);
if (transientSlotIter != prototypeIdentifiers.end())
{
ScriptCanvas::TransientSlotIdentifier slotIdentifier = transientSlotIter->second;
ScriptCanvas::Slot* slot = node->GetSlotByTransientId(slotIdentifier);
node->ClearSlotVariableId(slot->GetId());
}
}
tempWidth = m_widthOffset;
tempHeight = m_heightOffset;
tempRowHeight = m_maxRowHeight;
}
// Determine where we failed, and remove that value
// Updating everything after it to the new state.
//
// i.e. if we failed on the first element. We can drop values off of it.
// Then reset everything after it to the full 'state' allowing us to skip
// large swathes of invalid configurations.
while (i < slotOrdering.size())
{
const ScriptCanvas::SlotId& indexPoint = slotOrdering[i];
auto groupDataIter = groupDataTypes.find(indexPoint);
if (groupDataIter != groupDataTypes.end())
{
groupDataIter->second.erase(groupDataIter->second.begin());
if (groupDataIter->second.empty())
{
--i;
}
else
{
break;
}
}
else
{
break;
}
}
// If we rolled off the front node. We are done.
// Otherwise we need to reset elements.
if (i >= 0)
{
i++;
while (i < slotOrdering.size())
{
const ScriptCanvas::SlotId& indexPoint = slotOrdering[i];
auto groupDataIter = groupDataTypes.find(indexPoint);
if (groupDataIter != groupDataTypes.end())
{
groupDataIter->second = m_availableVariableIds;
}
i++;
}
}
else
{
break;
}
}
if (!usedGraphCanvasNodeIds.empty())
{
// Create a group to create some visual chunking that'll look nice.
//
// Need to force one group per element for visual chunkiness.
// Each group will also represent the end of a chunk for the row(otherwise weird overlap issues could visually occur)
AZ::EntityId groupId = GraphCanvas::GraphUtils::CreateGroupForElements(m_graphCanvasGraphId, usedGraphCanvasNodeIds);
GraphCanvas::CommentRequestBus::Event(groupId, &GraphCanvas::CommentRequests::SetComment, "New Group");
if (groupId.IsValid())
{
tempWidth = origWidth;
tempHeight = origHeight;
tempRowHeight = origRowHeight;
DeveloperUtils::UpdateViewportPositionOffsetForNode(groupId, m_viewportRectangle, tempWidth, tempHeight, tempRowHeight, m_minorPitch);
// If we got kicked down to a new row. Nothing left to do.
if (tempRowHeight <= 0)
{
m_widthOffset = tempWidth;
m_heightOffset = tempHeight;
m_maxRowHeight = tempRowHeight;
}
else
{
m_widthOffset = 0;
m_heightOffset = origHeight + tempRowHeight + aznumeric_cast<int>(m_minorPitch.GetY());
m_maxRowHeight = 0;
}
GraphCanvas::CommentRequestBus::Event(groupId, &GraphCanvas::CommentRequests::SetComment, protoTypeNode->GetDebugName().c_str());
}
}
AZStd::unordered_set< AZ::EntityId > deleteSet = {
GraphCanvas::GraphUtils::FindOutermostNode(nodeIdPair.m_graphCanvasId)
};
GraphCanvas::SceneRequestBus::Event(m_graphCanvasGraphId, &GraphCanvas::SceneRequests::Delete, deleteSet);
}
ScriptCanvasEditor::NodeIdPair ProcessMimeEvent(GraphCanvas::GraphCanvasMimeEvent* currentEvent)
{
int tempWidth = m_widthOffset;
int tempHeight = m_heightOffset;
int tempRowHeight = m_maxRowHeight;
auto nodeIdPair = DeveloperUtils::HandleMimeEvent(currentEvent, m_graphCanvasGraphId, m_viewportRectangle, tempWidth, tempHeight, tempRowHeight, m_minorPitch);
if (HasDynamicSlots(nodeIdPair))
{
PopulateSlots(currentEvent, nodeIdPair);
}
return nodeIdPair;
}
GraphCanvas::Endpoint ConvertToGraphCanvasEndpoint(const ScriptCanvas::Endpoint& endpoint)
{
GraphCanvas::Endpoint graphCanvasEndpoint;
ScriptCanvasEditor::SlotMappingRequestBus::EventResult(graphCanvasEndpoint.m_slotId, endpoint.GetNodeId(), &ScriptCanvasEditor::SlotMappingRequests::MapToGraphCanvasId, endpoint.GetSlotId());
GraphCanvas::SlotRequestBus::EventResult(graphCanvasEndpoint.m_nodeId, graphCanvasEndpoint.GetSlotId(), &GraphCanvas::SlotRequests::GetNode);
return graphCanvasEndpoint;
}
AZ::EntityId m_graphCanvasGraphId;
ScriptCanvas::ScriptCanvasId m_scriptCanvasId;
AZ::Vector2 m_nodeCreationPos = AZ::Vector2::CreateZero();
AZ::EntityId m_viewId;
AZ::EntityId m_gridId;
AZ::Vector2 m_minorPitch = AZ::Vector2::CreateZero();
QRectF m_viewportRectangle;
int m_widthOffset = 0;
int m_heightOffset = 0;
int m_maxRowHeight = 0;
ScriptCanvas::Graph* m_graph = nullptr;
AZStd::vector<ScriptCanvas::VariableId> m_availableVariableIds;
AZStd::unordered_map<ScriptCanvas::VariableId, ScriptCanvas::Data::Type> m_variableTypeMapping;
};
void VariablePaletteFullCreationAction()
{
ScriptCanvasEditor::AutomationRequestBus::Broadcast(&ScriptCanvasEditor::AutomationRequests::SignalAutomationBegin);
DynamicSlotFullCreationInterface fullCreationInterface;
DeveloperUtils::ProcessNodePalette(fullCreationInterface);
ScriptCanvasEditor::AutomationRequestBus::Broadcast(&ScriptCanvasEditor::AutomationRequests::SignalAutomationEnd);
}
QAction* CreateDynamicSlotFullCreationAction(QWidget* mainWindow)
{
QAction* createVariablePaletteAction = nullptr;
if (mainWindow)
{
createVariablePaletteAction = new QAction(QAction::tr("Create Dynamic Node Range"), mainWindow);
createVariablePaletteAction->setAutoRepeat(false);
createVariablePaletteAction->setToolTip("Tries to create every node in the node palette with dynamic slots. And will generate variations of the node with variables assigned to each slot in each combination depending on what variables are available in the Variable Manager.");
createVariablePaletteAction->setShortcut(QKeySequence(QAction::tr("Ctrl+Shift+k", "Debug|Create Variable Palette")));
mainWindow->addAction(createVariablePaletteAction);
mainWindow->connect(createVariablePaletteAction, &QAction::triggered, &VariablePaletteFullCreationAction);
}
return createVariablePaletteAction;
}
}
}
@@ -0,0 +1,130 @@
/*
* 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 "precompiled.h"
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/GridBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <GraphCanvas/Editor/EditorTypes.h>
#include <GraphCanvas/Widgets/GraphCanvasGraphicsView/GraphCanvasGraphicsView.h>
#include <GraphCanvas/Widgets/NodePalette/TreeItems/NodePaletteTreeItem.h>
#include <Editor/View/Widgets/NodePalette/CreateNodeMimeEvent.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <Editor/Include/ScriptCanvas/Bus/NodeIdPair.h>
#include <ScriptCanvasDeveloperEditor/AutomationActions/NodePaletteFullCreation.h>
#include <ScriptCanvasDeveloperEditor/DeveloperUtils.h>
namespace ScriptCanvasDeveloperEditor
{
namespace NodePaletteFullCreation
{
class FullCreationNodePaletteInterface
: public ProcessNodePaletteInterface
{
public:
void SetupInterface(const AZ::EntityId& activeGraphCanvasGraphId, const ScriptCanvas::ScriptCanvasId& scriptCanvasId)
{
m_graphCanvasGraphId = activeGraphCanvasGraphId;
m_scriptCanvasId = scriptCanvasId;
GraphCanvas::SceneRequestBus::EventResult(m_viewId, activeGraphCanvasGraphId, &GraphCanvas::SceneRequests::GetViewId);
GraphCanvas::SceneRequestBus::EventResult(m_gridId, activeGraphCanvasGraphId, &GraphCanvas::SceneRequests::GetGrid);
GraphCanvas::GridRequestBus::EventResult(m_minorPitch, m_gridId, &GraphCanvas::GridRequests::GetMinorPitch);
GraphCanvas::ViewRequestBus::EventResult(m_nodeCreationPos, m_viewId, &GraphCanvas::ViewRequests::GetViewSceneCenter);
GraphCanvas::GraphCanvasGraphicsView* graphicsView = nullptr;
GraphCanvas::ViewRequestBus::EventResult(graphicsView, m_viewId, &GraphCanvas::ViewRequests::AsGraphicsView);
m_viewportRectangle = graphicsView->mapToScene(graphicsView->viewport()->geometry()).boundingRect();
}
bool ShouldProcessItem([[maybe_unused]] const GraphCanvas::NodePaletteTreeItem* nodePaletteTreeItem) const
{
return true;
}
void ProcessItem(const GraphCanvas::NodePaletteTreeItem* nodePaletteTreeItem)
{
GraphCanvas::GraphCanvasMimeEvent* mimeEvent = nodePaletteTreeItem->CreateMimeEvent();
if (ScriptCanvasEditor::MultiCreateNodeMimeEvent* multiCreateMimeEvent = azrtti_cast<ScriptCanvasEditor::MultiCreateNodeMimeEvent*>(mimeEvent))
{
AZStd::vector< GraphCanvas::GraphCanvasMimeEvent* > mimeEvents = multiCreateMimeEvent->CreateMimeEvents();
for (GraphCanvas::GraphCanvasMimeEvent* currentEvent : mimeEvents)
{
DeveloperUtils::HandleMimeEvent(currentEvent, m_graphCanvasGraphId, m_viewportRectangle, m_widthOffset, m_heightOffset, m_maxRowHeight, m_minorPitch);
delete currentEvent;
}
}
else if (mimeEvent)
{
DeveloperUtils::HandleMimeEvent(mimeEvent, m_graphCanvasGraphId, m_viewportRectangle, m_widthOffset, m_heightOffset, m_maxRowHeight, m_minorPitch);
}
}
private:
AZ::EntityId m_graphCanvasGraphId;
ScriptCanvas::ScriptCanvasId m_scriptCanvasId;
AZ::Vector2 m_nodeCreationPos = AZ::Vector2::CreateZero();
AZ::EntityId m_viewId;
AZ::EntityId m_gridId;
AZ::Vector2 m_minorPitch = AZ::Vector2::CreateZero();
QRectF m_viewportRectangle;
int m_widthOffset = 0;
int m_heightOffset = 0;
int m_maxRowHeight = 0;
int creationCounter = 100;
};
void NodePaletteFullCreationAction()
{
ScriptCanvasEditor::AutomationRequestBus::Broadcast(&ScriptCanvasEditor::AutomationRequests::SignalAutomationBegin);
FullCreationNodePaletteInterface nodePaletteInterface;
DeveloperUtils::ProcessNodePalette(nodePaletteInterface);
ScriptCanvasEditor::AutomationRequestBus::Broadcast(&ScriptCanvasEditor::AutomationRequests::SignalAutomationEnd);
}
QAction* CreateNodePaletteFullCreationAction(QWidget* mainWindow)
{
QAction* createNodePaletteAction = nullptr;
if (mainWindow)
{
createNodePaletteAction = new QAction(QAction::tr("Create Node Palette"), mainWindow);
createNodePaletteAction->setAutoRepeat(false);
createNodePaletteAction->setToolTip("Tries to create every node in the node palette. All of them. At once.");
createNodePaletteAction->setShortcut(QKeySequence(QAction::tr("Ctrl+Shift+h", "Debug|Create Node Palette")));
mainWindow->addAction(createNodePaletteAction);
mainWindow->connect(createNodePaletteAction, &QAction::triggered, &NodePaletteFullCreationAction);
}
return createNodePaletteAction;
}
}
}
@@ -0,0 +1,105 @@
/*
* 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 "precompiled.h"
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/GridBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <GraphCanvas/Editor/EditorTypes.h>
#include <GraphCanvas/Widgets/GraphCanvasGraphicsView/GraphCanvasGraphicsView.h>
#include <GraphCanvas/Widgets/NodePalette/TreeItems/NodePaletteTreeItem.h>
#include <Editor/View/Widgets/NodePalette/CreateNodeMimeEvent.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <Editor/Include/ScriptCanvas/Bus/NodeIdPair.h>
#include <ScriptCanvasDeveloperEditor/AutomationActions/VariableListFullCreation.h>
#include <ScriptCanvasDeveloperEditor/DeveloperUtils.h>
namespace ScriptCanvasDeveloperEditor
{
namespace VariablePaletteFullCreation
{
class VariablePaletteFullCreationInterface
: public ProcessVariablePaletteInterface
{
public:
VariablePaletteFullCreationInterface()
{
m_variableNameFormat = AZ::Uuid::CreateRandom().ToString<AZStd::string>().c_str();
m_variableNameFormat += " %i";
}
~VariablePaletteFullCreationInterface()
{
}
void SetupInterface([[maybe_unused]] const AZ::EntityId& graphCanvasId, const ScriptCanvas::ScriptCanvasId& scriptCanvasId)
{
m_variableRequests = ScriptCanvas::GraphVariableManagerRequestBus::FindFirstHandler(scriptCanvasId);
}
bool ShouldProcessVariableType([[maybe_unused]] const ScriptCanvas::Data::Type& dataType) const
{
return true;
}
void ProcessVariableType(const ScriptCanvas::Data::Type& dataType)
{
AZStd::string variableName = AZStd::string::format(m_variableNameFormat.c_str(), m_variableCounter);
ScriptCanvas::Datum datum(dataType, ScriptCanvas::Datum::eOriginality::Original);
AZ::Outcome<ScriptCanvas::VariableId, AZStd::string> outcome = AZ::Failure(AZStd::string());
m_variableRequests->AddVariable(variableName, datum);
++m_variableCounter;
}
private:
AZStd::string m_variableNameFormat;
int m_variableCounter = 0;
ScriptCanvas::GraphVariableManagerRequests* m_variableRequests = nullptr;
};
void VariablePaletteFullCreationAction()
{
ScriptCanvasEditor::AutomationRequestBus::Broadcast(&ScriptCanvasEditor::AutomationRequests::SignalAutomationBegin);
VariablePaletteFullCreationInterface fullCreationInterface;
DeveloperUtils::ProcessVariablePalette(fullCreationInterface);
ScriptCanvasEditor::AutomationRequestBus::Broadcast(&ScriptCanvasEditor::AutomationRequests::SignalAutomationEnd);
}
QAction* CreateVariablePaletteFullCreationAction(QWidget* mainWindow)
{
QAction* createVariablePaletteAction = nullptr;
if (mainWindow)
{
createVariablePaletteAction = new QAction(QAction::tr("Create Node Palette"), mainWindow);
createVariablePaletteAction->setAutoRepeat(false);
createVariablePaletteAction->setToolTip("Tries to create every variable in the variable palette. All of them. At once.");
createVariablePaletteAction->setShortcut(QKeySequence(QAction::tr("Ctrl+Shift+j", "Debug|Create Variable Palette")));
mainWindow->addAction(createVariablePaletteAction);
mainWindow->connect(createVariablePaletteAction, &QAction::triggered, &VariablePaletteFullCreationAction);
}
return createVariablePaletteAction;
}
}
}
@@ -0,0 +1,57 @@
/*
* 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 "precompiled.h"
#include <ScriptCanvasDeveloperEditor/Developer.h>
#include <ScriptCanvasDeveloperEditor/Mock.h>
#include <ScriptCanvasDeveloperEditor/WrapperMock.h>
#include <ScriptCanvas/Libraries/Libraries.h>
namespace ScriptCanvasDeveloper
{
namespace Libraries
{
void Developer::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<Developer, ScriptCanvas::Library::LibraryDefinition>()
->Version(1)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<Developer>("Developer", "Library of Developer only nodes")->
ClassElement(AZ::Edit::ClassElements::EditorData, "")->
Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/ScriptCanvas/ScriptCanvas.png")
;
}
}
}
void Developer::InitNodeRegistry(ScriptCanvas::NodeRegistry& nodeRegistry)
{
ScriptCanvas::Library::AddNodeToRegistry<Developer, Nodes::Mock>(nodeRegistry);
ScriptCanvas::Library::AddNodeToRegistry<Developer, Nodes::WrapperMock>(nodeRegistry);
}
AZStd::vector<AZ::ComponentDescriptor*> Developer::GetComponentDescriptors()
{
return AZStd::vector<AZ::ComponentDescriptor*>({
Nodes::Mock::CreateDescriptor(),
Nodes::WrapperMock::CreateDescriptor()
});
}
}
}
@@ -0,0 +1,158 @@
/*
* 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 "precompiled.h"
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/GridBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <GraphCanvas/Editor/EditorTypes.h>
#include <GraphCanvas/Components/Nodes/NodeUIBus.h>
#include <GraphCanvas/Widgets/GraphCanvasGraphicsView/GraphCanvasGraphicsView.h>
#include <GraphCanvas/Widgets/NodePalette/TreeItems/NodePaletteTreeItem.h>
#include <Editor/View/Widgets/NodePalette/CreateNodeMimeEvent.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <ScriptCanvasDeveloperEditor/DeveloperUtils.h>
namespace ScriptCanvasDeveloperEditor
{
///////////////////
// DeveloperUtils
///////////////////
ScriptCanvasEditor::NodeIdPair DeveloperUtils::HandleMimeEvent(GraphCanvas::GraphCanvasMimeEvent* mimeEvent, GraphCanvas::GraphId graphCanvasGraphId, const QRectF& viewportRectangle, int& widthOffset, int& heightOffset, int& maxRowHeight, AZ::Vector2 spacing)
{
AZ::Vector2 position(aznumeric_cast<float>(viewportRectangle.x()) + widthOffset, aznumeric_cast<float>(viewportRectangle.y()) + heightOffset);
ScriptCanvasEditor::NodeIdPair createdPair;
ScriptCanvasEditor::AutomationRequestBus::BroadcastResult(createdPair, &ScriptCanvasEditor::AutomationRequests::ProcessCreateNodeMimeEvent, mimeEvent, graphCanvasGraphId, position);
UpdateViewportPositionOffsetForNode(createdPair.m_graphCanvasId, viewportRectangle, widthOffset, heightOffset, maxRowHeight, spacing);
GraphCanvas::SceneNotificationBus::Event(graphCanvasGraphId, &GraphCanvas::SceneNotifications::PostCreationEvent);
return createdPair;
}
void DeveloperUtils::UpdateViewportPositionOffsetForNode(GraphCanvas::NodeId nodeId, const QRectF& viewportRectangle, int& widthOffset, int& heightOffset, int& maxRowHeight, AZ::Vector2 spacing)
{
QGraphicsItem* graphicsWidget = nullptr;
GraphCanvas::SceneMemberUIRequestBus::EventResult(graphicsWidget, nodeId, &GraphCanvas::SceneMemberUIRequests::GetRootGraphicsItem);
GraphCanvas::NodeUIRequestBus::Event(nodeId, &GraphCanvas::NodeUIRequests::AdjustSize);
if (graphicsWidget)
{
int height = aznumeric_cast<int>(graphicsWidget->boundingRect().height());
if (height > maxRowHeight)
{
maxRowHeight = height;
}
widthOffset += aznumeric_cast<int>(graphicsWidget->boundingRect().width() + spacing.GetX());
if (widthOffset >= viewportRectangle.width())
{
widthOffset = 0;
heightOffset += maxRowHeight + aznumeric_cast<int>(spacing.GetY());
maxRowHeight = 0;
}
}
}
void DeveloperUtils::ProcessNodePalette(ProcessNodePaletteInterface& processNodePaletteInterface)
{
AZ::EntityId activeGraphCanvasGraphId;
ScriptCanvasEditor::GeneralRequestBus::BroadcastResult(activeGraphCanvasGraphId, &ScriptCanvasEditor::GeneralRequests::GetActiveGraphCanvasGraphId);
ScriptCanvas::ScriptCanvasId activeScriptCanvasId;
ScriptCanvasEditor::GeneralRequestBus::BroadcastResult(activeScriptCanvasId, &ScriptCanvasEditor::GeneralRequests::GetActiveScriptCanvasId);
if (activeGraphCanvasGraphId.IsValid())
{
processNodePaletteInterface.SetupInterface(activeGraphCanvasGraphId, activeScriptCanvasId);
ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::PushPreventUndoStateUpdate);
const GraphCanvas::GraphCanvasTreeItem* treeItem = nullptr;
ScriptCanvasEditor::AutomationRequestBus::BroadcastResult(treeItem, &ScriptCanvasEditor::AutomationRequests::GetNodePaletteRoot);
AZStd::list< const GraphCanvas::GraphCanvasTreeItem* > expandedItems;
expandedItems.emplace_back(treeItem);
while (!expandedItems.empty())
{
const GraphCanvas::GraphCanvasTreeItem* treeItem2 = expandedItems.front();
expandedItems.pop_front();
for (int i = 0; i < treeItem2->GetChildCount(); ++i)
{
expandedItems.emplace_back(treeItem2->FindChildByRow(i));
}
if (const GraphCanvas::NodePaletteTreeItem* nodePaletteTreeItem = azrtti_cast<const GraphCanvas::NodePaletteTreeItem*>(treeItem2))
{
if (processNodePaletteInterface.ShouldProcessItem(nodePaletteTreeItem))
{
AZ_TracePrintf("ScriptCanvas", "%s", nodePaletteTreeItem->GetName().toUtf8().data());
processNodePaletteInterface.ProcessItem(nodePaletteTreeItem);
}
else
{
continue;
}
}
else
{
continue;
}
}
ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::PopPreventUndoStateUpdate);
ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::PostUndoPoint, activeScriptCanvasId);
}
}
void DeveloperUtils::ProcessVariablePalette(ProcessVariablePaletteInterface& variablePaletteInterface)
{
AZ::EntityId activeGraphCanvasGraphId;
ScriptCanvasEditor::GeneralRequestBus::BroadcastResult(activeGraphCanvasGraphId, &ScriptCanvasEditor::GeneralRequests::GetActiveGraphCanvasGraphId);
ScriptCanvas::ScriptCanvasId activeScriptCanvasId;
ScriptCanvasEditor::GeneralRequestBus::BroadcastResult(activeScriptCanvasId, &ScriptCanvasEditor::GeneralRequests::GetActiveScriptCanvasId);
if (activeScriptCanvasId.IsValid())
{
variablePaletteInterface.SetupInterface(activeGraphCanvasGraphId, activeScriptCanvasId);
ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::PushPreventUndoStateUpdate);
AZStd::vector<ScriptCanvas::Data::Type> variableTypes;
ScriptCanvasEditor::VariableAutomationRequestBus::BroadcastResult(variableTypes, &ScriptCanvasEditor::VariableAutomationRequests::GetVariableTypes);
for (auto variableType : variableTypes)
{
if (variablePaletteInterface.ShouldProcessVariableType(variableType))
{
AZ_TracePrintf("ScriptCanvas", "Processing Variable Type - %s", ScriptCanvas::Data::GetName(variableType).c_str());
variablePaletteInterface.ProcessVariableType(variableType);
}
}
ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::PopPreventUndoStateUpdate);
ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::PostUndoPoint, activeScriptCanvasId);
}
}
}
@@ -0,0 +1,580 @@
/*
* 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 "precompiled.h"
#include <AzCore/std/containers/set.h>
#include <Editor/Nodes/NodeUtils.h>
#include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
#include <GraphCanvas/Components/Slots/SlotBus.h>
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/StyleBus.h>
#include <ScriptCanvas/Data/DataRegistry.h>
#include <ScriptCanvas/Bus/ScriptCanvasBus.h>
#include <ScriptCanvasDeveloperEditor/Mock.h>
namespace ScriptCanvasDeveloper
{
namespace Nodes
{
struct DataTypeNameSortFunctor
{
bool operator()(const AZStd::pair<Data::Type, AZStd::string_view>& lhs, const AZStd::pair<Data::Type, AZStd::string>& rhs) const
{
return lhs.second < rhs.second;
}
};
void SlotConfig::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<SlotConfig>()
->Version(0)
->Field("m_name", &SlotConfig::m_name)
->Field("m_toolTip", &SlotConfig::m_toolTip)
->Field("m_type", &SlotConfig::m_type)
->Field("m_slotId", &SlotConfig::m_slotId)
->Field("m_state", &SlotConfig::m_state)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<SlotConfig>("SlotConfig", "Configuration for slot")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->DataElement(AZ::Edit::UIHandlers::Default, &SlotConfig::m_name, "Slot Name", "Slot Name")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &SlotConfig::OnSlotNameChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &SlotConfig::m_toolTip, "Slot Tooltip", "Slot Tooltip")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &SlotConfig::OnSlotToolTipChanged)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlotConfig::m_type, "Slot Type", "The Data Type represented by this slot")
->Attribute(AZ::Edit::Attributes::GenericValueList, &SlotConfig::GetCreatableTypes)
->Attribute(AZ::Edit::Attributes::PostChangeNotify, &SlotConfig::OnSlotDataTypeChanged)
;
}
}
}
SlotConfig::SlotConfig()
: m_name("New Slot")
{
}
SlotConfig::~SlotConfig()
{
if (m_owner)
{
m_owner->m_pendingConfigRemovals.push_back(m_slotId);
}
}
AZStd::vector<AZStd::pair<Data::Type, AZStd::string>> SlotConfig::GetCreatableTypes()
{
if (!m_owner)
{
return AZStd::vector<AZStd::pair<Data::Type, AZStd::string>>{};
}
Slot* slot = m_owner->GetSlot(m_slotId);
SlotDescriptor slotDescriptor = slot ? slot->GetDescriptor() : SlotDescriptor();
if (slotDescriptor.IsExecution())
{
return AZStd::vector<AZStd::pair<Data::Type, AZStd::string>>{};
}
AZStd::set<AZStd::pair<Data::Type, AZStd::string_view>, DataTypeNameSortFunctor> sortedTypes;
sortedTypes.emplace(Data::Type::Invalid(), "");
AZStd::unordered_set<Data::Type> creatableTypes;
ScriptCanvasEditor::SystemRequestBus::Broadcast(&ScriptCanvasEditor::SystemRequests::GetEditorCreatableTypes, creatableTypes);
for (const Data::Type& creatableType : creatableTypes)
{
if (const AZ::BehaviorClass* behaviorClass = AZ::BehaviorContextHelper::GetClass(creatableType.GetAZType()))
{
if (AZ::FindAttribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, behaviorClass->m_attributes))
{
continue;
}
bool isDeprecated{};
if (auto isDeprecatedAttributePtr = AZ::FindAttribute(AZ::Script::Attributes::Deprecated, behaviorClass->m_attributes))
{
AZ::AttributeReader(nullptr, isDeprecatedAttributePtr).Read<bool>(isDeprecated);
}
if (isDeprecated)
{
continue;
}
}
sortedTypes.emplace(creatableType, Data::GetName(creatableType));
}
return AZStd::vector<AZStd::pair<Data::Type, AZStd::string>>(sortedTypes.begin(), sortedTypes.end());
}
AZ::Crc32 SlotConfig::OnSlotNameChanged()
{
if (m_owner)
{
auto gcSlotIt = AZStd::find_if(m_owner->m_graphCanvasSlotIds.begin(), m_owner->m_graphCanvasSlotIds.end(), [this](AZ::EntityId testSlotId)
{
AZStd::any* slotUserData{};
GraphCanvas::SlotRequestBus::EventResult(slotUserData, testSlotId, &GraphCanvas::SlotRequests::GetUserData);
auto scSlotId = AZStd::any_cast<SlotId>(slotUserData);
return scSlotId && *scSlotId == m_slotId;
});
if (gcSlotIt != m_owner->m_graphCanvasSlotIds.end())
{
AZ::EntityId gcSlotId = *gcSlotIt;
GraphCanvas::SlotRequestBus::Event(gcSlotId, &GraphCanvas::SlotRequests::SetName, m_name);
}
}
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
AZ::Crc32 SlotConfig::OnSlotToolTipChanged()
{
if (m_owner)
{
auto gcSlotIt = AZStd::find_if(m_owner->m_graphCanvasSlotIds.begin(), m_owner->m_graphCanvasSlotIds.end(), [this](AZ::EntityId testSlotId)
{
AZStd::any* slotUserData{};
GraphCanvas::SlotRequestBus::EventResult(slotUserData, testSlotId, &GraphCanvas::SlotRequests::GetUserData);
auto scSlotId = AZStd::any_cast<SlotId>(slotUserData);
return scSlotId && *scSlotId == m_slotId;
});
if (gcSlotIt != m_owner->m_graphCanvasSlotIds.end())
{
AZ::EntityId gcSlotId = *gcSlotIt;
GraphCanvas::SlotRequestBus::Event(gcSlotId, &GraphCanvas::SlotRequests::SetTooltip, m_toolTip);
}
}
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
void SlotConfig::OnSlotDataTypeChanged([[maybe_unused]] const Data::Type& oldDataType)
{
if (!m_owner)
{
return;
}
Slot* slot = m_owner->GetSlot(m_slotId);
SlotDescriptor slotDescriptor = slot ? slot->GetDescriptor() : SlotDescriptor();
if (slotDescriptor.IsExecution())
{
return;
}
m_owner->RemoveSlot(m_slotId);
m_slotId = {};
if (slotDescriptor.IsInput())
{
if (m_type.IsValid())
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = m_name;
slotConfiguration.m_toolTip = m_toolTip;
slotConfiguration.SetType(m_type);
slotConfiguration.SetConnectionType(ConnectionType::Input);
m_slotId = m_owner->AddSlot(slotConfiguration);
}
else
{
DynamicDataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = m_name;
slotConfiguration.m_toolTip = m_toolTip;
slotConfiguration.m_dynamicDataType = DynamicDataType::Any;
slotConfiguration.SetConnectionType(ConnectionType::Input);
m_slotId = m_owner->AddSlot(slotConfiguration);
}
}
else if (slotDescriptor.IsOutput())
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = m_name;
slotConfiguration.m_toolTip = m_toolTip;
slotConfiguration.SetType(m_type);
slotConfiguration.SetConnectionType(ConnectionType::Output);
m_slotId = m_owner->AddSlot(slotConfiguration);
}
}
void Mock::OnGraphCanvasNodeDisplayed(AZ::EntityId graphCanvasId)
{
if (!MockDescriptorRequestBus::Handler::BusIsConnected())
{
MockDescriptorRequestBus::Handler::BusConnect(GetEntityId());
m_graphCanvasNodeId = graphCanvasId;
SetUiEntityId(graphCanvasId);
OnNodeDisplayed(graphCanvasId);
}
}
void Mock::Reflect(AZ::ReflectContext* context)
{
SlotConfig::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<Mock, ScriptCanvas::Node>()
->Version(0)
->Field("m_uiEntityId", &Mock::m_graphCanvasNodeId)
->Field("m_uiSlotIds", &Mock::m_graphCanvasSlotIds)
->Field("m_nodeTitle", &Mock::m_nodeTitle)
->Field("m_nodeSubTitle", &Mock::m_nodeSubTitle)
->Field("m_dataInConfigArray", &Mock::m_dataInConfigArray)
->Field("m_dataOutConfigArray", &Mock::m_dataOutConfigArray)
->Field("m_executionInConfigArray", &Mock::m_executionInConfigArray)
->Field("m_executionOutConfigArray", &Mock::m_executionOutConfigArray)
->Field("m_nodeColorPaletteOverride", &Mock::m_nodeColorPaletteOverride);
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<Mock>("Mock", "Node for mocking node visuals")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->DataElement(AZ::Edit::UIHandlers::Default, &Mock::m_nodeTitle, "Node Title", "Node Title for this mock node")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &Mock::OnNodeTitleChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &Mock::m_nodeSubTitle, "Node Sub Title", "Node Sub Title for this mock node")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &Mock::OnNodeSubTitleChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &Mock::m_dataInConfigArray, "Data Input Slot Configuration", "Configuration array of adding/removing Mock data input slots")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &Mock::OnDataInSlotArrayChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &Mock::m_dataOutConfigArray, "Data Output Slot Configuration", "Configuration array of adding/removing Mock data output slots")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &Mock::OnDataOutSlotArrayChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &Mock::m_executionInConfigArray, "Execution Input Slot Configuration", "Configuration array of adding/removing Mock execution input slots")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &Mock::OnExecutionInSlotArrayChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &Mock::m_executionOutConfigArray, "Execution Output Slot Configuration", "Configuration array of adding/removing Mock execution output slots")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &Mock::OnExecutionOutSlotArrayChanged)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &Mock::m_nodeColorPaletteOverride, "Node Color Palette Override", "Updates the node color from one of the possible palettes")
->Attribute(AZ::Edit::Attributes::StringList, &Mock::GetColorPaletteList)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &Mock::OnNodeColorPaletteChanged)
;
}
}
}
Mock::Mock()
: m_nodeTitle("Mock")
, m_nodeSubTitle("Node")
{
}
Mock::~Mock()
{
ScriptCanvasEditor::EditorNodeNotificationBus::Handler::BusDisconnect();
GraphCanvas::NodeNotificationBus::Handler::BusDisconnect();
}
void Mock::OnInit()
{
ScriptCanvasEditor::EditorNodeNotificationBus::Handler::BusConnect(GetEntityId());
if (m_graphCanvasNodeId.IsValid())
{
GraphCanvas::NodeNotificationBus::Handler::BusConnect(m_graphCanvasNodeId);
GraphCanvas::SceneMemberNotificationBus::Handler::BusConnect(m_graphCanvasNodeId);
}
OnNodeTitleChanged();
OnNodeSubTitleChanged();
OnNodeColorPaletteChanged();
for (auto& slotConfig : m_executionInConfigArray)
{
slotConfig.m_owner = this;
slotConfig.OnSlotNameChanged();
slotConfig.OnSlotToolTipChanged();
}
for (auto& slotConfig : m_executionOutConfigArray)
{
slotConfig.m_owner = this;
slotConfig.OnSlotNameChanged();
slotConfig.OnSlotToolTipChanged();
}
for (auto& slotConfig : m_dataInConfigArray)
{
slotConfig.m_owner = this;
slotConfig.OnSlotNameChanged();
slotConfig.OnSlotToolTipChanged();
}
for (auto& slotConfig : m_dataOutConfigArray)
{
slotConfig.m_owner = this;
slotConfig.OnSlotNameChanged();
slotConfig.OnSlotToolTipChanged();
}
}
void Mock::SetUiEntityId(AZ::EntityId uiEntityId)
{
GraphCanvas::NodeNotificationBus::Handler::BusDisconnect();
m_graphCanvasNodeId = uiEntityId;
if (m_graphCanvasNodeId.IsValid())
{
GraphCanvas::NodeNotificationBus::Handler::BusConnect(m_graphCanvasNodeId);
}
}
void Mock::Clear()
{
m_graphCanvasNodeId.SetInvalid();
m_graphCanvasSlotIds.clear();
m_nodeTitle = "Mock";
OnNodeTitleChanged();
m_nodeSubTitle.clear();
OnNodeSubTitleChanged();
m_dataInConfigArray.clear();
OnDataInSlotArrayChanged();
m_dataOutConfigArray.clear();
OnDataOutSlotArrayChanged();
m_executionInConfigArray.clear();
OnExecutionInSlotArrayChanged();
m_executionInConfigArray.clear();
OnExecutionOutSlotArrayChanged();
OnClear();
}
void Mock::OnClear()
{
}
void Mock::OnNodeDisplayed([[maybe_unused]] const GraphCanvas::NodeId& nodeId)
{
}
AZ::Crc32 Mock::OnNodeTitleChanged()
{
GraphCanvas::NodeTitleRequestBus::Event(m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::SetTitle, m_nodeTitle);
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
AZ::Crc32 Mock::OnNodeSubTitleChanged()
{
GraphCanvas::NodeTitleRequestBus::Event(m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::SetSubTitle, m_nodeSubTitle);
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
AZ::Crc32 Mock::OnNodeColorPaletteChanged()
{
if (!m_nodeColorPaletteOverride.empty())
{
GraphCanvas::NodeTitleRequestBus::Event(m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::SetDefaultPalette, m_nodeColorPaletteOverride);
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
return AZ::Edit::PropertyRefreshLevels::None;
}
AZStd::vector<AZStd::string> Mock::GetColorPaletteList() const
{
AZStd::vector<AZStd::string> colorPaletteOptions;
AZ::EntityId uiSceneId;
GraphCanvas::SceneMemberRequestBus::EventResult(uiSceneId, m_graphCanvasNodeId, &GraphCanvas::SceneMemberRequests::GetScene);
GraphCanvas::EditorId editorId;
GraphCanvas::SceneRequestBus::EventResult(editorId, uiSceneId, &GraphCanvas::SceneRequests::GetEditorId);
GraphCanvas::StyleManagerRequestBus::EventResult(colorPaletteOptions, editorId, &GraphCanvas::StyleManagerRequests::GetColorPaletteStyles);
return colorPaletteOptions;
}
AZ::Crc32 Mock::OnDataInSlotArrayChanged()
{
const auto pendingConfigRemovals = AZStd::move(m_pendingConfigRemovals);
for (const auto& oldSlotId : pendingConfigRemovals)
{
RemoveSlot(oldSlotId);
}
for (auto& dataInConfig : m_dataInConfigArray)
{
dataInConfig.m_owner = this;
if (dataInConfig.m_state == SlotConfigState::New)
{
if (dataInConfig.m_type.IsValid())
{
DataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = dataInConfig.m_name;
slotConfiguration.m_toolTip = dataInConfig.m_toolTip;
slotConfiguration.SetType(dataInConfig.m_type);
slotConfiguration.SetConnectionType(ConnectionType::Input);
dataInConfig.m_slotId = AddSlot(slotConfiguration);
}
else
{
DynamicDataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = dataInConfig.m_name;
slotConfiguration.m_toolTip = dataInConfig.m_toolTip;
slotConfiguration.m_dynamicDataType = DynamicDataType::Any;
slotConfiguration.SetConnectionType(ConnectionType::Input);
dataInConfig.m_slotId = AddSlot(slotConfiguration);
}
dataInConfig.m_state = SlotConfigState::Unmodified;
}
}
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
AZ::Crc32 Mock::OnDataOutSlotArrayChanged()
{
const auto pendingConfigRemovals = AZStd::move(m_pendingConfigRemovals);
for (const auto& oldSlotId : pendingConfigRemovals)
{
RemoveSlot(oldSlotId);
}
for (auto& dataOutConfig : m_dataOutConfigArray)
{
dataOutConfig.m_owner = this;
if (dataOutConfig.m_state == SlotConfigState::New)
{
DynamicDataSlotConfiguration slotConfiguration;
slotConfiguration.m_name = dataOutConfig.m_name;
slotConfiguration.m_toolTip = dataOutConfig.m_toolTip;
slotConfiguration.SetConnectionType(ConnectionType::Output);
dataOutConfig.m_slotId = AddSlot(slotConfiguration);
dataOutConfig.m_state = SlotConfigState::Unmodified;
}
}
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
AZ::Crc32 Mock::OnExecutionInSlotArrayChanged()
{
const auto pendingConfigRemovals = AZStd::move(m_pendingConfigRemovals);
for (const auto& oldSlotId : pendingConfigRemovals)
{
RemoveSlot(oldSlotId);
}
for (auto& executionInConfig : m_executionInConfigArray)
{
executionInConfig.m_owner = this;
if (executionInConfig.m_state == SlotConfigState::New)
{
ExecutionSlotConfiguration slotConfiguration;
slotConfiguration.m_name = executionInConfig.m_name;
slotConfiguration.m_toolTip = executionInConfig.m_toolTip;
slotConfiguration.SetConnectionType(ConnectionType::Input);
executionInConfig.m_slotId = AddSlot(slotConfiguration);
executionInConfig.m_state = SlotConfigState::Unmodified;
}
}
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
AZ::Crc32 Mock::OnExecutionOutSlotArrayChanged()
{
const auto pendingConfigRemovals = AZStd::move(m_pendingConfigRemovals);
for (const auto& oldSlotId : pendingConfigRemovals)
{
RemoveSlot(oldSlotId);
}
for (auto& executionOutConfig : m_executionOutConfigArray)
{
executionOutConfig.m_owner = this;
if (executionOutConfig.m_state == SlotConfigState::New)
{
ExecutionSlotConfiguration slotConfiguration;
slotConfiguration.m_name = executionOutConfig.m_name;
slotConfiguration.m_toolTip = executionOutConfig.m_toolTip;
slotConfiguration.SetConnectionType(ConnectionType::Output);
executionOutConfig.m_slotId = AddSlot(slotConfiguration);
executionOutConfig.m_state = SlotConfigState::Unmodified;
}
}
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
void Mock::OnSlotAddedToNode(const AZ::EntityId& slotId)
{
if (AZStd::find(m_graphCanvasSlotIds.begin(), m_graphCanvasSlotIds.end(), slotId) == m_graphCanvasSlotIds.end())
{
m_graphCanvasSlotIds.push_back(slotId);
}
}
void Mock::OnSlotRemovedFromNode(const AZ::EntityId& slotId)
{
auto slotIt = AZStd::find(m_graphCanvasSlotIds.begin(), m_graphCanvasSlotIds.end(), slotId);
if (slotIt == m_graphCanvasSlotIds.end())
{
m_graphCanvasSlotIds.erase(slotIt);
}
}
void Mock::OnAddedToScene([[maybe_unused]] const AZ::EntityId& sceneId)
{
OnNodeTitleChanged();
OnNodeSubTitleChanged();
OnNodeColorPaletteChanged();
for (auto& slotConfig : m_executionInConfigArray)
{
slotConfig.OnSlotNameChanged();
slotConfig.OnSlotToolTipChanged();
}
for (auto& slotConfig : m_executionOutConfigArray)
{
slotConfig.OnSlotNameChanged();
slotConfig.OnSlotToolTipChanged();
}
for (auto& slotConfig : m_dataInConfigArray)
{
slotConfig.OnSlotNameChanged();
slotConfig.OnSlotToolTipChanged();
}
for (auto& slotConfig : m_dataOutConfigArray)
{
slotConfig.m_owner = this;
slotConfig.OnSlotNameChanged();
slotConfig.OnSlotToolTipChanged();
}
MockDescriptorNotificationBus::Event(GetEntityId(), &MockDescriptorNotifications::OnGraphCanvasNodeSetup, m_graphCanvasNodeId);
}
void Mock::OnSceneMemberDeserialized([[maybe_unused]] const GraphCanvas::GraphId& graphId, [[maybe_unused]] const GraphCanvas::GraphSerialization& serialization)
{
OnGraphCanvasNodeDisplayed(m_graphCanvasNodeId);
}
}
}
@@ -0,0 +1,395 @@
/*
* 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 "precompiled.h"
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/string/string_view.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <ScriptCanvas/Bus/ScriptCanvasBus.h>
#include <ScriptCanvasDeveloperEditor/NodeListDumpAction.h>
#include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QMimeData>
namespace ScriptCanvasDeveloperEditor
{
namespace NodeListDumpAction
{
void DumpBehaviorContextNodes();
void DumpBehaviorContextMethods(AZStd::string& dumpStr);
void DumpBehaviorContextEbuses(AZStd::string& dumpStr);
QAction* CreateNodeListDumpAction(QWidget* mainWindow)
{
QAction* nodeDumpAction{};
if (mainWindow)
{
nodeDumpAction = new QAction(QAction::tr("Dump EBus Nodes"), mainWindow);
nodeDumpAction->setAutoRepeat(false);
nodeDumpAction->setToolTip("Dumps a list of all EBus nodes(their inputs and outputs) to the clipboard");
nodeDumpAction->setShortcut(QKeySequence(QAction::tr("Ctrl+Alt+N", "Debug|Dump EBus Nodes")));
mainWindow->addAction(nodeDumpAction);
mainWindow->connect(nodeDumpAction, &QAction::triggered, &DumpBehaviorContextNodes);
}
return nodeDumpAction;
}
namespace DumpInternal
{
const size_t maxInputParameters = 10;
}
void DumpBehaviorContextNodes()
{
AZStd::string nodeList = "Group Name,Class Name/Ebus Name,Event Name/Method Name,Output Type";
for (size_t i = 0; i < DumpInternal::maxInputParameters; ++i)
{
nodeList += ",Input Type " + AZStd::to_string(aznumeric_cast<int>(i) + 1);
}
nodeList += "\n";
DumpBehaviorContextMethods(nodeList);
DumpBehaviorContextEbuses(nodeList);
QMimeData* mime = new QMimeData;
mime->setData("text/plain", QByteArray(nodeList.cbegin(), static_cast<int>(nodeList.size())));
QClipboard* clipboard = QApplication::clipboard();
clipboard->setMimeData(mime);
}
void DumpBehaviorContextMethods(AZStd::string& dumpStr)
{
AZ::SerializeContext* serializeContext{};
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AZ::BehaviorContext* behaviorContext{};
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (serializeContext == nullptr || behaviorContext == nullptr)
{
return;
}
for (const auto& classIter : behaviorContext->m_classes)
{
const AZ::BehaviorClass* behaviorClass = classIter.second;
// Check for "ignore" attribute for ScriptCanvas
auto excludeClassAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, behaviorClass->m_attributes));
const bool excludeClass = excludeClassAttributeData && static_cast<AZ::u64>(excludeClassAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
if (excludeClass)
{
continue; // skip this class
}
AZStd::string_view categoryName;
if (auto categoryAttribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::Category, behaviorClass->m_attributes)))
{
categoryName = categoryAttribute->Get(nullptr);
}
bool canCreate = serializeContext->FindClassData(behaviorClass->m_typeId) != nullptr;
for (auto methodPair : behaviorClass->m_methods)
{
// Check for "ignore" attribute for ScriptCanvas
auto excludeMethodAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, methodPair.second->m_attributes));
const bool excludeMethod = excludeMethodAttributeData && static_cast<AZ::u64>(excludeMethodAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
if (excludeMethod)
{
continue; // skip this method
}
dumpStr += AZStd::string::format(R"("%s","%s","%s",)", !categoryName.empty() ? categoryName.data() : "", classIter.first.c_str(), methodPair.first.c_str());
AZ::BehaviorMethod* method = methodPair.second;
const auto result = method->HasResult() ? method->GetResult() : nullptr;
if (result)
{
AZStd::string resultType = result->m_name;
dumpStr += "\"" + resultType + "\"";
}
else
{
dumpStr += "\"void\"";
}
for (size_t i = 0; i < method->GetNumArguments(); ++i)
{
dumpStr += ",";
if (const AZ::BehaviorParameter* argument = method->GetArgument(i))
{
AZStd::string argType = argument->m_name;
dumpStr += "\"" + argType;
const AZStd::string* argName = method->GetArgumentName(i);
if (argName && !argName->empty())
{
dumpStr += "(" + *argName + ")";
const AZStd::string* argToolTip = method->GetArgumentToolTip(i);
if (argToolTip && !argToolTip->empty())
{
dumpStr += ": " + *argToolTip;
}
}
else if (i == 0 && method->IsMember())
{
dumpStr += "(This Pointer)";
}
dumpStr += "\"";
}
}
for (size_t i = method->GetNumArguments(); i < DumpInternal::maxInputParameters; ++i)
{
dumpStr += ",";
}
dumpStr += "\n";
}
}
}
void DumpBehaviorContextEBusHandlers(AZStd::string& dumpStr, AZ::BehaviorEBus* ebus, AZStd::string_view categoryName)
{
if (!ebus)
{
return;
}
if (!ebus->m_createHandler || !ebus->m_destroyHandler)
{
return;
}
AZ::BehaviorContext* behaviorContext{};
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
AZ::BehaviorEBusHandler* handler;
if (ebus->m_createHandler->InvokeResult(handler))
{
for (const AZ::BehaviorEBusHandler::BusForwarderEvent& event : handler->GetEvents())
{
dumpStr += AZStd::string::format(R"("%s","%s","%s",)", !categoryName.empty() ? categoryName.data() : "", ebus->m_name.c_str(), event.m_name);
if (event.HasResult())
{
const AZ::BehaviorParameter& resultParam = event.m_parameters[AZ::eBehaviorBusForwarderEventIndices::Result];
AZStd::string resultType = resultParam.m_name;
dumpStr += "\"" + resultType + "\"";
}
else
{
dumpStr += "\"void\"";
}
for (size_t i = AZ::eBehaviorBusForwarderEventIndices::ParameterFirst; i < event.m_parameters.size(); ++i)
{
const AZ::BehaviorParameter& argParam = event.m_parameters[i];
dumpStr += ",";
AZStd::string argType = argParam.m_name;
dumpStr += "\"" + argType;
AZStd::string argName = argType;
AZStd::string argToolTip = argType;
if (event.m_metadataParameters.size() > i)
{
argName = event.m_metadataParameters[i].m_name;
argToolTip = event.m_metadataParameters[i].m_toolTip;
}
if (!argName.empty())
{
dumpStr += "(" + argName + ")";
if (!argToolTip.empty())
{
dumpStr += ": " + argToolTip;
}
}
dumpStr += "\"";
}
for (size_t i = event.m_parameters.size(); i < DumpInternal::maxInputParameters; ++i)
{
dumpStr += ",";
}
dumpStr += "\n";
}
ebus->m_destroyHandler->Invoke(handler); // Destroys the Created EbusHandler
}
}
void DumpBehaviorContextEbuses(AZStd::string& dumpStr)
{
AZ::SerializeContext* serializeContext{};
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AZ::BehaviorContext* behaviorContext{};
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (serializeContext == nullptr || behaviorContext == nullptr)
{
return;
}
// We will skip buses that are ONLY registered on classes that derive from EditorComponentBase,
// because they don't have a runtime implementation. Buses such as the TransformComponent which
// is implemented by both an EditorComponentBase derived class and a Component derived class
// will still appear
AZStd::unordered_set<AZ::Crc32> skipBuses;
AZStd::unordered_set<AZ::Crc32> potentialSkipBuses;
AZStd::unordered_set<AZ::Crc32> nonSkipBuses;
for (const auto& classIter : behaviorContext->m_classes)
{
const AZ::BehaviorClass* behaviorClass = classIter.second;
// Check for "ignore" attribute for ScriptCanvas
auto excludeClassAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, behaviorClass->m_attributes));
const bool excludeClass = excludeClassAttributeData && static_cast<AZ::u64>(excludeClassAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
if (excludeClass)
{
for (const auto& requestBus : behaviorClass->m_requestBuses)
{
skipBuses.insert(AZ::Crc32(requestBus.c_str()));
}
continue; // skip this class
}
auto baseClass = AZStd::find(behaviorClass->m_baseClasses.begin(),
behaviorClass->m_baseClasses.end(),
AzToolsFramework::Components::EditorComponentBase::TYPEINFO_Uuid());
if (baseClass != behaviorClass->m_baseClasses.end())
{
for (const auto& requestBus : behaviorClass->m_requestBuses)
{
potentialSkipBuses.insert(AZ::Crc32(requestBus.c_str()));
}
}
// If the Ebus does not inherit from EditorComponentBase then do not skip it
else
{
for (const auto& requestBus : behaviorClass->m_requestBuses)
{
nonSkipBuses.insert(AZ::Crc32(requestBus.c_str()));
}
}
}
// Add buses which are not on the non-skip list to the skipBuses set
for (auto potentialSkipBus : potentialSkipBuses)
{
if (nonSkipBuses.find(potentialSkipBus) == nonSkipBuses.end())
{
skipBuses.insert(potentialSkipBus);
}
}
for (const auto& ebusIter : behaviorContext->m_ebuses)
{
AZ::BehaviorEBus* ebus = ebusIter.second;
if (ebus == nullptr)
{
continue;
}
auto excludeEbusAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, ebusIter.second->m_attributes));
const bool excludeBus = excludeEbusAttributeData && static_cast<AZ::u64>(excludeEbusAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
auto skipBusIterator = skipBuses.find(AZ::Crc32(ebusIter.first.c_str()));
if (skipBusIterator != skipBuses.end() || excludeBus)
{
continue;
}
AZStd::string_view categoryName;
if (auto categoryAttribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::Category, ebus->m_attributes)))
{
categoryName = categoryAttribute->Get(nullptr);
}
DumpBehaviorContextEBusHandlers(dumpStr, ebus, categoryName);
for (const auto& eventIter : ebus->m_events)
{
auto excludeEventAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, eventIter.second.m_attributes));
const bool excludeEvent = excludeEventAttributeData && static_cast<AZ::u64>(excludeEventAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
if (excludeEvent)
{
continue;
}
const AZ::BehaviorMethod* const method = eventIter.second.m_event ? eventIter.second.m_event : eventIter.second.m_broadcast;
if (!method)
{
continue;
}
dumpStr += AZStd::string::format(R"("%s","%s","%s",)", !categoryName.empty() ? categoryName.data() : "", ebusIter.first.c_str(), eventIter.first.c_str());
const auto& resultParam = method->HasResult() ? method->GetResult() : nullptr;
if (resultParam)
{
AZStd::string resultType = resultParam->m_name;
dumpStr += "\"" + resultType + "\"";
}
else
{
dumpStr += "\"void\"";
}
for (size_t i = 0; i < method->GetNumArguments(); ++i)
{
dumpStr += ",";
if (const auto& argParam = method->GetArgument(i))
{
AZStd::string argType = argParam->m_name;
dumpStr += "\"" + argType;
const AZStd::string* argName = method->GetArgumentName(i);
if (argName && !argName->empty())
{
dumpStr += "(" + *argName + ")";
const AZStd::string* argToolTip = method->GetArgumentToolTip(i);
if (argToolTip && !argToolTip->empty())
{
dumpStr += ": " + *argToolTip;
}
}
else if (i == 0 && method->HasBusId())
{
dumpStr += "(EBus ID)";
}
dumpStr += "\"";
}
}
for (size_t i = method->GetNumArguments(); i < DumpInternal::maxInputParameters; ++i)
{
dumpStr += ",";
}
dumpStr += "\n";
}
}
}
} // namespace NodeListDumpAction
}
@@ -0,0 +1,87 @@
/*
* 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 "precompiled.h"
#include <AzToolsFramework/UI/PropertyEditor/GenericComboBoxCtrl.h>
#include <ScriptCanvas/Libraries/Libraries.h>
#include <ScriptCanvas/Data/Data.h>
#include <ScriptCanvasDeveloperEditor/ScriptCanvasDeveloperEditorComponent.h>
#include <ScriptCanvasDeveloperEditor/NodeListDumpAction.h>
#include <ScriptCanvasDeveloperEditor/TSGenerateAction.h>
#include <ScriptCanvasDeveloperEditor/AutomationActions/DynamicSlotFullCreation.h>
#include <ScriptCanvasDeveloperEditor/AutomationActions/NodePaletteFullCreation.h>
#include <ScriptCanvasDeveloperEditor/AutomationActions/VariableListFullCreation.h>
#include <ScriptCanvasDeveloperEditor/Developer.h>
namespace ScriptCanvasDeveloperEditor
{
void SystemComponent::Reflect(AZ::ReflectContext* context)
{
ScriptCanvasDeveloper::Libraries::Developer::Reflect(context);
if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<SystemComponent, AZ::Component>()
->Version(0)
;
}
}
void SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("ScriptCanvasEditorService", 0x4fe2af98));
}
void SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("ScriptCanvasDeveloperEditorService", 0x344d3e44));
}
void SystemComponent::Init()
{
AZ::EnvironmentVariable<ScriptCanvas::NodeRegistry> nodeRegistryVariable = AZ::Environment::FindVariable<ScriptCanvas::NodeRegistry>(ScriptCanvas::s_nodeRegistryName);
if (nodeRegistryVariable)
{
ScriptCanvas::NodeRegistry& nodeRegistry = nodeRegistryVariable.Get();
ScriptCanvasDeveloper::Libraries::Developer::InitNodeRegistry(nodeRegistry);
}
}
void SystemComponent::Activate()
{
QWidget* mainWindow{};
ScriptCanvasEditor::UIRequestBus::BroadcastResult(mainWindow, &ScriptCanvasEditor::UIRequests::GetMainWindow);
if (mainWindow)
{
MainWindowCreationEvent(mainWindow);
}
ScriptCanvasEditor::UINotificationBus::Handler::BusConnect();
AzToolsFramework::RegisterGenericComboBoxHandler<ScriptCanvas::Data::Type>();
}
void SystemComponent::Deactivate()
{
ScriptCanvasEditor::UINotificationBus::Handler::BusDisconnect();
}
void SystemComponent::MainWindowCreationEvent(QWidget* mainWindow)
{
NodeListDumpAction::CreateNodeListDumpAction(mainWindow);
TSGenerateAction::SetupTSFileAction(mainWindow);
DynamicSlotFullCreation::CreateDynamicSlotFullCreationAction(mainWindow);
NodePaletteFullCreation::CreateNodePaletteFullCreationAction(mainWindow);
VariablePaletteFullCreation::CreateVariablePaletteFullCreationAction(mainWindow);
}
}
@@ -0,0 +1,58 @@
/*
* 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 "precompiled.h"
#include <ScriptCanvasDeveloper/ScriptCanvasDeveloperGem.h>
#include <ScriptCanvasDeveloper/ScriptCanvasDeveloperComponent.h>
#include <ScriptCanvasDeveloperEditor/ScriptCanvasDeveloperEditorComponent.h>
#include <ScriptCanvasDeveloperEditor/Developer.h>
namespace ScriptCanvasDeveloper
{
////////////////////////////////////////////////////////////////////////////
// ScriptCanvasDeveloperModule
////////////////////////////////////////////////////////////////////////////
//! Create ComponentDescriptors and add them to the list.
//! The descriptors will be registered at the appropriate time.
//! The descriptors will be destroyed (and thus unregistered) at the appropriate time.
ScriptCanvasDeveloperModule::ScriptCanvasDeveloperModule()
: AZ::Module()
{
m_descriptors.insert(m_descriptors.end(), {
ScriptCanvasDeveloper::SystemComponent::CreateDescriptor(),
ScriptCanvasDeveloperEditor::SystemComponent::CreateDescriptor()
});
AZStd::vector<AZ::ComponentDescriptor*> componentDescriptors(ScriptCanvasDeveloper::Libraries::Developer::GetComponentDescriptors());
m_descriptors.insert(m_descriptors.end(), componentDescriptors.begin(), componentDescriptors.end());
}
ScriptCanvasDeveloperModule::~ScriptCanvasDeveloperModule()
{
}
AZ::ComponentTypeList ScriptCanvasDeveloperModule::GetRequiredSystemComponents() const
{
AZ::ComponentTypeList components;
components.insert(components.end(), std::initializer_list<AZ::Uuid> {
azrtti_typeid<ScriptCanvasDeveloper::SystemComponent>(),
azrtti_typeid<ScriptCanvasDeveloperEditor::SystemComponent>()
});
return components;
}
}
AZ_DECLARE_MODULE_CLASS(Gem_ScriptCanvasDeveloperGem, ScriptCanvasDeveloper::ScriptCanvasDeveloperModule)
@@ -0,0 +1,441 @@
/*
* 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 "precompiled.h"
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/string/conversions.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <ScriptCanvas/Bus/ScriptCanvasBus.h>
#include <ScriptCanvas/Data/Data.h>
#include <ScriptCanvasDeveloperEditor/TSGenerateAction.h>
#include <XMLDoc.h>
#include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QMimeData>
namespace ScriptCanvasDeveloperEditor
{
namespace TSGenerateAction
{
void GenerateTSFile();
void DumpBehaviorContextMethods(const XMLDocPtr& doc);
void DumpBehaviorContextEbuses(const XMLDocPtr& doc);
void DumpBehaviorContextEBusHandlers(const XMLDocPtr& doc, AZ::BehaviorEBus* ebus, const AZStd::string& categoryName);
bool StartContext(const XMLDocPtr& doc, const AZStd::string& contextType, const AZStd::string& contextName, const AZStd::string& toolTip, const AZStd::string& categoryName, bool addContextTypeToKey= false);
void AddMessageNode(const XMLDocPtr& doc, const AZStd::string& classorbusName, const AZStd::string& eventormethodName, const AZStd::string& toolTip, const AZStd::string& categoryName, const AZ::BehaviorEBusHandler::BusForwarderEvent& event);
void AddMessageNode(const XMLDocPtr& doc, const AZStd::string& classorbusName, const AZStd::string& eventormethodName, const AZStd::string& toolTip, const AZStd::string& categoryName, const AZ::BehaviorMethod* method);
QAction* SetupTSFileAction(QWidget* mainWindow)
{
QAction* qAction = nullptr;
if (mainWindow)
{
qAction = new QAction(QAction::tr("Create EBus Localization File"), mainWindow);
qAction->setAutoRepeat(false);
qAction->setToolTip("Creates a QT .TS file of all EBus nodes(their inputs and outputs) to a file in the current folder.");
qAction->setShortcut(QKeySequence(QAction::tr("Ctrl+Alt+X", "Debug|Build EBus .TS file")));
mainWindow->addAction(qAction);
mainWindow->connect(qAction, &QAction::triggered, &GenerateTSFile);
}
return qAction;
}
void GenerateTSFile()
{
AZStd::string tsFileName("@devroot@/editor/translation/scriptcanvas_en_us.ts");
XMLDocPtr tsDoc(XMLDoc::LoadFromDisk(tsFileName));
if (tsDoc == nullptr)
{
tsDoc = XMLDoc::Alloc("ScriptCanvas");
}
DumpBehaviorContextMethods(tsDoc);
DumpBehaviorContextEbuses(tsDoc);
tsDoc->WriteToDisk(tsFileName);
}
void DumpBehaviorContextMethods(const XMLDocPtr& doc)
{
AZ::SerializeContext* serializeContext{};
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AZ::BehaviorContext* behaviorContext{};
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (serializeContext == nullptr || behaviorContext == nullptr)
{
return;
}
for (const auto& classIter : behaviorContext->m_classes)
{
const AZ::BehaviorClass* behaviorClass = classIter.second;
// Check for "ignore" attribute for ScriptCanvas
auto excludeClassAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, behaviorClass->m_attributes));
const bool excludeClass = excludeClassAttributeData && static_cast<AZ::u64>(excludeClassAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
if (excludeClass)
{
continue; // skip this class
}
AZStd::string categoryName;
if (auto categoryAttribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::Category, behaviorClass->m_attributes)))
{
categoryName = categoryAttribute->Get(nullptr);
}
AZStd::string methodToolTip;
if (auto methodToolTipAttribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::ToolTip, behaviorClass->m_attributes)))
{
methodToolTip = methodToolTipAttribute->Get(nullptr);
}
bool addContext = false;
for (auto methodPair : behaviorClass->m_methods)
{
// Check for "ignore" attribute for ScriptCanvas
auto excludeMethodAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, methodPair.second->m_attributes));
const bool excludeMethod = excludeMethodAttributeData && static_cast<AZ::u64>(excludeMethodAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
if (excludeMethod)
{
continue; // skip this method
}
if( !addContext )
{
StartContext(doc, "Method", classIter.first, methodToolTip, categoryName);
addContext = true;
}
AZStd::string toolTip;
if (auto toolTipAttribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::ToolTip, methodPair.second->m_attributes)))
{
toolTip = toolTipAttribute->Get(nullptr);
}
AZStd::string nodeCategoryName;
if (auto attribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::Category, methodPair.second->m_attributes)))
{
nodeCategoryName = attribute->Get(nullptr);
}
AddMessageNode(doc, classIter.first, methodPair.first, toolTip, nodeCategoryName, methodPair.second);
}
}
}
void DumpBehaviorContextEbuses(const XMLDocPtr& doc)
{
AZ::SerializeContext* serializeContext{};
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AZ::BehaviorContext* behaviorContext{};
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
if (serializeContext == nullptr || behaviorContext == nullptr)
{
return;
}
// We will skip buses that are ONLY registered on classes that derive from EditorComponentBase,
// because they don't have a runtime implementation. Buses such as the TransformComponent which
// is implemented by both an EditorComponentBase derived class and a Component derived class
// will still appear
AZStd::unordered_set<AZ::Crc32> skipBuses;
AZStd::unordered_set<AZ::Crc32> potentialSkipBuses;
AZStd::unordered_set<AZ::Crc32> nonSkipBuses;
for (const auto& classIter : behaviorContext->m_classes)
{
const AZ::BehaviorClass* behaviorClass = classIter.second;
// Check for "ignore" attribute for ScriptCanvas
auto excludeClassAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, behaviorClass->m_attributes));
const bool excludeClass = excludeClassAttributeData && static_cast<AZ::u64>(excludeClassAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
if (excludeClass)
{
for (const auto& requestBus : behaviorClass->m_requestBuses)
{
skipBuses.insert(AZ::Crc32(requestBus.c_str()));
}
continue; // skip this class
}
auto baseClass = AZStd::find(behaviorClass->m_baseClasses.begin(),
behaviorClass->m_baseClasses.end(),
AzToolsFramework::Components::EditorComponentBase::TYPEINFO_Uuid());
if (baseClass != behaviorClass->m_baseClasses.end())
{
for (const auto& requestBus : behaviorClass->m_requestBuses)
{
potentialSkipBuses.insert(AZ::Crc32(requestBus.c_str()));
}
}
// If the Ebus does not inherit from EditorComponentBase then do not skip it
else
{
for (const auto& requestBus : behaviorClass->m_requestBuses)
{
nonSkipBuses.insert(AZ::Crc32(requestBus.c_str()));
}
}
}
// Add buses which are not on the non-skip list to the skipBuses set
for (auto potentialSkipBus : potentialSkipBuses)
{
if (nonSkipBuses.find(potentialSkipBus) == nonSkipBuses.end())
{
skipBuses.insert(potentialSkipBus);
}
}
for (const auto& ebusIter : behaviorContext->m_ebuses)
{
bool addContext = false;
AZ::BehaviorEBus* ebus = ebusIter.second;
if (ebus == nullptr)
{
continue;
}
auto excludeEbusAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, ebusIter.second->m_attributes));
const bool excludeBus = excludeEbusAttributeData && static_cast<AZ::u64>(excludeEbusAttributeData->Get(nullptr)) & static_cast<AZ::u64>(AZ::Script::Attributes::ExcludeFlags::Documentation);
auto skipBusIterator = skipBuses.find(AZ::Crc32(ebusIter.first.c_str()));
if (!ebus || skipBusIterator != skipBuses.end() || excludeBus)
{
continue;
}
AZStd::string categoryName;
if (auto categoryAttribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::Category, ebus->m_attributes)))
{
auto categoryAttribName = categoryAttribute->Get(nullptr);
if (categoryAttribName != nullptr)
{
categoryName = categoryAttribName;
}
}
DumpBehaviorContextEBusHandlers(doc, ebus, categoryName);
for (const auto& eventIter : ebus->m_events)
{
const AZ::BehaviorMethod* const method = (eventIter.second.m_event != nullptr) ? eventIter.second.m_event : eventIter.second.m_broadcast;
if (!method || AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, eventIter.second.m_attributes))
{
continue;
}
if( !addContext )
{
StartContext(doc, "EBus", ebusIter.first, ebusIter.second->m_toolTip, categoryName);
addContext = true;
}
AZStd::string toolTip;
if (auto toolTipAttribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::ToolTip, eventIter.second.m_attributes)))
{
toolTip = toolTipAttribute->Get(nullptr);
}
AZStd::string nodeCategoryName;
if (auto attribute = azrtti_cast<AZ::AttributeData<const char*>*>(AZ::FindAttribute(AZ::Script::Attributes::Category, eventIter.second.m_attributes)))
{
nodeCategoryName = attribute->Get(nullptr);
}
AddMessageNode(doc, ebusIter.first, eventIter.first, toolTip, nodeCategoryName, method);
}
}
}
void DumpBehaviorContextEBusHandlers(const XMLDocPtr& doc, AZ::BehaviorEBus* ebus, const AZStd::string& categoryName)
{
if (!ebus)
{
return;
}
if (!ebus->m_createHandler || !ebus->m_destroyHandler)
{
return;
}
AZ::BehaviorContext* behaviorContext{};
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
bool addContext = false;
AZ::BehaviorEBusHandler* handler(nullptr);
if (ebus->m_createHandler->InvokeResult(handler))
{
for (const AZ::BehaviorEBusHandler::BusForwarderEvent& event : handler->GetEvents())
{
if (!addContext)
{
StartContext(doc, "Handler", ebus->m_name, ebus->m_toolTip, categoryName, true);
addContext = true;
}
AddMessageNode(doc, ebus->m_name, event.m_name, "", categoryName, event);
}
ebus->m_destroyHandler->Invoke(handler); // Destroys the Created EbusHandler
}
}
AZStd::string GetBaseID(const AZStd::string& classorbusName, const AZStd::string& eventormethodName)
{
AZStd::string p1(classorbusName);
AZStd::string p2(eventormethodName);
AZStd::to_upper(p1.begin(), p1.end());
AZStd::to_upper(p2.begin(), p2.end());
return p1 + "_" + p2;
}
void AddCommonNodeElements(const XMLDocPtr& doc, const AZStd::string& baseID, const AZStd::string& classorbusName, const AZStd::string& eventormethodName, const AZStd::string& toolTip, const AZStd::string& categoryName)
{
doc->AddToContext(baseID + "_NAME", eventormethodName, AZStd::string::format("Class/Bus: %s Event/Method: %s", classorbusName.c_str(), eventormethodName.c_str()));
doc->AddToContext(baseID + "_TOOLTIP", toolTip);
doc->AddToContext(baseID + "_CATEGORY", categoryName);
doc->AddToContext(baseID + "_OUT_NAME");
doc->AddToContext(baseID + "_OUT_TOOLTIP");
doc->AddToContext(baseID + "_IN_NAME");
doc->AddToContext(baseID + "_IN_TOOLTIP");
}
void AddResultElements(const XMLDocPtr& doc, const AZStd::string& baseID, const AZ::Uuid& typeId, const AZStd::string& name, const AZStd::string& toolTip)
{
ScriptCanvas::Data::Type outputType(ScriptCanvas::Data::FromAZType(typeId));
doc->AddToContext(baseID + "_OUTPUT0_NAME", ScriptCanvas::Data::GetName(outputType), "C++ Type: " + name);
doc->AddToContext(baseID + "_OUTPUT0_TOOLTIP", toolTip);
}
void AddParameterElements(const XMLDocPtr& doc, const AZStd::string& baseID, size_t index, const AZ::Uuid& typeId, const AZStd::string& argName, const AZStd::string& argToolTip, const AZStd::string& cppType)
{
AZStd::string paramID(AZStd::string::format("%s_PARAM%zu_", baseID.c_str(), index));
ScriptCanvas::Data::Type outputType(ScriptCanvas::Data::FromAZType(typeId));
doc->AddToContext(paramID + "NAME", argName, AZStd::string::format("Simple Type: %s C++ Type: %s", ScriptCanvas::Data::GetName(outputType).c_str(), cppType.c_str()));
doc->AddToContext(paramID + "TOOLTIP", argToolTip);
}
void AddOutputElements(const XMLDocPtr& doc, const AZStd::string& baseID, size_t index, const AZ::Uuid& typeId, const AZStd::string& argName, const AZStd::string& argToolTip, const AZStd::string& cppType)
{
AZStd::string paramID(AZStd::string::format("%s_OUTPUT%zu_", baseID.c_str(), index));
ScriptCanvas::Data::Type outputType(ScriptCanvas::Data::FromAZType(typeId));
doc->AddToContext(paramID + "NAME", argName, AZStd::string::format("Simple Type: %s C++ Type: %s", ScriptCanvas::Data::GetName(outputType).c_str(), cppType.c_str()));
doc->AddToContext(paramID + "TOOLTIP", argToolTip);
}
bool StartContext(const XMLDocPtr& doc, const AZStd::string& contextType, const AZStd::string& contextName, const AZStd::string& toolTip, const AZStd::string& categoryName, bool addContextTypeToKey/* = false*/)
{
bool isNewContext = doc->StartContext(contextType + ": " + contextName);
if( isNewContext )
{
AZStd::string p1(contextName);
if(addContextTypeToKey)
{
p1 = contextType + "_" + p1;
}
p1 += "_";
AZStd::to_upper(p1.begin(), p1.end());
doc->AddToContext(p1 + "NAME", contextName);
doc->AddToContext(p1 + "TOOLTIP", toolTip);
doc->AddToContext(p1 + "CATEGORY", categoryName);
}
return isNewContext;
}
void AddMessageNode(const XMLDocPtr& doc, const AZStd::string& classorbusName, const AZStd::string& eventormethodName, const AZStd::string& toolTip, const AZStd::string& categoryName, const AZ::BehaviorEBusHandler::BusForwarderEvent& event)
{
AZStd::string baseID( "HANDLER_" + GetBaseID(classorbusName, eventormethodName));
if( !doc->MethodFamilyExists(baseID) )
{
AddCommonNodeElements(doc, baseID, classorbusName, eventormethodName, toolTip, categoryName);
if ( event.HasResult() )
{
const AZStd::string name = event.m_metadataParameters[AZ::eBehaviorBusForwarderEventIndices::Result].m_name.empty() ? event.m_parameters[AZ::eBehaviorBusForwarderEventIndices::Result].m_name : event.m_parameters[AZ::eBehaviorBusForwarderEventIndices::Result].m_name;
AddParameterElements(doc, baseID, 0, event.m_parameters[AZ::eBehaviorBusForwarderEventIndices::Result].m_typeId, name, event.m_metadataParameters[AZ::eBehaviorBusForwarderEventIndices::Result].m_toolTip, "");
AZ_TracePrintf("ScriptCanvas", "EBusHandler Index: 0 CategoryName: %s Ebus: %s Event: %s Name: %s", categoryName.c_str(), classorbusName.c_str(), eventormethodName.c_str(), name.c_str());
}
size_t outputIndex = 0;
for (size_t i = AZ::eBehaviorBusForwarderEventIndices::ParameterFirst; i < event.m_parameters.size(); ++i)
{
const AZ::BehaviorParameter& argParam = event.m_parameters[i];
AddOutputElements(doc, baseID, outputIndex++, argParam.m_typeId, event.m_metadataParameters[i].m_name, event.m_metadataParameters[i].m_toolTip, argParam.m_name);
}
}
}
void AddMessageNode(const XMLDocPtr& doc, const AZStd::string& classorbusName, const AZStd::string& eventormethodName, const AZStd::string& toolTip, const AZStd::string& categoryName, const AZ::BehaviorMethod* method)
{
AZStd::string baseID( GetBaseID(classorbusName, eventormethodName) );
if (!doc->MethodFamilyExists(baseID))
{
AddCommonNodeElements(doc, baseID, classorbusName, eventormethodName, toolTip, categoryName);
const auto result = method->HasResult() ? method->GetResult() : nullptr;
if (result)
{
AddResultElements(doc, baseID, result->m_typeId, result->m_name, "");
}
size_t start = method->HasBusId() ? 1 : 0;
for (size_t i = start; i < method->GetNumArguments(); ++i)
{
if (const AZ::BehaviorParameter* argument = method->GetArgument(i))
{
AddParameterElements(doc, baseID, i-start, argument->m_typeId, *method->GetArgumentName(i), *method->GetArgumentToolTip(i), argument->m_name);
}
}
}
}
} // namespace TSGenerateAction
}
@@ -0,0 +1,188 @@
/*
* 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 "precompiled.h"
#include <qmenu.h>
#include <Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h>
#include <Editor/Include/ScriptCanvas/Bus/RequestBus.h>
#include <Editor/Nodes/NodeUtils.h>
#include <ScriptCanvasDeveloperEditor/WrapperMock.h>
namespace ScriptCanvasDeveloper
{
namespace Nodes
{
////////////////
// WrapperMock
////////////////
void WrapperMock::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<WrapperMock, Mock>()
->Version(0)
->Field("m_wrappedNodeIds", &WrapperMock::m_wrappedNodeIds)
->Field("m_actionName", &WrapperMock::m_actionName)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<WrapperMock>("WrapperMock", "Node for Mocking Wrapper Node visuals")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(ScriptCanvas::Attributes::Node::NodeType, ScriptCanvasEditor::Nodes::NodeType::WrapperNode)
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &WrapperMock::m_actionName, "Action Name", "The Add Action Button Name")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &WrapperMock::OnActionNameChanged)
;
}
}
}
WrapperMock::WrapperMock()
: m_actionName("Mock Action")
{
}
void WrapperMock::OnWrapperAction(const QRect&, const QPointF& scenePoint, const QPoint& screenPoint)
{
GraphCanvas::GraphId graphId;
GraphCanvas::SceneMemberRequestBus::EventResult(graphId, GetGraphCanvasNodeId(), &GraphCanvas::SceneMemberRequests::GetScene);
ScriptCanvas::ScriptCanvasId scriptCanvasId;
ScriptCanvasEditor::GeneralRequestBus::BroadcastResult(scriptCanvasId, &ScriptCanvasEditor::GeneralRequests::GetScriptCanvasId, graphId);
QMenu menu;
QAction* addMock = menu.addAction("Add Mock Node");
QAction* addWrapperMock = menu.addAction("Add Wrapper Mock Node");
QAction* result = menu.exec(screenPoint);
ScriptCanvasEditor::NodeIdPair nodePair;
const AZ::Vector2 scenePointVec2 = AZ::Vector2(aznumeric_cast<float>(scenePoint.x()), aznumeric_cast<float>(scenePoint.y()));
if (result == addMock)
{
ScriptCanvasEditor::EditorGraphRequestBus::EventResult(nodePair, scriptCanvasId, &ScriptCanvasEditor::EditorGraphRequests::CreateCustomNode, azrtti_typeid<Mock>(), AZ::Vector2(aznumeric_cast<float>(scenePoint.x()), aznumeric_cast<float>(scenePoint.y())));
}
else if (result == addWrapperMock)
{
ScriptCanvasEditor::EditorGraphRequestBus::EventResult(nodePair, scriptCanvasId, &ScriptCanvasEditor::EditorGraphRequests::CreateCustomNode, azrtti_typeid<WrapperMock>(), AZ::Vector2(aznumeric_cast<float>(scenePoint.x()), aznumeric_cast<float>(scenePoint.y())));
}
if (nodePair.m_scriptCanvasId.IsValid()
&& nodePair.m_graphCanvasId.IsValid())
{
m_wrappedNodeIds.push_back(nodePair.m_scriptCanvasId);
m_graphCanvasMapping[nodePair.m_graphCanvasId] = nodePair.m_scriptCanvasId;
GraphCanvas::WrappedNodeConfiguration configuration;
configuration.m_layoutOrder = static_cast<int>(m_wrappedNodeIds.size() - 1);
GraphCanvas::WrapperNodeRequestBus::Event(GetGraphCanvasNodeId(), &GraphCanvas::WrapperNodeRequests::WrapNode, nodePair.m_graphCanvasId, configuration);
}
}
void WrapperMock::OnGraphCanvasNodeSetup([[maybe_unused]] const GraphCanvas::NodeId& graphCanvasNodeId)
{
AZ::EntityId scriptCanvasNodeId = (*MockDescriptorNotificationBus::GetCurrentBusId());
MockDescriptorNotificationBus::MultiHandler::BusDisconnect(scriptCanvasNodeId);
GraphCanvas::NodeId nodeId;
MockDescriptorRequestBus::EventResult(nodeId, scriptCanvasNodeId, &MockDescriptorRequests::GetGraphCanvasNodeId);
for (int i = 0; i < m_wrappedNodeIds.size(); ++i)
{
if (m_wrappedNodeIds[i] == scriptCanvasNodeId)
{
m_graphCanvasMapping[nodeId] = m_wrappedNodeIds[i];
GraphCanvas::WrappedNodeConfiguration configuration;
configuration.m_layoutOrder = i;
GraphCanvas::WrapperNodeRequestBus::Event(GetGraphCanvasNodeId(), &GraphCanvas::WrapperNodeRequests::WrapNode, nodeId, configuration);
break;
}
}
}
void WrapperMock::OnNodeRemoved(const GraphCanvas::NodeId& nodeId)
{
auto mapIter = m_graphCanvasMapping.find(nodeId);
if (mapIter != m_graphCanvasMapping.end())
{
AZ::EntityId scriptCanvasNodeId = mapIter->second;
auto removeIter = AZStd::remove_if(m_wrappedNodeIds.begin(), m_wrappedNodeIds.end(), [scriptCanvasNodeId](const AZ::EntityId& testId) { return scriptCanvasNodeId == testId; });
if (removeIter != m_wrappedNodeIds.end())
{
m_wrappedNodeIds.erase(removeIter);
}
}
}
void WrapperMock::OnActionNameChanged()
{
GraphCanvas::WrapperNodeRequestBus::Event(GetGraphCanvasNodeId(), &GraphCanvas::WrapperNodeRequests::SetActionString, QString(m_actionName.c_str()));
}
void WrapperMock::OnClear()
{
GraphCanvas::GraphId graphId;
GraphCanvas::SceneMemberRequestBus::EventResult(graphId, GetGraphCanvasNodeId(), &GraphCanvas::SceneMemberRequests::GetScene);
AZStd::unordered_set< AZ::EntityId > deleteIds;
for (auto& mapPair : m_graphCanvasMapping)
{
deleteIds.erase(mapPair.first);
}
GraphCanvas::SceneRequestBus::Event(graphId, &GraphCanvas::SceneRequests::Delete, deleteIds);
m_wrappedNodeIds.clear();
m_graphCanvasMapping.clear();
}
void WrapperMock::OnNodeDisplayed(const GraphCanvas::NodeId& graphCanvasNodeId)
{
ScriptCanvasEditor::ScriptCanvasWrapperNodeDescriptorRequestBus::Handler::BusConnect(graphCanvasNodeId);
for (unsigned int i = 0; i < m_wrappedNodeIds.size(); ++i)
{
GraphCanvas::NodeId nodeId;
MockDescriptorRequestBus::EventResult(nodeId, m_wrappedNodeIds[i], &MockDescriptorRequests::GetGraphCanvasNodeId);
if (nodeId.IsValid())
{
m_graphCanvasMapping[nodeId] = m_wrappedNodeIds[i];
GraphCanvas::WrappedNodeConfiguration configuration;
configuration.m_layoutOrder = i;
GraphCanvas::WrapperNodeRequestBus::Event(GetGraphCanvasNodeId(), &GraphCanvas::WrapperNodeRequests::WrapNode, nodeId, configuration);
}
else
{
MockDescriptorNotificationBus::MultiHandler::BusConnect(m_wrappedNodeIds[i]);
}
}
OnActionNameChanged();
}
}
}
@@ -0,0 +1,416 @@
/*
* 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 "precompiled.h"
#include "XMLDoc.h"
#include <AzCore/XML/rapidxml_print.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/SystemFile.h>
#include <AzFramework/StringFunc/StringFunc.h>
namespace ScriptCanvasDeveloperEditor
{
namespace Internal
{
xml_node<> *FindDocumentTypeNode(const xml_document<> & doc, const AZStd::string & nodeName)
{
// this will only work if the xml document was parsed with the flag "parse_doctype_node"
for(xml_node<> *docTypeNode=doc.first_node(); docTypeNode!=nullptr; docTypeNode=docTypeNode->next_sibling())
{
if (docTypeNode->type() == node_type::node_doctype)
{
if ( nodeName == docTypeNode->value() )
{
return docTypeNode;
}
}
}
return nullptr;
}
bool GetAttribute(xml_node<> *tsNode, AZStd::string_view attribName, float & value)
{
if( tsNode != nullptr)
{
for (xml_attribute<> *attrib = tsNode->first_attribute(); attrib != nullptr; attrib = attrib->next_attribute())
{
if ( attribName == attrib->name() )
{
value = AzFramework::StringFunc::ToFloat( attrib->value() );
return true;
}
}
}
return false;
}
bool GetAttribute(xml_node<> *tsNode, AZStd::string_view attribName, AZStd::string & value)
{
if( tsNode != nullptr)
{
for (xml_attribute<> *attrib = tsNode->first_attribute(); attrib != nullptr; attrib = attrib->next_attribute())
{
if (attribName == attrib->name())
{
value = attrib->value();
return true;
}
}
}
return false;
}
xml_node<> *FindContextNode(const xml_document<> & doc, const AZStd::string & contextName)
{
xml_node<> *tsNode = doc.first_node("TS");
if (tsNode != nullptr)
{
for(xml_node<> *contextNode=tsNode->first_node("context"); contextNode!=nullptr; contextNode=contextNode->next_sibling("context") )
{
xml_node<> *contextNameNode = contextNode->first_node("name");
if (contextNameNode != nullptr)
{
if( contextName == contextNameNode->value() )
{
return contextNode;
}
}
}
}
return nullptr;
}
}
XMLDocPtr XMLDoc::Alloc(const AZStd::string& contextName)
{
XMLDocPtr xmlDoc( AZStd::make_shared<XMLDoc>() );
xmlDoc->CreateTSDoc(contextName);
return xmlDoc;
}
XMLDocPtr XMLDoc::LoadFromDisk(const AZStd::string& fileName)
{
XMLDocPtr xmlDoc(AZStd::make_shared<XMLDoc>());
if ( !xmlDoc->LoadTSDoc(fileName) )
{
xmlDoc = nullptr;
}
return xmlDoc;
}
XMLDoc::XMLDoc()
: m_tsNode(nullptr)
, m_context(nullptr)
, m_readBuffer(0)
{
}
void XMLDoc::CreateTSDoc(const AZStd::string& contextName)
{
xml_node<>* decl = m_doc.allocate_node(node_declaration);
decl->append_attribute(m_doc.allocate_attribute("version", "1.0"));
decl->append_attribute(m_doc.allocate_attribute("encoding", "utf-8"));
m_doc.append_node(decl);
xml_node<>* commentNode = m_doc.allocate_node(node_comment, "", AllocString(AZStd::string::format("Generated for %s", contextName.c_str())));
m_doc.append_node(commentNode);
xml_node<>* docType = m_doc.allocate_node(node_doctype, "", "TS");
m_doc.append_node(docType);
m_tsNode = m_doc.allocate_node(node_element, "TS");
m_doc.append_node(m_tsNode);
m_tsNode->append_attribute(m_doc.allocate_attribute("version", "2.1"));
m_tsNode->append_attribute(m_doc.allocate_attribute("language", "en_US"));
}
bool XMLDoc::LoadTSDoc(const AZStd::string& fileName)
{
bool success = false;
char tsFilePath[AZ::IO::MaxPathLength] = { "" };
if (AZ::IO::FileIOBase::GetInstance()->ResolvePath(fileName.c_str(), tsFilePath, AZ::IO::MaxPathLength))
{
AZ::IO::FileIOStream xmlFile;
if( AZ::IO::FileIOBase::GetInstance()->Exists(tsFilePath) )
{
if ( xmlFile.Open(tsFilePath, AZ::IO::OpenMode::ModeRead|AZ::IO::OpenMode::ModeText) )
{
AZ::IO::SizeType bytesToRead = xmlFile.GetLength();
if( bytesToRead > 0 )
{
m_readBuffer.resize(bytesToRead, '\0');
if( xmlFile.Read(bytesToRead, m_readBuffer.data() ) == bytesToRead )
{
m_doc.parse<parse_doctype_node|parse_declaration_node|parse_comment_nodes>( m_readBuffer.data() );
success = IsValidTSDoc();
if (success)
{
AZ_TracePrintf("ScriptCanvas", "Loaded \"%s\"", tsFilePath);
}
}
else
{
AZ_Error("ScriptCanvas", false, "XMLDoc::LoadTSDoc-Error reading Qt .ts file! filename=\"%s\".", tsFilePath);
}
}
else
{
AZ_Error("ScriptCanvas", false, "XMLDoc::LoadTSDoc-Zero byte Qt .ts file! filename=\"%s\".", tsFilePath);
}
}
else
{
AZ_Error("ScriptCanvas", false, "XMLDoc::LoadTSDoc-Can't open file Qt .ts file! filename=\"%s\".", tsFilePath);
}
}
}
else
{
AZ_Error("ScriptCanvas", false, "XMLDoc::LoadTSDoc-Invalid filename specified! filename=\"%s\".", tsFilePath);
}
return success;
}
bool XMLDoc::WriteToDisk(const AZStd::string & fileName)
{
bool success = false;
char tsFilePath[AZ::IO::MaxPathLength] = { "" };
if (AZ::IO::FileIOBase::GetInstance()->ResolvePath(fileName.c_str(), tsFilePath, AZ::IO::MaxPathLength))
{
AZStd::string writeFolder(tsFilePath);
AzFramework::StringFunc::Path::StripFullName(writeFolder);
if (!AZ::IO::FileIOBase::GetInstance()->IsDirectory(writeFolder.c_str()))
{
AZ::IO::FileIOBase::GetInstance()->CreatePath(writeFolder.c_str());
}
AZ::IO::FileIOStream xmlFile;
if (xmlFile.Open(tsFilePath, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText))
{
AZStd::string xmlData(ToString());
AZ::IO::SizeType bytesWritten = xmlFile.Write(xmlData.size(), xmlData.data());
if (bytesWritten != xmlData.size())
{
AZ_Error("ScriptCanvas", false, "Write error writing out %s, bytes actually written: %llu expected bytes to write: %llu!", tsFilePath, bytesWritten, xmlData.size());
}
else
{
AZ_TracePrintf("ScriptCanvas", "Successfully wrote out ScriptCanvas localization file \"%s\".", tsFilePath);
success = true;
}
xmlFile.Close();
}
else
{
AZ_Error("ScriptCanvas", false, "Could not open file \"%s\"!", tsFilePath);
}
}
else
{
AZ_Error("ScriptCanvas", false, "Invalid filename specified XMLDoc::WriteToDisk! filename=\"%s\".", tsFilePath);
}
return success;
}
bool XMLDoc::StartContext(const AZStd::string& contextName)
{
bool isNew = false;
if( !contextName.empty() )
{
// check to see if we have a context of this name already, if so find that node and use it, otherwise
// create a new one.
xml_node<> *existingContextNode = Internal::FindContextNode(m_doc, contextName);
if (existingContextNode == nullptr)
{
m_context = m_doc.allocate_node(node_element, "context");
m_tsNode->append_node(m_context);
xml_node<>* contextNameNode = m_doc.allocate_node(node_element, "name", AllocString(contextName));
m_context->append_node(contextNameNode);
isNew = true;
}
else
{
m_context = existingContextNode;
}
}
else
{
m_context = nullptr;
}
return isNew;
}
void XMLDoc::AddToContext(const AZStd::string& id, const AZStd::string& translation/*=""*/, const AZStd::string& comment /*=""*/, const AZStd::string& source/*=""*/)
{
if (m_context == nullptr)
{
return;
}
xml_node<>* messageNode = m_doc.allocate_node(node_element, "message");
messageNode->append_attribute(m_doc.allocate_attribute("id", AllocString(id)));
xml_node<>* sourceNode = m_doc.allocate_node(node_element, "source", AllocString(source.empty() ? id.c_str() : source.c_str()));
messageNode->append_node(sourceNode);
xml_node<>* translationNode = m_doc.allocate_node(node_element, "translation", AllocString(translation));
messageNode->append_node(translationNode);
xml_node<>* commentNode = m_doc.allocate_node(node_element, "comment", AllocString(comment));
messageNode->append_node(commentNode);
m_context->append_node(messageNode);
}
bool XMLDoc::MethodFamilyExists(const AZStd::string& baseId) const
{
if (m_tsNode != nullptr)
{
AZStd::string nameID(baseId + "_NAME");
for (xml_node<> *contextNode=m_tsNode->first_node("context"); contextNode!=nullptr; contextNode=contextNode->next_sibling("context"))
{
for (xml_node<> *messageNode = contextNode->first_node("message"); messageNode != nullptr; messageNode = messageNode->next_sibling("message"))
{
AZStd::string id;
if ( Internal::GetAttribute(messageNode, "id", id) )
{
if (id == nameID)
{
return true;
}
}
}
}
}
return false;
}
AZStd::string XMLDoc::ToString() const
{
AZStd::string buffer;
print( AZStd::back_inserter(buffer), m_doc, 0);
return buffer;
}
const char *XMLDoc::AllocString(const AZStd::string& str)
{
return m_doc.allocate_string( str.c_str(), str.size() + 1 );
}
bool XMLDoc::IsValidTSDoc()
{
bool isTSDoc = false;
//
// Basic format of a .ts file, we are checking to make sure the document type is ts, and the version is 2.1 or greater
// and there is a non-null language attribute. and at least 1 context section
//
//<?xml version="1.0" encoding="utf-8"?>
//<!DOCTYPE TS>
//<TS version="2.1" language="en_US">
// <context>
// ...
// </context>
//</TS>
//
// this node should be the doc type
xml_node<> *docTypeNode = Internal::FindDocumentTypeNode(m_doc, "TS");
if (docTypeNode !=nullptr)
{
xml_node<> *tsNode = m_doc.first_node("TS");
if( tsNode != nullptr)
{
float attribVersion = 0.0f;
if( Internal::GetAttribute(tsNode, "version", attribVersion) && (attribVersion >= 2.1f) )
{
AZStd::string attribLanguage;
if( Internal::GetAttribute(tsNode, "language", attribLanguage) && !attribLanguage.empty() )
{
xml_node<> *contextNode = tsNode->first_node("context");
if(contextNode != nullptr)
{
m_tsNode = tsNode;
AZ_TracePrintf("ScriptCanvas", "TS: Version=%2.1f, Language=\"%s\"", attribVersion, attribLanguage.c_str());
isTSDoc = true;
}
else
{
AZ_Warning("ScriptCanvas", false, "TS document contains no \"context\" nodes!");
}
}
else
{
AZ_Warning("ScriptCanvas", false, "TS document has a bad or missing \"language\" attribute!");
}
}
else
{
AZ_Warning("ScriptCanvas", false, "TS document has a bad or missing \"version\" attribute!");
}
}
else
{
AZ_Error("ScriptCanvas", false, "TS document contains no \"TS\" node!");
}
}
else
{
AZ_Error("ScriptCanvas", false, "XML doc is not a valid TS document!");
}
return isTSDoc;
}
}
@@ -0,0 +1,52 @@
/*
* 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.
*
*/
#pragma once
#include <AzCore/XML/rapidxml.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
using namespace AZ::rapidxml;
namespace ScriptCanvasDeveloperEditor
{
class XMLDoc;
using XMLDocPtr = AZStd::shared_ptr<XMLDoc>;
class XMLDoc
{
public:
static XMLDocPtr Alloc(const AZStd::string& contextName);
static XMLDocPtr LoadFromDisk(const AZStd::string& fileName);
XMLDoc();
virtual ~XMLDoc() {}
bool WriteToDisk(const AZStd::string & filename);
bool StartContext(const AZStd::string& contextName);
void AddToContext(const AZStd::string& id, const AZStd::string& translation = "", const AZStd::string& comment = "", const AZStd::string& source = "");
bool MethodFamilyExists(const AZStd::string& familyName) const;
AZStd::string ToString() const;
private:
void CreateTSDoc(const AZStd::string& contextName);
bool LoadTSDoc(const AZStd::string& contextName);
bool IsValidTSDoc();
const char *AllocString(const AZStd::string& str);
private:
xml_document<> m_doc;
xml_node<> * m_tsNode;
xml_node<> * m_context;
AZStd::vector<char> m_readBuffer;
};
}