238 lines
7.5 KiB
C++
238 lines
7.5 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "DataTableCustomization.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 "IDetailChildrenBuilder.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 "FDataTableCustomizationLayout"
|
|
|
|
void FDataTableCustomizationLayout::CustomizeHeader(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
|
|
{
|
|
this->StructPropertyHandle = InStructPropertyHandle;
|
|
|
|
if (StructPropertyHandle->HasMetaData(TEXT("RowType")))
|
|
{
|
|
const FString& RowType = StructPropertyHandle->GetMetaData(TEXT("RowType"));
|
|
RowTypeFilter = FName(*RowType);
|
|
RowFilterStruct = UClass::TryFindTypeSlow<UScriptStruct>(RowType);
|
|
}
|
|
|
|
FSimpleDelegate OnDataTableChangedDelegate = FSimpleDelegate::CreateSP(this, &FDataTableCustomizationLayout::OnDataTableChanged);
|
|
StructPropertyHandle->SetOnPropertyValueChanged(OnDataTableChangedDelegate);
|
|
|
|
HeaderRow
|
|
.NameContent()
|
|
[
|
|
InStructPropertyHandle->CreatePropertyNameWidget()
|
|
];
|
|
|
|
FDataTableEditorUtils::AddSearchForReferencesContextMenu(HeaderRow, FExecuteAction::CreateSP(this, &FDataTableCustomizationLayout::OnSearchForReferences));
|
|
}
|
|
|
|
void FDataTableCustomizationLayout::CustomizeChildren(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
|
|
{
|
|
/** Get all the existing property handles */
|
|
DataTablePropertyHandle = InStructPropertyHandle->GetChildHandle("DataTable");
|
|
RowNamePropertyHandle = InStructPropertyHandle->GetChildHandle("RowName");
|
|
const FName PropertyName = InStructPropertyHandle->GetProperty()->GetFName();
|
|
|
|
if (DataTablePropertyHandle->IsValidHandle() && RowNamePropertyHandle->IsValidHandle())
|
|
{
|
|
/** Setup Change callback */
|
|
FSimpleDelegate OnDataTableChangedDelegate = FSimpleDelegate::CreateSP(this, &FDataTableCustomizationLayout::OnDataTableChanged);
|
|
DataTablePropertyHandle->SetOnPropertyValueChanged(OnDataTableChangedDelegate);
|
|
|
|
/** Construct a asset picker widget with a custom filter */
|
|
StructBuilder.AddCustomRow(LOCTEXT("DataTable_TableName", "Data Table"))
|
|
.RowTag(PropertyName)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("DataTable_TableName", "Data Table"))
|
|
.Font(StructCustomizationUtils.GetRegularFont())
|
|
]
|
|
.ValueContent()
|
|
.MaxDesiredWidth(0.0f) // don't constrain the combo button width
|
|
[
|
|
SNew(SObjectPropertyEntryBox)
|
|
.PropertyHandle(DataTablePropertyHandle)
|
|
.AllowedClass(UDataTable::StaticClass())
|
|
.OnShouldFilterAsset(this, &FDataTableCustomizationLayout::ShouldFilterAsset)
|
|
];
|
|
|
|
FPropertyComboBoxArgs ComboArgs(RowNamePropertyHandle,
|
|
FOnGetPropertyComboBoxStrings::CreateSP(this, &FDataTableCustomizationLayout::OnGetRowStrings),
|
|
FOnGetPropertyComboBoxValue::CreateSP(this, &FDataTableCustomizationLayout::OnGetRowValueString));
|
|
ComboArgs.ShowSearchForItemCount = 1;
|
|
|
|
/** Construct a combo box widget to select from a list of valid options */
|
|
StructBuilder.AddCustomRow(LOCTEXT("DataTable_RowName", "Row Name"))
|
|
.RowTag(PropertyName)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("DataTable_RowName", "Row Name"))
|
|
.Font(StructCustomizationUtils.GetRegularFont())
|
|
]
|
|
.ValueContent()
|
|
.MaxDesiredWidth(0.0f) // don't constrain the combo button width
|
|
[
|
|
PropertyCustomizationHelpers::MakePropertyComboBox(ComboArgs)
|
|
];
|
|
}
|
|
}
|
|
|
|
bool FDataTableCustomizationLayout::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 FDataTableCustomizationLayout::OnSearchForReferences()
|
|
{
|
|
UDataTable* DataTable;
|
|
FName RowName;
|
|
|
|
if (GetCurrentValue(DataTable, RowName) && DataTable)
|
|
{
|
|
TArray<FAssetIdentifier> AssetIdentifiers;
|
|
AssetIdentifiers.Add(FAssetIdentifier(DataTable, RowName));
|
|
|
|
FEditorDelegates::OnOpenReferenceViewer.Broadcast(AssetIdentifiers, FReferenceViewerParams());
|
|
}
|
|
}
|
|
|
|
FString FDataTableCustomizationLayout::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 FDataTableCustomizationLayout::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);
|
|
}
|
|
}
|
|
|
|
void FDataTableCustomizationLayout::OnDataTableChanged()
|
|
{
|
|
UDataTable* CurrentTable;
|
|
FName OldName;
|
|
|
|
// Clear name on table change if no longer valid
|
|
if (GetCurrentValue(CurrentTable, OldName))
|
|
{
|
|
if (!CurrentTable || !CurrentTable->FindRowUnchecked(OldName))
|
|
{
|
|
RowNamePropertyHandle->SetValue(FName());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FDataTableCustomizationLayout::ShouldFilterAsset(const struct FAssetData& AssetData)
|
|
{
|
|
if (!RowTypeFilter.IsNone())
|
|
{
|
|
static const FName RowStructureTagName("RowStructure");
|
|
FString RowStructure;
|
|
if (AssetData.GetTagValue<FString>(RowStructureTagName, RowStructure))
|
|
{
|
|
if (RowStructure == RowTypeFilter.ToString())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This is slow, but at the moment we don't have an alternative to the short struct name search
|
|
UScriptStruct* RowStruct = UClass::TryFindTypeSlow<UScriptStruct>(RowStructure);
|
|
if (RowStruct && RowFilterStruct && RowStruct->IsChildOf(RowFilterStruct))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|
|
|