450 lines
14 KiB
C++
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 |