// Copyright Epic Games, Inc. All Rights Reserved. #include "PerQualityLevelPropertyCustomization.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Engine/GameViewportClient.h" #include "Widgets/SBoxPanel.h" #include "Widgets/Layout/SSpacer.h" #include "Widgets/Text/STextBlock.h" #include "Widgets/Layout/SBox.h" #include "Widgets/Input/SComboBox.h" #include "Widgets/Images/SImage.h" #include "DetailWidgetRow.h" #include "Editor.h" #include "PropertyHandle.h" #include "DetailLayoutBuilder.h" #include "SPerQualityLevelPropertiesWidget.h" #include "ScopedTransaction.h" #include "IPropertyUtilities.h" #include "UObject/MetaData.h" #include "Scalability.h" #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()) { FName KeyName; if (KeyProperty->GetValue(KeyName) == FPropertyAccess::Success && KeyName == 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")); TSharedPtr PerQualityLevelProperty = StructPropertyHandle->GetChildHandle(FName("PerQuality")); TSharedPtr DefaultProperty = StructPropertyHandle->GetChildHandle(FName("Default")); if (PerQualityLevelProperty.IsValid() && DefaultProperty.IsValid()) { TSharedPtr MapProperty = PerQualityLevelProperty->AsMap(); if (MapProperty.IsValid()) { MapProperty->AddItem(); uint32 NumChildren = 0; PerQualityLevelProperty->GetNumChildren(NumChildren); for (uint32 ChildIdx = 0; ChildIdx < NumChildren; ChildIdx++) { TSharedPtr ChildProperty = PerQualityLevelProperty->GetChildHandle(ChildIdx); if (ChildProperty.IsValid()) { TSharedPtr KeyProperty = ChildProperty->GetKeyHandle(); if (KeyProperty.IsValid()) { FName KeyName; if (KeyProperty->GetValue(KeyName) == FPropertyAccess::Success && KeyName == NAME_None) { // Set Key KeyProperty->SetValue(InQualityLevelName); // Set Value typename OverrideType::ValueType DefaultValue; DefaultProperty->GetValue(DefaultValue); ChildProperty->SetValue(DefaultValue); if (PropertyUtilities.IsValid()) { PropertyUtilities.Pin()->ForceRefresh(); } return true; } } } } } } return false; } 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); for (FName QualityLevelName : KeyArray) { if (QualityLevelName == InQualityLevelName) { PerQualityLevelMap->Remove(InQualityLevelName); 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 (FName QualityLevelName : KeyArray) { QualityLevelOverrideNames.AddUnique(QualityLevelName); } } } 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(QualityLevelProperty::EQualityLevels::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; #undef LOCTEXT_NAMESPACE