// Copyright Epic Games, Inc. All Rights Reserved. #include "CustomChildBuilder.h" #include "Modules/ModuleManager.h" #include "DetailGroup.h" #include "PropertyHandleImpl.h" #include "DetailPropertyRow.h" #include "ObjectPropertyNode.h" #include "SStandaloneCustomizedValueWidget.h" IDetailChildrenBuilder& FCustomChildrenBuilder::AddCustomBuilder( TSharedRef InCustomBuilder ) { FDetailLayoutCustomization NewCustomization; NewCustomization.CustomBuilderRow = MakeShareable( new FDetailCustomBuilderRow( InCustomBuilder ) ); ChildCustomizations.Add( NewCustomization ); return *this; } IDetailGroup& FCustomChildrenBuilder::AddGroup( FName GroupName, const FText& LocalizedDisplayName, const bool bStartExpanded) { FDetailLayoutCustomization NewCustomization; NewCustomization.DetailGroup = MakeShareable( new FDetailGroup( GroupName, ParentCategory.Pin().ToSharedRef(), LocalizedDisplayName, bStartExpanded ) ); ChildCustomizations.Add( NewCustomization ); return *NewCustomization.DetailGroup; } FDetailWidgetRow& FCustomChildrenBuilder::AddCustomRow( const FText& SearchString ) { const TSharedRef NewRow = MakeShared(); FDetailLayoutCustomization NewCustomization; NewRow->FilterString( SearchString ); // Bind to PasteFromText if specified if (const TSharedPtr PasteFromTextDelegate = GetParentCategory().OnPasteFromText()) { NewRow->OnPasteFromTextDelegate = PasteFromTextDelegate; } NewCustomization.WidgetDecl = NewRow; ChildCustomizations.Add( NewCustomization ); return *NewRow; } IDetailPropertyRow& FCustomChildrenBuilder::AddProperty( TSharedRef PropertyHandle ) { check( PropertyHandle->IsValidHandle() ) FDetailLayoutCustomization NewCustomization; NewCustomization.PropertyRow = MakeShareable( new FDetailPropertyRow( StaticCastSharedRef( PropertyHandle )->GetPropertyNode(), ParentCategory.Pin().ToSharedRef() ) ); if (CustomResetChildToDefault.IsSet()) { NewCustomization.PropertyRow->OverrideResetToDefault(CustomResetChildToDefault.GetValue()); } ChildCustomizations.Add( NewCustomization ); return *NewCustomization.PropertyRow; } IDetailPropertyRow* FCustomChildrenBuilder::AddExternalStructure(TSharedRef ChildStructure, FName UniqueIdName) { return AddExternalStructureProperty(ChildStructure, NAME_None, FAddPropertyParams().UniqueId(UniqueIdName)); } IDetailPropertyRow* FCustomChildrenBuilder::AddExternalStructureProperty(TSharedRef ChildStructure, FName PropertyName, const FAddPropertyParams& Params) { return AddExternalStructureProperty<>(ChildStructure, PropertyName, Params); } IDetailPropertyRow* FCustomChildrenBuilder::AddExternalStructure(TSharedPtr ChildStructure, FName UniqueIdName) { return AddExternalStructureProperty(ChildStructure, NAME_None, FAddPropertyParams().UniqueId(UniqueIdName)); } IDetailPropertyRow* FCustomChildrenBuilder::AddChildStructure(TSharedRef PropertyHandle, TSharedPtr ChildStructure, FName UniqueIdName, const FText& DisplayNameOverride) { return AddChildStructureProperty(PropertyHandle, ChildStructure, NAME_None, FAddPropertyParams().UniqueId(UniqueIdName), DisplayNameOverride); } IDetailPropertyRow* FCustomChildrenBuilder::AddExternalStructureProperty(TSharedPtr ChildStructure, FName PropertyName, const FAddPropertyParams& Params) { return AddExternalStructureProperty<>(ChildStructure, PropertyName, Params); } IDetailPropertyRow* FCustomChildrenBuilder::AddStructureProperty(const FAddPropertyParams& Params, TFunctionRef MakePropertyRowCustomization) { FDetailLayoutCustomization NewCustomization; MakePropertyRowCustomization(NewCustomization); if (Params.ShouldHideRootObjectNode() && NewCustomization.HasPropertyNode() && NewCustomization.GetPropertyNode()->AsComplexNode()) { NewCustomization.PropertyRow->SetForceShowOnlyChildren(true); } TSharedPtr NewRow = NewCustomization.PropertyRow; if (NewRow.IsValid()) { NewRow->SetCustomExpansionId(Params.GetUniqueId()); TSharedPtr PropertyNode = NewRow->GetPropertyNode(); TSharedPtr RootNode = StaticCastSharedRef(PropertyNode->FindComplexParent()->AsShared()); ChildCustomizations.Add(NewCustomization); } return NewRow.Get(); } template IDetailPropertyRow* FCustomChildrenBuilder::AddExternalStructureProperty(const T& ChildStructure, FName PropertyName, const FAddPropertyParams& Params) { return AddStructureProperty(Params, [&](FDetailLayoutCustomization& NewCustomization) { FDetailPropertyRow::MakeExternalPropertyRowCustomization( ChildStructure, PropertyName, ParentCategory.Pin().ToSharedRef(), NewCustomization, Params ); }); } IDetailPropertyRow* FCustomChildrenBuilder::AddChildStructureProperty(TSharedRef PropertyHandle, TSharedPtr ChildStructure, FName PropertyName, const FAddPropertyParams& Params, const FText& DisplayNameOverride) { return AddStructureProperty(Params, [&](FDetailLayoutCustomization& NewCustomization) { FDetailPropertyRow::MakeChildPropertyRowCustomization( PropertyHandle, ChildStructure, PropertyName, ParentCategory.Pin().ToSharedRef(), NewCustomization, Params, DisplayNameOverride ); }); } TArray> FCustomChildrenBuilder::AddAllExternalStructureProperties(TSharedRef ChildStructure) { const TSharedPtr ParentCategoryPinned = ParentCategory.Pin(); return ParentCategoryPinned ? ParentCategoryPinned->AddAllExternalStructureProperties(ChildStructure) : TArray>(); } TArray> FCustomChildrenBuilder::AddAllExternalStructureProperties(TSharedPtr ChildStructure) { const TSharedPtr ParentCategoryPinned = ParentCategory.Pin(); return ParentCategoryPinned ? ParentCategoryPinned->AddAllExternalStructureProperties(ChildStructure) : TArray>(); } IDetailPropertyRow* FCustomChildrenBuilder::AddExternalObjects(const TArray& Objects, FName UniqueIdName) { FAddPropertyParams Params = FAddPropertyParams() .UniqueId(UniqueIdName) .AllowChildren(true); return AddExternalObjects(Objects, Params); } IDetailPropertyRow* FCustomChildrenBuilder::AddExternalObjects(const TArray& Objects, const FAddPropertyParams& Params) { return AddExternalObjectProperty(Objects, NAME_None, Params); } IDetailPropertyRow* FCustomChildrenBuilder::AddExternalObjectProperty(const TArray& Objects, FName PropertyName, const FAddPropertyParams& Params) { TSharedRef ParentCategoryRef = ParentCategory.Pin().ToSharedRef(); FDetailLayoutCustomization NewCustomization; FDetailPropertyRow::MakeExternalPropertyRowCustomization(Objects, PropertyName, ParentCategoryRef, NewCustomization, Params); if (Params.ShouldHideRootObjectNode() && NewCustomization.HasPropertyNode() && NewCustomization.GetPropertyNode()->AsObjectNode()) { NewCustomization.PropertyRow->SetForceShowOnlyChildren(true); } TSharedPtr NewRow = NewCustomization.PropertyRow; if (NewRow.IsValid()) { NewRow->SetCustomExpansionId(Params.GetUniqueId()); ChildCustomizations.Add(NewCustomization); } return NewRow.Get(); } TSharedRef FCustomChildrenBuilder::GenerateStructValueWidget( TSharedRef StructPropertyHandle ) { FStructProperty* StructProperty = CastFieldChecked( StructPropertyHandle->GetProperty() ); FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked("PropertyEditor"); TSharedPtr DetailsView = ParentCategory.Pin()->GetDetailsViewSharedPtr(); FPropertyTypeLayoutCallback LayoutCallback = PropertyEditorModule.GetPropertyTypeCustomization(StructProperty, *StructPropertyHandle, DetailsView ? DetailsView->GetCustomPropertyTypeLayoutMap() : FCustomPropertyTypeLayoutMap() ); if (LayoutCallback.IsValid()) { TSharedRef CustomStructInterface = LayoutCallback.GetCustomizationInstance(); return SNew( SStandaloneCustomizedValueWidget, CustomStructInterface, StructPropertyHandle).ParentCategory(ParentCategory.Pin().ToSharedRef()); } else { // Uncustomized structs have nothing for their value content return SNullWidget::NullWidget; } } IDetailCategoryBuilder& FCustomChildrenBuilder::GetParentCategory() const { return *ParentCategory.Pin(); } FCustomChildrenBuilder& FCustomChildrenBuilder::OverrideResetChildrenToDefault(const FResetToDefaultOverride& ResetToDefault) { CustomResetChildToDefault = ResetToDefault; return *this; } IDetailGroup* FCustomChildrenBuilder::GetParentGroup() const { return ParentGroup.IsValid() ? ParentGroup.Pin().Get() : nullptr; }