Added SteveFixedDataTableRowHandle

This commit is contained in:
Steve Streeting 2023-10-06 16:15:32 +01:00
parent 91e428a7d6
commit 19363c00f7
7 changed files with 332 additions and 23 deletions

View File

@ -0,0 +1,12 @@
#pragma once
#include "Engine/DataTable.h"
#include "StevesFixedDataTableRowHandle.generated.h"
/// Just a type to denote that this table row handle should be edited differently
USTRUCT(BlueprintType)
struct STEVESUEHELPERS_API FStevesFixedDataTableRowHandle : public FDataTableRowHandle
{
GENERATED_USTRUCT_BODY()
};

View File

@ -0,0 +1,194 @@
#include "StevesFixedDataTableCustomisationLayout.h"
#include "AssetRegistry/AssetData.h"
#include "Containers/Map.h"
#include "DataTableEditorUtils.h"
#include "Delegates/Delegate.h"
#include "DetailWidgetRow.h"
#include "Editor.h"
#include "Engine/DataTable.h"
#include "Fonts/SlateFontInfo.h"
#include "Framework/Commands/UIAction.h"
#include "HAL/Platform.h"
#include "HAL/PlatformCrt.h"
#include "Internationalization/Internationalization.h"
#include "Internationalization/Text.h"
#include "Misc/Attribute.h"
#include "PropertyCustomizationHelpers.h"
#include "PropertyEditorModule.h"
#include "PropertyHandle.h"
#include "Templates/Casts.h"
#include "UObject/Class.h"
#include "UObject/Object.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Text/STextBlock.h"
class SToolTip;
#define LOCTEXT_NAMESPACE "FSsFixedDataTableCustomisationLayout"
void FStevesFixedDataTableCustomisationLayout::CustomizeHeader(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
DataTablePropertyHandle = InStructPropertyHandle->GetChildHandle("DataTable");
RowNamePropertyHandle = InStructPropertyHandle->GetChildHandle("RowName");
if (InStructPropertyHandle->HasMetaData(TEXT("DataTable")))
{
// Find data table from asset ref
const FString& DataTablePath = InStructPropertyHandle->GetMetaData(TEXT("DataTable"));
if (UDataTable* DataTable = LoadObject<UDataTable>(nullptr, *DataTablePath, nullptr))
{
DataTablePropertyHandle->SetValue(DataTable);
}
else
{
UE_LOG(LogDataTable, Warning, TEXT("No Datatable found at %s"), *DataTablePath);
}
}
else
{
UE_LOG(LogDataTable, Warning, TEXT("No Datatable meta tag present on property %s"), *InStructPropertyHandle->GetPropertyDisplayName().ToString());
}
FPropertyComboBoxArgs ComboArgs(RowNamePropertyHandle,
FOnGetPropertyComboBoxStrings::CreateSP(this, &FStevesFixedDataTableCustomisationLayout::OnGetRowStrings),
FOnGetPropertyComboBoxValue::CreateSP(this, &FStevesFixedDataTableCustomisationLayout::OnGetRowValueString));
ComboArgs.ShowSearchForItemCount = 1;
TSharedRef<SWidget> BrowseTableButton = PropertyCustomizationHelpers::MakeBrowseButton(
FSimpleDelegate::CreateSP(this, &FStevesFixedDataTableCustomisationLayout::BrowseTableButtonClicked),
LOCTEXT("SsBrowseToDatatable", "Browse to DataTable in Content Browser"));
HeaderRow
.NameContent()
[
InStructPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
.MaxDesiredWidth(0.0f) // don't constrain the combo button width
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.FillWidth(1.0f)
[
PropertyCustomizationHelpers::MakePropertyComboBox(ComboArgs)
]
+SHorizontalBox::Slot()
.Padding(2.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.AutoWidth()
[
BrowseTableButton
]
]; ;
FDataTableEditorUtils::AddSearchForReferencesContextMenu(HeaderRow, FExecuteAction::CreateSP(this, &FStevesFixedDataTableCustomisationLayout::OnSearchForReferences));
}
void FStevesFixedDataTableCustomisationLayout::BrowseTableButtonClicked()
{
if (DataTablePropertyHandle.IsValid())
{
UObject* SourceDataTable = nullptr;
if (DataTablePropertyHandle->GetValue(SourceDataTable) == FPropertyAccess::Success)
{
TArray<FAssetData> Assets;
Assets.Add(SourceDataTable);
GEditor->SyncBrowserToObjects(Assets);
}
}
}
bool FStevesFixedDataTableCustomisationLayout::GetCurrentValue(UDataTable*& OutDataTable, FName& OutName) const
{
if (RowNamePropertyHandle.IsValid() && RowNamePropertyHandle->IsValidHandle() && DataTablePropertyHandle.IsValid() && DataTablePropertyHandle->IsValidHandle())
{
// If either handle is multiple value or failure, fail
UObject* SourceDataTable = nullptr;
if (DataTablePropertyHandle->GetValue(SourceDataTable) == FPropertyAccess::Success)
{
OutDataTable = Cast<UDataTable>(SourceDataTable);
if (RowNamePropertyHandle->GetValue(OutName) == FPropertyAccess::Success)
{
return true;
}
}
}
return false;
}
void FStevesFixedDataTableCustomisationLayout::OnSearchForReferences()
{
UDataTable* DataTable;
FName RowName;
if (GetCurrentValue(DataTable, RowName) && DataTable)
{
TArray<FAssetIdentifier> AssetIdentifiers;
AssetIdentifiers.Add(FAssetIdentifier(DataTable, RowName));
FEditorDelegates::OnOpenReferenceViewer.Broadcast(AssetIdentifiers, FReferenceViewerParams());
}
}
FString FStevesFixedDataTableCustomisationLayout::OnGetRowValueString() const
{
if (!RowNamePropertyHandle.IsValid() || !RowNamePropertyHandle->IsValidHandle())
{
return FString();
}
FName RowNameValue;
const FPropertyAccess::Result RowResult = RowNamePropertyHandle->GetValue(RowNameValue);
if (RowResult == FPropertyAccess::Success)
{
if (RowNameValue.IsNone())
{
return LOCTEXT("DataTable_None", "None").ToString();
}
return RowNameValue.ToString();
}
else if (RowResult == FPropertyAccess::Fail)
{
return LOCTEXT("DataTable_None", "None").ToString();
}
else
{
return LOCTEXT("MultipleValues", "Multiple Values").ToString();
}
}
void FStevesFixedDataTableCustomisationLayout::OnGetRowStrings(TArray< TSharedPtr<FString> >& OutStrings, TArray<TSharedPtr<SToolTip>>& OutToolTips, TArray<bool>& OutRestrictedItems) const
{
UDataTable* DataTable = nullptr;
FName IgnoredRowName;
// Ignore return value as we will show rows if table is the same but row names are multiple values
GetCurrentValue(DataTable, IgnoredRowName);
TArray<FName> AllRowNames;
if (DataTable != nullptr)
{
for (TMap<FName, uint8*>::TConstIterator Iterator(DataTable->GetRowMap()); Iterator; ++Iterator)
{
AllRowNames.Add(Iterator.Key());
}
// Sort the names alphabetically.
AllRowNames.Sort(FNameLexicalLess());
}
for (const FName& RowName : AllRowNames)
{
OutStrings.Add(MakeShared<FString>(RowName.ToString()));
OutRestrictedItems.Add(false);
}
}
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,38 @@
#pragma once
#include "Containers/Array.h"
#include "Containers/UnrealString.h"
#include "IPropertyTypeCustomization.h"
#include "Templates/SharedPointer.h"
#include "UObject/NameTypes.h"
class IPropertyHandle;
class SToolTip;
class UDataTable;
class UScriptStruct;
struct FAssetData;
/// Drop-down for data table row name when the table itself is fixed in meta tags
class FStevesFixedDataTableCustomisationLayout : public IPropertyTypeCustomization
{
public:
static TSharedRef<IPropertyTypeCustomization> MakeInstance()
{
return MakeShareable( new FStevesFixedDataTableCustomisationLayout );
}
virtual void CustomizeHeader(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override;
// Not needed, but must be implemented
virtual void CustomizeChildren(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override {}
protected:
bool GetCurrentValue(UDataTable*& OutDataTable, FName& OutName) const;
void OnSearchForReferences();
void OnGetRowStrings(TArray< TSharedPtr<FString> >& OutStrings, TArray<TSharedPtr<SToolTip>>& OutToolTips, TArray<bool>& OutRestrictedItems) const;
FString OnGetRowValueString() const;
void BrowseTableButtonClicked();
TSharedPtr<IPropertyHandle> DataTablePropertyHandle;
TSharedPtr<IPropertyHandle> RowNamePropertyHandle;
};

View File

@ -0,0 +1,20 @@
#include "StevesUEHelpersEd.h"
#include "StevesFixedDataTableCustomisationLayout.h"
#define LOCTEXT_NAMESPACE "FStevesUEHelpersEdModule"
void FStevesUEHelpersEdModule::StartupModule()
{
FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropertyModule.RegisterCustomPropertyTypeLayout("StevesFixedDataTableRowHandle", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FStevesFixedDataTableCustomisationLayout::MakeInstance));
}
void FStevesUEHelpersEdModule::ShutdownModule()
{
FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropertyModule.UnregisterCustomPropertyTypeLayout("StevesFixedDataTableRowHandle");
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FStevesUEHelpersEdModule, StevesUEHelpersEd)

View File

@ -0,0 +1,11 @@
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FStevesUEHelpersEdModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};

View File

@ -0,0 +1,30 @@
using UnrealBuildTool;
public class StevesUEHelpersEd : ModuleRules
{
public StevesUEHelpersEd(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"UnrealEd",
"PropertyEditor",
"DataTableEditor"
}
);
}
}

