Files
UnrealEngineUWP/Engine/Source/Editor/DetailCustomizations/Private/DataTableCustomization.cpp
Marcus Wassmer a8d6cc952b Merging //UE4/Dev-Main@4700769 to Dev-Rendering (//UE4/Dev-Rendering)
#rb none

[CL 4729861 by Marcus Wassmer in Dev-Rendering branch]
2019-01-15 18:04:38 -05:00

287 lines
9.0 KiB
C++

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "DataTableCustomization.h"
#include "DataTableRowUtlis.h"
#include "Editor.h"
#include "Framework/Application/SlateApplication.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Widgets/Input/SSearchBox.h"
#define LOCTEXT_NAMESPACE "FDataTableCustomizationLayout"
TSharedPtr<FString> FDataTableCustomizationLayout::InitWidgetContent()
{
TSharedPtr<FString> InitialValue = MakeShareable(new FString(LOCTEXT("DataTable_None", "None").ToString()));;
FName RowName;
const FPropertyAccess::Result RowResult = RowNamePropertyHandle->GetValue(RowName);
RowNames.Empty();
/** Get the properties we wish to work with */
const UDataTable* DataTable = nullptr;
DataTablePropertyHandle->GetValue((UObject*&)DataTable);
if (DataTable != nullptr)
{
/** Extract all the row names from the RowMap */
for (TMap<FName, uint8*>::TConstIterator Iterator(DataTable->GetRowMap()); Iterator; ++Iterator)
{
/** Create a simple array of the row names */
TSharedRef<FString> RowNameItem = MakeShareable(new FString(Iterator.Key().ToString()));
RowNames.Add(RowNameItem);
/** Set the initial value to the currently selected item */
if (Iterator.Key() == RowName)
{
InitialValue = RowNameItem;
}
}
}
/** Reset the initial value to ensure a valid entry is set */
if (RowResult != FPropertyAccess::MultipleValues)
{
FName NewValue = FName(**InitialValue);
RowNamePropertyHandle->SetValue(NewValue);
}
return InitialValue;
}
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);
}
FSimpleDelegate OnDataTableChangedDelegate = FSimpleDelegate::CreateSP(this, &FDataTableCustomizationLayout::OnDataTableChanged);
StructPropertyHandle->SetOnPropertyValueChanged(OnDataTableChangedDelegate);
HeaderRow
.NameContent()
[
InStructPropertyHandle->CreatePropertyNameWidget(FText::GetEmpty(), FText::GetEmpty(), false)
];
FDataTableRowUtils::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");
if (DataTablePropertyHandle->IsValidHandle() && RowNamePropertyHandle->IsValidHandle())
{
/** Queue up a refresh of the selected item, not safe to do from here */
StructCustomizationUtils.GetPropertyUtilities()->EnqueueDeferredAction(FSimpleDelegate::CreateSP(this, &FDataTableCustomizationLayout::OnDataTableChanged));
/** 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"))
.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)
];
/** Construct a combo box widget to select from a list of valid options */
StructBuilder.AddCustomRow(LOCTEXT("DataTable_RowName", "Row Name"))
.NameContent()
[
SNew(STextBlock)
.Text(LOCTEXT("DataTable_RowName", "Row Name"))
.Font(StructCustomizationUtils.GetRegularFont())
]
.ValueContent()
.MaxDesiredWidth(0.0f) // don't constrain the combo button width
[
SAssignNew(RowNameComboButton, SComboButton)
.ToolTipText(this, &FDataTableCustomizationLayout::GetRowNameComboBoxContentText)
.OnGetMenuContent(this, &FDataTableCustomizationLayout::GetListContent)
.OnComboBoxOpened(this, &FDataTableCustomizationLayout::HandleMenuOpen)
.ContentPadding(FMargin(2.0f, 2.0f))
.ButtonContent()
[
SNew(STextBlock)
.Text(this, &FDataTableCustomizationLayout::GetRowNameComboBoxContentText)
]
];
}
}
void FDataTableCustomizationLayout::HandleMenuOpen()
{
FSlateApplication::Get().SetKeyboardFocus(SearchBox);
}
void FDataTableCustomizationLayout::OnSearchForReferences()
{
if (CurrentSelectedItem.IsValid() && !CurrentSelectedItem->IsEmpty() && DataTablePropertyHandle.IsValid() && DataTablePropertyHandle->IsValidHandle())
{
UObject* SourceDataTable;
DataTablePropertyHandle->GetValue(SourceDataTable);
FName RowName(**CurrentSelectedItem);
TArray<FAssetIdentifier> AssetIdentifiers;
AssetIdentifiers.Add(FAssetIdentifier(SourceDataTable, RowName));
FEditorDelegates::OnOpenReferenceViewer.Broadcast(AssetIdentifiers);
}
}
TSharedRef<SWidget> FDataTableCustomizationLayout::GetListContent()
{
SAssignNew(RowNameComboListView, SListView<TSharedPtr<FString> >)
.ListItemsSource(&RowNames)
.OnSelectionChanged(this, &FDataTableCustomizationLayout::OnSelectionChanged)
.OnGenerateRow(this, &FDataTableCustomizationLayout::HandleRowNameComboBoxGenarateWidget)
.SelectionMode(ESelectionMode::Single);
// Ensure no filter is applied at the time the menu opens
OnFilterTextChanged(FText::GetEmpty());
if (CurrentSelectedItem.IsValid())
{
RowNameComboListView->SetSelection(CurrentSelectedItem);
}
return SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SAssignNew(SearchBox, SSearchBox)
.OnTextChanged(this, &FDataTableCustomizationLayout::OnFilterTextChanged)
]
+ SVerticalBox::Slot()
.FillHeight(1.f)
[
SNew(SBox)
.MaxDesiredHeight(600)
[
RowNameComboListView.ToSharedRef()
]
];
}
void FDataTableCustomizationLayout::OnDataTableChanged()
{
CurrentSelectedItem = InitWidgetContent();
if (RowNameComboListView.IsValid())
{
RowNameComboListView->SetSelection(CurrentSelectedItem);
RowNameComboListView->RequestListRefresh();
}
}
TSharedRef<ITableRow> FDataTableCustomizationLayout::HandleRowNameComboBoxGenarateWidget(TSharedPtr<FString> InItem, const TSharedRef<STableViewBase>& OwnerTable)
{
return
SNew(STableRow<TSharedPtr<FString>>, OwnerTable)
[
SNew(STextBlock).Text(FText::FromString(*InItem))
];
}
FText FDataTableCustomizationLayout::GetRowNameComboBoxContentText() const
{
FString RowNameValue;
const FPropertyAccess::Result RowResult = RowNamePropertyHandle->GetValue(RowNameValue);
if (RowResult == FPropertyAccess::Success)
{
return FText::FromString(*RowNameValue);
}
else if (RowResult == FPropertyAccess::Fail)
{
return LOCTEXT("DataTable_None", "None");
}
else
{
return LOCTEXT("MultipleValues", "Multiple Values");
}
}
void FDataTableCustomizationLayout::OnSelectionChanged(TSharedPtr<FString> SelectedItem, ESelectInfo::Type SelectInfo)
{
if (SelectedItem.IsValid())
{
CurrentSelectedItem = SelectedItem;
FName NewValue = FName(**SelectedItem);
RowNamePropertyHandle->SetValue(NewValue);
// Close the combo
RowNameComboButton->SetIsOpen(false);
}
}
void FDataTableCustomizationLayout::OnFilterTextChanged(const FText& InFilterText)
{
FString CurrentFilterText = InFilterText.ToString();
FName RowName;
const FPropertyAccess::Result RowResult = RowNamePropertyHandle->GetValue(RowName);
RowNames.Empty();
/** Get the properties we wish to work with */
const UDataTable* DataTable = nullptr;
DataTablePropertyHandle->GetValue((UObject*&)DataTable);
TArray<FString> AllRowNames;
if (DataTable != nullptr)
{
for (TMap<FName, uint8*>::TConstIterator Iterator(DataTable->GetRowMap()); Iterator; ++Iterator)
{
FString RowString = Iterator.Key().ToString();
AllRowNames.Add(RowString);
}
// Sort the names alphabetically.
AllRowNames.Sort();
}
for (const FString& RowString : AllRowNames)
{
if (CurrentFilterText == TEXT("") || RowString.Contains(CurrentFilterText))
{
TSharedRef<FString> RowNameItem = MakeShareable(new FString(RowString));
RowNames.Add(RowNameItem);
}
}
RowNameComboListView->RequestListRefresh();
}
bool FDataTableCustomizationLayout::ShouldFilterAsset(const struct FAssetData& AssetData)
{
if (!RowTypeFilter.IsNone())
{
const UDataTable* DataTable = Cast<UDataTable>(AssetData.GetAsset());
if (DataTable->RowStruct && DataTable->RowStruct->GetFName() == RowTypeFilter)
{
return false;
}
return true;
}
return false;
}
#undef LOCTEXT_NAMESPACE