12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130 |
- /*
- * 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);
- }
- }
- }
- }
|