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,15 @@
# AdvancedClassDisplay
- **功能描述:** 指定该类型的变量在高级显示里显示
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** bool
- **关联项:**
UCLASS[AdvancedClassDisplay](../../Specifier/UCLASS/Category/AdvancedClassDisplay/AdvancedClassDisplay.md)
- **常用程度:** ★★★

View File

@@ -0,0 +1,174 @@
# AllowEditInlineCustomization
- **功能描述:** 允许EditInline的对象属性可以自定义属性细节面板来编辑该对象内的数据。
- **使用位置:** UPROPERTY
- **元数据类型:** string="abc"
- **关联项:** [EditInline](../EditInline/EditInline.md)
- **常用程度:** ★
允许EditInline的对象属性可以自定义属性细节面板来编辑该对象内的数据。
## 测试代码:
```cpp
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyCommonObject :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
int32 MyInt = 123;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
FString MyString;
};
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyCustomAsset :public UObject
{
GENERATED_BODY()
public:
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (EditInline))
UMyCommonObject* MyCommonObject;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (EditInline,AllowEditInlineCustomization))
UMyCommonObject* MyCommonObject_Customization;
};
```
## 效果:
![Untitled](Untitled.png)
要做到自定义EditInline的效果采用自定义的IPropertyTypeCustomization和RegisterCustomPropertyTypeLayout也能做到。区别是正如上面代码里的UMyCustomAsset里面有两个同类型的UMyCommonObject*对象假如用IPropertyTypeCustomization的方式就会导致两个变量都变成自定义的UI模式。而用AllowEditInlineCustomization就可以使得其中你想要的那个变成自定义方式而其他的不做改变。
在用法上AllowEditInlineCustomization必须配合自定义的FAssetEditorToolkit来自己定义一个DetailView而不是只自定义某个类型在引擎统一的DetailView的显示然后再自定义IDetailCustomization来提供具体的Widget最后用RegisterInstancedCustomPropertyLayout来关联起来。
```cpp
DetailsView->RegisterInstancedCustomPropertyLayout(UMyCommonObject::StaticClass(),FOnGetDetailCustomizationInstance::CreateStatic(&FMyCommonObjectDetailsCustomization::MakeInstance));
```
这部分代码可参考MyCustomAsset的相关实现
## 源码:
```cpp
FDetailPropertyRow::FDetailPropertyRow(TSharedPtr<FPropertyNode> InPropertyNode, TSharedRef<FDetailCategoryImpl> InParentCategory, TSharedPtr<FComplexPropertyNode> InExternalRootNode)
{
static FName InlineCustomizationKeyMeta("AllowEditInlineCustomization");
if (PropertyNode->AsComplexNode() && ExternalRootNode.IsValid()) // AsComplexNode works both for objects and structs
{
// We are showing an entirely different object inline. Generate a layout for it now.
if (IDetailsViewPrivate* DetailsView = InParentCategory->GetDetailsView())
{
ExternalObjectLayout = MakeShared<FDetailLayoutData>();
DetailsView->UpdateSinglePropertyMap(InExternalRootNode, *ExternalObjectLayout, true);
}
}
else if (PropertyNode->HasNodeFlags(EPropertyNodeFlags::EditInlineNew) && PropertyNode->GetProperty()->HasMetaData(InlineCustomizationKeyMeta))
{
// Allow customization of 'edit inline new' objects if the metadata key has been specified.
// The child of this node, if set, will be an object node that we will want to treat as an 'external object layout'
TSharedPtr<FPropertyNode> ChildNode = PropertyNode->GetNumChildNodes() > 0 ? PropertyNode->GetChildNode(0) : nullptr;
TSharedPtr<FComplexPropertyNode> ComplexChildNode = StaticCastSharedPtr<FComplexPropertyNode>(ChildNode);
if (ComplexChildNode.IsValid())
{
// We are showing an entirely different object inline. Generate a layout for it now.
if (IDetailsViewPrivate* DetailsView = InParentCategory->GetDetailsView())
{
ExternalObjectLayout = MakeShared<FDetailLayoutData>();
DetailsView->UpdateSinglePropertyMap(ComplexChildNode, *ExternalObjectLayout, true);
}
}
}
}
```
作用的原理是在创建FDetailPropertyRow的时候即一个属性的在细节面板里的一行如果有AllowEditInlineCustomization就会创建ExternalObjectLayout 之后在FDetailPropertyRow的创建孩子的时候就会判断是否有ExternalObjectLayout如果有就可以应用上我们之前的Customization如果没有就会应用默认的设置。如下是使用ExternalObjectLayout的代码
```cpp
void FDetailPropertyRow::GenerateChildrenForPropertyNode( TSharedPtr<FPropertyNode>& RootPropertyNode, FDetailNodeList& OutChildren )
{
// Children should be disabled if we are disabled
TAttribute<bool> ParentEnabledState = TAttribute<bool>::CreateSP(this, &FDetailPropertyRow::GetEnabledState);
if( PropertyTypeLayoutBuilder.IsValid() && bShowCustomPropertyChildren )
{
const TArray< FDetailLayoutCustomization >& ChildRows = PropertyTypeLayoutBuilder->GetChildCustomizations();
for( int32 ChildIndex = 0; ChildIndex < ChildRows.Num(); ++ChildIndex )
{
TSharedRef<FDetailItemNode> ChildNodeItem = MakeShared<FDetailItemNode>(ChildRows[ChildIndex], ParentCategory.Pin().ToSharedRef(), ParentEnabledState);
ChildNodeItem->Initialize();
OutChildren.Add( ChildNodeItem );
}
}
else if (ExternalObjectLayout.IsValid() && ExternalObjectLayout->DetailLayout->HasDetails())
{
OutChildren.Append(ExternalObjectLayout->DetailLayout->GetAllRootTreeNodes());
//自定义的面板
}
else if ((bShowCustomPropertyChildren || !CustomPropertyWidget.IsValid()) && RootPropertyNode->GetNumChildNodes() > 0)
{
//正常的默认创建孩子
}
```
源码里使用的一个例子是LevelSequence上Bind Actor上的Binding Property的细节面板。
假如我们采用一些代码去掉
```cpp
USTRUCT()
struct FMovieSceneBindingPropertyInfo
{
GENERATED_BODY()
// Locator for the entry
UPROPERTY(EditAnywhere, Category = "Default", meta=(AllowedLocators="Actor", DisplayName="Actor"))
FUniversalObjectLocator Locator;
// Flags for how to resolve the locator
UPROPERTY()
ELocatorResolveFlags ResolveFlags = ELocatorResolveFlags::None;
UPROPERTY(Instanced, VisibleAnywhere, Category = "Default", meta=(EditInline, AllowEditInlineCustomization, DisplayName="Custom Binding Type"))
UMovieSceneCustomBinding* CustomBinding = nullptr;
};
//自己Hack 代码
UObject* obj = UInsiderLibrary::FindObjectWithNameSmart(TEXT("MovieSceneBindingPropertyInfo"));
UScriptStruct* ss = Cast<UScriptStruct>(obj);
FProperty* prop = ss->FindPropertyByName(TEXT("CustomBinding"));
prop->RemoveMetaData(TEXT("AllowEditInlineCustomization"));
```
效果就会从左变到右边:
![Untitled](AllowEditInlineCustomization/Untitled%201.png)
注册的方式也不同:
```cpp
void ULevelSequenceEditorSubsystem::AddBindingDetailCustomizations(TSharedRef<IDetailsView> DetailsView, TSharedPtr<ISequencer> ActiveSequencer, FGuid BindingGuid)
{
// TODO: Do we want to create a generalized way for folks to add instanced property layouts for other custom binding types so they can have access to sequencer context?
if (ActiveSequencer.IsValid())
{
UMovieSceneSequence* Sequence = ActiveSequencer->GetFocusedMovieSceneSequence();
UMovieScene* MovieScene = Sequence ? Sequence->GetMovieScene() : nullptr;
if (MovieScene)
{
FPropertyEditorModule& PropertyEditor = FModuleManager::Get().LoadModuleChecked<FPropertyEditorModule>(TEXT("PropertyEditor"));
DetailsView->RegisterInstancedCustomPropertyTypeLayout(FMovieSceneBindingPropertyInfo::StaticStruct()->GetFName(), FOnGetPropertyTypeCustomizationInstance::CreateLambda([](TWeakPtr<ISequencer> InSequencer, UMovieScene* InMovieScene, FGuid InBindingGuid, ULevelSequenceEditorSubsystem* LevelSequenceEditorSubsystem)
{
return MakeShared<FMovieSceneBindingPropertyInfoDetailCustomization>(InSequencer, InMovieScene, InBindingGuid, LevelSequenceEditorSubsystem);
}, ActiveSequencer.ToWeakPtr(), MovieScene, BindingGuid, this));
DetailsView->RegisterInstancedCustomPropertyLayout(UMovieSceneSpawnableActorBinding::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FMovieSceneSpawnableActorBindingBaseCustomization::MakeInstance, ActiveSequencer.ToWeakPtr(), MovieScene, BindingGuid));
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,15 @@
# AutoCollapseCategories
- **功能描述:** 指定类内部的属性目录自动折叠起来
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** strings="abc"
- **关联项:**
UCLASS[AutoCollapseCategories](../../Specifier/UCLASS/Category/AutoCollapseCategories/AutoCollapseCategories.md), [DontAutoCollapseCategories](../../Specifier/UCLASS/Category/DontAutoCollapseCategories.md), [AutoExpandCategories](../../Specifier/UCLASS/Category/AutoExpandCategories/AutoExpandCategories.md)
- **常用程度:** ★★★

View File

@@ -0,0 +1,15 @@
# AutoExpandCategories
- **功能描述:** 指定类内部的属性目录自动展开起来
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** strings="abc"
- **关联项:**
UCLASS[AutoExpandCategories](../../Specifier/UCLASS/Category/AutoExpandCategories/AutoExpandCategories.md), [AutoCollapseCategories](../../Specifier/UCLASS/Category/AutoCollapseCategories/AutoCollapseCategories.md)
- **常用程度:** ★★★

View File

@@ -0,0 +1,16 @@
# Category
- **功能描述:** 指定属性在细节面板中的分类
- **使用位置:** UFUNCTION, UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** string="A | B | C"
- **关联项:**
UFUNCTION[Category](../../Specifier/UFUNCTION/Category/Category.md)
UPROPERTY[Category](../../Specifier/UPROPERTY/DetaisPanel/Category/Category.md)
- **常用程度:** ★★★★★

View File

@@ -0,0 +1,17 @@
# ClassGroupNames
- **功能描述:** 指定ClassGroup的名字
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** strings="abc"
- **限制类型:** TArray<FString>
- **关联项:**
UCLASS[ClassGroup](../../Specifier/UCLASS/Category/ClassGroup/ClassGroup.md)
- **常用程度:** ★★★

View File

@@ -0,0 +1,61 @@
# DeprecatedNode
- **功能描述:** 用于BehaviorTreeNode或EnvQueryNode说明该类已废弃在编辑器中红色错误展示并有错误ToolTip提示
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** bool
- **限制类型:** BehaviorTreeNodeEnvQueryNode
- **常用程度:** ★★
在AI行为树或EQS的节点上设置标记该节点已经弃用。
## 源码中的例子:
```cpp
UCLASS(meta = (DeprecatedNode, DeprecationMessage = "Please use IsAtLocation decorator instead."), MinimalAPI)
class UBTDecorator_ReachedMoveGoal : public UBTDecorator
{
GENERATED_UCLASS_BODY()
};
UCLASS(MinimalAPI, meta=(DeprecatedNode, DeprecationMessage = "This class is now deprecated, please use RunMode supporting random results instead."))
class UEnvQueryTest_Random : public UEnvQueryTest
{
GENERATED_UCLASS_BODY()
};
```
## C++测试代码:
```cpp
UCLASS(meta = (DeprecatedNode, DeprecationMessage = "This BT node is deprecated. Don't use this anymore."), MinimalAPI)
class UBTTask_MyDeprecatedNode : public UBTTaskNode
{
GENERATED_UCLASS_BODY()
};
```
行为树里的结果如果加上DeprecatedNode就会红色显示并提示错误信息。
![Untitled](Untitled.png)
## 源码里测试的代码:
```cpp
FString FGraphNodeClassHelper::GetDeprecationMessage(const UClass* Class)
{
static FName MetaDeprecated = TEXT("DeprecatedNode");
static FName MetaDeprecatedMessage = TEXT("DeprecationMessage");
FString DefDeprecatedMessage("Please remove it!");
FString DeprecatedPrefix("DEPRECATED");
FString DeprecatedMessage;
if (Class && Class->HasAnyClassFlags(CLASS_Native) && Class->HasMetaData(MetaDeprecated))
{
DeprecatedMessage = DeprecatedPrefix + TEXT(": ");
DeprecatedMessage += Class->HasMetaData(MetaDeprecatedMessage) ? Class->GetMetaData(MetaDeprecatedMessage) : DefDeprecatedMessage;
}
return DeprecatedMessage;
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -0,0 +1,63 @@
# DisplayAfter
- **功能描述:** 使本属性在指定的属性之后显示。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** string="abc"
- **常用程度:** ★★★
使本属性在指定的属性之后显示。
- 默认情况下,属性在细节面板中的顺序是依照头文件中的定义顺序。但如果我们想自己调节这个顺序,就可以用该标记。
- 限制条件是这两个属性必须得是在同一个Category下。这也很好理解Category组织的优先级肯定更大。
## 测试代码:
```cpp
UCLASS(BlueprintType)
class INSIDER_API UMyProperty_Priority :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AfterTest)
int32 MyInt = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AfterTest)
FString MyString;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AfterTest, meta = (DisplayAfter = "MyInt"))
int32 MyInt_After = 123;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AfterTest2, meta = (DisplayAfter = "MyInt"))
int32 MyInt_After2 = 123;
};
```
## 测试效果:
可见MyInt_After直接在Int后显示。
而MyInt_After2 因为在不同的Category下因此就保留原样。
![Untitled](Untitled.png)
## 原理:
检查该属性如果有DisplayAfter就把它插入在指定的属性之后。
```cpp
void PropertyEditorHelpers::OrderPropertiesFromMetadata(TArray<FProperty*>& Properties)
{
const FString& DisplayAfterPropertyName = Prop->GetMetaData(NAME_DisplayAfter);
if (DisplayAfterPropertyName.IsEmpty())
{
InsertProperty(OrderedProperties);
}
else
{
TArray<TPair<FProperty*, int32>>& DisplayAfterProperties = DisplayAfterPropertyMap.FindOrAdd(FName(*DisplayAfterPropertyName));
InsertProperty(DisplayAfterProperties);
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1,42 @@
# DisplayPriority
- **功能描述:** 指定本属性在细节面板的显示顺序优先级,越小的优先级越高。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** int32
- **常用程度:** ★★★
指定本属性在细节面板的显示顺序优先级,越小的优先级越高。
- 如果有DisplayAfter的设置则DisplayAfter的优先级更高。
- 同样的限制得是在同Category里。
## 测试代码:
```cpp
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PriorityTest, meta = (DisplayPriority = 3))
int32 MyInt_P3 = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PriorityTest, meta = (DisplayPriority = 1))
int32 MyInt_P1 = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PriorityTest, meta = (DisplayPriority = 2))
int32 MyInt_P2 = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PriorityTest, meta = (DisplayPriority = 4,DisplayAfter="MyInt_P1"))
int32 MyInt_P4 = 123;
```
## 测试结果:
P4即使优先级比较低但因为DisplayAfter也仍然排在了P1之后。
![Untitled](Untitled.png)
## 原理:
排序的逻辑在这个函数内,自行查看就好。一个简单的插入排序算法。
```cpp
void PropertyEditorHelpers::OrderPropertiesFromMetadata(TArray<FProperty*>& Properties)
{}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

