// Copyright Epic Games, Inc. All Rights Reserved. #include "PerQualityLevelPropertyCustomization.h" #include "Containers/Map.h" #include "Containers/UnrealString.h" #include "Delegates/Delegate.h" #include "DetailWidgetRow.h" #include "HAL/PlatformCrt.h" #include "IPropertyUtilities.h" #include "Internationalization/Internationalization.h" #include "Math/Color.h" #include "Math/UnrealMathSSE.h" #include "Misc/AssertionMacros.h" #include "Misc/Attribute.h" #include "PerQualityLevelProperties.h" #include "PropertyEditorModule.h" #include "PropertyHandle.h" #include "SPerQualityLevelPropertiesWidget.h" #include "ScopedTransaction.h" #include "Styling/SlateColor.h" #include "Templates/Tuple.h" #include "UObject/UnrealNames.h" #include "UObject/UnrealType.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/Text/STextBlock.h" class SWidget; #define LOCTEXT_NAMESPACE "PerOverridePropertyCustomization" template TSharedRef FPerQualityLevelPropertyCustomization::GetWidget(FName InQualityLevelName, TSharedRef StructPropertyHandle) const { TSharedPtr EditProperty; if (InQualityLevelName == NAME_None) { EditProperty = StructPropertyHandle->GetChildHandle(FName("Default")); } else { TSharedPtr MapProperty = StructPropertyHandle->GetChildHandle(FName("PerQuality")); if (MapProperty.IsValid()) { uint32 NumChildren = 0; MapProperty->GetNumChildren(NumChildren); for (uint32 ChildIdx = 0; ChildIdx < NumChildren; ChildIdx++) { TSharedPtr ChildProperty = MapProperty->GetChildHandle(ChildIdx); if (ChildProperty.IsValid()) { TSharedPtr KeyProperty = ChildProperty->GetKeyHandle(); if (KeyProperty.IsValid()) { int32 InQualityLevelNameToInt = INDEX_NONE; if (KeyProperty->GetValue(InQualityLevelNameToInt) == FPropertyAccess::Success && InQualityLevelNameToInt == QualityLevelProperty::FNameToQualityLevel(InQualityLevelName)) { EditProperty = ChildProperty; break; } } } } } } // Push down struct metadata to per-quality level properties { // First get the source map const TMap* SourceMap = StructPropertyHandle->GetMetaDataProperty()->GetMetaDataMap(); // Iterate through source map, setting each key/value pair in the destination for (const auto& It : *SourceMap) { EditProperty->SetInstanceMetaData(*It.Key.ToString(), *It.Value); } // Copy instance metadata as well const TMap* InstanceSourceMap = StructPropertyHandle->GetInstanceMetaDataMap(); for (const auto& It : *InstanceSourceMap) { EditProperty->SetInstanceMetaData(*It.Key.ToString(), *It.Value); } } if (EditProperty.IsValid()) { return EditProperty->CreatePropertyValueWidget(false); } else { return SNew(STextBlock) .Text(NSLOCTEXT("FPerQualityLevelPropertyCustomization", "GetWidget", "Could not find valid property")) .ColorAndOpacity(FLinearColor::Red); } } template float FPerQualityLevelPropertyCustomization::CalcDesiredWidth(TSharedRef StructPropertyHandle) { int32 NumOverrides = 0; TSharedPtr MapProperty = StructPropertyHandle->GetChildHandle(FName("PerQuality")); if (MapProperty.IsValid()) { TArray RawData; MapProperty->AccessRawData(RawData); for (const void* Data : RawData) { const TMap* PerQualityLevelMap = (const TMap*)(Data); NumOverrides = FMath::Max(PerQualityLevelMap->Num(), NumOverrides); } } return (float)(1 + NumOverrides) * 125.f; } template bool FPerQualityLevelPropertyCustomization::AddOverride(FName InQualityLevelName, TSharedRef StructPropertyHandle) { FScopedTransaction Transaction(LOCTEXT("AddOverride", "Add Quality Level Override")); bool bSucces = false; TSharedPtr PerQualityLevelProperty = StructPropertyHandle->GetChildHandle(FName("PerQuality")); TSharedPtr DefaultProperty = StructPropertyHandle->GetChildHandle(FName("Default")); if (PerQualityLevelProperty.IsValid() && DefaultProperty.IsValid()) { TSharedPtr MapProperty = PerQualityLevelProperty->AsMap(); if (MapProperty.IsValid()) { // get the Tmap containing the Key,value TArray RawData; PerQualityLevelProperty->AccessRawData(RawData); if (!RawData.IsEmpty()) { TMap* PerQualityLevelMap = (TMap*)(RawData[0]); check(PerQualityLevelMap); int32 InQualityLevelNameToInt = QualityLevelProperty::FNameToQualityLevel(InQualityLevelName); if (PerQualityLevelMap->Find(InQualityLevelNameToInt) == nullptr) { typename OverrideType::ValueType DefaultValue; DefaultProperty->GetValue(DefaultValue); PerQualityLevelMap->Add(InQualityLevelNameToInt, DefaultValue); if (PropertyUtilities.IsValid()) { PropertyUtilities.Pin()->ForceRefresh(); } bSucces = true; } } } } return bSucces; } template bool FPerQualityLevelPropertyCustomization::RemoveOverride(FName InQualityLevelName, TSharedRef StructPropertyHandle) { FScopedTransaction Transaction(LOCTEXT("RemoveQualityLevelOverride", "Remove Quality Level Override")); TSharedPtr MapProperty = StructPropertyHandle->GetChildHandle(FName("PerQuality")); if (MapProperty.IsValid()) { TArray RawData; MapProperty->AccessRawData(RawData); for (const void* Data : RawData) { TMap* PerQualityLevelMap = (TMap*)(Data); check(PerQualityLevelMap); TArray KeyArray; PerQualityLevelMap->GenerateKeyArray(KeyArray); int32 InQualityLevelNameToInt = QualityLevelProperty::FNameToQualityLevel(InQualityLevelName); for (int32 QL : KeyArray) { if (QL == InQualityLevelNameToInt) { PerQualityLevelMap->Remove(InQualityLevelNameToInt); if (PropertyUtilities.IsValid()) { PropertyUtilities.Pin()->ForceRefresh(); } return true; } } } } return false; } template TArray FPerQualityLevelPropertyCustomization::GetOverrideNames(TSharedRef StructPropertyHandle) const { TArray QualityLevelOverrideNames; TSharedPtr MapProperty = StructPropertyHandle->GetChildHandle(FName("PerQuality")); if (MapProperty.IsValid()) { TArray RawData; MapProperty->AccessRawData(RawData); for (const void* Data : RawData) { const TMap* PerQualityLevelMap = (const TMap*)(Data); check(PerQualityLevelMap); TArray KeyArray; PerQualityLevelMap->GenerateKeyArray(KeyArray); for (int32 QL : KeyArray) { QualityLevelOverrideNames.AddUnique(QualityLevelProperty::QualityLevelToFName(QL)); } } } return QualityLevelOverrideNames; } template void FPerQualityLevelPropertyCustomization::CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { FPerQualityLevelPropertyCustomization::PropertyUtilities = StructCustomizationUtils.GetPropertyUtilities(); HeaderRow.NameContent() [ StructPropertyHandle->CreatePropertyNameWidget() ] .ValueContent() .MinDesiredWidth(FPerQualityLevelPropertyCustomization::CalcDesiredWidth(StructPropertyHandle)) .MaxDesiredWidth((float)(static_cast(EPerQualityLevels::Num) + 1) * 125.0f) [ SNew(SPerQualityLevelPropertiesWidget) .OnGenerateWidget(this, &FPerQualityLevelPropertyCustomization::GetWidget, StructPropertyHandle) .OnAddEntry(this, &FPerQualityLevelPropertyCustomization::AddOverride, StructPropertyHandle) .OnRemoveEntry(this, &FPerQualityLevelPropertyCustomization::RemoveOverride, StructPropertyHandle) .EntryNames(this, &FPerQualityLevelPropertyCustomization::GetOverrideNames, StructPropertyHandle) ]; } template TSharedRef FPerQualityLevelPropertyCustomization::MakeInstance() { return MakeShareable(new FPerQualityLevelPropertyCustomization); } /* Only explicitly instantiate the types which are supported *****************************************************************************/ template class FPerQualityLevelPropertyCustomization; template class FPerQualityLevelPropertyCustomization; #undef LOCTEXT_NAMESPACE