2019-12-26 15:33:43 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2018-02-22 11:25:06 -05:00
# include "PerPlatformPropertyCustomization.h"
# include "Widgets/DeclarativeSyntaxSupport.h"
# include "Engine/GameViewportClient.h"
# include "Widgets/SBoxPanel.h"
# include "Widgets/Layout/SSpacer.h"
# include "Widgets/Text/STextBlock.h"
# include "Widgets/Layout/SBox.h"
# include "Widgets/Input/SComboBox.h"
# include "Widgets/Images/SImage.h"
# include "DetailWidgetRow.h"
# include "Editor.h"
# include "PropertyHandle.h"
# include "DetailLayoutBuilder.h"
2019-05-17 08:58:49 -04:00
# include "PlatformInfo.h"
2018-02-22 11:25:06 -05:00
# include "ScopedTransaction.h"
2018-05-23 21:04:31 -04:00
# include "IPropertyUtilities.h"
2019-03-11 12:18:32 -04:00
# include "UObject/MetaData.h"
2020-11-17 12:45:35 -04:00
# include "Framework/MultiBox/MultiBoxBuilder.h"
# include "SPerPlatformPropertiesWidget.h"
2018-02-22 11:25:06 -05:00
2018-06-14 04:43:51 -04:00
# define LOCTEXT_NAMESPACE "PerPlatformPropertyCustomization"
2018-02-22 11:25:06 -05:00
template < typename PerPlatformType >
2020-11-17 12:45:35 -04:00
void FPerPlatformPropertyCustomization < PerPlatformType > : : CustomizeChildren ( TSharedRef < IPropertyHandle > StructPropertyHandle , IDetailChildrenBuilder & StructBuilder , IPropertyTypeCustomizationUtils & StructCustomizationUtils )
2018-02-22 11:25:06 -05:00
{
2018-05-23 21:04:31 -04:00
PropertyUtilities = StructCustomizationUtils . GetPropertyUtilities ( ) ;
2018-05-18 11:28:11 -04:00
int32 PlatformNumber = PlatformInfo : : GetAllPlatformGroupNames ( ) . Num ( ) ;
2020-11-17 12:45:35 -04:00
TAttribute < TArray < FName > > PlatformOverrideNames = TAttribute < TArray < FName > > : : Create ( TAttribute < TArray < FName > > : : FGetter : : CreateSP ( this , & FPerPlatformPropertyCustomization < PerPlatformType > : : GetPlatformOverrideNames , StructPropertyHandle ) ) ;
FPerPlatformPropertyCustomNodeBuilderArgs Args ;
2021-11-07 23:43:01 -05:00
Args . FilterText = StructPropertyHandle - > GetPropertyDisplayName ( ) ;
Args . OnGenerateNameWidget = FOnGetContent : : CreateLambda ( [ StructPropertyHandle ] ( )
{
return StructPropertyHandle - > CreatePropertyNameWidget ( ) ;
} ) ;
2020-11-17 12:45:35 -04:00
Args . PlatformOverrideNames = PlatformOverrideNames ;
Args . OnAddPlatformOverride = FOnPlatformOverrideAction : : CreateSP ( this , & FPerPlatformPropertyCustomization < PerPlatformType > : : AddPlatformOverride , StructPropertyHandle ) ;
Args . OnRemovePlatformOverride = FOnPlatformOverrideAction : : CreateSP ( this , & FPerPlatformPropertyCustomization < PerPlatformType > : : RemovePlatformOverride , StructPropertyHandle ) ;
Args . OnGenerateWidgetForPlatformRow = FOnGenerateWidget : : CreateSP ( this , & FPerPlatformPropertyCustomization < PerPlatformType > : : GetWidget , StructPropertyHandle ) ;
StructBuilder . AddCustomBuilder ( MakeShared < FPerPlatformPropertyCustomNodeBuilder > ( MoveTemp ( Args ) ) ) ;
2018-02-22 11:25:06 -05:00
}
2020-11-17 12:45:35 -04:00
2018-02-22 11:25:06 -05:00
template < typename PerPlatformType >
TSharedRef < SWidget > FPerPlatformPropertyCustomization < PerPlatformType > : : GetWidget ( FName PlatformGroupName , TSharedRef < IPropertyHandle > StructPropertyHandle ) const
{
TSharedPtr < IPropertyHandle > EditProperty ;
if ( PlatformGroupName = = NAME_None )
{
EditProperty = StructPropertyHandle - > GetChildHandle ( FName ( " Default " ) ) ;
}
else
{
TSharedPtr < IPropertyHandle > MapProperty = StructPropertyHandle - > GetChildHandle ( FName ( " PerPlatform " ) ) ;
if ( MapProperty . IsValid ( ) )
{
uint32 NumChildren = 0 ;
MapProperty - > GetNumChildren ( NumChildren ) ;
for ( uint32 ChildIdx = 0 ; ChildIdx < NumChildren ; ChildIdx + + )
{
TSharedPtr < IPropertyHandle > ChildProperty = MapProperty - > GetChildHandle ( ChildIdx ) ;
if ( ChildProperty . IsValid ( ) )
{
TSharedPtr < IPropertyHandle > KeyProperty = ChildProperty - > GetKeyHandle ( ) ;
if ( KeyProperty . IsValid ( ) )
{
FName KeyName ;
if ( KeyProperty - > GetValue ( KeyName ) = = FPropertyAccess : : Success & & KeyName = = PlatformGroupName )
{
EditProperty = ChildProperty ;
break ;
}
}
}
}
}
2019-03-11 12:18:32 -04:00
}
// Push down struct metadata to per-platform properties
{
// First get the source map
2019-12-13 11:07:03 -05:00
const TMap < FName , FString > * SourceMap = StructPropertyHandle - > GetMetaDataProperty ( ) - > GetMetaDataMap ( ) ;
// Iterate through source map, setting each key/value pair in the destination
for ( const auto & It : * SourceMap )
2019-03-11 12:18:32 -04:00
{
EditProperty - > SetInstanceMetaData ( * It . Key . ToString ( ) , * It . Value ) ;
}
2019-05-15 03:35:08 -04:00
// Copy instance metadata as well
const TMap < FName , FString > * InstanceSourceMap = StructPropertyHandle - > GetInstanceMetaDataMap ( ) ;
for ( const auto & It : * InstanceSourceMap )
{
EditProperty - > SetInstanceMetaData ( * It . Key . ToString ( ) , * It . Value ) ;
}
2018-02-22 11:25:06 -05:00
}
2020-11-17 12:45:35 -04:00
if ( ensure ( EditProperty . IsValid ( ) ) )
2018-02-22 11:25:06 -05:00
{
return EditProperty - > CreatePropertyValueWidget ( false ) ;
}
2020-11-17 12:45:35 -04:00
return SNullWidget : : NullWidget ;
2018-02-22 11:25:06 -05:00
}
template < typename PerPlatformType >
bool FPerPlatformPropertyCustomization < PerPlatformType > : : AddPlatformOverride ( FName PlatformGroupName , TSharedRef < IPropertyHandle > StructPropertyHandle )
{
2018-06-14 04:43:51 -04:00
FScopedTransaction Transaction ( LOCTEXT ( " AddPlatformOverride " , " Add Platform Override " ) ) ;
2018-02-22 11:25:06 -05:00
TSharedPtr < IPropertyHandle > PerPlatformProperty = StructPropertyHandle - > GetChildHandle ( FName ( " PerPlatform " ) ) ;
TSharedPtr < IPropertyHandle > DefaultProperty = StructPropertyHandle - > GetChildHandle ( FName ( " Default " ) ) ;
if ( PerPlatformProperty . IsValid ( ) & & DefaultProperty . IsValid ( ) )
{
TSharedPtr < IPropertyHandleMap > MapProperty = PerPlatformProperty - > AsMap ( ) ;
if ( MapProperty . IsValid ( ) )
{
MapProperty - > AddItem ( ) ;
uint32 NumChildren = 0 ;
PerPlatformProperty - > GetNumChildren ( NumChildren ) ;
for ( uint32 ChildIdx = 0 ; ChildIdx < NumChildren ; ChildIdx + + )
{
TSharedPtr < IPropertyHandle > ChildProperty = PerPlatformProperty - > GetChildHandle ( ChildIdx ) ;
if ( ChildProperty . IsValid ( ) )
{
TSharedPtr < IPropertyHandle > KeyProperty = ChildProperty - > GetKeyHandle ( ) ;
if ( KeyProperty . IsValid ( ) )
{
FName KeyName ;
if ( KeyProperty - > GetValue ( KeyName ) = = FPropertyAccess : : Success & & KeyName = = NAME_None )
{
// Set Key
KeyProperty - > SetValue ( PlatformGroupName ) ;
// Set Value
typename PerPlatformType : : ValueType DefaultValue ;
DefaultProperty - > GetValue ( DefaultValue ) ;
ChildProperty - > SetValue ( DefaultValue ) ;
2018-05-23 21:04:31 -04:00
2018-02-22 11:25:06 -05:00
return true ;
}
}
}
}
}
}
return false ;
}
template < typename PerPlatformType >
bool FPerPlatformPropertyCustomization < PerPlatformType > : : RemovePlatformOverride ( FName PlatformGroupName , TSharedRef < IPropertyHandle > StructPropertyHandle )
{
2018-06-14 04:43:51 -04:00
FScopedTransaction Transaction ( LOCTEXT ( " RemovePlatformOverride " , " Remove Platform Override " ) ) ;
2018-05-18 11:28:11 -04:00
TSharedPtr < IPropertyHandle > MapProperty = StructPropertyHandle - > GetChildHandle ( FName ( " PerPlatform " ) ) ;
if ( MapProperty . IsValid ( ) )
2018-02-22 11:25:06 -05:00
{
2018-05-18 11:28:11 -04:00
TArray < const void * > RawData ;
MapProperty - > AccessRawData ( RawData ) ;
for ( const void * Data : RawData )
2018-02-22 11:25:06 -05:00
{
2018-05-18 11:28:11 -04:00
TMap < FName , typename PerPlatformType : : ValueType > * PerPlatformMap = ( TMap < FName , typename PerPlatformType : : ValueType > * ) ( Data ) ;
check ( PerPlatformMap ) ;
TArray < FName > KeyArray ;
PerPlatformMap - > GenerateKeyArray ( KeyArray ) ;
for ( FName PlatformName : KeyArray )
2018-02-22 11:25:06 -05:00
{
2018-05-18 11:28:11 -04:00
if ( PlatformName = = PlatformGroupName )
2018-02-22 11:25:06 -05:00
{
2018-05-18 11:28:11 -04:00
PerPlatformMap - > Remove ( PlatformName ) ;
2018-05-29 13:32:01 -04:00
2018-05-18 11:28:11 -04:00
return true ;
2018-02-22 11:25:06 -05:00
}
}
}
}
return false ;
2018-05-18 11:28:11 -04:00
2018-02-22 11:25:06 -05:00
}
template < typename PerPlatformType >
TArray < FName > FPerPlatformPropertyCustomization < PerPlatformType > : : GetPlatformOverrideNames ( TSharedRef < IPropertyHandle > StructPropertyHandle ) const
{
TArray < FName > PlatformOverrideNames ;
TSharedPtr < IPropertyHandle > MapProperty = StructPropertyHandle - > GetChildHandle ( FName ( " PerPlatform " ) ) ;
if ( MapProperty . IsValid ( ) )
{
TArray < const void * > RawData ;
MapProperty - > AccessRawData ( RawData ) ;
for ( const void * Data : RawData )
{
const TMap < FName , typename PerPlatformType : : ValueType > * PerPlatformMap = ( const TMap < FName , typename PerPlatformType : : ValueType > * ) ( Data ) ;
check ( PerPlatformMap ) ;
TArray < FName > KeyArray ;
PerPlatformMap - > GenerateKeyArray ( KeyArray ) ;
for ( FName PlatformName : KeyArray )
{
PlatformOverrideNames . AddUnique ( PlatformName ) ;
}
}
}
return PlatformOverrideNames ;
}
template < typename PerPlatformType >
TSharedRef < IPropertyTypeCustomization > FPerPlatformPropertyCustomization < PerPlatformType > : : MakeInstance ( )
{
return MakeShareable ( new FPerPlatformPropertyCustomization < PerPlatformType > ) ;
}
/* Only explicitly instantiate the types which are supported
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
template class FPerPlatformPropertyCustomization < FPerPlatformInt > ;
template class FPerPlatformPropertyCustomization < FPerPlatformFloat > ;
2018-11-19 07:03:18 -05:00
template class FPerPlatformPropertyCustomization < FPerPlatformBool > ;
2018-02-22 11:25:06 -05:00
2020-11-17 12:45:35 -04:00
# undef LOCTEXT_NAMESPACE
void FPerPlatformPropertyCustomNodeBuilder : : SetOnRebuildChildren ( FSimpleDelegate InOnRegenerateChildren )
{
OnRebuildChildren = InOnRegenerateChildren ;
}
void FPerPlatformPropertyCustomNodeBuilder : : SetOnToggleExpansion ( FOnToggleNodeExpansion InOnToggleExpansion )
{
OnToggleExpansion = InOnToggleExpansion ;
}
void FPerPlatformPropertyCustomNodeBuilder : : GenerateHeaderRowContent ( FDetailWidgetRow & HeaderRow )
{
// Build Platform menu
FMenuBuilder AddPlatformMenuBuilder ( true , nullptr , nullptr , true ) ;
// Platform (group) names
const TArray < FName > & PlatformGroupNameArray = PlatformInfo : : GetAllPlatformGroupNames ( ) ;
const TArray < FName > & VanillaPlatformNameArray = PlatformInfo : : GetAllVanillaPlatformNames ( ) ;
// Sanitized platform names
TArray < FName > BasePlatformNameArray ;
// Mapping from platform group name to individual platforms
TMultiMap < FName , FName > GroupToPlatform ;
TArray < FName > PlatformOverrides = Args . PlatformOverrideNames . Get ( ) ;
// Create mapping from platform to platform groups and remove postfixes and invalid platform names
for ( const FName & PlatformName : VanillaPlatformNameArray )
{
// Add platform name if it isn't already set, and also add to group mapping
if ( ! PlatformOverrides . Contains ( PlatformName ) )
{
BasePlatformNameArray . AddUnique ( PlatformName ) ;
GroupToPlatform . AddUnique ( PlatformInfo : : FindPlatformInfo ( PlatformName ) - > DataDrivenPlatformInfo - > PlatformGroupName , PlatformName ) ;
}
}
// Create section for platform groups
const FName PlatformGroupSection ( TEXT ( " PlatformGroupSection " ) ) ;
AddPlatformMenuBuilder . BeginSection ( PlatformGroupSection , FText : : FromString ( TEXT ( " Platform Groups " ) ) ) ;
for ( const FName & GroupName : PlatformGroupNameArray )
{
if ( ! PlatformOverrides . Contains ( GroupName ) )
{
const FTextFormat Format = NSLOCTEXT ( " SPerPlatformPropertiesWidget " , " AddOverrideGroupFor " , " Add Override for Platforms part of the {0} Platform Group " ) ;
AddPlatformToMenu ( GroupName , Format , AddPlatformMenuBuilder ) ;
}
}
AddPlatformMenuBuilder . EndSection ( ) ;
for ( const FName & GroupName : PlatformGroupNameArray )
{
// Create a section for each platform group and their respective platforms
AddPlatformMenuBuilder . BeginSection ( GroupName , FText : : FromName ( GroupName ) ) ;
TArray < FName > PlatformNames ;
GroupToPlatform . MultiFind ( GroupName , PlatformNames ) ;
const FTextFormat Format = NSLOCTEXT ( " SPerPlatformPropertiesWidget " , " AddOverrideFor " , " Add Override specifically for {0} " ) ;
for ( const FName & PlatformName : PlatformNames )
{
AddPlatformToMenu ( PlatformName , Format , AddPlatformMenuBuilder ) ;
}
AddPlatformMenuBuilder . EndSection ( ) ;
}
2021-11-07 23:43:01 -05:00
HeaderRow
. FilterString ( Args . FilterText )
. IsEnabled ( Args . IsEnabled )
. NameContent ( )
2020-11-17 12:45:35 -04:00
[
2021-11-07 23:43:01 -05:00
Args . OnGenerateNameWidget . Execute ( )
2020-11-17 12:45:35 -04:00
]
. ValueContent ( )
. MinDesiredWidth ( 125 + 28.0f )
[
SNew ( SHorizontalBox )
. ToolTipText ( NSLOCTEXT ( " SPerPlatformPropertiesWidget " , " DefaultPlatformDesc " , " This property can have per-platform or platform group overrides. \n This is the default value used when no override has been set for a platform or platform group. " ) )
+ SHorizontalBox : : Slot ( )
[
SNew ( SPerPlatformPropertiesRow , NAME_None )
. OnGenerateWidget ( Args . OnGenerateWidgetForPlatformRow )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 2.0f , 0.0f , 0.0f , 0.0f )
. VAlign ( VAlign_Center )
[
SNew ( SComboButton )
2022-05-09 13:12:28 -04:00
. ComboButtonStyle ( FAppStyle : : Get ( ) , " SimpleComboButton " )
2020-11-17 12:45:35 -04:00
. HasDownArrow ( false )
. ToolTipText ( NSLOCTEXT ( " SPerPlatformPropertiesWidget " , " AddOverrideToolTip " , " Add an override for a specific platform or platform group " ) )
. ButtonContent ( )
[
SNew ( SImage )
2022-05-09 13:12:28 -04:00
. Image ( FAppStyle : : GetBrush ( " Icons.PlusCircle " ) )
2020-11-17 12:45:35 -04:00
. ColorAndOpacity ( FSlateColor : : UseForeground ( ) )
]
. MenuContent ( )
[
AddPlatformMenuBuilder . MakeWidget ( )
]
]
] ;
}
void FPerPlatformPropertyCustomNodeBuilder : : GenerateChildContent ( IDetailChildrenBuilder & ChildrenBuilder )
{
TArray < FName > PlatformOverrides = Args . PlatformOverrideNames . Get ( ) ;
for ( FName PlatformName : PlatformOverrides )
{
FText PlatformDisplayName = FText : : AsCultureInvariant ( PlatformName . ToString ( ) ) ;
FDetailWidgetRow & Row = ChildrenBuilder . AddCustomRow ( PlatformDisplayName ) ;
Row . IsEnabled ( Args . IsEnabled ) ;
Row . NameContent ( )
[
SNew ( STextBlock )
. Text ( PlatformDisplayName )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
] ;
Row . ValueContent ( )
[
SNew ( SPerPlatformPropertiesRow , PlatformName )
. OnGenerateWidget ( Args . OnGenerateWidgetForPlatformRow )
. OnRemovePlatform ( this , & FPerPlatformPropertyCustomNodeBuilder : : OnRemovePlatformOverride )
] ;
}
}
FName FPerPlatformPropertyCustomNodeBuilder : : GetName ( ) const
{
2021-12-10 20:34:26 -05:00
return Args . Name ;
2020-11-17 12:45:35 -04:00
}
void FPerPlatformPropertyCustomNodeBuilder : : OnAddPlatformOverride ( const FName PlatformName )
{
if ( Args . OnAddPlatformOverride . IsBound ( ) & & Args . OnAddPlatformOverride . Execute ( PlatformName ) )
{
OnRebuildChildren . ExecuteIfBound ( ) ;
OnToggleExpansion . ExecuteIfBound ( true ) ;
}
}
bool FPerPlatformPropertyCustomNodeBuilder : : OnRemovePlatformOverride ( const FName PlatformName )
{
if ( Args . OnRemovePlatformOverride . IsBound ( ) & & Args . OnRemovePlatformOverride . Execute ( PlatformName ) )
{
OnRebuildChildren . ExecuteIfBound ( ) ;
}
return true ;
}
void FPerPlatformPropertyCustomNodeBuilder : : AddPlatformToMenu ( const FName PlatformName , const FTextFormat Format , FMenuBuilder & AddPlatformMenuBuilder )
{
const FText MenuText = FText : : Format ( FText : : FromString ( TEXT ( " {0} " ) ) , FText : : AsCultureInvariant ( PlatformName . ToString ( ) ) ) ;
const FText MenuTooltipText = FText : : Format ( Format , FText : : AsCultureInvariant ( PlatformName . ToString ( ) ) ) ;
AddPlatformMenuBuilder . AddMenuEntry (
MenuText ,
MenuTooltipText ,
2022-05-09 13:12:28 -04:00
FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " PerPlatformWidget.AddPlatform " ) ,
2020-11-17 12:45:35 -04:00
FUIAction ( FExecuteAction : : CreateSP ( this , & FPerPlatformPropertyCustomNodeBuilder : : OnAddPlatformOverride , PlatformName ) )
) ;
}