View File

@@ -0,0 +1,77 @@
# EditCondition
- **功能描述:** 给一个属性指定另外一个属性或者表达式来作为是否可编辑的条件。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** string="abc"
- **关联项:** [EditConditionHides](../EditConditionHides/EditConditionHides.md), [InlineEditConditionToggle](../InlineEditConditionToggle/InlineEditConditionToggle.md), [HideEditConditionToggle](../HideEditConditionToggle/HideEditConditionToggle.md)
- **常用程度:** ★★★★★
给一个属性指定另外一个属性或者表达式来作为是否可编辑的条件。
- 表达式里引用的属性必须得是同一个类或结构范围内的。
## 测试代码:
```cpp
UCLASS(BlueprintType)
class INSIDER_API UMyProperty_EditCondition_Test :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Property)
bool MyBool;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Property)
int32 MyInt = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Property, meta = (EditCondition = "MyBool"))
int32 MyInt_EditCondition = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Property, meta = (EditCondition = "!MyBool"))
int32 MyInt_EditCondition_Not = 123;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PropertyExpression)
int32 MyFirstInt = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PropertyExpression)
int32 MySecondInt = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PropertyExpression, meta = (EditCondition = "(MyFirstInt+MySecondInt)==500"))
int32 MyInt_EditConditionExpression = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PropertyExpression, meta = (EditCondition = "!((MyFirstInt+MySecondInt)==500)"))
int32 MyInt_EditConditionExpression_Not = 123;
};
```
## 测试结果:
- 可以通过bool单个属性来控制其他属性是否可以编辑
- 也可以通过一个表达式引入更复杂的计算机制来决定是否来编辑。
![EditCondition](EditCondition.gif)
## 原理:
在细节面板的属性初始化的时候会判断该属性EditCondition设置如果有值会创建FEditConditionParser来解析表达式然后求值。
```cpp
void FPropertyNode::InitNode(const FPropertyNodeInitParams& InitParams)
{
const FString& EditConditionString = MyProperty->GetMetaData(TEXT("EditCondition"));
// see if the property supports some kind of edit condition and this isn't the "parent" property of a static array
const bool bIsStaticArrayParent = MyProperty->ArrayDim > 1 && GetArrayIndex() != -1;
if (!EditConditionString.IsEmpty() && !bIsStaticArrayParent)
{
EditConditionExpression = EditConditionParser.Parse(EditConditionString);
if (EditConditionExpression.IsValid())
{
EditConditionContext = MakeShareable(new FEditConditionContext(*this));
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

View File

@@ -0,0 +1,58 @@
# EditConditionHides
- **功能描述:** 在已经有EditCondition的情况下指定该属性在EditCondition不满足的情况下隐藏起来。
- **使用位置:** UPROPERTY
- **元数据类型:** bool
- **关联项:** [EditCondition](../EditCondition/EditCondition.md)
- **常用程度:** ★★★★★
在已经有EditCondition的情况下指定该属性在EditCondition不满足的情况下隐藏起来。
## 测试代码:
```cpp
UCLASS(BlueprintType)
class INSIDER_API UMyProperty_EditCondition_Test :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Property)
bool MyBool;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Property, meta = (EditConditionHides, EditCondition = "MyBool"))
int32 MyInt_EditCondition_Hides = 123;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PropertyExpression)
int32 MyFirstInt = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PropertyExpression)
int32 MySecondInt = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PropertyExpression, meta = (EditConditionHides, EditCondition = "(MyFirstInt+MySecondInt)==500"))
int32 MyInt_EditConditionExpression_Hides = 123;
};
```
## 测试效果:
下面的图中可以明显见到两个属性随着条件的满足显示了出来。
![EditConditionHides](EditConditionHides.gif)
## 原理:
其实就是加了个是否显示的判断。
```cpp
bool FPropertyNode::IsOnlyVisibleWhenEditConditionMet() const
{
static const FName Name_EditConditionHides("EditConditionHides");
if (Property.IsValid() && Property->HasMetaData(Name_EditConditionHides))
{
return HasEditCondition();
}
return false;
}
```

View File

@@ -0,0 +1,100 @@
# EditInline
- **功能描述:** 为对象属性创建一个实例,并作为子对象。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** bool
- **关联项:** [NoEditInline](../NoEditInline.md), [AllowEditInlineCustomization](../AllowEditInlineCustomization/AllowEditInlineCustomization.md), [ForceInlineRow](../ForceInlineRow/ForceInlineRow.md)
UPROPERTY[Instanced](../../../Specifier/UPROPERTY/Instance/Instanced/Instanced.md)
- **常用程度:** ★★★
为对象属性创建一个实例,并作为子对象。
也可以手动设置。如果UClass上有EditInlineNew但是属性上没有Instanced这个时候可以手动的设置EditInline然后通过自己手动赋值对象引用属性来使得这个对象可以直接编辑。
和ShowInnerProperties是否等价EditInline在对象容器Array,Map,Set的情况下也可以使用。但ShowInnerProperties只能在单个对象属性上生效。
可以设置在Struct上看源码里也有该设置。但其实并没有效果。
## 示例代码:
```cpp
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UMyProperty_EditInline_Sub* MyObject;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (EditInline))
UMyProperty_EditInline_Sub* MyObject_EditInline;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (NoEditInline))
UMyProperty_EditInline_Sub* MyObject_NoEditInline;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<UMyProperty_EditInline_Sub*> MyObjectArray;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (EditInline))
TArray<UMyProperty_EditInline_Sub*> MyObjectArray_EditInline;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (NoEditInline))
TArray<UMyProperty_EditInline_Sub*> MyObjectArray_NoEditInline;
```
## 蓝图效果:
![Untitled](Untitled.png)
## 原理:
会相应的设置EPropertyNodeFlags::EditInlineNew。
```cpp
void FPropertyNode::InitNode(const FPropertyNodeInitParams& InitParams)
{
// we are EditInlineNew if this property has the flag, or if inside a container that has the flag.
bIsEditInlineNew = GotReadAddresses && bIsObjectOrInterface && !MyProperty->HasMetaData(Name_NoEditInline) &&
(MyProperty->HasMetaData(Name_EditInline) || (bIsInsideContainer && OwnerProperty->HasMetaData(Name_EditInline)));
bShowInnerObjectProperties = bIsObjectOrInterface && MyProperty->HasMetaData(Name_ShowInnerProperties);
if (bIsEditInlineNew)
{
SetNodeFlags(EPropertyNodeFlags::EditInlineNew, true);
}
else if (bShowInnerObjectProperties)
{
SetNodeFlags(EPropertyNodeFlags::ShowInnerObjectProperties, true);
}
}
bool SPropertyEditorEditInline::Supports( const FPropertyNode* InTreeNode, int32 InArrayIdx )
{
return InTreeNode
&& InTreeNode->HasNodeFlags(EPropertyNodeFlags::EditInlineNew)
&& InTreeNode->FindObjectItemParent()
&& !InTreeNode->IsPropertyConst();
}
void FItemPropertyNode::InitExpansionFlags(void)
{
FProperty* MyProperty = GetProperty();
if (TSharedPtr<FPropertyNode>& ValueNode = GetOrCreateOptionalValueNode())
{
// This is a set optional, so check its SetValue instead.
MyProperty = ValueNode->GetProperty();
}
bool bExpandableType = CastField<FStructProperty>(MyProperty)
|| (CastField<FArrayProperty>(MyProperty) || CastField<FSetProperty>(MyProperty) || CastField<FMapProperty>(MyProperty));
if (bExpandableType
|| HasNodeFlags(EPropertyNodeFlags::EditInlineNew)
|| HasNodeFlags(EPropertyNodeFlags::ShowInnerObjectProperties)
|| (MyProperty->ArrayDim > 1 && ArrayIndex == -1))
{
SetNodeFlags(EPropertyNodeFlags::CanBeExpanded, true);
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@@ -0,0 +1,154 @@
# ForceInlineRow
- **功能描述:** 强制TMap属性里的结构key和其他Value合并到同一行来显示
- **使用位置:** UPROPERTY
- **元数据类型:** bool
- **关联项:** [EditInline](../EditInline/EditInline.md)
- **常用程度:** ★
强制TMap属性里的结构key和其他Value合并到同一行来显示。这里要注意的点是
- 本属性是TMap属性这样才有Key。TArray或TSet是没有用的。
- FStruct作为Key这样源码里的机制才能生效因为判断的就是Key Property
- 该FStruct有注册相关的IPropertyTypeCustomization这样才能自定义该结构的显示UI
- 该IPropertyTypeCustomization的ShouldInlineKey返回false默认就是否则true的话则不管有没有标ForceInlineRow都会合并成一行
## 测试代码:
```cpp
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TMap<FMyCommonStruct, int32> MyStructMap;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ForceInlineRow))
TMap<FMyCommonStruct, int32> MyStructMap_ForceInlineRow;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TMap<int32, FMyCommonStruct> MyStructMap2;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ForceInlineRow))
TMap<int32, FMyCommonStruct> MyStructMap_ForceInlineRow2;
void FMyCommonStructCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils)
{
HeaderRow.NameContent()[SNew(STextBlock).Text(INVTEXT("This is MyCommonStruct"))];
TSharedPtr<IPropertyHandle> IntPropertyHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMyCommonStruct, MyInt));
TSharedPtr<IPropertyHandle> StringPropertyHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMyCommonStruct, MyString));
HeaderRow.ValueContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(5.0f, 0.0f).AutoWidth()
[
IntPropertyHandle->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.Padding(5.0f, 0.0f).AutoWidth()
[
IntPropertyHandle->CreatePropertyValueWidget()
]
+ SHorizontalBox::Slot()
.Padding(5.0f, 0.0f).AutoWidth()
[
StringPropertyHandle->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.Padding(5.0f, 0.0f).AutoWidth()
[
StringPropertyHandle->CreatePropertyValueWidget()
]
];
}
```
## 测试效果:
可以见到MyStructMap的数据项展示就分为了两行。而带有ForceInlineRow之后数据项UI就合并为一行显得更加的简洁。
在下面也特别观察到如果把FStruct作为Value则是没有这个区别的。
![Untitled](Untitled.png)
假如不注册FMyCommonStruct相应的IPropertyTypeCustomization的话则结构的属性UI采用默认方式显示则都是分为两行。
![Untitled](Untitled%201.png)
而假如FMyCommonStruct的IPropertyTypeCustomization的ShouldInlineKey返回true则会导致即使没有ForceInlineRow也会把该拥有该结构作为Key的属性给都合并为一行显示这个时候就失去ForceInlineRow的作用和区别了。
![Untitled](Untitled%202.png)
## 原理:
该部分逻辑也同样处于在FDetailPropertyRow的构造函数创建过程中判断是否有GetPropertyKeyNode则其实是在要求TMap属性。
接着作为Key的类型如果是UObject*则因为NeedsKeyNode一直返回false则无论如何都会进入MakePropertyEditor的分支。
因此此项测试的类型其实是Struct这样就必须依赖bInlineRow 和FoundPropertyCustomisation 的配合。这个时候就必须有IPropertyTypeCustomization才会进入分支而且如果IPropertyTypeCustomization::ShouldInlineKey()返回true则就不管属性上的ForceInlineRow如何都会进入分支。否则就靠属性上的ForceInlineRow这个时候才是这个Meta发挥作用的时候。
```cpp
FDetailPropertyRow::FDetailPropertyRow(TSharedPtr<FPropertyNode> InPropertyNode, TSharedRef<FDetailCategoryImpl> InParentCategory, TSharedPtr<FComplexPropertyNode> InExternalRootNode)
{
if (PropertyNode->GetPropertyKeyNode().IsValid())
{
TSharedPtr<IPropertyTypeCustomization> FoundPropertyCustomisation = GetPropertyCustomization(PropertyNode->GetPropertyKeyNode().ToSharedRef(), ParentCategory.Pin().ToSharedRef());
bool bInlineRow = FoundPropertyCustomisation != nullptr ? FoundPropertyCustomisation->ShouldInlineKey() : false;
static FName InlineKeyMeta("ForceInlineRow");
bInlineRow |= InPropertyNode->GetParentNode()->GetProperty()->HasMetaData(InlineKeyMeta);
// Only create the property editor if it's not a struct or if it requires to be inlined (and has customization)
if (!NeedsKeyNode(PropertyNodeRef, InParentCategory) || (bInlineRow && FoundPropertyCustomisation != nullptr))
{
CachedKeyCustomTypeInterface = FoundPropertyCustomisation;
MakePropertyEditor(PropertyNode->GetPropertyKeyNode().ToSharedRef(), Utilities, PropertyKeyEditor);
}
}
}
bool FDetailPropertyRow::NeedsKeyNode(TSharedRef<FPropertyNode> InPropertyNode, TSharedRef<FDetailCategoryImpl> InParentCategory)
{
FStructProperty* KeyStructProp = CastField<FStructProperty>(InPropertyNode->GetPropertyKeyNode()->GetProperty());
return KeyStructProp != nullptr;
}
```
源码里使用的例子:
在源码里搜索发现到该例子但实际上其实这里HLODSetups上的ForceInlineRow并不能起作用。
```cpp
USTRUCT()
struct FRuntimePartitionDesc
{
GENERATED_USTRUCT_BODY()
#if WITH_EDITORONLY_DATA
/** Partition class */
UPROPERTY(EditAnywhere, Category = RuntimeSettings)
TSubclassOf<URuntimePartition> Class;
/** Name for this partition, used to map actors to it through the Actor.RuntimeGrid property */
UPROPERTY(EditAnywhere, Category = RuntimeSettings, Meta = (EditCondition = "Class != nullptr", HideEditConditionToggle))
FName Name;
/** Main partition object */
UPROPERTY(VisibleAnywhere, Category = RuntimeSettings, Instanced, Meta = (EditCondition = "Class != nullptr", HideEditConditionToggle, NoResetToDefault, TitleProperty = "Name"))
TObjectPtr<URuntimePartition> MainLayer;
/** HLOD setups used by this partition, one for each layers in the hierarchy */
UPROPERTY(EditAnywhere, Category = RuntimeSettings, Meta = (EditCondition = "Class != nullptr", HideEditConditionToggle, ForceInlineRow))
TArray<FRuntimePartitionHLODSetup> HLODSetups;
#endif
#if WITH_EDITOR
void UpdateHLODPartitionLayers();
#endif
};
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@@ -0,0 +1,15 @@
# HideBehind
- **功能描述:** 只在指定的属性为true或不为空的时候本属性才显示
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** string="abc"
- **限制类型:** Foliage模块中
- **常用程度:** ★
```cpp
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Placement, meta=(UIMin = 0, ClampMin = 0, UIMax = 359, ClampMax = 359, HideBehind="AlignToNormal"))
float AlignMaxAngle;
```
只在Foliage里用到其实用EditCondition就可以达到同样的效果了。

View File

@@ -0,0 +1,9 @@
# HideCategories
- **功能描述:** 隐藏的类别
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** strings="abc"
Related To UCLASS: ShowCategories (../../Specifier/UCLASS/ShowCategories.md)
- **关联项:** ShowCategories (ShowCategories.md)
- **常用程度:** ★★★

View File

@@ -0,0 +1,84 @@
# HideEditConditionToggle
- **功能描述:** 用在使用EditCondition的属性上表示该属性不想要其EditCondition用到的属性被隐藏起来。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** bool
- **限制类型:** bool
- **关联项:** [EditCondition](../EditCondition/EditCondition.md)
- **常用程度:** ★★★★★
用在使用EditCondition的属性上表示该属性不想要其EditCondition用到的属性被隐藏起来。和InlineEditConditionToggle是有相反的作用。
## 测试代码:
```cpp
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InlineEditConditionToggle, meta = (InlineEditConditionToggle))
bool MyBool_Inline;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InlineEditConditionToggle, meta = (EditCondition = "MyBool_Inline"))
int32 MyInt_EditCondition_UseInline = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InlineEditConditionToggle, meta = (HideEditConditionToggle,EditCondition = "MyBool_Inline"))
int32 MyInt_EditCondition_UseInline_Hide = 123;
};
```
## 测试效果:
![HideEditConditionToggle](HideEditConditionToggle.gif)
## 原理:
判断如果有HideEditConditionToggle就支持不支持当前行有单选框的按钮。
```cpp
bool FPropertyNode::SupportsEditConditionToggle() const
{
if (!Property.IsValid())
{
return false;
}
FProperty* MyProperty = Property.Get();
static const FName Name_HideEditConditionToggle("HideEditConditionToggle");
if (EditConditionExpression.IsValid() && !Property->HasMetaData(Name_HideEditConditionToggle))
{
const FBoolProperty* ConditionalProperty = EditConditionContext->GetSingleBoolProperty(EditConditionExpression);
if (ConditionalProperty != nullptr)
{
// There are 2 valid states for inline edit conditions:
// 1. The property is marked as editable and has InlineEditConditionToggle set.
// 2. The property is not marked as editable and does not have InlineEditConditionToggle set.
// In both cases, the original property will be hidden and only show up as a toggle.
static const FName Name_InlineEditConditionToggle("InlineEditConditionToggle");
const bool bIsInlineEditCondition = ConditionalProperty->HasMetaData(Name_InlineEditConditionToggle);
const bool bIsEditable = ConditionalProperty->HasAllPropertyFlags(CPF_Edit);
if (bIsInlineEditCondition == bIsEditable)
{
return true;
}
if (bIsInlineEditCondition && !bIsEditable)
{
UE_LOG(LogPropertyNode, Warning, TEXT("Property being used as inline edit condition is not editable, but has redundant InlineEditConditionToggle flag. Field \"%s\" in class \"%s\"."), *ConditionalProperty->GetNameCPP(), *Property->GetOwnerStruct()->GetName());
return true;
}
// The property is already shown, and not marked as inline edit condition.
if (!bIsInlineEditCondition && bIsEditable)
{
return false;
}
}
}
return false;
}
```

View File

@@ -0,0 +1,69 @@
# HideInDetailPanel
- **功能描述:** 在Actor的事件面板里隐藏该动态多播委托属性。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** bool
- **限制类型:** Actor里的动态多播委托
- **常用程度:** ★★
在Actor的事件面板里隐藏该动态多播委托属性。
## 测试代码:
```cpp
UCLASS(BlueprintType,Blueprintable)
class INSIDER_API AMyProperty_HideInDetailPanel :public AActor
{
GENERATED_BODY()
public:
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnMyHideTestEvent);
UPROPERTY(BlueprintAssignable, Category = "Event")
FOnMyHideTestEvent MyEvent;
UPROPERTY(BlueprintAssignable, Category = "Event", meta = (HideInDetailPanel))
FOnMyHideTestEvent MyEvent_HideInDetailPanel;
};
```
## 测试效果:
测试步骤是在蓝图里创建AMyProperty_HideInDetailPanel 的子类然后观察Event的显示情况。
可见MyEvent会显示在Class Defautls里的Events而MyEvent_HideInDetailPanel则没有显示。
不过MyEvent_HideInDetailPanel依然是可以在蓝图里进行绑定只不过默认没显示在UI上而已。
![Untitled](Untitled.png)
## 原理:
先判断没有这个标记然后创建相应的UI控件。
```cpp
void FActorDetails::AddEventsCategory(IDetailLayoutBuilder& DetailBuilder)
{
IDetailCategoryBuilder& EventsCategory = DetailBuilder.EditCategory("Events", FText::GetEmpty(), ECategoryPriority::Uncommon);
static const FName HideInDetailPanelName("HideInDetailPanel");
// Find all the Multicast delegate properties and give a binding button for them
for (TFieldIterator<FMulticastDelegateProperty> PropertyIt(Actor->GetClass(), EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
{
FMulticastDelegateProperty* Property = *PropertyIt;
// Only show BP assiangable, non-hidden delegates
if (!Property->HasAnyPropertyFlags(CPF_Parm) && Property->HasAllPropertyFlags(CPF_BlueprintAssignable) && !Property->HasMetaData(HideInDetailPanelName))
{}
}
}
void FBlueprintDetails::AddEventsCategory(IDetailLayoutBuilder& DetailBuilder, FName PropertyName, UClass* PropertyClass)
{
static const FName HideInDetailPanelName("HideInDetailPanel");
// Check for multicast delegates that we can safely assign
if ( !Property->HasAnyPropertyFlags(CPF_Parm) && Property->HasAllPropertyFlags(CPF_BlueprintAssignable) &&
!Property->HasMetaData(HideInDetailPanelName) )
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

View File

@@ -0,0 +1,10 @@
# IgnoreCategoryKeywordsInSubclasses
- **功能描述:** 用于让一个类的首个子类忽略所有继承的 ShowCategories 和 HideCategories 说明符。
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** bool
Related To UCLASS: ComponentWrapperClass (../../Specifier/UCLASS/ComponentWrapperClass.md)
- **常用程度:** ★
和ComponentWrapperClass相互关联

View File

@@ -0,0 +1,88 @@
# InlineEditConditionToggle
- **功能描述:** 使这个bool属性在被用作EditCondition的时候内联到对方的属性行里成为一个单选框而不是自己成为一个编辑行。
- **使用位置:** UPROPERTY
- **元数据类型:** bool
- **限制类型:** bool
- **关联项:** [EditCondition](../EditCondition/EditCondition.md)
- **常用程度:** ★★★★★
使这个bool属性在被用作EditCondition的时候内联到对方的属性行里成为一个单选框而不是自己成为一个编辑行。
虽然EditCondition支持别的类型属性或者是表达式但是这个InlineEditConditionToggle只支持bool属性。
## 测试代码:
```cpp
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InlineEditConditionToggle, meta = (InlineEditConditionToggle))
bool MyBool_Inline;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InlineEditConditionToggle, meta = (EditCondition = "MyBool_Inline"))
int32 MyInt_EditCondition_UseInline = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InlineEditConditionToggle)
int32 MyThirdInt_Inline = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InlineEditConditionToggle, meta = (EditCondition = "MyThirdInt_Inline>200"))
int32 MyInt_EditConditionExpression_UseInline = 123;
```
## 测试效果:
可见MyBool_Inline变成了单选框。而MyThirdInt_Inline就没有被隐藏掉。
![InlineEditConditionToggle](InlineEditConditionToggle.gif)
## 原理:
可以看到用这个判断是否支持出现单选框。
```cpp
bool FPropertyNode::SupportsEditConditionToggle() const
{
if (!Property.IsValid())
{
return false;
}
FProperty* MyProperty = Property.Get();
static const FName Name_HideEditConditionToggle("HideEditConditionToggle");
if (EditConditionExpression.IsValid() && !Property->HasMetaData(Name_HideEditConditionToggle))
{
const FBoolProperty* ConditionalProperty = EditConditionContext->GetSingleBoolProperty(EditConditionExpression);
if (ConditionalProperty != nullptr)
{
// There are 2 valid states for inline edit conditions:
// 1. The property is marked as editable and has InlineEditConditionToggle set.
// 2. The property is not marked as editable and does not have InlineEditConditionToggle set.
// In both cases, the original property will be hidden and only show up as a toggle.
static const FName Name_InlineEditConditionToggle("InlineEditConditionToggle");
const bool bIsInlineEditCondition = ConditionalProperty->HasMetaData(Name_InlineEditConditionToggle);
const bool bIsEditable = ConditionalProperty->HasAllPropertyFlags(CPF_Edit);
if (bIsInlineEditCondition == bIsEditable)
{
return true;
}
if (bIsInlineEditCondition && !bIsEditable)
{
UE_LOG(LogPropertyNode, Warning, TEXT("Property being used as inline edit condition is not editable, but has redundant InlineEditConditionToggle flag. Field \"%s\" in class \"%s\"."), *ConditionalProperty->GetNameCPP(), *Property->GetOwnerStruct()->GetName());
return true;
}
// The property is already shown, and not marked as inline edit condition.
if (!bIsInlineEditCondition && bIsEditable)
{
return false;
}
}
}
return false;
}
```

View File

@@ -0,0 +1,130 @@
# MaxPropertyDepth
- **功能描述:** 指定对象或结构在细节面板里展开的层数。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** int32
- **限制类型:** 对象或结构属性
- **常用程度:** ★
指定对象或结构在细节面板里展开的层数。
- 默认是没有限制的,可以一直递归展开到最深层次字段。
- 如果对象的子对象再有子对象,这样递归很多层级,可能我们会想要限制不想展开太深,因此我们可以指定一个层级限制。
- 取值-1表示没有限制0表示完全不展开>0表示限制的层数。
- 源码里没有找到例子,但却是可以工作的。
## 测试代码:
```cpp
USTRUCT(BlueprintType)
struct INSIDER_API FMyStructDepth1
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
int32 MyInt1 = 123;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
FString MyString1;
};
USTRUCT(BlueprintType)
struct INSIDER_API FMyStructDepth2
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
FMyStructDepth1 MyStruct1;
};
USTRUCT(BlueprintType)
struct INSIDER_API FMyStructDepth3
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
FMyStructDepth2 MyStruct2;
};
USTRUCT(BlueprintType)
struct INSIDER_API FMyStructDepth4
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
FMyStructDepth3 MyStruct3;
};
UCLASS(BlueprintType)
class INSIDER_API UMyProperty_MaxPropertyDepth :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FMyStructDepth4 MyStruct;
UPROPERTY(EditAnywhere, BlueprintReadWrite,meta=(MaxPropertyDepth=2))
FMyStructDepth4 MyStruct_Depth;
};
```
## 测试效果:
![Untitled](Untitled.png)
## 原理:
在每个FPropertyNode构建子节点的时候检查一下当前的MaxChildDepthAllowed ,超过了就不继续往下构建。
```cpp
/** Safety Value representing Depth in the property tree used to stop diabolical topology cases
* -1 = No limit on children
* 0 = No more children are allowed. Do not process child nodes
* >0 = A limit has been set by the property and will tick down for successive children
*/
int32 MaxChildDepthAllowed;
void FPropertyNode::InitNode(const FPropertyNodeInitParams& InitParams)
{
//Get the property max child depth
static const FName Name_MaxPropertyDepth("MaxPropertyDepth");
if (Property->HasMetaData(Name_MaxPropertyDepth))
{
int32 NewMaxChildDepthAllowed = Property->GetIntMetaData(Name_MaxPropertyDepth);
//Ensure new depth is valid. Otherwise just let the parent specified value stand
if (NewMaxChildDepthAllowed > 0)
{
//if there is already a limit on the depth allowed, take the minimum of the allowable depths
if (MaxChildDepthAllowed >= 0)
{
MaxChildDepthAllowed = FMath::Min(MaxChildDepthAllowed, NewMaxChildDepthAllowed);
}
else
{
//no current limit, go ahead and take the new limit
MaxChildDepthAllowed = NewMaxChildDepthAllowed;
}
}
}
}
void FPropertyNode::RebuildChildren()
{
if (MaxChildDepthAllowed != 0)
{
//the case where we don't want init child nodes is when an Item has children that we don't want to display
//the other option would be to make each node "Read only" under that item.
//The example is a material assigned to a static mesh.
if (HasNodeFlags(EPropertyNodeFlags::CanBeExpanded) && (ChildNodes.Num() == 0))
{
InitChildNodes();
if (ExpandedPropertyItemSet.Size() > 0)
{
FPropertyNodeUtils::SetExpandedItems(ThisAsSharedRef, ExpandedPropertyItemSet);
}
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1,18 @@
# NoEditInline
- **功能描述:** Object properties pointing to an UObject instance whos class is marked editinline will not show their properties inline in property windows. Useful for getting actor components to appear in the component tree but not inline in the root actor details panel.
- **使用位置:** UPROPERTY
- **元数据类型:** bool
- **限制类型:** UObject*
- **关联项:** EditInline (EditInline.md)
对象引用默认就不能EditInline因此也不需要额外再加上这个。除非Instanced之后
结构属性默认就可以EditInline加上这个后也没有作用因此也不需要加上这个。
在源码中只找到:
```cpp
UPROPERTY(VisibleAnywhere, Category = "Connection Point", meta = (NoEditInline))
FLinearColor Color = FLinearColor::Black;
```

View File

@@ -0,0 +1,46 @@
# NoResetToDefault
- **功能描述:** 禁用和隐藏属性在细节面板上的“重置”功能。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** bool
- **常用程度:** ★★★
禁用和隐藏属性在细节面板上的“重置”功能。
## 测试代码:
```cpp
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category=ResetToDefaultTest)
int32 MyInt_Default = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category=ResetToDefaultTest, meta = (NoResetToDefault))
int32 MyInt_NoResetToDefault = 123;
```
## 测试效果:
可以发现默认的属性在改变值后右侧会出现一个重置按钮以便让属性重置回默认值。NoResetToDefault的作用就是去除这个功能。
![ResetToDefaultTest](ResetToDefaultTest.gif)
## 原理:
编辑器里会判断这个meta如果没有则创建SResetToDefaultPropertyEditor。
```cpp
bool SSingleProperty::GeneratePropertyCustomization()
{
if (!PropertyEditor->GetPropertyHandle()->HasMetaData(TEXT("NoResetToDefault")) && !bShouldHideResetToDefault)
{
HorizontalBox->AddSlot()
.Padding( 2.0f )
.AutoWidth()
.VAlign( VAlign_Center )
[
SNew( SResetToDefaultPropertyEditor, PropertyEditor->GetPropertyHandle() )
];
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@@ -0,0 +1,15 @@
# PrioritizeCategories
- **功能描述:** 把指定的属性目录优先显示在前面
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** strings="abc"
- **关联项:**
UCLASS[PrioritizeCategories](../../Specifier/UCLASS/Category/PrioritizeCategories/PrioritizeCategories.md)
- **常用程度:** ★★★

View File

@@ -0,0 +1,16 @@
# ReapplyCondition
- **功能描述:** // Properties that have a ReapplyCondition should be disabled behind the specified property when in reapply mode
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** string="abc"
- **常用程度:** ★
## 代码:
```cpp
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Placement, meta=(UIMin = 0, ClampMin = 0, UIMax = 359, ClampMax = 359, ReapplyCondition="ReapplyRandomPitchAngle"))
float RandomPitchAngle;
```
也只在Foliage中用到。

View File

@@ -0,0 +1,24 @@
# ShowCategories
- **功能描述:** 显示类别
- **使用位置:** UCLASS
- **元数据类型:** strings="abc"
- **关联项:** [HideCategories](HideCategories.md)
在类上面标记的ShowCategories并不会保存到meta中去只是用来抹除基类HideCategories的设置。因此meta里的ShowCategories是没有用到的。
```cpp
//(BlueprintType = true, IncludePath = Class/Display/MyClass_HideCategories.h, IsBlueprintBase = true, ModuleRelativePath = Class/Display/MyClass_HideCategories.h)
UCLASS(Blueprintable, ShowCategories = MyGroup1)
class INSIDER_API UMyClass_ShowCategories :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int Property_NotInGroup;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MyGroup1)
int Property_Group1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyGroup2 | MyGroup22")
int Property_Group222;
};
```

View File

@@ -0,0 +1,7 @@
# UsesHierarchy
- **功能描述:** 说明类使用层级数据。用于实例化“细节”面板中的层级编辑功能。
- **使用位置:** UCLASS
- **引擎模块:** DetailsPanel
- **元数据类型:** bool
- **常用程度:** 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,93 @@
# bShowOnlyWhenTrue
- **功能描述:** 根据编辑器config配置文件里字段值来决定当前属性是否显示。
- **使用位置:** UPROPERTY
- **引擎模块:** DetailsPanel
- **元数据类型:** string="abc"
- **常用程度:** ★
根据编辑器config配置文件里字段值来决定当前属性是否显示。
- 这个编辑器config配置文件指的是GEditorPerProjectIni因此一般是Config\DefaultEditorPerProjectUserSettings.ini
- 其中Section的名字是“UnrealEd.PropertyFilters”
- 然后Key的值就可以定了。
在源码里没有找到使用的例子,但这依然是可以工作的。
## 测试代码:
```cpp
D:\github\GitWorkspace\Hello\Config\DefaultEditorPerProjectUserSettings.ini
[UnrealEd.PropertyFilters]
ShowMyInt=true
ShowMyString=false
UCLASS(BlueprintType)
class INSIDER_API UMyProperty_Show :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MyInt = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (bShowOnlyWhenTrue = "ShowMyInt"))
int32 MyInt_WithShowOnly = 123;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (bShowOnlyWhenTrue = "ShowMyString"))
FString MyString_WithShowOnly;
};
```
## 测试结果:
可见MyString_WithShowOnly就没有显示出来因为我们在DefaultEditorPerProjectUserSettings中配置了ShowMyString=false。
![Untitled](Untitled.png)
## 原理:
就是取得config中的值用来决定属性框是否显示。
```cpp
void FObjectPropertyNode::GetCategoryProperties(const TSet<UClass*>& ClassesToConsider, const FProperty* CurrentProperty, bool bShouldShowDisableEditOnInstance, bool bShouldShowHiddenProperties,
const TSet<FName>& CategoriesFromBlueprints, TSet<FName>& CategoriesFromProperties, TArray<FName>& SortedCategories)
{
bool bMetaDataAllowVisible = true;
const FString& ShowOnlyWhenTrueString = CurrentProperty->GetMetaData(Name_bShowOnlyWhenTrue);
if (ShowOnlyWhenTrueString.Len())
{
//ensure that the metadata visibility string is actually set to true in order to show this property
GConfig->GetBool(TEXT("UnrealEd.PropertyFilters"), *ShowOnlyWhenTrueString, bMetaDataAllowVisible, GEditorPerProjectIni);
}
if (bMetaDataAllowVisible)
{
if (PropertyEditorHelpers::ShouldBeVisible(*this, CurrentProperty) && !HiddenCategories.Contains(CategoryName))
{
if (!CategoriesFromBlueprints.Contains(CategoryName) && !CategoriesFromProperties.Contains(CategoryName))
{
SortedCategories.AddUnique(CategoryName);
}
CategoriesFromProperties.Add(CategoryName);
}
}
}
void FCategoryPropertyNode::InitChildNodes()
{
bool bMetaDataAllowVisible = true;
if (!bShowHiddenProperties)
{
static const FName Name_bShowOnlyWhenTrue("bShowOnlyWhenTrue");
const FString& MetaDataVisibilityCheckString = It->GetMetaData(Name_bShowOnlyWhenTrue);
if (MetaDataVisibilityCheckString.Len())
{
//ensure that the metadata visibility string is actually set to true in order to show this property
// @todo Remove this
GConfig->GetBool(TEXT("UnrealEd.PropertyFilters"), *MetaDataVisibilityCheckString, bMetaDataAllowVisible, GEditorPerProjectIni);
}
}
}
```