void FFoliageTypeObjectCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) { TSharedPtr<IPropertyHandle> FoliageTypeHandle = PropertyHandle->GetChildHandle("FoliageTypeObject"); // Only allow foliage type assets to be created (i.e. don't show all the factories for blueprints) TArray<const UClass*> SupportedClasses; SupportedClasses.Add(UFoliageType_InstancedStaticMesh::StaticClass()); HeaderRow .NameContent() [ FoliageTypeHandle->CreatePropertyNameWidget() ] .ValueContent() .MinDesiredWidth(250.f) .MaxDesiredWidth(0.f) [ SNew(SObjectPropertyEntryBox) .PropertyHandle(FoliageTypeHandle) .ThumbnailPool(CustomizationUtils.GetThumbnailPool()) .NewAssetFactories(PropertyCustomizationHelpers::GetNewAssetFactoriesForClasses(SupportedClasses)) .OnShouldFilterAsset(this, &FFoliageTypeObjectCustomization::OnShouldFilterAsset) ]; //PropertyCustomizationHelpers::MakeInsertDeleteDuplicateButton <-- not sure how to get that to show up properly, since the struct doesn't know it's an array }
void FPrimaryAssetIdCustomization::CustomizeHeader(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { if (!UAssetManager::IsValid()) { HeaderRow .NameContent() [ InStructPropertyHandle->CreatePropertyNameWidget() ] .ValueContent() .MinDesiredWidth(250.0f) .MaxDesiredWidth(0.0f) [ SNew(STextBlock) .Text(LOCTEXT("NoAssetManager", "Enable Asset Manager to edit Primary Asset Ids")) ]; return; } StructPropertyHandle = InStructPropertyHandle; const FString& TypeFilterString = StructPropertyHandle->GetMetaData("AllowedTypes"); if( !TypeFilterString.IsEmpty() ) { TArray<FString> CustomTypeFilterNames; TypeFilterString.ParseIntoArray(CustomTypeFilterNames, TEXT(","), true); for(auto It = CustomTypeFilterNames.CreateConstIterator(); It; ++It) { const FString& TypeName = *It; AllowedTypes.Add(*TypeName); } } FOnShouldFilterAsset AssetFilter = FOnShouldFilterAsset::CreateStatic(&IAssetManagerEditorModule::OnShouldFilterPrimaryAsset, AllowedTypes); // Can the field be cleared const bool bAllowClear = !(StructPropertyHandle->GetMetaDataProperty()->PropertyFlags & CPF_NoClear); HeaderRow .NameContent() [ InStructPropertyHandle->CreatePropertyNameWidget() ] .ValueContent() .MinDesiredWidth(250.0f) .MaxDesiredWidth(0.0f) [ // Add an object entry box. Even though this isn't an object entry, we will simulate one SNew( SObjectPropertyEntryBox ) .ObjectPath(this, &FPrimaryAssetIdCustomization::OnGetObjectPath) .PropertyHandle(InStructPropertyHandle) .ThumbnailPool(StructCustomizationUtils.GetThumbnailPool()) .OnShouldFilterAsset(AssetFilter) .OnObjectChanged(this, &FPrimaryAssetIdCustomization::OnSetObject) .AllowClear(bAllowClear) ]; }
void FStringAssetReferenceCustomization::CustomizeHeader( TSharedRef<IPropertyHandle> InStructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) { StructPropertyHandle = InStructPropertyHandle; FString ClassFilterString = StructPropertyHandle->GetMetaData("AllowedClasses"); if( !ClassFilterString.IsEmpty() ) { TArray<FString> CustomClassFilterNames; ClassFilterString.ParseIntoArray(&CustomClassFilterNames, TEXT(","), true); for(auto It = CustomClassFilterNames.CreateConstIterator(); It; ++It) { const FString& ClassName = *It; UClass* Class = FindObject<UClass>(ANY_PACKAGE, *ClassName); if(!Class) { Class = LoadObject<UClass>(nullptr, *ClassName); } if(Class) { CustomClassFilters.Add(Class); } } } bExactClass = StructPropertyHandle->GetBoolMetaData("ExactClass"); FOnShouldFilterAsset AssetFilter; UClass* ClassFilter = UObject::StaticClass(); if(CustomClassFilters.Num() == 1 && !bExactClass) { // If we only have one class to filter on, set it as the class type filter rather than use a filter callback // We can only do this if we don't need an exact match, as the class filter also allows derived types // The class filter is much faster than the callback as we're not performing two different sets of type tests // (one against UObject, one against the actual type) ClassFilter = CustomClassFilters[0]; } else if(CustomClassFilters.Num() > 0) { // Only bind the filter if we have classes that need filtering AssetFilter.BindSP(this, &FStringAssetReferenceCustomization::OnShouldFilterAsset); } // Can the field be cleared const bool bAllowClear = !(StructPropertyHandle->GetMetaDataProperty()->PropertyFlags & CPF_NoClear); HeaderRow .NameContent() [ InStructPropertyHandle->CreatePropertyNameWidget() ] .ValueContent() .MinDesiredWidth(250.0f) .MaxDesiredWidth(0.0f) [ // Add an object entry box. Even though this isn't an object entry, we will simulate one SNew( SObjectPropertyEntryBox ) .PropertyHandle( InStructPropertyHandle ) .ThumbnailPool( StructCustomizationUtils.GetThumbnailPool() ) .AllowedClass( ClassFilter ) .OnShouldFilterAsset( AssetFilter ) .AllowClear( bAllowClear ) ]; }