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,223 @@
/*
* 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
// AZ
#include <AzCore/EBus/EBus.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Component/Entity.h>
// Graph Canvas
#include <GraphCanvas/Editor/EditorTypes.h>
// Graph Model
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/Slot.h>
class QPixmap;
class QPoint;
class QPointF;
class QRect;
namespace GraphModelIntegration
{
class ThumbnailItem;
struct GraphModelSerialization
{
AZ_TYPE_INFO(GraphModelSerialization, "{0D4D420B-5D9E-429C-A567-DF8596439F5F}");
using SerializedSlotMapping = AZStd::unordered_map<GraphModel::SlotId, GraphCanvas::SlotId>;
//! Keep track of any nodes and their slots that have been serialized
AZStd::unordered_map<GraphCanvas::NodeId, GraphModel::NodePtr> m_serializedNodes;
AZStd::unordered_map<GraphCanvas::NodeId, SerializedSlotMapping> m_serializedSlotMappings;
//! Mapping of serialized nodeIds to their wrapper (parent) nodeId and layout order so they can be restored after deserialization
using SerializedNodeWrappingMap = AZStd::unordered_map<GraphCanvas::NodeId, AZStd::pair<GraphCanvas::NodeId, AZ::u32>>;
SerializedNodeWrappingMap m_serializedNodeWrappings;
};
//! GraphManagerRequests
//! Create/delete for handling our Graph Controllers
class GraphManagerRequests : public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
//! Create a scene and a corresponding graph controller
virtual AZ::Entity* CreateScene(GraphModel::GraphPtr graph, const GraphCanvas::EditorId editorId) = 0;
//! Remove the graph controller for the scene
virtual void RemoveScene(const GraphCanvas::GraphId& sceneId) = 0;
//! Create a new Graph Controller for the given scene
virtual void CreateGraphController(const GraphCanvas::GraphId& sceneId, GraphModel::GraphPtr graph) = 0;
//! Delete the Graph Controller for the given scene
virtual void DeleteGraphController(const GraphCanvas::GraphId& sceneId) = 0;
//! Retrieve a reference to the Graph object for the specified Graph Controller (if it exists)
virtual GraphModel::GraphPtr GetGraph(const GraphCanvas::GraphId& sceneId) = 0;
//! Get/set our serialized mappings of the GraphCanvas nodes/slots that correspond to
//! GraphModel nodes/slots
virtual const GraphModelSerialization& GetSerializedMappings() = 0;
virtual void SetSerializedMappings(const GraphModelSerialization& serialization) = 0;
};
using GraphManagerRequestBus = AZ::EBus<GraphManagerRequests>;
//! GraphControllerRequests
//! Used to invoke functionality on specific Graph Controllers
class GraphControllerRequests : public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
//////////////////////////////////////////////////////////////////////////
//! Add a new node at the specified position
virtual GraphCanvas::NodeId AddNode(GraphModel::NodePtr node, AZ::Vector2& sceneDropPosition) = 0;
//! Remove the specified node
virtual bool RemoveNode(GraphModel::NodePtr node) = 0;
//! Retrieve the position for the specified node
virtual AZ::Vector2 GetPosition(GraphModel::NodePtr node) const = 0;
//! Embed a node on a wrapper node
virtual void WrapNode(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node) = 0;
//! Embed a node on a wrapper node with a layout order configured
virtual void WrapNodeOrdered(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node, AZ::u32 layoutOrder) = 0;
//! Unwrap a node from a wrapper node
//! This results in a no-op if node isn't actually wrapped on the wrapperNode
virtual void UnwrapNode(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node) = 0;
//! Set the action string for the specified node (used by wrapper nodes for
//! setting the action widget label)
virtual void SetWrapperNodeActionString(GraphModel::NodePtr node, const char* actionString) = 0;
//! Add a new connection between the specified source and target
virtual GraphModel::ConnectionPtr AddConnection(GraphModel::SlotPtr sourceSlot, GraphModel::SlotPtr targetSlot) = 0;
//! Create a new connection between the specified source and target specified slots
virtual GraphModel::ConnectionPtr AddConnectionBySlotId(GraphModel::NodePtr sourceNode, GraphModel::SlotId sourceSlotId, GraphModel::NodePtr targetNode, GraphModel::SlotId targetSlotId) = 0;
//! Remove the specified connection
virtual bool RemoveConnection(GraphModel::ConnectionPtr connection) = 0;
//! Extend the given Slot on the specified node
virtual GraphModel::SlotId ExtendSlot(GraphModel::NodePtr node, GraphModel::SlotName slotName) = 0;
//! Returns a GraphModel::Node that corresponds to the Graph Canvas Node Id
virtual GraphModel::NodePtr GetNodeById(const GraphCanvas::NodeId& nodeId) = 0;
//! Retrieve the list of GraphModel::Nodes for the specified GraphCanvas node IDs
virtual GraphModel::NodePtrList GetNodesFromGraphNodeIds(const AZStd::vector<GraphCanvas::NodeId>& nodeIds) = 0;
//! Returns the GraphCanvas::NodeId that corresponds to the specified GraphModel::Node
virtual GraphCanvas::NodeId GetNodeIdByNode(GraphModel::NodePtr node) const = 0;
//! Returns the GraphCanvas::SlotId that corresponds to the specified GraphModel::Slot
virtual GraphCanvas::SlotId GetSlotIdBySlot(GraphModel::SlotPtr slot) const = 0;
//! Retrieve all of the nodes in our graph
virtual GraphModel::NodePtrList GetNodes() = 0;
//! Retrieve the selected nodes in our graph
virtual GraphModel::NodePtrList GetSelectedNodes() = 0;
//! Set the selected property on the specified Nodes
virtual void SetSelected(GraphModel::NodePtrList nodes, bool selected) = 0;
//! Clears the selection in the scene
virtual void ClearSelection() = 0;
//! Enable the specified node in the graph
virtual void EnableNode(GraphModel::NodePtr node) = 0;
//! Disable the specified node in the graph
virtual void DisableNode(GraphModel::NodePtr node) = 0;
//! Move the view to be centered on the given Nodes
virtual void CenterOnNodes(GraphModel::NodePtrList nodes) = 0;
//! Retrieve the major pitch of the grid for this scene graph
virtual AZ::Vector2 GetMajorPitch() const = 0;
//! Embed a thumbnail image on a specified node. This is the most straightforward use-case
//! where the client just wants to show a static image. The thumnbnail image can be updated
//! after being set using this same API.
//! \param node Node to add the thumbnail on
//! \param image Pixmap for the image of the thumbnail
virtual void SetThumbnailImageOnNode(GraphModel::NodePtr node, const QPixmap& image) = 0;
//! Embed a custom thumbnail item on a specified node. This allows the client to
//! implement their own ThumbnailItem to display anything they want by overriding
//! paint() method. Ownership of the ThumbnailItem is passed to the node layout.
//! \param node Node to add the thumbnail on
//! \param item Custom item for the thumbnail
virtual void SetThumbnailOnNode(GraphModel::NodePtr node, ThumbnailItem* item) = 0;
//! Remove the thumbnail from a specified node. If you created your own custom ThumbnailItem
//! and set it using SetThumbnailOnNode, then ownership is passed back to whoever calls this
//! method so they are in charge of deleting it.
//! \param node Node to remove the thumbnail from
virtual void RemoveThumbnailFromNode(GraphModel::NodePtr node) = 0;
};
using GraphControllerRequestBus = AZ::EBus<GraphControllerRequests>;
//! GraphControllerNotifications
//! Notifications about changes to the state of scene graphs.
class GraphControllerNotifications
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = AZ::EntityId;
//! A node has been added to the scene.
virtual void OnGraphModelNodeAdded(GraphModel::NodePtr /*node*/) {}
//! A node has been removed from the scene.
virtual void OnGraphModelNodeRemoved(GraphModel::NodePtr /*node*/) {}
//! Invoked prior to a node being removed from the scene.
virtual void PreOnGraphModelNodeRemoved(GraphModel::NodePtr /*node*/) {}
//! A connection has been added to the scene.
virtual void OnGraphModelConnectionAdded(GraphModel::ConnectionPtr /*connection*/) {}
//! A connection has been removed from the scene.
virtual void OnGraphModelConnectionRemoved(GraphModel::ConnectionPtr /*connection*/) {}
//! The specified node has been wrapped (embedded) onto the wrapperNode
virtual void OnGraphModelNodeWrapped(GraphModel::NodePtr /*wrapperNode*/, GraphModel::NodePtr /*node*/) {}
//! The specified node has been unwrapped (removed) from the wrapperNode
virtual void OnGraphModelNodeUnwrapped(GraphModel::NodePtr /*wrapperNode*/, GraphModel::NodePtr /*node*/) {}
//! Something in the graph has been modified
//! \param node The node that was modified in the graph. If this is nullptr, some metadata on the graph itself was modified
virtual void OnGraphModelGraphModified(GraphModel::NodePtr node) {}
};
using GraphControllerNotificationBus = AZ::EBus<GraphControllerNotifications>;
}
@@ -0,0 +1,39 @@
/*
* 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
// Graph Canvas
#include <GraphCanvas/Components/NodePropertyDisplay/BooleanDataInterface.h>
// Graph Model
#include <GraphModel/Model/Slot.h>
namespace GraphModelIntegration
{
//! Satisfies GraphCanvas API requirements for showing bool property widgets in nodes.
class BooleanDataInterface
: public GraphCanvas::BooleanDataInterface
{
public:
AZ_CLASS_ALLOCATOR(BooleanDataInterface, AZ::SystemAllocator, 0);
BooleanDataInterface(GraphModel::SlotPtr slot);
~BooleanDataInterface() = default;
bool GetBool() const override;
void SetBool(bool enabled) override;
private:
AZStd::weak_ptr<GraphModel::Slot> m_slot;
};
}
@@ -0,0 +1,62 @@
/*
* 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
// AZ ...
#include <AzCore/std/containers/unordered_map.h>
// GraphCanvas ...
#include <GraphCanvas/Widgets/GraphCanvasEditor/GraphCanvasAssetEditorMainWindow.h>
// GraphModel ...
#include <GraphModel/GraphModelBus.h>
namespace GraphModelIntegration
{
/**
* This class extends the base GraphCanvas windowing framework to integrate
* GraphModel functionality into the generic windowing framework.
*/
class EditorMainWindow
: public GraphCanvas::AssetEditorMainWindow
, protected GraphControllerNotificationBus::MultiHandler
{
public:
explicit EditorMainWindow(GraphCanvas::AssetEditorWindowConfig* config, QWidget* parent = nullptr);
~EditorMainWindow() override;
protected:
/// Subclasses must implement this method so that this class can
/// create graphs on their behalf.
virtual GraphModel::IGraphContextPtr GetGraphContext() const = 0;
/// Helper method for retrieving the graph associated with a graphId.
GraphModel::GraphPtr GetGraphById(GraphCanvas::GraphId graphId) const;
/// Helper method for retrieving the graphId associated with a graph.
GraphCanvas::GraphId GetGraphId(GraphModel::GraphPtr graph) const;
// GraphCanvas::AssetEditorMainWindow overrides ...
void OnEditorOpened(GraphCanvas::EditorDockWidget* dockWidget) override;
void OnEditorClosing(GraphCanvas::EditorDockWidget* dockWidget) override;
void OnWrapperNodeActionWidgetClicked(const AZ::EntityId& wrapperNode, const QRect& actionWidgetBoundingRect, const QPointF& scenePoint, const QPoint& screenPoint) override;
/// Client can override this to handle click events on a wrapper node's action widget
/// using a GraphModel::NodePtr instead of the lower-level GraphCanvas::NodeId
virtual void HandleWrapperNodeActionWidgetClicked(GraphModel::NodePtr wrapperNode, [[maybe_unused]] const QRect& actionWidgetBoundingRect, [[maybe_unused]] const QPointF& scenePoint, [[maybe_unused]] const QPoint& screenPoint) {}
/// Keep track of the graphs we create on behalf of the client when
/// new editor dock widgets are created.
AZStd::unordered_map<GraphCanvas::GraphId, GraphModel::GraphPtr> m_graphs;
};
}
@@ -0,0 +1,45 @@
/*
* 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
// Graph Canvas
#include <GraphCanvas/Components/NodePropertyDisplay/DoubleDataInterface.h>
// Graph Model
#include <GraphModel/Model/Slot.h>
namespace GraphModelIntegration
{
//! Satisfies GraphCanvas API requirements for showing float property widgets in nodes.
class FloatDataInterface
: public GraphCanvas::NumericDataInterface
{
public:
AZ_CLASS_ALLOCATOR(FloatDataInterface, AZ::SystemAllocator, 0);
FloatDataInterface(GraphModel::SlotPtr slot);
~FloatDataInterface() = default;
double GetNumber() const override;
void SetNumber(double value) override;
int GetDecimalPlaces() const override;
int GetDisplayDecimalPlaces() const override;
double GetMin() const override;
double GetMax() const override;
private:
AZStd::weak_ptr<GraphModel::Slot> m_slot;
};
}
@@ -0,0 +1,64 @@
/*
* 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
// AZ
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/containers/map.h>
// Graph Model
#include <GraphModel/Model/Common.h>
namespace GraphCanvas
{
class EntitySaveDataContainer;
}
namespace GraphModelIntegration
{
//! This class provides a way to bundle metadata from Graph Canvas for storage
//! in a GraphModel::Graph. The Graph class has a single AZStd::any for storing
//! UI-specific metadata, where the node canvas stores one of these GraphCanvasMetadata.
//! This allows the Graph's file on disk to include information about where nodes
//! are located in the scene, bookmarks, comment blocks, node groupings, etc.
class GraphCanvasMetadata
{
public:
AZ_RTTI(GraphCanvasMetadata, "{BD95C3EB-CD09-4F82-9724-032BD1827B95}");
virtual ~GraphCanvasMetadata() = default;
static void Reflect(AZ::ReflectContext* reflectContext);
private:
friend class GraphController;
// I tried using a unique_ptr but SerializeContext didn't like it
typedef AZStd::shared_ptr<GraphCanvas::EntitySaveDataContainer> EntitySaveDataContainerPtr;
// Using a map instead of unordered_map for simpler xml diffs
typedef AZStd::map<GraphModel::NodeId, EntitySaveDataContainerPtr> NodeMetadataMap;
typedef AZStd::map<AZ::EntityId, EntitySaveDataContainerPtr> OtherMetadataMap;
//! Graph Canvas metadata that pertains to the entire scene
EntitySaveDataContainerPtr m_sceneMetadata;
//! Graph Canvas metadata that pertains to each node in our data model. For example,
//! the position of each node.
NodeMetadataMap m_nodeMetadata;
//! Graph Canvas metadata that is not related to our data model. For example,
//! Comment nodes and Group Box nodes.
OtherMetadataMap m_otherMetadata;
};
}
@@ -0,0 +1,327 @@
/*
* 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
// AZ
#include <AzCore/std/containers/unordered_map.h>
// Qt
#include <QPixmap>
// Graph Canvas
#include <GraphCanvas/Editor/GraphModelBus.h>
#include <GraphCanvas/Components/Slots/SlotBus.h>
#include <GraphCanvas/Components/SceneBus.h>
// Graph Model
#include <GraphModel/GraphModelBus.h>
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/Slot.h>
class QGraphicsLinearLayout;
namespace GraphModelIntegration
{
class GraphCanvasMetadata;
class ThumbnailItem;
//! This is the main class for binding the node graph data to the UI provided by Graph Canvas
class GraphController
: private GraphCanvas::GraphModelRequestBus::Handler
, private GraphCanvas::SceneNotificationBus::Handler
, public GraphControllerRequestBus::Handler
{
public:
AZ_RTTI(GraphController, "{E8433794-4BAE-4B63-B5A5-6EE69DFF0793}");
GraphController(GraphModel::GraphPtr graph, AZ::EntityId graphCanvasSceneId);
~GraphController() override;
GraphController(const GraphController&) = delete;
GraphModel::GraphPtr GetGraph() { return m_graph; }
const GraphModel::GraphPtr GetGraph() const { return m_graph; }
const AZ::EntityId GetGraphCanvasSceneId() const { return m_graphCanvasSceneId; }
////////////////////////////////////////////////////////////////////////////////////
// GraphModel::GraphControllerRequestBus, connections
//! Adds a node to the Graph and creates the corresponding Graph Canvas UI elements
//! \param node The node to add. This should be a freshly created Node that hasn't been added to the Graph yet.
//! \param sceneDropPosition The position in the Graph Cavnas scene where the Node was dropped
GraphCanvas::NodeId AddNode(GraphModel::NodePtr node, AZ::Vector2& sceneDropPosition) override;
bool RemoveNode(GraphModel::NodePtr node) override;
AZ::Vector2 GetPosition(GraphModel::NodePtr node) const override;
void WrapNode(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node) override;
void WrapNodeOrdered(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node, AZ::u32 layoutOrder) override;
void UnwrapNode(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node) override;
void SetWrapperNodeActionString(GraphModel::NodePtr node, const char* actionString) override;
GraphModel::ConnectionPtr AddConnection(GraphModel::SlotPtr sourceSlot, GraphModel::SlotPtr targetSlot) override;
GraphModel::ConnectionPtr AddConnectionBySlotId(GraphModel::NodePtr sourceNode, GraphModel::SlotId sourceSlotId, GraphModel::NodePtr targetNode, GraphModel::SlotId targetSlotId) override;
bool RemoveConnection(GraphModel::ConnectionPtr connection) override;
GraphModel::SlotId ExtendSlot(GraphModel::NodePtr node, GraphModel::SlotName slotName) override;
GraphModel::NodePtr GetNodeById(const GraphCanvas::NodeId& nodeId) override;
GraphModel::NodePtrList GetNodesFromGraphNodeIds(const AZStd::vector<GraphCanvas::NodeId>& nodeIds) override;
GraphCanvas::NodeId GetNodeIdByNode(GraphModel::NodePtr node) const override;
GraphCanvas::SlotId GetSlotIdBySlot(GraphModel::SlotPtr slot) const override;
GraphModel::NodePtrList GetNodes() override;
GraphModel::NodePtrList GetSelectedNodes() override;
void SetSelected(GraphModel::NodePtrList nodes, bool selected) override;
void ClearSelection() override;
void EnableNode(GraphModel::NodePtr node);
void DisableNode(GraphModel::NodePtr node);
void CenterOnNodes(GraphModel::NodePtrList nodes) override;
AZ::Vector2 GetMajorPitch() const override;
void SetThumbnailImageOnNode(GraphModel::NodePtr node, const QPixmap& image) override;
void SetThumbnailOnNode(GraphModel::NodePtr node, ThumbnailItem* item) override;
void RemoveThumbnailFromNode(GraphModel::NodePtr node) override;
////////////////////////////////////////////////////////////////////////////////////
private:
//! Helper method for retrieving the UI layout for a given node
QGraphicsLinearLayout* GetLayoutFromNode(GraphModel::NodePtr node);
//! Saves metadata for a Graph Canvas element into the Graph data model so it's ready
//! to be serialized out with the data model. graphCanvasElement could be any number
//! of entities including a node, comment, group, or the scene itself.
void SaveMetadata(const AZ::EntityId& graphCanvasElement);
//! Utility function for getting the GraphCanvasMetadata from the Graph data model
GraphCanvasMetadata* GetGraphMetadata();
////////////////////////////////////////////////////////////////////////////////////
// Functions for building Graph Canvas UI from our data model
//! Creates the all Graph Canvas elements necessary for representing the Graph. This will be called once
//! to instrument a Graph that was recently loaded.
void CreateFullGraphUi();
//! Creates the GraphCanvas slot UI representing a given Slot
AZ::Entity* CreateSlotUi(GraphModel::SlotPtr slot, AZ::EntityId nodeUiId);
//! Creates the GraphCanvas node UI represeting a given Node
//! \param scenePosition Pass in a lambda function that provides the node's position given it's GraphCanvas node EntityId.
AZ::EntityId CreateNodeUi(GraphModel::NodeId nodeId, GraphModel::NodePtr node, AZStd::function<AZ::Vector2(AZ::EntityId/*nodeUiId*/)> getScenePosition);
//! Utility function for adding a Graph Canvas node to a Graph Canvas scene
void AddNodeUiToScene(AZ::EntityId graphCanvasNodeId, const AZ::Vector2& scenePosition);
//! Creates the GraphCanvas UI represeting a given Connection
void CreateConnectionUi(GraphModel::ConnectionPtr connection);
//! Create a new GraphModel::Connection using the given source and target slots. This will also remove any existing connections on the target slot.
GraphModel::ConnectionPtr CreateConnection(GraphModel::SlotPtr sourceSlot, GraphModel::SlotPtr targetSlot);
//! Check if creating a connection between the specified target and source node would
//! cause a connection loopback.
bool CheckForLoopback(GraphModel::NodePtr sourceNode, GraphModel::NodePtr targetNode) const;
void WrapNodeUi(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node, AZ::u32 layoutOrder = GraphModel::DefaultWrappedNodeLayoutOrder);
void WrapNodeInternal(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node, AZ::u32 layoutOrder = GraphModel::DefaultWrappedNodeLayoutOrder);
////////////////////////////////////////////////////////////////////////////////////
// GraphCanvas::SceneNotificationBus, connections
void OnNodeAdded(const AZ::EntityId& nodeUiId) override;
void OnNodeRemoved(const AZ::EntityId& nodeUiId) override;
void PreOnNodeRemoved(const AZ::EntityId& nodeUiId) override;
void OnConnectionRemoved(const AZ::EntityId& connectionUiId) override;
void OnEntitiesSerialized(GraphCanvas::GraphSerialization& serializationTarget) override;
void OnEntitiesDeserialized(const GraphCanvas::GraphSerialization& serializationSource) override;
void OnEntitiesDeserializationComplete(const GraphCanvas::GraphSerialization& serializationSource) override;
////////////////////////////////////////////////////////////////////////////////////
// GraphCanvas::GraphModelRequestBus, connections
void DisconnectConnection([[maybe_unused]] const AZ::EntityId& connectionUiId) override {}
bool CreateConnection(const AZ::EntityId& connectionUiId, const GraphCanvas::Endpoint& sourcePoint, const GraphCanvas::Endpoint& targetPoint) override;
bool IsValidConnection(const GraphCanvas::Endpoint& sourcePoint, const GraphCanvas::Endpoint& targetPoint) const override;
bool IsValidVariableAssignment(const AZ::EntityId& variableId, const GraphCanvas::Endpoint& targetPoint) const override;
////////////////////////////////////////////////////////////////////////////////////
// GraphCanvas::GraphModelRequestBus, undo
// CJS TODO: I put this stuff in to handle making the file as dirty, but it looks like I might be able to get OnSaveDataDirtied to do that instead.
void RequestUndoPoint() override;
void RequestPushPreventUndoStateUpdate() override;
void RequestPopPreventUndoStateUpdate() override;
void TriggerUndo() override {}
void TriggerRedo() override {}
////////////////////////////////////////////////////////////////////////////////////
// GraphCanvas::GraphModelRequestBus, other
bool EnableNodes(const AZStd::unordered_set<GraphCanvas::NodeId>& nodeIds) override;
bool DisableNodes(const AZStd::unordered_set<GraphCanvas::NodeId>& nodeIds) override;
AZStd::string GetDataTypeString(const AZ::Uuid& typeId);
//! This is where we find all of the graph metadata (like node positions, comments, etc) and store it in the node graph for serialization
// CJS TODO: Use this instead of the above undo functions
void OnSaveDataDirtied(const AZ::EntityId& savedElement) override;
void OnRemoveUnusedNodes() override {}
void OnRemoveUnusedElements() override {}
void ResetSlotToDefaultValue(const GraphCanvas::Endpoint& endpoint) override;
/// Extendable slot handlers
void RemoveSlot(const GraphCanvas::Endpoint& endpoint) override;
bool IsSlotRemovable(const GraphCanvas::Endpoint& endpoint) const override;
GraphCanvas::SlotId RequestExtension(const GraphCanvas::NodeId& nodeId, const GraphCanvas::ExtenderId& extenderId) override;
bool ShouldWrapperAcceptDrop(const GraphCanvas::NodeId& wrapperNode, const QMimeData* mimeData) const override;
void AddWrapperDropTarget(const GraphCanvas::NodeId& wrapperNode) override;
void RemoveWrapperDropTarget(const GraphCanvas::NodeId& wrapperNode) override;
////////////////////////////////////////////////////////////////////////////////////
// GraphCanvas::GraphModelRequestBus, node properties
//! Creates a GraphCanvas::NodePropertyDisplay and a data interface for editing input values
GraphCanvas::NodePropertyDisplay* CreateDataSlotPropertyDisplay(const AZ::Uuid& dataTypeUuid, const GraphCanvas::NodeId& nodeUiId, const GraphCanvas::SlotId& slotUiId) const override;
GraphCanvas::NodePropertyDisplay* CreatePropertySlotPropertyDisplay(const AZ::Crc32& propertyId, const GraphCanvas::NodeId& nodeUiId, const GraphCanvas::SlotId& slotUiId) const override;
//! Common implementation for CreateDataSlotPropertyDisplay and CreatePropertySlotPropertyDisplay
GraphCanvas::NodePropertyDisplay* CreateSlotPropertyDisplay(GraphModel::SlotPtr inputSlot) const;
////////////////////////////////////////////////////////////////////////////////////
//! This class maps the association between our data model's GraphElements and Graph Camvas's UI elements
class GraphElementMap
{
public:
//! Adds a 1:1 mapping between a Graph Canvas UI element and a GraphElement
void Add(AZ::EntityId graphCanvasId, GraphModel::GraphElementPtr graphElement);
//! Removes the Graph Canvas EntityId and its associated GraphElement from the map
void Remove(AZ::EntityId graphCanvasId);
//! Removes the GraphElement and its associated Graph Canvas EntityId from the map
void Remove(GraphModel::ConstGraphElementPtr graphElement);
//! Find the GraphElement that corresponds to the given Graph Canvas EntityId.
//! Returns nullptr if the mapping doesn't exist.
GraphModel::GraphElementPtr Find(AZ::EntityId graphCanvasId);
GraphModel::ConstGraphElementPtr Find(AZ::EntityId graphCanvasId) const;
//! Find the Graph Canvas EntityId that corresponds to the given GraphElement.
//! Returns an invalid EntityId if the mapping doesn't exist.
AZ::EntityId Find(GraphModel::ConstGraphElementPtr graphElement) const;
private:
// shared_ptr can't be a key in a map so we use a raw pointer. This is fine because the two maps
// are kept in sync, and the other map has a shared_ptr.
typedef AZStd::unordered_map<const GraphModel::GraphElement*, AZ::EntityId /*graphCanvasId*/> GraphElementToUiMap;
GraphElementToUiMap m_graphElementToUi;
typedef AZStd::unordered_map<AZ::EntityId /*graphCanvasId*/, GraphModel::GraphElementPtr> UiToGraphElementMap;
UiToGraphElementMap m_uiToGraphElement;
};
//! This class provides a collection of GraphElementMaps for the various types of elements. We could
//! put all the elements in one GraphElementMap, but splitting them out makes debugging a lot easier.
class GraphElementMapCollection
{
public:
GraphElementMapCollection() = default;
//! Adds a 1:1 mapping between a Graph Canvas UI element and a GraphElement.
//! Automatically determines which GraphElementMap is appropriate.
void Add(AZ::EntityId graphCanvasId, GraphModel::GraphElementPtr graphElement);
void Remove(AZ::EntityId graphCanvasId);
void Remove(GraphModel::ConstGraphElementPtr graphElement);
//! Find the GraphElement that corresponds to the given Graph Canvas EntityId.
//! Returns nullptr if the mapping doesn't exist, or the ElementType is wrong.
template<typename ElementType>
AZStd::shared_ptr<ElementType> Find(AZ::EntityId graphCanvasId);
template<typename ElementType>
AZStd::shared_ptr<const ElementType> Find(AZ::EntityId graphCanvasId) const;
//! Find the Graph Canvas EntityId that corresponds to the given GraphElement.
//! Returns an invalid EntityId if the mapping doesn't exist.
AZ::EntityId Find(GraphModel::ConstGraphElementPtr graphElement) const;
private:
GraphElementMap m_nodeMap;
GraphElementMap m_slotMap;
GraphElementMap m_connectionMap;
//! Returns which is the right GraphElementMap for graphElement based on its type
GraphElementMap* GetMapFor(GraphModel::ConstGraphElementPtr graphElement);
const GraphElementMap* GetMapFor(GraphModel::ConstGraphElementPtr graphElement) const;
// This list allows for easy iteration over all the GraphElementMaps.
AZStd::vector<GraphElementMap*> m_allMaps = { &m_nodeMap, &m_slotMap, &m_connectionMap };
} m_elementMap;
AZ::SerializeContext* m_serializeContext = nullptr;
GraphModel::GraphPtr m_graph;
AZ::EntityId m_graphCanvasSceneId;
AZStd::unordered_map<GraphModel::NodeId, GraphModelIntegration::ThumbnailItem*> m_nodeThumbnails;
AZStd::unordered_map<GraphCanvas::NodeId, AZStd::unordered_map<GraphCanvas::ExtenderId, GraphModel::SlotName>> m_nodeExtenderIds;
bool m_isCreatingConnectionUi = false;
};
template<typename ElementType>
AZStd::shared_ptr<ElementType> GraphController::GraphElementMapCollection::Find(AZ::EntityId graphCanvasId)
{
GraphModel::GraphElementPtr graphElement;
for (GraphElementMap* map : m_allMaps)
{
graphElement = map->Find(graphCanvasId);
if (graphElement)
{
break;
}
}
return azrtti_cast<ElementType*>(graphElement);
}
template<typename ElementType>
AZStd::shared_ptr<const ElementType> GraphController::GraphElementMapCollection::Find(AZ::EntityId graphCanvasId) const
{
GraphModel::ConstGraphElementPtr graphElement;
for (GraphElementMap* map : m_allMaps)
{
graphElement = map->Find(graphCanvasId);
if (graphElement)
{
break;
}
}
return azrtti_cast<const ElementType*>(graphElement);
}
}
@@ -0,0 +1,54 @@
/*
* 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
// AZ
#include <AzCore/base.h>
// Graph Model
#include <GraphModel/GraphModelBus.h>
#include <GraphModel/Integration/GraphController.h>
namespace GraphModelIntegration
{
//! This is the main class for managing the Graph Controllers for Graph Canvas scenes
class GraphControllerManager
: private GraphManagerRequestBus::Handler
{
public:
AZ_RTTI(GraphControllerManager, "{DA358B3E-46EF-411B-B84B-0397F5CD3539}");
GraphControllerManager() = default;
////////////////////////////////////////////////////////////////////////////////////
// GraphModelIntegration::GraphManagerRequestBus overrides
AZ::Entity* CreateScene(GraphModel::GraphPtr graph, const GraphCanvas::EditorId editorId) override;
void RemoveScene(const GraphCanvas::GraphId& sceneId) override;
void CreateGraphController(const GraphCanvas::GraphId& sceneId, GraphModel::GraphPtr graph) override;
void DeleteGraphController(const GraphCanvas::GraphId& sceneId) override;
GraphModel::GraphPtr GetGraph(const GraphCanvas::GraphId& sceneId) override;
const GraphModelSerialization& GetSerializedMappings() override;
void SetSerializedMappings(const GraphModelSerialization& serialization) override;
////////////////////////////////////////////////////////////////////////////////////
void Activate();
void Deactivate();
private:
AZ_DISABLE_COPY_MOVE(GraphControllerManager);
AZStd::unordered_map<GraphCanvas::GraphId, AZStd::shared_ptr<GraphController>> m_graphControllers;
GraphModelSerialization m_serialization;
};
}
@@ -0,0 +1,89 @@
/*
* 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/Component/ComponentApplicationBus.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/string/string.h>
namespace GraphModelIntegration
{
namespace Attributes
{
const static AZ::Crc32 TitlePaletteOverride = AZ_CRC("TitlePaletteOverride", 0x2faad537);
}
class Helpers
{
public:
//! Helper method to retrieve the TitlePaletteOverride attribute (if exists) set on
//! a given AZ type class, that will also check any base class that it is derived from
static AZStd::string GetTitlePaletteOverride(const AZ::TypeId& typeId)
{
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AZ_Assert(serializeContext, "Failed to acquire application serialize context.");
AZStd::string paletteOverride;
const AZ::SerializeContext::ClassData* derivedClassData = serializeContext->FindClassData(typeId);
if (!derivedClassData)
{
return paletteOverride;
}
// Use the EnumHierarchy API to retrive a list of TypeIds that this class derives from,
// starting with the actual type and going backwards
AZStd::vector<AZ::TypeId> typeIds;
if (derivedClassData->m_azRtti)
{
derivedClassData->m_azRtti->EnumHierarchy(&RttiEnumHeirarchyHelper, &typeIds);
}
// Look through all the derived TypeIds to see if the TitlePaletteOverride attribute
// was set in the EditContext at any level
for (auto currentTypeId : typeIds)
{
auto classData = serializeContext->FindClassData(currentTypeId);
if (classData)
{
if (classData->m_editData)
{
const AZ::Edit::ElementData* elementData = classData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData);
if (elementData)
{
if (auto titlePaletteAttribute = elementData->FindAttribute(Attributes::TitlePaletteOverride))
{
AZ::AttributeReader nameReader(nullptr, titlePaletteAttribute);
nameReader.Read<AZStd::string>(paletteOverride);
}
}
}
}
}
return paletteOverride;
}
private:
//! Callback method needed for IRttiHelper::EnumHierarchy that gets invoked at every level
//! allowing us to build a list of each TypeId it encounters
static void RttiEnumHeirarchyHelper(const AZ::TypeId& typeId, void* userData)
{
AZStd::vector<AZ::TypeId>* typeIds = reinterpret_cast<AZStd::vector<AZ::TypeId>*>(userData);
typeIds->push_back(typeId);
}
};
}
@@ -0,0 +1,44 @@
/*
* 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
// Graph Canvas
#include <GraphCanvas/Components/NodePropertyDisplay/NumericDataInterface.h>
// Graph Model
#include <GraphModel/Model/Slot.h>
namespace GraphModelIntegration
{
//! Satisfies GraphCanvas API requirements for showing int property widgets in nodes.
class IntegerDataInterface
: public GraphCanvas::NumericDataInterface
{
public:
AZ_CLASS_ALLOCATOR(IntegerDataInterface, AZ::SystemAllocator, 0);
IntegerDataInterface(GraphModel::SlotPtr slot);
~IntegerDataInterface() = default;
double GetNumber() const override;
void SetNumber(double value) override;
int GetDecimalPlaces() const override;
int GetDisplayDecimalPlaces() const override;
double GetMin() const override;
double GetMax() const override;
private:
AZStd::weak_ptr<GraphModel::Slot> m_slot;
};
}
@@ -0,0 +1,39 @@
/*
* 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
// AZ
#include <AzCore/EBus/EBus.h>
// Graph Canvas
#include <GraphCanvas/Editor/EditorTypes.h>
namespace GraphModelIntegration
{
class GraphController;
//! Bus functions that allow the GraphModel Integration system to callback to the client system.
class IntegrationBusInterface : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//! Return the Graph Canvas EntityId for whichever Graph Canvas scene is active in the Editor
virtual GraphCanvas::GraphId GetActiveGraphCanvasSceneId() const = 0;
//! Notifies the client node graph system that the graph data has changed
virtual void SignalSceneDirty(GraphCanvas::GraphId graphCanvasSceneId) = 0;
};
using IntegrationBus = AZ::EBus<IntegrationBusInterface>;
}
@@ -0,0 +1,179 @@
/*
* 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
// AZ
#include <AzCore/Serialization/SerializeContext.h>
// Graph Canvas
#include <GraphCanvas/Components/GridBus.h>
#include <GraphCanvas/GraphCanvasBus.h>
#include <GraphCanvas/Widgets/NodePalette/TreeItems/DraggableNodePaletteTreeItem.h>
#include <GraphCanvas/Widgets/GraphCanvasMimeEvent.h>
namespace GraphModelIntegration
{
//! Provides a common interface for instantiating Graph Canvas support nodes like comments through the Node Palette
class CreateGraphCanvasNodeMimeEvent
: public GraphCanvas::GraphCanvasMimeEvent
{
public:
AZ_RTTI(CreateGraphCanvasNodeMimeEvent, "{7171A847-7405-459F-A031-CC9AE50745B6}", GraphCanvas::GraphCanvasMimeEvent);
AZ_CLASS_ALLOCATOR(CreateGraphCanvasNodeMimeEvent, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext);
if (serializeContext)
{
serializeContext->Class<CreateGraphCanvasNodeMimeEvent, GraphCanvas::GraphCanvasMimeEvent>()
->Version(0)
;
}
}
CreateGraphCanvasNodeMimeEvent() = default;
~CreateGraphCanvasNodeMimeEvent() = default;
bool ExecuteEvent([[maybe_unused]] const AZ::Vector2& mouseDropPosition, AZ::Vector2& dropPosition, const AZ::EntityId& graphCanvasSceneId) override final
{
AZ::Entity* graphCanvasNode = CreateNode();
if (graphCanvasNode)
{
AZ::EntityId graphCanvasNodeId = graphCanvasNode->GetId();
GraphCanvas::SceneRequestBus::Event(graphCanvasSceneId, &GraphCanvas::SceneRequests::AddNode, graphCanvasNodeId, dropPosition);
GraphCanvas::SceneMemberUIRequestBus::Event(graphCanvasNodeId, &GraphCanvas::SceneMemberUIRequests::SetSelected, true);
AZ::EntityId gridId;
GraphCanvas::SceneRequestBus::EventResult(gridId, graphCanvasSceneId, &GraphCanvas::SceneRequests::GetGrid);
AZ::Vector2 offset;
GraphCanvas::GridRequestBus::EventResult(offset, gridId, &GraphCanvas::GridRequests::GetMinorPitch);
dropPosition += offset;
return true;
}
return false;
}
protected:
virtual AZ::Entity* CreateNode() const = 0;
};
////////////////////////////////////////////////////////////////////////////////////
// Comment Node
class CreateCommentNodeMimeEvent
: public CreateGraphCanvasNodeMimeEvent
{
public:
AZ_RTTI(CreateCommentNodeMimeEvent, "{1060EE7B-DBC2-4B7F-BC4C-4AB4651A3812}", CreateGraphCanvasNodeMimeEvent);
AZ_CLASS_ALLOCATOR(CreateCommentNodeMimeEvent, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext);
if (serializeContext)
{
serializeContext->Class<CreateCommentNodeMimeEvent, GraphCanvas::GraphCanvasMimeEvent>()
->Version(0)
;
}
}
CreateCommentNodeMimeEvent() = default;
~CreateCommentNodeMimeEvent() = default;
virtual AZ::Entity* CreateNode() const override
{
AZ::Entity* graphCanvasNode = nullptr;
GraphCanvas::GraphCanvasRequestBus::BroadcastResult(graphCanvasNode, &GraphCanvas::GraphCanvasRequests::CreateCommentNodeAndActivate);
return graphCanvasNode;
}
};
class CommentNodePaletteTreeItem
: public GraphCanvas::DraggableNodePaletteTreeItem
{
public:
AZ_CLASS_ALLOCATOR(CommentNodePaletteTreeItem, AZ::SystemAllocator, 0);
CommentNodePaletteTreeItem(AZStd::string_view nodeName, GraphCanvas::EditorId editorId)
: DraggableNodePaletteTreeItem(nodeName, editorId)
{
SetToolTip("Comment box for notes. Does not affect script execution or data.");
}
~CommentNodePaletteTreeItem() = default;
GraphCanvas::GraphCanvasMimeEvent* CreateMimeEvent() const override
{
return aznew CreateCommentNodeMimeEvent();
}
};
////////////////////////////////////////////////////////////////////////////////////
// Node Group Node
class CreateNodeGroupNodeMimeEvent
: public CreateGraphCanvasNodeMimeEvent
{
public:
AZ_RTTI(CreateNodeGroupNodeMimeEvent, "{1451A2F2-640B-4CB3-BF48-DD77E97EC900}", CreateGraphCanvasNodeMimeEvent);
AZ_CLASS_ALLOCATOR(CreateNodeGroupNodeMimeEvent, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext);
if (serializeContext)
{
serializeContext->Class<CreateNodeGroupNodeMimeEvent, GraphCanvas::GraphCanvasMimeEvent>()
->Version(0)
;
}
}
CreateNodeGroupNodeMimeEvent() = default;
~CreateNodeGroupNodeMimeEvent() = default;
virtual AZ::Entity* CreateNode() const override
{
AZ::Entity* graphCanvasNode = nullptr;
GraphCanvas::GraphCanvasRequestBus::BroadcastResult(graphCanvasNode, &GraphCanvas::GraphCanvasRequests::CreateNodeGroupAndActivate);
return graphCanvasNode;
}
};
class NodeGroupNodePaletteTreeItem
: public GraphCanvas::DraggableNodePaletteTreeItem
{
public:
AZ_CLASS_ALLOCATOR(NodeGroupNodePaletteTreeItem, AZ::SystemAllocator, 0);
NodeGroupNodePaletteTreeItem(AZStd::string_view nodeName, GraphCanvas::EditorId editorId)
: DraggableNodePaletteTreeItem(nodeName, editorId)
{}
~NodeGroupNodePaletteTreeItem() = default;
GraphCanvas::GraphCanvasMimeEvent* CreateMimeEvent() const override
{
return aznew CreateNodeGroupNodeMimeEvent();
}
};
/// Add common utilities to a specific Node Palette tree.
void AddCommonNodePaletteUtilities(GraphCanvas::GraphCanvasTreeItem* rootItem, const GraphCanvas::EditorId& editorId);
}
@@ -0,0 +1,110 @@
/*
* 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
// AZ
#include <AzCore/std/smart_ptr/make_shared.h>
// Graph Canvas
#include <GraphCanvas/Widgets/NodePalette/TreeItems/DraggableNodePaletteTreeItem.h>
#include <GraphCanvas/Widgets/GraphCanvasMimeEvent.h>
// Graph Model
#include <GraphModel/GraphModelBus.h>
#include <GraphModel/Model/Common.h>
namespace GraphModelIntegration
{
template<typename NodeType>
class CreateInputOutputNodeMimeEvent;
//! Provides a common interface for instantiating InputGraphNode and OutputGraphNode through the Node Palette
template<typename NodeType>
class InputOutputNodePaletteItem
: public GraphCanvas::DraggableNodePaletteTreeItem
{
public:
AZ_CLASS_ALLOCATOR(InputOutputNodePaletteItem, AZ::SystemAllocator, 0);
//! Constructor
//! \param nodeName Name of the node that will show up in the Palette
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0xa6d1a85a))
//! \param dataType The type of data that the InputGraphNode or OutputGraphNode will represent
InputOutputNodePaletteItem(AZStd::string_view nodeName, GraphCanvas::EditorId editorId, GraphModel::DataTypePtr dataType)
: DraggableNodePaletteTreeItem(nodeName, editorId)
, m_dataType(dataType)
{}
~InputOutputNodePaletteItem() = default;
GraphCanvas::GraphCanvasMimeEvent* CreateMimeEvent() const override
{
return aznew CreateInputOutputNodeMimeEvent<NodeType>(m_dataType);
}
protected:
GraphModel::DataTypePtr m_dataType;
};
template<typename NodeType>
class CreateInputOutputNodeMimeEvent
: public GraphCanvas::GraphCanvasMimeEvent
{
public:
AZ_RTTI(((CreateInputOutputNodeMimeEvent<NodeType>), "{16BED069-A386-4E5C-8A5A-0827121991E7}", NodeType), GraphCanvas::GraphCanvasMimeEvent);
AZ_CLASS_ALLOCATOR(CreateInputOutputNodeMimeEvent, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext);
if (serializeContext)
{
serializeContext->Class<CreateInputOutputNodeMimeEvent, GraphCanvas::GraphCanvasMimeEvent>()
->Version(0)
->Field("m_dataType", &CreateInputOutputNodeMimeEvent::m_dataType)
;
}
}
CreateInputOutputNodeMimeEvent() = default; // Required by SerializeContext
explicit CreateInputOutputNodeMimeEvent(GraphModel::DataTypePtr dataType)
{
// Copy because m_dataType has to be non-const for use with SerializeContext, and dataType is const
m_dataType = AZStd::make_shared<GraphModel::DataType>(*dataType);
}
bool ExecuteEvent([[maybe_unused]] const AZ::Vector2& mouseDropPosition, AZ::Vector2& dropPosition, const AZ::EntityId& graphCanvasSceneId) override
{
GraphModel::GraphPtr graph = nullptr;
GraphManagerRequestBus::BroadcastResult(graph, &GraphManagerRequests::GetGraph, graphCanvasSceneId);
if (!graph)
{
return false;
}
AZStd::shared_ptr<GraphModel::Node> node = AZStd::make_shared<NodeType>(graph, m_dataType);
if (!node)
{
return false;
}
GraphControllerRequestBus::Event(graphCanvasSceneId, &GraphControllerRequests::AddNode, node, dropPosition);
return true;
}
protected:
AZStd::shared_ptr<GraphModel::DataType> m_dataType;
};
}
@@ -0,0 +1,121 @@
/*
* 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
// AZ
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/StringFunc/StringFunc.h>
// Graph Canvas
#include <GraphCanvas/Widgets/NodePalette/TreeItems/DraggableNodePaletteTreeItem.h>
#include <GraphCanvas/Widgets/GraphCanvasMimeEvent.h>
// Graph Model
#include <GraphModel/GraphModelBus.h>
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/Module/ModuleNode.h>
namespace GraphModelIntegration
{
AZStd::string GetNodeName(AZStd::string_view sourceFileName)
{
AZStd::string name = "Unnamed";
if (!AzFramework::StringFunc::Path::GetFileName(sourceFileName.data(), name))
{
AZ_Assert(false, "Could not get node name from module file path [%s]", sourceFileName.data());
}
return name;
}
class CreateModuleNodeMimeEvent
: public GraphCanvas::GraphCanvasMimeEvent
{
public:
AZ_RTTI(CreateModuleNodeMimeEvent, "{914F9D88-7B60-408D-A16F-BCCE4CA41EFB}", GraphCanvas::GraphCanvasMimeEvent);
AZ_CLASS_ALLOCATOR(CreateModuleNodeMimeEvent, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext);
if (serializeContext)
{
serializeContext->Class<CreateModuleNodeMimeEvent, GraphCanvas::GraphCanvasMimeEvent>()
->Version(0)
->Field("m_sourceFileName", &CreateModuleNodeMimeEvent::m_sourceFileName)
->Field("m_sourceFileId", &CreateModuleNodeMimeEvent::m_sourceFileId)
;
}
}
CreateModuleNodeMimeEvent() = default; // required by SerializeContext
CreateModuleNodeMimeEvent(AZStd::string_view sourceFileName, AZ::Uuid sourceFileId)
: m_sourceFileName(sourceFileName)
, m_sourceFileId(sourceFileId)
{
}
bool ExecuteEvent([[maybe_unused]] const AZ::Vector2& mouseDropPosition, AZ::Vector2& dropPosition, const AZ::EntityId& graphCanvasSceneId) override
{
GraphModel::GraphPtr graph = nullptr;
GraphManagerRequestBus::BroadcastResult(graph, &GraphManagerRequests::GetGraph, graphCanvasSceneId);
if (!graph)
{
return false;
}
AZStd::shared_ptr<GraphModel::Node> node = AZStd::make_shared<GraphModel::ModuleNode>(graph, m_sourceFileId, m_sourceFileName);
if (!node)
{
return false;
}
GraphControllerRequestBus::Event(graphCanvasSceneId, &GraphControllerRequests::AddNode, node, dropPosition);
return true;
}
protected:
AZStd::string m_sourceFileName;
AZ::Uuid m_sourceFileId;
};
//! Provides the interface for instantiating ModuleNodes through the Node Palette. The ModuleNode is based on a
//! module node graph file that defines the inputs, outputs, and behavior of the node.
class ModuleNodePaletteItem
: public GraphCanvas::DraggableNodePaletteTreeItem
{
public:
AZ_CLASS_ALLOCATOR(ModuleNodePaletteItem, AZ::SystemAllocator, 0);
//! Constructor
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0xa6d1a85a))
//! \param sourceFileId The unique id for the module node graph source file.
//! \param sourceFilePath The path to the module node graph source file. This will be used for node naming and debug output.
ModuleNodePaletteItem(GraphCanvas::EditorId editorId, AZ::Uuid sourceFileId, AZStd::string_view sourceFilePath)
: DraggableNodePaletteTreeItem(GetNodeName(sourceFilePath).data(), editorId)
, m_sourceFileName(sourceFilePath)
, m_sourceFileId(sourceFileId)
{}
~ModuleNodePaletteItem() = default;
GraphCanvas::GraphCanvasMimeEvent* CreateMimeEvent() const override
{
return aznew CreateModuleNodeMimeEvent(m_sourceFileName, m_sourceFileId);
}
protected:
AZStd::string m_sourceFileName;
AZ::Uuid m_sourceFileId;
};
}
@@ -0,0 +1,108 @@
/*
* 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
// AZ
#include <AzCore/std/smart_ptr/make_shared.h>
// Graph Canvas
#include <GraphCanvas/Widgets/NodePalette/TreeItems/DraggableNodePaletteTreeItem.h>
#include <GraphCanvas/Widgets/GraphCanvasMimeEvent.h>
// Graph Model
#include <GraphModel/GraphModelBus.h>
#include <GraphModel/Integration/Helpers.h>
namespace GraphModelIntegration
{
template<typename NodeType>
class CreateStandardNodeMimeEvent;
//! Provides a common interface for instantiating GraphModel::Node subclasses through the Node Palette
template<typename NodeType>
class StandardNodePaletteItem
: public GraphCanvas::DraggableNodePaletteTreeItem
{
public:
AZ_CLASS_ALLOCATOR(StandardNodePaletteItem, AZ::SystemAllocator, 0);
//! Constructor
//! \param nodeName Name of the node that will show up in the Palette
//! \param editorId Unique name of the client system editor (ex: AZ_CRC("ShaderCanvas", 0xa6d1a85a))
StandardNodePaletteItem(AZStd::string_view nodeName, GraphCanvas::EditorId editorId)
: DraggableNodePaletteTreeItem(nodeName, editorId)
{
// Setting the palette override (if specified) is mainly used to set the icon color for this
// node palette item, but it can also be used to override other styling aspects as well
AZStd::string paletteOverride = Helpers::GetTitlePaletteOverride(azrtti_typeid<NodeType>());
if (!paletteOverride.empty())
{
SetTitlePalette(paletteOverride);
}
}
~StandardNodePaletteItem() = default;
GraphCanvas::GraphCanvasMimeEvent* CreateMimeEvent() const override
{
return aznew CreateStandardNodeMimeEvent<NodeType>();
}
};
template<typename NodeType>
class CreateStandardNodeMimeEvent
: public GraphCanvas::GraphCanvasMimeEvent
{
public:
AZ_RTTI( ( (CreateStandardNodeMimeEvent<NodeType>), "{DF6213A0-5C60-4C22-88F1-4CEA6D8A17EF}", NodeType), GraphCanvas::GraphCanvasMimeEvent);
AZ_CLASS_ALLOCATOR(CreateStandardNodeMimeEvent, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext);
if (serializeContext)
{
serializeContext->Class<CreateStandardNodeMimeEvent, GraphCanvas::GraphCanvasMimeEvent>()
->Version(0)
;
}
}
bool ExecuteEvent([[maybe_unused]] const AZ::Vector2& mouseDropPosition, AZ::Vector2& dropPosition, const AZ::EntityId& graphCanvasSceneId) override
{
GraphModel::GraphPtr graph = nullptr;
GraphManagerRequestBus::BroadcastResult(graph, &GraphManagerRequests::GetGraph, graphCanvasSceneId);
if (!graph)
{
return false;
}
AZStd::shared_ptr<GraphModel::Node> node = AZStd::make_shared<NodeType>(graph);
if (!node)
{
return false;
}
GraphControllerRequestBus::EventResult(m_createdNodeId, graphCanvasSceneId, &GraphControllerRequests::AddNode, node, dropPosition);
return true;
}
};
template<typename NodeType>
void ReflectAndCreateNodeMimeEvent(AZ::ReflectContext* context)
{
NodeType::Reflect(context);
GraphModelIntegration::CreateStandardNodeMimeEvent<NodeType>::Reflect(context);
}
}
@@ -0,0 +1,39 @@
/*
* 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
// Graph Canvas
#include <GraphCanvas/Components/NodePropertyDisplay/ReadOnlyDataInterface.h>
// Graph Model
#include <GraphModel/Model/Slot.h>
namespace GraphModelIntegration
{
//! Satisfies GraphCanvas API requirements for showing read only property widgets in nodes.
class ReadOnlyDataInterface
: public GraphCanvas::ReadOnlyDataInterface
{
public:
AZ_CLASS_ALLOCATOR(ReadOnlyDataInterface, AZ::SystemAllocator, 0);
ReadOnlyDataInterface(GraphModel::SlotPtr slot);
~ReadOnlyDataInterface() = default;
// GraphCanvas::ReadOnlyDataInterface overrides ...
AZStd::string GetString() const override;
private:
AZStd::weak_ptr<GraphModel::Slot> m_slot;
};
}
@@ -0,0 +1,39 @@
/*
* 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
// Graph Canvas
#include <GraphCanvas/Components/NodePropertyDisplay/StringDataInterface.h>
// Graph Model
#include <GraphModel/Model/Slot.h>
namespace GraphModelIntegration
{
//! Satisfies GraphCanvas API requirements for showing string property widgets in nodes.
class StringDataInterface
: public GraphCanvas::StringDataInterface
{
public:
AZ_CLASS_ALLOCATOR(StringDataInterface, AZ::SystemAllocator, 0);
StringDataInterface(GraphModel::SlotPtr slot);
~StringDataInterface() = default;
AZStd::string GetString() const;
void SetString(const AZStd::string& value);
private:
AZStd::weak_ptr<GraphModel::Slot> m_slot;
};
}
@@ -0,0 +1,46 @@
/*
* 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
// Qt
#include <QPixmap>
// GraphModel
#include <GraphModel/Integration/ThumbnailItem.h>
namespace GraphModelIntegration
{
/**
* Default image implementation of our ThumbnailItem class to draw a
* simple QPixmap as the thumbnail.
*/
class ThumbnailImageItem
: public ThumbnailItem
{
public:
AZ_RTTI(ThumbnailImageItem, "{DB2F488F-95CF-49BC-8DD4-806969A71A16}", ThumbnailItem);
ThumbnailImageItem(const QPixmap& image, QGraphicsItem* parent = nullptr);
void UpdateImage(const QPixmap& image);
//! Override from QGraphicsLayoutItem
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override;
//! Override from QGraphicsItem
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
protected:
QPixmap m_pixmap;
};
}
@@ -0,0 +1,43 @@
/*
* 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
// AZ
#include <AzCore/RTTI/RTTI.h>
// Qt
#include <QGraphicsItem>
#include <QGraphicsLayoutItem>
namespace GraphModelIntegration
{
/**
* Base layout item class for embedding thumbnails inside a Node. The paint()
* method can be overriden to implement any custom rendering desired.
*/
class ThumbnailItem
: public QGraphicsLayoutItem
, public QGraphicsItem
{
public:
AZ_RTTI(ThumbnailItem, "{4248ADDE-4DFF-4A02-A8FD-B992E3CFF94B}");
ThumbnailItem(QGraphicsItem* parent = nullptr);
//! Override from QGraphicsLayoutItem
void setGeometry(const QRectF &geom) override;
//! Override from QGraphicsItem
QRectF boundingRect() const override;
};
}
@@ -0,0 +1,102 @@
/*
* 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
// Graph Canvas
#include <GraphCanvas/Components/NodePropertyDisplay/VectorDataInterface.h>
// Graph Model
#include <GraphModel/Integration/IntegrationBus.h>
#include <GraphModel/Model/Slot.h>
namespace GraphModelIntegration
{
template<class Type, int ElementCount>
class VectorDataInterface
: public GraphCanvas::VectorDataInterface
{
public:
AZ_CLASS_ALLOCATOR(VectorDataInterface, AZ::SystemAllocator, 0);
VectorDataInterface(GraphModel::SlotPtr slot)
: m_slot(slot)
{
}
~VectorDataInterface() = default;
const char* GetLabel(int index) const override
{
if (index == 0)
{
return "X";
}
else if (index == 1)
{
return "Y";
}
else if (index == 2)
{
return "Z";
}
else if (index == 3)
{
return "W";
}
return "???";
}
AZStd::string GetStyle() const override
{
return "vectorized";
}
AZStd::string GetElementStyle(int index) const override
{
return AZStd::string::format("vector_%i", index);
}
int GetElementCount() const override
{
return ElementCount;
}
double GetValue(int index) const override
{
if (GraphModel::SlotPtr slot = m_slot.lock())
{
return slot->GetValue<Type>().GetElement(index);
}
else
{
return 0.0;
}
}
void SetValue(int index, double value) override
{
if (GraphModel::SlotPtr slot = m_slot.lock())
{
Type vector = slot->GetValue<Type>();
if (value != vector.GetElement(index))
{
vector.SetElement(index, aznumeric_cast<float>(value));
slot->SetValue(vector);
GraphCanvas::GraphId graphCanvasSceneId;
IntegrationBus::BroadcastResult(graphCanvasSceneId, &IntegrationBusInterface::GetActiveGraphCanvasSceneId);
IntegrationBus::Broadcast(&IntegrationBusInterface::SignalSceneDirty, graphCanvasSceneId);
}
}
}
private:
AZStd::weak_ptr<GraphModel::Slot> m_slot;
};
}
@@ -0,0 +1,75 @@
/*
* 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
// AZ
#include <AzCore/Component/EntityId.h>
#include <AzCore/std/tuple.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
namespace GraphModel
{
//!!! Start in Graph.h for high level GraphModel documentation !!!
// Node ID that is unique within the context of a Graph
using NodeId = int;
// Slot ID that is unique within the context of a Node
struct SlotIdData;
using SlotId = SlotIdData;
// An Endpoint is a specific Slot within a specific Node.
// It's basically a Slot ID that is unique within the context of an entire Graph.
using Endpoint = AZStd::pair<NodeId, SlotId>;
class DataType;
using DataTypePtr = AZStd::shared_ptr<const DataType>; //!< All pointers are const since this data is immutable anyway
using DataTypeList = AZStd::vector<DataTypePtr>;
class IGraphContext;
using IGraphContextPtr = AZStd::shared_ptr<IGraphContext>;
using ConstIGraphContextPtr = AZStd::shared_ptr<const IGraphContext>;
class Graph;
using GraphPtr = AZStd::shared_ptr<Graph>;
using ConstGraphPtr = AZStd::shared_ptr<const Graph>;
class GraphElement;
using GraphElementPtr = AZStd::shared_ptr<GraphElement>;
using ConstGraphElementPtr = AZStd::shared_ptr<const GraphElement>;
class Node;
using NodePtr = AZStd::shared_ptr<Node>;
using ConstNodePtr = AZStd::shared_ptr<const Node>;
using NodePtrList = AZStd::vector<NodePtr>;
class SlotDefinition;
using SlotDefinitionPtr = AZStd::shared_ptr<const SlotDefinition>; //!< All pointers are const since this data is immutable anyway
class Slot;
using SlotPtr = AZStd::shared_ptr<Slot>;
using ConstSlotPtr = AZStd::shared_ptr<const Slot>;
using SlotPtrList = AZStd::vector<SlotPtr>;
class Connection;
using ConnectionPtr = AZStd::shared_ptr<Connection>;
using ConstConnectionPtr = AZStd::shared_ptr<const Connection>;
class ModuleGraphManager;
using ModuleGraphManagerPtr = AZStd::shared_ptr<ModuleGraphManager>;
using ConstModuleGraphManagerPtr = AZStd::shared_ptr<const ModuleGraphManager>;
static const AZ::u32 DefaultWrappedNodeLayoutOrder = -1;
} // namespace GraphModel
@@ -0,0 +1,64 @@
/*
* 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
// Graph Model
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/GraphElement.h>
#include <GraphModel/Model/Slot.h>
namespace GraphModel
{
//!!! Start in Graph.h for high level GraphModel documentation !!!
//! Defines the connection between an Output Slot and an Input Slot.
//! Usually a Connection instance will be created by the Graph class
//! rather than directly.
class Connection : public GraphElement
{
public:
AZ_CLASS_ALLOCATOR(Connection, AZ::SystemAllocator, 0);
AZ_RTTI(Connection, "{B4301AE1-98F4-474E-B0A1-18F27EEDB059}", GraphElement);
static void Reflect(AZ::ReflectContext* context);
Connection() = default; // Needed by SerializeContext
~Connection() override = default;
//! Create a Connection for a specific Graph, though this doesn't actually
//! add it to the Graph.
Connection(GraphPtr graph, SlotPtr sourceSlot, SlotPtr targetSlot);
//! Initializion after the Connection has been serialized in.
//! This must be called whenever the default constructor is used.
//! Sets the m_graph pointer and caches pointers to other GraphElements.
void PostLoadSetup(GraphPtr graph);
NodePtr GetSourceNode() const;
NodePtr GetTargetNode() const;
SlotPtr GetSourceSlot() const;
SlotPtr GetTargetSlot() const;
const Endpoint& GetSourceEndpoint() const;
const Endpoint& GetTargetEndpoint() const;
private:
AZStd::weak_ptr<Slot> m_sourceSlot;
AZStd::weak_ptr<Slot> m_targetSlot;
Endpoint m_sourceEndpoint;
Endpoint m_targetEndpoint;
};
} // namespace GraphModel
@@ -0,0 +1,98 @@
/*
* 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
// AZ
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/string_view.h>
// GraphModel
#include <GraphModel/Model/Common.h>
namespace AZ
{
class ReflectContext;
}
namespace GraphModel
{
//! Provides a way for client systems to describe each data type that they support, including a
//! unique enum value, the AZ type Uuid, and a user-friendly display name. Client systems may
//! subclass DataType if desired, for example to provide additional name formats.
class DataType
{
public:
AZ_CLASS_ALLOCATOR(DataType, AZ::SystemAllocator, 0);
AZ_RTTI(DataType, "{B8CBD17E-B8F7-4090-99A7-E9E9970D3EF3}");
static void Reflect(AZ::ReflectContext* reflection);
//! Data types can be described by a simple enum value. Client systems can
//! use whatever value they want as long as each type has a unique value.
using Enum = uint32_t;
static const Enum ENUM_INVALID = uint32_t(-1);
DataType();
//! Constructs a new DataType object.
//! @param typeEnum - The main unique ID used by the GraphModel framework for this DataType object.Every DataType in the IGraphContext must have a unique enum value.
//! @param typeUuid - An alternate unique ID that is used by the node graph UI system. (This is not necessarily the same thing as an RTTI TypeId.The only requirement is that it maps 1:1 with the typeEnum).
//! @param defaultValue - The default value assigned to any slot that uses this data type upon creation.
//! @param typeDisplayName - Used for tooltips or other UI elements as well as debug messages.This should be unique, and similar to typeEnum.
//! @param cppTypeName - The name of the c++ class that the DataType maps to.This is only used for debug messages.
DataType(Enum typeEnum, AZ::Uuid typeUuid, AZStd::any defaultValue, AZStd::string_view typeDisplayName, AZStd::string_view cppTypeName);
DataType(const DataType& other);
virtual ~DataType() = default;
// Because the DataType class is supposed to be immutable
bool operator=(const DataType& other) = delete;
bool operator==(const DataType& other) const;
bool operator!=(const DataType& other) const;
bool IsValid() const;
//! Return the enum value that identifies this DataType
Enum GetTypeEnum() const { return m_typeEnum; }
//! Return the type Uuid that corresponds to this DataType
AZ::Uuid GetTypeUuid() const;
//! Returns GetTypeUuid() as a string (for convenience)
AZStd::string GetTypeUuidString() const;
//! Returns a default value for data of this type
AZStd::any GetDefaultValue() const;
//! Returns the C++ type name
AZStd::string GetCppName() const;
//! Returns a user friently type name, for UI display
AZStd::string GetDisplayName() const;
private:
Enum m_typeEnum;
AZ::Uuid m_typeUuid;
AZStd::any m_defaultValue;
AZStd::string m_cppName;
AZStd::string m_displayName;
};
} // namespace GraphModel
@@ -0,0 +1,168 @@
/*
* 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
// AZ
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/any.h>
#include <AzCore/std/smart_ptr/enable_shared_from_this.h>
// Graph Model
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/GraphElement.h>
namespace AZ
{
class ReflectContext;
}
namespace GraphModel
{
//! This is the main class for the GraphModel framework. It provides a generic node graph data model
//! that is originally intended for use with Graph Canvas providing the UI, but in theory it could
//! be used with any node graph widget system. It is also designed with primarily editor processing
//! in mind, rather than runtime processing, so if this were to be used at runtime we may need some
//! improvements.
//!
//! Data Model Goals
//! * Keep it simple
//! (For example, avoid using the component entity system even though that's an established pattern
//! in Script Canvas's data model)
//! * It shouldn't know anything about GraphCanvas or any other UI representation; it's purely a data model
//! * Make it suitible for multiple contexts
//! (For example, even though this is built for Shader Canvas initially, it should be generic enough
//! to use for the Particle Editor or other contexts)
//! * It shouldn't know anything about how the nodes will be used.
//! (For example, any functionality specific to Shader Canvas, Particle Editors, or any other context
//! should be added to some external subclasses of GraphModel classes)
//!
//! Key elements of a Graph include
//! * Node - The main building block of a Graph. Contains multiple input slots and output slots.
//! * Slot - Every node contains input slots and/or output slots that can be connected together
//! * Endpoint - A specific Slot on a specific Node; basically a {NodeID,SlotID} pair
//! * Connection - A link from an output Endpoint to an input Endpoint (we could also say this is a link
//! from an output Slot to an input Slot)
//! * Metadata - Every graph can contain generic metadata like comments and node groupings for example.
//! But this is specific to the node graph UI system, and the Graph class just stores this
//! in an abstract way to bundle the data together.
//!
//! For continued reading, see Node.h next.
class Graph : public AZStd::enable_shared_from_this<Graph>
{
public:
AZ_CLASS_ALLOCATOR(Graph, AZ::SystemAllocator, 0);
AZ_RTTI(Graph, "{CBF5DC3C-A0A7-45F5-A207-06433A9A10C5}");
static void Reflect(AZ::ReflectContext* context);
typedef AZStd::unordered_map<NodeId, NodePtr> NodeMap;
typedef AZStd::unordered_map<NodeId, ConstNodePtr> ConstNodeMap;
// Used to store the mappings for our wrapped nodes, where the key is the NodeId of
// the wrapped node, and the value is a pair of the NodeId for the parent WrapperNode
// and the layout order for the wrapped node
typedef AZStd::unordered_map<NodeId, AZStd::pair<NodeId, AZ::u32>> NodeWrappingMap;
// We use a vector instead of set to maintain a consistent order in the serialized data, to reduce diffs
typedef AZStd::vector<ConnectionPtr> ConnectionList;
Graph() = default; // Needed by SerializeContext
Graph(const Graph&) = delete;
//! Constructor
//! \param graphContext interface to client system specific data and functionality
explicit Graph(IGraphContextPtr graphContext);
virtual ~Graph() = default;
//! Initializion after the Graph has been serialized in.
//! This must be called after building a Graph from serialized data
//! in order to connect internal pointers between elements of the Graph
//! and perform any other precedural setup that isn't stored in the
//! serialized data.
//! \param graphContext interface to client system specific data and functionality
void PostLoadSetup(IGraphContextPtr graphContext);
//! Add a node that has been deserialized to the graph
//! This should only be necessary for cases like copy/paste where we
//! need to load a deserialized node, but don't actually know the nodeId before-hand
NodeId PostLoadSetup(NodePtr node);
//! Returns the interface to client system specific data and functionality
IGraphContextPtr GetContext() const;
//! This name is used for debug messages in GraphModel classes, to provide appropriate context for the user.
//! It's a convenience function for GetContext()->GetSystemName()
const char* GetSystemName() const;
//! Adds a Node to the graph and gives it a unique ID
NodeId AddNode(NodePtr node);
//! Removes a Node and all connections between it and other Nodes in the graph
bool RemoveNode(ConstNodePtr node);
//! Wrap (embed) the node onto the specified wrapperNode
//! The wrapperNode and node must already exist in the graph before being wrapped
void WrapNode(NodePtr wrapperNode, NodePtr node, AZ::u32 layoutOrder = DefaultWrappedNodeLayoutOrder);
//! Remove the wrapping from the specified node
void UnwrapNode(ConstNodePtr node);
//! Return our full map of node wrappings
const NodeWrappingMap& GetNodeWrappings();
NodePtr GetNode(NodeId nodeId);
const NodeMap& GetNodes();
ConstNodeMap GetNodes() const;
//! Adds a new connection between sourceSlot and targetSlot and returns the
//! new Connection, or returns the existing Connection if one already exists.
ConnectionPtr AddConnection(SlotPtr sourceSlot, SlotPtr targetSlot);
//! Removes a connection from the Graph, and returns whether it was found and removed
bool RemoveConnection(ConstConnectionPtr connection);
const ConnectionList& GetConnections();
//! Set/gets a bundle of generic metadata that is provided by the node graph UI
//! system. This may include node positions, comment blocks, node groupings, and
//! bookmarks, for example.
void SetUiMetadata(const AZStd::any& uiMetadata);
const AZStd::any& GetUiMetadata() const;
AZStd::any& GetUiMetadata();
AZStd::shared_ptr<Slot> FindSlot(const Endpoint& endpoint);
protected:
bool Contains(SlotPtr slot) const;
ConnectionPtr FindConnection(ConstSlotPtr sourceSlot, ConstSlotPtr targetSlot);
//! Common implementation for removing a specific connection from m_connections
bool RemoveConnection(ConnectionList::iterator iter);
private:
NodeMap m_nodes;
int m_nextNodeId = 1; //!< NodeIds are unique within each Graph. This is a simple counter for generating the next ID.
ConnectionList m_connections;
//! Used to store and serialize metadata from the graph UI, like node positions, comments, group boxes, etc.
AZStd::any m_uiMetadata;
//! Used to store all of our node <-> wrapper node mappings
NodeWrappingMap m_nodeWrappings;
IGraphContextPtr m_graphContext; //!< interface to client system specific data and functionality
};
} // namespace GraphModel
@@ -0,0 +1,49 @@
/*
* 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
// AZ
#include <AzCore/Memory/SystemAllocator.h>
// Graph Model
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/Graph.h>
namespace GraphModel
{
//!!! Start in Graph.h for high level GraphModel documentation !!!
//! The common base class for every element in a Graph, like Node, Slot, and Connection.
class GraphElement
{
public:
AZ_CLASS_ALLOCATOR(GraphElement, AZ::SystemAllocator, 0);
AZ_RTTI(GraphElement, "{FD83C7CA-556B-49F1-BACE-6E9C7A4D6347}");
GraphElement() = default; // Needed by SerializeContext
virtual ~GraphElement() = default;
GraphElement(GraphPtr graph);
//! Returns the Graph that owns this GraphElement
GraphPtr GetGraph() const;
//! Returns the IGraphContext for this GraphElement
IGraphContextPtr GetGraphContext() const;
protected:
AZStd::weak_ptr<Graph> m_graph; // Every GraphElement will at least need a pointer to the Graph, so it can convert IDs into actual element pointers.
};
} // namespace GraphModel
@@ -0,0 +1,70 @@
/*
* 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
// AZ
#include <AzCore/std/containers/vector.h>
// GraphModel
#include <GraphModel/Model/DataType.h>
namespace GraphModel
{
//!!! Start in Graph.h for high level GraphModel documentation !!!
//! IGraphContext provides an interface to client system specific features for the GraphModel framework to use.
//! All systems that use GraphModel must provide an implementation of this interface, passed to the main Graph object.
class IGraphContext
{
public:
using DataTypeList = AZStd::vector<DataTypePtr>;
virtual ~IGraphContext() = default;
//! Returns the name of the system that is using the GraphModel framework, mostly for debug messages.
virtual const char* GetSystemName() const = 0;
//! Returns the file extension used for module files
virtual const char* GetModuleFileExtension() const = 0;
//! Returns a ModuleGraphManager to support creating ModuleNodes. Subclasses can just return nullptr if this isn't needed.
virtual ModuleGraphManagerPtr GetModuleGraphManager() const = 0;
//! Returns all available data types.
virtual const DataTypeList& GetAllDataTypes() const = 0;
//! Returns a DataType object representing the given TypeId, or Invalid if it doesn't exist.
virtual DataTypePtr GetDataType(AZ::Uuid typeId) const = 0;
//! Returns a DataType object representing the given AZStd::any value, or Invalid if it doesn't exist.
//! This data type method has a different name because if the GraphContext implementation doesn't override
//! this, there will be a compile error for a hidden function because of subclasses implementing
//! the templated version below
virtual DataTypePtr GetDataTypeForValue(const AZStd::any& value) const { return GetDataType(value.type()); }
//! Returns a DataType object representing the given TypeId, or Invalid if it doesn't exist.
virtual DataTypePtr GetDataType(DataType::Enum typeEnum) const = 0;
//! Utility function to returns a DataType object representing the given template type T, or Invalid if it doesn't exist.
//! Subclasses may need to implement this function too, and just call IGraphContext::GetDataType<T>()
//! in order to avoid "error C2275: 'Type': illegal use of this type as an expression"
template<typename T>
DataTypePtr GetDataType() const { return GetDataType(azrtti_typeid<T>()); }
};
} // namespace GraphModel
@@ -0,0 +1,110 @@
/*
* 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
// AZ
#include <AzCore/std/string/string_view.h>
// Graph Model
#include <GraphModel/Model/Node.h>
namespace AZ
{
class ReflectContext;
}
namespace GraphModel
{
//! Common base class for GraphInput/OutputNodes
class BaseInputOutputNode : public Node
{
public:
AZ_RTTI(BaseInputOutputNode, "{C54F11AE-3151-44D7-B206-9206FA888963}", Node);
static void Reflect(AZ::ReflectContext* context);
BaseInputOutputNode() = default; // Needed by SerializeContext
//! Constructor
//! \param graph The graph that owns this node
//! \param dataType The type of data represented by this node
BaseInputOutputNode(GraphPtr graph, DataTypePtr dataType);
const char* GetTitle() const override;
GraphModel::DataTypePtr GetNodeDataType() const;
AZStd::string GetName() const;
AZStd::string GetDisplayName() const;
AZStd::string GetDescription() const;
protected:
//! Registers metadata slots that are common for inputs and outputs, like name, displayName, and description.
void RegisterCommonSlots(AZStd::string_view directionName);
AZStd::string m_title;
AZStd::shared_ptr<DataType> m_dataType;
};
//! Provides a node that serves as a data input into a node graph.
class GraphInputNode : public BaseInputOutputNode
{
public:
AZ_RTTI(GraphInputNode, "{4CDE10B9-14C1-4B5A-896C-C3E15EDAC665}", BaseInputOutputNode);
static void Reflect(AZ::ReflectContext* context);
GraphInputNode() = default; // Needed by SerializeContext
//! Constructor
//! \param graph The graph that owns this node
//! \param dataType The type of data represented by this node
GraphInputNode(GraphModel::GraphPtr graph, DataTypePtr dataType);
void PostLoadSetup(GraphPtr graph, NodeId id) override;
//! Returns the value of the DefaultValue slot, which indicates the default value for this input. This
//! is the value that will be used when this node's graph is used as a ModuleNode, but no data is
//! connected to this graph input.
AZStd::any GetDefaultValue() const;
protected:
//! Registers SlotDescriptors for each of this node's slots
void RegisterSlots() override;
};
//! Provides an node that serves as a data output from a node graph.
class GraphOutputNode : public BaseInputOutputNode
{
public:
AZ_RTTI(GraphOutputNode, "{5E5188E1-7F79-41D4-965F-248EECE7A735}", BaseInputOutputNode);
static void Reflect(AZ::ReflectContext* context);
GraphOutputNode() = default; // Needed by SerializeContext
//! Constructor
//! \param graph The graph that owns this node
//! \param dataType The type of data represented by this node
GraphOutputNode(GraphModel::GraphPtr graph, DataTypePtr dataType);
void PostLoadSetup(GraphPtr graph, NodeId id) override;
protected:
//! Registers SlotDescriptors for each of this node's slots
void RegisterSlots() override;
};
}
@@ -0,0 +1,82 @@
/*
* 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
// AZ
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
// Graph Model
#include <GraphModel/Model/Common.h>
namespace AZ
{
namespace IO
{
class FileIOStream;
}
}
namespace GraphModel
{
//! This is a manager that exists to support ModuleNode. A ModuleNode is a node that contains
//! another node graph to be reused as a single node. If there are multiple ModuleNode instances
//! that all use the same graph, we should only need one copy of the referenced graph in memory.
//! The collection of available modules graphs will be managed here.
//! The graphs stored here are const/immutable, and used only for instancing ModuleNodes, which
//! do not make any changes to the underlying module graph.
class ModuleGraphManager
: public AzToolsFramework::AssetSystemBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(ModuleGraphManager, AZ::SystemAllocator, 0);
AZ_RTTI(Graph, "{68476353-C672-4408-9B34-A409CC63858E}");
explicit ModuleGraphManager(IGraphContextPtr graphContext, AZ::SerializeContext* serializeContext = nullptr);
virtual ~ModuleGraphManager();
//! Returns the Graph loaded from a module source file. If the file has already been loaded,
//! it simply returns the Graph. If it has not been loaded yet, this function will first load
//! the Graph from the source file.
//! \param sourceFileId Unique Id of the sourfe file that contains a module graph
AZ::Outcome<ConstGraphPtr, AZStd::string> GetModuleGraph(AZ::Uuid sourceFileId);
protected:
//! Loads a module graph from the given stream
virtual ConstGraphPtr LoadGraph(AZ::IO::FileIOStream& stream);
//////////////////////////////////////////////////////////////////////////
// AzToolsFramework::AssetSystemBus
//! WHen a module graph source file is added or changed, this will cause the Graph to be reloaded
void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override;
//////////////////////////////////////////////////////////////////////////
private:
//! Loads a Graph from a module source file
//! \param sourceFileId Unique Id of the sourfe file that contains a module graph
AZ::Outcome<ConstGraphPtr, AZStd::string> LoadGraph(AZ::Uuid sourceFileId);
// We use a weak_ptr to allow the graphs to go out of scope and be deleted when not used
using ModuleGraphMap = AZStd::unordered_map<AZ::Uuid /*Source File ID*/, AZStd::weak_ptr<const Graph>>;
AZStd::weak_ptr<IGraphContext> m_graphContext; //!< interface to client system specific data and functionality. Uses a weak_ptr so the IGraphContext can hold this ModuleGraphManager.
AZStd::string m_moduleFileExtension;
AZ::SerializeContext* m_serializeContext;
ModuleGraphMap m_graphs;
};
} // namespace GraphModel
@@ -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.
*
*/
#pragma once
// Graph Model
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/Node.h>
namespace GraphModel
{
//! Encapsulates an entire node graph as a node to be used in another graph.
//! The graph that defines this node is called a Module Graph, which has
//! GraphInputNodes and/or GraphOutputNodes to define inputs and outputs
//! for the graph. These input/output nodes become input/output Slots in
//! the ModuleNode.
class ModuleNode : public Node
{
public:
AZ_CLASS_ALLOCATOR(ModuleNode, AZ::SystemAllocator, 0);
AZ_RTTI(ModuleNode, "{C7D57EFE-462D-48A0-B46F-6E927D504BA5}", Node);
static void Reflect(AZ::ReflectContext* context);
ModuleNode() = default; // Needed by SerializeContext
//! Constructor
//! \param ownerGraph The graph that owns this node
//! \param sourceFileId The unique id for the module node graph source file, which is the module graph that defines this ModuleNode.
//! \param sourceFilePath The path to the module node graph source file. This will be used for node naming and debug output.
ModuleNode(GraphPtr ownerGraph, AZ::Uuid moduleGraphFileId, AZStd::string_view moduleGraphFileName);
const char* GetTitle() const override;
void PostLoadSetup(GraphPtr ownerGraph, NodeId id) override;
protected:
//! Gets the module graph that defines this ModuleNode
void LoadModuleGraph(ModuleGraphManagerPtr moduleGraphManager);
//! Registers input and output SlotDescriptions based on the contents of the module graph
void RegisterSlots() override;
ConstGraphPtr m_moduleGraph; //!< The module graph that defines the inputs, outputs, and behavior of this node
AZStd::string m_nodeTitle; //!< Node title indicates the name of the module file
AZ::Uuid m_moduleGraphFileId; //!< Unique identifier of the source file that contains the module graph
};
}
@@ -0,0 +1,258 @@
/*
* 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
// AZ
#include <AzCore/Math/Crc.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/set.h>
#include <AzCore/std/smart_ptr/enable_shared_from_this.h>
// Graph Model
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/GraphElement.h>
#include <GraphModel/Model/Slot.h>
namespace AZ
{
class ReflectContext;
}
namespace GraphModel
{
//!!! Start in Graph.h for high level GraphModel documentation !!!
enum class NodeType
{
GeneralNode = 0,
WrapperNode
};
//! The abstract base class for every type of node in a Graph. It consists primarily of a set of
//! Slots. There is no functionality here beyond managing the Slots and finding Connections. Any
//! useful functionality must be provided by subclasses in the client context where the GraphModel
//! framework is used.
//!
//! Slots are divided into two main objects: a SlotDefinition and the actual Slot.
//! The SlotDefinition contains the predefined description of each slot that the Node contains. This
//! information is not saved with the Node data in the Graph because it is provided by the Node subclass
//! itself (either hard-coded or reflected from some other source). The Slot is the functional part,
//! and contains any data related to specific instance of the Node (for example, the default value
//! of an Input Data Slot). This data is serialized with the Node. Whenever a Node is created, either
//! directly or by serializing in, the Node class ensures that Slots are created for each SlotDefinition
//! defined by the Node subclass.
//!
//! Every Slot in the Node has a SlotId, which is unique within the context of the Node.
//! A specific Slot in a spectific Node is called an Endpoint and is identified by a pairing of
//! NodeId and SlotId.
//!
//! Subclasses must call RegisterSlot() to define the Node's inputs and outputs, but it shouldn't need
//! to serialize any of its own data. This base class's Slot lists are reflected for serialization, and
//! that's all that should be needed in most cases.
class Node : public GraphElement, public AZStd::enable_shared_from_this<Node>
{
friend class Graph; // Because the Graph needs to set the ID, but no one else should be able to.
public:
AZ_CLASS_ALLOCATOR(Node, AZ::SystemAllocator, 0);
AZ_RTTI(Node, "{274B4495-FDBF-45A9-9BAD-9E90269F2B73}", GraphElement);
static void Reflect(AZ::ReflectContext* context);
static const int INVALID_NODE_ID = 0;
using SlotDefinitionList = AZStd::vector<SlotDefinitionPtr>;
// We use a map instead of unordered_map to get consistent order in XML to make diffs more readable. Performance
// isn't really a concern because these maps will be rather small.
// But ConstSlotMap uses unordered_map because it isn't serialized.
using SlotMap = AZStd::map<SlotId, SlotPtr>;
using ConstSlotMap = AZStd::unordered_map<SlotId, const SlotPtr>;
// Special case mapping for holding the extendable slots so we can keep track of their indexed
// order as well.
struct SortSlotsBySubId
{
AZ_TYPE_INFO(SortSlotsBySubId, "{01ED3FF5-0DE4-4B25-84FA-8763EB05FAFE}");
SortSlotsBySubId() = default;
bool operator()(const SlotPtr& left, const SlotPtr& right) const
{
return left->GetSlotSubId() < right->GetSlotSubId();
}
};
using ExtendableSlotSet = AZStd::set<SlotPtr, SortSlotsBySubId>;
using ExtendableSlotMap = AZStd::map<SlotName, ExtendableSlotSet>;
Node() = default; // Needed by SerializeContext
//! Constructor
//! \param graph The Graph that will own this Node (though constructing the Node doesn't actually add it to this graph yet).
explicit Node(GraphPtr graph);
//! Initializion after the Node has been serialized in.
//! This must be called whenever the default constructor is used.
//! Sets the m_graph pointer and caches pointers to other GraphElements.
//! It also ensures the loaded Slot data aligns with the defined SlotDefinitions.
virtual void PostLoadSetup(GraphPtr graph, NodeId id);
//! An alternative to the above PostLoadSetup when the
//! nodeId isn't already known (e.g. a deserialized node that has been copy/pasted)
virtual void PostLoadSetup();
//! Returns the name that will be displayed as the title of the Node in the UI
virtual const char* GetTitle() const = 0;
//! Returns the name that will be displayed as the sub-title of the Node in the UI
virtual const char* GetSubTitle() const
{
return "";
};
//! Returns node type (general by default) which can be overriden for
//! other types, such as wrapper nodes
virtual NodeType GetNodeType() const
{
return NodeType::GeneralNode;
}
NodeId GetId() const;
bool Contains(ConstSlotPtr slot) const;
//! Returns SlotDefinitions for all available Slots
const SlotDefinitionList& GetSlotDefinitions() const;
//! Returns the map of all available Slots.
//! For the generic case, there will be one Slot for every SlotDefinition in GetSlotDefinitions().
//! Additionally, for extendable slots there could be 0 or more Slots per SlotDefinition
const SlotMap& GetSlots();
ConstSlotMap GetSlots() const;
//! Returns the slot with the given slotId, or nullptr if it doesn't exist
SlotPtr GetSlot(const SlotId& slotId);
ConstSlotPtr GetSlot(const SlotId& slotId) const;
//! Returns the slot with the given SlotName, or nullptr if it doesn't exist.
//! This is a simplified version for normal (non-extendable) slots. It is equivalent to calling GetSlot
//! with the given SlotName and a subId of 0. If the slot is actually extendable, it
//! will return the first indexed slot if it exists.
SlotPtr GetSlot(const SlotName& name);
ConstSlotPtr GetSlot(const SlotName& name) const;
//! Returns an ordered set of the extendable slots for a given SlotName, or an empty set if there are none
const ExtendableSlotSet& GetExtendableSlots(const SlotName& name);
//! Returns the number of extendable slots for a given SlotName.
//! Will return -1 if the specified slot is not extendable.
int GetExtendableSlotCount(const SlotName& name);
//! Returns the DataType for the given slot, which can be overriden for individual nodes to extend
virtual DataTypePtr GetDataType(ConstSlotPtr slot) const;
//! Delete the specified slot, which is only allowed on extendable slots.
//! This method does nothing if the slot is not extendable.
void DeleteSlot(SlotPtr slot);
//! Check if the specified slot can be deleted, which is restricted by
//! - The slot must be extendable
//! - Deleting the slot can't reduce the number of extendable slots below the configured minimum
//! number of allowed slots for this definition
//! This method is also virtual so the client can impose any custom limitations as needed.
//! This method does nothing if the slot is not extendable.
virtual bool CanDeleteSlot(ConstSlotPtr slot) const;
//! Append a new slot to an extendable slot list.
//! This is restricted such that
//! - The slot definition must be extendable
//! - Creating a new slot can't increase the number of extendable slots above the configured maximum
//! number of allowed slots for this definition
//! This method does nothing if the slot is not extendable.
virtual SlotPtr AddExtendedSlot(const SlotName& slotName);
protected:
//! Default implementation will prevent slots from being extended past the
//! maximum allowed configuration, but the client could override this to impose
//! additional restrictions
virtual bool CanExtendSlot(SlotDefinitionPtr slotDefinition) const;
//! Subclasses should call this function during construction to define its slots.
//! The slot's name must be unique among all slots in this node.
void RegisterSlot(SlotDefinitionPtr slotDefinition);
//! Overridden by specific nodes to register their necessary slots
//! This is called automatically by this Node base class when PostLoadSetup is called,
//! which occurs after a Node has been deserialized. The derived classes are stil in charge
//! of calling it in their Node(GraphPtr graph) constructor, since their overrides aren't
//! accessible from the base class during construction.
virtual void RegisterSlots() {}
//! Once a subclass is done calling RegisterSlot(), it can call this function to
//! instantiate all the slot data. This should only be done when creating a new
//! Node, not when loading a Node from serialize data (in that case Slot creation
//! will be handled automatically by PostLoadSetup()).
void CreateSlotData();
private:
//! Common implementation for RegisterSlot() to a specific SlotDefinitionList
void RegisterSlot(SlotDefinitionPtr slotDefinition, SlotDefinitionList& slotDefinitionList);
//! Common implementation for CreateSlotData() to a specific SlotMap
void CreateSlotData(SlotMap& slotMap, const SlotDefinitionList& slotDefinitionList);
//! Specific implementation for creating slot data for extendable slots
void CreateExtendableSlotData();
//! This is a substep in the PostLoadSetup() process. It ensures that the set of loaded Slot
//! data aligns with the Node's pre-established SlotDefinitions, and calls PostLoadSetup()
//! on each Slot.
//! \param slotData The collection of loaded Slot object data (m_inputDataSlots, m_outputDataSlots, etc)
//! \param slotDefinitions The set of estalished SlotDefinitions that defines the Node's set of available slots
void SyncAndSetupSlots(SlotMap& slotData, Node::SlotDefinitionList& slotDefinitions);
//! Special case of above method for the extendable slots, which are stored in a different mapping
void SyncAndSetupExtendableSlots();
//! Assertions for use during slot registration, to prevent duplicates
void AssertPointerIsNew(SlotDefinitionPtr newSlotDefinition, const SlotDefinitionList& existingSlotDefinitions) const;
void AssertNameIsNew(SlotDefinitionPtr newSlotDefinition, const SlotDefinitionList& existingSlotDefinitions) const;
void AssertDisplayNameIsNew(SlotDefinitionPtr newSlotDefinition, const SlotDefinitionList& existingSlotDefinitions) const;
NodeId m_id = INVALID_NODE_ID;
// These are what will actually be serialized. That way we don't have to make every node sub-type
// provide its own reflection; it just puts the slots in these lists via RegisterSlot() and CreateSlotData().
// These are stored in separate maps rather than just one because some of these slot types don't need to be
// reflected to SerializeContext.
SlotMap m_propertySlots; //!< For slots with configuration = SlotDirection::Input SlotType::Property
SlotMap m_inputDataSlots; //!< For slots with configuration = SlotDirection::Input SlotType::Data
SlotMap m_outputDataSlots; //!< For slots with configuration = SlotDirection::Output SlotType::Data
SlotMap m_inputEventSlots; //!< For slots with configuration = SlotDirection::Input SlotType::Event
SlotMap m_outputEventSlots; //!< For slots with configuration = SlotDirection::Output SlotType::Event
ExtendableSlotMap m_extendableSlots; //!< For all extendable slots, regardless of configuration, since we need to serialize all of them
SlotMap m_allSlots; //!< Provies a single list of all of the above SlotMaps for convenient looping over them all
// These are not serialized; they're definitions of the slots that are part of the Node type
// definition so saving this data is unnecessary.
SlotDefinitionList m_propertySlotDefinitions; //!< For slots with configuration = SlotDirection::Input SlotType::Property
SlotDefinitionList m_inputDataSlotDefinitions; //!< For slots with configuration = SlotDirection::Input SlotType::Data
SlotDefinitionList m_outputDataSlotDefinitions; //!< For slots with configuration = SlotDirection::Output SlotType::Data
SlotDefinitionList m_inputEventSlotDefinitions; //!< For slots with configuration = SlotDirection::Input SlotType::Event
SlotDefinitionList m_outputEventSlotDefinitions; //!< For slots with configuration = SlotDirection::Output SlotType::Event
SlotDefinitionList m_extendableSlotDefinitions; //!< For all extendable slot configurations
SlotDefinitionList m_allSlotDefinitions; //!< Provies a single list of all of the above SlotDefinitionLists for convenient looping over them all
};
} // namespace GraphModel
@@ -0,0 +1,353 @@
/*
* 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
// AZ
#include <AzCore/std/any.h>
#include <AzCore/std/hash.h>
#include <AzCore/std/containers/list.h>
#include <AzCore/std/containers/set.h>
#include <AzCore/std/smart_ptr/enable_shared_from_this.h>
// Graph Model
#include <GraphModel/Model/Common.h>
#include <GraphModel/Model/GraphElement.h>
#include <GraphModel/Model/IGraphContext.h>
namespace GraphModel
{
//!!! Start in Graph.h for high level GraphModel documentation !!!
//! All slots have a SlotType and a SlotDirection. This combination determines the slot's available features.
enum class SlotType
{
Invalid,
Data, //!< Has a DataType and can be connected to other Data slots. Input Data slot has a default value for when it is not connected.
Event, //!< Has no DataType. Represents an event sent or received. Can be connected to other Event slots.
Property //!< Has a DataType and a value. Cannot be connected to other slots. SlotDirection must be Input.
};
//! All slots have a SlotType and a SlotDirection. This combination determines the slot's available features.
enum class SlotDirection
{
Invalid,
Input, //!< Represents information consumed by the node, usually appearing on the left side.
Output //!< Represents information produced by the node, usually appearing on the right side.
};
//! The sub ID is only used for extendable slots that can support
//! multiple slots of the same definition, where the sub ID is a
//! counter, not an index of the current slots
using SlotName = AZStd::string;
using SlotSubId = int;
struct SlotIdData
{
public:
AZ_TYPE_INFO(SlotIdData, "{D24130B9-89C4-4EAA-9A5D-3469B05C5065}");
static void Reflect(AZ::ReflectContext* context);
SlotIdData() = default;
explicit SlotIdData(const SlotName& name);
explicit SlotIdData(const SlotName& name, SlotSubId subId);
~SlotIdData() = default;
bool IsValid() const;
bool operator==(const SlotIdData& rhs) const;
bool operator!=(const SlotIdData& rhs) const;
bool operator<(const SlotIdData& rhs) const;
bool operator>(const SlotIdData& rhs) const;
AZStd::size_t GetHash() const;
SlotName m_name;
SlotSubId m_subId = 0;
};
struct ExtendableSlotConfiguration
{
public:
AZ_TYPE_INFO(ExtendableSlotConfiguration, "{ACD18AD2-AD90-408C-9C11-920C2A8D77EC}");
AZ_CLASS_ALLOCATOR(ExtendableSlotConfiguration, AZ::SystemAllocator, 0);
ExtendableSlotConfiguration() = default;
~ExtendableSlotConfiguration() = default;
bool m_isValid = false; //!< Flag to determine if this extendable slot configuration is valid
AZStd::string m_addButtonLabel; //!< Label for the button for adding new extendable slots
AZStd::string m_addButtonTooltip; //!< Tooltip for the button for adding new extendable slots
int m_minimumSlots = 1;
int m_maximumSlots = 100;
};
//! Provides static information about a Slot, like its name and data type.
//! The set of features provided by this slot is determined by the combination
//! of SlotDirection and SlotType, which is set depending on which Create* function
//! is used to create the SlotDefinition.
//!
//! This information will either be hard-coded for each Node type, or
//! reflected from some other source, so it does not need to be saved with
//! the Node data (i.e. it isn't added to a SerializeContext).
//!
//! See the Node class documentation for more.
//!
//! (We take the approach of using a single class with some features unused
//! in specific configurations because it ends up being cleaner than a complex
//! class hierarchy).
class SlotDefinition
{
public:
AZ_CLASS_ALLOCATOR(SlotDefinition, AZ::SystemAllocator, 0);
AZ_RTTI(SlotDefinition, "{917F9C1A-1513-4694-B25A-D6404A4991ED}");
SlotDefinition() = default;
virtual ~SlotDefinition() = default;
//! This set of factory functions create a SlotDefinition for each of the valid SlotDirection/SlotType combinations
static SlotDefinitionPtr CreateInputData(AZStd::string_view name, AZStd::string_view displayName, DataTypePtr dataType, AZStd::any defaultValue, AZStd::string_view description, ExtendableSlotConfiguration* extendableSlotConfiguration = nullptr);
static SlotDefinitionPtr CreateInputData(AZStd::string_view name, AZStd::string_view displayName, DataTypeList supportedDataTypes, AZStd::any defaultValue, AZStd::string_view description, ExtendableSlotConfiguration* extendableSlotConfiguration = nullptr);
static SlotDefinitionPtr CreateOutputData(AZStd::string_view name, AZStd::string_view displayName, DataTypePtr dataType, AZStd::string_view description, ExtendableSlotConfiguration* extendableSlotConfiguration = nullptr);
static SlotDefinitionPtr CreateInputEvent(AZStd::string_view name, AZStd::string_view displayName, AZStd::string_view description, ExtendableSlotConfiguration* extendableSlotConfiguration = nullptr);
static SlotDefinitionPtr CreateOutputEvent(AZStd::string_view name, AZStd::string_view displayName, AZStd::string_view description, ExtendableSlotConfiguration* extendableSlotConfiguration = nullptr);
static SlotDefinitionPtr CreateProperty(AZStd::string_view name, AZStd::string_view displayName, DataTypePtr dataType, AZStd::any defaultValue, AZStd::string_view description, ExtendableSlotConfiguration* extendableSlotConfiguration = nullptr);
SlotDirection GetSlotDirection() const;
SlotType GetSlotType() const;
//! Returns whether slot value is relevent to this slot's configuration
bool SupportsValue() const;
//! Returns whether slot data type is relevent to this slot's configuration
bool SupportsDataType() const;
//! Returns whether this slot's configuration allows connections to other slots
bool SupportsConnections() const;
//! Returns whether this slot matches the given configuration
bool Is(SlotDirection slotDirection, SlotType slotType) const;
//! Returns whether or not this slot is configured to be extendable
bool SupportsExtendability() const;
const SlotName& GetName() const; //!< Valid for all slot configurations
const AZStd::string& GetDisplayName() const; //!< Valid for all slot configurations
const AZStd::string& GetDescription() const; //!< Valid for all slot configurations
const DataTypeList& GetSupportedDataTypes() const; //!< Valid for Data and Property slots. Otherwise returns an empty DataTypeList.
AZStd::any GetDefaultValue() const; //!< Valid for Input Data and Property slots. Otherwise returns an empty AZStd::any.
//! These methods are only pertinent for extendable slots
const int GetMinimumSlots() const; //!< Retrieve the minimum configured number of extendable slots (returns a default value if not configured)
const int GetMaximumSlots() const; //!< Retrieve the maximum configured number of extendable slots (returns a default value if not configured)
const AZStd::string& GetExtensionLabel() const; //!< Retrieve the text for the label with the '+' sign for adding extendable slots
const AZStd::string& GetExtensionTooltip() const; //!< Retrieve the hover tooltip for the label with the '+' sign for adding extendable slots
private:
//! Helper method for handling the assignment/registration of the extendable slot configuration for a definition.
static void HandleExtendableSlotRegistration(AZStd::shared_ptr<SlotDefinition> slotDefinition, ExtendableSlotConfiguration* extendableSlotConfiguration);
SlotDirection m_slotDirection = SlotDirection::Invalid;
SlotType m_slotType = SlotType::Invalid;
SlotName m_name;
AZStd::string m_displayName;
AZStd::string m_description;
DataTypeList m_supportedDataTypes;
AZStd::any m_defaultValue;
ExtendableSlotConfiguration m_extendableSlotConfiguration;
};
//!!! Start in Graph.h for high level GraphModel documentation !!!
//! Represents the instance of a slot, based on a specific SlotDefinition.
//! If you think of the SlotDefinition as a class declaration, then a Slot is like an
//! instance of that class. Slots may contain data like default values and connections
//! to other Slots. The specific set of supported features is determined by the
//! SlotDefinition's combination of SlotType and SlotDirection.
//!
//! (We take the approach of using a single class with some features unused
//! in specific configurations because it ends up being cleaner than a complex
//! class hierarchy).
class Slot : public GraphElement, public AZStd::enable_shared_from_this<Slot>
{
friend class Graph; // So the Graph can update the Slot's cache of Connection pointers
public:
AZ_CLASS_ALLOCATOR(Slot, AZ::SystemAllocator, 0);
AZ_RTTI(Slot, "{50494867-04F1-4785-BB9C-9D6C96DCBFC9}", GraphElement);
static void Reflect(AZ::ReflectContext* context);
using ConnectionList = AZStd::set<AZStd::shared_ptr<Connection>>; // AZStd::unordered_set doesn't work with shared_ptr so use set
using WeakConnectionList = AZStd::list<AZStd::weak_ptr<Connection>>; // AZStd::set doesn't work with weak_ptr so use list
Slot() = default; // Needed by SerializeContext
~Slot() override = default;
//! Constructor
//! \param graph The Graph that will own this Slot
//! \param slotDefinition The descriptor that defines this Slot
//! \param subId The subId that is used to identify extendable slots
Slot(GraphPtr graph, SlotDefinitionPtr slotDefinition, SlotSubId subId = 0);
//! Initializion after the Slot has been serialized in.
//! This must be called whenever the default constructor is used.
//! Sets the m_graph pointer and caches pointers to other GraphElements.
virtual void PostLoadSetup(GraphPtr graph, SlotDefinitionPtr slotDefinition);
//! Return the SlotDefinition that defines this Slot
SlotDefinitionPtr GetDefinition() const;
//! Convenience functions that wrap SlotDefinition accessors
bool Is(SlotDirection slotDirection, SlotType slotType) const;
SlotDirection GetSlotDirection() const;
SlotType GetSlotType() const;
bool SupportsValue() const;
bool SupportsDataType() const;
bool SupportsConnections() const;
bool SupportsExtendability() const;
const SlotName& GetName() const; //!< Valid for all slot configurations
const AZStd::string& GetDisplayName() const; //!< Valid for all slot configurations
const AZStd::string& GetDescription() const; //!< Valid for all slot configurations
DataTypePtr GetDataType() const; //!< Valid for Data and Property slots. Otherwise returns null.
AZStd::any GetDefaultValue() const; //!< Valid for Input Data and Property slots. Otherwise returns an empty AZStd::any.
//! Valid for Data and Property slots. Otherwise returns an empty DataTypeList.
//! If valid, this will return the full list of all data types this slot could support.
const DataTypeList& GetSupportedDataTypes() const;
//! Valid for Data and Property slots. Otherwise returns an empty DataTypeList.
//! If valid, this will return the subset of data types that this slot can currently accept
//! based on the configuration of the node this slot belongs to and/or connections to other slots on the node.
const DataTypeList& GetPossibleDataTypes() const;
//! Convenience functions that wrap SlotDefinition accessors (specific to definitions that support extendable slots)
const int GetMinimumSlots() const;
const int GetMaximumSlots() const;
SlotId GetSlotId() const;
SlotSubId GetSlotSubId() const;
//! Get the Node that contains this Slot.
//! This function cannot be called until this Slot is added to a Node and
//! that Node is added to the Graph.
NodePtr GetParentNode() const;
//! Return the slot's value, which will be used if there are no input connections.
//! Valid for Input Data and Property slots.
AZStd::any GetValue() const;
//! Return the slot's value, which will be used if there are no input connections. Returns 0 if the type doesn't match.
//! Type template type T must match the slot's data type.
//! Valid for Input Data and Property slots.
template<typename T>
const T& GetValue() const;
//! Sets the slot's value, which will be used if there are no input connections.
//! Type template type T must match the slot's data type.
//! Valid for Input Data and Property slots.
template<typename T>
void SetValue(const T& value);
//! Sets the slot's value, which will be used if there are no input connections.
//! AZStd::any type must match the slot's data type.
//! Valid for Input Data and Property slots.
void SetValue(const AZStd::any& value);
// CJS TODO: More functions to add a bit later...
// CJS TODO: Also cache connection information here so Slot doesn't have to search the Graph for connections
//! Whether it's connected to other Slots in the Graph
//! (Property slots will never have connections)
// bool IsConnected() const;
//! Returns the list of connections to this Slot.
//! (Property slots will never have connections)
ConnectionList GetConnections() const;
//! Returns the list of other Slots that this Slot is connected to
//! (Property slots will never have connections)
// AZStd::vector<SlotPtr> GetConnectedSlots();
//! Returns the list of all Nodes that this Slot is connected to
//! (Property slots will never have connections)
//AZStd::vector<NodePtr> GetConnectedNodes();
//! Returns the list of IDs for other Slots that this Slot is connected to
//! (Property slots will never have connections)
// AZStd::vector<Endpoint> GetConnectedEndpoints();
//! Returns the list of IDs for all Nodes that this Slot is connected to
//! (Property slots will never have connections)
// AZStd::vector<NodeId> GetConnectedNodeIds();
protected:
#if defined(AZ_ENABLE_TRACING)
void AssertWithTypeInfo(bool expression, DataTypePtr dataTypeUsed, const char* message) const;
void AssertTypeMatch(DataTypePtr dataTypeUsed, const char* message) const;
#endif
private:
mutable AZStd::weak_ptr<Node> m_parentNode; //!< This is a mutable because it is just-in-time initialized in a const accessor function. This is okay because it's just a cache.
SlotDefinitionPtr m_slotDefinition; //!< Pointer to the SlotDefinition in the parent Node, that defines this slot.
AZStd::any m_value; //!< This is the value that gets used for a Property slot or an Input Data slot that doesn't have any connection.
WeakConnectionList m_connections; //!< List of connections to this Slot. Not reflected/serialized because this is just a cache of information owned by the Graph.
SlotSubId m_subId = 0; //!< SubId to uniquely identify extendable slots of the same name (regular slots will always have a SubId of 0)
};
template<typename T>
const T& Slot::GetValue() const
{
const T* pValue = AZStd::any_cast<T>(&m_value);
#if defined(AZ_ENABLE_TRACING)
DataTypePtr dataTypeUsed = GetGraphContext()->GetDataType<T>();
AssertWithTypeInfo(SupportsValue(), dataTypeUsed, "This slot type does not support Value");
AssertTypeMatch(dataTypeUsed, "Slot::GetValue used with the wrong type");
AssertWithTypeInfo(nullptr != pValue, dataTypeUsed, "m_value does not hold data of the appropriate type");
#endif
return *pValue;
}
template<typename T>
void Slot::SetValue(const T& value)
{
#if defined(AZ_ENABLE_TRACING)
DataTypePtr dataTypeUsed = GetGraphContext()->GetDataType<T>();
AssertWithTypeInfo(SupportsValue(), dataTypeUsed, "This slot type does not support Value");
AssertTypeMatch(dataTypeUsed, "Slot::SetValue used with the wrong type");
#endif
m_value = value;
}
} // namespace GraphModel
namespace AZStd
{
// This must be defined so that our custom data type SlotId can be used as a key
// in AZStd::unordered_map
template <>
struct hash<GraphModel::SlotId>
{
typedef GraphModel::SlotId argument_type;
typedef size_t result_type;
AZ_FORCE_INLINE size_t operator()(const argument_type& id) const
{
return id.GetHash();
}
};
}