Struct title display name

About

Only for array of structs

See details and example here using the meta attribute TitleProperty.

Examples

  • TitleProperty="MyStructProperty"
  • TitleProperty="{MyStructProperty}"
  • TitleProperty="Some text and {MyStructProperty}!"

In Editor

Internally the editor seems to use FTitleMetadataFormatter to get the final display name. FTitleMetadataFormatter::TryParse is called which returns an FTitleMetadataFormatter that we use to call GetDisplayText. (See SPropertyEditorArrayItem::Construct or FItemPropertyNode::GetDisplayName for an example of that process).

So how does this works?
FTitleMetadataFormatter is a really simple struct, it has two member vars: FText Format and TArray<TSharedPtr<IPropertyHandle>> PropertyHandles. and the 2 functions I mentioned above.

Example 1 (no formatting)
Lets take for first example TitleProperty="PushEndOffset". No fancy formatting just the name of a property in my struct which is a FVector. In this example we will imagine we only have one entry in the array (the process is the same for each entry).

Since we have no formatting FTitleMetadataFormatter::TryParse will just get the property handle of the property name we gave (PushEndOffset) and add it to PropertyHandles, Format will just be {PushEndOffset}.

Then inside GetDisplayText we create a temp var FFormatNamedArguments FormatArgs and iterate all PropertyHandles. For each entry we call IPropertyHandle::GetValueAsDisplayText (which should call FProperty::ExportText_Internal, in our example this will return (X=0.000000,Y=0.000000,Z=0.500000)) and add it to FormatArgs.

In the end we call FText::Format(Format, FormatArgs) and the result is used as the display text.

Example 2 (with formatting)
To avoid repetitive content I will just point out the differences, which here are in FTitleMetadataFormatter::TryParse In this second example we will have TitleProperty="{PushEndOffset}".

If “formatting chars” are detected (editor seems to only check for {) FText::GetFormatPatternParameters will be called, which returns an array of all the elements we put inside {}. Then for each element we get property handle from the struct and add it to PropertyHandles. Format will simply equal to whatever TitleProperty is.

Little trick for more fancy display name

// .h
 
// Our struct
USTRUCT(BlueprintType, DisplayName="Push Data For Tag Query")
struct FPTPushDataForTagQuery
{
	GENERATED_BODY();
 
	FPTPushDataForTagQuery();
	
	void PostSerialize(const FArchive& Ar);
 
#if WITH_EDITORONLY_DATA
	// Without an attribute such as EditAnywhere or VisibleAnywhere the editor TitleProperty code won't be able to find this property.
	UPROPERTY(VisibleAnywhere, meta=(EditCondition="false", EditConditionHides))
	FString EditorDisplayName;
#endif
 
	UPROPERTY(EditAnywhere, Category="PushThemAll|Setup")
	FGameplayTagRequirements TagRequirements;
 
	UPROPERTY(EditAnywhere, Category="PushThemAll|Setup")
	FVector PushEndOffset;
	
};
template<>
struct TStructOpsTypeTraits<FPTPushDataForTagQuery> : public TStructOpsTypeTraitsBase2<FPTPushDataForTagQuery>
{
	enum
	{
		WithPostSerialize = true,
   };
};
 
 
// somewhere in a class
UPROPERTY(EditAnywhere, meta=(TitleProperty="Target: {EditorDisplayName}"))
TArray<FPTPushDataForTagQuery> PushDataForQueries;
 
 
// .cpp
FPTPushDataForTagQuery::FPTPushDataForTagQuery():
	PushEndOffset(FVector::ZeroVector)
{
	// We cannot set EditorDisplayName here because when created for editor details panel view the struct will be in default state and not have our user overrides.
}
 
void FPTPushDataForTagQuery::PostSerialize(const FArchive& Ar)
{
	// Here the struct instance will have user overrides.
	EditorDisplayName = FString::Printf(TEXT("%s"), *TagRequirements.ToString());
}