// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #pragma once #ifndef NGA_WITH_ENGINE_CPP #include "Version.h" #if (ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 22) || ENGINE_MAJOR_VERSION > 4 // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #include "StateMachineConnectionDrawingPolicy.h" #include "Rendering/DrawElements.h" #include "AnimStateNodeBase.h" #include "AnimStateTransitionNode.h" #include "AnimationStateNodes/SGraphNodeAnimTransition.h" #include "AnimStateEntryNode.h" ///////////////////////////////////////////////////// // FStateMachineConnectionDrawingPolicy FStateMachineConnectionDrawingPolicy::FStateMachineConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj) : FConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements) , GraphObj(InGraphObj) { } void FStateMachineConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*inout*/ FConnectionParams& Params) { Params.AssociatedPin1 = OutputPin; Params.AssociatedPin2 = InputPin; Params.WireThickness = 1.5f; if (InputPin) { if (UAnimStateTransitionNode* TransNode = Cast(InputPin->GetOwningNode())) { Params.WireColor = SGraphNodeAnimTransition::StaticGetTransitionColor(TransNode, HoveredPins.Contains(InputPin)); Params.bUserFlag1 = TransNode->Bidirectional; } } const bool bDeemphasizeUnhoveredPins = HoveredPins.Num() > 0; if (bDeemphasizeUnhoveredPins) { ApplyHoverDeemphasis(OutputPin, InputPin, /*inout*/ Params.WireThickness, /*inout*/ Params.WireColor); } } void FStateMachineConnectionDrawingPolicy::DetermineLinkGeometry( FArrangedChildren& ArrangedNodes, TSharedRef& OutputPinWidget, UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*out*/ FArrangedWidget*& StartWidgetGeometry, /*out*/ FArrangedWidget*& EndWidgetGeometry ) { if (UAnimStateEntryNode* EntryNode = Cast(OutputPin->GetOwningNode())) { StartWidgetGeometry = PinGeometries->Find(OutputPinWidget); UAnimStateNodeBase* State = CastChecked(InputPin->GetOwningNode()); int32 StateIndex = NodeWidgetMap.FindChecked(State); EndWidgetGeometry = &(ArrangedNodes[StateIndex]); } else if (UAnimStateTransitionNode* TransNode = Cast(InputPin->GetOwningNode())) { UAnimStateNodeBase* PrevState = TransNode->GetPreviousState(); UAnimStateNodeBase* NextState = TransNode->GetNextState(); if ((PrevState != NULL) && (NextState != NULL)) { int32* PrevNodeIndex = NodeWidgetMap.Find(PrevState); int32* NextNodeIndex = NodeWidgetMap.Find(NextState); if ((PrevNodeIndex != NULL) && (NextNodeIndex != NULL)) { StartWidgetGeometry = &(ArrangedNodes[*PrevNodeIndex]); EndWidgetGeometry = &(ArrangedNodes[*NextNodeIndex]); } } } else { StartWidgetGeometry = PinGeometries->Find(OutputPinWidget); if (TSharedPtr* pTargetWidget = PinToPinWidgetMap.Find(InputPin)) { TSharedRef InputWidget = (*pTargetWidget).ToSharedRef(); EndWidgetGeometry = PinGeometries->Find(InputWidget); } } } void FStateMachineConnectionDrawingPolicy::Draw(TMap, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) { // Build an acceleration structure to quickly find geometry for the nodes NodeWidgetMap.Empty(); for (int32 NodeIndex = 0; NodeIndex < ArrangedNodes.Num(); ++NodeIndex) { FArrangedWidget& CurWidget = ArrangedNodes[NodeIndex]; TSharedRef ChildNode = StaticCastSharedRef(CurWidget.Widget); NodeWidgetMap.Add(ChildNode->GetNodeObj(), NodeIndex); } // Now draw FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes); } void FStateMachineConnectionDrawingPolicy::DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, const FVector2D& EndPoint, UEdGraphPin* Pin) { FConnectionParams Params; DetermineWiringStyle(Pin, nullptr, /*inout*/ Params); const FVector2D SeedPoint = EndPoint; const FVector2D AdjustedStartPoint = FGeometryHelper::FindClosestPointOnGeom(PinGeometry, SeedPoint); DrawSplineWithArrow(AdjustedStartPoint, EndPoint, Params); } void FStateMachineConnectionDrawingPolicy::DrawSplineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params) { Internal_DrawLineWithArrow(StartAnchorPoint, EndAnchorPoint, Params); // Is the connection bidirectional? if (Params.bUserFlag1) { Internal_DrawLineWithArrow(EndAnchorPoint, StartAnchorPoint, Params); } } void FStateMachineConnectionDrawingPolicy::Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params) { //@TODO: Should this be scaled by zoom factor? const float LineSeparationAmount = 4.5f; const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint; const FVector2D UnitDelta = DeltaPos.GetSafeNormal(); const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal(); // Come up with the final start/end points const FVector2D DirectionBias = Normal * LineSeparationAmount; const FVector2D LengthBias = ArrowRadius.X * UnitDelta; const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias; const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias; // Draw a line/spline DrawConnection(WireLayerID, StartPoint, EndPoint, Params); // Draw the arrow const FVector2D ArrowDrawPos = EndPoint - ArrowRadius; const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X); FSlateDrawElement::MakeRotatedBox( DrawElementsList, ArrowLayerID, FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor), ArrowImage, ESlateDrawEffect::None, AngleInRadians, TOptional(), FSlateDrawElement::RelativeToElement, Params.WireColor ); } void FStateMachineConnectionDrawingPolicy::DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, const FConnectionParams& Params) { // Get a reasonable seed point (halfway between the boxes) const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom); const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom); const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f; // Find the (approximate) closest points between the two boxes const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint); const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint); DrawSplineWithArrow(StartAnchorPoint, EndAnchorPoint, Params); } FVector2D FStateMachineConnectionDrawingPolicy::ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const { const FVector2D Delta = End - Start; const FVector2D NormDelta = Delta.GetSafeNormal(); return NormDelta; } #elif (ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 17) || ENGINE_MAJOR_VERSION > 4 #include "StateMachineConnectionDrawingPolicy.h" #include "Rendering/DrawElements.h" #include "AnimStateNodeBase.h" #include "AnimStateTransitionNode.h" #include "AnimationStateNodes/SGraphNodeAnimTransition.h" #include "AnimStateEntryNode.h" ///////////////////////////////////////////////////// // FStateMachineConnectionDrawingPolicy FStateMachineConnectionDrawingPolicy::FStateMachineConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj) : FConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements) , GraphObj(InGraphObj) { } void FStateMachineConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*inout*/ FConnectionParams& Params) { Params.AssociatedPin1 = OutputPin; Params.AssociatedPin2 = InputPin; Params.WireThickness = 1.5f; if (InputPin) { if (UAnimStateTransitionNode* TransNode = Cast(InputPin->GetOwningNode())) { Params.WireColor = SGraphNodeAnimTransition::StaticGetTransitionColor(TransNode, HoveredPins.Contains(InputPin)); Params.bUserFlag1 = TransNode->Bidirectional; } } const bool bDeemphasizeUnhoveredPins = HoveredPins.Num() > 0; if (bDeemphasizeUnhoveredPins) { ApplyHoverDeemphasis(OutputPin, InputPin, /*inout*/ Params.WireThickness, /*inout*/ Params.WireColor); } } void FStateMachineConnectionDrawingPolicy::DetermineLinkGeometry( FArrangedChildren& ArrangedNodes, TSharedRef& OutputPinWidget, UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*out*/ FArrangedWidget*& StartWidgetGeometry, /*out*/ FArrangedWidget*& EndWidgetGeometry ) { if (UAnimStateEntryNode* EntryNode = Cast(OutputPin->GetOwningNode())) { StartWidgetGeometry = PinGeometries->Find(OutputPinWidget); UAnimStateNodeBase* State = CastChecked(InputPin->GetOwningNode()); int32 StateIndex = NodeWidgetMap.FindChecked(State); EndWidgetGeometry = &(ArrangedNodes[StateIndex]); } else if (UAnimStateTransitionNode* TransNode = Cast(InputPin->GetOwningNode())) { UAnimStateNodeBase* PrevState = TransNode->GetPreviousState(); UAnimStateNodeBase* NextState = TransNode->GetNextState(); if ((PrevState != NULL) && (NextState != NULL)) { int32* PrevNodeIndex = NodeWidgetMap.Find(PrevState); int32* NextNodeIndex = NodeWidgetMap.Find(NextState); if ((PrevNodeIndex != NULL) && (NextNodeIndex != NULL)) { StartWidgetGeometry = &(ArrangedNodes[*PrevNodeIndex]); EndWidgetGeometry = &(ArrangedNodes[*NextNodeIndex]); } } } else { StartWidgetGeometry = PinGeometries->Find(OutputPinWidget); if (TSharedRef* pTargetWidget = PinToPinWidgetMap.Find(InputPin)) { TSharedRef InputWidget = *pTargetWidget; EndWidgetGeometry = PinGeometries->Find(InputWidget); } } } void FStateMachineConnectionDrawingPolicy::Draw(TMap, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) { // Build an acceleration structure to quickly find geometry for the nodes NodeWidgetMap.Empty(); for (int32 NodeIndex = 0; NodeIndex < ArrangedNodes.Num(); ++NodeIndex) { FArrangedWidget& CurWidget = ArrangedNodes[NodeIndex]; TSharedRef ChildNode = StaticCastSharedRef(CurWidget.Widget); NodeWidgetMap.Add(ChildNode->GetNodeObj(), NodeIndex); } // Now draw FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes); } void FStateMachineConnectionDrawingPolicy::DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, const FVector2D& EndPoint, UEdGraphPin* Pin) { FConnectionParams Params; DetermineWiringStyle(Pin, nullptr, /*inout*/ Params); const FVector2D SeedPoint = EndPoint; const FVector2D AdjustedStartPoint = FGeometryHelper::FindClosestPointOnGeom(PinGeometry, SeedPoint); DrawSplineWithArrow(AdjustedStartPoint, EndPoint, Params); } void FStateMachineConnectionDrawingPolicy::DrawSplineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params) { Internal_DrawLineWithArrow(StartAnchorPoint, EndAnchorPoint, Params); // Is the connection bidirectional? if (Params.bUserFlag1) { Internal_DrawLineWithArrow(EndAnchorPoint, StartAnchorPoint, Params); } } void FStateMachineConnectionDrawingPolicy::Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params) { //@TODO: Should this be scaled by zoom factor? const float LineSeparationAmount = 4.5f; const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint; const FVector2D UnitDelta = DeltaPos.GetSafeNormal(); const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal(); // Come up with the final start/end points const FVector2D DirectionBias = Normal * LineSeparationAmount; const FVector2D LengthBias = ArrowRadius.X * UnitDelta; const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias; const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias; // Draw a line/spline DrawConnection(WireLayerID, StartPoint, EndPoint, Params); // Draw the arrow const FVector2D ArrowDrawPos = EndPoint - ArrowRadius; const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X); FSlateDrawElement::MakeRotatedBox( DrawElementsList, ArrowLayerID, FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor), ArrowImage, ClippingRect, ESlateDrawEffect::None, AngleInRadians, TOptional(), FSlateDrawElement::RelativeToElement, Params.WireColor ); } void FStateMachineConnectionDrawingPolicy::DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, const FConnectionParams& Params) { // Get a reasonable seed point (halfway between the boxes) const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom); const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom); const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f; // Find the (approximate) closest points between the two boxes const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint); const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint); DrawSplineWithArrow(StartAnchorPoint, EndAnchorPoint, Params); } FVector2D FStateMachineConnectionDrawingPolicy::ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const { const FVector2D Delta = End - Start; const FVector2D NormDelta = Delta.GetSafeNormal(); return NormDelta; } #else #include "StateMachineConnectionDrawingPolicy.h" #include "Rendering/DrawElements.h" #include "AnimStateNodeBase.h" #include "AnimStateTransitionNode.h" #include "AnimationStateNodes/SGraphNodeAnimTransition.h" #include "AnimStateEntryNode.h" ///////////////////////////////////////////////////// // FStateMachineConnectionDrawingPolicy FStateMachineConnectionDrawingPolicy::FStateMachineConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj) : FConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements) , GraphObj(InGraphObj) { } void FStateMachineConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*inout*/ FConnectionParams& Params) { Params.AssociatedPin1 = OutputPin; Params.AssociatedPin2 = InputPin; Params.WireThickness = 1.5f; if (InputPin) { if (UAnimStateTransitionNode* TransNode = Cast(InputPin->GetOwningNode())) { Params.WireColor = SGraphNodeAnimTransition::StaticGetTransitionColor(TransNode, HoveredPins.Contains(InputPin)); Params.bUserFlag1 = TransNode->Bidirectional; } } const bool bDeemphasizeUnhoveredPins = HoveredPins.Num() > 0; if (bDeemphasizeUnhoveredPins) { ApplyHoverDeemphasis(OutputPin, InputPin, /*inout*/ Params.WireThickness, /*inout*/ Params.WireColor); } } void FStateMachineConnectionDrawingPolicy::DetermineLinkGeometry( FArrangedChildren& ArrangedNodes, TSharedRef& OutputPinWidget, UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*out*/ FArrangedWidget*& StartWidgetGeometry, /*out*/ FArrangedWidget*& EndWidgetGeometry ) { if (UAnimStateEntryNode* EntryNode = Cast(OutputPin->GetOwningNode())) { StartWidgetGeometry = PinGeometries->Find(OutputPinWidget); UAnimStateNodeBase* State = CastChecked(InputPin->GetOwningNode()); int32 StateIndex = NodeWidgetMap.FindChecked(State); EndWidgetGeometry = &(ArrangedNodes[StateIndex]); } else if (UAnimStateTransitionNode* TransNode = Cast(InputPin->GetOwningNode())) { UAnimStateNodeBase* PrevState = TransNode->GetPreviousState(); UAnimStateNodeBase* NextState = TransNode->GetNextState(); if ((PrevState != NULL) && (NextState != NULL)) { int32* PrevNodeIndex = NodeWidgetMap.Find(PrevState); int32* NextNodeIndex = NodeWidgetMap.Find(NextState); if ((PrevNodeIndex != NULL) && (NextNodeIndex != NULL)) { StartWidgetGeometry = &(ArrangedNodes[*PrevNodeIndex]); EndWidgetGeometry = &(ArrangedNodes[*NextNodeIndex]); } } } else { StartWidgetGeometry = PinGeometries->Find(OutputPinWidget); if (TSharedRef* pTargetWidget = PinToPinWidgetMap.Find(InputPin)) { TSharedRef InputWidget = *pTargetWidget; EndWidgetGeometry = PinGeometries->Find(InputWidget); } } } void FStateMachineConnectionDrawingPolicy::Draw(TMap, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) { // Build an acceleration structure to quickly find geometry for the nodes NodeWidgetMap.Empty(); for (int32 NodeIndex = 0; NodeIndex < ArrangedNodes.Num(); ++NodeIndex) { FArrangedWidget& CurWidget = ArrangedNodes[NodeIndex]; TSharedRef ChildNode = StaticCastSharedRef(CurWidget.Widget); NodeWidgetMap.Add(ChildNode->GetNodeObj(), NodeIndex); } // Now draw FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes); } void FStateMachineConnectionDrawingPolicy::DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, const FVector2D& EndPoint, UEdGraphPin* Pin) { FConnectionParams Params; DetermineWiringStyle(Pin, nullptr, /*inout*/ Params); const FVector2D SeedPoint = EndPoint; const FVector2D AdjustedStartPoint = FGeometryHelper::FindClosestPointOnGeom(PinGeometry, SeedPoint); DrawSplineWithArrow(AdjustedStartPoint, EndPoint, Params); } void FStateMachineConnectionDrawingPolicy::DrawSplineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params) { Internal_DrawLineWithArrow(StartAnchorPoint, EndAnchorPoint, Params); // Is the connection bidirectional? if (Params.bUserFlag1) { Internal_DrawLineWithArrow(EndAnchorPoint, StartAnchorPoint, Params); } } void FStateMachineConnectionDrawingPolicy::Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params) { //@TODO: Should this be scaled by zoom factor? const float LineSeparationAmount = 4.5f; const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint; const FVector2D UnitDelta = DeltaPos.GetSafeNormal(); const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal(); // Come up with the final start/end points const FVector2D DirectionBias = Normal * LineSeparationAmount; const FVector2D LengthBias = ArrowRadius.X * UnitDelta; const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias; const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias; // Draw a line/spline DrawConnection(WireLayerID, StartPoint, EndPoint, Params); // Draw the arrow const FVector2D ArrowDrawPos = EndPoint - ArrowRadius; const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X); FSlateDrawElement::MakeRotatedBox( DrawElementsList, ArrowLayerID, FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor), ArrowImage, ESlateDrawEffect::None, AngleInRadians, TOptional(), FSlateDrawElement::RelativeToElement, Params.WireColor ); } void FStateMachineConnectionDrawingPolicy::DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, const FConnectionParams& Params) { // Get a reasonable seed point (halfway between the boxes) const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom); const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom); const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f; // Find the (approximate) closest points between the two boxes const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint); const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint); DrawSplineWithArrow(StartAnchorPoint, EndAnchorPoint, Params); } FVector2D FStateMachineConnectionDrawingPolicy::ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const { const FVector2D Delta = End - Start; const FVector2D NormDelta = Delta.GetSafeNormal(); return NormDelta; } #endif #endif