You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
731 lines
23 KiB
C++
731 lines
23 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <AzCore/Component/ComponentApplication.h>
|
|
#include <AzCore/Serialization/EditContext.h>
|
|
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
|
|
|
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
|
|
|
#include <Components/Nodes/NodeComponent.h>
|
|
|
|
#include <Components/GeometryComponent.h>
|
|
#include <Components/PersistentIdComponent.h>
|
|
#include <GraphCanvas/Components/Nodes/NodeUIBus.h>
|
|
#include <GraphCanvas/Components/Slots/SlotBus.h>
|
|
|
|
namespace GraphCanvas
|
|
{
|
|
//////////////////
|
|
// NodeComponent
|
|
//////////////////
|
|
|
|
void NodeComponent::Reflect(AZ::ReflectContext* context)
|
|
{
|
|
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
|
if (!serializeContext)
|
|
{
|
|
return;
|
|
}
|
|
|
|
serializeContext->Class<NodeSaveData>()
|
|
->Version(1)
|
|
->Field("HideUnusedSlots", &NodeSaveData::m_hideUnusedSlots)
|
|
;
|
|
|
|
serializeContext->Class<NodeComponent, GraphCanvasPropertyComponent>()
|
|
->Version(4)
|
|
->Field("Configuration", &NodeComponent::m_configuration)
|
|
->Field("Slots", &NodeComponent::m_slots)
|
|
->Field("UserData", &NodeComponent::m_userData)
|
|
->FieldFromBase<NodeComponent>("SaveData", &ComponentSaveDataInterface<NodeSaveData>::m_saveData)
|
|
;
|
|
|
|
|
|
AZ::EditContext* editContext = serializeContext->GetEditContext();
|
|
if (!editContext)
|
|
{
|
|
return;
|
|
}
|
|
|
|
editContext->Class<NodeComponent>("Node", "The node's UI representation")
|
|
->ClassElement(AZ::Edit::ClassElements::EditorData, "Node's class attributes")
|
|
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &NodeComponent::m_configuration, "Configuration", "This node's properties")
|
|
;
|
|
}
|
|
|
|
AZ::Entity* NodeComponent::CreateCoreNodeEntity(const NodeConfiguration& config)
|
|
{
|
|
// Create this Node's entity.
|
|
AZ::Entity* entity = aznew AZ::Entity();
|
|
|
|
entity->CreateComponent<NodeComponent>(config);
|
|
entity->CreateComponent<GeometryComponent>();
|
|
entity->CreateComponent<PersistentIdComponent>();
|
|
|
|
return entity;
|
|
}
|
|
|
|
NodeComponent::NodeComponent()
|
|
{
|
|
}
|
|
|
|
NodeComponent::NodeComponent(const NodeConfiguration& config)
|
|
: m_configuration(config)
|
|
{
|
|
}
|
|
|
|
NodeComponent::~NodeComponent()
|
|
{
|
|
for (auto& slotRef : m_slots)
|
|
{
|
|
delete slotRef;
|
|
}
|
|
}
|
|
|
|
void NodeComponent::Init()
|
|
{
|
|
InitSaveDataInterface(GetEntityId());
|
|
|
|
AZ::EntityBus::Handler::BusConnect(GetEntityId());
|
|
|
|
for (auto entityRef : m_slots)
|
|
{
|
|
AZ::Entity* slotEntity = entityRef;
|
|
if (slotEntity)
|
|
{
|
|
if (slotEntity->GetState() == AZ::Entity::State::Constructed)
|
|
{
|
|
slotEntity->Init();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NodeComponent::Activate()
|
|
{
|
|
}
|
|
|
|
void NodeComponent::Deactivate()
|
|
{
|
|
GraphCanvasPropertyComponent::Deactivate();
|
|
|
|
GroupableSceneMemberRequestBus::Handler::BusDisconnect();
|
|
SceneMemberRequestBus::Handler::BusDisconnect();
|
|
NodeRequestBus::Handler::BusDisconnect();
|
|
|
|
for (AZ::Entity* slotEntity : m_slots)
|
|
{
|
|
if (slotEntity)
|
|
{
|
|
if (slotEntity && slotEntity->GetState() == AZ::Entity::State::Active)
|
|
{
|
|
slotEntity->Deactivate();
|
|
}
|
|
}
|
|
}
|
|
|
|
ConnectionNotificationBus::Handler::BusDisconnect();
|
|
}
|
|
|
|
void NodeComponent::OnConnectedTo(const AZ::EntityId& /*connectionId*/, const Endpoint& /*endpoint*/)
|
|
{
|
|
UpdateDisabledStateVisuals();
|
|
}
|
|
|
|
void NodeComponent::OnDisconnectedFrom(const AZ::EntityId& /*connectionId*/, const Endpoint& /*endpoint*/)
|
|
{
|
|
RootGraphicsItemRequests* itemInterface = RootGraphicsItemRequestBus::FindFirstHandler(GetEntityId());
|
|
|
|
if (itemInterface)
|
|
{
|
|
RootGraphicsItemEnabledState enabledState = itemInterface->GetEnabledState();
|
|
RootGraphicsItemEnabledState updatedState = UpdateEnabledState();
|
|
|
|
if (updatedState != enabledState)
|
|
{
|
|
AZStd::unordered_set< NodeId > updatedStateSet;
|
|
updatedStateSet.insert(GetEntityId());
|
|
|
|
GraphUtils::SetNodesEnabledState(updatedStateSet, updatedState);
|
|
}
|
|
}
|
|
}
|
|
|
|
void NodeComponent::OnEntityExists(const AZ::EntityId& /*entityId*/)
|
|
{
|
|
// Temporary version conversion added in 1.xx to add a PersistentId onto the SceneMembers.
|
|
// Remove after a few revisions with warnings about resaving graphs.
|
|
if (AZ::EntityUtils::FindFirstDerivedComponent<PersistentIdComponent>(GetEntityId()) == nullptr)
|
|
{
|
|
AZ::Entity* selfEntity = GetEntity();
|
|
if (selfEntity)
|
|
{
|
|
selfEntity->CreateComponent<PersistentIdComponent>();
|
|
}
|
|
}
|
|
}
|
|
|
|
void NodeComponent::OnEntityActivated(const AZ::EntityId&)
|
|
{
|
|
AZ::EntityBus::Handler::BusDisconnect();
|
|
|
|
// Removing the Node properties from the side panel until we decide what we want to show.
|
|
//GraphCanvasPropertyComponent::Activate();
|
|
|
|
NodeRequestBus::Handler::BusConnect(GetEntityId());
|
|
SceneMemberRequestBus::Handler::BusConnect(GetEntityId());
|
|
GroupableSceneMemberRequestBus::Handler::BusConnect(GetEntityId());
|
|
|
|
for (AZ::Entity* slotEntity : m_slots)
|
|
{
|
|
if (slotEntity)
|
|
{
|
|
if (slotEntity && slotEntity->GetState() == AZ::Entity::State::Init)
|
|
{
|
|
slotEntity->Activate();
|
|
SlotRequestBus::Event(slotEntity->GetId(), &SlotRequests::SetNode, GetEntityId());
|
|
StyleNotificationBus::Event(slotEntity->GetId(), &StyleNotifications::OnStyleChanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnNodeActivated);
|
|
}
|
|
|
|
void NodeComponent::SetScene(const AZ::EntityId& sceneId)
|
|
{
|
|
if (SceneNotificationBus::Handler::BusIsConnected())
|
|
{
|
|
SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnRemovedFromScene, m_sceneId);
|
|
SceneNotificationBus::Handler::BusDisconnect(m_sceneId);
|
|
}
|
|
|
|
m_sceneId = sceneId;
|
|
RegisterIds(GetEntityId(), m_sceneId);
|
|
|
|
if (m_sceneId.IsValid())
|
|
{
|
|
SceneNotificationBus::Handler::BusConnect(m_sceneId);
|
|
SceneMemberNotificationBus::Handler::BusConnect(m_sceneId);
|
|
|
|
SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnSceneSet, m_sceneId);
|
|
|
|
OnStylesChanged();
|
|
|
|
AZ::EntityId grid;
|
|
SceneRequestBus::EventResult(grid, m_sceneId, &SceneRequests::GetGrid);
|
|
|
|
NodeUIRequestBus::Event(GetEntityId(), &NodeUIRequests::SetGrid, grid);
|
|
NodeUIRequestBus::Event(GetEntityId(), &NodeUIRequests::SetSnapToGrid, true);
|
|
NodeUIRequestBus::Event(GetEntityId(), &NodeUIRequests::SetResizeToGrid, true);
|
|
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnAddedToScene, m_sceneId);
|
|
}
|
|
}
|
|
|
|
void NodeComponent::ClearScene(const AZ::EntityId& oldSceneId)
|
|
{
|
|
SceneNotificationBus::Handler::BusDisconnect(oldSceneId);
|
|
|
|
AZ_Assert(m_sceneId.IsValid(), "This node (ID: %p) is not in a scene (ID: %p)!", GetEntityId(), m_sceneId);
|
|
AZ_Assert(GetEntityId().IsValid(), "This node (ID: %p) doesn't have an Entity!", GetEntityId());
|
|
|
|
if (!m_sceneId.IsValid() || !GetEntityId().IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnRemovedFromScene, m_sceneId);
|
|
m_sceneId.SetInvalid();
|
|
}
|
|
|
|
void NodeComponent::SignalMemberSetupComplete()
|
|
{
|
|
SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnMemberSetupComplete);
|
|
|
|
if (m_saveData.m_hideUnusedSlots)
|
|
{
|
|
SceneRequests* requests = SceneRequestBus::FindFirstHandler(GetScene());
|
|
|
|
if (requests->IsLoading() || requests->IsPasting())
|
|
{
|
|
m_updateSlotState = true;
|
|
}
|
|
else
|
|
{
|
|
HideUnusedSlotsImpl();
|
|
}
|
|
}
|
|
}
|
|
|
|
AZ::EntityId NodeComponent::GetScene() const
|
|
{
|
|
return m_sceneId;
|
|
}
|
|
|
|
void NodeComponent::OnSceneReady()
|
|
{
|
|
SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnSceneReady);
|
|
}
|
|
|
|
void NodeComponent::OnStylesChanged()
|
|
{
|
|
for (auto& slotRef : m_slots)
|
|
{
|
|
StyleNotificationBus::Event(slotRef->GetId(), &StyleNotifications::OnStyleChanged);
|
|
}
|
|
}
|
|
|
|
void NodeComponent::OnGraphLoadComplete()
|
|
{
|
|
if (m_updateSlotState)
|
|
{
|
|
m_updateSlotState = false;
|
|
if (m_saveData.m_hideUnusedSlots)
|
|
{
|
|
HideUnusedSlotsImpl();
|
|
}
|
|
}
|
|
}
|
|
|
|
void NodeComponent::OnPasteEnd()
|
|
{
|
|
if (m_updateSlotState)
|
|
{
|
|
m_updateSlotState = false;
|
|
if (m_saveData.m_hideUnusedSlots)
|
|
{
|
|
HideUnusedSlotsImpl();
|
|
}
|
|
}
|
|
}
|
|
|
|
void NodeComponent::SetTooltip(const AZStd::string& tooltip)
|
|
{
|
|
m_configuration.SetTooltip(tooltip);
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnTooltipChanged, m_configuration.GetTooltip());
|
|
}
|
|
|
|
void NodeComponent::SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip)
|
|
{
|
|
m_configuration.SetTooltip(tooltip.GetDisplayString());
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnTooltipChanged, m_configuration.GetTooltip());
|
|
}
|
|
|
|
void NodeComponent::AddSlot(const AZ::EntityId& slotId)
|
|
{
|
|
AZ_Assert(slotId.IsValid(), "Slot entity (ID: %s) is not valid!", slotId.ToString().data());
|
|
|
|
if (SlotRequestBus::FindFirstHandler(slotId))
|
|
{
|
|
auto slotEntity = AzToolsFramework::GetEntityById(slotId);
|
|
auto entry = AZStd::find_if(m_slots.begin(), m_slots.end(), [slotId](AZ::Entity* slot) { return slot->GetId() == slotId; });
|
|
if (entry == m_slots.end() && slotEntity)
|
|
{
|
|
m_slots.emplace_back(slotEntity);
|
|
SlotRequestBus::Event(slotId, &SlotRequests::SetNode, GetEntityId());
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnSlotAddedToNode, slotId);
|
|
SlotNotificationBus::MultiHandler::BusConnect(slotId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AZ_Assert(false, "Entity (ID: %s) does not implement SlotRequestBus", slotId.ToString().data());
|
|
}
|
|
}
|
|
|
|
void NodeComponent::RemoveSlot(const AZ::EntityId& slotId)
|
|
{
|
|
AZ_Assert(slotId.IsValid(), "Slot (ID: %s) is not valid!", slotId.ToString().data());
|
|
|
|
auto entry = AZStd::find_if(m_slots.begin(), m_slots.end(), [slotId](AZ::Entity* slot) { return slot->GetId() == slotId; });
|
|
AZ_Assert(entry != m_slots.end(), "Slot (ID: %s) is unknown", slotId.ToString().data());
|
|
|
|
if (entry != m_slots.end())
|
|
{
|
|
m_slots.erase(entry);
|
|
|
|
QGraphicsLayoutItem* layoutItem = nullptr;
|
|
VisualRequestBus::EventResult(layoutItem, slotId, &VisualRequests::AsGraphicsLayoutItem);
|
|
|
|
SlotNotificationBus::MultiHandler::BusDisconnect(slotId);
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnSlotRemovedFromNode, slotId);
|
|
SlotRequestBus::Event(slotId, &SlotRequests::ClearConnections);
|
|
SlotRequestBus::Event(slotId, &SlotRequests::SetNode, AZ::EntityId());
|
|
|
|
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, slotId);
|
|
NodeUIRequestBus::Event(GetEntityId(), &NodeUIRequests::AdjustSize);
|
|
|
|
delete layoutItem;
|
|
}
|
|
}
|
|
|
|
AZStd::vector<AZ::EntityId> NodeComponent::GetSlotIds() const
|
|
{
|
|
AZStd::vector<AZ::EntityId> result;
|
|
result.reserve(m_slots.size());
|
|
|
|
for (auto slot : m_slots)
|
|
{
|
|
result.emplace_back(slot->GetId());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
AZStd::vector<SlotId> NodeComponent::GetVisibleSlotIds() const
|
|
{
|
|
AZStd::vector< SlotId > result;
|
|
result.reserve(m_slots.size());
|
|
|
|
for (auto slot : m_slots)
|
|
{
|
|
SlotId slotId = slot->GetId();
|
|
|
|
bool isVisible = false;
|
|
SlotGroup slotGroup = SlotGroups::Invalid;
|
|
|
|
SlotRequestBus::EventResult(slotGroup, slotId, &SlotRequests::GetSlotGroup);
|
|
SlotLayoutRequestBus::EventResult(isVisible, GetEntityId(), &SlotLayoutRequests::IsSlotGroupVisible, slotGroup);
|
|
|
|
if (!isVisible)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
result.emplace_back(slotId);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
AZStd::vector<SlotId> NodeComponent::FindVisibleSlotIdsByType(const ConnectionType& connectionType, const SlotType& slotType) const
|
|
{
|
|
AZStd::vector<SlotId> result;
|
|
result.reserve(m_slots.size());
|
|
|
|
for (auto slot : m_slots)
|
|
{
|
|
SlotId slotId = slot->GetId();
|
|
|
|
bool isVisible = false;
|
|
SlotGroup slotGroup = SlotGroups::Invalid;
|
|
|
|
SlotRequestBus::EventResult(slotGroup, slotId, &SlotRequests::GetSlotGroup);
|
|
SlotLayoutRequestBus::EventResult(isVisible, GetEntityId(), &SlotLayoutRequests::IsSlotGroupVisible, slotGroup);
|
|
|
|
if (!isVisible)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ConnectionType testConnectionType = ConnectionType::CT_Invalid;
|
|
SlotRequestBus::EventResult(testConnectionType, slotId, &SlotRequests::GetConnectionType);
|
|
|
|
if (testConnectionType == ConnectionType::CT_Invalid || testConnectionType != connectionType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
SlotType testSlotType = SlotTypes::Invalid;
|
|
SlotRequestBus::EventResult(testSlotType, slotId, &SlotRequests::GetSlotType);
|
|
|
|
if (testSlotType == SlotTypes::Invalid || testSlotType != slotType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
result.emplace_back(slotId);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool NodeComponent::HasConnections() const
|
|
{
|
|
bool hasConnections = false;
|
|
|
|
for (auto slot : m_slots)
|
|
{
|
|
SlotId slotId = slot->GetId();
|
|
|
|
SlotRequestBus::EventResult(hasConnections, slotId, &SlotRequests::HasConnections);
|
|
|
|
if (hasConnections)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hasConnections;
|
|
}
|
|
|
|
AZStd::any* NodeComponent::GetUserData()
|
|
{
|
|
return &m_userData;
|
|
}
|
|
|
|
bool NodeComponent::IsWrapped() const
|
|
{
|
|
return m_wrappingNode.IsValid();
|
|
}
|
|
|
|
void NodeComponent::SetWrappingNode(const AZ::EntityId& wrappingNode)
|
|
{
|
|
if (!wrappingNode.IsValid())
|
|
{
|
|
AZ::EntityId wrappedNodeCache = m_wrappingNode;
|
|
|
|
m_wrappingNode = wrappingNode;
|
|
|
|
if (wrappedNodeCache.IsValid())
|
|
{
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnNodeUnwrapped, wrappedNodeCache);
|
|
}
|
|
}
|
|
else if (!m_wrappingNode.IsValid())
|
|
{
|
|
m_wrappingNode = wrappingNode;
|
|
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnNodeWrapped, wrappingNode);
|
|
}
|
|
else
|
|
{
|
|
AZ_Warning("Graph Canvas", false, "The same node is trying to be wrapped by two objects at once.");
|
|
}
|
|
}
|
|
|
|
AZ::EntityId NodeComponent::GetWrappingNode() const
|
|
{
|
|
return m_wrappingNode;
|
|
}
|
|
|
|
void NodeComponent::SignalBatchedConnectionManipulationBegin()
|
|
{
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnBatchedConnectionManipulationBegin);
|
|
}
|
|
|
|
void NodeComponent::SignalBatchedConnectionManipulationEnd()
|
|
{
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnBatchedConnectionManipulationEnd);
|
|
}
|
|
|
|
void NodeComponent::SignalConnectionMoveBegin(const ConnectionId& connectionId)
|
|
{
|
|
ConnectionNotificationBus::Handler::BusConnect(connectionId);
|
|
}
|
|
|
|
RootGraphicsItemEnabledState NodeComponent::UpdateEnabledState()
|
|
{
|
|
RootGraphicsItemRequests* graphicsInterface = RootGraphicsItemRequestBus::FindFirstHandler(GetEntityId());
|
|
|
|
if (graphicsInterface == nullptr)
|
|
{
|
|
return RootGraphicsItemEnabledState::ES_Enabled;
|
|
}
|
|
|
|
if (graphicsInterface && graphicsInterface->GetEnabledState() == RootGraphicsItemEnabledState::ES_Disabled)
|
|
{
|
|
return graphicsInterface->GetEnabledState();
|
|
}
|
|
|
|
bool foundDisabledNode = false;
|
|
bool foundEnabledNode = false;
|
|
|
|
AZStd::unordered_set< NodeId > connectedNodes;
|
|
|
|
for (AZ::Entity* slotEntity : m_slots)
|
|
{
|
|
Endpoint currentEndpoint(GetEntityId(), slotEntity->GetId());
|
|
|
|
SlotRequests* slotInterface = SlotRequestBus::FindFirstHandler(slotEntity->GetId());
|
|
|
|
if (slotInterface == nullptr)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ConnectionType connectionType = slotInterface->GetConnectionType();
|
|
SlotType slotType = slotInterface->GetSlotType();
|
|
|
|
// We only want to follow execution In's for now.
|
|
if (connectionType == CT_Input
|
|
&& slotType == SlotTypes::ExecutionSlot)
|
|
{
|
|
AZStd::vector< ConnectionId > connections;
|
|
SlotRequestBus::EventResult(connections, slotEntity->GetId(), &SlotRequests::GetConnections);
|
|
|
|
for (ConnectionId connectionId : connections)
|
|
{
|
|
Endpoint otherEndpoint;
|
|
ConnectionRequestBus::EventResult(otherEndpoint, connectionId, &ConnectionRequests::FindOtherEndpoint, currentEndpoint);
|
|
|
|
if (otherEndpoint.IsValid())
|
|
{
|
|
bool isEnabled = false;
|
|
RootGraphicsItemRequestBus::EventResult(isEnabled, otherEndpoint.GetNodeId(), &RootGraphicsItemRequests::IsEnabled);
|
|
|
|
if (isEnabled)
|
|
{
|
|
foundEnabledNode = true;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
foundDisabledNode = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (foundDisabledNode && !foundEnabledNode)
|
|
{
|
|
graphicsInterface->SetEnabledState(RootGraphicsItemEnabledState::ES_PartialDisabled);
|
|
}
|
|
else
|
|
{
|
|
graphicsInterface->SetEnabledState(RootGraphicsItemEnabledState::ES_Enabled);
|
|
}
|
|
|
|
return graphicsInterface->GetEnabledState();
|
|
}
|
|
|
|
bool NodeComponent::HasHideableSlots() const
|
|
{
|
|
bool canHideSlots = false;
|
|
|
|
for (auto slotEntity : m_slots)
|
|
{
|
|
if (GraphUtils::IsSlotHideable(slotEntity->GetId()))
|
|
{
|
|
canHideSlots = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return canHideSlots;
|
|
}
|
|
|
|
bool NodeComponent::IsHidingUnusedSlots() const
|
|
{
|
|
return m_saveData.m_hideUnusedSlots;
|
|
}
|
|
|
|
void NodeComponent::ShowAllSlots()
|
|
{
|
|
if (m_saveData.m_hideUnusedSlots)
|
|
{
|
|
for (auto slotEntity : m_slots)
|
|
{
|
|
VisualRequestBus::Event(slotEntity->GetId(), &VisualRequests::SetVisible, true);
|
|
}
|
|
|
|
m_saveData.m_hideUnusedSlots = false;
|
|
m_saveData.SignalDirty();
|
|
}
|
|
}
|
|
|
|
void NodeComponent::HideUnusedSlots()
|
|
{
|
|
// Always hide the slots to deal with new slots that might have been added. Or previously filled slots that
|
|
// are no unfilled.
|
|
HideUnusedSlotsImpl();
|
|
|
|
m_saveData.m_hideUnusedSlots = true;
|
|
m_saveData.SignalDirty();
|
|
}
|
|
|
|
void NodeComponent::SignalNodeAboutToBeDeleted()
|
|
{
|
|
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnNodeAboutToBeDeleted);
|
|
}
|
|
|
|
void NodeComponent::OnMoveFinalized(bool isValidConnection)
|
|
{
|
|
if (isValidConnection)
|
|
{
|
|
UpdateDisabledStateVisuals();
|
|
}
|
|
|
|
ConnectionNotificationBus::Handler::BusDisconnect();
|
|
}
|
|
|
|
bool NodeComponent::IsGrouped() const
|
|
{
|
|
return !IsWrapped() && m_owningGroupId.IsValid();
|
|
}
|
|
|
|
const AZ::EntityId& NodeComponent::GetGroupId() const
|
|
{
|
|
return m_owningGroupId;
|
|
}
|
|
|
|
void NodeComponent::RegisterToGroup(const AZ::EntityId& groupId)
|
|
{
|
|
if (!IsWrapped())
|
|
{
|
|
m_owningGroupId = groupId;
|
|
GroupableSceneMemberNotificationBus::Event(GetEntityId(), &GroupableSceneMemberNotifications::OnGroupChanged);
|
|
}
|
|
}
|
|
|
|
void NodeComponent::UnregisterFromGroup(const AZ::EntityId& groupId)
|
|
{
|
|
if (m_owningGroupId == groupId)
|
|
{
|
|
m_owningGroupId.SetInvalid();
|
|
GroupableSceneMemberNotificationBus::Event(GetEntityId(), &GroupableSceneMemberNotifications::OnGroupChanged);
|
|
}
|
|
}
|
|
void NodeComponent::RemoveFromGroup()
|
|
{
|
|
if (m_owningGroupId.IsValid())
|
|
{
|
|
NodeGroupRequestBus::Event(m_owningGroupId, &NodeGroupRequests::RemoveElementFromGroup, GetEntityId());
|
|
}
|
|
}
|
|
|
|
void NodeComponent::HideUnusedSlotsImpl()
|
|
{
|
|
HideSlotConfig hideConfig;
|
|
|
|
for (auto slotEntity : m_slots)
|
|
{
|
|
Endpoint endpoint(GetEntityId(), slotEntity->GetId());
|
|
|
|
if (GraphUtils::CanHideEndpoint(endpoint, hideConfig))
|
|
{
|
|
VisualRequestBus::Event(endpoint.GetSlotId(), &VisualRequests::SetVisible, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void NodeComponent::UpdateDisabledStateVisuals()
|
|
{
|
|
RootGraphicsItemRequests* itemInterface = RootGraphicsItemRequestBus::FindFirstHandler(GetEntityId());
|
|
|
|
if (itemInterface)
|
|
{
|
|
RootGraphicsItemEnabledState enabledState = itemInterface->GetEnabledState();
|
|
RootGraphicsItemEnabledState updatedState = UpdateEnabledState();
|
|
|
|
if (updatedState != enabledState)
|
|
{
|
|
AZStd::unordered_set< NodeId > updatedStateSet;
|
|
updatedStateSet.insert(GetEntityId());
|
|
|
|
GraphUtils::SetNodesEnabledState(updatedStateSet, updatedState);
|
|
}
|
|
}
|
|
}
|
|
}
|