Goran Lazarevski 669cf5383b Lucky World source code
2025-03-18 19:25:25 +01:00

450 lines
14 KiB
C++

#include "MujocoComponentDetails.h"
#include "Components/MujocoBodyComponent.h"
#include "DetailLayoutBuilder.h"
#include "DetailCategoryBuilder.h"
#include "DetailWidgetRow.h"
#include "Widgets/Input/SSlider.h"
#include "PropertyHandle.h"
#include "IDetailChildrenBuilder.h"
#include "IPropertyTypeCustomization.h"
#include "Structs/MujocoActuator.h"
#include "Widgets/Input/SComboBox.h"
#include "Widgets/Text/STextBlock.h"
#include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h"
#include "Components/MujocoEqualityComponent.h"
#include "Components/MujocoActuatorComponent.h"
#include "Components/MujocoSiteComponent.h"
#include "Components/MujocoJointComponent.h"
#include "Components/MujocoTendonComponent.h"
#include "Components/MujocoGeomComponent.h"
#define LOCTEXT_NAMESPACE "MujocoComponentDetails"
TSharedRef<SWidget> FMujocoPropertyCustomization::MakeNameComboBox(const TSharedPtr<IPropertyHandle>& PropertyHandle, TArray<TSharedPtr<FName>>& Options)
{
// clang-format off
return SNew(SComboBox<TSharedPtr<FName>>)
.OptionsSource(&Options)
.OnGenerateWidget_Lambda([](TSharedPtr<FName> Option) -> TSharedRef<SWidget> { return SNew(STextBlock).Text(FText::FromName(*Option)); })
.OnSelectionChanged_Lambda([PropertyHandle](TSharedPtr<FName> NewSelection, ESelectInfo::Type) {
if (PropertyHandle->IsValidHandle() && NewSelection.IsValid())
{
PropertyHandle->SetValue(NewSelection->IsNone() ? NAME_None : *NewSelection, EPropertyValueSetFlags::InteractiveChange);
}
else
{
PropertyHandle->NotifyPostChange(EPropertyValueSetFlags::InteractiveChange);
}
})
.Content()
[
SNew(STextBlock).Text_Lambda([PropertyHandle]() -> FText {
FString Selected;
return (!PropertyHandle->IsValidHandle() || !PropertyHandle->GetValueAsDisplayString(Selected)) ? FText::FromName(NAME_None) : FText::FromString(Selected);
})
];
// clang-format on
}
TSharedRef<IPropertyTypeCustomization> FMujocoPropertyCustomization::MakeInstance()
{
return MakeShareable(new FMujocoPropertyCustomization());
}
void FMujocoPropertyCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils)
{
TSharedPtr<IPropertyHandle> JointHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, Joint));
TSharedPtr<IPropertyHandle> ETypeHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMujocoEquality, Type));
if (JointHandle && JointHandle->IsValidHandle())
{
FString JointStr;
FString TypeStr;
TSharedPtr<IPropertyHandle> TypeHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, Type));
if (!JointHandle->GetValueAsDisplayString(JointStr))
{
JointStr = "None";
}
if (TypeHandle && TypeHandle->IsValidHandle())
{
if (!TypeHandle->GetValueAsDisplayString(TypeStr))
{
TypeStr = "None";
}
}
// clang-format off
HeaderRow.NameContent()
[
PropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
SNew(STextBlock).Text(FText::FromString(FString::Printf(TEXT("%s (%s)"), *JointStr, *TypeStr)))
];
// clang-format on
return;
}
else if (ETypeHandle && ETypeHandle->IsValidHandle())
{
FString Joint1Str;
FString Joint2Str;
TSharedPtr<IPropertyHandle> Joint1Handle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMujocoEquality, Joint1));
TSharedPtr<IPropertyHandle> Joint2Handle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMujocoEquality, Joint2));
if (Joint1Handle && Joint1Handle->IsValidHandle() && Joint1Handle->GetValueAsDisplayString(Joint1Str))
{
if (Joint2Handle && Joint2Handle->IsValidHandle() && Joint2Handle->GetValueAsDisplayString(Joint2Str))
{
// clang-format off
HeaderRow.NameContent()
[
PropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
SNew(STextBlock).Text(FText::FromString(FString::Printf(TEXT("%s -> %s"), *Joint1Str, *Joint2Str)))
];
// clang-format on
return;
}
}
}
HeaderRow.NameContent()[PropertyHandle->CreatePropertyNameWidget()];
}
void FMujocoPropertyCustomization::CustomizeChildren(TSharedRef<IPropertyHandle> StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
JointOptions.Reset();
BodyOptions.Reset();
SiteOptions.Reset();
TendonOptions.Reset();
FlexOptions.Reset();
GeomOptions.Reset();
JointOptions.Add(MakeShareable(new FName("None")));
BodyOptions.Add(MakeShareable(new FName("None")));
SiteOptions.Add(MakeShareable(new FName("None")));
TendonOptions.Add(MakeShareable(new FName("None")));
FlexOptions.Add(MakeShareable(new FName("None")));
GeomOptions.Add(MakeShareable(new FName("None")));
TArray<UObject*> OuterObjects;
StructPropertyHandle->GetOuterObjects(OuterObjects);
for (UObject* Outer : OuterObjects)
{
if (UActorComponent* ModelComponent = Cast<UActorComponent>(Outer))
{
auto ModelOuter = ModelComponent->GetOuter();
if (UBlueprintGeneratedClass* BpGenerated = Cast<UBlueprintGeneratedClass>(ModelOuter))
{
if (BpGenerated->SimpleConstructionScript)
{
for (USCS_Node* Node : BpGenerated->SimpleConstructionScript->GetAllNodes())
{
if (UMujocoBodyComponent* BodyComponent = Cast<UMujocoBodyComponent>(Node->ComponentTemplate))
{
BodyOptions.Add(MakeShareable(new FName(Node->GetVariableName())));
}
else if (UMujocoSiteComponent* SiteComponent = Cast<UMujocoSiteComponent>(Node->ComponentTemplate))
{
SiteOptions.Add(MakeShareable(new FName(Node->GetVariableName())));
}
else if (UMujocoJointComponent* JointComponent = Cast<UMujocoJointComponent>(Node->ComponentTemplate))
{
JointOptions.Add(MakeShareable(new FName(Node->GetVariableName())));
}
else if (UMujocoTendonComponent* TendonComponent = Cast<UMujocoTendonComponent>(Node->ComponentTemplate))
{
TendonOptions.Add(MakeShareable(new FName(Node->GetVariableName())));
}
else if (UMujocoGeomComponent* GeomComponent = Cast<UMujocoGeomComponent>(Node->ComponentTemplate))
{
GeomOptions.Add(MakeShareable(new FName(Node->GetVariableName())));
}
}
}
}
}
}
uint32 NumChildren = 0;
StructPropertyHandle->GetNumChildren(NumChildren);
for (uint32 i = 0; i < NumChildren; ++i)
{
TSharedPtr<IPropertyHandle> ChildHandle = StructPropertyHandle->GetChildHandle(i);
if (ChildHandle.IsValid())
{
if (ChildHandle->HasMetaData("EditConditionHides") && !ChildHandle->IsEditable())
{
continue;
}
if (!ChildHandle->IsEditable())
{
StructBuilder.AddProperty(ChildHandle.ToSharedRef());
continue;
}
FName PropertyName = ChildHandle->GetProperty()->GetFName();
if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, Joint) || PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, JointInParent))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("JointName", "Joint Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, JointOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, Site) || PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, RefSite) || PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, CrankSite) || PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, SliderSite))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("SiteName", "Site Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, SiteOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, Body))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("BodyName", "Body Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, BodyOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, Tendon))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("TendonName", "Tendon Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, TendonOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoActuatorV2, Type))
{
ChildHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateLambda([this, ChildHandle]() { ChildHandle->GetParentHandle()->RequestRebuildChildren(); }));
StructBuilder.AddProperty(ChildHandle.ToSharedRef());
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Joint1))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("Joint1Name", "Joint 1 Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, JointOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Joint2))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("Joint2Name", "Joint 2 Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, JointOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Body1))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("Body1Name", "Body 1 Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, BodyOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Body2))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("Body2Name", "Body 2 Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, BodyOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Site1))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("Site1Name", "Site 1 Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, SiteOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Site2))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("Site2Name", "Site 2 Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, SiteOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Tendon1))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("Tendon1Name", "Tendon 1 Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, TendonOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Tendon2))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("Tendon2Name", "Tendon 2 Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, TendonOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Flex))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("FlexName", "Flex Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, FlexOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoTendonSpatialSite, Site))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("SiteName", "Site Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, SiteOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoTendonSpatialGeom, Geom))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("GeomName", "Geom Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, GeomOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoTendonSpatialGeom, SideSite))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("SideSiteName", "Side Site Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, SiteOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoTendonFixedJoint, Joint))
{
// clang-format off
StructBuilder.AddCustomRow(LOCTEXT("JointName", "Joint Name"))
.NameContent()
[
ChildHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
MakeNameComboBox(ChildHandle, JointOptions)
];
// clang-format on
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FMujocoEquality, Type))
{
ChildHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateLambda([this, ChildHandle]() { ChildHandle->GetParentHandle()->RequestRebuildChildren(); }));
StructBuilder.AddProperty(ChildHandle.ToSharedRef());
}
else
{
StructBuilder.AddProperty(ChildHandle.ToSharedRef());
}
}
}
}
#undef LOCTEXT_NAMESPACE