// 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 InFilterFuncs) override { if (InStruct->IsA()) { // 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 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 SGraphPinStruct::GenerateAssetPicker() { FStructViewerModule& StructViewerModule = FModuleManager::LoadModuleChecked("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(MetaStructName, EFindFirstObjectOptions::EnsureIfAmbiguous); if (!MetaStruct) { MetaStruct = LoadObject(nullptr, *MetaStructName); } } TSharedRef StructFilter = MakeShared(); 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(ChosenStruct)); } } FText SGraphPinStruct::GetDefaultComboText() const { return LOCTEXT("DefaultComboText", "Select Struct"); } #undef LOCTEXT_NAMESPACE