Files
UnrealEngine/Engine/Source/Editor/UnrealEd/Private/Elements/SMInstance/SMInstanceElementDetailsProxyObject.cpp
2025-05-18 13:04:45 +08:00

154 lines
5.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Elements/SMInstance/SMInstanceElementDetailsProxyObject.h"
#include "Components/InstancedStaticMeshComponent.h"
#include "Elements/SMInstance/SMInstanceElementData.h"
#include "UnrealEdGlobals.h"
#include "Editor/UnrealEdEngine.h"
#include "Engine/StaticMesh.h"
#define LOCTEXT_NAMESPACE "SMInstanceElementDetails"
void USMInstanceElementDetailsProxyObject::Initialize(const FSMInstanceElementId& InSMInstanceElementId)
{
ISMComponent = InSMInstanceElementId.ISMComponent;
ISMInstanceId = InSMInstanceElementId.InstanceId;
TickHandle = FTSTicker::GetCoreTicker().AddTicker(TEXT("USMInstanceElementDetailsProxyObject"), 0.1f, [this](float)
{
const bool bDidSyncInstance = SyncProxyStateFromInstance();
if (!bDidSyncInstance)
{
// The referenced instance is invalid, so mark this proxy as garbage so that the details panel stops using it
MarkAsGarbage();
}
return bDidSyncInstance;
});
SyncProxyStateFromInstance();
}
void USMInstanceElementDetailsProxyObject::Shutdown()
{
if (TickHandle.IsValid())
{
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
TickHandle.Reset();
}
ISMComponent.Reset();
ISMInstanceId = 0;
Transform = FTransform::Identity;
}
void USMInstanceElementDetailsProxyObject::BeginDestroy()
{
Super::BeginDestroy();
Shutdown();
}
void USMInstanceElementDetailsProxyObject::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
{
if (PropertyChangedEvent.Property)
{
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(USMInstanceElementDetailsProxyObject, Transform))
{
if (FSMInstanceManager SMInstance = GetSMInstance())
{
if (PropertyChangedEvent.ChangeType == EPropertyChangeType::Interactive)
{
if (!bIsWithinInteractiveTransformEdit)
{
SMInstance.NotifySMInstanceMovementStarted();
}
bIsWithinInteractiveTransformEdit = true;
}
// TODO: Need flag for local/world space, like FComponentTransformDetails
SMInstance.SetSMInstanceTransform(Transform, /*bWorldSpace*/false, /*bMarkRenderStateDirty*/true);
if (PropertyChangedEvent.ChangeType == EPropertyChangeType::Interactive)
{
check(bIsWithinInteractiveTransformEdit);
SMInstance.NotifySMInstanceMovementOngoing();
}
else
{
if (bIsWithinInteractiveTransformEdit)
{
SMInstance.NotifySMInstanceMovementEnded();
}
bIsWithinInteractiveTransformEdit = false;
}
GUnrealEd->UpdatePivotLocationForSelection();
GUnrealEd->RedrawLevelEditingViewports();
}
}
}
Super::PostEditChangeChainProperty(PropertyChangedEvent);
}
bool USMInstanceElementDetailsProxyObject::SyncProxyStateFromInstance()
{
if (FSMInstanceManager SMInstance = GetSMInstance())
{
// TODO: Need flag for local/world space, like FComponentTransformDetails
SMInstance.GetSMInstanceTransform(Transform, /*bWorldSpace*/false);
return true;
}
Transform = FTransform::Identity;
return false;
}
FSMInstanceManager USMInstanceElementDetailsProxyObject::GetSMInstance() const
{
const FSMInstanceId SMInstanceId = FSMInstanceElementIdMap::Get().GetSMInstanceIdFromSMInstanceElementId(FSMInstanceElementId{ ISMComponent.Get(), ISMInstanceId });
return FSMInstanceManager(SMInstanceId, SMInstanceElementDataUtil::GetSMInstanceManager(SMInstanceId));
}
UClass* FSMInstanceElementDetailsProxyObjectNameEditSink::GetSupportedClass() const
{
return USMInstanceElementDetailsProxyObject::StaticClass();
}
FText FSMInstanceElementDetailsProxyObjectNameEditSink::GetObjectDisplayName(UObject* Object) const
{
USMInstanceElementDetailsProxyObject* ProxyObject = CastChecked<USMInstanceElementDetailsProxyObject>(Object);
if (FSMInstanceManager SMInstance = ProxyObject->GetSMInstance())
{
FText DisplayName = SMInstance.GetSMInstanceDisplayName();
if (DisplayName.IsEmpty())
{
const UStaticMesh* StaticMesh = SMInstance.GetISMComponent()->GetStaticMesh();
const FText OwnerDisplayName = FText::FromString(StaticMesh ? StaticMesh->GetName() : SMInstance.GetISMComponent()->GetName());
DisplayName = FText::Format(LOCTEXT("ProxyObjectDisplayNameFmt", "{0} - Instance {1}"), OwnerDisplayName, SMInstance.GetInstanceId().InstanceIndex);
}
return DisplayName;
}
return FText();
}
FText FSMInstanceElementDetailsProxyObjectNameEditSink::GetObjectNameTooltip(UObject* Object) const
{
USMInstanceElementDetailsProxyObject* ProxyObject = CastChecked<USMInstanceElementDetailsProxyObject>(Object);
if (FSMInstanceManager SMInstance = ProxyObject->GetSMInstance())
{
FText Tooltip = SMInstance.GetSMInstanceTooltip();
if (Tooltip.IsEmpty())
{
const FText OwnerDisplayPath = FText::FromString(SMInstance.GetISMComponent()->GetPathName(SMInstance.GetISMComponent()->GetWorld())); // stops the path at the level of the world the object is in
Tooltip = FText::Format(LOCTEXT("ProxyObjectTooltipFmt", "Instance {0} on {1}"), SMInstance.GetInstanceId().InstanceIndex, OwnerDisplayPath);
}
return Tooltip;
}
return FText();
}
#undef LOCTEXT_NAMESPACE