Download

Unreal Engine Property Edit Conditions

Nov 4, 2020.Knowledge

Edit Conditions Before 4.23

Each UPROPERTY declaration may have an EditCondition defined in its metadata. This edit condition controlled whether or not the property it was attached to was editable in the details view. This edit condition was a single boolean value, eg:

meta=( EditCondition=“bAllowOverride” )

When bAllowOverride was true, the property would be editable:
image

This condition could also be negated (!bAllowOverride), in which case the property would not be editable when the condition was true:

image

Since each edit condition was a single boolean, it was also simple to inline the property by adding it to the edit condition property’s meta, eg.

UPROPERTY(…, meta =(InlineEditConditionToggle)) bool bLoopPositionOverride;

Which looked like this:

image

However, this meant that every property that used that edit condition would duplicate that property:

image

This could be confusing, so it was possible to hide the inline checkbox on certain properties using the metadata tag HideEditConditionToggle on a property, eg:

image

This allowed for a decent amount of customization of the details view without writing a full-blown IDetailCustomization. However, a single boolean is still extremely limiting, and there are many simple things which require more expressiveness. Enter 4.23…

EditConditions After 4.23

First, all of the above still applies after 4.23!

However, the edit condition is now evaluated using a full-fledged expression parser. This allows for much more complicated expressions to be evaluated, such as:

UPROPERTY(…, meta=(EditCondition="!bEnabled || Mode != EMode::MyMode && Duration > 10"))

For more examples of valid expressions, you can peruse EditConditionParserTests.cpp. You can also play around with some examples I’ve set up by opening the console in the editor and entering the command testprops and scrolling to the Edit Conditions category. This uses PropertyEditorTestObject.h for its data if you want to inspect it.

The expression parser uses standard C++ syntax, and the full set of operators that are supported are:

==, !=, >, >=, <, <=, ||, &&, !, +, -, *, /

Note that this does not include parentheses for sub-expressions, so operator precedence matters (and is the same as in C++).

Supported types are all numeric types (both property and literals), booleans, and enums (must be defined as UENUM), ie:

uint8, …, uint64, int8, …, int64, float, double, bool, UENUM()

Numeric types are all converted to doubles for comparisons, so these expressions are valid:

MyFloat > MyInteger MyInteger <= 5.5

You may have noticed those arithmetic operators at the end of the operator list. That means that you can do some basic arithmetic in expressions, eg.:

MyInteger < MyFloat - 5

However, do note that these are all evaluated as doubles, so you cannot rely on integer division semantics. Eg. this will evaluate to true when MyInteger is 5:

MyInteger / 2 == 2.5

Simple boolean expressions are still compatible with inline edit condition toggles, with some additional syntaxes enabled, since these are equivalent to the previous version when evaluated, eg.:

bAllowOverride == true or false == bAllowOverride

Enum comparisons supported are equality and inequality:

MyEnum == EMode::A or MyEnum != EMode::A

For enums that are marked with the Bitflags metadata, it is also possible to use the bitwise and operator (&) to test for certain flags:

UENUM(meta=(Bitflags)) enum EBitflags { Zero = 0, One = 1 } MyEnum & EBitflags::One

Restrictions

Only fields of the owning class are supported. No methods or functions!

Edit conditions are evaluated every tick when the property is visible. There is no optimizer, so even constant expressions can end up being expensive, eg.

5 * 2 / 10 - 1 == 0

Enums must be namespaced, even for old-style enums, eg:

enum MyEnum { A }; TEnumAsByte EnumValue; UPROPERTY(…, EditCondition=“EnumValue == MyEnum::A”)

Enums do not implement any comparisons other than equals and not-equals, and bitwise and for flags.

Properties inside structs are not supported, even built-in structs, so this will not parse:

MyColor.R == 0

No parentheses, so this will not parse:

(A || B) && (C || D)

No bitwise operators or bitshifts for integers.

Related Metadata

There are other metadata properties, related to edit conditions, which can help you set up the Details views that you want without extensive customization. Here are a few that might help you.

EditConditionHides

As the name implies, EditConditionHides says that the property’s EditCondition expression should also be used to calculate its visibility. For example:

meta=(EditCondition=”bEnabled”, EditConditionHides)

image

image

This also applies to more complex edit conditions, eg.:

meta=(EditCondition=”MyEnum == EMode::Mode2D || bEnabled”, EditConditionHides)

image

image

image

This can be useful for having a single checkbox to enable and display multiple properties, or have different modes with different controls, for example:

image

image

This property can also be applied in conjunction with our following metadata property to create even more customized UIs.

InlineCategoryProperty

The InlineCategoryProperty metadata tells the Details view to hide a boolean or enum property from the default details view position it would usually be in, and instead display it in-line with the category, eg.:

UPROPERTY(EditAnywhere, Category=”My Category”, meta=(InlineCategoryProperty))

image

image

However, sometimes we want to explicitly create a UI that has different modes that are exclusively enabled. Adding the InlineCategoryProperty metadata, and EditConditionHides to our child properties:

UPROPERTY(EditAnywhere, Category=”My Category”, meta=(InlineCategoryProperty)) EMode MyMode; UPROPERTY(EditAnywhere, Category = MyCategory, meta = (EditCondition=“MyMode == EMode::Mode2D”, EditConditionHides)) FVector2D MyVector2; UPROPERTY(EditAnywhere, Category = MyCategory, meta = (EditCondition=“MyMode == EMode::Mode3D”, EditConditionHides)) FVector MyVector3;

image

image

While only boolean or enum properties are currently supported, this should still give you an idea of how this feature can be used to create UIs that are dynamic and feel handcrafted, but without much effort.