UPROPERTY EditCondition and CanEditChange

Sometimes you want to make some properties only available for editing if the object is a certain type.

Imagine we have a farming game, and we let game designers create plant definitions. We add a property FlowerColor, but we want to make it clear that this is only used if the plant has flowers.

We can use the meta flag meta=(EditCondition="bHasFlowers") to make this property only editable if the bHasFlowers value is true.

Similarly, we can make properties that are only available if a variable is false with the exclamation-mark prefix, e.g. meta=(EditCondition="!bHasFlowers").

PlantDefinition.h (basic)

UCLASS()
class UPlantDefinition : public UDataObject
{

	UPROPERTY(EditDefaultsOnly)
	bool bHasFlowers = false;

	// Can only edit this property if "Has Flowers" is true
	UPROPERTY(EditDefaultsOnly, meta = (EditCondition = "bHasFlowers"))
	FLinearColor FlowerColor = FLinearColor::White;

};

Advanced Example using CanEditChange

In the example above we saw a way of making a property read-only with a boolean variable. But what can we do for more advanced conditions?

We can do this with the CanEditChange function, which allows us to write any kind of conditions we want in C++.

PlantDefinition.h (advanced)

UENUM()
enum class EPlantType
{
	Flower,
	Food,
	Poison
};

UCLASS()
class UPlantDefinition : public UDataObject
{
	// What type of plant is this?
	UPROPERTY(EditDefaultsOnly)
	EPlantType PlantType = EPlantType::Flower;

	UPROPERTY(EditDefaultsOnly, Category="Flower")
	FLinearColor FlowerColor = FLinearColor::White;

	UPROPERTY(EditDefaultsOnly, Category="Food")
	int32 FoodAmount = 1;

	UPROPERTY(EditDefaultsOnly, Category="Poison")
	float PoisonDamagePerSecond = 0.25f;

// Note CanEditChange is only available when compiling with the editor. You must add this or your builds might not work!
#if WITH_EDITOR
	virtual bool CanEditChange(const UProperty* InProperty) const override;
#endif

};

PlantDefinition.cpp

#if WITH_EDITOR
bool UPlantDefinition::CanEditChange(const UProperty* InProperty) const
{
	const bool ParentVal = Super::CanEditChange(InProperty);

	// Can we edit flower color?
	if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPlantDefinition, FlowerColor))
	{
		return PlantType == EPlantType::Flower;
	}

	// Can we edit food amount?
	if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPlantDefinition, FoodAmount))
	{
		return PlantType == EPlantType::Food;
	}

	// Can we edit poison amount?
	if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPlantDefinition, PoisonDamageperSecond))
	{
		return PlantType == EPlantType::Poison;
	}

	return ParentVal;
}
#endif

As a small aside, using a single definition like this for 3 different purposes might be better achieved with subclasses, rather than a multi-purpose single definition.

This is just a mock example to give you an idea of how ot use CanEditChange.