Files
UnrealEngine/Engine/Source/Editor/DetailCustomizations/Private/OverrideResetToDefault.h
2025-05-18 13:04:45 +08:00

89 lines
3.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "IDetailPropertyRow.h"
#include "Layout/Visibility.h"
#include "IPropertyTypeCustomization.h"
#include "PropertyHandle.h"
#include "UObject/PropertyAccessUtil.h"
/**
* Class template aiming to override ResetToDefault methods by comparing properties with an internal static DefaultObject.
*
* This behavior was originally written for settings UI and does not properly support inheritance (resetting a parent class's
* struct member to default and have it propagate to loaded children). If a struct wants to override ResetToDefault behavior
* using this class and must support the outer-object being a parent class, OnResetToDefault should be revisited to properly
* reset archetype instances as well.
*/
template<typename UStructType>
class TOverrideResetToDefaultWithStaticUStruct
{
public:
/** Called by the UI to show/hide the reset widgets */
static bool IsResetToDefaultVisible(TSharedPtr<IPropertyHandle> InPropertyHandle);
/** Reset to default triggered in UI */
static void OnResetToDefault(TSharedPtr<IPropertyHandle> InPropertyHandle);
protected:
/** Adds callbacks used by the UI to determine if a property can be reset and reset it. */
static void AddResetToDefaultOverrides(IDetailPropertyRow& InDetailPropertyRow);
static const UStructType DefaultObject;
};
template<typename UStructType>
const UStructType TOverrideResetToDefaultWithStaticUStruct<UStructType>::DefaultObject;
template<typename UStructType>
bool TOverrideResetToDefaultWithStaticUStruct<UStructType>::IsResetToDefaultVisible(TSharedPtr<IPropertyHandle> InPropertyHandle)
{
FProperty* Property = InPropertyHandle->GetProperty();
const void* DefaultValuePtr = nullptr;
void* ValuePtr = nullptr;
check(Property != nullptr);
DefaultValuePtr = Property->ContainerPtrToValuePtr<void>(&DefaultObject);
InPropertyHandle->GetValueData(ValuePtr);
if ((DefaultValuePtr != nullptr) && (ValuePtr != nullptr))
{
return !Property->Identical(DefaultValuePtr, ValuePtr);
}
return false;
}
template<typename UStructType>
void TOverrideResetToDefaultWithStaticUStruct<UStructType>::OnResetToDefault(TSharedPtr<IPropertyHandle> InPropertyHandle)
{
FProperty* Property = InPropertyHandle->GetProperty();
const void* DefaultValuePtr = nullptr;
void* ValuePtr = nullptr;
check(Property != nullptr);
DefaultValuePtr = Property->ContainerPtrToValuePtr<void>(&DefaultObject);
InPropertyHandle->GetValueData(ValuePtr);
if ((DefaultValuePtr != nullptr) && (ValuePtr != nullptr))
{
// SetPropertyValue_DirectSingle when called on an archetype can propagate to instances.
// See class comments: this ResetToDefault override was not written for contexts involving
// inheritance, so pass in empty archetype instances list.
TArray<void*> NoArchetypeInsts;
PropertyAccessUtil::SetPropertyValue_DirectSingle(Property, DefaultValuePtr, Property, ValuePtr, NoArchetypeInsts, 0, Property->HasAnyFlags(RF_ArchetypeObject), []() { return nullptr; });
}
}
template<typename UStructType>
void TOverrideResetToDefaultWithStaticUStruct<UStructType>::AddResetToDefaultOverrides(IDetailPropertyRow& InDetailPropertyRow)
{
InDetailPropertyRow.OverrideResetToDefault(FResetToDefaultOverride::Create(FIsResetToDefaultVisible::CreateStatic(&TOverrideResetToDefaultWithStaticUStruct<UStructType>::IsResetToDefaultVisible),
FResetToDefaultHandler::CreateStatic(&TOverrideResetToDefaultWithStaticUStruct<UStructType>::OnResetToDefault),
true));
}