// Copyright Epic Games, Inc. All Rights Reserved. #include "Widgets/GameSettingDetailView.h" #include "CommonRichTextBlock.h" #include "CommonTextBlock.h" #include "Components/SlateWrapperTypes.h" #include "Components/VerticalBox.h" #include "Components/VerticalBoxSlot.h" #include "Components/Widget.h" #include "Containers/Array.h" #include "Delegates/Delegate.h" #include "Engine/AssetManager.h" #include "Engine/StreamableManager.h" #include "GameSetting.h" #include "GameSettingFilterState.h" #include "HAL/Platform.h" #include "Internationalization/Internationalization.h" #include "Internationalization/Text.h" #include "Templates/Casts.h" #include "Templates/UnrealTemplate.h" #include "Types/SlateEnums.h" #include "UObject/SoftObjectPath.h" #include "UObject/SoftObjectPtr.h" #include "UObject/WeakObjectPtr.h" #include "UObject/WeakObjectPtrTemplates.h" #include "Widgets/GameSettingDetailExtension.h" #include "Widgets/GameSettingVisualData.h" #define LOCTEXT_NAMESPACE "GameSetting" UGameSettingDetailView::UGameSettingDetailView(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , ExtensionWidgetPool(*this) { } void UGameSettingDetailView::ReleaseSlateResources(bool bReleaseChildren) { Super::ReleaseSlateResources(bReleaseChildren); ExtensionWidgetPool.ReleaseAllSlateResources(); } void UGameSettingDetailView::NativeOnInitialized() { Super::NativeOnInitialized(); if (!IsDesignTime()) { FillSettingDetails(nullptr); } } void UGameSettingDetailView::NativeConstruct() { Super::NativeConstruct(); } void UGameSettingDetailView::FillSettingDetails(UGameSetting* InSetting) { // Ignore requests to show the same setting multiple times in a row. if (InSetting && InSetting == CurrentSetting) { return; } CurrentSetting = InSetting; if (Text_SettingName) { Text_SettingName->SetText(InSetting ? InSetting->GetDisplayName() : FText::GetEmpty()); } if (RichText_Description) { RichText_Description->SetText(InSetting ? InSetting->GetDescriptionRichText() : FText::GetEmpty()); } if (RichText_DynamicDetails) { const FText DynamicDetails = InSetting ? InSetting->GetDynamicDetails() : FText::GetEmpty(); RichText_DynamicDetails->SetText(DynamicDetails); RichText_DynamicDetails->SetVisibility(DynamicDetails.IsEmpty() ? ESlateVisibility::Collapsed : ESlateVisibility::HitTestInvisible); } if (RichText_WarningDetails) { if (InSetting && !InSetting->GetWarningRichText().IsEmpty()) { const FText WarningText = FText::Format(LOCTEXT("WarningReasonLine", " {0}"), InSetting->GetWarningRichText()); RichText_WarningDetails->SetText(WarningText); RichText_WarningDetails->SetVisibility(ESlateVisibility::HitTestInvisible); } else { RichText_WarningDetails->SetText(FText::GetEmpty()); RichText_WarningDetails->SetVisibility(ESlateVisibility::Collapsed); } } if (RichText_DisabledDetails) { TArray DisabledDetailLines; if (InSetting) { FGameSettingEditableState EditableState = InSetting->GetEditState(); if (!EditableState.IsEnabled()) { for (FText Reason : EditableState.GetDisabledReasons()) { DisabledDetailLines.Add(FText::Format(LOCTEXT("DisabledReasonLine", " {0}"), Reason)); } } if (EditableState.GetDisabledOptions().Num() > 0) { DisabledDetailLines.Add(LOCTEXT("DisabledOptionReasonLine", " There are fewer options than available due to Parental Controls.")); } } RichText_DisabledDetails->SetText(FText::Join(FText::FromString(TEXT("\n")), DisabledDetailLines)); RichText_DisabledDetails->SetVisibility(DisabledDetailLines.Num() == 0 ? ESlateVisibility::Collapsed : ESlateVisibility::HitTestInvisible); } if (Box_DetailsExtension) { // First release the widgets back into the pool. for (UWidget* ChildExtension : Box_DetailsExtension->GetAllChildren()) { ExtensionWidgetPool.Release(Cast(ChildExtension)); } // Remove the widgets from their container. Box_DetailsExtension->ClearChildren(); if (InSetting) { TArray> ExtensionClassPtrs; if (VisualData) { ExtensionClassPtrs = VisualData->GatherDetailExtensions(InSetting); } if (StreamingHandle.IsValid()) { StreamingHandle->CancelHandle(); } bool bEverythingAlreadyLoaded = true; TArray ExtensionPaths; ExtensionPaths.Reserve(ExtensionClassPtrs.Num()); for (TSoftClassPtr SoftClassPtr : ExtensionClassPtrs) { bEverythingAlreadyLoaded &= SoftClassPtr.IsValid(); ExtensionPaths.Add(SoftClassPtr.ToSoftObjectPath()); } if (bEverythingAlreadyLoaded) { for (TSoftClassPtr SoftClassPtr : ExtensionClassPtrs) { CreateDetailsExtension(InSetting, SoftClassPtr.Get()); } ExtensionWidgetPool.ReleaseInactiveSlateResources(); } else { TWeakObjectPtr SettingPtr = InSetting; StreamingHandle = UAssetManager::GetStreamableManager().RequestAsyncLoad( MoveTemp(ExtensionPaths), FStreamableDelegate::CreateWeakLambda(this, [this, SettingPtr, ExtensionClassPtrs] { for (TSoftClassPtr SoftClassPtr : ExtensionClassPtrs) { CreateDetailsExtension(SettingPtr.Get(), SoftClassPtr.Get()); } ExtensionWidgetPool.ReleaseInactiveSlateResources(); } )); } } } } void UGameSettingDetailView::CreateDetailsExtension(UGameSetting* InSetting, TSubclassOf ExtensionClass) { if (InSetting && ExtensionClass) { if (UGameSettingDetailExtension* Extension = ExtensionWidgetPool.GetOrCreateInstance(ExtensionClass)) { Extension->SetSetting(InSetting); UVerticalBoxSlot* ExtensionSlot = Box_DetailsExtension->AddChildToVerticalBox(Extension); ExtensionSlot->SetHorizontalAlignment(HAlign_Fill); } } } #undef LOCTEXT_NAMESPACE