240 lines
6.3 KiB
C++
240 lines
6.3 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SEnumCombo.h"
|
|
|
|
#include "Framework/Commands/UIAction.h"
|
|
#include "Framework/Commands/UICommandInfo.h"
|
|
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
|
#include "HAL/PlatformCrt.h"
|
|
#include "Internationalization/Internationalization.h"
|
|
#include "Math/NumericLimits.h"
|
|
#include "Math/UnrealMathSSE.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "Textures/SlateIcon.h"
|
|
#include "Types/SlateEnums.h"
|
|
#include "UObject/Class.h"
|
|
#include "UObject/NameTypes.h"
|
|
#include "UObject/UnrealNames.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
|
|
class SWidget;
|
|
|
|
#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;
|
|
OverrideNoFlagsSetText = InArgs._OverrideNoFlagsSetText;
|
|
bUpdatingSelectionInternally = false;
|
|
bIsBitflagsEnum = InArgs._bForceBitFlags || Enum->HasMetaData(TEXT("Bitflags"));
|
|
|
|
TArray<int32> EnumValueSubset = InArgs._EnumValueSubset;
|
|
if(EnumValueSubset.IsEmpty())
|
|
{
|
|
EnumValueSubset.Reserve(Enum->NumEnums() - 1);
|
|
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.
|
|
const int32 Value = static_cast<int32>(Enum->GetValueByIndex(i));
|
|
EnumValueSubset.Add(Value);
|
|
}
|
|
}
|
|
|
|
if (bIsBitflagsEnum)
|
|
{
|
|
const bool bUseEnumValuesAsMaskValues = Enum->GetBoolMetaData(UseEnumValuesAsMaskValuesInEditorName);
|
|
const int32 BitmaskBitCount = sizeof(int32) << 3;
|
|
|
|
for (int32 i = 0; i < EnumValueSubset.Num(); i++)
|
|
{
|
|
int32 Value = EnumValueSubset[i];
|
|
const int32 Index = Enum->GetIndexByValue(Value);
|
|
const bool bIsHidden = Enum->HasMetaData(TEXT("Hidden"), Index);
|
|
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(Index);
|
|
FText TooltipText = Enum->GetToolTipTextByIndex(Index);
|
|
if (TooltipText.IsEmpty())
|
|
{
|
|
TooltipText = FText::Format(LOCTEXT("BitmaskDefaultFlagToolTipText", "Toggle {0} on/off"), DisplayName);
|
|
}
|
|
|
|
VisibleEnums.Emplace(Index, Value, DisplayName, TooltipText);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int32 i = 0; i < EnumValueSubset.Num(); i++)
|
|
{
|
|
const int32 Value = EnumValueSubset[i];
|
|
const int32 Index = Enum->GetIndexByValue(Value);
|
|
if (Enum->HasMetaData(TEXT("Hidden"), Index) == false)
|
|
{
|
|
VisibleEnums.Emplace(Index, static_cast<int32>(Enum->GetValueByIndex(Index)), Enum->GetDisplayNameTextByIndex(Index), Enum->GetToolTipTextByIndex(Index));
|
|
}
|
|
}
|
|
}
|
|
|
|
SComboButton::Construct(SComboButton::FArguments()
|
|
.ComboButtonStyle(InArgs._ComboButtonStyle)
|
|
.ButtonStyle(InArgs._ButtonStyle)
|
|
.ContentPadding(InArgs._ContentPadding)
|
|
.OnGetMenuContent(this, &SEnumComboBox::OnGetMenuContent)
|
|
.ButtonContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.TextStyle(InArgs._TextStyle)
|
|
.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);
|
|
}
|
|
if (OverrideNoFlagsSetText.IsSet())
|
|
{
|
|
return OverrideNoFlagsSetText.Get();
|
|
}
|
|
else
|
|
{
|
|
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 Enum->GetToolTipTextByIndex(ValueNameIndex);
|
|
}
|
|
|
|
TSharedRef<SWidget> SEnumComboBox::OnGetMenuContent()
|
|
{
|
|
const bool bCloseAfterSelection = !bIsBitflagsEnum;
|
|
FMenuBuilder MenuBuilder(bCloseAfterSelection, nullptr, nullptr, true);
|
|
|
|
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
|