1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129 |
- /*
- * 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 <qcursor.h>
- #include <qgraphicsscene.h>
- #include <qgraphicsview.h>
- #include <QToolTip>
- #include <AzCore/Serialization/EditContext.h>
- #include <AzQtComponents/Components/ToastNotification.h>
- #include <Components/Connections/ConnectionComponent.h>
- #include <Components/Connections/ConnectionLayerControllerComponent.h>
- #include <Components/Connections/ConnectionVisualComponent.h>
- #include <Components/StylingComponent.h>
- #include <GraphCanvas/Components/Nodes/NodeBus.h>
- #include <GraphCanvas/Components/Slots/SlotBus.h>
- #include <GraphCanvas/Components/Slots/Extender/ExtenderSlotBus.h>
- #include <GraphCanvas/Editor/AssetEditorBus.h>
- #include <GraphCanvas/Editor/GraphModelBus.h>
- #include <GraphCanvas/Utils/GraphUtils.h>
- #include <GraphCanvas/Utils/ConversionUtils.h>
- #include <GraphCanvas/Widgets/GraphCanvasGraphicsView/GraphCanvasGraphicsView.h>
- namespace GraphCanvas
- {
- ///////////////////////////////
- // ConnectionEndpointAnimator
- ///////////////////////////////
- ConnectionComponent::ConnectionEndpointAnimator::ConnectionEndpointAnimator()
- : m_isAnimating(false)
- , m_timer(0.0f)
- , m_maxTime(0.25f)
- {
- }
- bool ConnectionComponent::ConnectionEndpointAnimator::IsAnimating() const
- {
- return m_isAnimating;
- }
- void ConnectionComponent::ConnectionEndpointAnimator::AnimateToEndpoint(const QPointF& startPoint, const Endpoint& endPoint, float maxTime)
- {
- if (m_isAnimating)
- {
- m_startPosition = m_currentPosition;
- }
- else
- {
- m_isAnimating = true;
- m_startPosition = startPoint;
- }
- m_targetEndpoint = endPoint;
- m_timer = 0.0f;
- m_maxTime = AZ::GetMax(maxTime, 0.001f);
- m_currentPosition = m_startPosition;
- }
- QPointF ConnectionComponent::ConnectionEndpointAnimator::GetAnimatedPosition() const
- {
- return m_currentPosition;
- }
- bool ConnectionComponent::ConnectionEndpointAnimator::Tick(float deltaTime)
- {
- m_timer += deltaTime;
- QPointF targetPosition;
- SlotUIRequestBus::EventResult(targetPosition, m_targetEndpoint.m_slotId, &SlotUIRequests::GetConnectionPoint);
- if (m_timer >= m_maxTime)
- {
- m_isAnimating = false;
- m_currentPosition = targetPosition;
- }
- else
- {
- float lerpPercent = (m_timer / m_maxTime);
- m_currentPosition.setX(AZ::Lerp(static_cast<float>(m_startPosition.x()), static_cast<float>(targetPosition.x()), lerpPercent));
- m_currentPosition.setY(AZ::Lerp(static_cast<float>(m_startPosition.y()), static_cast<float>(targetPosition.y()), lerpPercent));
- }
- return m_isAnimating;
- }
- ////////////////////////
- // ConnectionComponent
- ////////////////////////
- void ConnectionComponent::Reflect(AZ::ReflectContext* context)
- {
- Endpoint::Reflect(context);
- AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
- if (!serializeContext)
- {
- return;
- }
- serializeContext->Class<ConnectionComponent, AZ::Component>()
- ->Version(3)
- ->Field("Source", &ConnectionComponent::m_sourceEndpoint)
- ->Field("Target", &ConnectionComponent::m_targetEndpoint)
- ->Field("Tooltip", &ConnectionComponent::m_tooltip)
- ->Field("UserData", &ConnectionComponent::m_userData)
- ;
- AZ::EditContext* editContext = serializeContext->GetEditContext();
- if (!editContext)
- {
- return;
- }
- editContext->Class<ConnectionComponent>("Position", "The connection's position in the scene")
- ->ClassElement(AZ::Edit::ClassElements::EditorData, "Connection's class attributes")
- ->DataElement(AZ::Edit::UIHandlers::Default, &ConnectionComponent::m_tooltip, "Tooltip", "The connection's tooltip")
- ;
- }
- AZ::Entity* ConnectionComponent::CreateBaseConnectionEntity(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint, bool createModelConnection, const AZStd::string& selectorClass)
- {
- // Create this Connection's entity.
- AZ::Entity* entity = aznew AZ::Entity("Connection");
- entity->CreateComponent<ConnectionComponent>(sourceEndpoint, targetEndpoint, createModelConnection);
- entity->CreateComponent<StylingComponent>(Styling::Elements::Connection, AZ::EntityId(), selectorClass);
- entity->CreateComponent<ConnectionLayerControllerComponent>();
- return entity;
- }
- AZ::Entity* ConnectionComponent::CreateGeneralConnection(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint, bool createModelConnection, const AZStd::string& substyle)
- {
- AZ::Entity* entity = CreateBaseConnectionEntity(sourceEndpoint, targetEndpoint, createModelConnection, substyle);
- entity->CreateComponent<ConnectionVisualComponent>();
- return entity;
- }
- ConnectionComponent::ConnectionComponent()
- : m_dragContext(DragContext::Unknown)
- {
- }
- ConnectionComponent::ConnectionComponent(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint, bool createModelConnection)
- : AZ::Component()
- {
- m_sourceEndpoint = sourceEndpoint;
- m_targetEndpoint = targetEndpoint;
- AZ_Warning("GraphCanvas", m_targetEndpoint.IsValid() || m_sourceEndpoint.IsValid(), "Either source or target endpoint must be valid when creating a connection.");
- if (createModelConnection && m_sourceEndpoint.IsValid() && m_targetEndpoint.IsValid())
- {
- m_dragContext = DragContext::TryConnection;
- }
- else
- {
- m_dragContext = DragContext::Unknown;
- }
- }
- void ConnectionComponent::Activate()
- {
- ConnectionRequestBus::Handler::BusConnect(GetEntityId());
- SceneMemberRequestBus::Handler::BusConnect(GetEntityId());
-
- if (m_sourceEndpoint.IsValid() && m_targetEndpoint.IsValid() && m_dragContext != DragContext::TryConnection)
- {
- m_dragContext = DragContext::Connected;
- }
- StateController<RootGraphicsItemDisplayState>* displayStateController = nullptr;
- RootGraphicsItemRequestBus::EventResult(displayStateController, GetEntityId(), &RootGraphicsItemRequests::GetDisplayStateStateController);
- m_connectionStateStateSetter.AddStateController(displayStateController);
- }
- void ConnectionComponent::Deactivate()
- {
- StopMove();
- SceneMemberRequestBus::Handler::BusDisconnect();
- ConnectionRequestBus::Handler::BusDisconnect();
- CleanupToast();
- }
- void ConnectionComponent::OnSlotRemovedFromNode(const AZ::EntityId& slotId)
- {
- if (m_dragContext != DragContext::Connected)
- {
- if (slotId == m_sourceEndpoint.GetSlotId()
- || slotId == m_targetEndpoint.GetSlotId())
- {
- OnEscape();
- }
- }
- }
- AZ::EntityId ConnectionComponent::GetSourceSlotId() const
- {
- return m_sourceEndpoint.GetSlotId();
- }
- AZ::EntityId ConnectionComponent::GetSourceNodeId() const
- {
- return m_sourceEndpoint.GetNodeId();
- }
- Endpoint ConnectionComponent::GetSourceEndpoint() const
- {
- return m_sourceEndpoint;
- }
- QPointF ConnectionComponent::GetSourcePosition() const
- {
- if (m_sourceAnimator.IsAnimating())
- {
- return m_sourceAnimator.GetAnimatedPosition();
- }
- else if (m_sourceEndpoint.IsValid())
- {
- QPointF connectionPoint;
- SlotUIRequestBus::EventResult(connectionPoint, m_sourceEndpoint.m_slotId, &SlotUIRequests::GetConnectionPoint);
- return connectionPoint;
- }
- else
- {
- return m_mousePoint;
- }
- }
- void ConnectionComponent::StartSourceMove()
- {
- SlotRequestBus::Event(GetSourceEndpoint().GetSlotId(), &SlotRequests::RemoveConnectionId, GetEntityId(), GetTargetEndpoint());
- m_previousEndPoint = m_sourceEndpoint;
- m_sourceEndpoint = Endpoint();
- m_dragContext = DragContext::MoveSource;
- StartMove();
- }
- void ConnectionComponent::SnapSourceDisplayTo(const Endpoint& sourceEndpoint)
- {
- if (!sourceEndpoint.IsValid())
- {
- AZ_Error("GraphCanvas", false, "Trying to display a connection to an unknown source Endpoint");
- return;
- }
- bool canDisplaySource = false;
- SlotRequestBus::EventResult(canDisplaySource, m_targetEndpoint.GetSlotId(), &SlotRequests::CanDisplayConnectionTo, sourceEndpoint);
- if (!canDisplaySource)
- {
- return;
- }
- if (m_sourceEndpoint.IsValid())
- {
- SlotRequestBus::Event(m_sourceEndpoint.GetSlotId(), &SlotRequests::RemoveConnectionId, GetEntityId(), m_targetEndpoint);
- }
- Endpoint oldEndpoint = m_sourceEndpoint;
- m_sourceEndpoint = sourceEndpoint;
- ConnectionNotificationBus::Event(GetEntityId(), &ConnectionNotifications::OnSourceSlotIdChanged, oldEndpoint.GetSlotId(), m_sourceEndpoint.GetSlotId());
- SlotRequestBus::Event(m_sourceEndpoint.GetSlotId(), &SlotRequests::AddConnectionId, GetEntityId(), m_targetEndpoint);
- }
- void ConnectionComponent::AnimateSourceDisplayTo(const Endpoint& sourceEndpoint, float connectionTime)
- {
- QPointF startPosition = GetSourcePosition();
- SnapSourceDisplayTo(sourceEndpoint);
- m_sourceAnimator.AnimateToEndpoint(startPosition, sourceEndpoint, connectionTime);
-
- if (!AZ::TickBus::Handler::BusIsConnected())
- {
- AZ::TickBus::Handler::BusConnect();
- }
- }
- AZ::EntityId ConnectionComponent::GetTargetSlotId() const
- {
- return m_targetEndpoint.GetSlotId();
- }
- AZ::EntityId ConnectionComponent::GetTargetNodeId() const
- {
- return m_targetEndpoint.GetNodeId();
- }
- Endpoint ConnectionComponent::GetTargetEndpoint() const
- {
- return m_targetEndpoint;
- }
- QPointF ConnectionComponent::GetTargetPosition() const
- {
- if (m_targetAnimator.IsAnimating())
- {
- return m_targetAnimator.GetAnimatedPosition();
- }
- else if (m_targetEndpoint.IsValid())
- {
- QPointF connectionPoint;
- SlotUIRequestBus::EventResult(connectionPoint, m_targetEndpoint.m_slotId, &SlotUIRequests::GetConnectionPoint);
- return connectionPoint;
- }
- else
- {
- return m_mousePoint;
- }
- }
- void ConnectionComponent::StartTargetMove()
- {
- SlotRequestBus::Event(GetTargetEndpoint().GetSlotId(), &SlotRequests::RemoveConnectionId, GetEntityId(), GetSourceEndpoint());
- m_previousEndPoint = m_targetEndpoint;
- m_targetEndpoint = Endpoint();
- m_dragContext = DragContext::MoveTarget;
- StartMove();
- }
- void ConnectionComponent::SnapTargetDisplayTo(const Endpoint& targetEndpoint)
- {
- if (!targetEndpoint.IsValid())
- {
- AZ_Error("GraphCanvas", false, "Trying to display a connection to an unknown source Endpoint");
- return;
- }
- bool canDisplayTarget = false;
- SlotRequestBus::EventResult(canDisplayTarget, m_sourceEndpoint.GetSlotId(), &SlotRequests::CanDisplayConnectionTo, targetEndpoint);
- if (!canDisplayTarget)
- {
- return;
- }
- if (m_targetEndpoint.IsValid())
- {
- SlotRequestBus::Event(m_targetEndpoint.GetSlotId(), &SlotRequests::RemoveConnectionId, GetEntityId(), m_sourceEndpoint);
- }
- Endpoint oldTarget = m_targetEndpoint;
- m_targetEndpoint = targetEndpoint;
- ConnectionNotificationBus::Event(GetEntityId(), &ConnectionNotifications::OnTargetSlotIdChanged, oldTarget.GetSlotId(), m_targetEndpoint.GetSlotId());
- SlotRequestBus::Event(m_targetEndpoint.GetSlotId(), &SlotRequests::AddConnectionId, GetEntityId(), m_sourceEndpoint);
- }
- void ConnectionComponent::AnimateTargetDisplayTo(const Endpoint& targetEndpoint, float connectionTime)
- {
- QPointF startPosition = GetTargetPosition();
- SnapTargetDisplayTo(targetEndpoint);
- m_targetAnimator.AnimateToEndpoint(startPosition, targetEndpoint, connectionTime);
- if (!AZ::TickBus::Handler::BusIsConnected())
- {
- AZ::TickBus::Handler::BusConnect();
- }
- }
- bool ConnectionComponent::ContainsEndpoint(const Endpoint& endpoint) const
- {
- bool containsEndpoint = false;
- if (m_sourceEndpoint == endpoint)
- {
- containsEndpoint = (m_dragContext != DragContext::MoveSource);
- }
- else if (m_targetEndpoint == endpoint)
- {
- containsEndpoint = (m_dragContext != DragContext::MoveTarget);
- }
- return containsEndpoint;
- }
- void ConnectionComponent::ChainProposalCreation(const QPointF& scenePos, const QPoint& screenPos, AZ::EntityId groupTarget)
- {
- UpdateMovePosition(scenePos);
- SetGroupTarget(groupTarget);
- const bool chainAddition = true;
- FinalizeMove(scenePos, screenPos, chainAddition);
- }
- void ConnectionComponent::OnEscape()
- {
- StopMove();
- bool keepConnection = OnConnectionMoveCancelled();
- if (!keepConnection)
- {
- AZStd::unordered_set<AZ::EntityId> deletion;
- deletion.insert(GetEntityId());
- SceneRequestBus::Event(m_graphId, &SceneRequests::Delete, deletion);
- }
- }
- void ConnectionComponent::SetScene(const GraphId& graphId)
- {
- CleanupToast();
- m_graphId = graphId;
- if (!m_sourceEndpoint.IsValid())
- {
- StartSourceMove();
- }
- else if (!m_targetEndpoint.IsValid())
- {
- StartTargetMove();
- }
- else if (m_dragContext == DragContext::TryConnection)
- {
- OnConnectionMoveComplete(QPointF(), QPoint(), AZ::EntityId());
- }
- SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnSceneSet, m_graphId);
- }
- void ConnectionComponent::ClearScene(const AZ::EntityId& /*oldSceneId*/)
- {
- AZ_Warning("Graph Canvas", m_graphId.IsValid(), "This connection (ID: %s) is not in a scene (ID: %s)!", GetEntityId().ToString().data(), m_graphId.ToString().data());
- AZ_Warning("Graph Canvas", GetEntityId().IsValid(), "This connection (ID: %s) doesn't have an Entity!", GetEntityId().ToString().data());
- if (!m_graphId.IsValid() || !GetEntityId().IsValid())
- {
- return;
- }
- SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnRemovedFromScene, m_graphId);
- m_graphId.SetInvalid();
- }
- void ConnectionComponent::SignalMemberSetupComplete()
- {
- SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnMemberSetupComplete);
- }
- AZ::EntityId ConnectionComponent::GetScene() const
- {
- return m_graphId;
- }
- AZStd::string ConnectionComponent::GetTooltip() const
- {
- return m_tooltip;
- }
- void ConnectionComponent::SetTooltip(const AZStd::string& tooltip)
- {
- m_tooltip = tooltip;
- }
- AZStd::any* ConnectionComponent::GetUserData()
- {
- return &m_userData;
- }
- void ConnectionComponent::OnTick(float deltaTime, AZ::ScriptTimePoint)
- {
- bool sourceAnimating = m_sourceAnimator.IsAnimating() && m_sourceAnimator.Tick(deltaTime);
- bool targetAnimating = m_targetAnimator.IsAnimating() && m_targetAnimator.Tick(deltaTime);
- ConnectionUIRequestBus::Event(GetEntityId(), &ConnectionUIRequests::UpdateConnectionPath);
- if (!sourceAnimating && !targetAnimating)
- {
- AZ::TickBus::Handler::BusDisconnect();
- }
- }
- void ConnectionComponent::OnFocusLost()
- {
- OnEscape();
- }
- void ConnectionComponent::OnNodeIsBeingEdited(bool isBeingEdited)
- {
- if (isBeingEdited)
- {
- OnEscape();
- }
- }
- void ConnectionComponent::SetGroupTarget(AZ::EntityId groupTarget)
- {
- if (groupTarget != m_groupTarget)
- {
- m_groupTarget = groupTarget;
- if (m_groupTarget.IsValid())
- {
- StateController<RootGraphicsItemDisplayState>* displayStateController = nullptr;
- RootGraphicsItemRequestBus::EventResult(displayStateController, m_groupTarget, &RootGraphicsItemRequests::GetDisplayStateStateController);
- m_forcedGroupDisplayStateStateSetter.AddStateController(displayStateController);
- m_forcedGroupDisplayStateStateSetter.SetState(RootGraphicsItemDisplayState::Inspection);
- StateController<AZStd::string>* layerStateController = nullptr;
- LayerControllerRequestBus::EventResult(layerStateController, m_groupTarget, &LayerControllerRequests::GetLayerModifierController);
- m_forcedLayerStateSetter.AddStateController(layerStateController);
- m_forcedLayerStateSetter.SetState("dropTarget");
- }
- else
- {
- m_forcedGroupDisplayStateStateSetter.ResetStateSetter();
- m_forcedLayerStateSetter.ResetStateSetter();
- }
- }
- }
- void ConnectionComponent::FinalizeMove()
- {
- DragContext dragContext = m_dragContext;
- m_dragContext = DragContext::Connected;
- if (dragContext == DragContext::MoveSource)
- {
- ConnectionNotificationBus::Event(GetEntityId(), &ConnectionNotifications::OnSourceSlotIdChanged, m_previousEndPoint.GetSlotId(), m_sourceEndpoint.GetSlotId());
- SlotRequestBus::Event(GetSourceEndpoint().GetSlotId(), &SlotRequests::AddConnectionId, GetEntityId(), GetTargetEndpoint());
- }
- else
- {
- ConnectionNotificationBus::Event(GetEntityId(), &ConnectionNotifications::OnTargetSlotIdChanged, m_previousEndPoint.GetSlotId(), m_targetEndpoint.GetSlotId());
- SlotRequestBus::Event(GetTargetEndpoint().GetSlotId(), &SlotRequests::AddConnectionId, GetEntityId(), GetSourceEndpoint());
- }
- const bool isValidConnection = true;
- ConnectionNotificationBus::Event(GetEntityId(), &ConnectionNotifications::OnMoveFinalized, isValidConnection);
- }
- void ConnectionComponent::OnConnectionMoveStart()
- {
- SceneRequestBus::Event(m_graphId, &SceneRequests::SignalConnectionDragBegin);
- ConnectionNotificationBus::Event(GetEntityId(), &ConnectionNotifications::OnMoveBegin);
- GraphModelRequestBus::Event(m_graphId, &GraphModelRequests::DisconnectConnection, GetEntityId());
- if (m_dragContext == DragContext::MoveSource)
- {
- NodeRequestBus::Event(GetTargetNodeId(), &NodeRequests::SignalConnectionMoveBegin, GetEntityId());
- }
- else if (m_dragContext == DragContext::MoveTarget)
- {
- NodeRequestBus::Event(GetSourceNodeId(), &NodeRequests::SignalConnectionMoveBegin, GetEntityId());
- }
- }
- bool ConnectionComponent::OnConnectionMoveCancelled()
- {
- bool keepConnection = false;
- if (m_previousEndPoint.IsValid())
- {
- if (m_dragContext == DragContext::MoveSource)
- {
- m_sourceEndpoint = m_previousEndPoint;
- }
- else
- {
- m_targetEndpoint = m_previousEndPoint;
- }
- bool acceptConnection = GraphUtils::CreateModelConnection(m_graphId, GetEntityId(), m_sourceEndpoint, m_targetEndpoint);
- AZ_Error("GraphCanvas", acceptConnection, "Cancelled a move, and was unable to reconnect to the previous connection.");
- if (acceptConnection)
- {
- keepConnection = true;
- FinalizeMove();
- }
- }
- if (!keepConnection)
- {
- const bool isValidConnection = false;
- ConnectionNotificationBus::Event(GetEntityId(), &ConnectionNotifications::OnMoveFinalized, isValidConnection);
- }
- return keepConnection;
- }
- ConnectionComponent::ConnectionMoveResult ConnectionComponent::OnConnectionMoveComplete(const QPointF& scenePos, const QPoint& screenPos, AZ::EntityId groupTarget)
- {
- ConnectionMoveResult connectionResult = ConnectionMoveResult::DeleteConnection;
- bool acceptConnection = GraphUtils::CreateModelConnection(m_graphId, GetEntityId(), m_sourceEndpoint, m_targetEndpoint);
- if (acceptConnection)
- {
- connectionResult = ConnectionMoveResult::ConnectionMove;
- }
- else if (!acceptConnection && !m_previousEndPoint.IsValid() && m_dragContext != DragContext::TryConnection && AllowNodeCreation())
- {
- Endpoint knownEndpoint = m_sourceEndpoint;
- if (!knownEndpoint.IsValid())
- {
- knownEndpoint = m_targetEndpoint;
- }
- GraphCanvas::Endpoint otherEndpoint;
- EditorId editorId;
- SceneRequestBus::EventResult(editorId, m_graphId, &SceneRequests::GetEditorId);
- AssetEditorRequestBus::EventResult(otherEndpoint, editorId, &AssetEditorRequests::CreateNodeForProposalWithGroup, GetEntityId(), knownEndpoint, scenePos, screenPos, groupTarget);
- if (otherEndpoint.IsValid())
- {
- if (!m_sourceEndpoint.IsValid())
- {
- m_sourceEndpoint = otherEndpoint;
- }
- else if (!m_targetEndpoint.IsValid())
- {
- m_targetEndpoint = otherEndpoint;
- }
- acceptConnection = GraphUtils::CreateModelConnection(m_graphId, GetEntityId(), m_sourceEndpoint, m_targetEndpoint);
- if (acceptConnection)
- {
- connectionResult = ConnectionMoveResult::NodeCreation;
- }
- }
- }
- return connectionResult;
- }
- bool ConnectionComponent::AllowNodeCreation() const
- {
- return true;
- }
- void ConnectionComponent::CleanupToast()
- {
- if (m_toastId.IsValid())
- {
- ViewId viewId;
- SceneRequestBus::EventResult(viewId, m_graphId, &SceneRequests::GetViewId);
- auto viewHandler = ViewRequestBus::FindFirstHandler(viewId);
- if (viewHandler == nullptr)
- {
- return;
- }
-
- viewHandler->HideToastNotification(m_toastId);
- m_toastId.SetInvalid();
- }
- }
- void ConnectionComponent::StartMove()
- {
- QGraphicsItem* connectionGraphicsItem = nullptr;
- SceneMemberUIRequestBus::EventResult(connectionGraphicsItem, GetEntityId(), &SceneMemberUIRequests::GetRootGraphicsItem);
- if (connectionGraphicsItem)
- {
- connectionGraphicsItem->setSelected(false);
- connectionGraphicsItem->setOpacity(0.5f);
- m_eventFilter = aznew ConnectionEventFilter((*this));
- ViewId viewId;
- SceneRequestBus::EventResult(viewId, m_graphId, &SceneRequests::GetViewId);
- ViewNotificationBus::Handler::BusConnect(viewId);
- QGraphicsScene* graphicsScene = nullptr;
- SceneRequestBus::EventResult(graphicsScene, m_graphId, &SceneRequests::AsQGraphicsScene);
- if (graphicsScene)
- {
- graphicsScene->addItem(m_eventFilter);
- if (!graphicsScene->views().empty())
- {
- QGraphicsView* view = graphicsScene->views().front();
- m_mousePoint = view->mapToScene(view->mapFromGlobal(QCursor::pos()));
- }
- }
- connectionGraphicsItem->installSceneEventFilter(m_eventFilter);
- connectionGraphicsItem->grabMouse();
- SceneNotificationBus::Handler::BusConnect(m_graphId);
- StyledEntityRequestBus::Event(GetEntityId(), &StyledEntityRequests::AddSelectorState, Styling::States::Dragging);
- AZ::EntityId nodeId;
- StateController<RootGraphicsItemDisplayState>* stateController = nullptr;
- if (m_dragContext == DragContext::MoveSource)
- {
- nodeId = GetTargetEndpoint().GetNodeId();
- }
- else
- {
- nodeId = GetSourceEndpoint().GetNodeId();
- }
- RootGraphicsItemRequestBus::EventResult(stateController, nodeId, &RootGraphicsItemRequests::GetDisplayStateStateController);
- m_nodeDisplayStateStateSetter.AddStateController(stateController);
- m_nodeDisplayStateStateSetter.SetState(RootGraphicsItemDisplayState::Inspection);
- ConnectionUIRequestBus::Event(GetEntityId(), &ConnectionUIRequests::SetAltDeletionEnabled, false);
- NodeNotificationBus::Handler::BusConnect(nodeId);
- OnConnectionMoveStart();
- }
- }
- void ConnectionComponent::StopMove()
- {
- QGraphicsItem* connectionGraphicsItem = nullptr;
- SceneMemberUIRequestBus::EventResult(connectionGraphicsItem, GetEntityId(), &SceneMemberUIRequests::GetRootGraphicsItem);
- if (connectionGraphicsItem)
- {
- connectionGraphicsItem->removeSceneEventFilter(m_eventFilter);
- delete m_eventFilter;
- m_eventFilter = nullptr;
-
- connectionGraphicsItem->setOpacity(1.0f);
- connectionGraphicsItem->ungrabMouse();
- StyledEntityRequestBus::Event(GetEntityId(), &StyledEntityRequests::RemoveSelectorState, Styling::States::Dragging);
- }
- SceneNotificationBus::Handler::BusDisconnect();;
- NodeNotificationBus::Handler::BusDisconnect();
- ViewNotificationBus::Handler::BusDisconnect();
- if (m_dragContext == DragContext::MoveSource)
- {
- SlotRequestBus::Event(GetSourceEndpoint().GetSlotId(), &SlotRequests::RemoveProposedConnection, GetEntityId(), GetTargetEndpoint());
- StyledEntityRequestBus::Event(GetSourceEndpoint().GetSlotId(), &StyledEntityRequests::RemoveSelectorState, Styling::States::ValidDrop);
- }
- else
- {
- SlotRequestBus::Event(GetTargetEndpoint().GetSlotId(), &SlotRequests::RemoveProposedConnection, GetEntityId(), GetSourceEndpoint());
- StyledEntityRequestBus::Event(GetTargetEndpoint().GetSlotId(), &StyledEntityRequests::RemoveSelectorState, Styling::States::ValidDrop);
- }
- m_nodeDisplayStateStateSetter.ResetStateSetter();
- SceneRequestBus::Event(m_graphId, &SceneRequests::SignalConnectionDragEnd);
- ConnectionUIRequestBus::Event(GetEntityId(), &ConnectionUIRequests::SetAltDeletionEnabled, true);
- SetGroupTarget(AZ::EntityId());
- }
- bool ConnectionComponent::UpdateProposal(Endpoint& activePoint, const Endpoint& proposalPoint, AZStd::function< void(const AZ::EntityId&, const AZ::EntityId&)> endpointChangedFunctor)
- {
- bool retVal = false;
- if (activePoint != proposalPoint)
- {
- retVal = true;
- QGraphicsItem* connectionGraphicsItem = nullptr;
- SceneMemberUIRequestBus::EventResult(connectionGraphicsItem, GetEntityId(), &SceneMemberUIRequests::GetRootGraphicsItem);
- if (activePoint.IsValid())
- {
- StateController<RootGraphicsItemDisplayState>* stateController = nullptr;
- RootGraphicsItemRequestBus::EventResult(stateController, activePoint.GetNodeId(), &RootGraphicsItemRequests::GetDisplayStateStateController);
- m_nodeDisplayStateStateSetter.RemoveStateController(stateController);
- StyledEntityRequestBus::Event(activePoint.m_slotId, &StyledEntityRequests::RemoveSelectorState, Styling::States::ValidDrop);
- if (connectionGraphicsItem)
- {
- connectionGraphicsItem->setOpacity(0.5f);
- }
- }
- AZ::EntityId oldId = activePoint.GetSlotId();
- activePoint = proposalPoint;
- endpointChangedFunctor(oldId, activePoint.GetSlotId());
- if (activePoint.IsValid())
- {
- StateController<RootGraphicsItemDisplayState>* stateController = nullptr;
- RootGraphicsItemRequestBus::EventResult(stateController, activePoint.GetNodeId(), &RootGraphicsItemRequests::GetDisplayStateStateController);
- m_nodeDisplayStateStateSetter.AddStateController(stateController);
- StyledEntityRequestBus::Event(activePoint.m_slotId, &StyledEntityRequests::AddSelectorState, Styling::States::ValidDrop);
- if (connectionGraphicsItem)
- {
- connectionGraphicsItem->setOpacity(1.0f);
- }
- }
- }
- return retVal || !activePoint.IsValid();
- }
- ConnectionComponent::ConnectionCandidate ConnectionComponent::FindConnectionCandidateAt(const QPointF& scenePos) const
- {
- Endpoint knownEndpoint = m_targetEndpoint;
- if (m_dragContext == DragContext::MoveTarget)
- {
- knownEndpoint = m_sourceEndpoint;
- }
- EditorId editorId;
- SceneRequestBus::EventResult(editorId, m_graphId, &SceneRequests::GetEditorId);
- double snapDist = 10.0;
- AssetEditorSettingsRequestBus::EventResult(snapDist, editorId, &AssetEditorSettingsRequests::GetSnapDistance);
- QPointF dist(snapDist, snapDist);
- QRectF rect(scenePos - dist, scenePos + dist);
- // These are returnned sorted. So we just need to return the first match we find.
- AZStd::vector<Endpoint> endpoints;
- SceneRequestBus::EventResult(endpoints, m_graphId, &SceneRequests::GetEndpointsInRect, rect);
- ConnectionCandidate candidate;
- for (Endpoint endpoint : endpoints)
- {
- // Skip over ourselves.
- if (endpoint == knownEndpoint)
- {
- continue;
- }
- if (!GraphUtils::IsSlotVisible(endpoint.GetSlotId()))
- {
- continue;
- }
- // For our tool tips we really only want to focus in on the first element
- if (!candidate.m_testedTarget.IsValid())
- {
- candidate.m_testedTarget = endpoint;
- }
- bool canCreateConnection = false;
- if (m_dragContext == DragContext::MoveSource && endpoint == m_sourceEndpoint)
- {
- canCreateConnection = true;
- }
- else if (m_dragContext == DragContext::MoveTarget && endpoint == m_targetEndpoint)
- {
- canCreateConnection = true;
- }
- else if (m_dragContext == DragContext::MoveTarget && endpoint == m_sourceEndpoint
- || m_dragContext == DragContext::MoveSource && endpoint == m_targetEndpoint)
- {
- continue;
- }
- else
- {
- // If we are checking against an extender slot. We need to go through special flow.
- // Since the extender will create a new slot for us to connect to.
- if (auto extenderHandler = ExtenderSlotRequestBus::FindFirstHandler(endpoint.GetSlotId()))
- {
- Endpoint newConnectionEndpoint = extenderHandler->ExtendForConnectionProposal(GetEntityId(), knownEndpoint);
- if (newConnectionEndpoint.IsValid())
- {
- canCreateConnection = true;
- endpoint = newConnectionEndpoint;
- }
- }
- else
- {
- SlotRequestBus::EventResult(canCreateConnection, endpoint.GetSlotId(), &SlotRequests::CanCreateConnectionTo, knownEndpoint);
- }
- }
- if (canCreateConnection)
- {
- candidate.m_connectableTarget = endpoint;
- break;
- }
- }
- return candidate;
- }
- void ConnectionComponent::UpdateMovePosition(const QPointF& position)
- {
- if (m_dragContext == DragContext::MoveSource
- || m_dragContext == DragContext::MoveTarget)
- {
- m_mousePoint = position;
- ConnectionCandidate connectionCandidate = FindConnectionCandidateAt(m_mousePoint);
- bool updateConnection = false;
- if (m_dragContext == DragContext::MoveSource)
- {
- AZStd::function<void(const AZ::EntityId&, const AZ::EntityId)> updateFunction = [this](const AZ::EntityId& oldId, const AZ::EntityId& newId)
- {
- SlotRequestBus::Event(oldId, &SlotRequests::RemoveProposedConnection, this->GetEntityId(), this->GetTargetEndpoint());
- SlotRequestBus::Event(newId, &SlotRequests::DisplayProposedConnection, this->GetEntityId(), this->GetTargetEndpoint());
- ConnectionNotificationBus::Event(this->GetEntityId(), &ConnectionNotifications::OnSourceSlotIdChanged, oldId, newId);
- };
- updateConnection = UpdateProposal(m_sourceEndpoint, connectionCandidate.m_connectableTarget, updateFunction);
- }
- else
- {
- AZStd::function<void(const AZ::EntityId&, const AZ::EntityId)> updateFunction = [this](const AZ::EntityId& oldId, const AZ::EntityId& newId)
- {
- SlotRequestBus::Event(oldId, &SlotRequests::RemoveProposedConnection, this->GetEntityId(), this->GetSourceEndpoint());
- SlotRequestBus::Event(newId, &SlotRequests::DisplayProposedConnection, this->GetEntityId(), this->GetSourceEndpoint());
- ConnectionNotificationBus::Event(this->GetEntityId(), &ConnectionNotifications::OnTargetSlotIdChanged, oldId, newId);
- };
- updateConnection = UpdateProposal(m_targetEndpoint, connectionCandidate.m_connectableTarget, updateFunction);
- }
- if (connectionCandidate.m_connectableTarget.IsValid())
- {
- Endpoint invalidEndpoint;
- DisplayConnectionToolTip(position, invalidEndpoint);
- // If we have a valid target. We want to not manage our group target.
- SetGroupTarget(AZ::EntityId());
- }
- else
- {
- DisplayConnectionToolTip(position, connectionCandidate.m_testedTarget);
-
- AZ::EntityId groupTarget;
- SceneRequestBus::EventResult(groupTarget, GetScene(), &SceneRequests::FindTopmostGroupAtPoint, m_mousePoint);
- SetGroupTarget(groupTarget);
- }
- if (updateConnection)
- {
- ConnectionUIRequestBus::Event(GetEntityId(), &ConnectionUIRequests::UpdateConnectionPath);
- }
- }
- }
- void ConnectionComponent::FinalizeMove(const QPointF& scenePos, const QPoint& screenPos, bool chainAddition)
- {
- if (m_dragContext == DragContext::Connected)
- {
- AZ_Error("Graph Canvas", false, "Receiving MouseRelease event in invalid drag state.");
- return;
- }
- DisplayConnectionToolTip(scenePos, Endpoint());
- DragContext chainContext = m_dragContext;
- AZ::EntityId groupTarget = m_groupTarget;
- StopMove();
- // Have to copy the GraphId here because deletion of the Entity this component is attached to deletes this component.
- GraphId graphId = m_graphId;
- ConnectionMoveResult connectionResult = OnConnectionMoveComplete(scenePos, screenPos, groupTarget);
- if (connectionResult == ConnectionMoveResult::DeleteConnection)
- {
- // If the previous endpoint is not valid, this implies a new connection is being created
- bool preventUndoState = !m_previousEndPoint.IsValid();
- if (preventUndoState)
- {
- GraphModelRequestBus::Event(graphId, &GraphModelRequests::RequestPushPreventUndoStateUpdate);
- }
- AZ::EntityId connectionId = GetEntityId();
- // OnMoveFinalized might end up deleting the connection if it was from an ExtenderSlot, so no member methods should be called after either of these methods.
- //
- // The SceneRequests::Delete will delete the Entity this component is attached.
- // Therefore it is invalid to access the members of this component after the call.
- const bool isValidConnection = false;
- ConnectionNotificationBus::Event(connectionId, &ConnectionNotifications::OnMoveFinalized, isValidConnection);
- AZStd::unordered_set<AZ::EntityId> deletion;
- deletion.insert(connectionId);
-
- SceneRequestBus::Event(graphId, &SceneRequests::Delete, deletion);
- if (preventUndoState)
- {
- GraphModelRequestBus::Event(graphId, &GraphModelRequests::RequestPopPreventUndoStateUpdate);
- }
- }
- else
- {
- FinalizeMove();
- GraphModelRequestBus::Event(graphId, &GraphModelRequests::RequestUndoPoint);
- if (chainAddition && connectionResult == ConnectionMoveResult::NodeCreation)
- {
- AZ::EntityId graphId2;
- SceneMemberRequestBus::EventResult(graphId2, GetEntityId(), &SceneMemberRequests::GetScene);
- AZ::EntityId nodeId;
- SlotType slotType = SlotTypes::Invalid;
- ConnectionType connectionType = CT_Invalid;
- if (chainContext == DragContext::MoveSource)
- {
- nodeId = GetSourceNodeId();
- slotType = SlotTypes::ExecutionSlot;
- connectionType = CT_Input;
- }
- else if (chainContext == DragContext::MoveTarget)
- {
- nodeId = GetTargetNodeId();
- slotType = SlotTypes::ExecutionSlot;
- connectionType = CT_Output;
- }
- SceneRequestBus::Event(graphId2, &SceneRequests::HandleProposalDaisyChainWithGroup, nodeId, slotType, connectionType, screenPos, scenePos, groupTarget);
- }
- }
- }
- void ConnectionComponent::DisplayConnectionToolTip(const QPointF& /*scenePoint*/, const Endpoint& connectionTarget)
- {
- if (m_endpointTooltip != connectionTarget)
- {
- GraphId graphId;
- SceneMemberRequestBus::EventResult(graphId, GetEntityId(), &SceneMemberRequests::GetScene);
- ViewId viewId;
- SceneRequestBus::EventResult(viewId, graphId, &SceneRequests::GetViewId);
- auto viewHandler = ViewRequestBus::FindFirstHandler(viewId);
- if (viewHandler == nullptr)
- {
- return;
- }
- CleanupToast();
- m_endpointTooltip = connectionTarget;
- // No endpoint I'm going to treat like a valid connection
- m_validationResult = ConnectionValidationTooltip();
- m_validationResult.m_isValid = true;
- // If our tooltip target is the same as both our target and source, this means we are trying to connect to the point we started from.
- // This just looks weird, so we won't do it.
- if (m_endpointTooltip.IsValid())
- {
- // If we are pointing at an extender slot. Don't investigate the reason for a failure.
- if (ExtenderSlotRequestBus::FindFirstHandler(m_endpointTooltip.GetSlotId()) != nullptr)
- {
- return;
- }
- if (m_dragContext == DragContext::MoveTarget)
- {
- if (m_sourceEndpoint != m_endpointTooltip)
- {
- m_validationResult = GraphUtils::GetModelConnnectionValidityToolTip(graphId, m_sourceEndpoint, m_endpointTooltip);
- }
- }
- else
- {
- if (m_targetEndpoint != m_endpointTooltip)
- {
- m_validationResult = GraphUtils::GetModelConnnectionValidityToolTip(graphId, m_endpointTooltip, m_targetEndpoint);
- }
- }
- }
- if (!m_validationResult.m_isValid)
- {
- EditorId editorId;
- SceneRequestBus::EventResult(editorId, graphId, &SceneRequests::GetEditorId);
- QPointF connectionPoint;
- SlotUIRequestBus::EventResult(connectionPoint, m_endpointTooltip.GetSlotId(), &SlotUIRequests::GetConnectionPoint);
-
- AZ::Vector2 globalConnectionVector = ConversionUtils::QPointToVector(connectionPoint);
- globalConnectionVector = viewHandler->MapToGlobal(globalConnectionVector);
- QPointF globalConnectionPoint = ConversionUtils::AZToQPoint(globalConnectionVector);
- QPointF anchorPoint(0.0f, 0.0f);
- AzQtComponents::ToastConfiguration toastConfiguration(AzQtComponents::ToastType::Error, "Unable to connect to slot", m_validationResult.m_failureReason.c_str());
- toastConfiguration.m_closeOnClick = false;
- m_toastId = viewHandler->ShowToastAtPoint(globalConnectionPoint.toPoint(), anchorPoint, toastConfiguration);
- }
- }
- }
- }
|