4
2

[UE5] 構造体のヘッダーにカスタム文字列を表示する

Posted at

image.png
UE5 のエディタ UI では、構造体のプロパティを折りたたむことができますが、その状態では中身が見えないという課題があります。そこで、プロパティ名の右側の空欄部分に内容を簡略化して表示できるよう、汎用的な PropertyCustomization を作成しました。また、TStructOpsTypeTraits で構造体を拡張することで、適切なテキスト出力をすることができます。今回はこの 2 つのエディタ拡張について紹介します。

image.png
これが、

image.png
こうなる。

構造体の追加

まずは、適当な Animation プロパティを持つ構造体を定義します。

USTRUCT()
struct FAnimationNode
{
	GENERATED_BODY()

	UPROPERTY( EditDefaultsOnly )
	TSoftObjectPtr<class UAnimationAsset> Animation;
};

// ...どこかのPROPERTY
public:
	UPROPERTY( EditDefaultsOnly )
	struct FAnimationNode Node;

PropertyCustomization に登録する

IPropertyTypeCustomization を継承したエディタ UI を拡張するクラスを作成し、StartupModule から PropertyCustomization を登録します。

// プロパティ列を拡張する UI クラス
class FNamedStructureDetails final : public IPropertyTypeCustomization
{
public:
	static TSharedRef<IPropertyTypeCustomization> MakeInstance()
	{
		return MakeShared<FNamedStructureDetails>();
	}

protected:
	// ヘッダー行をカスタマイズ
	virtual void CustomizeHeader(
		TSharedRef<IPropertyHandle> PropertyHandle,
		FDetailWidgetRow& HeaderRow,
		IPropertyTypeCustomizationUtils& CustomizationUtils ) override
	{
		HeaderRow
		.NameContent()
		[
			// プロパティ名を表示
			PropertyHandle->CreatePropertyNameWidget()
		]
		.ValueContent()
		[
			SNew( SHorizontalBox )
			+ SHorizontalBox::Slot()
			.VAlign( VAlign_Center ) // 表示位置を縦方向の中央に寄せる
			[
				SNew( STextBlock )
				.Text_Lambda( [PropertyHandle]
				{
					// 構造体から文字列を取得
					FText DisplayText;
					PropertyHandle->GetValueAsDisplayText( DisplayText );

					return DisplayText;
				} )
			]
		];
	}

	// 子要素は通常のレイアウトと同様に表示
	virtual void CustomizeChildren(
		TSharedRef<IPropertyHandle> PropertyHandle,
		IDetailChildrenBuilder& ChildBuilder,
		IPropertyTypeCustomizationUtils& CustomizationUtils ) override
	{
		uint32 NumChildren;
		PropertyHandle->GetNumChildren( NumChildren );

		for ( uint32 Index = 0; Index < NumChildren; ++Index )
		{
			// 通常と同様に、構造体の子要素を追加
			ChildBuilder.AddProperty( PropertyHandle->GetChildHandle( Index ).ToSharedRef() );
		}
	}
};

class FMyProjectModule final : public FDefaultGameModuleImpl
{
	virtual void StartupModule() override
	{
		auto& PropertyModule =
			FModuleManager::LoadModuleChecked<FPropertyEditorModule>( "PropertyEditor" );

		// PropertyCustomizationに登録
		PropertyModule.RegisterCustomPropertyTypeLayout(
			"NamedStructure", // 後述のPresentAsTypeで指定する
			FOnGetPropertyTypeCustomizationInstance::CreateStatic(
				&FNamedStructureDetails::MakeInstance
			)
		);
	}
};

IMPLEMENT_PRIMARY_GAME_MODULE( FMyProjectModule, MyProject, "MyProject" );

(本来はエディタでのみ使う機能なので、EditorModule に追加してください)

PresentAsType メタ指定子

構造体にメタ指定子を追加します。

// 登録したPropertyCustomization名を指定する
USTRUCT( meta = ( PresentAsType = "NamedStructure" ) )
struct FAnimationNode

通常、FPropertyEditorModule::RegisterCustomPropertyTypeLayout ではプロパティ名を登録しますが、PresentAsType を使用すると、どんな型でも PropertyCustomization を適用することが可能です。

image.png
ヘッダー欄に構造体の内容が、テキストとして表示されるようになりました。

ExportTextItem でテキスト出力を実装

TStructOpsTypeTraitsWithExportTextItem 特性を追加し、さらに構造体に ExportTextItem 関数を定義することで、構造体のテキスト出力フォーマットを拡張できます。今回は、PPF_PropertyWindow の場合、つまりエディタ UI での表示を拡張する例を示します。

struct FAnimationNode
{
	// UStruct Overrides
	bool ExportTextItem(
		FString& ValueStr, const FAnimationNode& DefaultValue,
		UObject* Parent, int32 PortFlags, UObject* ExportRootScope ) const
	{
		if ( PortFlags & PPF_PropertyWindow )
		{
			// AnimationがセットされていればAssetNameを表示
			ValueStr += !Animation.IsNull() ?
				Animation.GetAssetName() : FName( NAME_None ).ToString();
			return true;
		}

		return false;
	}

// ...略

template <>
struct TStructOpsTypeTraits<FAnimationNode> : TStructOpsTypeTraitsBase2<FAnimationNode>
{
	enum
	{
		WithExportTextItem = true,
	};
};

ValueStr += としているのは、呼び出し元の実装を引き継ぐことを想定するためです。配列であれば呼び出し元で "()" が付与されるなど。

image.png
以上で、テキスト出力を自由にカスタマイズできるようになりました。

配列の子要素でテキストを表示する

	UPROPERTY( EditDefaultsOnly )
	TArray<FAnimationNode> Nodes;

image.png
配列でも PropertyCustomization が適用されてヘッダー欄にテキストが表示されます。TitleProperty メタ指定子の必要もありません。

FInstancedStructでも!

image.png
FInstancedStruct を入れ子にする場合は、FInstancedStruct 自身が ExportTextItem を実装しており、内部の構造体のテキスト出力関数を呼び出してくれます。今回のケースでは FAnimationNodeFAnimationNode_SimpleFAnimationNode_Random に拡張するアイデアがあったため、この手法を採用しました。

まとめ

今回のカスタマイズにより、UE5 のエディタ UI で構造体の内容を柔軟に表示できるようになりました。特に、構造体の中身をテキスト形式で簡略表示することで、UI の使いやすさが向上しました。エディタでのプロパティ表示をカスタマイズしたい方には、今回紹介した手法が役立つでしょう。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2