Better handling of property mutability, and also, walk into structs.

This commit is contained in:
2026-04-04 23:57:59 -04:00
parent bd138e2790
commit c949a4db05
19 changed files with 172 additions and 50 deletions

View File

@@ -16,6 +16,7 @@
bool FWingProperty::SetObject(UObject *Obj, WingOut Errors) const
{
if (!CheckEditable(Errors)) return false;
FObjectPropertyBase *OProp = CastField<FObjectPropertyBase>(Prop);
if (!OProp)
{
@@ -47,6 +48,7 @@ bool FWingProperty::SetObject(UObject *Obj, WingOut Errors) const
bool FWingProperty::SetDouble(double D, WingOut Errors) const
{
if (!CheckEditable(Errors)) return false;
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
if (!NProp)
{
@@ -95,6 +97,7 @@ bool FWingProperty::SetDouble(double D, WingOut Errors) const
bool FWingProperty::SetInt64(int64 I, WingOut Errors) const
{
if (!CheckEditable(Errors)) return false;
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
if (!NProp)
{
@@ -133,6 +136,7 @@ bool FWingProperty::SetInt64(int64 I, WingOut Errors) const
bool FWingProperty::SetBool(bool B, WingOut Errors) const
{
if (!CheckEditable(Errors)) return false;
if (FBoolProperty* BoolProp = CastField<FBoolProperty>(Prop))
{
Prop->SetValue_InContainer(Container, &B);
@@ -144,6 +148,8 @@ bool FWingProperty::SetBool(bool B, WingOut Errors) const
bool FWingProperty::SetText(FString Value, WingOut Errors) const
{
if (!CheckEditable(Errors)) return false;
// Pin types get parsed by UWingTypes.
if (IsPinTypeProperty(Prop))
{
@@ -201,6 +207,8 @@ bool FWingProperty::SetText(FString Value, WingOut Errors) const
bool FWingProperty::SetJson(const FJsonValue &JsonValue, WingOut Errors) const
{
if (!CheckEditable(Errors)) return false;
if (JsonValue.Type == EJson::String)
{
return SetText(JsonValue.AsString(), Errors);
@@ -376,28 +384,35 @@ FString FWingProperty::GetCategory() const
return Result;
}
void FWingProperty::GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags, TArray<FWingProperty> &Props)
{
for (TFieldIterator<FProperty> It(Obj.UStructPtr); It; ++It)
{
if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue;
Props.Add(FWingProperty(*It, Obj.StructPtr));
}
}
TArray<FWingProperty> FWingProperty::GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags)
TArray<FWingProperty> FWingProperty::GetAll(FWingStructAndUStruct Obj)
{
TArray<FWingProperty> Result;
GetAll(Obj, Flags, Result);
for (TFieldIterator<FProperty> It(Obj.UStructPtr); It; ++It)
{
bool Editable = !It->HasAnyPropertyFlags(CPF_EditConst);
Result.Add(FWingProperty(*It, Obj.StructPtr, Editable));
}
return Result;
}
TArray<FName> FWingProperty::GetNames(UStruct *US, EPropertyFlags Flags)
TArray<FWingProperty> FWingProperty::GetVisible(FWingStructAndUStruct Obj)
{
TArray<FWingProperty> Result;
for (TFieldIterator<FProperty> It(Obj.UStructPtr); It; ++It)
{
if (!It->HasAllPropertyFlags(CPF_Edit)) continue;
bool Editable = !It->HasAnyPropertyFlags(CPF_EditConst);
Result.Add(FWingProperty(*It, Obj.StructPtr, Editable));
}
return Result;
}
TArray<FName> FWingProperty::GetVisibleNames(UStruct *US)
{
TArray<FName> Result;
for (TFieldIterator<FProperty> It(US); It; ++It)
{
if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue;
if (!It->HasAllPropertyFlags(CPF_Edit)) continue;
Result.Add(It->GetFName());
}
return Result;
@@ -419,10 +434,20 @@ void FWingProperty::Move(TArray<FWingProperty> &Out, TArray<FWingProperty> &In,
In.SetNum(Dst);
}
TArray<FWingProperty> FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Flags, bool Mutable)
TArray<FWingProperty> FWingProperty::GetDetails(UObject* Obj, bool Mutable)
{
if (!Obj) return {};
// If it's a UWingStructPointer, return the properties
// of the struct instead. Propagate editability of the host.
if (UWingStructPointer *SP = Cast<UWingStructPointer>(Obj))
{
TArray<FWingProperty> Result =
GetVisible(FWingStructAndUStruct(SP->StructBase, SP->StructType));
if (!Mutable || (!SP->Editable)) StripEditable(Result);
return Result;
}
// Blueprints don't have editable properties. So
// instead, we fetch properties from the generated CDO.
if (UBlueprint *BP = ::Cast<UBlueprint>(Obj))
@@ -446,7 +471,7 @@ TArray<FWingProperty> FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Fla
}
}
TArray<FWingProperty> Result = GetAll(Obj, Flags);
TArray<FWingProperty> Result = GetVisible(Obj);
// If it's a Material Graph node, also collect properties from
// the associated material expression.
@@ -455,7 +480,7 @@ TArray<FWingProperty> FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Fla
{
if (UMaterialExpression* Expr = MatNode->MaterialExpression)
{
GetAll(Expr, Flags, Result);
Result.Append(GetVisible(Expr));
}
}
@@ -466,10 +491,11 @@ TArray<FWingProperty> FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Fla
FWingProperty::Remove(Result, TEXT("Slot"));
if (UPanelSlot* Slot = Widget->Slot)
{
GetAll(Slot, Flags, Result);
Result.Append(GetVisible(Slot));
}
}
if (!Mutable) StripEditable(Result);
return Result;
}
@@ -555,4 +581,20 @@ bool FWingProperty::CheckImportTextResult(const FString &Value, WingOut Errors)
}
}
return true;
}
void FWingProperty::StripEditable(TArray<FWingProperty> &Props)
{
for (FWingProperty &Elt : Props) Elt.Editable = false;
}
bool FWingProperty::CheckEditable(WingOut Errors) const
{
if (!Editable)
{
Errors.Printf(TEXT("ERROR: Cannot edit property %s, not marked editable"),
*WingUtils::FormatName(Prop));
return false;
}
return true;
}