Files
UnrealEngineUWP/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintPinInfoDetails.cpp
sebastian nordgren 5050b88330 Details view reskin phase 1.
The details view now displays gridlines between rows, and now has 4 columns - edit condition, name, value, and reset/extensions.

Edit condition widgets are now created in SDetailSingleItemRow and are placed in their own fixed column on the left of the details view. FEditConditionParser is now in FPropertyNode rather FPropertyEditor, which allows access to it more broadly - notably in SDetailSingleItemRow.

The Reset to Default SWidget can no longer be replaced - the logic for it being visible and a handler for when it is pressed is still customizable. SPropertyEditorAsset no longer has a special slot for the reset to default widget.

All extension widgets are now placed in a resizable column on the right of the panel, including the Keyframe button.

FDetailColumnSizeData is now publicly exposed by IDetailsView, and is no longer passed around as much.

#rb matt.kuhlenschmidt

[CL 14375859 by sebastian nordgren in ue5-main branch]
2020-09-23 08:16:20 -04:00

195 lines
5.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimBlueprintPinInfoDetails.h"
#include "SPinTypeSelector.h"
#include "EdGraphSchema_K2.h"
#include "PropertyHandle.h"
#include "AnimGraphNode_LinkedInputPose.h"
#include "DetailLayoutBuilder.h"
#include "Widgets/SBoxPanel.h"
#include "DetailWidgetRow.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Widgets/Layout/SBox.h"
#include "Animation/AnimBlueprint.h"
#include "IAnimationBlueprintEditor.h"
#include "AnimationGraphSchema.h"
#include "Subsystems/AssetEditorSubsystem.h"
#define LOCTEXT_NAMESPACE "AnimBlueprintPinInfoDetails"
void FAnimBlueprintFunctionPinInfoDetails::CustomizeHeader(TSharedRef<IPropertyHandle> InStructPropertyHandle, FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& InStructCustomizationUtils)
{
TArray<UObject*> OuterObjects;
InStructPropertyHandle->GetOuterObjects(OuterObjects);
if(OuterObjects.Num() != 1)
{
return;
}
// skip if we cant edit this node as it is an interface graph
UAnimGraphNode_LinkedInputPose* Node = CastChecked<UAnimGraphNode_LinkedInputPose>(OuterObjects[0]);
if(!Node->CanUserDeleteNode())
{
return;
}
WeakOuterNode = Node;
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
StructPropertyHandle = InStructPropertyHandle;
NamePropertyHandle = InStructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimBlueprintFunctionPinInfo, Name));
TypePropertyHandle = InStructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimBlueprintFunctionPinInfo, Type));
StructPropertyHandle->MarkResetToDefaultCustomized(true);
InHeaderRow
.OverrideResetToDefault(FResetToDefaultOverride::Hide())
.NameContent()
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.MinDesiredWidth(125.0f)
.MaxDesiredWidth(250.0f)
[
SAssignNew(NameTextBox, SEditableTextBox)
.Font(IDetailLayoutBuilder::GetDetailFont())
.Text_Lambda([this]()
{
FName Value;
NamePropertyHandle->GetValue(Value);
return FText::FromName(Value);
})
.OnTextChanged(this, &FAnimBlueprintFunctionPinInfoDetails::HandleTextChanged)
.OnTextCommitted(this, &FAnimBlueprintFunctionPinInfoDetails::HandleTextCommitted)
]
]
]
.ValueContent()
.MaxDesiredWidth(980.f)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
.AutoWidth()
[
SNew(SPinTypeSelector, FGetPinTypeTree::CreateUObject(K2Schema, &UEdGraphSchema_K2::GetVariableTypeTree))
.TargetPinType(this, &FAnimBlueprintFunctionPinInfoDetails::GetTargetPinType)
.OnPinTypeChanged(this, &FAnimBlueprintFunctionPinInfoDetails::HandlePinTypeChanged)
.Schema(K2Schema)
.TypeTreeFilter(ETypeTreeFilter::None)
.bAllowArrays(true)
.Font(IDetailLayoutBuilder::GetDetailFont())
]
];
}
FEdGraphPinType FAnimBlueprintFunctionPinInfoDetails::GetTargetPinType() const
{
void* ValuePtr = nullptr;
if(TypePropertyHandle->GetValueData(ValuePtr) != FPropertyAccess::Fail)
{
return *((FEdGraphPinType*)ValuePtr);
}
return FEdGraphPinType();
}
void FAnimBlueprintFunctionPinInfoDetails::HandlePinTypeChanged(const FEdGraphPinType& InPinType)
{
void* ValuePtr = nullptr;
if(TypePropertyHandle->GetValueData(ValuePtr) != FPropertyAccess::Fail)
{
TypePropertyHandle->NotifyPreChange();
*((FEdGraphPinType*)ValuePtr) = InPinType;
TypePropertyHandle->NotifyPostChange(EPropertyChangeType::ValueSet);
UAnimBlueprint* AnimBlueprint = WeakOuterNode->GetAnimBlueprint();
IAssetEditorInstance* AssetEditor = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->FindEditorForAsset(AnimBlueprint, false);
check(AssetEditor->GetEditorName() == "AnimationBlueprintEditor");
static_cast<IAnimationBlueprintEditor*>(AssetEditor)->SetLastGraphPinTypeUsed(InPinType);
}
}
bool FAnimBlueprintFunctionPinInfoDetails::IsNameValid(const FString& InNewName)
{
if(WeakOuterNode.IsValid())
{
UAnimBlueprint* AnimBlueprint = CastChecked<UAnimBlueprint>(WeakOuterNode->GetGraph()->GetOuter());
for(UEdGraph* Graph : AnimBlueprint->FunctionGraphs)
{
if(Graph->Schema->IsChildOf(UAnimationGraphSchema::StaticClass()))
{
TArray<UAnimGraphNode_LinkedInputPose*> LinkedInputPoseNodes;
Graph->GetNodesOfClass(LinkedInputPoseNodes);
for(UAnimGraphNode_LinkedInputPose* LinkedInputPose : LinkedInputPoseNodes)
{
const TArray<FAnimBlueprintFunctionPinInfo>& Inputs = LinkedInputPose->Inputs;
if(LinkedInputPose == WeakOuterNode.Get())
{
const int32 CurrentIndex = StructPropertyHandle->GetIndexInArray();
for(int32 InputIndex = 0; InputIndex < Inputs.Num(); ++InputIndex)
{
if(InputIndex != CurrentIndex)
{
if(Inputs[InputIndex].Name.ToString().Equals(InNewName, ESearchCase::IgnoreCase))
{
return false;
}
}
}
}
else
{
for(int32 InputIndex = 0; InputIndex < Inputs.Num(); ++InputIndex)
{
if(Inputs[InputIndex].Name.ToString().Equals(InNewName, ESearchCase::IgnoreCase))
{
return false;
}
}
}
}
}
}
}
return true;
}
void FAnimBlueprintFunctionPinInfoDetails::HandleTextChanged(const FText& InNewText)
{
const FString NewTextAsString = InNewText.ToString();
if(!IsNameValid(NewTextAsString))
{
NameTextBox->SetError(LOCTEXT("DuplicateInputError", "This input name already exists in this blueprint."));
}
else
{
NameTextBox->SetError(FText::GetEmpty());
}
}
void FAnimBlueprintFunctionPinInfoDetails::HandleTextCommitted(const FText& InNewText, ETextCommit::Type InCommitType)
{
const FString NewTextAsString = InNewText.ToString();
if(IsNameValid(NewTextAsString))
{
FName NewName = *InNewText.ToString();
NamePropertyHandle->SetValue(NewName);
}
NameTextBox->SetError(FText::GetEmpty());
}
#undef LOCTEXT_NAMESPACE