2014-12-07 19:09:38 -05:00
|
|
|
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
#include "GraphEditorCommon.h"
|
|
|
|
|
#include "SGraphNodeAnimState.h"
|
|
|
|
|
#include "SGraphPreviewer.h"
|
|
|
|
|
#include "Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h"
|
|
|
|
|
#include "SGraphNode.h"
|
|
|
|
|
#include "IDocumentation.h"
|
2014-04-24 08:49:31 -04:00
|
|
|
#include "AnimStateConduitNode.h"
|
|
|
|
|
#include "AnimationStateMachineGraph.h"
|
2014-04-24 14:34:01 -04:00
|
|
|
#include "AnimGraphNode_StateMachineBase.h"
|
2014-05-29 17:24:15 -04:00
|
|
|
#include "Animation/AnimNode_StateMachine.h"
|
2014-10-14 22:50:06 -04:00
|
|
|
#include "SInlineEditableTextBlock.h"
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
|
// SStateMachineOutputPin
|
|
|
|
|
|
|
|
|
|
class SStateMachineOutputPin : public SGraphPin
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SLATE_BEGIN_ARGS(SStateMachineOutputPin){}
|
|
|
|
|
SLATE_END_ARGS()
|
|
|
|
|
|
|
|
|
|
void Construct(const FArguments& InArgs, UEdGraphPin* InPin);
|
|
|
|
|
protected:
|
|
|
|
|
// Begin SGraphPin interface
|
2014-06-13 06:14:46 -04:00
|
|
|
virtual TSharedRef<SWidget> GetDefaultValueWidget() override;
|
2014-03-14 14:13:41 -04:00
|
|
|
// End SGraphPin interface
|
|
|
|
|
|
|
|
|
|
const FSlateBrush* GetPinBorder() const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void SStateMachineOutputPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin)
|
|
|
|
|
{
|
|
|
|
|
this->SetCursor( EMouseCursor::Default );
|
|
|
|
|
|
|
|
|
|
typedef SStateMachineOutputPin ThisClass;
|
|
|
|
|
|
|
|
|
|
bShowLabel = true;
|
|
|
|
|
IsEditable = true;
|
|
|
|
|
|
|
|
|
|
GraphPinObj = InPin;
|
|
|
|
|
check(GraphPinObj != NULL);
|
|
|
|
|
|
|
|
|
|
const UEdGraphSchema* Schema = GraphPinObj->GetSchema();
|
|
|
|
|
check(Schema);
|
|
|
|
|
|
|
|
|
|
// Set up a hover for pins that is tinted the color of the pin.
|
|
|
|
|
SBorder::Construct( SBorder::FArguments()
|
|
|
|
|
.BorderImage( this, &SStateMachineOutputPin::GetPinBorder )
|
|
|
|
|
.BorderBackgroundColor( this, &ThisClass::GetPinColor )
|
|
|
|
|
.OnMouseButtonDown( this, &ThisClass::OnPinMouseDown )
|
|
|
|
|
.Cursor( this, &ThisClass::GetPinCursor )
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TSharedRef<SWidget> SStateMachineOutputPin::GetDefaultValueWidget()
|
|
|
|
|
{
|
|
|
|
|
return SNew(STextBlock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FSlateBrush* SStateMachineOutputPin::GetPinBorder() const
|
|
|
|
|
{
|
|
|
|
|
return ( IsHovered() )
|
|
|
|
|
? FEditorStyle::GetBrush( TEXT("Graph.StateNode.Pin.BackgroundHovered") )
|
|
|
|
|
: FEditorStyle::GetBrush( TEXT("Graph.StateNode.Pin.Background") );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
|
// SGraphNodeAnimState
|
|
|
|
|
|
|
|
|
|
void SGraphNodeAnimState::Construct(const FArguments& InArgs, UAnimStateNodeBase* InNode)
|
|
|
|
|
{
|
|
|
|
|
this->GraphNode = InNode;
|
|
|
|
|
|
|
|
|
|
this->SetCursor(EMouseCursor::CardinalCross);
|
|
|
|
|
|
|
|
|
|
this->UpdateGraphNode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphNodeAnimState::GetStateInfoPopup(UEdGraphNode* GraphNode, TArray<FGraphInformationPopupInfo>& Popups)
|
|
|
|
|
{
|
|
|
|
|
UAnimBlueprint* AnimBlueprint = Cast<UAnimBlueprint>(FBlueprintEditorUtils::FindBlueprintForNodeChecked(GraphNode));
|
|
|
|
|
UAnimInstance* ActiveObject = (AnimBlueprint != NULL) ? Cast<UAnimInstance>(AnimBlueprint->GetObjectBeingDebugged()) : NULL;
|
|
|
|
|
UAnimBlueprintGeneratedClass* Class = AnimBlueprint->GetAnimBlueprintGeneratedClass();
|
|
|
|
|
|
|
|
|
|
//FKismetNodeInfoContext* K2Context = (FKismetNodeInfoContext*)Context;
|
|
|
|
|
FLinearColor CurrentStateColor(1.f, 0.5f, 0.25f);
|
|
|
|
|
|
|
|
|
|
// Display various types of debug data
|
|
|
|
|
if ((ActiveObject != NULL) && (Class != NULL))
|
|
|
|
|
{
|
|
|
|
|
if (FStateMachineDebugData* DebugInfo = Class->GetAnimBlueprintDebugData().StateMachineDebugData.Find(GraphNode->GetGraph()))
|
|
|
|
|
{
|
|
|
|
|
if (Class->AnimNodeProperties.Num())
|
|
|
|
|
{
|
|
|
|
|
UAnimationStateMachineGraph* TypedGraph = CastChecked<UAnimationStateMachineGraph>(GraphNode->GetGraph());
|
|
|
|
|
|
|
|
|
|
if (FAnimNode_StateMachine* CurrentInstance = Class->GetPropertyInstance<FAnimNode_StateMachine>(ActiveObject, TypedGraph->OwnerAnimGraphNode))
|
|
|
|
|
{
|
|
|
|
|
if (int32* pStateIndex = DebugInfo->NodeToStateIndex.Find(GraphNode))
|
|
|
|
|
{
|
|
|
|
|
const float Weight = CurrentInstance->GetStateWeight(*pStateIndex);
|
|
|
|
|
if (Weight > 0.0f)
|
|
|
|
|
{
|
|
|
|
|
FString StateText = FString::Printf(TEXT("%.1f%%"), Weight * 100.0f);
|
|
|
|
|
if (*pStateIndex == CurrentInstance->GetCurrentState())
|
|
|
|
|
{
|
|
|
|
|
StateText += FString::Printf(TEXT("\nActive for %.2f secs"), CurrentInstance->GetCurrentStateElapsedTime());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new (Popups) FGraphInformationPopupInfo(NULL, CurrentStateColor, StateText);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphNodeAnimState::GetNodeInfoPopups(FNodeInfoContext* Context, TArray<FGraphInformationPopupInfo>& Popups) const
|
|
|
|
|
{
|
|
|
|
|
GetStateInfoPopup(GraphNode, Popups);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FSlateColor SGraphNodeAnimState::GetBorderBackgroundColor() const
|
|
|
|
|
{
|
|
|
|
|
UAnimBlueprint* AnimBlueprint = Cast<UAnimBlueprint>(FBlueprintEditorUtils::FindBlueprintForNodeChecked(GraphNode));
|
|
|
|
|
UAnimInstance* ActiveObject = (AnimBlueprint != NULL) ? Cast<UAnimInstance>(AnimBlueprint->GetObjectBeingDebugged()) : NULL;
|
|
|
|
|
UAnimBlueprintGeneratedClass* Class = AnimBlueprint->GetAnimBlueprintGeneratedClass();
|
|
|
|
|
|
|
|
|
|
//FKismetNodeInfoContext* K2Context = (FKismetNodeInfoContext*)Context;
|
|
|
|
|
|
|
|
|
|
FLinearColor InactiveStateColor(0.08f, 0.08f, 0.08f);
|
|
|
|
|
FLinearColor ActiveStateColorDim(0.4f, 0.3f, 0.15f);
|
|
|
|
|
FLinearColor ActiveStateColorBright(1.f, 0.6f, 0.35f);
|
|
|
|
|
|
|
|
|
|
// Display various types of debug data
|
|
|
|
|
if ((ActiveObject != NULL) && (Class != NULL))
|
|
|
|
|
{
|
|
|
|
|
if (FStateMachineDebugData* DebugInfo = Class->GetAnimBlueprintDebugData().StateMachineDebugData.Find(GraphNode->GetGraph()))
|
|
|
|
|
{
|
|
|
|
|
if (Class->AnimNodeProperties.Num())
|
|
|
|
|
{
|
|
|
|
|
UAnimationStateMachineGraph* TypedGraph = CastChecked<UAnimationStateMachineGraph>(GraphNode->GetGraph());
|
|
|
|
|
|
|
|
|
|
if (FAnimNode_StateMachine* CurrentInstance = Class->GetPropertyInstance<FAnimNode_StateMachine>(ActiveObject, TypedGraph->OwnerAnimGraphNode))
|
|
|
|
|
{
|
|
|
|
|
if (int32* pStateIndex = DebugInfo->NodeToStateIndex.Find(GraphNode))
|
|
|
|
|
{
|
|
|
|
|
const float Weight = CurrentInstance->GetStateWeight(*pStateIndex);
|
|
|
|
|
if (Weight > 0.0f)
|
|
|
|
|
{
|
|
|
|
|
return FMath::Lerp<FLinearColor>(ActiveStateColorDim, ActiveStateColorBright, Weight);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return InactiveStateColor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphNodeAnimState::UpdateGraphNode()
|
|
|
|
|
{
|
|
|
|
|
InputPins.Empty();
|
|
|
|
|
OutputPins.Empty();
|
|
|
|
|
|
|
|
|
|
// Reset variables that are going to be exposed, in case we are refreshing an already setup node.
|
|
|
|
|
RightNodeBox.Reset();
|
|
|
|
|
LeftNodeBox.Reset();
|
|
|
|
|
|
|
|
|
|
const FSlateBrush* NodeTypeIcon = GetNameIcon();
|
|
|
|
|
|
|
|
|
|
FLinearColor TitleShadowColor(0.6f, 0.6f, 0.6f);
|
|
|
|
|
TSharedPtr<SErrorText> ErrorText;
|
|
|
|
|
TSharedPtr<SNodeTitle> NodeTitle = SNew(SNodeTitle, GraphNode);
|
|
|
|
|
|
|
|
|
|
this->ContentScale.Bind( this, &SGraphNode::GetContentScale );
|
2014-11-03 10:40:57 -05:00
|
|
|
this->GetOrAddSlot( ENodeZone::Center )
|
2014-03-14 14:13:41 -04:00
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
.BorderImage( FEditorStyle::GetBrush( "Graph.StateNode.Body" ) )
|
|
|
|
|
.Padding(0)
|
|
|
|
|
.BorderBackgroundColor( this, &SGraphNodeAnimState::GetBorderBackgroundColor )
|
|
|
|
|
[
|
|
|
|
|
SNew(SOverlay)
|
|
|
|
|
|
|
|
|
|
// PIN AREA
|
|
|
|
|
+SOverlay::Slot()
|
|
|
|
|
.HAlign(HAlign_Fill)
|
|
|
|
|
.VAlign(VAlign_Fill)
|
|
|
|
|
[
|
|
|
|
|
SAssignNew(RightNodeBox, SVerticalBox)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
// STATE NAME AREA
|
|
|
|
|
+SOverlay::Slot()
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.Padding(10.0f)
|
|
|
|
|
[
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
.BorderImage( FEditorStyle::GetBrush("Graph.StateNode.ColorSpill") )
|
|
|
|
|
.BorderBackgroundColor( TitleShadowColor )
|
|
|
|
|
.HAlign(HAlign_Center)
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
.Visibility(EVisibility::SelfHitTestInvisible)
|
|
|
|
|
[
|
|
|
|
|
SNew(SHorizontalBox)
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
[
|
|
|
|
|
// POPUP ERROR MESSAGE
|
|
|
|
|
SAssignNew(ErrorText, SErrorText )
|
|
|
|
|
.BackgroundColor( this, &SGraphNodeAnimState::GetErrorColor )
|
|
|
|
|
.ToolTipText( this, &SGraphNodeAnimState::GetErrorMsgToolTip )
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
2014-09-11 20:21:09 -04:00
|
|
|
.AutoWidth()
|
|
|
|
|
.VAlign(VAlign_Center)
|
2014-03-14 14:13:41 -04:00
|
|
|
[
|
|
|
|
|
SNew(SImage)
|
|
|
|
|
.Image(NodeTypeIcon)
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.Padding(FMargin(4.0f, 0.0f, 4.0f, 0.0f))
|
|
|
|
|
[
|
|
|
|
|
SNew(SVerticalBox)
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
SAssignNew(InlineEditableText, SInlineEditableTextBlock)
|
|
|
|
|
.Style( FEditorStyle::Get(), "Graph.StateNode.NodeTitleInlineEditableText" )
|
|
|
|
|
.Text( NodeTitle.Get(), &SNodeTitle::GetHeadTitle )
|
|
|
|
|
.OnVerifyTextChanged(this, &SGraphNodeAnimState::OnVerifyNameTextChanged)
|
|
|
|
|
.OnTextCommitted(this, &SGraphNodeAnimState::OnNameTextCommited)
|
|
|
|
|
.IsReadOnly( this, &SGraphNodeAnimState::IsNameReadOnly )
|
|
|
|
|
.IsSelected(this, &SGraphNodeAnimState::IsSelectedExclusively)
|
|
|
|
|
]
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
|
|
|
|
NodeTitle.ToSharedRef()
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
ErrorReporting = ErrorText;
|
|
|
|
|
ErrorReporting->SetError(ErrorMsg);
|
|
|
|
|
CreatePinWidgets();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphNodeAnimState::CreatePinWidgets()
|
|
|
|
|
{
|
|
|
|
|
UAnimStateNodeBase* StateNode = CastChecked<UAnimStateNodeBase>(GraphNode);
|
|
|
|
|
|
|
|
|
|
UEdGraphPin* CurPin = StateNode->GetOutputPin();
|
|
|
|
|
if (!CurPin->bHidden)
|
|
|
|
|
{
|
|
|
|
|
TSharedPtr<SGraphPin> NewPin = SNew(SStateMachineOutputPin, CurPin);
|
|
|
|
|
|
|
|
|
|
NewPin->SetIsEditable(IsEditable);
|
|
|
|
|
|
|
|
|
|
this->AddPin(NewPin.ToSharedRef());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphNodeAnimState::AddPin(const TSharedRef<SGraphPin>& PinToAdd)
|
|
|
|
|
{
|
|
|
|
|
PinToAdd->SetOwner( SharedThis(this) );
|
|
|
|
|
RightNodeBox->AddSlot()
|
|
|
|
|
.HAlign(HAlign_Fill)
|
|
|
|
|
.VAlign(VAlign_Fill)
|
|
|
|
|
.FillHeight(1.0f)
|
|
|
|
|
[
|
|
|
|
|
PinToAdd
|
|
|
|
|
];
|
|
|
|
|
OutputPins.Add(PinToAdd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TSharedPtr<SToolTip> SGraphNodeAnimState::GetComplexTooltip()
|
|
|
|
|
{
|
|
|
|
|
UAnimStateNodeBase* StateNode = CastChecked<UAnimStateNodeBase>(GraphNode);
|
|
|
|
|
|
|
|
|
|
return SNew(SToolTip)
|
|
|
|
|
[
|
|
|
|
|
SNew(SVerticalBox)
|
|
|
|
|
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
[
|
2014-06-09 11:12:17 -04:00
|
|
|
// Create the tooltip preview, ensure to disable state overlays to stop
|
|
|
|
|
// PIE and read-only borders obscuring the graph
|
2014-03-14 14:13:41 -04:00
|
|
|
SNew(SGraphPreviewer, StateNode->GetBoundGraph())
|
|
|
|
|
.CornerOverlayText(this, &SGraphNodeAnimState::GetPreviewCornerText)
|
2014-06-09 11:12:17 -04:00
|
|
|
.ShowGraphStateOverlay(false)
|
2014-03-14 14:13:41 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
+SVerticalBox::Slot()
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
.Padding(FMargin(0.0f, 5.0f, 0.0f, 0.0f))
|
|
|
|
|
[
|
|
|
|
|
IDocumentation::Get()->CreateToolTip(FText::FromString("Documentation"), NULL, StateNode->GetDocumentationLink(), StateNode->GetDocumentationExcerptName())
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-07 09:52:40 -05:00
|
|
|
FText SGraphNodeAnimState::GetPreviewCornerText() const
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
UAnimStateNodeBase* StateNode = CastChecked<UAnimStateNodeBase>(GraphNode);
|
|
|
|
|
|
2015-01-07 09:52:40 -05:00
|
|
|
return FText::Format(NSLOCTEXT("SGraphNodeAnimState", "PreviewCornerStateText", "{0} state"), FText::FromString(StateNode->GetStateName()));
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FSlateBrush* SGraphNodeAnimState::GetNameIcon() const
|
|
|
|
|
{
|
|
|
|
|
return FEditorStyle::GetBrush( TEXT("Graph.StateNode.Icon") );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
|
// SGraphNodeAnimConduit
|
|
|
|
|
|
|
|
|
|
void SGraphNodeAnimConduit::Construct(const FArguments& InArgs, UAnimStateConduitNode* InNode)
|
|
|
|
|
{
|
|
|
|
|
SGraphNodeAnimState::Construct(SGraphNodeAnimState::FArguments(), InNode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphNodeAnimConduit::GetNodeInfoPopups(FNodeInfoContext* Context, TArray<FGraphInformationPopupInfo>& Popups) const
|
|
|
|
|
{
|
|
|
|
|
// Intentionally empty.
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-07 09:52:40 -05:00
|
|
|
FText SGraphNodeAnimConduit::GetPreviewCornerText() const
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
UAnimStateNodeBase* StateNode = CastChecked<UAnimStateNodeBase>(GraphNode);
|
|
|
|
|
|
2015-01-07 09:52:40 -05:00
|
|
|
return FText::Format(NSLOCTEXT("SGraphNodeAnimState", "PreviewCornerConduitText", "{0} conduit"), FText::FromString(StateNode->GetStateName()));
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FSlateBrush* SGraphNodeAnimConduit::GetNameIcon() const
|
|
|
|
|
{
|
|
|
|
|
return FEditorStyle::GetBrush( TEXT("Graph.ConduitNode.Icon") );
|
|
|
|
|
}
|