vault backup: 2024-10-12 17:19:45

This commit is contained in:
2024-10-12 17:19:46 +08:00
parent ff94ddca61
commit 244c0c52f6
960 changed files with 31348 additions and 10 deletions

View File

@@ -0,0 +1,104 @@
# ArraySizeEnum
- **功能描述:** 为固定数组提供一个枚举,使得数组元素按照枚举值来作为索引和显示。
- **使用位置:** UPROPERTY
- **引擎模块:** Container Property
- **元数据类型:** string="abc"
- **限制类型:** T Array[Size]
- **常用程度:** ★★★
为固定数组提供一个枚举,使得数组元素按照枚举值来作为索引和显示。
- 所谓固定数组是区别于TArray这种可以动态改变大小的数组而是平凡的用[size]直接定义的数组。这种固定数组static array因为不会增删因此才有时适合用枚举里的所有值用作下标达成更高的便利性。
- 枚举里一般会把最后一个枚举项一般叫做Max或者Sizecount之类作为数据大小值。
- 枚举里不想显示的枚举值可以用Hidden隐藏起来但因为数组下标对应的是枚举项的下标就是第几个枚举值而不是枚举项的值因此会发现数组的实际显示项目比定义的Size要小。
## 测试代码:
```cpp
UENUM(BlueprintType)
enum class EMyArrayEnumNormal :uint8
{
First,
Second,
Third,
Max,
};
UENUM(BlueprintType)
enum class EMyArrayEnumHidden :uint8
{
First,
Second,
Cat = 5 UMETA(Hidden),
Third = 2,
Max = 3,
};
UPROPERTY(EditAnywhere, Category = ArraySizeEnumTest)
int32 MyIntArray_NoArraySizeEnum[3];
UPROPERTY(EditAnywhere, Category = ArraySizeEnumTest, meta = (ArraySizeEnum = "MyArrayEnumNormal"))
int32 MyIntArray_Normal_HasArraySizeEnum[(int)EMyArrayEnumNormal::Max];
UPROPERTY(EditAnywhere, Category = ArraySizeEnumTest, meta = (ArraySizeEnum = "MyArrayEnumHidden"))
int32 MyIntArray_Hidden_HasArraySizeEnum[(int)EMyArrayEnumHidden::Max];
```
## 测试效果:
都是大小为3的固定数组。
- MyIntArray_NoArraySizeEnum是最普通的数组模样。
- MyIntArray_Normal_HasArraySizeEnum正统的使用枚举项来当数组下标的例子。可以发现下标名字不是012而是枚举项名称了。
- MyIntArray_Hidden_HasArraySizeEnum采用的枚举项里有隐藏的一项Cat但它的下标是2因为定义的顺序因此数组的第3个被隐藏了起来。
![Untitled](Untitled.png)
## 原理:
可以发现一开始判断是否是固定数组ArrayDim>1其实就是固定数组了然后通过名字找枚举以及为数组的每一项去枚举里找枚举项从而生成细节面板里的子行。
```cpp
void FItemPropertyNode::InitChildNodes()
{
if( MyProperty->ArrayDim > 1 && ArrayIndex == -1 )
{
// Do not add array children which are defined by an enum but the enum at the array index is hidden
// This only applies to static arrays
static const FName NAME_ArraySizeEnum("ArraySizeEnum");
UEnum* ArraySizeEnum = NULL;
if (MyProperty->HasMetaData(NAME_ArraySizeEnum))
{
ArraySizeEnum = FindObject<UEnum>(NULL, *MyProperty->GetMetaData(NAME_ArraySizeEnum));
}
// Expand array.
for( int32 Index = 0 ; Index < MyProperty->ArrayDim ; Index++ )
{
bool bShouldBeHidden = false;
if( ArraySizeEnum )
{
// The enum at this array index is hidden
bShouldBeHidden = ArraySizeEnum->HasMetaData(TEXT("Hidden"), Index );
}
if( !bShouldBeHidden )
{
TSharedPtr<FItemPropertyNode> NewItemNode( new FItemPropertyNode);
FPropertyNodeInitParams InitParams;
InitParams.ParentNode = SharedThis(this);
InitParams.Property = MyProperty;
InitParams.ArrayOffset = Index*MyProperty->ElementSize;
InitParams.ArrayIndex = Index;
InitParams.bAllowChildren = true;
InitParams.bForceHiddenPropertyVisibility = bShouldShowHiddenProperties;
InitParams.bCreateDisableEditOnInstanceNodes = bShouldShowDisableEditOnInstance;
NewItemNode->InitNode( InitParams );
AddChildNode(NewItemNode);
}
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

View File

@@ -0,0 +1,63 @@
# EditFixedOrder
- **功能描述:** 使数组的元素无法通过拖拽来重新排序。
- **使用位置:** UPROPERTY
- **引擎模块:** Container Property
- **元数据类型:** bool
- **限制类型:** TArray
- **常用程度:** ★★
## 测试代码:
```cpp
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EditFixedOrderTest)
TArray<int32> MyIntArray_NoEditFixedOrder;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EditFixedOrderTest, meta = (EditFixedOrder))
TArray<int32> MyIntArray_EditFixedOrder;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EditFixedOrderTest)
TSet<int32> MyIntSet_NoEditFixedOrder;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EditFixedOrderTest, meta = (EditFixedOrder))
TSet<int32> MyIntSet_EditFixedOrder;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EditFixedOrderTest)
TMap<int32,FString> MyIntMap_NoEditFixedOrder;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EditFixedOrderTest, meta = (EditFixedOrder))
TMap<int32,FString> MyIntMap_EditFixedOrder;
```
## 测试效果:
- 可见只有第一个MyIntArray_NoEditFixedOrder在数组元素上出现可拖拽的标记然后可以改变顺序。
- 加上EditFixedOrder的TArray就无法改变顺序了。
- 其他TSetTMap是不支持该meta的因为其内部本身顺序也无关。
![EditFixedOrder](EditFixedOrder.gif)
## 原理:
可以看见细节面板里一个属性行是否可重排序的判断是外部是个数组且没有EditFixedOrder和ArraySizeEnum固定数组。当然本身这个属性也要在可编辑状态比如被禁用灰掉就显然不可编辑了
```cpp
bool FPropertyNode::IsReorderable()
{
FProperty* NodeProperty = GetProperty();
if (NodeProperty == nullptr)
{
return false;
}
// It is reorderable if the parent is an array and metadata doesn't prohibit it
const FArrayProperty* OuterArrayProp = NodeProperty->GetOwner<FArrayProperty>();
static const FName Name_DisableReordering("EditFixedOrder");
static const FName NAME_ArraySizeEnum("ArraySizeEnum");
return OuterArrayProp != nullptr
&& !OuterArrayProp->HasMetaData(Name_DisableReordering)
&& !IsEditConst()
&& !OuterArrayProp->HasMetaData(NAME_ArraySizeEnum)
&& !FApp::IsGame();
}
```

View File

@@ -0,0 +1,55 @@
# NoElementDuplicate
- **功能描述:** 去除TArray属性里数据项的Duplicate菜单项按钮。
- **使用位置:** UPROPERTY
- **引擎模块:** Container Property
- **元数据类型:** bool
- **限制类型:** TArray
- **常用程度:** ★
去除TArray属性里数据项的Duplicate菜单项按钮。
用于TArray属性值可以是任何类型可以是数值结构也可以是Object*。
## 测试代码:
```cpp
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = IntArray)
TArray<int32> MyIntArray;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = IntArray, meta = (NoElementDuplicate))
TArray<int32> MyIntArray_NoElementDuplicate;
```
## 效果:
可以看到带有NoElementDuplicate的数组在值的右侧下拉箭头的菜单项里只有两项。
![Untitled](Untitled.png)
## 原理:
判断如有NoElementDuplicate则只生成Insert_Delete 菜单否则是默认的Insert_Delete_Duplicate 。当然要求当前属性是数组属性且不是EditFixedSize固定大小的。
```cpp
void GetRequiredPropertyButtons( TSharedRef<FPropertyNode> PropertyNode, TArray<EPropertyButton::Type>& OutRequiredButtons, bool bUsingAssetPicker )
{
const FArrayProperty* OuterArrayProp = NodeProperty->GetOwner<FArrayProperty>();
if( OuterArrayProp )
{
if( PropertyNode->HasNodeFlags(EPropertyNodeFlags::SingleSelectOnly) && !(OuterArrayProp->PropertyFlags & CPF_EditFixedSize) )
{
if (OuterArrayProp->HasMetaData(TEXT("NoElementDuplicate")))
{
OutRequiredButtons.Add( EPropertyButton::Insert_Delete );
}
else
{
OutRequiredButtons.Add( EPropertyButton::Insert_Delete_Duplicate );
}
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,40 @@
# ReadOnlyKeys
- **功能描述:** 使TMap属性的Key不能编辑。
- **使用位置:** UPROPERTY
- **引擎模块:** Container Property
- **元数据类型:** bool
- **限制类型:** TMap属性
- **常用程度:** ★★
使TMap属性的Key不能编辑。
意味着这个TMap里的元素是在这之前构造函数里初始化等就设置好的但我们只希望用户更改值的内容而不改Key的名字。这在某些情况下比较有用比如以Platform作为Key这样Platform的列表是固定的就不希望用户更改了。
## 测试代码:
```cpp
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ReadOnlyKeysTest)
TMap<int32, FString> MyIntMap_NoReadOnlyKeys;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ReadOnlyKeysTest, meta = (ReadOnlyKeys))
TMap<int32, FString> MyIntMap_ReadOnlyKeys;
```
## 测试结果:
可见MyIntMap_ReadOnlyKeys的Key是灰色的不可编辑。
![Untitled](Untitled.png)
## 源码里搜到:
```cpp
void FDetailPropertyRow::MakeNameOrKeyWidget( FDetailWidgetRow& Row, const TSharedPtr<FDetailWidgetRow> InCustomRow ) const
{
if (PropertyHandle->HasMetaData(TEXT("ReadOnlyKeys")))
{
PropertyKeyEditor->GetPropertyNode()->SetNodeFlags(EPropertyNodeFlags::IsReadOnly, true);
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1,163 @@
# TitleProperty
- **功能描述:** 指定结构数组里的结构成员属性内容来作为结构数组元素的显示标题。
- **使用位置:** UPROPERTY
- **引擎模块:** Container Property
- **元数据类型:** string="abc"
- **限制类型:** TArray<FStruct>
- **常用程度:** ★★
指定结构数组里的结构成员属性内容来作为结构数组元素的显示标题。
## 重点是:
- 作用目标为结构数组TArray<FStruct>其他的TSetTMap不支持。
- TitleProperty顾名思义是用作标题的属性。但要更明确一些标题指的是结构数组元素在细节面板里显示的标题。属性指的是结构数组里的结构里面的属性。
- 然后下一步是TitleProperty的格式要怎么写。根据引擎源码TitleProperty最后是用FTitleMetadataFormatter来解析计算内容。通过查看其内部代码可知其TitleProperty格式可以为
- 如果TitleProperty里包含“{”则会把里面的字符串当作一个FTextFormat以“{ArgName}…”组织的格式字符串)。最终格式是以“{PropertyName}…”组织的字符串去找多个对应的属性。
- 否则就会把TitleProperty的全部当作PropertyName直接去找对应的属性名称。
## 测试代码:
```cpp
USTRUCT(BlueprintType)
struct INSIDER_API FMyArrayTitleStruct
{
GENERATED_BODY()
public:
FMyArrayTitleStruct() = default;
FMyArrayTitleStruct(int32 id) :MyInt(id) {}
UPROPERTY(BlueprintReadWrite, EditAnywhere)
int32 MyInt = 123;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
FString MyString=TEXT("Hello");
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float MyFloat=456.f;
};
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = TitlePropertyTest)
TArray<FMyArrayTitleStruct> MyStructArray_NoTitleProperty;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = TitlePropertyTest, meta = (TitleProperty="{MyString}[{MyInt}]"))
TArray<FMyArrayTitleStruct> MyStructArray_HasTitleProperty;
```
## 测试效果:
可以发现下面的数组元素的标题变为了“Hello[x]”而不是默认的“3 members”。
![Untitled](Untitled.png)
## 原理:
属性编辑器里属性节点如果发现有TitleProperty则会生成一个FTitleMetadataFormatter的TitlePropertyFormatter 来进行字符串格式的解析和输出结果内容。其内部其实真正用的又是FTextFormat这样才可以把多个属性的内容拼接成一个目标字符串。
当然SPropertyEditorTitle还注意到了如果有TitleProperty可能会实时的改变因此绑定了一个函数来进行Tick更新。
```cpp
//绑定一个函数来每tick获取名字
void SPropertyEditorTitle::Construct( const FArguments& InArgs, const TSharedRef<FPropertyEditor>& InPropertyEditor )
{
// If our property has title support we want to fetch the value every tick, otherwise we can just use a static value
static const FName NAME_TitleProperty = FName(TEXT("TitleProperty"));
const bool bHasTitleProperty = InPropertyEditor->GetProperty() && InPropertyEditor->GetProperty()->HasMetaData(NAME_TitleProperty);
if (bHasTitleProperty)
{
NameTextBlock =
SNew(STextBlock)
.Text(InPropertyEditor, &FPropertyEditor::GetDisplayName)
.Font(NameFont);
}
else
{
NameTextBlock =
SNew(STextBlock)
.Text(InPropertyEditor->GetDisplayName())
.Font(NameFont);
}
}
FText FPropertyEditor::GetDisplayName() const
{
FItemPropertyNode* ItemPropertyNode = PropertyNode->AsItemPropertyNode();
if ( ItemPropertyNode != NULL )
{
return ItemPropertyNode->GetDisplayName();
}
if (const FComplexPropertyNode* ComplexPropertyNode = PropertyNode->AsComplexNode())
{
const FText DisplayName = ComplexPropertyNode->GetDisplayName();
// Does this property define its own name?
if (!DisplayName.IsEmpty())
{
return DisplayName;
}
}
FString DisplayName;
PropertyNode->GetQualifiedName( DisplayName, true );
return FText::FromString(DisplayName);
}
//生成TitleFormatter来解析TitleProperty里面的内容最后得出文字。发现不支持MapSet因此只支持array。签名还有个判断ArrayIndex()==1的分支走进普通属性
FText FItemPropertyNode::GetDisplayName() const
{
if (CastField<FSetProperty>(ParentProperty) == nullptr && CastField<FMapProperty>(ParentProperty) == nullptr)
{
// Check if this property has Title Property Meta
static const FName NAME_TitleProperty = FName(TEXT("TitleProperty"));
FString TitleProperty = PropertyPtr->GetMetaData(NAME_TitleProperty);
if (!TitleProperty.IsEmpty())
{
// Find the property and get the right property handle
if (PropertyStruct != nullptr)
{
const TSharedPtr<IPropertyHandle> ThisAsHandle = PropertyEditorHelpers::GetPropertyHandle(NonConstThis->AsShared(), nullptr, nullptr);
TSharedPtr<FTitleMetadataFormatter> TitleFormatter = FTitleMetadataFormatter::TryParse(ThisAsHandle, TitleProperty);
if (TitleFormatter)
{
TitleFormatter->GetDisplayText(FinalDisplayName);
}
}
}
}
}
//生成一个TitlePropertyFormatter
void SPropertyEditorArrayItem::Construct( const FArguments& InArgs, const TSharedRef< class FPropertyEditor>& InPropertyEditor )
{
static const FName TitlePropertyFName = FName(TEXT("TitleProperty"));
// if this is a struct property, try to find a representative element to use as our stand in
if (PropertyEditor->PropertyIsA( FStructProperty::StaticClass() ))
{
const FProperty* MainProperty = PropertyEditor->GetProperty();
const FProperty* ArrayProperty = MainProperty ? MainProperty->GetOwner<const FProperty>() : nullptr;
if (ArrayProperty) // should always be true
{
TitlePropertyFormatter = FTitleMetadataFormatter::TryParse(PropertyEditor->GetPropertyHandle(), ArrayProperty->GetMetaData(TitlePropertyFName));
}
}
}
```
源码中例子:
读者还可以在UPropertyEditorTestObject里找到应用的例子。用testprops命令行就可以打开。
```cpp
UPROPERTY(EditAnywhere, Category=ArraysOfProperties, meta=(TitleProperty=IntPropertyInsideAStruct))
TArray<FPropertyEditorTestBasicStruct> StructPropertyArrayWithTitle;
UPROPERTY(EditAnywhere, Category=ArraysOfProperties, meta=(TitleProperty="{IntPropertyInsideAStruct} + {FloatPropertyInsideAStruct}"))
TArray<FPropertyEditorTestBasicStruct> StructPropertyArrayWithFormattedTitle;
UPROPERTY(EditAnywhere, Category=ArraysOfProperties, meta=(TitleProperty=ErrorProperty))
TArray<FPropertyEditorTestBasicStruct> StructPropertyArrayWithTitleError;
UPROPERTY(EditAnywhere, Category=ArraysOfProperties, meta=(TitleProperty="{ErrorProperty}"))
TArray<FPropertyEditorTestBasicStruct> StructPropertyArrayWithFormattedTitleError;
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB