Files
UnrealEngine/Engine/Source/Editor/Kismet/Private/BlueprintWarningsConfigurationPanel.cpp
2025-05-18 13:04:45 +08:00

312 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BlueprintWarningsConfigurationPanel.h"
#include "Blueprint/BlueprintSupport.h"
#include "BlueprintRuntime.h"
#include "BlueprintRuntimeSettings.h"
#include "Containers/BitArray.h"
#include "Containers/Set.h"
#include "Containers/SparseArray.h"
#include "Containers/UnrealString.h"
#include "Delegates/Delegate.h"
#include "Fonts/SlateFontInfo.h"
#include "Framework/Views/ITypedTableView.h"
#include "HAL/PlatformCrt.h"
#include "Internationalization/Internationalization.h"
#include "Internationalization/Text.h"
#include "Layout/Children.h"
#include "Layout/Margin.h"
#include "Math/Color.h"
#include "Misc/AssertionMacros.h"
#include "Misc/Attribute.h"
#include "Misc/Optional.h"
#include "Misc/Paths.h"
#include "Modules/ModuleManager.h"
#include "SSettingsEditorCheckoutNotice.h"
#include "Serialization/Archive.h"
#include "SlotBase.h"
#include "Styling/AppStyle.h"
#include "Styling/SlateColor.h"
#include "Templates/UnrealTemplate.h"
#include "Types/SlateEnums.h"
#include "UObject/Class.h"
#include "UObject/NameTypes.h"
#include "UObject/UObjectGlobals.h"
#include "Widgets/Input/SComboBox.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/Layout/SSpacer.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Views/SHeaderRow.h"
#include "Widgets/Views/SListView.h"
#include "Widgets/Views/STableRow.h"
class ITableRow;
class STableViewBase;
class SWidget;
struct FTableRowStyle;
#define LOCTEXT_NAMESPACE "BlueprintWarningConfigurationPanel"
static const TCHAR* ColumnWarningIdentifier = TEXT("WarningIdentifier");
static const TCHAR* ColumnWarningDescription = TEXT("WarningDescription");
static const TCHAR* ColumnWarningBehavior = TEXT("WarningAsError");
typedef SComboBox< TSharedPtr<EBlueprintWarningBehavior> > FBlueprintWarningBehaviorComboBox;
class SBlueprintWarningRow : public SMultiColumnTableRow< FBlueprintWarningListEntry >
{
SLATE_BEGIN_ARGS(SBlueprintWarningRow) { }
SLATE_STYLE_ARGUMENT( FTableRowStyle, Style )
SLATE_END_ARGS()
void Construct( const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView, FBlueprintWarningListEntry InWarningInfo, SBlueprintWarningsConfigurationPanel* InParent )
{
WarningInfo = InWarningInfo;
Parent = InParent;
SMultiColumnTableRow<FBlueprintWarningListEntry>::Construct(FSuperRowType::FArguments(), InOwnerTableView);
}
virtual TSharedRef<SWidget> GenerateWidgetForColumn(const FName& InColumnName) override
{
if(InColumnName == ColumnWarningIdentifier)
{
return SNew(SBox)
.Padding(FMargin(4.0f, 0.0f))
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromName(WarningInfo->WarningIdentifier))
];
}
else if (InColumnName == ColumnWarningDescription )
{
return SNew(SBox)
.Padding(FMargin(4.0f, 0.0f))
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(WarningInfo->WarningDescription)
];
}
else if (InColumnName == ColumnWarningBehavior )
{
const auto& GetWarningText = [this]() -> FText
{
UEnum* const BlueprintWarningBehaviorEnum = FindObjectChecked<UEnum>(nullptr, TEXT("/Script/BlueprintRuntime.EBlueprintWarningBehavior"));
EBlueprintWarningBehavior Behavior = EBlueprintWarningBehavior::Warn;
FName WarningIdentifier = this->WarningInfo->WarningIdentifier;
if (FBlueprintSupport::ShouldTreatWarningAsError(WarningIdentifier))
{
Behavior = EBlueprintWarningBehavior::Error;
}
else if (FBlueprintSupport::ShouldSuppressWarning(WarningIdentifier))
{
Behavior = EBlueprintWarningBehavior::Suppress;
}
return BlueprintWarningBehaviorEnum->GetDisplayNameTextByValue(static_cast<int64>(Behavior));
};
return SNew(FBlueprintWarningBehaviorComboBox)
.Content()
[
SNew(STextBlock)
.Text_Lambda(GetWarningText)
]
.OptionsSource(&(Parent->CachedBlueprintWarningBehaviors))
.OnSelectionChanged(
FBlueprintWarningBehaviorComboBox::FOnSelectionChanged::CreateLambda(
[this]( TSharedPtr<EBlueprintWarningBehavior> Behavior, ESelectInfo::Type )
{
// apply result to each selected entry:
this->Parent->UpdateSelectedWarningBehaviors(*Behavior, *(this->WarningInfo));
}
)
)
.OnGenerateWidget(
FBlueprintWarningBehaviorComboBox::FOnGenerateWidget::CreateStatic(
[]( TSharedPtr<EBlueprintWarningBehavior> Behavior )->TSharedRef<SWidget>
{
UEnum* const BlueprintWarningBehaviorEnum = FindObjectChecked<UEnum>(nullptr, TEXT("/Script/BlueprintRuntime.EBlueprintWarningBehavior"));
return SNew(STextBlock)
.Text(BlueprintWarningBehaviorEnum->GetDisplayNameTextByValue(static_cast<int64>(*Behavior)));
}
)
);
}
else
{
ensure(false);
return SNew(SBorder);
}
}
private:
FBlueprintWarningListEntry WarningInfo;
SBlueprintWarningsConfigurationPanel* Parent;
};
void SBlueprintWarningsConfigurationPanel::Construct(const FArguments& InArgs)
{
IBlueprintRuntime* SettingsModule = FModuleManager::GetModulePtr<IBlueprintRuntime>("BlueprintRuntime");
if (!SettingsModule)
{
return;
}
UBlueprintRuntimeSettings* RuntimeSettings = SettingsModule->GetMutableBlueprintRuntimeSettings();
const TArray<FBlueprintWarningDeclaration>& Warnings = FBlueprintSupport::GetBlueprintWarnings();
for (const FBlueprintWarningDeclaration& Warning : Warnings )
{
CachedBlueprintWarningData.Add(MakeShareable(new FBlueprintWarningDeclaration(Warning)));
}
// This is not a great pattern:
CachedBlueprintWarningBehaviors.Add( MakeShareable( new EBlueprintWarningBehavior( EBlueprintWarningBehavior::Warn ) ) );
CachedBlueprintWarningBehaviors.Add( MakeShareable( new EBlueprintWarningBehavior( EBlueprintWarningBehavior::Error ) ) );
CachedBlueprintWarningBehaviors.Add( MakeShareable( new EBlueprintWarningBehavior( EBlueprintWarningBehavior::Suppress ) ) );
FString RelativeConfigFilePath = RuntimeSettings->GetDefaultConfigFilename();
FString FullSettingsPath = FPaths::ConvertRelativePathToFull(RelativeConfigFilePath);
TSharedPtr<SSettingsEditorCheckoutNotice> SettingsFile;
TSharedPtr<SBorder> Label;
// display a table of all known blueprint warnings, their description, etc:
ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SAssignNew(SettingsFile, SSettingsEditorCheckoutNotice)
.ConfigFilePath(FullSettingsPath)
]
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0.0f, 16.0f, 0.0f, 0.0f)
[
SAssignNew(Label, SBorder)
.Padding(3.0f)
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
.BorderBackgroundColor(FLinearColor(.6, .6, .6, 1.0f))
[
SNew(STextBlock)
.Font(FAppStyle::GetFontStyle("DetailsView.CategoryFontStyle"))
.Text(LOCTEXT("BlueprintWarningSettings", "Warning Behavior"))
]
]
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(SBorder)
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
[
SAssignNew(ListView, FBlueprintWarningListView)
.SelectionMode(ESelectionMode::Multi)
.ListItemsSource(&CachedBlueprintWarningData)
.OnGenerateRow(
FBlueprintWarningListView::FOnGenerateRow::CreateLambda(
[this](FBlueprintWarningListEntry Warning, const TSharedRef<STableViewBase>& Owner) -> TSharedRef< ITableRow >
{
return SNew(SBlueprintWarningRow, Owner, Warning, this);
}
)
)
.HeaderRow
(
SNew(SHeaderRow)
+ SHeaderRow::Column(ColumnWarningIdentifier)
.DefaultLabel(LOCTEXT("BlueprintWarningIdentifierHeaderLabel", "Identifier"))
.DefaultTooltip(LOCTEXT("BlueprintWarningIdentifierHeaderTooltip", "Identifier used in game runtime when warning is raised"))
.FillWidth(0.15f)
+ SHeaderRow::Column(ColumnWarningDescription)
.DefaultLabel(LOCTEXT("BlueprintWarningDescriptionHeaderLabel", "Description"))
.DefaultTooltip(LOCTEXT("BlueprintWarningDescriptionHeaderTooltip", "Description of when the warning is raised"))
.FillWidth(0.55f)
+ SHeaderRow::Column(ColumnWarningBehavior)
.DefaultLabel(LOCTEXT("BlueprintWarningBehaviorHeaderLabel", "Behavior"))
.DefaultTooltip(LOCTEXT("BlueprintWarningBehaviorHeaderTooltip", "Determines what happens when the warning is raised - warnings can be treated more strictly or suppressed entirely"))
.FillWidth(0.3f)
)
]
]
+ SVerticalBox::Slot()
[
SNew(SSpacer)
]
];
TAttribute<bool> Enabled = TAttribute<bool>::Create(
TAttribute<bool>::FGetter::CreateLambda(
[SettingsFile]()
{
return SettingsFile->IsUnlocked();
}
)
);
ListView->SetEnabled(Enabled);
Label->SetEnabled(Enabled);
}
void SBlueprintWarningsConfigurationPanel::UpdateSelectedWarningBehaviors(EBlueprintWarningBehavior NewBehavior, const FBlueprintWarningDeclaration& AlteredWarning)
{
IBlueprintRuntime* SettingsModule = FModuleManager::GetModulePtr<IBlueprintRuntime>("BlueprintRuntime");
if (!SettingsModule)
{
return;
}
UBlueprintRuntimeSettings* RuntimeSettings = SettingsModule->GetMutableBlueprintRuntimeSettings();
// no TArray.ForEach makes this the most convenient pattern:
for (const TSharedPtr<FBlueprintWarningDeclaration>& Declaration : CachedBlueprintWarningData)
{
if (ListView->IsItemSelected(Declaration) || Declaration->WarningIdentifier == AlteredWarning.WarningIdentifier)
{
// update config data:
FName CurrentIdentifer = Declaration->WarningIdentifier;
int WarningEntryIndex = RuntimeSettings->WarningSettings.IndexOfByPredicate(
[CurrentIdentifer](const FBlueprintWarningSettings& Entry) -> bool
{
return Entry.WarningIdentifier == CurrentIdentifer;
}
);
switch(NewBehavior)
{
case EBlueprintWarningBehavior::Warn:
if (WarningEntryIndex >= 0)
{
RuntimeSettings->WarningSettings.RemoveAtSwap(WarningEntryIndex);
}
break;
case EBlueprintWarningBehavior::Error:
case EBlueprintWarningBehavior::Suppress:
if (WarningEntryIndex >= 0)
{
FBlueprintWarningSettings& WarningEntry = RuntimeSettings->WarningSettings[WarningEntryIndex];
WarningEntry.WarningBehavior = NewBehavior;
}
else
{
FBlueprintWarningSettings NewEntry;
NewEntry.WarningIdentifier = CurrentIdentifer;
NewEntry.WarningDescription = Declaration->WarningDescription;
NewEntry.WarningBehavior = NewBehavior;
RuntimeSettings->WarningSettings.Add(NewEntry);
}
break;
}
}
}
// make sure runtime behavior matches config data:
SettingsModule->PropagateWarningSettings();
}
#undef LOCTEXT_NAMESPACE