Files
UnrealEngineUWP/Engine/Source/Editor/EditorWidgets/Private/SEnumCombo.cpp
sebastian nordgren 1ceeb6b19c Reverting SEnumCombo changes in 19111919 due to causing crashes when UMETA(Hidden) values were at the start of the enum.
#jira UE-143994
#jira UE-143998
#rb daren.cheng
#preflight 622224a3335298c3145bc7c9

[CL 19265950 by sebastian nordgren in ue5-main branch]
2022-03-04 09:55:19 -05:00

203 lines
5.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SEnumCombo.h"
#include "EditorStyleSet.h"
#include "Types/SlateEnums.h"
#include "Widgets/SToolTip.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#define LOCTEXT_NAMESPACE "EditorWidgets"
void SEnumComboBox::Construct(const FArguments& InArgs, const UEnum* InEnum)
{
static const FName UseEnumValuesAsMaskValuesInEditorName(TEXT("UseEnumValuesAsMaskValuesInEditor"));
Enum = InEnum;
CurrentValue = InArgs._CurrentValue;
check(CurrentValue.IsBound());
OnEnumSelectionChangedDelegate = InArgs._OnEnumSelectionChanged;
OnGetToolTipForValue = InArgs._OnGetToolTipForValue;
Font = InArgs._Font;
bUpdatingSelectionInternally = false;
bIsBitflagsEnum = Enum->HasMetaData(TEXT("Bitflags"));
if (bIsBitflagsEnum)
{
const bool bUseEnumValuesAsMaskValues = Enum->GetBoolMetaData(UseEnumValuesAsMaskValuesInEditorName);
const int32 BitmaskBitCount = sizeof(int32) << 3;
for (int32 i = 0; i < Enum->NumEnums() - 1; i++)
{
// Note: SEnumComboBox API prior to bitflags only supports 32 bit values, truncating the value here to keep the old API.
int32 Value = Enum->GetValueByIndex(i);
const bool bIsHidden = Enum->HasMetaData(TEXT("Hidden"), i);
if (Value >= 0 && !bIsHidden)
{
if (bUseEnumValuesAsMaskValues)
{
if (Value >= MAX_int32 || !FMath::IsPowerOfTwo(Value))
{
continue;
}
}
else
{
if (Value >= BitmaskBitCount)
{
continue;
}
Value = 1 << Value;
}
FText DisplayName = Enum->GetDisplayNameTextByIndex(i);
FText TooltipText = Enum->GetToolTipTextByIndex(i);
if (TooltipText.IsEmpty())
{
TooltipText = FText::Format(LOCTEXT("BitmaskDefaultFlagToolTipText", "Toggle {0} on/off"), DisplayName);
}
VisibleEnums.Emplace(i, Value, DisplayName, TooltipText);
}
}
}
else
{
for (int32 i = 0; i < Enum->NumEnums() - 1; i++)
{
if (Enum->HasMetaData(TEXT("Hidden"), i) == false)
{
VisibleEnums.Emplace(i, Enum->GetValueByIndex(i), Enum->GetDisplayNameTextByIndex(i), Enum->GetToolTipTextByIndex(i));
}
}
}
SComboButton::Construct(SComboButton::FArguments()
.ButtonStyle(InArgs._ButtonStyle)
.ContentPadding(InArgs._ContentPadding)
.OnGetMenuContent(this, &SEnumComboBox::OnGetMenuContent)
.ButtonContent()
[
SNew(STextBlock)
.Font(Font)
.Text(this, &SEnumComboBox::GetCurrentValueText)
.ToolTipText(this, &SEnumComboBox::GetCurrentValueTooltip)
]);
}
FText SEnumComboBox::GetCurrentValueText() const
{
if (bIsBitflagsEnum)
{
if (CurrentValue.IsSet())
{
const int32 BitmaskValue = CurrentValue.Get();
if (BitmaskValue != 0)
{
TArray<FText> SetFlags;
SetFlags.Reserve(VisibleEnums.Num());
for (const FEnumInfo& FlagInfo : VisibleEnums)
{
if ((BitmaskValue & FlagInfo.Value) != 0)
{
SetFlags.Add(FlagInfo.DisplayName);
}
}
if (SetFlags.Num() > 3)
{
SetFlags.SetNum(3);
SetFlags.Add(FText::FromString("..."));
}
return FText::Join(FText::FromString(" | "), SetFlags);
}
return LOCTEXT("BitmaskButtonContentNoFlagsSet", "(No Flags Set)");
}
return FText::GetEmpty();
}
const int32 ValueNameIndex = Enum->GetIndexByValue(CurrentValue.Get());
return Enum->GetDisplayNameTextByIndex(ValueNameIndex);
}
FText SEnumComboBox::GetCurrentValueTooltip() const
{
if (bIsBitflagsEnum)
{
const int32 BitmaskValue = CurrentValue.Get();
if (BitmaskValue != 0)
{
TArray<FText> SetFlags;
SetFlags.Reserve(VisibleEnums.Num());
for (const FEnumInfo& FlagInfo : VisibleEnums)
{
if ((BitmaskValue & FlagInfo.Value) != 0)
{
if (OnGetToolTipForValue.IsBound())
{
SetFlags.Add(OnGetToolTipForValue.Execute(FlagInfo.Index));
}
else
{
SetFlags.Add(FlagInfo.DisplayName);
}
}
}
return FText::Join(FText::FromString(" | "), SetFlags);
}
return FText::GetEmpty();
}
const int32 ValueNameIndex = Enum->GetIndexByValue(CurrentValue.Get());
if (OnGetToolTipForValue.IsBound())
{
return OnGetToolTipForValue.Execute(ValueNameIndex);
}
return VisibleEnums[ValueNameIndex].TooltipText;
}
TSharedRef<SWidget> SEnumComboBox::OnGetMenuContent()
{
const bool bCloseAfterSelection = !bIsBitflagsEnum;
FMenuBuilder MenuBuilder(bCloseAfterSelection, nullptr);
for (const FEnumInfo& FlagInfo : VisibleEnums)
{
MenuBuilder.AddMenuEntry(
FlagInfo.DisplayName,
FlagInfo.TooltipText,
FSlateIcon(),
FUIAction
(
FExecuteAction::CreateLambda([this, FlagInfo]()
{
if (bIsBitflagsEnum)
{
// Toggle value
const int32 Value = CurrentValue.Get() ^ FlagInfo.Value;
OnEnumSelectionChangedDelegate.ExecuteIfBound(Value, ESelectInfo::Direct);
}
else
{
// Set value
OnEnumSelectionChangedDelegate.ExecuteIfBound(FlagInfo.Value, ESelectInfo::OnMouseClick);
}
}),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([this, FlagInfo]() -> bool
{
return (CurrentValue.Get() & FlagInfo.Value) != 0;
})
),
NAME_None,
bIsBitflagsEnum ? EUserInterfaceActionType::Check : EUserInterfaceActionType::None);
}
return MenuBuilder.MakeWidget();
}
#undef LOCTEXT_NAMESPACE