// Copyright Epic Games, Inc. All Rights Reserved. #include "UserGeneratedContentLocalizationDescriptorDetails.h" #include "UserGeneratedContentLocalization.h" #include "PropertyHandle.h" #include "DetailWidgetRow.h" #include "IDetailChildrenBuilder.h" #include "SCulturePicker.h" #include "Widgets/Text/STextBlock.h" #include "Widgets/Input/SComboButton.h" #include "Widgets/Views/SMultipleOptionTable.h" #include "Internationalization/Culture.h" #include "Internationalization/Internationalization.h" #define LOCTEXT_NAMESPACE "UserGeneratedContentLocalizationDescriptorDetails" void FUserGeneratedContentLocalizationDescriptorDetails::CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { if (StructPropertyHandle->HasMetaData("ShowOnlyInnerProperties")) { return; } HeaderRow .NameContent() [ StructPropertyHandle->CreatePropertyNameWidget() ] .ValueContent() [ StructPropertyHandle->CreatePropertyValueWidget() ]; } void FUserGeneratedContentLocalizationDescriptorDetails::CustomizeChildren(TSharedRef StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { // Build the list of available cultures used by the child customizations { FUserGeneratedContentLocalizationDescriptor DefaultUGCLocDescriptor; DefaultUGCLocDescriptor.InitializeFromProject(); const TArray LocalizedCultureList = FInternationalization::Get().GetAvailableCultures(DefaultUGCLocDescriptor.CulturesToGenerate, false); AvailableCultures.Reset(LocalizedCultureList.Num()); Algo::Transform(LocalizedCultureList, AvailableCultures, [](const FCultureRef Culture) -> FCulturePtr { return Culture; }); // Sort by the current display name so that the order in the "native language" picker and the "cultures to generate" list matches AvailableCultures.StableSort([](FCulturePtr One, FCulturePtr Two) { return FTextComparison::CompareTo(One->GetDisplayName(), Two->GetDisplayName()) < 0; }); } uint32 NumChildren = 0; StructPropertyHandle->GetNumChildren(NumChildren); for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex) { if (TSharedPtr ChildPropertyHandle = StructPropertyHandle->GetChildHandle(ChildIndex)) { const FName ChildPropertyName = ChildPropertyHandle->GetProperty()->GetFName(); if (ChildPropertyName == GET_MEMBER_NAME_CHECKED(FUserGeneratedContentLocalizationDescriptor, NativeCulture)) { CustomizeNativeCulture(ChildPropertyHandle.ToSharedRef(), StructBuilder, StructCustomizationUtils); } else if(ChildPropertyName == GET_MEMBER_NAME_CHECKED(FUserGeneratedContentLocalizationDescriptor, CulturesToGenerate)) { CustomizeCulturesToGenerate(ChildPropertyHandle.ToSharedRef(), StructBuilder, StructCustomizationUtils); } else { StructBuilder.AddProperty(ChildPropertyHandle.ToSharedRef()); } } } } void FUserGeneratedContentLocalizationDescriptorDetails::CustomizeNativeCulture(TSharedRef PropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { NativeCultureHandle = PropertyHandle; StructBuilder.AddCustomRow(PropertyHandle->GetPropertyDisplayName()) .RowTag(PropertyHandle->GetProperty()->GetFName()) .PropertyHandleList({ PropertyHandle }) .NameContent() [ PropertyHandle->CreatePropertyNameWidget() ] .ValueContent() [ SNew(SCulturePickerCombo) .Font(IPropertyTypeCustomizationUtils::GetRegularFont()) .SelectedCulture(this, &FUserGeneratedContentLocalizationDescriptorDetails::NativeCulture_GetCulture) .OnSelectionChanged(this, &FUserGeneratedContentLocalizationDescriptorDetails::NativeCulture_OnSelectionChanged) .IsCulturePickable(this, &FUserGeneratedContentLocalizationDescriptorDetails::NativeCulture_IsCulturePickable) .DisplayNameFormat(SCulturePicker::ECultureDisplayFormat::ActiveCultureDisplayName) .ViewMode(SCulturePicker::ECulturesViewMode::Flat) ]; } FCulturePtr FUserGeneratedContentLocalizationDescriptorDetails::NativeCulture_GetCulture() const { FString NativeCultureName; NativeCultureHandle->GetValue(NativeCultureName); return NativeCultureName.IsEmpty() ? nullptr : FInternationalization::Get().GetCulture(NativeCultureName); } bool FUserGeneratedContentLocalizationDescriptorDetails::NativeCulture_IsCulturePickable(FCulturePtr Culture) const { return AvailableCultures.Contains(Culture); } void FUserGeneratedContentLocalizationDescriptorDetails::NativeCulture_OnSelectionChanged(FCulturePtr SelectedCulture, ESelectInfo::Type SelectInfo) { NativeCultureHandle->SetValue(SelectedCulture->GetName()); } void FUserGeneratedContentLocalizationDescriptorDetails::CustomizeCulturesToGenerate(TSharedRef PropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { CulturesToGenerateHandle = PropertyHandle; StructBuilder.AddCustomRow(PropertyHandle->GetPropertyDisplayName()) .RowTag(PropertyHandle->GetProperty()->GetFName()) .PropertyHandleList({ PropertyHandle }) .NameContent() [ PropertyHandle->CreatePropertyNameWidget() ] .ValueContent() .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) [ SNew(SMultipleOptionTable, &AvailableCultures) .ListHeight(100.0f) .OnGenerateOptionWidget_Lambda([](FCulturePtr Culture) -> TSharedRef { return SNew(STextBlock) .Font(IPropertyTypeCustomizationUtils::GetRegularFont()) .Text(FText::AsCultureInvariant(Culture->GetDisplayName())) .ToolTipText(FText::AsCultureInvariant(Culture->GetName())); }) .OnPreBatchSelect(this, &FUserGeneratedContentLocalizationDescriptorDetails::CulturesToGenerate_OnPreBatchSelect) .OnPostBatchSelect(this, &FUserGeneratedContentLocalizationDescriptorDetails::CulturesToGenerate_OnPostBatchSelect) .OnOptionSelectionChanged(this, &FUserGeneratedContentLocalizationDescriptorDetails::CulturesToGenerate_OnCultureSelectionChanged) .IsOptionSelected(this, &FUserGeneratedContentLocalizationDescriptorDetails::CulturesToGenerate_IsCultureSelected) ]; } void FUserGeneratedContentLocalizationDescriptorDetails::CulturesToGenerate_OnPreBatchSelect() { CulturesToGenerate_IsInBatchSelectOperation = true; CulturesToGenerateHandle->NotifyPreChange(); } void FUserGeneratedContentLocalizationDescriptorDetails::CulturesToGenerate_OnPostBatchSelect() { CulturesToGenerateHandle->NotifyPostChange(EPropertyChangeType::ValueSet); CulturesToGenerateHandle->NotifyFinishedChangingProperties(); CulturesToGenerate_IsInBatchSelectOperation = false; } void FUserGeneratedContentLocalizationDescriptorDetails::CulturesToGenerate_OnCultureSelectionChanged(bool IsSelected, FCulturePtr Culture) { if (!CulturesToGenerate_IsInBatchSelectOperation) { CulturesToGenerateHandle->NotifyPreChange(); } CulturesToGenerateHandle->EnumerateRawData([IsSelected, &Culture](void* RawData, const int32 /*DataIndex*/, const int32 /*NumDatas*/) { TArray* RawCulturesToGenerateArray = reinterpret_cast*>(RawData); if (IsSelected) { RawCulturesToGenerateArray->AddUnique(Culture->GetName()); } else { RawCulturesToGenerateArray->Remove(Culture->GetName()); } return true; }); if (!CulturesToGenerate_IsInBatchSelectOperation) { CulturesToGenerateHandle->NotifyPostChange(IsSelected ? EPropertyChangeType::ArrayAdd : EPropertyChangeType::ArrayRemove); CulturesToGenerateHandle->NotifyFinishedChangingProperties(); } } bool FUserGeneratedContentLocalizationDescriptorDetails::CulturesToGenerate_IsCultureSelected(FCulturePtr Culture) const { FString CultureName = Culture->GetName(); TSharedPtr CulturesToGenerateArray = CulturesToGenerateHandle->AsArray(); checkf(CulturesToGenerateArray, TEXT("CulturesToGenerate was not an array!")); uint32 ElementCount = 0; CulturesToGenerateArray->GetNumElements(ElementCount); for (uint32 Index = 0; Index < ElementCount; ++Index) { const TSharedRef ElementPropertyHandle = CulturesToGenerateArray->GetElement(Index); FString CultureNameAtIndex; ElementPropertyHandle->GetValue(CultureNameAtIndex); if (CultureNameAtIndex == CultureName) { return true; } } return false; } #undef LOCTEXT_NAMESPACE