// 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 class TOverrideResetToDefaultWithStaticUStruct { public: /** Called by the UI to show/hide the reset widgets */ static bool IsResetToDefaultVisible(TSharedPtr InPropertyHandle); /** Reset to default triggered in UI */ static void OnResetToDefault(TSharedPtr 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 const UStructType TOverrideResetToDefaultWithStaticUStruct::DefaultObject; template bool TOverrideResetToDefaultWithStaticUStruct::IsResetToDefaultVisible(TSharedPtr InPropertyHandle) { FProperty* Property = InPropertyHandle->GetProperty(); const void* DefaultValuePtr = nullptr; void* ValuePtr = nullptr; check(Property != nullptr); DefaultValuePtr = Property->ContainerPtrToValuePtr(&DefaultObject); InPropertyHandle->GetValueData(ValuePtr); if ((DefaultValuePtr != nullptr) && (ValuePtr != nullptr)) { return !Property->Identical(DefaultValuePtr, ValuePtr); } return false; } template void TOverrideResetToDefaultWithStaticUStruct::OnResetToDefault(TSharedPtr InPropertyHandle) { FProperty* Property = InPropertyHandle->GetProperty(); const void* DefaultValuePtr = nullptr; void* ValuePtr = nullptr; check(Property != nullptr); DefaultValuePtr = Property->ContainerPtrToValuePtr(&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 NoArchetypeInsts; PropertyAccessUtil::SetPropertyValue_DirectSingle(Property, DefaultValuePtr, Property, ValuePtr, NoArchetypeInsts, 0, Property->HasAnyFlags(RF_ArchetypeObject), []() { return nullptr; }); } } template void TOverrideResetToDefaultWithStaticUStruct::AddResetToDefaultOverrides(IDetailPropertyRow& InDetailPropertyRow) { InDetailPropertyRow.OverrideResetToDefault(FResetToDefaultOverride::Create(FIsResetToDefaultVisible::CreateStatic(&TOverrideResetToDefaultWithStaticUStruct::IsResetToDefaultVisible), FResetToDefaultHandler::CreateStatic(&TOverrideResetToDefaultWithStaticUStruct::OnResetToDefault), true)); }