2021-09-22 20:15:55 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "CustomPrimitiveDataCustomization.h"
# include "Widgets/Layout/SBox.h"
# include "Widgets/Text/STextBlock.h"
# include "Widgets/Input/SHyperlink.h"
2021-12-14 19:40:18 -05:00
# include "Widgets/Images/SImage.h"
2021-09-22 20:15:55 -04:00
# include "Widgets/Colors/SColorPicker.h"
# include "Widgets/Colors/SColorBlock.h"
# include "SlateOptMacros.h"
2022-05-09 13:31:58 -04:00
# include "Styling/AppStyle.h"
2021-09-22 20:15:55 -04:00
# include "IDetailGroup.h"
# include "IDetailPropertyRow.h"
# include "IPropertyTypeCustomization.h"
# include "IPropertyUtilities.h"
# include "PropertyCustomizationHelpers.h"
# include "Materials/MaterialInstance.h"
# include "Materials/MaterialExpressionScalarParameter.h"
# include "Materials/MaterialExpressionVectorParameter.h"
# include "IMaterialEditor.h"
2021-09-28 05:31:56 -04:00
# include "Components/PrimitiveComponent.h"
# include "Components/MeshComponent.h"
# include "Components/TextRenderComponent.h"
2021-09-22 20:15:55 -04:00
# define LOCTEXT_NAMESPACE "CustomPrimitiveDataCustomization"
TSharedRef < IPropertyTypeCustomization > FCustomPrimitiveDataCustomization : : MakeInstance ( )
{
return MakeShareable ( new FCustomPrimitiveDataCustomization ) ;
}
2021-10-20 23:18:42 -04:00
FCustomPrimitiveDataCustomization : : FCustomPrimitiveDataCustomization ( )
{
// NOTE: Optimally would be bound to a "OnMaterialChanged" for each component
FCoreUObjectDelegates : : OnObjectPropertyChanged . AddRaw ( this , & FCustomPrimitiveDataCustomization : : OnObjectPropertyChanged ) ;
UMaterial : : OnMaterialCompilationFinished ( ) . AddRaw ( this , & FCustomPrimitiveDataCustomization : : OnMaterialCompiled ) ;
}
2021-09-22 20:15:55 -04:00
FCustomPrimitiveDataCustomization : : ~ FCustomPrimitiveDataCustomization ( )
{
Cleanup ( ) ;
2021-10-20 23:18:42 -04:00
FCoreUObjectDelegates : : OnObjectPropertyChanged . RemoveAll ( this ) ;
UMaterial : : OnMaterialCompilationFinished ( ) . RemoveAll ( this ) ;
2021-09-22 20:15:55 -04:00
}
void FCustomPrimitiveDataCustomization : : CustomizeHeader ( TSharedRef < IPropertyHandle > PropertyHandle , FDetailWidgetRow & HeaderRow , IPropertyTypeCustomizationUtils & CustomizationUtils )
{
TSharedPtr < IPropertyHandle > DataProperty = PropertyHandle - > GetChildHandle ( " Data " ) ;
// Move the data array to be the outer, so we don't have to expand the struct
HeaderRow . NameContent ( )
[
PropertyHandle - > CreatePropertyNameWidget ( )
]
. ValueContent ( )
[
DataProperty - > CreatePropertyValueWidget ( )
] ;
}
void FCustomPrimitiveDataCustomization : : CustomizeChildren ( TSharedRef < IPropertyHandle > PropertyHandle , IDetailChildrenBuilder & ChildBuilder , IPropertyTypeCustomizationUtils & CustomizationUtils )
{
Cleanup ( ) ;
PropertyUtils = CustomizationUtils . GetPropertyUtilities ( ) ;
2021-09-29 02:23:42 -04:00
DataHandle = PropertyHandle - > GetChildHandle ( " Data " ) ;
DataArrayHandle = DataHandle - > AsArray ( ) ;
2021-09-22 20:15:55 -04:00
int32 MaxPrimitiveDataIndex = INDEX_NONE ;
ForEachSelectedComponent ( [ & ] ( UPrimitiveComponent * Component )
{
PopulateParameterData ( Component , MaxPrimitiveDataIndex ) ;
} ) ;
uint32 NumElements ;
2021-09-29 02:23:42 -04:00
FPropertyAccess : : Result AccessResult = GetNumElements ( NumElements ) ;
2021-09-22 20:15:55 -04:00
2021-10-20 23:18:42 -04:00
FSimpleDelegate OnElemsChanged = FSimpleDelegate : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : RequestRefresh ) ;
2021-09-22 20:15:55 -04:00
DataArrayHandle - > SetOnNumElementsChanged ( OnElemsChanged ) ;
2021-10-20 23:18:42 -04:00
DataHandle - > SetOnPropertyValueChanged ( FSimpleDelegate : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : OnElementsModified , AccessResult , NumElements ) ) ;
2021-09-22 20:15:55 -04:00
const int32 NumPrimitiveIndices = FMath : : Max ( MaxPrimitiveDataIndex + 1 , ( int32 ) NumElements ) ;
if ( NumPrimitiveIndices = = 0 )
{
return ;
}
2021-09-29 02:23:42 -04:00
// We're only editable if the property is editable and if we're not a multi-selection situation
const bool bDataEditable = DataHandle . IsValid ( ) & & DataHandle - > IsEditable ( ) & & AccessResult = = FPropertyAccess : : Success ;
2021-09-22 20:15:55 -04:00
uint8 VectorGroupPrimIdx = 0 ;
IDetailGroup * VectorGroup = NULL ;
for ( uint8 PrimIdx = 0 ; PrimIdx < NumPrimitiveIndices ; + + PrimIdx )
{
TSharedPtr < IPropertyHandle > ElementHandle = PrimIdx < NumElements ? TSharedPtr < IPropertyHandle > ( DataArrayHandle - > GetElement ( PrimIdx ) ) : NULL ;
if ( VectorGroup & & ( PrimIdx - VectorGroupPrimIdx ) > 3 )
{
// We're no longer in a vector group
VectorGroup = NULL ;
}
2021-09-23 18:47:22 -04:00
// Always prioritize the first vector found, and only if it's the first element of the vector
2021-09-22 20:15:55 -04:00
if ( VectorGroup = = NULL & & VectorParameterData . Contains ( PrimIdx ) )
{
2021-09-23 18:47:22 -04:00
bool bContainsFirstElementOfVector = false ;
for ( const FParameterData & ParameterData : VectorParameterData [ PrimIdx ] )
{
if ( ParameterData . IndexOffset = = 0 )
{
bContainsFirstElementOfVector = true ;
break ;
}
}
if ( bContainsFirstElementOfVector )
{
// Create a collapsing group that contains our color picker, so we can quickly assign colors to our vector
VectorGroupPrimIdx = PrimIdx ;
2021-12-14 19:40:18 -05:00
VectorGroup = CreateVectorGroup ( ChildBuilder , PrimIdx , bDataEditable , NumElements , CustomizationUtils ) ;
2021-09-23 18:47:22 -04:00
}
2021-09-22 20:15:55 -04:00
}
if ( ScalarParameterData . Contains ( PrimIdx ) | | VectorParameterData . Contains ( PrimIdx ) )
{
2021-12-14 19:40:18 -05:00
CreateParameterRow ( ChildBuilder , PrimIdx , ElementHandle , bDataEditable , VectorGroup , CustomizationUtils ) ;
2021-09-22 20:15:55 -04:00
}
else
{
2021-09-28 09:07:40 -04:00
// We've encountered a gap in declared custom primitive data, mark it undeclared
TSharedRef < SWidget > UndeclaredWidget = GetUndeclaredParameterWidget ( PrimIdx , CustomizationUtils ) ;
TSharedRef < SWidget > NameWidget = CreateNameWidget ( PrimIdx , UndeclaredWidget , CustomizationUtils ) ;
2021-09-22 20:15:55 -04:00
if ( ElementHandle . IsValid ( ) )
{
ChildBuilder . AddProperty ( ElementHandle . ToSharedRef ( ) )
. CustomWidget ( )
. NameContent ( )
2021-12-14 19:40:18 -05:00
. HAlign ( HAlign_Fill )
2021-09-22 20:15:55 -04:00
[
NameWidget
]
. ValueContent ( )
[
ElementHandle - > CreatePropertyValueWidget ( false )
]
. IsEnabled ( bDataEditable ) ; ;
}
else
{
ChildBuilder . AddCustomRow ( FText : : AsNumber ( PrimIdx ) )
. NameContent ( )
2021-12-14 19:40:18 -05:00
. HAlign ( HAlign_Fill )
2021-09-22 20:15:55 -04:00
[
NameWidget
]
. IsEnabled ( bDataEditable ) ;
}
}
}
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
2021-12-14 19:40:18 -05:00
IDetailGroup * FCustomPrimitiveDataCustomization : : CreateVectorGroup ( IDetailChildrenBuilder & ChildBuilder , uint8 PrimIdx , bool bDataEditable , int32 NumElements , IPropertyTypeCustomizationUtils & CustomizationUtils )
2021-09-22 20:15:55 -04:00
{
IDetailGroup * VectorGroup = & ChildBuilder . AddGroup ( VectorParameterData [ PrimIdx ] [ 0 ] . Info . Name , FText : : FromName ( VectorParameterData [ PrimIdx ] [ 0 ] . Info . Name ) ) ;
TSharedPtr < SColorBlock > ColorBlock ;
TSharedPtr < SVerticalBox > VectorGroupNameBox = SNew ( SVerticalBox ) ;
// Use this to make sure we don't make duplicate parameters for the group header
TSet < FGuid > AddedParametersForThisGroup ;
2021-12-14 19:40:18 -05:00
TSet < FName > ParameterNames ;
TSet < TSoftObjectPtr < UMaterialInterface > > Materials ;
2021-09-22 20:15:55 -04:00
for ( const FParameterData & ParameterData : VectorParameterData [ PrimIdx ] )
{
if ( AddedParametersForThisGroup . Contains ( ParameterData . ExpressionID ) )
{
continue ;
}
2021-12-14 19:40:18 -05:00
Materials . Add ( ParameterData . Material - > GetMaterial ( ) ) ;
2021-09-22 20:15:55 -04:00
AddedParametersForThisGroup . Add ( ParameterData . ExpressionID ) ;
2021-12-14 19:40:18 -05:00
ParameterNames . Add ( ParameterData . Info . Name ) ;
2021-09-22 20:15:55 -04:00
2021-09-28 09:07:40 -04:00
TSharedRef < SHyperlink > Hyperlink = CreateHyperlink ( FText : : FromName ( ParameterData . Info . Name ) , ParameterData . Material , ParameterData . ExpressionID ) ;
Hyperlink - > SetToolTipText ( LOCTEXT ( " VectorHyperlinkTooltip " , " Jump to Vector Parameter " ) ) ;
2021-09-22 20:15:55 -04:00
VectorGroupNameBox - > AddSlot ( )
. Padding ( 2.f )
[
2021-09-28 09:07:40 -04:00
Hyperlink
2021-09-22 20:15:55 -04:00
] ;
}
2021-12-14 19:40:18 -05:00
if ( MaterialsToWatch . Num ( ) ! = Materials . Num ( ) )
{
// Some materials aren't defining parameters at this index, add the undeclared parameter widget in case this was user error
VectorGroupNameBox - > AddSlot ( )
. Padding ( 2.f )
[
GetUndeclaredParameterWidget ( PrimIdx , CustomizationUtils )
] ;
}
TSharedPtr < SWidget > NameContent ;
if ( ParameterNames . Num ( ) > 1 )
{
NameContent = CreateWarningWidget ( VectorGroupNameBox . ToSharedRef ( ) , LOCTEXT ( " OverlappingVectorParameters " , " Primitive index has overlapping parameter names declared, make sure vector names match to remove warning " ) ) ;
}
else
{
NameContent = VectorGroupNameBox ;
}
2021-09-22 20:15:55 -04:00
VectorGroup - > HeaderRow ( )
. NameContent ( )
2021-12-14 19:40:18 -05:00
. HAlign ( HAlign_Fill )
2021-09-22 20:15:55 -04:00
[
2021-12-14 19:40:18 -05:00
NameContent . ToSharedRef ( )
2021-09-22 20:15:55 -04:00
]
. ValueContent ( )
[
SNew ( SHorizontalBox )
. IsEnabled ( bDataEditable )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. Padding ( 0.f , 2.f )
[
SAssignNew ( ColorBlock , SColorBlock )
. Color ( this , & FCustomPrimitiveDataCustomization : : GetVectorColor , PrimIdx )
. ShowBackgroundForAlpha ( true )
. AlphaDisplayMode ( EColorBlockAlphaDisplayMode : : Separate )
. OnMouseButtonDown ( this , & FCustomPrimitiveDataCustomization : : OnMouseButtonDownColorBlock , PrimIdx )
. Size ( FVector2D ( 35.0f , 12.0f ) )
. Visibility ( PrimIdx < NumElements ? EVisibility : : Visible : EVisibility : : Collapsed )
]
+ SHorizontalBox : : Slot ( )
. Padding ( 2.0f )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
PropertyCustomizationHelpers : : MakeAddButton ( FSimpleDelegate : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : OnAddedDesiredPrimitiveData , ( uint8 ) ( PrimIdx + 3 ) ) , FText ( ) , ( int32 ) NumElements < PrimIdx + 4 )
]
+ SHorizontalBox : : Slot ( )
. Padding ( 2.0f )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
PropertyCustomizationHelpers : : MakeEmptyButton ( FSimpleDelegate : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : OnRemovedPrimitiveData , PrimIdx ) , LOCTEXT ( " RemoveVector " , " Removes this vector (and anything after) " ) , ( int32 ) PrimIdx < NumElements )
]
+ SHorizontalBox : : Slot ( )
. Padding ( 2.0f )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
PropertyCustomizationHelpers : : MakeResetButton ( FSimpleDelegate : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : SetDefaultVectorValue , PrimIdx ) , FText ( ) , ( int32 ) PrimIdx < NumElements )
]
] ;
ColorBlocks . Add ( PrimIdx , ColorBlock ) ;
return VectorGroup ;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
2021-12-14 19:40:18 -05:00
void FCustomPrimitiveDataCustomization : : CreateParameterRow ( IDetailChildrenBuilder & ChildBuilder , uint8 PrimIdx , TSharedPtr < IPropertyHandle > ElementHandle , bool bDataEditable , IDetailGroup * VectorGroup , IPropertyTypeCustomizationUtils & CustomizationUtils )
2021-09-22 20:15:55 -04:00
{
// Use this to make sure we don't make duplicate parameters in each row
TSet < FGuid > AddedParametersForThisRow ;
TArray < FText > SearchText ;
TSharedPtr < SVerticalBox > VerticalBox = SNew ( SVerticalBox ) ;
2021-12-14 19:40:18 -05:00
TSet < UMaterial * > Materials ;
TSet < FName > ParameterNames ;
2021-09-22 20:15:55 -04:00
if ( VectorParameterData . Contains ( PrimIdx ) )
{
for ( const FParameterData & ParameterData : VectorParameterData [ PrimIdx ] )
{
if ( AddedParametersForThisRow . Contains ( ParameterData . ExpressionID ) )
{
continue ;
}
2021-12-14 19:40:18 -05:00
Materials . Add ( ParameterData . Material - > GetMaterial ( ) ) ;
2021-09-22 20:15:55 -04:00
AddedParametersForThisRow . Add ( ParameterData . ExpressionID ) ;
FMaterialParameterMetadata ParameterMetadata ;
ParameterData . Material - > GetParameterDefaultValue ( EMaterialParameterType : : Vector , ParameterData . Info , ParameterMetadata ) ;
FText ChannelName ;
switch ( ParameterData . IndexOffset )
{
case 0 :
ChannelName = ParameterMetadata . ChannelNames . R . IsEmpty ( ) ? LOCTEXT ( " DefaultVectorChannelRed " , " R " ) : ParameterMetadata . ChannelNames . R ;
2021-09-22 21:12:05 -04:00
break ;
2021-09-22 20:15:55 -04:00
case 1 :
ChannelName = ParameterMetadata . ChannelNames . G . IsEmpty ( ) ? LOCTEXT ( " DefaultVectorChannelGreen " , " G " ) : ParameterMetadata . ChannelNames . G ;
2021-09-22 21:12:05 -04:00
break ;
2021-09-22 20:15:55 -04:00
case 2 :
ChannelName = ParameterMetadata . ChannelNames . B . IsEmpty ( ) ? LOCTEXT ( " DefaultVectorChannelBlue " , " B " ) : ParameterMetadata . ChannelNames . B ;
2021-09-22 21:12:05 -04:00
break ;
2021-09-22 20:15:55 -04:00
case 3 :
ChannelName = ParameterMetadata . ChannelNames . A . IsEmpty ( ) ? LOCTEXT ( " DefaultVectorChannelAlpha " , " A " ) : ParameterMetadata . ChannelNames . A ;
2021-09-22 21:12:05 -04:00
break ;
2021-09-22 20:15:55 -04:00
default :
checkNoEntry ( ) ;
break ;
}
2021-12-14 19:40:18 -05:00
ParameterNames . Add ( * ChannelName . ToString ( ) ) ;
const FText ParameterNameText = FText : : FromName ( ParameterData . Info . Name ) ;
2021-09-22 20:15:55 -04:00
const FText ParameterName = FText : : Format (
LOCTEXT ( " VectorParameterName " , " {0}.{1} " ) ,
2021-12-14 19:40:18 -05:00
ParameterNameText ,
2021-09-22 20:15:55 -04:00
ChannelName
) ;
2021-09-28 09:07:40 -04:00
TSharedRef < SHyperlink > Hyperlink = CreateHyperlink ( ParameterName , ParameterData . Material , ParameterData . ExpressionID ) ;
2021-12-14 19:40:18 -05:00
const FText HyperlinkToolTipText = FText : : Format (
LOCTEXT ( " VectorChannelHyperlinkTooltip " , " Jump to Vector Parameter \n NOTE: Vector channel name not used as parameter name for setters, \n use vector parameter name \" {0} \" or primitive index {1} instead. " ) ,
ParameterNameText ,
FText : : AsNumber ( PrimIdx ) ) ;
Hyperlink - > SetToolTipText ( HyperlinkToolTipText ) ;
2021-09-28 09:07:40 -04:00
2021-09-22 20:15:55 -04:00
VerticalBox - > AddSlot ( )
. Padding ( 2.f )
[
2021-09-28 09:07:40 -04:00
Hyperlink
2021-09-22 20:15:55 -04:00
] ;
SearchText . Add ( ParameterName ) ;
}
}
if ( ScalarParameterData . Contains ( PrimIdx ) )
{
for ( const FParameterData & ParameterData : ScalarParameterData [ PrimIdx ] )
{
if ( AddedParametersForThisRow . Contains ( ParameterData . ExpressionID ) )
{
continue ;
}
2021-12-14 19:40:18 -05:00
Materials . Add ( ParameterData . Material - > GetMaterial ( ) ) ;
2021-09-22 20:15:55 -04:00
AddedParametersForThisRow . Add ( ParameterData . ExpressionID ) ;
2021-12-14 19:40:18 -05:00
ParameterNames . Add ( ParameterData . Info . Name ) ;
2021-09-22 20:15:55 -04:00
const FText ParameterName = FText : : FromName ( ParameterData . Info . Name ) ;
2021-09-28 09:07:40 -04:00
TSharedRef < SHyperlink > Hyperlink = CreateHyperlink ( ParameterName , ParameterData . Material , ParameterData . ExpressionID ) ;
Hyperlink - > SetToolTipText ( LOCTEXT ( " ScalarHyperlinkTooltip " , " Jump to Scalar Parameter " ) ) ;
2021-09-22 20:15:55 -04:00
VerticalBox - > AddSlot ( )
. Padding ( 2.f )
[
2021-09-28 09:07:40 -04:00
Hyperlink
2021-09-22 20:15:55 -04:00
] ;
SearchText . Add ( ParameterName ) ;
}
}
2021-12-14 19:40:18 -05:00
if ( MaterialsToWatch . Num ( ) ! = Materials . Num ( ) )
2021-09-22 20:15:55 -04:00
{
2021-09-28 09:07:40 -04:00
// Some components aren't defining parameters at this index, add the undeclared parameter widget in case this was user error
2021-09-22 20:15:55 -04:00
VerticalBox - > AddSlot ( )
. Padding ( 2.f )
[
2021-09-28 09:07:40 -04:00
GetUndeclaredParameterWidget ( PrimIdx , CustomizationUtils )
2021-09-22 20:15:55 -04:00
] ;
}
2021-12-14 19:40:18 -05:00
TSharedPtr < SWidget > NameContent ;
if ( ParameterNames . Num ( ) > 1 )
{
NameContent = CreateWarningWidget ( VerticalBox . ToSharedRef ( ) , LOCTEXT ( " OverlappingParameters " , " Primitive index has overlapping parameter names declared, make sure scalar and/or vector channel names match to remove warning " ) ) ;
}
else
{
NameContent = VerticalBox ;
}
NameContent = CreateNameWidget ( PrimIdx , NameContent . ToSharedRef ( ) , CustomizationUtils ) ;
2021-09-22 20:15:55 -04:00
if ( ElementHandle . IsValid ( ) )
{
// We already have data for this row, be sure to use it
TSharedRef < IPropertyHandle > ElementHandleRef = ElementHandle . ToSharedRef ( ) ;
IDetailPropertyRow & Row = VectorGroup ? VectorGroup - > AddPropertyRow ( ElementHandleRef ) : ChildBuilder . AddProperty ( ElementHandleRef ) ;
TSharedRef < SWidget > ValueWidget = ElementHandle - > CreatePropertyValueWidget ( false ) ;
ValueWidget - > SetEnabled ( bDataEditable ) ;
ElementHandleRef - > SetOnPropertyResetToDefault ( FSimpleDelegate : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : SetDefaultValue , ElementHandle , PrimIdx ) ) ;
Row . CustomWidget ( )
. NameContent ( )
2021-12-14 19:40:18 -05:00
. HAlign ( HAlign_Fill )
2021-09-22 20:15:55 -04:00
[
2021-12-14 19:40:18 -05:00
NameContent . ToSharedRef ( )
2021-09-22 20:15:55 -04:00
]
. ValueContent ( )
[
ValueWidget
] ;
}
else
{
// We don't have data for this row, add an empty row that contains the parameter names and the ability to add data up until this point
FDetailWidgetRow & Row = VectorGroup ? VectorGroup - > AddWidgetRow ( ) : ChildBuilder . AddCustomRow ( FText : : Join ( LOCTEXT ( " SearchTextDelimiter " , " " ) , SearchText ) ) ;
Row . NameContent ( )
2021-12-14 19:40:18 -05:00
. HAlign ( HAlign_Fill )
2021-09-22 20:15:55 -04:00
[
2021-12-14 19:40:18 -05:00
NameContent . ToSharedRef ( )
2021-09-22 20:15:55 -04:00
]
. ValueContent ( )
[
SNew ( SHorizontalBox )
. IsEnabled ( bDataEditable )
+ SHorizontalBox : : Slot ( )
. Padding ( 2.0f )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
PropertyCustomizationHelpers : : MakeAddButton ( FSimpleDelegate : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : OnAddedDesiredPrimitiveData , PrimIdx ) )
]
] ;
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
template < typename Predicate >
void FCustomPrimitiveDataCustomization : : ForEachSelectedComponent ( Predicate Pred )
{
if ( PropertyUtils . IsValid ( ) )
{
for ( TWeakObjectPtr < UObject > Object : PropertyUtils - > GetSelectedObjects ( ) )
{
if ( UPrimitiveComponent * Component = Cast < UPrimitiveComponent > ( Object . Get ( ) ) )
{
Pred ( Component ) ;
}
else if ( AActor * Actor = Cast < AActor > ( Object . Get ( ) ) )
{
for ( UActorComponent * ActorComponent : Actor - > GetComponents ( ) )
{
if ( UPrimitiveComponent * PrimitiveComponent = Cast < UPrimitiveComponent > ( ActorComponent ) )
{
Pred ( PrimitiveComponent ) ;
}
}
}
}
}
}
2021-12-08 19:12:30 -05:00
bool FCustomPrimitiveDataCustomization : : IsSelected ( UPrimitiveComponent * Component ) const
{
return Component & & PropertyUtils . IsValid ( ) & & PropertyUtils - > GetSelectedObjects ( ) . ContainsByPredicate (
[ WeakComp = TWeakObjectPtr < UObject > ( Component ) , WeakActor = TWeakObjectPtr < UObject > ( Component - > GetOwner ( ) ) ] ( const TWeakObjectPtr < UObject > & SelectedObject )
{
// Selected objects could be components or actors
return SelectedObject . IsValid ( ) & & ( SelectedObject = = WeakComp | | SelectedObject = = WeakActor ) ;
} ) ;
}
2021-09-22 20:15:55 -04:00
void FCustomPrimitiveDataCustomization : : Cleanup ( )
{
PropertyUtils = NULL ;
2021-09-29 02:23:42 -04:00
DataHandle = NULL ;
2021-09-22 20:15:55 -04:00
DataArrayHandle = NULL ;
ComponentsToWatch . Empty ( ) ;
2022-01-26 17:08:07 -05:00
ComponentMaterialCounts . Empty ( ) ;
2021-09-22 20:15:55 -04:00
MaterialsToWatch . Empty ( ) ;
VectorParameterData . Empty ( ) ;
ScalarParameterData . Empty ( ) ;
ColorBlocks . Empty ( ) ;
}
void FCustomPrimitiveDataCustomization : : PopulateParameterData ( UPrimitiveComponent * PrimitiveComponent , int32 & MaxPrimitiveDataIndex )
{
const int32 NumMaterials = PrimitiveComponent - > GetNumMaterials ( ) ;
2021-09-28 05:31:56 -04:00
TSet < TSoftObjectPtr < UMaterial > > & CachedComponentMaterials = ComponentsToWatch . FindOrAdd ( PrimitiveComponent ) ;
2022-01-26 17:08:07 -05:00
ComponentMaterialCounts . FindOrAdd ( PrimitiveComponent ) = NumMaterials ;
2021-09-22 20:15:55 -04:00
for ( int32 i = 0 ; i < NumMaterials ; + + i )
{
UMaterialInterface * MaterialInterface = PrimitiveComponent - > GetMaterial ( i ) ;
2021-12-14 19:40:18 -05:00
UMaterial * Material = MaterialInterface ? MaterialInterface - > GetMaterial ( ) : NULL ;
2021-09-22 20:15:55 -04:00
if ( Material = = NULL )
{
continue ;
}
MaterialsToWatch . Add ( Material ) ;
2021-09-28 05:31:56 -04:00
CachedComponentMaterials . Add ( Material ) ;
2021-09-22 20:15:55 -04:00
TMap < FMaterialParameterInfo , FMaterialParameterMetadata > Parameters ;
MaterialInterface - > GetAllParametersOfType ( EMaterialParameterType : : Vector , Parameters ) ;
for ( const TPair < FMaterialParameterInfo , FMaterialParameterMetadata > & Parameter : Parameters )
{
const FMaterialParameterInfo & Info = Parameter . Key ;
const FMaterialParameterMetadata & ParameterMetadata = Parameter . Value ;
if ( ParameterMetadata . PrimitiveDataIndex > INDEX_NONE )
{
// Add each element individually, so that we can overlap vector parameter names
VectorParameterData . FindOrAdd ( ParameterMetadata . PrimitiveDataIndex + 0 ) . Add (
{
PrimitiveComponent ,
MaterialInterface ,
Info ,
ParameterMetadata . ExpressionGuid ,
0
} ) ;
VectorParameterData . FindOrAdd ( ParameterMetadata . PrimitiveDataIndex + 1 ) . Add (
{
PrimitiveComponent ,
MaterialInterface ,
Info ,
ParameterMetadata . ExpressionGuid ,
1
} ) ;
VectorParameterData . FindOrAdd ( ParameterMetadata . PrimitiveDataIndex + 2 ) . Add (
{
PrimitiveComponent ,
MaterialInterface ,
Info ,
ParameterMetadata . ExpressionGuid ,
2
} ) ;
VectorParameterData . FindOrAdd ( ParameterMetadata . PrimitiveDataIndex + 3 ) . Add (
{
PrimitiveComponent ,
MaterialInterface ,
Info ,
ParameterMetadata . ExpressionGuid ,
3
} ) ;
MaxPrimitiveDataIndex = FMath : : Max ( MaxPrimitiveDataIndex , ( int32 ) ( ParameterMetadata . PrimitiveDataIndex + 3 ) ) ;
}
}
Parameters . Reset ( ) ;
MaterialInterface - > GetAllParametersOfType ( EMaterialParameterType : : Scalar , Parameters ) ;
for ( const TPair < FMaterialParameterInfo , FMaterialParameterMetadata > & Parameter : Parameters )
{
const FMaterialParameterInfo & Info = Parameter . Key ;
const FMaterialParameterMetadata & ParameterMetadata = Parameter . Value ;
if ( ParameterMetadata . PrimitiveDataIndex > INDEX_NONE )
{
ScalarParameterData . FindOrAdd ( ParameterMetadata . PrimitiveDataIndex ) . Add (
{
PrimitiveComponent ,
MaterialInterface ,
Info ,
ParameterMetadata . ExpressionGuid ,
0
} ) ;
MaxPrimitiveDataIndex = FMath : : Max ( MaxPrimitiveDataIndex , ( int32 ) ParameterMetadata . PrimitiveDataIndex ) ;
}
}
}
}
2021-10-20 23:18:42 -04:00
void FCustomPrimitiveDataCustomization : : RequestRefresh ( )
2021-09-22 20:15:55 -04:00
{
2021-10-20 23:18:42 -04:00
if ( ! bDeferringRefresh & & PropertyUtils . IsValid ( ) )
2021-09-22 20:15:55 -04:00
{
2021-10-20 23:18:42 -04:00
bDeferringRefresh = true ;
PropertyUtils - > EnqueueDeferredAction ( FSimpleDelegate : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : OnDeferredRefresh ) ) ;
2021-09-22 20:15:55 -04:00
}
}
2021-10-20 23:18:42 -04:00
void FCustomPrimitiveDataCustomization : : OnDeferredRefresh ( )
{
if ( PropertyUtils . IsValid ( ) )
{
PropertyUtils - > ForceRefresh ( ) ;
}
bDeferringRefresh = false ;
}
2021-09-29 02:23:42 -04:00
void FCustomPrimitiveDataCustomization : : OnElementsModified ( const FPropertyAccess : : Result OldAccessResult , const uint32 OldNumElements )
{
uint32 NumElements ;
FPropertyAccess : : Result AccessResult = GetNumElements ( NumElements ) ;
// There's been a change in our array structure, whether that be from change in access or size
if ( AccessResult ! = OldAccessResult | | NumElements ! = OldNumElements )
{
2021-10-20 23:18:42 -04:00
RequestRefresh ( ) ;
2021-09-29 02:23:42 -04:00
}
}
2021-09-22 20:15:55 -04:00
void FCustomPrimitiveDataCustomization : : OnObjectPropertyChanged ( UObject * Object , FPropertyChangedEvent & PropertyChangedEvent )
{
2021-12-08 19:12:30 -05:00
UPrimitiveComponent * PrimComponent = Cast < UPrimitiveComponent > ( Object ) ;
2021-09-28 05:31:56 -04:00
const EPropertyChangeType : : Type IgnoreFlags = EPropertyChangeType : : Interactive | EPropertyChangeType : : Redirected ;
2022-01-26 17:08:07 -05:00
if ( ! ( PropertyChangedEvent . ChangeType & IgnoreFlags ) & & ComponentsToWatch . Contains ( PrimComponent ) & & ComponentMaterialCounts . Contains ( PrimComponent )
2021-12-08 19:12:30 -05:00
& & IsSelected ( PrimComponent ) ) // Need to test this in case we're hitting a stale hash in ComponentsToWatch (#jira UE-136687)
2021-09-22 20:15:55 -04:00
{
2021-09-28 05:31:56 -04:00
bool bMaterialChange = false ;
2021-12-08 19:12:30 -05:00
if ( PrimComponent - > IsA < UMeshComponent > ( ) )
2021-09-28 05:31:56 -04:00
{
bMaterialChange = PropertyChangedEvent . GetPropertyName ( ) = = GET_MEMBER_NAME_CHECKED ( UMeshComponent , OverrideMaterials ) ;
}
2021-12-08 19:12:30 -05:00
else if ( PrimComponent - > IsA < UTextRenderComponent > ( ) )
2021-09-28 05:31:56 -04:00
{
bMaterialChange = PropertyChangedEvent . GetPropertyName ( ) = = GET_MEMBER_NAME_CHECKED ( UTextRenderComponent , TextMaterial ) ;
}
else
{
// Fall back if not handled
// NOTE: Optimally would be done via an "OnMaterialChanged" for each component, however,
// the property name checks above should handle most cases
2021-12-08 19:12:30 -05:00
TSet < TSoftObjectPtr < UMaterial > > & CachedComponentMaterials = ComponentsToWatch [ PrimComponent ] ;
2022-01-26 17:08:07 -05:00
int32 CachedComponentMaterialCount = ComponentMaterialCounts [ PrimComponent ] ;
2021-09-28 05:31:56 -04:00
const int32 NumMaterials = PrimComponent - > GetNumMaterials ( ) ;
2022-01-26 17:08:07 -05:00
if ( NumMaterials ! = CachedComponentMaterialCount )
2021-09-28 05:31:56 -04:00
{
bMaterialChange = true ;
}
else
{
TSet < TSoftObjectPtr < UMaterial > > CurrentMaterials ;
CurrentMaterials . Reserve ( NumMaterials ) ;
for ( int32 i = 0 ; i < NumMaterials ; + + i )
{
UMaterialInterface * MaterialInterface = PrimComponent - > GetMaterial ( i ) ;
UMaterial * Material = MaterialInterface ? MaterialInterface - > GetMaterial ( ) : NULL ;
if ( Material )
{
CurrentMaterials . Add ( Material ) ;
}
}
bMaterialChange = CurrentMaterials . Difference ( CachedComponentMaterials ) . Num ( ) > 0 ;
}
}
if ( bMaterialChange )
2021-09-27 14:07:26 -04:00
{
2021-10-20 23:18:42 -04:00
RequestRefresh ( ) ;
2021-09-27 14:07:26 -04:00
}
2021-09-22 20:15:55 -04:00
}
}
void FCustomPrimitiveDataCustomization : : OnMaterialCompiled ( UMaterialInterface * Material )
{
// NOTE: We use a soft object ptr here as the old material object will be stale on compile
if ( MaterialsToWatch . Contains ( Material ) )
{
2021-10-20 23:18:42 -04:00
RequestRefresh ( ) ;
2021-09-22 20:15:55 -04:00
}
}
void FCustomPrimitiveDataCustomization : : OnNavigate ( TWeakObjectPtr < UMaterialInterface > MaterialInterface , FGuid ExpressionID )
{
UMaterial * Material = MaterialInterface . IsValid ( ) ? MaterialInterface - > GetMaterial ( ) : NULL ;
if ( UMaterialExpression * Expression = Material ? Material - > FindExpressionByGUID < UMaterialExpression > ( ExpressionID ) : NULL )
{
2021-09-23 19:17:53 -04:00
// FindExpression is recursive, so we need to ensure we open the correct asset
UObject * Asset = Expression - > GetOutermostObject ( ) ;
2021-09-22 20:15:55 -04:00
UAssetEditorSubsystem * AssetEditorSubsystem = GEditor - > GetEditorSubsystem < UAssetEditorSubsystem > ( ) ;
2021-09-23 19:17:53 -04:00
IAssetEditorInstance * AssetEditorInstance = AssetEditorSubsystem - > OpenEditorForAsset ( Asset ) ? AssetEditorSubsystem - > FindEditorForAsset ( Asset , true ) : NULL ;
if ( AssetEditorInstance ! = NULL )
{
if ( AssetEditorInstance - > GetEditorName ( ) = = " MaterialEditor " )
{
( ( IMaterialEditor * ) AssetEditorInstance ) - > JumpToExpression ( Expression ) ;
}
else
{
ensureMsgf ( false , TEXT ( " Missing navigate to expression for editor '%s' " ) , * AssetEditorInstance - > GetEditorName ( ) . ToString ( ) ) ;
}
}
2021-09-22 20:15:55 -04:00
}
}
void FCustomPrimitiveDataCustomization : : OnAddedDesiredPrimitiveData ( uint8 PrimIdx )
{
uint32 NumElements ;
2021-09-29 02:23:42 -04:00
if ( GetNumElements ( NumElements ) = = FPropertyAccess : : Success & & PrimIdx > = NumElements )
2021-09-22 20:15:55 -04:00
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnAddedDesiredPrimitiveData " , " Added Items " ) ) ;
for ( int32 i = NumElements ; i < = PrimIdx ; + + i )
{
DataArrayHandle - > AddItem ( ) ;
SetDefaultValue ( DataArrayHandle - > GetElement ( i ) , i ) ;
}
GEditor - > EndTransaction ( ) ;
}
}
void FCustomPrimitiveDataCustomization : : OnRemovedPrimitiveData ( uint8 PrimIdx )
{
uint32 NumElements ;
2021-09-29 02:23:42 -04:00
if ( GetNumElements ( NumElements ) = = FPropertyAccess : : Success & & PrimIdx < NumElements )
2021-09-22 20:15:55 -04:00
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnRemovedPrimitiveData " , " Removed Items " ) ) ;
for ( int32 i = NumElements - 1 ; i > = PrimIdx ; - - i )
{
DataArrayHandle - > DeleteItem ( i ) ;
}
GEditor - > EndTransaction ( ) ;
}
}
FLinearColor FCustomPrimitiveDataCustomization : : GetVectorColor ( uint8 PrimIdx ) const
{
2021-09-22 21:37:02 -04:00
FVector4f Color ( ForceInitToZero ) ;
2021-09-22 20:15:55 -04:00
uint32 NumElems ;
2021-09-29 02:23:42 -04:00
if ( GetNumElements ( NumElems ) = = FPropertyAccess : : Success )
2021-09-22 20:15:55 -04:00
{
const int32 MaxElems = FMath : : Min ( ( int32 ) NumElems , PrimIdx + 4 ) ;
for ( int32 i = PrimIdx ; i < MaxElems ; + + i )
{
DataArrayHandle - > GetElement ( i ) - > GetValue ( Color [ i - PrimIdx ] ) ;
}
}
return FLinearColor ( Color ) ;
}
void FCustomPrimitiveDataCustomization : : SetVectorColor ( FLinearColor NewColor , uint8 PrimIdx )
{
2021-09-22 21:37:02 -04:00
FVector4f Color ( NewColor ) ;
2021-09-22 20:15:55 -04:00
uint32 NumElems ;
2021-09-29 02:23:42 -04:00
if ( GetNumElements ( NumElems ) = = FPropertyAccess : : Success )
2021-09-22 20:15:55 -04:00
{
const int32 MaxElems = FMath : : Min ( ( int32 ) NumElems , PrimIdx + 4 ) ;
for ( int32 i = PrimIdx ; i < MaxElems ; + + i )
{
DataArrayHandle - > GetElement ( i ) - > SetValue ( Color [ i - PrimIdx ] ) ;
}
}
}
void FCustomPrimitiveDataCustomization : : SetDefaultValue ( TSharedPtr < IPropertyHandle > Handle , uint8 PrimIdx )
{
if ( Handle . IsValid ( ) )
{
TSet < TWeakObjectPtr < UPrimitiveComponent > > ChangedComponents ;
// Prioritize vector data since we have a color picker
if ( VectorParameterData . Contains ( PrimIdx ) )
{
for ( const FParameterData & ParameterData : VectorParameterData [ PrimIdx ] )
{
if ( ParameterData . Component . IsValid ( ) & & ! ChangedComponents . Contains ( ParameterData . Component ) )
{
FLinearColor Color ( ForceInitToZero ) ;
2021-09-29 02:23:42 -04:00
if ( ! ParameterData . Material . IsValid ( ) | | ParameterData . Material - > GetVectorParameterValue ( ParameterData . Info , Color ) )
2021-09-22 20:15:55 -04:00
{
float * ColorPtr = reinterpret_cast < float * > ( & Color ) ;
ParameterData . Component - > SetDefaultCustomPrimitiveDataFloat ( PrimIdx , ColorPtr [ ParameterData . IndexOffset ] ) ;
FPropertyChangedEvent PropertyChangedEvent ( Handle - > GetParentHandle ( ) - > GetParentHandle ( ) - > GetProperty ( ) ) ;
PropertyChangedEvent . SetActiveMemberProperty ( Handle - > GetParentHandle ( ) - > GetProperty ( ) ) ;
ParameterData . Component - > PostEditChangeProperty ( PropertyChangedEvent ) ;
ChangedComponents . Add ( ParameterData . Component ) ;
}
}
}
}
if ( ScalarParameterData . Contains ( PrimIdx ) )
{
2021-09-28 09:07:40 -04:00
for ( const FParameterData & ParameterData : ScalarParameterData [ PrimIdx ] )
2021-09-22 20:15:55 -04:00
{
if ( ParameterData . Component . IsValid ( ) & & ! ChangedComponents . Contains ( ParameterData . Component ) )
{
float Value = 0.f ;
2021-09-29 02:23:42 -04:00
if ( ! ParameterData . Material . IsValid ( ) | | ParameterData . Material - > GetScalarParameterValue ( ParameterData . Info , Value ) )
2021-09-22 20:15:55 -04:00
{
ParameterData . Component - > SetDefaultCustomPrimitiveDataFloat ( PrimIdx , Value ) ;
FPropertyChangedEvent PropertyChangedEvent ( Handle - > GetParentHandle ( ) - > GetParentHandle ( ) - > GetProperty ( ) ) ;
PropertyChangedEvent . SetActiveMemberProperty ( Handle - > GetParentHandle ( ) - > GetProperty ( ) ) ;
ParameterData . Component - > PostEditChangeProperty ( PropertyChangedEvent ) ;
ChangedComponents . Add ( ParameterData . Component ) ;
}
}
}
}
}
}
void FCustomPrimitiveDataCustomization : : SetDefaultVectorValue ( uint8 PrimIdx )
{
uint32 NumElems ;
2021-09-29 02:23:42 -04:00
if ( GetNumElements ( NumElems ) = = FPropertyAccess : : Success )
2021-09-22 20:15:55 -04:00
{
GEditor - > BeginTransaction ( LOCTEXT ( " SetDefaultVectorValue " , " Reset Vector To Default " ) ) ;
const int32 MaxElems = FMath : : Min ( ( int32 ) NumElems , PrimIdx + 4 ) ;
for ( int32 i = PrimIdx ; i < MaxElems ; + + i )
{
DataArrayHandle - > GetElement ( i ) - > ResetToDefault ( ) ;
}
GEditor - > EndTransaction ( ) ;
}
}
FReply FCustomPrimitiveDataCustomization : : OnMouseButtonDownColorBlock ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent , uint8 PrimIdx )
{
if ( MouseEvent . GetEffectingButton ( ) ! = EKeys : : LeftMouseButton )
{
return FReply : : Unhandled ( ) ;
}
GEditor - > BeginTransaction ( FText : : Format ( LOCTEXT ( " SetVectorColor " , " Edit Primitive Data Vector: {0} " ) , FText : : AsNumber ( PrimIdx ) ) ) ;
FColorPickerArgs PickerArgs ;
PickerArgs . bUseAlpha = true ;
PickerArgs . InitialColorOverride = GetVectorColor ( PrimIdx ) ;
PickerArgs . ParentWidget = ColorBlocks [ PrimIdx ] ;
PickerArgs . DisplayGamma = TAttribute < float > : : Create ( TAttribute < float > : : FGetter : : CreateUObject ( GEngine , & UEngine : : GetDisplayGamma ) ) ;
PickerArgs . OnColorCommitted = FOnLinearColorValueChanged : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : SetVectorColor , PrimIdx ) ;
PickerArgs . OnColorPickerCancelled = FOnColorPickerCancelled : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : OnColorPickerCancelled , PrimIdx ) ;
PickerArgs . OnColorPickerWindowClosed = FOnWindowClosed : : CreateSP ( this , & FCustomPrimitiveDataCustomization : : OnColorPickerWindowClosed ) ;
OpenColorPicker ( PickerArgs ) ;
return FReply : : Handled ( ) ;
}
void FCustomPrimitiveDataCustomization : : OnColorPickerCancelled ( FLinearColor OriginalColor , uint8 PrimIdx )
{
SetVectorColor ( OriginalColor , PrimIdx ) ;
GEditor - > CancelTransaction ( 0 ) ;
}
void FCustomPrimitiveDataCustomization : : OnColorPickerWindowClosed ( const TSharedRef < SWindow > & Window )
{
GEditor - > EndTransaction ( ) ;
}
2021-09-28 09:07:40 -04:00
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
TSharedRef < SWidget > FCustomPrimitiveDataCustomization : : CreateNameWidget ( int32 PrimIdx , TSharedRef < SWidget > ParameterName , IPropertyTypeCustomizationUtils & CustomizationUtils ) const
{
return SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
2021-12-14 19:40:18 -05:00
. HAlign ( HAlign_Left )
2021-09-28 09:07:40 -04:00
. VAlign ( VAlign_Center )
. AutoWidth ( )
. Padding ( 2.f , 2.f , 16.0f , 2.f )
[
SNew ( STextBlock )
. Text ( FText : : AsNumber ( PrimIdx ) )
. Font ( CustomizationUtils . GetRegularFont ( ) )
]
+ SHorizontalBox : : Slot ( )
2021-12-14 19:40:18 -05:00
. HAlign ( HAlign_Fill )
. VAlign ( VAlign_Center )
2021-09-28 09:07:40 -04:00
. Padding ( 0.f , 2.0f )
[
ParameterName
] ;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
2021-09-22 20:15:55 -04:00
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
TSharedRef < SHyperlink > FCustomPrimitiveDataCustomization : : CreateHyperlink ( FText Text , TWeakObjectPtr < UMaterialInterface > Material , const FGuid & ExpressionID )
{
return SNew ( SHyperlink )
. Text ( Text )
. OnNavigate ( this , & FCustomPrimitiveDataCustomization : : OnNavigate , Material , ExpressionID )
2022-05-09 13:31:58 -04:00
. Style ( FAppStyle : : Get ( ) , " HoverOnlyHyperlink " )
. TextStyle ( FAppStyle : : Get ( ) , " DetailsView.HyperlinkStyle " ) ;
2021-09-22 20:15:55 -04:00
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
2021-09-28 09:07:40 -04:00
TSharedRef < SWidget > FCustomPrimitiveDataCustomization : : GetUndeclaredParameterWidget ( int32 PrimIdx , IPropertyTypeCustomizationUtils & CustomizationUtils ) const
2021-09-22 20:15:55 -04:00
{
2021-12-14 19:40:18 -05:00
const FText ToolTipText = FText : : Format (
LOCTEXT ( " UndeclaredParameterTooltip " , " An assigned material doesn't declare a parameter for primitive index {0} " ) ,
FText : : AsNumber ( PrimIdx ) ) ;
const uint16 FontSize = CustomizationUtils . GetRegularFont ( ) . GetClampSize ( ) ;
return SNew ( SHorizontalBox )
. ToolTipText ( ToolTipText )
+ SHorizontalBox : : Slot ( )
. Padding ( 4.f , 0.f )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SImage )
. DesiredSizeOverride ( FVector2D ( FontSize ) )
2022-05-09 13:31:58 -04:00
. Image ( FAppStyle : : GetBrush ( " Icons.Warning " ) )
2021-12-14 19:40:18 -05:00
]
+ SHorizontalBox : : Slot ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " UndeclaredParameter " , " Undeclared " ) )
. Font ( CustomizationUtils . GetRegularFont ( ) )
] ;
2021-09-22 20:15:55 -04:00
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
2021-12-14 19:40:18 -05:00
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
TSharedRef < SWidget > FCustomPrimitiveDataCustomization : : CreateWarningWidget ( TSharedRef < SWidget > Content , FText WarningText ) const
{
// Similar to SWarningOrErrorBox widget
return SNew ( SBorder )
2022-05-09 13:31:58 -04:00
. BorderImage ( FAppStyle : : GetBrush ( " RoundedWarning " ) )
2021-12-14 19:40:18 -05:00
[
SNew ( SHorizontalBox )
. ToolTipText ( WarningText )
+ SHorizontalBox : : Slot ( )
. Padding ( 16.f , 2.f )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SImage )
2022-05-09 13:31:58 -04:00
. Image ( FAppStyle : : GetBrush ( " Icons.WarningWithColor " ) )
2021-12-14 19:40:18 -05:00
]
+ SHorizontalBox : : Slot ( )
. Padding ( 0.f , 2.f , 16.f , 2.f )
. HAlign ( HAlign_Fill )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
Content
]
] ;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
2021-09-29 02:23:42 -04:00
FPropertyAccess : : Result FCustomPrimitiveDataCustomization : : GetNumElements ( uint32 & NumElements ) const
{
if ( DataHandle . IsValid ( ) & & DataArrayHandle . IsValid ( ) )
{
DataArrayHandle - > GetNumElements ( NumElements ) ;
// This is a low touch way to work out whether we have multiple selections or not,
// since FPropertyHandleArray::GetNumElements above always returns FPropertyAccess::Success
void * Address ;
return DataHandle - > GetValueData ( Address ) ;
}
NumElements = 0 ;
return FPropertyAccess : : Fail ;
}
2021-09-22 20:15:55 -04:00
# undef LOCTEXT_NAMESPACE