2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "DetailCustomizationsPrivatePCH.h"
# include "ActorDetails.h"
# include "AssetSelection.h"
# include "Editor/Layers/Public/LayersModule.h"
# include "Editor/LevelEditor/Public/LevelEditor.h"
# include "Editor/LevelEditor/Public/LevelEditorActions.h"
# include "Editor/ClassViewer/Public/ClassViewerModule.h"
# include "Editor/ClassViewer/Public/ClassViewerFilter.h"
# include "Editor/UnrealEd/Public/Kismet2/KismetEditorUtilities.h"
# include "Editor/UnrealEd/Public/Kismet2/KismetDebugUtilities.h"
# include "ClassIconFinder.h"
# include "Runtime/AssetRegistry/Public/AssetRegistryModule.h"
# include "BlueprintGraphDefinitions.h"
2014-05-29 17:11:10 -04:00
# include "Engine/Breakpoint.h"
2014-03-14 14:13:41 -04:00
# include "ActorMaterialCategory.h"
# include "IContentBrowserSingleton.h"
# include "ContentBrowserModule.h"
# include "ScopedTransaction.h"
2014-05-12 08:38:45 -04:00
# include "CreateBlueprintFromActorDialog.h"
2014-03-14 14:13:41 -04:00
# include "ActorEditorUtils.h"
# include "BlueprintEditorUtils.h"
# include "ComponentTransformDetails.h"
# include "ComponentsTree.h"
# include "IPropertyUtilities.h"
# include "IDocumentation.h"
2014-06-04 14:16:29 -04:00
# include "Runtime/Engine/Classes/Engine/BrushShape.h"
2014-03-14 14:13:41 -04:00
# include "ActorDetailsDelegates.h"
# define LOCTEXT_NAMESPACE "ActorDetails"
2014-04-30 17:34:38 -04:00
FExtendActorDetails OnExtendActorDetails ;
2014-03-14 14:13:41 -04:00
TSharedRef < IDetailCustomization > FActorDetails : : MakeInstance ( )
{
return MakeShareable ( new FActorDetails ) ;
}
FActorDetails : : ~ FActorDetails ( )
{
}
void FActorDetails : : CustomizeDetails ( IDetailLayoutBuilder & DetailLayout )
{
// These details only apply when adding an instance of the actor in a level
if ( ! DetailLayout . GetDetailsView ( ) . HasClassDefaultObject ( ) & & DetailLayout . GetDetailsView ( ) . GetSelectedActorInfo ( ) . NumSelected > 0 )
{
// Build up a list of unique blueprints in the selection set (recording the first actor in the set for each one)
TMap < UBlueprint * , UObject * > UniqueBlueprints ;
// Per level Actor Counts
TMap < ULevel * , int32 > ActorsPerLevelCount ;
bool bHasBillboardComponent = false ;
const TArray < TWeakObjectPtr < UObject > > & SelectedObjects = DetailLayout . GetDetailsView ( ) . GetSelectedObjects ( ) ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
AActor * Actor = Cast < AActor > ( SelectedObjects [ ObjectIndex ] . Get ( ) ) ;
if ( Actor ! = NULL )
{
// Store the selected actors for use later. Its fine to do this when CustomizeDetails is called because if the selected actors changes, CustomizeDetails will be called again on a new instance
// and our current resource would be destroyed.
SelectedActors . Add ( Actor ) ;
// Record the level that contains this actor and increment it's actor count
ULevel * Level = Actor - > GetTypedOuter < ULevel > ( ) ;
if ( Level ! = NULL )
{
int32 & ActorCountForThisLevel = ActorsPerLevelCount . FindOrAdd ( Level ) ;
+ + ActorCountForThisLevel ;
}
// Add to the unique blueprint map if the actor is generated from a blueprint
if ( UBlueprint * Blueprint = Cast < UBlueprint > ( Actor - > GetClass ( ) - > ClassGeneratedBy ) )
{
if ( ! UniqueBlueprints . Find ( Blueprint ) )
{
UniqueBlueprints . Add ( Blueprint , Actor ) ;
}
}
if ( ! bHasBillboardComponent )
{
bHasBillboardComponent = Actor - > FindComponentByClass < UBillboardComponent > ( ) ! = NULL ;
}
}
}
if ( ! bHasBillboardComponent )
{
// Actor billboard scale is not relevant if the actor doesn't have a billboard component
DetailLayout . HideProperty ( GET_MEMBER_NAME_CHECKED ( AActor , SpriteScale ) ) ;
}
AddTransformCategory ( DetailLayout ) ;
AddMaterialCategory ( DetailLayout ) ;
AddActorCategory ( DetailLayout , ActorsPerLevelCount ) ;
// Get the list of hidden categories
TArray < FString > HideCategories ;
DetailLayout . GetDetailsView ( ) . GetBaseClass ( ) - > GetHideCategories ( HideCategories ) ;
// Add Blueprint category, if not being hidden
if ( ! HideCategories . Contains ( TEXT ( " Blueprint " ) ) )
{
AddBlueprintCategory ( DetailLayout , UniqueBlueprints ) ;
}
OnExtendActorDetails . Broadcast ( DetailLayout , FGetSelectedActors : : CreateSP ( this , & FActorDetails : : GetSelectedActors ) ) ;
if ( ! HideCategories . Contains ( TEXT ( " Layers " ) ) )
{
AddLayersCategory ( DetailLayout ) ;
}
//AddComponentsCategory( DetailLayout );
}
}
void FActorDetails : : OnConvertActor ( UClass * ChosenClass )
{
if ( ChosenClass )
{
// Check each selected actor's pointer.
TArray < AActor * > SelectedActorsRaw ;
for ( int32 i = 0 ; i < SelectedActors . Num ( ) ; i + + )
{
if ( SelectedActors [ i ] . IsValid ( ) )
{
SelectedActorsRaw . Add ( SelectedActors [ i ] . Get ( ) ) ;
}
}
// If there are valid pointers, convert the actors.
if ( SelectedActorsRaw . Num ( ) )
{
// Dismiss the menu BEFORE converting actors as it can refresh the details panel and if the menu is still open
// it will be parented to an invalid actor details widget
FSlateApplication : : Get ( ) . DismissAllMenus ( ) ;
GEditor - > ConvertActors ( SelectedActorsRaw , ChosenClass , TSet < FString > ( ) , true ) ;
}
}
}
class FConvertToClassFilter : public IClassViewerFilter
{
public :
/** All classes in this set will be allowed. */
TSet < const UClass * > AllowedClasses ;
/** All classes in this set will be disallowed. */
TSet < const UClass * > DisallowedClasses ;
/** Allowed ChildOf relationship. */
TSet < const UClass * > AllowedChildOfRelationship ;
virtual bool IsClassAllowed ( const FClassViewerInitializationOptions & InInitOptions , const UClass * InClass , TSharedRef < FClassViewerFilterFuncs > InFilterFuncs ) OVERRIDE
{
EFilterReturn : : Type eState = InFilterFuncs - > IfInClassesSet ( AllowedClasses , InClass ) ;
if ( eState = = EFilterReturn : : NoItems )
{
eState = InFilterFuncs - > IfInChildOfClassesSet ( AllowedChildOfRelationship , InClass ) ;
}
// As long as it has not failed to be on an allowed list, check if it is on a disallowed list.
if ( eState = = EFilterReturn : : Passed )
{
eState = InFilterFuncs - > IfInClassesSet ( DisallowedClasses , InClass ) ;
// If it passes, it's on the disallowed list, so we do not want it.
if ( eState = = EFilterReturn : : Passed )
{
return false ;
}
else
{
return true ;
}
}
return false ;
}
virtual bool IsUnloadedClassAllowed ( const FClassViewerInitializationOptions & InInitOptions , const TSharedRef < const IUnloadedBlueprintData > InUnloadedClassData , TSharedRef < FClassViewerFilterFuncs > InFilterFuncs ) OVERRIDE
{
EFilterReturn : : Type eState = InFilterFuncs - > IfInClassesSet ( AllowedClasses , InUnloadedClassData ) ;
if ( eState = = EFilterReturn : : NoItems )
{
eState = InFilterFuncs - > IfInChildOfClassesSet ( AllowedChildOfRelationship , InUnloadedClassData ) ;
}
// As long as it has not failed to be on an allowed list, check if it is on a disallowed list.
if ( eState = = EFilterReturn : : Passed )
{
eState = InFilterFuncs - > IfInClassesSet ( DisallowedClasses , InUnloadedClassData ) ;
// If it passes, it's on the disallowed list, so we do not want it.
if ( eState = = EFilterReturn : : Passed )
{
return false ;
}
else
{
return true ;
}
}
return false ;
}
} ;
UClass * FActorDetails : : GetConversionRoot ( UClass * InCurrentClass ) const
{
UClass * ParentClass = InCurrentClass ;
while ( ParentClass )
{
if ( ParentClass - > GetBoolMetaData ( FName ( TEXT ( " IsConversionRoot " ) ) ) )
{
break ;
}
ParentClass = ParentClass - > GetSuperClass ( ) ;
}
return ParentClass ;
}
void FActorDetails : : CreateClassPickerConvertActorFilter ( const TWeakObjectPtr < AActor > ConvertActor , class FClassViewerInitializationOptions * ClassPickerOptions )
{
// Shouldn't ever be overwriting an already established filter
check ( ConvertActor . IsValid ( ) )
check ( ClassPickerOptions ! = NULL & & ! ClassPickerOptions - > ClassFilter . IsValid ( ) )
TSharedPtr < FConvertToClassFilter > Filter = MakeShareable ( new FConvertToClassFilter ) ;
ClassPickerOptions - > ClassFilter = Filter ;
UClass * ConvertClass = ConvertActor - > GetClass ( ) ;
UClass * RootConversionClass = GetConversionRoot ( ConvertClass ) ;
if ( RootConversionClass )
{
Filter - > AllowedChildOfRelationship . Add ( RootConversionClass ) ;
}
// Never convert to the same class
Filter - > DisallowedClasses . Add ( ConvertClass ) ;
2014-06-04 14:16:29 -04:00
2014-06-05 17:31:47 -04:00
if ( ConvertActor - > IsA < ABrush > ( ) )
2014-06-04 14:16:29 -04:00
{
// Volumes cannot be converted to brushes or brush shapes or the abstract type
Filter - > DisallowedClasses . Add ( ABrush : : StaticClass ( ) ) ;
Filter - > DisallowedClasses . Add ( ABrushShape : : StaticClass ( ) ) ;
Filter - > DisallowedClasses . Add ( AVolume : : StaticClass ( ) ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-06-04 14:16:29 -04:00
2014-03-14 14:13:41 -04:00
TSharedRef < SWidget > FActorDetails : : OnGetConvertContent ( )
{
// Build a class picker widget
// Fill in options
FClassViewerInitializationOptions Options ;
Options . bShowUnloadedBlueprints = true ;
Options . bIsActorsOnly = true ;
Options . bIsPlaceableOnly = true ;
// All selected actors are of the same class, so just need to use one to generate the filter
if ( SelectedActors . Num ( ) > 0 )
{
CreateClassPickerConvertActorFilter ( SelectedActors . Top ( ) , & Options ) ;
}
Options . Mode = EClassViewerMode : : ClassPicker ;
Options . DisplayMode = EClassViewerDisplayMode : : ListView ;
TSharedRef < SWidget > ClassPicker = FModuleManager : : LoadModuleChecked < FClassViewerModule > ( " ClassViewer " ) . CreateClassViewer ( Options , FOnClassPicked : : CreateSP ( this , & FActorDetails : : OnConvertActor ) ) ;
return
SNew ( SBox )
. WidthOverride ( 280 )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. MaxHeight ( 500 )
[
ClassPicker
]
] ;
}
EVisibility FActorDetails : : GetConvertMenuVisibility ( ) const
{
return GEditorModeTools ( ) . EnsureNotInMode ( FBuiltinEditorModes : : EM_InterpEdit ) ?
EVisibility : : Visible :
EVisibility : : Collapsed ;
}
TSharedRef < SWidget > FActorDetails : : MakeConvertMenu ( const FSelectedActorInfo & SelectedActorInfo )
{
2014-06-04 14:16:29 -04:00
UClass * RootConversionClass = GetConversionRoot ( SelectedActorInfo . SelectionClass ) ;
return
SNew ( SComboButton )
. ContentPadding ( 2 )
. IsEnabled ( RootConversionClass ! = NULL )
. Visibility ( this , & FActorDetails : : GetConvertMenuVisibility )
. OnGetMenuContent ( this , & FActorDetails : : OnGetConvertContent )
. ButtonContent ( )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " ConvertButton " , " Select a Type " ) )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
] ;
2014-03-14 14:13:41 -04:00
}
void FActorDetails : : OnNarrowSelectionSetToSpecificLevel ( TWeakObjectPtr < ULevel > LevelToNarrowInto )
{
if ( ULevel * RequiredLevel = LevelToNarrowInto . Get ( ) )
{
// Remove any selected objects that aren't in the specified level
TArray < AActor * > ActorsToDeselect ;
for ( TArray < TWeakObjectPtr < AActor > > : : TConstIterator Iter ( SelectedActors ) ; Iter ; + + Iter )
{
if ( ( * Iter ) . IsValid ( ) )
{
AActor * Actor = ( * Iter ) . Get ( ) ;
if ( ! Actor - > IsIn ( RequiredLevel ) )
{
ActorsToDeselect . Add ( Actor ) ;
}
}
}
for ( TArray < AActor * > : : TIterator DeselectIt ( ActorsToDeselect ) ; DeselectIt ; + + DeselectIt )
{
AActor * Actor = * DeselectIt ;
GEditor - > SelectActor ( Actor , /*bSelected=*/ false , /*bNotify=*/ false ) ;
}
// Tell the editor selection status was changed.
GEditor - > NoteSelectionChange ( ) ;
}
}
bool FActorDetails : : IsActorValidForLevelScript ( ) const
{
AActor * Actor = GEditor - > GetSelectedActors ( ) - > GetTop < AActor > ( ) ;
return FKismetEditorUtilities : : IsActorValidForLevelScript ( Actor ) ;
}
FReply FActorDetails : : FindSelectedActorsInLevelScript ( )
{
GUnrealEd - > FindSelectedActorsInLevelScript ( ) ;
return FReply : : Handled ( ) ;
} ;
bool FActorDetails : : AreAnySelectedActorsInLevelScript ( ) const
{
return GUnrealEd - > AreAnySelectedActorsInLevelScript ( ) ;
} ;
/** Util to create a menu for events we can add for the selected actor */
TSharedRef < SWidget > FActorDetails : : MakeEventOptionsWidgetFromSelection ( )
{
FMenuBuilder EventMenuBuilder ( true , NULL ) ;
AActor * Actor = SelectedActors [ 0 ] . Get ( ) ;
FKismetEditorUtilities : : AddLevelScriptEventOptionsForActor ( EventMenuBuilder , SelectedActors [ 0 ] , true , true , false ) ;
return EventMenuBuilder . MakeWidget ( ) ;
}
void FActorDetails : : AddLayersCategory ( IDetailLayoutBuilder & DetailBuilder )
{
if ( ! FModuleManager : : Get ( ) . IsModuleLoaded ( TEXT ( " Layers " ) ) )
{
return ;
}
FLayersModule & LayersModule = FModuleManager : : LoadModuleChecked < FLayersModule > ( TEXT ( " Layers " ) ) ;
const FString LayerCategory = LOCTEXT ( " LayersCategory " , " Layers " ) . ToString ( ) ;
DetailBuilder . EditCategory ( " Layers " , LayerCategory , ECategoryPriority : : Uncommon )
. AddCustomRow ( TEXT ( " " ) )
[
LayersModule . CreateLayerCloud ( SelectedActors )
] ;
}
void FActorDetails : : AddTransformCategory ( IDetailLayoutBuilder & DetailBuilder )
{
const FSelectedActorInfo & SelectedActorInfo = DetailBuilder . GetDetailsView ( ) . GetSelectedActorInfo ( ) ;
bool bAreBrushesSelected = SelectedActorInfo . bHaveBrush ;
bool bIsOnlyWorldPropsSelected = SelectedActors . Num ( ) = = 1 & & SelectedActors [ 0 ] . IsValid ( ) & & SelectedActors [ 0 ] - > IsA < AWorldSettings > ( ) ;
bool bLacksRootComponent = SelectedActors [ 0 ] . IsValid ( ) & & ( SelectedActors [ 0 ] - > GetRootComponent ( ) = = NULL ) ;
// Don't show the Transform details when brushes are selected, if the only actor selected is world properties, or if they have no RootComponent
if ( bAreBrushesSelected | | bIsOnlyWorldPropsSelected | | bLacksRootComponent )
{
return ;
}
2014-05-02 15:00:21 -04:00
TSharedRef < FComponentTransformDetails > TransformDetails = MakeShareable ( new FComponentTransformDetails ( DetailBuilder . GetDetailsView ( ) . GetSelectedObjects ( ) , SelectedActorInfo , DetailBuilder ) ) ;
2014-03-14 14:13:41 -04:00
IDetailCategoryBuilder & TransformCategory = DetailBuilder . EditCategory ( " TransformCommon " , LOCTEXT ( " TransformCommonCategory " , " Transform " ) . ToString ( ) , ECategoryPriority : : Transform ) ;
TransformCategory . AddCustomBuilder ( TransformDetails ) ;
}
void FActorDetails : : AddMaterialCategory ( IDetailLayoutBuilder & DetailBuilder )
{
MaterialCategory = MakeShareable ( new FActorMaterialCategory ( SelectedActors ) ) ;
MaterialCategory - > Create ( DetailBuilder ) ;
}
void FActorDetails : : AddActorCategory ( IDetailLayoutBuilder & DetailBuilder , const TMap < ULevel * , int32 > & ActorsPerLevelCount )
{
FLevelEditorModule & LevelEditor = FModuleManager : : GetModuleChecked < FLevelEditorModule > ( TEXT ( " LevelEditor " ) ) ;
const FLevelEditorCommands & Commands = LevelEditor . GetLevelEditorCommands ( ) ;
TSharedRef < const FUICommandList > CommandBindings = LevelEditor . GetGlobalLevelEditorActions ( ) ;
const FSelectedActorInfo & SelectedActorInfo = DetailBuilder . GetDetailsView ( ) . GetSelectedActorInfo ( ) ;
TSharedPtr < SVerticalBox > LevelBox ;
IDetailCategoryBuilder & ActorCategory = DetailBuilder . EditCategory ( " Actor " , TEXT ( " " ) , ECategoryPriority : : Uncommon ) ;
// Create the info buttons per level
for ( auto LevelIt ( ActorsPerLevelCount . CreateConstIterator ( ) ) ; LevelIt ; + + LevelIt )
{
ULevel * Level = LevelIt . Key ( ) ;
int32 SelectedActorCountInLevel = LevelIt . Value ( ) ;
// Get a description of the level
FText LevelDescription = FText : : FromString ( FPackageName : : GetShortName ( Level - > GetOutermost ( ) - > GetFName ( ) ) ) ;
if ( Level = = Level - > OwningWorld - > PersistentLevel )
{
LevelDescription = NSLOCTEXT ( " UnrealEd " , " PersistentLevel " , " Persistent Level " ) ;
}
// Create a description and tooltip for the actor count/selection hyperlink
const FText ActorCountDescription = FText : : Format ( LOCTEXT ( " SelectedActorsInOneLevel " , " {0} selected in " ) , FText : : AsNumber ( SelectedActorCountInLevel ) ) ;
const FText Tooltip = FText : : Format ( LOCTEXT ( " SelectedActorsHyperlinkTooltip " , " Narrow the selection set to just the actors in {0} " ) , LevelDescription ) ;
// Create the row for this level
TWeakObjectPtr < ULevel > WeakLevelPtr = Level ;
ActorCategory . AddCustomRow ( LOCTEXT ( " SelectionFilter " , " Selected " ) . ToString ( ) )
. NameContent ( )
[
SNew ( SHyperlink )
. Style ( FEditorStyle : : Get ( ) , " HoverOnlyHyperlink " )
. OnNavigate ( this , & FActorDetails : : OnNarrowSelectionSetToSpecificLevel , WeakLevelPtr )
. Text ( ActorCountDescription )
. TextStyle ( FEditorStyle : : Get ( ) , " DetailsView.HyperlinkStyle " )
. ToolTipText ( Tooltip )
]
. ValueContent ( )
[
SNew ( STextBlock )
. Text ( LevelDescription )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
] ;
}
2014-06-04 14:16:29 -04:00
// WorldSettings should never convert to another class type
if ( SelectedActorInfo . SelectionClass ! = AWorldSettings : : StaticClass ( ) & & SelectedActorInfo . HasConvertableAsset ( ) )
2014-03-14 14:13:41 -04:00
{
2014-06-04 14:16:29 -04:00
ActorCategory . AddCustomRow ( LOCTEXT ( " ConvertMenu " , " Convert " ) . ToString ( ) )
2014-03-14 14:13:41 -04:00
. NameContent ( )
2014-06-04 14:16:29 -04:00
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " ConvertButton " , " Convert Actor " ) )
. ToolTipText ( LOCTEXT ( " ConvertButton_ToolTip " , " Convert actors to different types " ) )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
]
. ValueContent ( )
2014-03-14 14:13:41 -04:00
[
MakeConvertMenu ( SelectedActorInfo )
] ;
}
}
void FActorDetails : : AddBlueprintCategory ( IDetailLayoutBuilder & DetailBuilder , const TMap < UBlueprint * , UObject * > & UniqueBlueprints )
{
// Create the overarching structure and expose the vertical box to add entries per-blueprint
TSharedPtr < SVerticalBox > Box ;
IDetailCategoryBuilder & BlueprintCategory = DetailBuilder . EditCategory ( " Blueprint " , NSLOCTEXT ( " BlueprintDetails " , " BlueprintTitle " , " Blueprint " ) . ToString ( ) , ECategoryPriority : : Uncommon ) ;
// Only show the blueprints section if a single actor is selected
if ( SelectedActors . Num ( ) > 0 )
{
// We don't need to replace the blueprints with a combined one unless the number of selected actors have
AddUtilityBlueprintRows ( BlueprintCategory ) ;
if ( UniqueBlueprints . Num ( ) > 0 )
{
// Add an edit row for each blueprint
for ( auto BlueprintIt ( UniqueBlueprints . CreateConstIterator ( ) ) ; BlueprintIt ; + + BlueprintIt )
{
UBlueprint * Blueprint = BlueprintIt . Key ( ) ;
UObject * Actor = BlueprintIt . Value ( ) ;
AddSingleBlueprintRow ( BlueprintCategory , Blueprint , Actor ) ;
}
}
else
{
AddSingleBlueprintRow ( BlueprintCategory , NULL , SelectedActors [ 0 ] . Get ( ) ) ;
}
}
}
void FActorDetails : : AddComponentsCategory ( IDetailLayoutBuilder & DetailBuilder )
{
AActor * SelectedActor = NULL ;
const TArray < TWeakObjectPtr < AActor > > & Actors = GetSelectedActors ( ) ;
if ( Actors . Num ( ) = = 1 & & Actors [ 0 ] . IsValid ( ) )
{
SelectedActor = Actors [ 0 ] . Get ( ) ;
}
DetailBuilder . EditCategory ( " Components " , NSLOCTEXT ( " ActorDetails " , " ComponentsSection " , " Components " ) . ToString ( ) , ECategoryPriority : : Uncommon )
. InitiallyCollapsed ( true )
. AddCustomRow ( NSLOCTEXT ( " ActorDetails " , " ComponentsSection " , " Components " ) . ToString ( ) )
[
SNew ( SComponentsTree , SelectedActor )
] ;
}
const TArray < TWeakObjectPtr < AActor > > & FActorDetails : : GetSelectedActors ( ) const
{
return SelectedActors ;
}
void FActorDetails : : AddUtilityBlueprintRows ( IDetailCategoryBuilder & BlueprintCategory )
{
if ( SelectedActors . Num ( ) = = 1 )
{
// Find In Level Blueprint
TWeakObjectPtr < AActor > ActorPtr = SelectedActors [ 0 ] ;
FText ActorLabel = NSLOCTEXT ( " UnrealEd " , " None " , " None " ) ;
if ( ActorPtr . IsValid ( ) )
{
ActorLabel = FText : : FromString ( ActorPtr . Get ( ) - > GetActorLabel ( ) ) ;
}
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ActorLabel " ) , ActorLabel ) ;
const FText FindButtonLabel = FText : : Format ( LOCTEXT ( " FindInLevelScript " , " Find {ActorLabel} in Level Blueprint " ) , Args ) ;
const FText FindButtonToolTip = FText : : Format ( LOCTEXT ( " FindInLevelScript_ToolTip " , " Search for uses of {ActorLabel} in the Level Blueprint " ) , Args ) ;
BlueprintCategory . AddCustomRow ( LOCTEXT ( " FindInLevelScript_Filter " , " Find in Level Script " ) . ToString ( ) )
. WholeRowContent ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 0 , 0 , 10 , 0 )
[
SNew ( SBox )
. WidthOverride ( 250 )
[
SNew ( SButton )
. ToolTipText ( FindButtonToolTip )
. OnClicked ( this , & FActorDetails : : FindSelectedActorsInLevelScript )
. IsEnabled ( this , & FActorDetails : : AreAnySelectedActorsInLevelScript )
. HAlign ( HAlign_Fill )
. ContentPadding ( 2 )
[
SNew ( STextBlock )
. Text ( FindButtonLabel )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
]
]
]
] ;
// Add Level Events
const FText AddEventLabel = FText : : Format ( LOCTEXT ( " ScriptingEvents " , " Add Level Events for {ActorLabel} " ) , Args ) ;
const FText AddEventToolTip = FText : : Format ( LOCTEXT ( " ScripingEvents_Tooltip " , " Adds or views events for {ActorLabel} in the Level Blueprint " ) , Args ) ;
BlueprintCategory . AddCustomRow ( LOCTEXT ( " ScriptingEvents_Filter " , " Level Blueprint Events " ) . ToString ( ) )
. WholeRowContent ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 0 , 0 , 10 , 0 )
[
SNew ( SBox )
. WidthOverride ( 250 )
[
SNew ( SComboButton )
. IsEnabled ( this , & FActorDetails : : IsActorValidForLevelScript )
. OnGetMenuContent ( this , & FActorDetails : : MakeEventOptionsWidgetFromSelection )
. ContentPadding ( 2 )
. HAlign ( HAlign_Fill )
. ButtonContent ( )
[
SNew ( STextBlock )
. Text ( AddEventLabel )
. ToolTipText ( AddEventToolTip )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
]
]
]
] ;
}
// Create the row for this blueprint
BlueprintCategory . AddCustomRow ( NSLOCTEXT ( " BlueprintDetails " , " BlueprintFilter " , " Blueprints " ) . ToString ( ) )
. WholeRowContent ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 0 , 0 , 10 , 0 )
[
SNew ( SBox )
. WidthOverride ( 250 )
[
SNew ( SButton )
. ToolTipText ( LOCTEXT ( " CreateHarvestBlueprint_ToolTip " , " Harvest Components from Selected Actors and create Blueprint " ) )
. HAlign ( HAlign_Fill )
//.ButtonColorAndOpacity( FLinearColor( 0.2f, 0.4f, 0.6f, 1.0f ) )
. OnClicked ( FOnClicked : : CreateRaw ( this , & FActorDetails : : OnPickBlueprintPathClicked , true ) )
. ContentPadding ( 2 )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " ReplaceWithAmalgamBlueprint " , " Replace With Composited Blueprint " ) )
]
]
]
] ;
}
// Creates a row for a single blueprint in the selection details view
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void FActorDetails : : AddSingleBlueprintRow ( IDetailCategoryBuilder & BlueprintCategory , UBlueprint * InBlueprint , UObject * InExampleActor )
{
TWeakObjectPtr < UBlueprint > WeakBP = InBlueprint ;
TWeakObjectPtr < UObject > WeakFirstAsset = InExampleActor ;
TAttribute < const FSlateBrush * > BlueprintStatusIcon ;
BlueprintStatusIcon . Bind ( FGetBrushImage : : CreateSP ( this , & FActorDetails : : GetBlueprintStatusIcon , WeakBP ) ) ;
TAttribute < FText > BlueprintStatusTooltip ;
BlueprintStatusTooltip . Bind ( FGetText : : CreateSP ( this , & FActorDetails : : GetBlueprintStatusTooltip , WeakBP ) ) ;
TAttribute < const FSlateBrush * > BreakpointStatusIcon ;
BreakpointStatusIcon . Bind ( FGetBrushImage : : CreateSP ( this , & FActorDetails : : GetBlueprintBreakpointStatusIcon , WeakBP ) ) ;
const FSlateFontInfo & InfoFont = FEditorStyle : : GetFontStyle ( TEXT ( " ExpandableArea.NormalFont " ) ) ;
FText Name , Description ;
if ( InBlueprint )
{
Name = FText : : FromString ( InBlueprint - > GetName ( ) ) ;
Description = FText : : FromString ( InBlueprint - > GetDesc ( ) ) ;
}
int NumBlueprintableActors = 0 ;
bool IsBlueprintBased = InBlueprint ? true : false ;
if ( ! InBlueprint )
{
for ( TWeakObjectPtr < AActor > & Actor : SelectedActors )
{
if ( FKismetEditorUtilities : : CanCreateBlueprintOfClass ( Actor - > GetClass ( ) ) )
{
NumBlueprintableActors + + ;
}
}
}
const bool bCanCreateActorBlueprint = ( ! IsBlueprintBased & & ( NumBlueprintableActors = = 1 ) ) ;
// Set up PathPickerConfig.
PathForActorBlueprint = FString ( " /Game/ " ) ;
FPathPickerConfig PathPickerConfig ;
PathPickerConfig . DefaultPath = PathForActorBlueprint ;
PathPickerConfig . OnPathSelected = FOnPathSelected : : CreateRaw ( this , & FActorDetails : : OnSelectBlueprintPath ) ;
FContentBrowserModule & ContentBrowserModule = FModuleManager : : LoadModuleChecked < FContentBrowserModule > ( " ContentBrowser " ) ;
FText CreateBlueprintToolTip = LOCTEXT ( " CreateBlueprintSuccess_ToolTip " , " Create a Blueprint based on this Actor " ) ;
if ( IsBlueprintBased )
{
CreateBlueprintToolTip = LOCTEXT ( " CreateBlueprintFail_ToolTip " , " Cannot create Blueprint using this Actor class " ) ;
}
else if ( ! IsBlueprintBased & & NumBlueprintableActors > 1 )
{
CreateBlueprintToolTip = LOCTEXT ( " CreateBlueprintFailTooMany_ToolTip " , " Cannot create Blueprint, please select only one Actor " ) ;
}
FString SelectedActorClassName ;
if ( NumBlueprintableActors = = 1 )
{
SelectedActorClassName = SelectedActors [ 0 ] - > GetClass ( ) - > GetName ( ) ;
}
FText CurrentBlueprintLong = FText : : Format ( FText : : FromString ( TEXT ( " {0} {1} " ) ) , Name , Description ) ;
// Blueprint Details
BlueprintCategory . AddCustomRow ( NSLOCTEXT ( " BlueprintDetails " , " BlueprintFilter " , " Blueprints " ) . ToString ( ) )
. Visibility ( InBlueprint ? EVisibility : : Visible : EVisibility : : Collapsed )
. NameContent ( )
[
SNew ( SHorizontalBox )
// Blueprint status icon
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. Padding ( 0.0f , 0.0f , 4.0f , 0.0f )
[
SNew ( SButton )
. OnClicked ( this , & FActorDetails : : OnCompileBlueprintClicked , WeakBP )
. ToolTipText ( BlueprintStatusTooltip )
. ButtonStyle ( FEditorStyle : : Get ( ) , " NoBorder " )
. ContentPadding ( 0.0f )
[
SNew ( SImage )
. Image ( BlueprintStatusIcon )
]
]
// Blueprint name
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Fill )
. Padding ( 0.0f , 0.0f , 4.0f , 0.0f )
[
SNew ( STextBlock )
. Font ( InfoFont )
. Text ( Name )
. ToolTipText ( CurrentBlueprintLong )
]
// Blueprint Description
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Fill )
. Padding ( 0.0f , 0.0f , 4.0f , 0.0f )
[
SNew ( STextBlock )
. Font ( InfoFont )
. ColorAndOpacity ( FSlateColor : : UseSubduedForeground ( ) )
. Text ( Description )
. ToolTipText ( CurrentBlueprintLong )
]
]
. ValueContent ( )
. MinDesiredWidth ( 200.0f )
. MaxDesiredWidth ( 200.0f )
[
SNew ( SHorizontalBox )
// Breakpoint enable/disable toggle and status button
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
. Padding ( 0.0f , 0.0f , 4.0f , 0.0f )
[
SNew ( SButton )
. OnClicked ( this , & FActorDetails : : OnToggleBreakpointsClicked , WeakBP )
. ToolTipText ( LOCTEXT ( " BlueprintBreakpointToggleAll_Tooltip " , " Toggle the enabled state of all breakpoints in this blueprint " ) )
. ButtonStyle ( FEditorStyle : : Get ( ) , " NoBorder " )
. ContentPadding ( 0.0f )
[
SNew ( SImage )
. Image ( BreakpointStatusIcon )
]
]
// Button for editing the blueprint
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SButton )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Center )
. IsEnabled ( InBlueprint ! = NULL )
. OnClicked ( this , & FActorDetails : : OnEditBlueprintClicked , WeakBP , WeakFirstAsset )
[
SNew ( STextBlock )
. Font ( InfoFont )
. Text ( LOCTEXT ( " EditAsset " , " Edit " ) )
]
]
// Button for pushing to Blueprint defaults
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SButton )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Center )
. IsEnabled ( this , & FActorDetails : : PushToBlueprintDefaults_IsEnabled , WeakBP )
. OnClicked ( this , & FActorDetails : : PushToBlueprintDefaults_OnClicked , WeakBP )
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip (
TAttribute < FText > : : Create ( TAttribute < FText > : : FGetter : : CreateRaw ( this , & FActorDetails : : PushToBlueprintDefaults_ToolTipText , WeakBP ) ) ,
NULL ,
TEXT ( " Shared/LevelEditor " ) ,
TEXT ( " PushToBlueprintDefaults " ) ) )
[
SNew ( STextBlock )
. Font ( InfoFont )
. Text ( LOCTEXT ( " PushToBlueprintDefaultsButtonLabel " , " Apply " ) )
]
]
// Button for resetting to Blueprint defaults
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SButton )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Center )
. IsEnabled ( this , & FActorDetails : : ResetToBlueprintDefaults_IsEnabled , WeakBP )
. OnClicked ( this , & FActorDetails : : ResetToBlueprintDefaults_OnClicked , WeakBP )
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip (
TAttribute < FText > : : Create ( TAttribute < FText > : : FGetter : : CreateRaw ( this , & FActorDetails : : ResetToBlueprintDefaults_ToolTipText , WeakBP ) ) ,
NULL ,
TEXT ( " Shared/LevelEditor " ) ,
TEXT ( " ResetToBlueprintDefaults " ) ) )
[
SNew ( STextBlock )
. Font ( InfoFont )
. Text ( LOCTEXT ( " ResetToBlueprintDefaultsButtonLabel " , " Reset " ) )
]
]
] ;
if ( ! InBlueprint )
{
BlueprintCategory . AddCustomRow ( LOCTEXT ( " CreateBlueprintFilterString " , " Create Blueprint " ) . ToString ( ) , true )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " NoBorder " ) )
. Padding ( 0 )
. ToolTipText ( CreateBlueprintToolTip )
[
SNew ( SButton )
. IsEnabled ( bCanCreateActorBlueprint )
. ButtonColorAndOpacity ( FLinearColor ( 0.2f , 0.4f , 0.6f , 1.0f ) )
. OnClicked ( FOnClicked : : CreateRaw ( this , & FActorDetails : : OnPickBlueprintPathClicked , false ) )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( STextBlock )
. Text ( FText : : Format ( LOCTEXT ( " CreateBlueprintFromActor " , " Create {0} Blueprint... " ) , FText : : FromString ( SelectedActorClassName ) ) )
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
. Padding ( 4.0f , 0.0f , 0.0f , 0.0f )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( TEXT ( " Kismet.CreateBlueprint " ) ) )
]
]
]
]
] ;
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
FReply FActorDetails : : OnPickBlueprintPathClicked ( bool bHarvest )
{
2014-05-12 08:38:45 -04:00
FCreateBlueprintFromActorDialog : : OpenDialog ( bHarvest ) ;
2014-03-14 14:13:41 -04:00
return FReply : : Handled ( ) ;
}
void FActorDetails : : OnSelectBlueprintPath ( const FString & Path )
{
PathForActorBlueprint = Path ;
}
FText FActorDetails : : GetBlueprintStatusTooltip ( TWeakObjectPtr < class UBlueprint > Asset ) const
{
if ( UBlueprint * Blueprint = Asset . Get ( ) )
{
switch ( Blueprint - > Status )
{
default :
case BS_Unknown :
case BS_Dirty :
return LOCTEXT ( " BlueprintStatus_Tooltip_Unknown " , " Blueprint may have been modified. Click to recompile. " ) ;
case BS_Error :
return LOCTEXT ( " BlueprintStatus_Tooltip_Error " , " Blueprint has one or more errors! " ) ;
case BS_UpToDate :
return LOCTEXT ( " BlueprintStatus_Tooltip_UpToDate " , " Blueprint is up to date. " ) ;
case BS_UpToDateWithWarnings :
return LOCTEXT ( " BlueprintStatus_Tooltip_Warning " , " Blueprint has one or more warnings! " ) ;
}
}
return FText : : GetEmpty ( ) ;
}
const FSlateBrush * FActorDetails : : GetBlueprintStatusIcon ( TWeakObjectPtr < class UBlueprint > Asset ) const
{
if ( UBlueprint * Blueprint = Asset . Get ( ) )
{
switch ( Blueprint - > Status )
{
default :
case BS_Unknown :
case BS_Dirty :
return FEditorStyle : : GetBrush ( " Kismet.Status.Unknown.Small " ) ;
case BS_Error :
return FEditorStyle : : GetBrush ( " Kismet.Status.Error.Small " ) ;
case BS_UpToDate :
return FEditorStyle : : GetBrush ( " Kismet.Status.Good.Small " ) ;
case BS_UpToDateWithWarnings :
return FEditorStyle : : GetBrush ( " Kismet.Status.Warning.Small " ) ;
}
}
return NULL ;
}
const FSlateBrush * FActorDetails : : GetBlueprintBreakpointStatusIcon ( TWeakObjectPtr < class UBlueprint > Asset ) const
{
if ( UBlueprint * Blueprint = Asset . Get ( ) )
{
const int32 TotalBreakpointCount = Blueprint - > Breakpoints . Num ( ) ;
// Count the number of enabled breakpoints
int32 EnabledCount = 0 ;
for ( int32 BreakpointIndex = 0 ; BreakpointIndex < TotalBreakpointCount ; + + BreakpointIndex )
{
UBreakpoint * & Breakpoint = Blueprint - > Breakpoints [ BreakpointIndex ] ;
if ( Breakpoint - > IsEnabledByUser ( ) )
{
+ + EnabledCount ;
}
}
if ( TotalBreakpointCount > 0 )
{
if ( EnabledCount = = TotalBreakpointCount )
{
// all are enabled
return FEditorStyle : : GetBrush ( " Kismet.Breakpoint.EnabledAndValid " ) ; //@TODO: Show enabled and invalid if not compiled?
}
else if ( EnabledCount = = 0 )
{
// none are enabled
return FEditorStyle : : GetBrush ( " Kismet.Breakpoint.Disabled " ) ;
}
else
{
// some are enabled but not all
return FEditorStyle : : GetBrush ( " Kismet.Breakpoint.MixedStatus " ) ; //@TODO: Show enabled and invalid if not compiled?
}
}
}
// show nothing, no breakpoints to care about
return FEditorStyle : : GetBrush ( " Kismet.Breakpoint.NoneSpacer " ) ;
}
FReply FActorDetails : : OnCompileBlueprintClicked ( TWeakObjectPtr < class UBlueprint > Asset )
{
if ( UBlueprint * Blueprint = Asset . Get ( ) )
{
if ( ! Blueprint - > IsUpToDate ( ) )
{
FKismetEditorUtilities : : CompileBlueprint ( Blueprint ) ;
}
}
return FReply : : Handled ( ) ;
}
FReply FActorDetails : : OnToggleBreakpointsClicked ( TWeakObjectPtr < class UBlueprint > Asset )
{
if ( UBlueprint * Blueprint = Asset . Get ( ) )
{
// Recompile the blueprint before trying to set a breakpoint if it's dirty or unknown and we're not in PIE/SIE
if ( ( ( Blueprint - > Status = = BS_Unknown ) | | ( Blueprint - > Status = = BS_Dirty ) ) & & ( GEditor - > PlayWorld = = NULL ) )
{
FKismetEditorUtilities : : CompileBlueprint ( Blueprint ) ;
}
// If the blueprint is still not up to date, don't modify the breakpoints
if ( ! Blueprint - > IsUpToDate ( ) )
{
return FReply : : Handled ( ) ;
}
const int32 TotalBreakpointCount = Blueprint - > Breakpoints . Num ( ) ;
// Count the number of enabled breakpoints
int32 EnabledCount = 0 ;
for ( int32 BreakpointIndex = 0 ; BreakpointIndex < TotalBreakpointCount ; + + BreakpointIndex )
{
UBreakpoint * & Breakpoint = Blueprint - > Breakpoints [ BreakpointIndex ] ;
if ( Breakpoint - > IsEnabledByUser ( ) )
{
+ + EnabledCount ;
}
}
if ( TotalBreakpointCount > 0 )
{
// Determine what the new state should be
bool bNewEnabledState = false ;
if ( EnabledCount = = TotalBreakpointCount )
{
// all are enabled; make them all disabled
bNewEnabledState = false ;
}
else if ( EnabledCount = = 0 )
{
// none are enabled; make them all enabled
bNewEnabledState = true ;
}
else
{
// some are enabled but not all; make them all enabled
bNewEnabledState = true ;
}
// Now make all the breakpoints enabled/disabled
for ( int32 BreakpointIndex = 0 ; BreakpointIndex < TotalBreakpointCount ; + + BreakpointIndex )
{
UBreakpoint * & Breakpoint = Blueprint - > Breakpoints [ BreakpointIndex ] ;
FKismetDebugUtilities : : SetBreakpointEnabled ( Breakpoint , bNewEnabledState ) ;
}
}
}
return FReply : : Handled ( ) ;
}
FReply FActorDetails : : OnEditBlueprintClicked ( TWeakObjectPtr < UBlueprint > InBlueprint , TWeakObjectPtr < UObject > InAsset )
{
if ( UBlueprint * Blueprint = InBlueprint . Get ( ) )
{
// Set the object being debugged if given an actor reference (if we don't do this before we edit the object the editor wont know we are debebugging something)
if ( UObject * Asset = InAsset . Get ( ) )
{
check ( Asset - > GetClass ( ) - > ClassGeneratedBy = = Blueprint ) ;
Blueprint - > SetObjectBeingDebugged ( Asset ) ;
}
// Open the blueprint
GEditor - > EditObject ( Blueprint ) ;
}
return FReply : : Handled ( ) ;
}
bool FActorDetails : : PushToBlueprintDefaults_IsEnabled ( TWeakObjectPtr < UBlueprint > InBlueprint ) const
{
bool bIsEnabled = false ;
if ( SelectedActors . Num ( ) = = 1 )
{
AActor * Actor = SelectedActors [ 0 ] . Get ( ) ;
UBlueprint * Blueprint = InBlueprint . Get ( ) ;
if ( Actor ! = NULL
& & Blueprint ! = NULL
& & Actor - > GetClass ( ) - > ClassGeneratedBy = = Blueprint )
{
AActor * BlueprintCDO = Actor - > GetClass ( ) - > GetDefaultObject < AActor > ( ) ;
if ( BlueprintCDO ! = NULL )
{
const auto CopyOptions = ( EditorUtilities : : ECopyOptions : : Type ) ( EditorUtilities : : ECopyOptions : : PreviewOnly | EditorUtilities : : ECopyOptions : : OnlyCopyEditOrInterpProperties ) ;
bIsEnabled = EditorUtilities : : CopyActorProperties ( Actor , BlueprintCDO , CopyOptions ) > 0 ;
}
}
}
return bIsEnabled ;
}
FText FActorDetails : : PushToBlueprintDefaults_ToolTipText ( TWeakObjectPtr < UBlueprint > InBlueprint ) const
{
int32 NumChangedProperties = 0 ;
if ( SelectedActors . Num ( ) = = 1 )
{
AActor * Actor = SelectedActors [ 0 ] . Get ( ) ;
UBlueprint * Blueprint = InBlueprint . Get ( ) ;
if ( Actor ! = NULL
& & Blueprint ! = NULL
& & Actor - > GetClass ( ) - > ClassGeneratedBy = = Blueprint )
{
AActor * BlueprintCDO = Actor - > GetClass ( ) - > GetDefaultObject < AActor > ( ) ;
if ( BlueprintCDO ! = NULL )
{
const auto CopyOptions = ( EditorUtilities : : ECopyOptions : : Type ) ( EditorUtilities : : ECopyOptions : : PreviewOnly | EditorUtilities : : ECopyOptions : : OnlyCopyEditOrInterpProperties ) ;
NumChangedProperties + = EditorUtilities : : CopyActorProperties ( Actor , BlueprintCDO , CopyOptions ) ;
}
}
}
if ( NumChangedProperties = = 0 )
{
return LOCTEXT ( " DisabledPushToBlueprintDefaults_ToolTip " , " Replaces the Blueprint's defaults with any altered property values. " ) ;
}
else if ( NumChangedProperties > 1 )
{
return FText : : Format ( LOCTEXT ( " PushToBlueprintDefaults_ToolTip " , " Click to apply {0} changed properties to the Blueprint. " ) , FText : : AsNumber ( NumChangedProperties ) ) ;
}
else
{
return LOCTEXT ( " PushOneToBlueprintDefaults_ToolTip " , " Click to apply 1 changed property to the Blueprint. " ) ;
}
}
FReply FActorDetails : : PushToBlueprintDefaults_OnClicked ( TWeakObjectPtr < UBlueprint > InBlueprint )
{
int32 NumChangedProperties = 0 ;
if ( SelectedActors . Num ( ) = = 1 )
{
const FScopedTransaction Transaction ( LOCTEXT ( " PushToBlueprintDefaults_Transaction " , " Apply Changes to Blueprint " ) ) ;
// Perform the actual copy
AActor * Actor = SelectedActors [ 0 ] . Get ( ) ;
UBlueprint * Blueprint = InBlueprint . Get ( ) ;
if ( Actor ! = NULL
& & Blueprint ! = NULL
& & Actor - > GetClass ( ) - > ClassGeneratedBy = = Blueprint )
{
AActor * BlueprintCDO = Actor - > GetClass ( ) - > GetDefaultObject < AActor > ( ) ;
if ( BlueprintCDO ! = NULL )
{
const auto CopyOptions = ( EditorUtilities : : ECopyOptions : : Type ) ( EditorUtilities : : ECopyOptions : : OnlyCopyEditOrInterpProperties | EditorUtilities : : ECopyOptions : : PropagateChangesToArcheypeInstances ) ;
NumChangedProperties = EditorUtilities : : CopyActorProperties ( Actor , BlueprintCDO , CopyOptions ) ;
if ( NumChangedProperties > 0 )
{
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
}
}
// Set up a notification record to indicate success/failure
FNotificationInfo NotificationInfo ( FText : : GetEmpty ( ) ) ;
NotificationInfo . FadeInDuration = 1.0f ;
NotificationInfo . FadeOutDuration = 2.0f ;
NotificationInfo . bUseLargeFont = false ;
SNotificationItem : : ECompletionState CompletionState ;
if ( NumChangedProperties > 0 )
{
if ( NumChangedProperties > 1 )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " BlueprintName " ) , FText : : FromName ( Blueprint - > GetFName ( ) ) ) ;
Args . Add ( TEXT ( " NumChangedProperties " ) , NumChangedProperties ) ;
Args . Add ( TEXT ( " ActorName " ) , FText : : FromString ( Actor - > GetActorLabel ( ) ) ) ;
NotificationInfo . Text = FText : : Format ( LOCTEXT ( " PushToBlueprintDefaults_ApplySuccess " , " Updated Blueprint {BlueprintName} ({NumChangedProperties} property changes applied from actor {ActorName}). " ) , Args ) ;
}
else
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " BlueprintName " ) , FText : : FromName ( Blueprint - > GetFName ( ) ) ) ;
Args . Add ( TEXT ( " ActorName " ) , FText : : FromString ( Actor - > GetActorLabel ( ) ) ) ;
NotificationInfo . Text = FText : : Format ( LOCTEXT ( " PushOneToBlueprintDefaults_ApplySuccess " , " Updated Blueprint {BlueprintName} (1 property change applied from actor {ActorName}). " ) , Args ) ;
}
CompletionState = SNotificationItem : : CS_Success ;
}
else
{
NotificationInfo . Text = LOCTEXT ( " PushToBlueprintDefaults_ApplyFailed " , " No properties were copied " ) ;
CompletionState = SNotificationItem : : CS_Fail ;
}
// Add the notification to the queue
const auto Notification = FSlateNotificationManager : : Get ( ) . AddNotification ( NotificationInfo ) ;
Notification - > SetCompletionState ( CompletionState ) ;
}
return FReply : : Handled ( ) ;
}
bool FActorDetails : : ResetToBlueprintDefaults_IsEnabled ( TWeakObjectPtr < UBlueprint > InBlueprint ) const
{
bool bIsEnabled = false ;
if ( SelectedActors . Num ( ) = = 1 )
{
AActor * Actor = SelectedActors [ 0 ] . Get ( ) ;
UBlueprint * Blueprint = InBlueprint . Get ( ) ;
if ( Actor ! = NULL
& & Blueprint ! = NULL
& & Actor - > GetClass ( ) - > ClassGeneratedBy = = Blueprint )
{
AActor * BlueprintCDO = Actor - > GetClass ( ) - > GetDefaultObject < AActor > ( ) ;
if ( BlueprintCDO ! = NULL )
{
const auto CopyOptions = ( EditorUtilities : : ECopyOptions : : Type ) ( EditorUtilities : : ECopyOptions : : PreviewOnly | EditorUtilities : : ECopyOptions : : OnlyCopyEditOrInterpProperties ) ;
bIsEnabled = EditorUtilities : : CopyActorProperties ( BlueprintCDO , Actor , CopyOptions ) > 0 ;
}
}
}
return bIsEnabled ;
}
FText FActorDetails : : ResetToBlueprintDefaults_ToolTipText ( TWeakObjectPtr < UBlueprint > InBlueprint ) const
{
int32 NumChangedProperties = 0 ;
if ( SelectedActors . Num ( ) = = 1 )
{
AActor * Actor = SelectedActors [ 0 ] . Get ( ) ;
UBlueprint * Blueprint = InBlueprint . Get ( ) ;
if ( Actor ! = NULL
& & Blueprint ! = NULL
& & Actor - > GetClass ( ) - > ClassGeneratedBy = = Blueprint )
{
AActor * BlueprintCDO = Actor - > GetClass ( ) - > GetDefaultObject < AActor > ( ) ;
if ( BlueprintCDO ! = NULL )
{
const auto CopyOptions = ( EditorUtilities : : ECopyOptions : : Type ) ( EditorUtilities : : ECopyOptions : : PreviewOnly | EditorUtilities : : ECopyOptions : : OnlyCopyEditOrInterpProperties ) ;
NumChangedProperties + = EditorUtilities : : CopyActorProperties ( BlueprintCDO , Actor , CopyOptions ) ;
}
}
}
if ( NumChangedProperties = = 0 )
{
return LOCTEXT ( " DisabledResetBlueprintDefaults_ToolTip " , " Resets altered properties back to their Blueprint default values. " ) ;
}
else if ( NumChangedProperties > 1 )
{
return FText : : Format ( LOCTEXT ( " ResetToBlueprintDefaults_ToolTip " , " Click to reset {0} changed properties to their Blueprint default values. " ) , FText : : AsNumber ( NumChangedProperties ) ) ;
}
else
{
return LOCTEXT ( " ResetOneToBlueprintDefaults_ToolTip " , " Click to reset 1 changed property to its Blueprint default value. " ) ;
}
}
FReply FActorDetails : : ResetToBlueprintDefaults_OnClicked ( TWeakObjectPtr < UBlueprint > InBlueprint )
{
int32 NumChangedProperties = 0 ;
if ( SelectedActors . Num ( ) = = 1 )
{
const FScopedTransaction Transaction ( LOCTEXT ( " ResetToBlueprintDefaults_Transaction " , " Reset to Blueprint Defaults " ) ) ;
// Perform the actual copy
AActor * Actor = SelectedActors [ 0 ] . Get ( ) ;
UBlueprint * Blueprint = InBlueprint . Get ( ) ;
if ( Actor ! = NULL
& & Blueprint ! = NULL
& & Actor - > GetClass ( ) - > ClassGeneratedBy = = Blueprint )
{
AActor * BlueprintCDO = Actor - > GetClass ( ) - > GetDefaultObject < AActor > ( ) ;
if ( BlueprintCDO ! = NULL )
{
const auto CopyOptions = ( EditorUtilities : : ECopyOptions : : Type ) ( EditorUtilities : : ECopyOptions : : OnlyCopyEditOrInterpProperties | EditorUtilities : : ECopyOptions : : CallPostEditChangeProperty ) ;
NumChangedProperties = EditorUtilities : : CopyActorProperties ( BlueprintCDO , Actor , CopyOptions ) ;
}
}
// Set up a notification record to indicate success/failure
FNotificationInfo NotificationInfo ( FText : : GetEmpty ( ) ) ;
NotificationInfo . FadeInDuration = 1.0f ;
NotificationInfo . FadeOutDuration = 2.0f ;
NotificationInfo . bUseLargeFont = false ;
SNotificationItem : : ECompletionState CompletionState ;
if ( NumChangedProperties > 0 )
{
if ( NumChangedProperties > 1 )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " BlueprintName " ) , FText : : FromName ( Blueprint - > GetFName ( ) ) ) ;
Args . Add ( TEXT ( " NumChangedProperties " ) , NumChangedProperties ) ;
Args . Add ( TEXT ( " ActorName " ) , FText : : FromString ( Actor - > GetActorLabel ( ) ) ) ;
NotificationInfo . Text = FText : : Format ( LOCTEXT ( " ResetToBlueprintDefaults_ApplySuccess " , " Reset {ActorName} ({NumChangedProperties} property changes applied from Blueprint {BlueprintName}). " ) , Args ) ;
}
else
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " BlueprintName " ) , FText : : FromName ( Blueprint - > GetFName ( ) ) ) ;
Args . Add ( TEXT ( " ActorName " ) , FText : : FromString ( Actor - > GetActorLabel ( ) ) ) ;
NotificationInfo . Text = FText : : Format ( LOCTEXT ( " ResetOneToBlueprintDefaults_ApplySuccess " , " Reset {ActorName} (1 property change applied from Blueprint {BlueprintName}). " ) , Args ) ;
}
CompletionState = SNotificationItem : : CS_Success ;
}
else
{
NotificationInfo . Text = LOCTEXT ( " ResetToBlueprintDefaults_Failed " , " No properties were reset " ) ;
CompletionState = SNotificationItem : : CS_Fail ;
}
// Add the notification to the queue
const auto Notification = FSlateNotificationManager : : Get ( ) . AddNotification ( NotificationInfo ) ;
Notification - > SetCompletionState ( CompletionState ) ;
}
return FReply : : Handled ( ) ;
}
# undef LOCTEXT_NAMESPACE