void SPropertyEditorAsset::Construct( const FArguments& InArgs, const TSharedPtr<FPropertyEditor>& InPropertyEditor ) { PropertyEditor = InPropertyEditor; PropertyHandle = InArgs._PropertyHandle; OnSetObject = InArgs._OnSetObject; OnShouldFilterAsset = InArgs._OnShouldFilterAsset; UProperty* Property = nullptr; if(PropertyEditor.IsValid()) { Property = PropertyEditor->GetPropertyNode()->GetProperty(); UObjectPropertyBase* ObjectProperty = Cast<UObjectPropertyBase>(Property); check(ObjectProperty); bAllowClear = !(Property->PropertyFlags & CPF_NoClear); ObjectClass = ObjectProperty->PropertyClass; bIsActor = ObjectProperty->PropertyClass->IsChildOf( AActor::StaticClass() ); } else { bAllowClear = InArgs._AllowClear; ObjectPath = InArgs._ObjectPath; ObjectClass = InArgs._Class; bIsActor = ObjectClass->IsChildOf( AActor::StaticClass() ); if (PropertyHandle.IsValid() && PropertyHandle->IsValidHandle()) { Property = PropertyHandle->GetProperty(); } else { CustomClassFilters.Add(ObjectClass); } } // Account for the allowed classes specified in the property metadata if (Property) { FString ClassFilterString; if (UArrayProperty* ArrayParent = Cast<UArrayProperty>(Property->GetOuter())) { ClassFilterString = ArrayParent->GetMetaData("AllowedClasses"); } else { ClassFilterString = Property->GetMetaData("AllowedClasses"); } if (ClassFilterString.IsEmpty()) { CustomClassFilters.Add(ObjectClass); } else { TArray<FString> CustomClassFilterNames; ClassFilterString.ParseIntoArray(CustomClassFilterNames, TEXT(","), true); for (auto It = CustomClassFilterNames.CreateConstIterator(); It; ++It) { const FString& ClassName = *It; UClass* Class = FindObject<UClass>(ANY_PACKAGE, *ClassName); if (!Class) { Class = LoadObject<UClass>(nullptr, *ClassName); } if (Class) { // If the class is an interface, expand it to be all classes in memory that implement the class. if (Class->HasAnyClassFlags(CLASS_Interface)) { for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt) { UClass* const ClassWithInterface = (*ClassIt); if (ClassWithInterface->ImplementsInterface(Class)) { CustomClassFilters.Add(ClassWithInterface); } } } else { CustomClassFilters.Add(Class); } } } } } if (InArgs._NewAssetFactories.IsSet()) { NewAssetFactories = InArgs._NewAssetFactories.GetValue(); } else if (CustomClassFilters.Num() > 1 || !CustomClassFilters.Contains(UObject::StaticClass())) { NewAssetFactories = PropertyCustomizationHelpers::GetNewAssetFactoriesForClasses(CustomClassFilters); } TSharedPtr<SHorizontalBox> ValueContentBox = NULL; ChildSlot [ SNew( SAssetDropTarget ) .OnIsAssetAcceptableForDrop( this, &SPropertyEditorAsset::OnAssetDraggedOver ) .OnAssetDropped( this, &SPropertyEditorAsset::OnAssetDropped ) [ SAssignNew( ValueContentBox, SHorizontalBox ) ] ]; TAttribute<bool> IsEnabledAttribute(this, &SPropertyEditorAsset::CanEdit); TAttribute<FText> TooltipAttribute(this, &SPropertyEditorAsset::OnGetToolTip); if (Property && Property->HasAllPropertyFlags(CPF_DisableEditOnTemplate)) { // There are some cases where editing an Actor Property is not allowed, such as when it is contained within a struct or a CDO TArray<UObject*> ObjectList; PropertyEditor->GetPropertyHandle()->GetOuterObjects(ObjectList); // If there is no objects, that means we must have a struct asset managing this property if (ObjectList.Num() == 0) { IsEnabledAttribute.Set(false); TooltipAttribute.Set(LOCTEXT("VariableHasDisableEditOnTemplate", "Editing this value in structure's defaults is not allowed")); } else { // Go through all the found objects and see if any are a CDO, we can't set an actor in a CDO default. for (UObject* Obj : ObjectList) { if (Obj->HasAllFlags(RF_ClassDefaultObject)) { IsEnabledAttribute.Set(false); TooltipAttribute.Set(LOCTEXT("VariableHasDisableEditOnTemplateTooltip", "Editing this value in a Class Default Object is not allowed")); break; } } } } AssetComboButton = SNew(SComboButton) .ToolTipText(TooltipAttribute) .ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" ) .ForegroundColor(FEditorStyle::GetColor("PropertyEditor.AssetName.ColorAndOpacity")) .OnGetMenuContent( this, &SPropertyEditorAsset::OnGetMenuContent ) .OnMenuOpenChanged( this, &SPropertyEditorAsset::OnMenuOpenChanged ) .IsEnabled( IsEnabledAttribute ) .ContentPadding(2.0f) .ButtonContent() [ // Show the name of the asset or actor SNew(STextBlock) .TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" ) .Font( FEditorStyle::GetFontStyle( PropertyEditorConstants::PropertyFontStyle ) ) .Text(this,&SPropertyEditorAsset::OnGetAssetName) ]; TSharedRef<SHorizontalBox> ButtonBox = SNew( SHorizontalBox ); TSharedPtr<SVerticalBox> CustomContentBox; if( ShouldDisplayThumbnail(InArgs) ) { FObjectOrAssetData Value; GetValue( Value ); AssetThumbnail = MakeShareable( new FAssetThumbnail( Value.AssetData, InArgs._ThumbnailSize.X, InArgs._ThumbnailSize.Y, InArgs._ThumbnailPool ) ); ValueContentBox->AddSlot() .Padding( 0.0f, 0.0f, 2.0f, 0.0f ) .AutoWidth() [ SAssignNew( ThumbnailBorder, SBorder ) .Padding( 5.0f ) .BorderImage( this, &SPropertyEditorAsset::GetThumbnailBorder ) .OnMouseDoubleClick( this, &SPropertyEditorAsset::OnAssetThumbnailDoubleClick ) [ SNew( SBox ) .ToolTipText(TooltipAttribute) .WidthOverride( InArgs._ThumbnailSize.X ) .HeightOverride( InArgs._ThumbnailSize.Y ) [ AssetThumbnail->MakeThumbnailWidget() ] ] ]; ValueContentBox->AddSlot() [ SNew( SBox ) .VAlign( VAlign_Center ) [ SAssignNew( CustomContentBox, SVerticalBox ) + SVerticalBox::Slot() [ AssetComboButton.ToSharedRef() ] + SVerticalBox::Slot() .AutoHeight() .Padding( 0.0f, 2.0f, 4.0f, 2.0f ) [ ButtonBox ] ] ]; } else { ValueContentBox->AddSlot() [ SAssignNew( CustomContentBox, SVerticalBox ) +SVerticalBox::Slot() .VAlign( VAlign_Center ) [ SNew( SHorizontalBox ) + SHorizontalBox::Slot() [ AssetComboButton.ToSharedRef() ] + SHorizontalBox::Slot() .AutoWidth() .Padding( 4.f, 0.f ) [ ButtonBox ] ] ]; } if( InArgs._CustomContentSlot.Widget != SNullWidget::NullWidget ) { CustomContentBox->AddSlot() .VAlign( VAlign_Center ) .Padding( FMargin( 0.0f, 2.0f ) ) [ InArgs._CustomContentSlot.Widget ]; } if( !bIsActor && InArgs._DisplayUseSelected ) { ButtonBox->AddSlot() .VAlign(VAlign_Center) .AutoWidth() .Padding( 2.0f, 0.0f ) [ PropertyCustomizationHelpers::MakeUseSelectedButton( FSimpleDelegate::CreateSP( this, &SPropertyEditorAsset::OnUse ), FText(), IsEnabledAttribute ) ]; } if( InArgs._DisplayBrowse ) { ButtonBox->AddSlot() .Padding( 2.0f, 0.0f ) .AutoWidth() .VAlign(VAlign_Center) [ PropertyCustomizationHelpers::MakeBrowseButton( FSimpleDelegate::CreateSP( this, &SPropertyEditorAsset::OnBrowse ), TAttribute<FText>( this, &SPropertyEditorAsset::GetOnBrowseToolTip ) ) ]; } if( bIsActor ) { TSharedRef<SWidget> ActorPicker = PropertyCustomizationHelpers::MakeInteractiveActorPicker( FOnGetAllowedClasses::CreateSP(this, &SPropertyEditorAsset::OnGetAllowedClasses), FOnShouldFilterActor(), FOnActorSelected::CreateSP( this, &SPropertyEditorAsset::OnActorSelected ) ); ActorPicker->SetEnabled( IsEnabledAttribute ); ButtonBox->AddSlot() .Padding( 2.0f, 0.0f ) .AutoWidth() .VAlign(VAlign_Center) [ ActorPicker ]; } if( InArgs._ResetToDefaultSlot.Widget != SNullWidget::NullWidget ) { TSharedRef<SWidget> ResetToDefaultWidget = InArgs._ResetToDefaultSlot.Widget; ResetToDefaultWidget->SetEnabled( IsEnabledAttribute ); ButtonBox->AddSlot() .Padding( 4.0f, 0.0f ) .AutoWidth() .VAlign(VAlign_Center) [ ResetToDefaultWidget ]; } }
void SPropertyEditorAsset::Construct( const FArguments& InArgs, const TSharedPtr<FPropertyEditor>& InPropertyEditor ) { PropertyEditor = InPropertyEditor; PropertyHandle = InArgs._PropertyHandle; OnSetObject = InArgs._OnSetObject; UObject* Object = NULL; if(PropertyEditor.IsValid()) { UProperty* NodeProperty = PropertyEditor->GetPropertyNode()->GetProperty(); UObjectPropertyBase* ObjectProperty = Cast<UObjectPropertyBase>( NodeProperty ); check(ObjectProperty); bAllowClear = !(NodeProperty->PropertyFlags & CPF_NoClear); PropertyEditor->GetPropertyHandle()->GetValue( Object ); ObjectClass = ObjectProperty->PropertyClass; bIsActor = ObjectProperty->PropertyClass->IsChildOf( AActor::StaticClass() ); } else { bAllowClear = InArgs._AllowClear; ObjectPath = InArgs._ObjectPath; ObjectClass = InArgs._Class; bIsActor = ObjectClass->IsChildOf( AActor::StaticClass() ); } OnShouldFilterAsset = InArgs._OnShouldFilterAsset; TSharedPtr<SHorizontalBox> HorizontalBox = NULL; ChildSlot [ SNew( SAssetDropTarget ) .OnIsAssetAcceptableForDrop( this, &SPropertyEditorAsset::OnAssetDraggedOver ) .OnAssetDropped( this, &SPropertyEditorAsset::OnAssetDropped ) [ SAssignNew( HorizontalBox, SHorizontalBox ) ] ]; if(ShouldDisplayThumbnail(InArgs)) { FObjectOrAssetData Value; GetValue( Value ); AssetThumbnail = MakeShareable( new FAssetThumbnail( Value.AssetData, InArgs._ThumbnailSize.X, InArgs._ThumbnailSize.Y, InArgs._ThumbnailPool ) ); if( AssetThumbnail.IsValid() ) { HorizontalBox->AddSlot() .Padding( 0.0f, 0.0f, 2.0f, 0.0f ) .AutoWidth() [ SNew(SBorder) .Padding(2.0f) .BorderImage( FEditorStyle::GetBrush("PropertyEditor.AssetThumbnailShadow") ) .OnMouseDoubleClick( this, &SPropertyEditorAsset::OnAssetThumbnailDoubleClick ) [ SNew( SBox ) .ToolTipText( this, &SPropertyEditorAsset::OnGetToolTip ) .WidthOverride( InArgs._ThumbnailSize.X ) .HeightOverride( InArgs._ThumbnailSize.Y ) [ AssetThumbnail->MakeThumbnailWidget() ] ] ]; } } TSharedPtr<SHorizontalBox> ButtonBox; HorizontalBox->AddSlot() .FillWidth(1.0f) .Padding( 0.0f, 4.0f, 4.0f, 4.0f ) .VAlign(VAlign_Center) [ SNew(SVerticalBox) +SVerticalBox::Slot() .VAlign( VAlign_Center ) [ SAssignNew( ButtonBox, SHorizontalBox ) .IsEnabled( this, &SPropertyEditorAsset::CanEdit ) + SHorizontalBox::Slot() [ SAssignNew(AssetComboButton, SComboButton) .ToolTipText( this, &SPropertyEditorAsset::OnGetToolTip ) .ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" ) .ForegroundColor(FEditorStyle::GetColor("PropertyEditor.AssetName.ColorAndOpacity")) .OnGetMenuContent( this, &SPropertyEditorAsset::OnGetMenuContent ) .ContentPadding(2.0f) .ButtonContent() [ // Show the name of the asset or actor SNew(STextBlock) .TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" ) .Font( FEditorStyle::GetFontStyle( PropertyEditorConstants::PropertyFontStyle ) ) .Text(this,&SPropertyEditorAsset::OnGetAssetName) ] ] ] +SVerticalBox::Slot() .AutoHeight() .Padding( InArgs._CustomContentSlot.Widget == SNullWidget::NullWidget ? FMargin( 0.0f, 0.0f ) : FMargin( 0.0f, 2.0f ) ) [ InArgs._CustomContentSlot.Widget ] ]; if(!bIsActor) { ButtonBox->AddSlot() .VAlign(VAlign_Center) .Padding( 2.0f, 0.0f ) .AutoWidth() [ PropertyCustomizationHelpers::MakeUseSelectedButton( FSimpleDelegate::CreateSP( this, &SPropertyEditorAsset::OnUse ) ) ]; } ButtonBox->AddSlot() .AutoWidth() .Padding( 2.0f, 0.0f ) .VAlign(VAlign_Center) [ PropertyCustomizationHelpers::MakeBrowseButton( FSimpleDelegate::CreateSP( this, &SPropertyEditorAsset::OnBrowse ), TAttribute<FText>( this, &SPropertyEditorAsset::GetOnBrowseToolTip ) ) ]; if(bIsActor) { ButtonBox->AddSlot() .AutoWidth() .Padding( 2.0f, 0.0f ) .VAlign(VAlign_Center) [ PropertyCustomizationHelpers::MakeInteractiveActorPicker( FOnGetAllowedClasses::CreateSP(this, &SPropertyEditorAsset::OnGetAllowedClasses), FOnActorSelected::CreateSP( this, &SPropertyEditorAsset::OnActorSelected ) ) ]; } if( InArgs._ResetToDefaultSlot.Widget != SNullWidget::NullWidget ) { ButtonBox->AddSlot() .AutoWidth() .Padding( 2.0f, 0.0f ) .VAlign(VAlign_Center) [ InArgs._ResetToDefaultSlot.Widget ]; } }