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.
Basic Example
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)
A simple way of making a property read-only unless a boolean is true
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 the CanEditChange() function is only available when compiling with the editor.
// Make sure to wrap it with the WITH_EDITOR define or your builds fail!
#if WITH_EDITOR
virtual bool CanEditChange(const FProperty* InProperty) const override;
#endif
};
PlantDefinition.cpp
#if WITH_EDITOR
bool UPlantDefinition::CanEditChange(const FProperty* InProperty) const
{
// If other logic prevents editing, we want to respect that
const bool ParentVal = Super::CanEditChange(InProperty);
// Can we edit flower color?
if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPlantDefinition, FlowerColor))
{
return ParentVal && PlantType == EPlantType::Flower;
}
// Can we edit food amount?
if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPlantDefinition, FoodAmount))
{
return ParentVal && PlantType == EPlantType::Food;
}
// Can we edit poison amount?
if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPlantDefinition, PoisonDamageperSecond))
{
return ParentVal && PlantType == EPlantType::Poison;
}
return ParentVal;
}
#endif