View File

@ -1,25 +1,29 @@
{
"FileVersion" : 3,
"Version" : 1,
"VersionName" : "1.0",
"FriendlyName" : "Steve's UE4 Helpers",
"Description" : "A set of common helper classes for UE4 projects by Steve Streeing",
"Category" : "Code Utilities",
"CreatedBy" : "Steve Streeting",
"CreatedByURL" : "https://www.stevestreeting.com",
"DocsURL" : "",
"MarketplaceURL" : "",
"SupportURL" : "https://github.com/sinbad/StevesUEHelpers",
"EnabledByDefault" : true,
"CanContainContent" : false,
"IsBetaVersion" : true,
"Installed" : false,
"Modules" :
[
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "Steve's UE4 Helpers",
"Description": "A set of common helper classes for UE4 projects by Steve Streeing",
"Category": "Code Utilities",
"CreatedBy": "Steve Streeting",
"CreatedByURL": "https://www.stevestreeting.com",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "https://github.com/sinbad/StevesUEHelpers",
"EnabledByDefault": true,
"CanContainContent": false,
"IsBetaVersion": true,
"Installed": false,
"Modules": [
{
"Name" : "StevesUEHelpers",
"Type" : "Runtime",
"LoadingPhase" : "PreDefault"
"Name": "StevesUEHelpers",
"Type": "Runtime",
"LoadingPhase": "PreDefault"
},
{
"Name": "StevesUEHelpersEd",
"Type": "Editor",
"LoadingPhase": "PostDefault"
}
],
"Plugins": [