Files
UnrealEngine/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinStruct.cpp
2025-05-18 13:04:45 +08:00

175 lines
5.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "KismetPins/SGraphPinStruct.h"
#include "Containers/UnrealString.h"
#include "Delegates/Delegate.h"
#include "EdGraph/EdGraphPin.h"
#include "EdGraph/EdGraphSchema.h"
#include "Editor.h"
#include "Editor/EditorEngine.h"
#include "StructUtils/UserDefinedStruct.h"
#include "Internationalization/Internationalization.h"
#include "Layout/Margin.h"
#include "Misc/Attribute.h"
#include "Modules/ModuleManager.h"
#include "SGraphPin.h"
#include "ScopedTransaction.h"
#include "Selection.h"
#include "SlotBase.h"
#include "StructViewerFilter.h"
#include "StructViewerModule.h"
#include "Styling/AppStyle.h"
#include "Types/SlateStructs.h"
#include "UObject/Class.h"
#include "UObject/NameTypes.h"
#include "Widgets/Input/SMenuAnchor.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/SBoxPanel.h"
class SWidget;
class UObject;
#define LOCTEXT_NAMESPACE "SGraphPinStruct"
/////////////////////////////////////////////////////
// SGraphPinStruct
void SGraphPinStruct::Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj)
{
SGraphPin::Construct(SGraphPin::FArguments(), InGraphPinObj);
}
FReply SGraphPinStruct::OnClickUse()
{
FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast();
UObject* SelectedObject = GEditor->GetSelectedObjects()->GetTop(UScriptStruct::StaticClass());
if (SelectedObject)
{
const FScopedTransaction Transaction(NSLOCTEXT("GraphEditor", "ChangeStructPinValue", "Change Struct Pin Value"));
GraphPinObj->Modify();
GraphPinObj->GetSchema()->TrySetDefaultObject(*GraphPinObj, SelectedObject);
}
return FReply::Handled();
}
class FGraphPinStructFilter : public IStructViewerFilter
{
public:
/** The meta struct for the property that classes must be a child-of. */
const UScriptStruct* MetaStruct = nullptr;
// TODO: Have a flag controlling whether we allow UserDefinedStructs, even when a MetaClass is set (as they cannot support inheritance, but may still be allowed (eg, data tables))?
virtual bool IsStructAllowed(const FStructViewerInitializationOptions& InInitOptions, const UScriptStruct* InStruct, TSharedRef<FStructViewerFilterFuncs> InFilterFuncs) override
{
if (InStruct->IsA<UUserDefinedStruct>())
{
// User Defined Structs don't support inheritance, so only include them if we have don't a MetaStruct set
return MetaStruct == nullptr;
}
// Don't show any hidden structs
static const FName NAME_HiddenMetaTag = "Hidden";
if (InStruct->HasMetaData(NAME_HiddenMetaTag))
{
return false;
}
// Query the native struct to see if it has the correct parent type (if any)
return !MetaStruct || InStruct->IsChildOf(MetaStruct);
}
virtual bool IsUnloadedStructAllowed(const FStructViewerInitializationOptions& InInitOptions, const FSoftObjectPath& InStructPath, TSharedRef<FStructViewerFilterFuncs> InFilterFuncs) override
{
// User Defined Structs don't support inheritance, so only include them if we have don't a MetaStruct set
return MetaStruct == nullptr;
}
};
TSharedRef<SWidget> SGraphPinStruct::GenerateAssetPicker()
{
FStructViewerModule& StructViewerModule = FModuleManager::LoadModuleChecked<FStructViewerModule>("StructViewer");
// Fill in options
FStructViewerInitializationOptions Options;
Options.Mode = EStructViewerMode::StructPicker;
Options.NameTypeToDisplay = EStructViewerNameTypeToDisplay::DisplayName;
Options.bShowNoneOption = true;
const UScriptStruct* MetaStruct = nullptr;
static const FName NAME_MetaStructMetaTag = "MetaStruct";
const FString MetaStructName = GraphPinObj->GetOwningNode()->GetPinMetaData(GraphPinObj->PinName, NAME_MetaStructMetaTag);
if (!MetaStructName.IsEmpty())
{
MetaStruct = UClass::TryFindTypeSlow<UScriptStruct>(MetaStructName, EFindFirstObjectOptions::EnsureIfAmbiguous);
if (!MetaStruct)
{
MetaStruct = LoadObject<UScriptStruct>(nullptr, *MetaStructName);
}
}
TSharedRef<FGraphPinStructFilter> StructFilter = MakeShared<FGraphPinStructFilter>();
Options.StructFilter = StructFilter;
StructFilter->MetaStruct = MetaStruct;
return
SNew(SBox)
.WidthOverride(280.0f)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.FillHeight(1.0f)
.MaxHeight(500.0f)
[
SNew(SBorder)
.Padding(4.0f)
.BorderImage( FAppStyle::GetBrush("ToolPanel.GroupBorder") )
[
StructViewerModule.CreateStructViewer(Options, FOnStructPicked::CreateSP(this, &SGraphPinStruct::OnPickedNewStruct))
]
]
];
}
FOnClicked SGraphPinStruct::GetOnUseButtonDelegate()
{
return FOnClicked::CreateSP(this, &SGraphPinStruct::OnClickUse);
}
void SGraphPinStruct::OnPickedNewStruct(const UScriptStruct* ChosenStruct)
{
if(GraphPinObj->IsPendingKill())
{
return;
}
FString NewPath;
if (ChosenStruct)
{
NewPath = ChosenStruct->GetPathName();
}
if (GraphPinObj->GetDefaultAsString() != NewPath)
{
const FScopedTransaction Transaction( NSLOCTEXT("GraphEditor", "ChangeStructPinValue", "Change Struct Pin Value" ) );
GraphPinObj->Modify();
AssetPickerAnchor->SetIsOpen(false);
GraphPinObj->GetSchema()->TrySetDefaultObject(*GraphPinObj, const_cast<UScriptStruct*>(ChosenStruct));
}
}
FText SGraphPinStruct::GetDefaultComboText() const
{
return LOCTEXT("DefaultComboText", "Select Struct");
}
#undef LOCTEXT_NAMESPACE