Initial commit.

This commit is contained in:
Jamie Greunbaum 2023-03-13 15:58:22 -04:00
commit e6492ea0e3
17 changed files with 3420 additions and 0 deletions

20
ControllerMenu.uplugin Normal file
View File

@ -0,0 +1,20 @@
{
"FileVersion": 3,
"Version": 1.0,
"VersionName": "1.0",
"FriendlyName": "ControllerMenu",
"Description": "Custom class that allows easy setup of hybrid controller/keyboard/mouse menu navigation.",
"Category": "Menu",
"CreatedBy": "Batty Bovine Productions, LLC",
"CreatedByURL": "https://battybovine.com",
"EnabledByDefault": true,
"CanContainContent": true,
"IsBetaVersion": true,
"Modules": [
{
"Name": "ControllerMenu",
"Type": "Runtime",
"LoadingPhase": "PreDefault"
}
]
}

View File

@ -0,0 +1,49 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
using System.IO;
namespace UnrealBuildTool.Rules
{
public class ControllerMenu : ModuleRules
{
public ControllerMenu(ReadOnlyTargetRules Target) : base(Target)
{
bLegacyPublicIncludePaths = true;
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
ShadowVariableWarningLevel = WarningLevel.Warning;
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public"));
PrivateIncludePaths.AddRange(
new string[]
{
"ControllerMenu/Private"
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"InputCore",
"UMG",
"DeveloperSettings"
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Slate",
"SlateCore"
}
);
}
}
}
///

View File

@ -0,0 +1,44 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#include "CoreMinimal.h"
#include "Engine.h"
#include "Modules/ModuleManager.h"
#include "IControllerMenu_Implementation.h"
DEFINE_LOG_CATEGORY(ControllerMenuLog);
#define LOCTEXT_NAMESPACE "ControllerMenu"
class FControllerMenu : public IControllerMenu_Implementation
{
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
// End IModuleInterface implementation
};
void FControllerMenu::StartupModule()
{
// This code will execute after your module is loaded into memory (but after global variables are initialized, of course.)
UE_LOG(ControllerMenuLog, Warning, TEXT("ControllerMenu: Log Started"));
}
void FControllerMenu::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
UE_LOG(ControllerMenuLog, Warning, TEXT("ControllerMenu: Log Ended"));
}
IMPLEMENT_MODULE(FControllerMenu, ControllerMenu)
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,47 @@
/**
* Copyright ©2019 BattyBovine
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**/
#include "ControllerMenuGlobalSettings.h"
void UControllerMenuGlobalSettings::PostInitProperties()
{
Super::PostInitProperties();
}
FName UControllerMenuGlobalSettings::GetCategoryName() const
{
return FName(TEXT("Plugins"));
}
#if WITH_EDITOR
void UControllerMenuGlobalSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
if (PropertyChangedEvent.Property)
{
this->ExportValuesToConsoleVariables(PropertyChangedEvent.Property);
}
}
#endif

View File

@ -0,0 +1,14 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#include "CoreUObject.h"
#include "Engine.h"
#include "ModuleManager.h"
#include "Slate.h"
#include "UnrealEd.h"
// You should place include statements to your module's private header files here. You only need to
// add includes for headers that are used in most of your module's source files though.
#include "IControllerMenu_Implementation.h"

View File

@ -0,0 +1,173 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#include "ControllerButton.h"
#include "ConstructorHelpers.h"
#include "Components/ButtonSlot.h"
#include "Components/TextBlock.h"
#include "Engine/Font.h"
#include "Framework/Application/SlateApplication.h"
#include "Input/SButton.h"
#include "Misc/ConfigCacheIni.h"
#include "Text/STextBlock.h"
#include "Widgets/SBoxPanel.h"
#define LOCTEXT_NAMESPACE "ControllerButton"
UControllerButton::UControllerButton(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer)
{
this->bIsVariable = true;
if (this->DefaultControllerButtonStyle == nullptr)
{
// HACK: THIS SHOULD NOT COME FROM CORESTYLE AND SHOULD INSTEAD BE DEFINED BY ENGINE TEXTURES/PROJECT SETTINGS
this->DefaultControllerButtonStyle = new FButtonStyle(FCoreStyle::Get().GetWidgetStyle<FButtonStyle>("Button"));
// Unlink UMG default colors from the editor settings colors.
this->DefaultControllerButtonStyle->UnlinkColors();
}
this->ButtonStyle = *this->DefaultControllerButtonStyle;
this->ClickMethod = EButtonClickMethod::DownAndUp;
this->TouchMethod = EButtonTouchMethod::DownAndUp;
this->PressMethod = EButtonPressMethod::ButtonPress;
}
TSharedRef<SWidget> UControllerButton::RebuildWidget()
{
this->SlateButton = SNew(SButton)
.OnClicked(BIND_UOBJECT_DELEGATE(FOnClicked, SlateHandleClicked))
.OnPressed(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandlePressed))
.OnReleased(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandleReleased))
.OnHovered_UObject(this, &UControllerButton::SlateHandleHovered)
.OnUnhovered_UObject(this, &UControllerButton::SlateHandleUnhovered)
.ButtonStyle(&this->ButtonStyle)
.ClickMethod(this->ClickMethod)
.TouchMethod(this->TouchMethod)
.PressMethod(this->PressMethod)
.HAlign(EHorizontalAlignment::HAlign_Fill)
.VAlign(EVerticalAlignment::VAlign_Fill)
.IsEnabled(this->GetIsEnabled())
.IsFocusable(this->bIsFocusable);
if (this->GetChildrenCount() > 0)
{
Cast<UButtonSlot>(this->GetContentSlot())->BuildSlot(SlateButton.ToSharedRef());
}
// Cache our normal style settings for programmatically changing the style later
this->NormalBrush = this->ButtonStyle.Normal;
this->NormalPadding = this->ButtonStyle.NormalPadding;
return this->SlateButton.ToSharedRef();
}
//void UControllerButton::SynchronizeProperties()
//{
// Super::SynchronizeProperties();
//}
void UControllerButton::ReleaseSlateResources(bool bReleaseChildren)
{
Super::ReleaseSlateResources(bReleaseChildren);
this->SlateButton.Reset();
}
UClass* UControllerButton::GetSlotClass() const
{
return UButtonSlot::StaticClass();
}
void UControllerButton::OnSlotAdded(UPanelSlot* InSlot)
{
// Add the child to the live slot if it already exists
if (this->SlateButton.IsValid())
{
CastChecked<UButtonSlot>(InSlot)->BuildSlot(this->SlateButton.ToSharedRef());
}
}
void UControllerButton::OnSlotRemoved(UPanelSlot* InSlot)
{
// Remove the widget from the live slot if it exists.
if (this->SlateButton.IsValid())
{
this->SlateButton->SetContent(SNullWidget::NullWidget);
}
}
FReply UControllerButton::SlateHandleClicked()
{
this->OnClicked.Broadcast();
return FReply::Handled();
}
void UControllerButton::SlateHandlePressed()
{
this->OnPressed.Broadcast();
}
void UControllerButton::SlateHandleReleased()
{
this->OnReleased.Broadcast();
}
void UControllerButton::SlateHandleHovered()
{
this->OnHovered.Broadcast();
}
void UControllerButton::SlateHandleUnhovered()
{
this->OnUnhovered.Broadcast();
}
/** BEGIN ITakesControllerFocus implementation */
void UControllerButton::Press_Implementation()
{
this->ControllerButtonState = EControllerButtonState::Pressed;
this->ButtonStyle.Normal = this->ButtonStyle.Pressed;
this->SlateButton->SetPadding(this->ButtonStyle.PressedPadding);
FSlateApplication::Get().PlaySound(this->ButtonStyle.PressedSlateSound);
this->SlateHandlePressed();
}
void UControllerButton::Release_Implementation()
{
this->ControllerButtonState = EControllerButtonState::Hovered;
this->ButtonStyle.Normal = this->ButtonStyle.Hovered;
this->SlateButton->SetPadding(this->ButtonStyle.NormalPadding);
this->SlateHandleReleased();
}
void UControllerButton::Hover_Implementation()
{
this->ControllerButtonState = EControllerButtonState::Hovered;
this->ButtonStyle.Normal = this->ButtonStyle.Hovered;
this->SlateButton->SetPadding(this->ButtonStyle.NormalPadding);
FSlateApplication::Get().PlaySound(this->ButtonStyle.HoveredSlateSound);
this->SlateHandleHovered();
}
void UControllerButton::Unhover_Implementation()
{
this->ControllerButtonState = EControllerButtonState::Normal;
this->ButtonStyle.Normal = this->NormalBrush;
this->SlateButton->SetPadding(this->NormalPadding);
this->SlateHandleUnhovered();
}
/** END ITakesControllerFocus implementation */
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,476 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#include "TextSpinner.h"
#include "ConstructorHelpers.h"
#include "SCustomTextBlock.h"
#include "Engine/Font.h"
#include "Framework/Application/SlateApplication.h"
#include "Input/SButton.h"
#include "Misc/ConfigCacheIni.h"
#include "Widgets/SBoxPanel.h"
#define LOCTEXT_NAMESPACE "TextSpinner"
UTextSpinner::UTextSpinner(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer)
{
this->bIsVariable = true;
this->bLoop = false;
this->bIsPressable = false;
this->bEmitSelectionChangedEvents = true;
this->OptionTextShadowOffset = FVector2D(1.0f, 1.0f);
this->OptionTextColorAndOpacity = FLinearColor::White;
this->OptionTextColorAndOpacityHovered = FLinearColor::White;
this->OptionTextColorAndOpacityPressed = FLinearColor::White;
this->OptionTextShadowColorAndOpacity = FLinearColor::Transparent;
this->ButtonTextColorAndOpacity = FLinearColor::White;
this->ButtonTextShadowColorAndOpacity = FLinearColor::Transparent;
if (this->DefaultSpinnerButtonStyle == nullptr)
{
// HACK: THIS SHOULD NOT COME FROM CORESTYLE AND SHOULD INSTEAD BE DEFINED BY ENGINE TEXTURES/PROJECT SETTINGS
this->DefaultSpinnerButtonStyle = new FButtonStyle(FCoreStyle::Get().GetWidgetStyle<FButtonStyle>("Button"));
// Unlink UMG default colors from the editor settings colors.
this->DefaultSpinnerButtonStyle->UnlinkColors();
}
this->PreviousNextButtonStyle = this->OptionButtonStyle = *this->DefaultSpinnerButtonStyle;
if (!IsRunningDedicatedServer())
{
static ConstructorHelpers::FObjectFinder<UFont> RobotoFontObj(TEXT("/Engine/EngineFonts/Roboto"));
this->OptionTextFont = FSlateFontInfo(RobotoFontObj.Object, 24, FName("Bold"));
this->ButtonTextFont = FSlateFontInfo(RobotoFontObj.Object, 24, FName("Bold"));
}
this->ClickMethod = EButtonClickMethod::DownAndUp;
this->TouchMethod = EButtonTouchMethod::DownAndUp;
this->PressMethod = EButtonPressMethod::ButtonPress;
// Retrieve and cache the Previous and Next arrows from the plugin settings
if (GConfig)
{
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("TextSpinnerPreviousText"), this->PreviousTextString, GGameIni);
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("TextSpinnerNextText"), this->NextTextString, GGameIni);
}
}
TSharedRef<SWidget> UTextSpinner::RebuildWidget()
{
// Create the box which will contain our compound widget
this->ParentHBox = SNew(SHorizontalBox);
// Generate the "Next" button content
this->NextButtonText = SNew(STextBlock);
this->NextButtonText->SetText(this->NextTextString.IsEmpty() ? FText::AsCultureInvariant(">") : FText::FromString(this->NextTextString));
this->NextButtonText->SetColorAndOpacity(this->ButtonTextColorAndOpacity);
this->NextButtonText->SetFont(this->ButtonTextFont);
this->NextButtonText->SetMargin(this->ButtonTextMargin);
this->NextButtonText->SetJustification(ETextJustify::Center);
this->NextButton = SNew(SButton)
.OnClicked(BIND_UOBJECT_DELEGATE(FOnClicked, SlateHandleClickedNext))
.OnPressed(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandlePressedNext))
.OnReleased(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandleReleasedNext))
.OnHovered_UObject(this, &UTextSpinner::SlateHandleHoveredNext)
.OnUnhovered_UObject(this, &UTextSpinner::SlateHandleUnhoveredNext)
.ButtonStyle(&this->PreviousNextButtonStyle)
.ClickMethod(this->ClickMethod)
.TouchMethod(this->TouchMethod)
.PressMethod(this->PressMethod)
.HAlign(EHorizontalAlignment::HAlign_Right)
.VAlign(EVerticalAlignment::VAlign_Center)
.IsFocusable(this->bIsFocusable)
.IsEnabled(this->Items.Num() > 1)
.Content()
[
this->NextButtonText.ToSharedRef()
];
SHorizontalBox::FScopedWidgetSlotArguments NextButtonSlot = this->ParentHBox->AddSlot();
NextButtonSlot.AutoWidth();
NextButtonSlot.HAlign(EHorizontalAlignment::HAlign_Right);
NextButtonSlot.VAlign(EVerticalAlignment::VAlign_Fill);
NextButtonSlot.AttachWidget(this->NextButton.ToSharedRef());
this->OptionText = SNew(SCustomTextBlock);
this->OptionText->SetText(this->GetSelectedItem());
this->OptionText->SetColorAndOpacity(this->OptionTextColorAndOpacity);
this->OptionText->SetFont(this->OptionTextFont);
this->OptionText->SetMargin(this->OptionTextMargin);
this->OptionText->SetJustification(ETextJustify::Center);
this->OptionText->SetPreventDisable(this->bIsPressable);
this->OptionButton = SNew(SButton)
.OnClicked(BIND_UOBJECT_DELEGATE(FOnClicked, SlateHandleClicked))
.OnPressed(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandlePressed))
.OnReleased(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandleReleased))
.OnHovered_UObject(this, &UTextSpinner::SlateHandleHovered)
.OnUnhovered_UObject(this, &UTextSpinner::SlateHandleUnhovered)
.ButtonStyle(&this->OptionButtonStyle)
.ClickMethod(this->ClickMethod)
.TouchMethod(this->TouchMethod)
.PressMethod(this->PressMethod)
.HAlign(EHorizontalAlignment::HAlign_Fill)
.VAlign(EVerticalAlignment::VAlign_Center)
.IsFocusable(this->bIsFocusable)
.IsEnabled(this->GetIsEnabled() && this->bIsPressable)
.Content()
[
this->OptionText.ToSharedRef()
];
SHorizontalBox::FScopedWidgetSlotArguments TextSlot = this->ParentHBox->AddSlot();
TextSlot.FillWidth(1.0);
TextSlot.HAlign(EHorizontalAlignment::HAlign_Fill);
TextSlot.VAlign(EVerticalAlignment::VAlign_Fill);
TextSlot.AttachWidget(this->OptionButton.ToSharedRef());
// Generate the "Previous" button content
this->PreviousButtonText = SNew(STextBlock);
this->PreviousButtonText->SetText(this->PreviousTextString.IsEmpty() ? FText::AsCultureInvariant("<") : FText::FromString(this->PreviousTextString));
this->PreviousButtonText->SetColorAndOpacity(this->ButtonTextColorAndOpacity);
this->PreviousButtonText->SetFont(this->ButtonTextFont);
this->PreviousButtonText->SetMargin(this->ButtonTextMargin);
this->PreviousButtonText->SetJustification(ETextJustify::Center);
this->PreviousButton = SNew(SButton)
.OnClicked(BIND_UOBJECT_DELEGATE(FOnClicked, SlateHandleClickedPrevious))
.OnPressed(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandlePressedPrevious))
.OnReleased(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandleReleasedPrevious))
.OnHovered_UObject(this, &UTextSpinner::SlateHandleHoveredPrevious)
.OnUnhovered_UObject(this, &UTextSpinner::SlateHandleUnhoveredPrevious)
.ButtonStyle(&this->PreviousNextButtonStyle)
.ClickMethod(this->ClickMethod)
.TouchMethod(this->TouchMethod)
.PressMethod(this->PressMethod)
.HAlign(EHorizontalAlignment::HAlign_Left)
.VAlign(EVerticalAlignment::VAlign_Center)
.IsFocusable(this->bIsFocusable)
.IsEnabled(this->Items.Num() > 1)
.Content()
[
this->PreviousButtonText.ToSharedRef()
];
SHorizontalBox::FScopedWidgetSlotArguments PreviousButtonSlot = this->ParentHBox->AddSlot();
PreviousButtonSlot.AutoWidth();
PreviousButtonSlot.HAlign(EHorizontalAlignment::HAlign_Left);
PreviousButtonSlot.VAlign(EVerticalAlignment::VAlign_Fill);
PreviousButtonSlot.AttachWidget(this->PreviousButton.ToSharedRef());
// Cache our normal style settings for programmatically changing the style later
this->NormalBrush = this->OptionButtonStyle.Normal;
this->NormalPadding = this->OptionButtonStyle.NormalPadding;
return this->ParentHBox.ToSharedRef();
}
void UTextSpinner::SetSelectedItem(const FText Item/*, ESelectInfo::Type SelectionType*/)
{
const int32 FoundIndex = this->FindItemIndex(Item);
if (FoundIndex != INDEX_NONE)
{
this->SetSelectedIndex(FoundIndex);
if (this->bEmitSelectionChangedEvents)
{
this->OnSelectionChanged.Broadcast(this->Items[this->SelectedItemIndex], this->SelectedItemIndex);
}
}
}
bool UTextSpinner::SetSelectedIndex(const int32 Index/*, ESelectInfo::Type SelectionType*/)
{
if (const int32 NumItems = this->Items.Num())
{
int32 NewSelection = INDEX_NONE;
if (this->bLoop)
{
NewSelection = (Index + NumItems) % NumItems;
}
else
{
NewSelection = FMath::Clamp<int32>(Index, 0, NumItems - 1);
}
if (NewSelection > INDEX_NONE && NewSelection != this->SelectedItemIndex)
{
this->SelectedItemIndex = NewSelection;
this->OptionText->SetText(this->Items[this->SelectedItemIndex]);
if (this->bEmitSelectionChangedEvents)
{
this->OnSelectionChanged.Broadcast(this->Items[this->SelectedItemIndex], this->SelectedItemIndex);
}
return true;
}
}
else
{
this->SelectedItemIndex = INDEX_NONE;
}
return false;
}
void UTextSpinner::AddItem(const FText Item)
{
this->Items.Emplace(Item);
if (this->SelectedItemIndex < 0)
{
this->SelectedItemIndex = 0;
}
if (this->Items.Num() > 1)
{
this->PreviousButton->SetEnabled(true);
this->NextButton->SetEnabled(true);
}
else
{
this->PreviousButton->SetEnabled(false);
this->NextButton->SetEnabled(false);
}
}
void UTextSpinner::PreviousItem()
{
if (this->PreviousButton->IsEnabled())
{
if (this->SetSelectedIndex(this->SelectedItemIndex - 1))
{
FSlateApplication::Get().PlaySound(this->PreviousNextButtonStyle.PressedSlateSound);
}
}
}
void UTextSpinner::NextItem()
{
if (this->NextButton->IsEnabled())
{
if (this->SetSelectedIndex(this->SelectedItemIndex + 1))
{
FSlateApplication::Get().PlaySound(this->PreviousNextButtonStyle.PressedSlateSound);
}
}
}
int32 UTextSpinner::FindItemIndex(const FText& Item) const
{
if (this->Items.Num())
{
int32 FoundIndex;
for (FoundIndex = 0; FoundIndex < this->Items.Num(); FoundIndex++)
{
if (Item.EqualTo(this->Items[FoundIndex]))
{
return FoundIndex;
}
}
}
return INDEX_NONE;
}
void UTextSpinner::SynchronizeProperties()
{
Super::SynchronizeProperties();
this->PreviousButtonText->SetFont(this->ButtonTextFont);
this->PreviousButtonText->SetColorAndOpacity(this->ButtonTextColorAndOpacity);
this->PreviousButtonText->SetMargin(this->ButtonTextMargin);
this->PreviousButtonText->SetJustification(ETextJustify::Center);
this->OptionText->SetText(this->GetSelectedItem());
this->OptionText->SetFont(this->OptionTextFont);
switch (this->OptionButtonState)
{
case ETextSpinnerState::Normal:
this->OptionText->SetColorAndOpacity(this->OptionTextColorAndOpacity);
break;
case ETextSpinnerState::Hovered:
this->OptionText->SetColorAndOpacity(this->OptionTextColorAndOpacityHovered);
break;
case ETextSpinnerState::Pressed:
if (this->bIsPressable)
{
this->OptionText->SetColorAndOpacity(this->OptionTextColorAndOpacityPressed);
}
break;
}
this->OptionText->SetMargin(this->OptionTextMargin);
this->OptionText->SetJustification(this->OptionTextJustification);
this->NextButtonText->SetFont(this->ButtonTextFont);
this->NextButtonText->SetColorAndOpacity(this->ButtonTextColorAndOpacity);
this->NextButtonText->SetMargin(this->ButtonTextMargin);
this->NextButtonText->SetJustification(ETextJustify::Center);
}
void UTextSpinner::ReleaseSlateResources(bool bReleaseChildren)
{
Super::ReleaseSlateResources(bReleaseChildren);
this->PreviousButton.Reset();
this->PreviousButtonText.Reset();
this->OptionButton.Reset();
this->OptionText.Reset();
this->NextButton.Reset();
this->NextButtonText.Reset();
this->ParentHBox.Reset();
}
FReply UTextSpinner::SlateHandleClicked()
{
if (this->bIsPressable)
{
this->OnClicked.Broadcast();
return FReply::Handled();
}
return FReply::Unhandled();
}
void UTextSpinner::SlateHandlePressed()
{
if (this->bIsPressable)
{
this->OnPressed.Broadcast();
}
}
void UTextSpinner::SlateHandleReleased()
{
if (this->bIsPressable)
{
this->OnReleased.Broadcast();
}
}
void UTextSpinner::SlateHandleHovered()
{
this->OnHovered.Broadcast();
}
void UTextSpinner::SlateHandleUnhovered()
{
this->OnUnhovered.Broadcast();
}
FReply UTextSpinner::SlateHandleClickedPrevious()
{
this->OnPreviousClicked.Broadcast();
return FReply::Handled();
}
void UTextSpinner::SlateHandlePressedPrevious()
{
this->SetSelectedIndex(this->SelectedItemIndex - 1);
this->OnPreviousPressed.Broadcast();
}
void UTextSpinner::SlateHandleReleasedPrevious()
{
this->OnPreviousReleased.Broadcast();
}
void UTextSpinner::SlateHandleHoveredPrevious()
{
this->OnPreviousHovered.Broadcast();
}
void UTextSpinner::SlateHandleUnhoveredPrevious()
{
this->OnPreviousUnhovered.Broadcast();
}
FReply UTextSpinner::SlateHandleClickedNext()
{
this->OnNextClicked.Broadcast();
return FReply::Handled();
}
void UTextSpinner::SlateHandlePressedNext()
{
this->SetSelectedIndex(this->SelectedItemIndex + 1);
this->OnNextPressed.Broadcast();
}
void UTextSpinner::SlateHandleReleasedNext()
{
this->OnNextReleased.Broadcast();
}
void UTextSpinner::SlateHandleHoveredNext()
{
this->OnNextHovered.Broadcast();
}
void UTextSpinner::SlateHandleUnhoveredNext()
{
this->OnNextUnhovered.Broadcast();
}
/** BEGIN ITakesControllerFocus implementation */
void UTextSpinner::Press_Implementation()
{
if (this->bIsPressable)
{
this->OptionButtonState = ETextSpinnerState::Pressed;
this->OptionButtonStyle.Normal = this->OptionButtonStyle.Pressed;
this->OptionButton->SetPadding(this->OptionButtonStyle.PressedPadding);
FSlateApplication::Get().PlaySound(this->OptionButtonStyle.PressedSlateSound);
this->OptionText->SetColorAndOpacity(this->OptionTextColorAndOpacityPressed);
this->SlateHandlePressed();
}
}
void UTextSpinner::Release_Implementation()
{
if (this->bIsPressable)
{
this->OptionButtonState = ETextSpinnerState::Hovered;
this->OptionButtonStyle.Normal = this->OptionButtonStyle.Hovered;
this->OptionButton->SetPadding(this->OptionButtonStyle.NormalPadding);
this->OptionText->SetColorAndOpacity(this->OptionTextColorAndOpacityHovered);
this->SlateHandleReleased();
}
}
void UTextSpinner::Hover_Implementation()
{
this->OptionButtonState = ETextSpinnerState::Hovered;
this->OptionButtonStyle.Normal = this->OptionButtonStyle.Hovered;
this->OptionButton->SetPadding(this->OptionButtonStyle.NormalPadding);
FSlateApplication::Get().PlaySound(this->OptionButtonStyle.HoveredSlateSound);
this->OptionText->SetColorAndOpacity(this->OptionTextColorAndOpacityHovered);
this->SlateHandleHovered();
}
void UTextSpinner::Unhover_Implementation()
{
this->OptionButtonState = ETextSpinnerState::Normal;
this->OptionButtonStyle.Normal = this->NormalBrush;
this->OptionButton->SetPadding(this->OptionButtonStyle.NormalPadding);
this->OptionText->SetColorAndOpacity(this->OptionTextColorAndOpacity);
this->SlateHandleUnhovered();
}
/** END ITakesControllerFocus implementation */
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,58 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#include "ControllerMenuMessageBoxWidget.h"
#include "Components/ControllerButton.h"
#include "Components/TextBlock.h"
bool UControllerMenuMessageBoxWidget::Initialize()
{
if (Super::Initialize() && (this->AcceptButton && this->CancelButton))
{
this->AddHorizontalFocusableWidget(this->CancelButton);
this->AddHorizontalFocusableWidget(this->AcceptButton);
this->SetCancelButton(this->CancelButton);
this->AcceptButton->OnPressed.AddDynamic(this, &UControllerMenuMessageBoxWidget::Accepted);
this->CancelButton->OnPressed.AddDynamic(this, &UControllerMenuMessageBoxWidget::Cancelled);
return true;
}
return false;
}
void UControllerMenuMessageBoxWidget::SetMessageBody(const FText& Message)
{
this->MessageBody->SetText(Message);
}
void UControllerMenuMessageBoxWidget::SetAcceptText(const FText& Accept)
{
this->AcceptText->SetText(Accept);
}
void UControllerMenuMessageBoxWidget::SetCancelText(const FText& Cancel)
{
this->CancelText->SetText(Cancel);
}
void UControllerMenuMessageBoxWidget::Accepted()
{
this->UnbindMenuActions();
this->OnAccepted.Broadcast();
this->ExitMenu();
}
void UControllerMenuMessageBoxWidget::Cancelled()
{
this->UnbindMenuActions();
this->OnCancelled.Broadcast();
this->ExitMenu();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
/**
* Copyright ©2019 BattyBovine
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**/
#pragma once
#include "Engine/DeveloperSettings.h"
#include "ControllerMenuGlobalSettings.generated.h"
/**
* Global settings for ControllerMenu classes
*/
UCLASS(Config=Game, defaultconfig, meta = (DisplayName = "ControllerMenu"))
class CONTROLLERMENU_API UControllerMenuGlobalSettings : public UDeveloperSettings
{
GENERATED_BODY()
public:
UPROPERTY(config, EditAnywhere, Category = "Input | Axis", meta = (
DisplayName = "AxisY Action",
ToolTip = "Input action for pressing up and down in a menu using a joystick axis.\nIf this is set, it will override Up/Down action mappings.",
ConfigRestartRequired = false))
FString AxisYAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Axis", meta = (
DisplayName = "AxisX Action",
ToolTip = "Input action for pressing left and right in a menu using a joystick axis.\nIf this is set, it will override Left/Right action mappings.",
ConfigRestartRequired = false))
FString AxisXAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Axis", meta = (
DisplayName = "Axis Movement Threshold",
ToolTip = "Sets how far the joystick must move before menu movement is recognised.",
ConfigRestartRequired = false))
float AxisMovementThreshold = 0.75;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Up Action",
ToolTip = "Input action for pressing up in a menu.\nWill not be used if an AxisY action is set.",
ConfigRestartRequired = false))
FString UpAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Down Action",
ToolTip = "Input action for pressing down in a menu.\nWill not be used if an AxisY action is set.",
ConfigRestartRequired = false))
FString DownAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Left Action",
ToolTip = "Input action for pressing left in a menu.\nWill not be used if an AxisX action is set.",
ConfigRestartRequired = false))
FString LeftAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Right Action",
ToolTip = "Input action for pressing right in a menu.\nWill not be used if an AxisX action is set.",
ConfigRestartRequired = false))
FString RightAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Previous Action",
ToolTip = "Input action for navigating to the previous item in a menu.",
ConfigRestartRequired = false))
FString PreviousAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Next Action",
ToolTip = "Input action for navigating to the next item in a menu.",
ConfigRestartRequired = false))
FString NextAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Accept Action",
ToolTip = "Input action for pressing the accept button in a menu.",
ConfigRestartRequired = false))
FString AcceptAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Cancel Action",
ToolTip = "Input action for pressing the cancel button in a menu.",
ConfigRestartRequired = false))
FString CancelAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Actions", meta = (
DisplayName = "Pause Action",
ToolTip = "Input action for pressing the pause button in a menu.",
ConfigRestartRequired = false))
FString PauseAction;
UPROPERTY(config, EditAnywhere, Category = "Input | Mouse", meta = (
DisplayName = "Mouse Movement Threshold",
ToolTip = "Sets the distance the mouse needs to move before the menu passes control to it.",
ConfigRestartRequired = false))
float MouseMovementThreshold = 2.0;
UPROPERTY(config, EditAnywhere, Category = "Widgets | ControllerMenu", meta = (
DisplayName = "Cancel Confirm",
ToolTip = "If enabled, the \"Cancel\" action will set focus to the menu's cancel button if it's not in focus, then a second press will activate the button. If disabled, the cancel action will simply press the cancel button directly.",
ConfigRestartRequired = false))
bool CancelConfirm = true;
UPROPERTY(config, EditAnywhere, Category = "Widgets | Text Spinner", meta = (
DisplayName = "Previous Text",
ToolTip = "Change the string used for the \"Previous\" button in the text spinner widget.",
ConfigRestartRequired = false))
FString TextSpinnerPreviousText = "<";
UPROPERTY(config, EditAnywhere, Category = "Widgets | Text Spinner", meta = (
DisplayName = "Next Text",
ToolTip = "Change the string used for the \"Next\" button in the text spinner widget.",
ConfigRestartRequired = false))
FString TextSpinnerNextText = ">";
public:
virtual void PostInitProperties() override;
virtual FName GetCategoryName() const override;
#if WITH_EDITOR
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
};

View File

@ -0,0 +1,45 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
DECLARE_LOG_CATEGORY_EXTERN(ControllerMenuLog, Log, All);
/**
* The public interface to this module. In most cases, this interface is only public to sibling modules
* within this plugin.
*/
class IControllerMenu_Implementation : public IModuleInterface
{
public:
/**
* Singleton-like access to this module's interface. This is just for convenience!
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
*
* @return Returns singleton instance, loading the module on demand if needed
*/
static inline IControllerMenu_Implementation& Get()
{
return FModuleManager::LoadModuleChecked<IControllerMenu_Implementation>("ControllerMenu");
}
/**
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
*
* @return True if the module is loaded and ready to use
*/
static inline bool IsAvailable()
{
return FModuleManager::Get().IsModuleLoaded("ControllerMenu");
}
};

View File

@ -0,0 +1,49 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#pragma once
#include "CoreMinimal.h"
#include "ITakesControllerFocus.generated.h"
UINTERFACE(BlueprintType)
class CONTROLLERMENU_API UTakesControllerFocus : public UInterface
{
GENERATED_BODY()
};
class CONTROLLERMENU_API ITakesControllerFocus
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
void Press();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
void Release();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
void Hover();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
void Unhover();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
FSlateBrush GetNormalStyle();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
FSlateBrush GetHoveredStyle();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
FSlateBrush GetPressedStyle();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
FMargin GetNormalPadding();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
FMargin GetPressedPadding();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="ControllerMenu")
void SetFocusable(bool Focusable);
protected:
FSlateBrush NormalBrush;
FMargin NormalPadding;
};

View File

@ -0,0 +1,137 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#pragma once
#include "CoreMinimal.h"
#include "ITakesControllerFocus.h"
#include "Components/Button.h"
#include "Components/ContentWidget.h"
#include "ControllerButton.generated.h"
UENUM(BlueprintType)
enum class EControllerButtonState : uint8
{
Normal,
Hovered,
Pressed
};
/**
* A custom button that supports progammatic hover and press behaviour
*/
UCLASS(Blueprintable, BlueprintType, meta=(DisplayName="Button"))
class CONTROLLERMENU_API UControllerButton : public UContentWidget, public ITakesControllerFocus
{
GENERATED_BODY()
public:
UControllerButton(const FObjectInitializer& ObjectInitializer);
/** Sets the current enabled status of the widget */
virtual void SetIsEnabled(bool bInIsEnabled) override { Super::SetIsEnabled(bInIsEnabled); this->OnFocusChanged.Broadcast(); }
/** The button style used at runtime */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance", meta=(DisplayName="Button Style"))
FButtonStyle ButtonStyle;
/** BEGIN ITakesControllerFocus implementation */
virtual void Press_Implementation() override;
virtual void Release_Implementation() override;
virtual void Hover_Implementation() override;
virtual void Unhover_Implementation() override;
virtual FSlateBrush GetNormalStyle_Implementation() override { return this->NormalBrush; }
virtual FSlateBrush GetHoveredStyle_Implementation() override { return this->ButtonStyle.Hovered; }
virtual FSlateBrush GetPressedStyle_Implementation() override { return this->ButtonStyle.Pressed; }
virtual FMargin GetNormalPadding_Implementation() override { return this->NormalPadding; }
virtual FMargin GetPressedPadding_Implementation() override { return this->ButtonStyle.PressedPadding; }
virtual void SetFocusable_Implementation(bool Focusable) override { this->bIsFocusable = Focusable; }
/** END ITakesControllerFocus implementation */
/** Called when the button is clicked */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonClickedEvent OnClicked;
/** Called when the button is pressed */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonPressedEvent OnPressed;
/** Called when the main button is released */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonReleasedEvent OnReleased;
/** Called when the button is hovered */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonHoverEvent OnHovered;
/** Called when the button is unhovered */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonHoverEvent OnUnhovered;
/** The type of mouse action required by the user to trigger the buttons' 'Click' */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Interaction", AdvancedDisplay)
TEnumAsByte<EButtonClickMethod::Type> ClickMethod;
/** The type of touch action required by the user to trigger the buttons' 'Click' */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Interaction", AdvancedDisplay)
TEnumAsByte<EButtonTouchMethod::Type> TouchMethod;
/** The type of keyboard/gamepad button press action required by the user to trigger the buttons' 'Click' */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Interaction", AdvancedDisplay)
TEnumAsByte<EButtonPressMethod::Type> PressMethod;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnFocusChangedEvent);
UPROPERTY(BlueprintAssignable, Category = "ControllerMenu | Event")
FOnFocusChangedEvent OnFocusChanged;
/** Whether the button can be focused with the keyboard or gamepad */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Interaction")
uint8 bIsFocusable : 1;
TSharedPtr<SButton> SlateButton;
#if WITH_EDITOR
virtual const FText GetPaletteCategory() override { return NSLOCTEXT("Button", "ControllerMenu", "ControllerMenu"); }
#endif
protected:
/** BEGIN UWidget Interface */
virtual TSharedRef<SWidget> RebuildWidget() override;
//virtual void SynchronizeProperties() override;
/** END UWidget Interface */
/** BEGIN UVisual Interface */
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
/** END UVisual Interface */
/** BEGIN UPanelWidget Interface */
virtual UClass* GetSlotClass() const override;
virtual void OnSlotAdded(UPanelSlot* Slot) override;
virtual void OnSlotRemoved(UPanelSlot* Slot) override;
/** END UPanelWidget Interface */
FReply SlateHandleClicked();
void SlateHandlePressed();
void SlateHandleReleased();
void SlateHandleHovered();
void SlateHandleUnhovered();
private:
struct FButtonStyle* DefaultControllerButtonStyle = nullptr;
EControllerButtonState ControllerButtonState = EControllerButtonState::Normal;
};

View File

@ -0,0 +1,335 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#pragma once
#include "CoreMinimal.h"
#include "ITakesControllerFocus.h"
#include "Components/Button.h"
#include "TextSpinner.generated.h"
UENUM(BlueprintType)
enum class ETextSpinnerState : uint8
{
Normal,
Hovered,
Pressed
};
/**
* A spinner box that displays text instead of numbers
*/
UCLASS(Blueprintable, BlueprintType, meta=(DisplayName="Text Spinner"))
class CONTROLLERMENU_API UTextSpinner : public UWidget, public ITakesControllerFocus
{
GENERATED_BODY()
public:
UTextSpinner(const FObjectInitializer& ObjectInitializer);
/** Set the selected item to the specified item, if possible */
UFUNCTION(BlueprintCallable)
void SetSelectedItem(const FText Item/*, ESelectInfo::Type SelectionType = ESelectInfo::Direct*/);
/** Get the selected item */
UFUNCTION(BlueprintPure)
FText GetSelectedItem() const { if (this->SelectedItemIndex >= 0 && this->Items.Num()) { return this->Items[this->SelectedItemIndex]; } return FText(); }
/** Select the item at the specified index */
UFUNCTION(BlueprintCallable)
bool SetSelectedIndex(const int32 Index/*, ESelectInfo::Type SelectionType = ESelectInfo::Direct*/);
/** Get the index of the selected item */
UFUNCTION(BlueprintPure)
int32 GetSelectedIndex() const { return this->SelectedItemIndex; }
/** Add an item to the list */
UFUNCTION(BlueprintCallable)
void AddItem(const FText Item);
/** Switch to the previous item in the list */
UFUNCTION(BlueprintCallable)
void PreviousItem();
/** Switch to the next item in the list */
UFUNCTION(BlueprintCallable)
void NextItem();
UFUNCTION(BlueprintPure)
int32 FindItemIndex(const FText& Item) const;
UFUNCTION(BlueprintPure)
FText GetItemAtIndex(int32 Index) { return (Index >= 0 && Index < this->Items.Num()) ? this->Items[Index] : FText(); }
UFUNCTION(BlueprintCallable)
void ClearItems() { this->Items.Empty(); }
/** BEGIN ITakesControllerFocus interface */
virtual void Press_Implementation() override;
virtual void Release_Implementation() override;
virtual void Hover_Implementation() override;
virtual void Unhover_Implementation() override;
virtual FSlateBrush GetNormalStyle_Implementation() override { return this->NormalBrush; }
virtual FSlateBrush GetHoveredStyle_Implementation() override { return this->OptionButtonStyle.Hovered; }
virtual FSlateBrush GetPressedStyle_Implementation() override { return this->OptionButtonStyle.Pressed; }
virtual FMargin GetNormalPadding_Implementation() override { return this->NormalPadding; }
virtual FMargin GetPressedPadding_Implementation() override { return this->OptionButtonStyle.PressedPadding; }
//virtual void SetFocusable_Implementation(bool Focusable) override { this->bIsFocusable = Focusable; }
/** END ITakesControllerFocus interface */
/** The list of items to cycle through */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Text Spinner")
TArray<FText> Items;
/** If true, items will loop around when scrolling past the last item in the list */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Text Spinner")
uint8 bLoop : 1;
/** Bindings for Option Text colour */
PROPERTY_BINDING_IMPLEMENTATION(FSlateColor, OptionTextColorAndOpacity);
PROPERTY_BINDING_IMPLEMENTATION(FSlateColor, OptionTextColorAndOpacityHovered);
PROPERTY_BINDING_IMPLEMENTATION(FSlateColor, OptionTextColorAndOpacityPressed);
PROPERTY_BINDING_IMPLEMENTATION(FLinearColor, OptionTextShadowColorAndOpacity);
/** Bindings for Previous/Next Text colour */
PROPERTY_BINDING_IMPLEMENTATION(FSlateColor, ButtonTextColorAndOpacity);
/** The button style used at runtime */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance", meta=(DisplayName="Button Style"))
FButtonStyle OptionButtonStyle;
/** The button style used at runtime */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Appearance", meta=(DisplayName="Previous/Next Style"))
FButtonStyle PreviousNextButtonStyle;
/** Text justification */
UPROPERTY(Category = "Text | Spinner", EditAnywhere, BlueprintReadOnly)
TEnumAsByte<ETextJustify::Type> OptionTextJustification;
/** Margin */
UPROPERTY(Category = "Text | Spinner", EditAnywhere, BlueprintReadOnly)
FMargin OptionTextMargin;
/** Normal Color and Opacity */
UPROPERTY(Category = "Text | Spinner", EditAnywhere, BlueprintReadOnly)
FSlateColor OptionTextColorAndOpacity;
/** A delegate for Normal Color and Opacity */
UPROPERTY()
FGetSlateColor OptionTextColorAndOpacityDelegate;
/** Hover Color and Opacity */
UPROPERTY(Category = "Text | Spinner", EditAnywhere, BlueprintReadOnly)
FSlateColor OptionTextColorAndOpacityHovered;
/** A delegate for Hover Color and Opacity */
UPROPERTY()
FGetSlateColor OptionTextColorAndOpacityHoveredDelegate;
/** Pressed Color and Opacity */
UPROPERTY(Category = "Text | Spinner", EditAnywhere, BlueprintReadOnly)
FSlateColor OptionTextColorAndOpacityPressed;
/** A delegate for Pressed Color and Opacity */
UPROPERTY()
FGetSlateColor OptionTextColorAndOpacityPressedDelegate;
/** The main text font */
UPROPERTY(Category = "Text | Spinner", EditAnywhere, BlueprintReadOnly)
FSlateFontInfo OptionTextFont;
/** The direction the shadow is cast */
UPROPERTY(Category = "Text | Spinner", EditAnywhere, BlueprintReadOnly)
FVector2D OptionTextShadowOffset;
/** Shadow Color */
UPROPERTY(Category = "Text | Spinner", EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "Shadow Color"))
FLinearColor OptionTextShadowColorAndOpacity;
/** A delegate for the Shadow Color and Opacity */
UPROPERTY()
FGetLinearColor OptionTextShadowColorAndOpacityDelegate;
/** The button font */
UPROPERTY(Category = "Text | Buttons", EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "Text Font"))
FSlateFontInfo ButtonTextFont;
/** Button colour and opacity */
UPROPERTY(Category = "Text | Buttons", EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "Text Color And Opacity"))
FSlateColor ButtonTextColorAndOpacity;
/** A delegate for button colour and opacity */
UPROPERTY()
FGetSlateColor ButtonTextColorAndOpacityDelegate;
/** Button shadow colour */
UPROPERTY(Category = "Text | Buttons", EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "Shadow Color"))
FLinearColor ButtonTextShadowColorAndOpacity;
/** A delegate for the button shadow colour and opacity */
UPROPERTY()
FGetLinearColor ButtonTextShadowColorAndOpacityDelegate;
/** Button margin */
UPROPERTY(Category = "Text | Buttons", EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "Text Margin"))
FMargin ButtonTextMargin;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSelectionChangedEvent, FText, SelectedItem, int32, SelectedIndex/*, ESelectInfo::Type, SelectionType*/);
UPROPERTY(BlueprintAssignable, Category=Events)
FOnSelectionChangedEvent OnSelectionChanged;
UPROPERTY(Category = "Text Spinner", EditAnywhere, BlueprintReadWrite)
uint8 bEmitSelectionChangedEvents : 1;
/** Called when the main button is clicked */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonClickedEvent OnClicked;
/** Called when the main button is pressed */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonPressedEvent OnPressed;
/** Called when the main button is released */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonReleasedEvent OnReleased;
/** Called when the main button is hovered */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonHoverEvent OnHovered;
/** Called when the main button is unhovered */
UPROPERTY(BlueprintAssignable, Category="Button | Event")
FOnButtonHoverEvent OnUnhovered;
/** Called when the "Previous" button is clicked */
UPROPERTY(BlueprintAssignable, Category="Previous Button | Event")
FOnButtonClickedEvent OnPreviousClicked;
/** Called when the "Previous" button is pressed */
UPROPERTY(BlueprintAssignable, Category="Previous Button | Event")
FOnButtonPressedEvent OnPreviousPressed;
/** Called when the "Previous" button is released */
UPROPERTY(BlueprintAssignable, Category="Previous Button | Event")
FOnButtonReleasedEvent OnPreviousReleased;
/** Called when the "Previous" button is hovered */
UPROPERTY(BlueprintAssignable, Category="Previous Button | Event")
FOnButtonHoverEvent OnPreviousHovered;
/** Called when the "Previous" button is unhovered */
UPROPERTY(BlueprintAssignable, Category="Previous Button | Event")
FOnButtonHoverEvent OnPreviousUnhovered;
/** Called when the "Next" button is clicked */
UPROPERTY(BlueprintAssignable, Category="Next Button | Event")
FOnButtonClickedEvent OnNextClicked;
/** Called when the "Next" button is pressed */
UPROPERTY(BlueprintAssignable, Category="Next Button | Event")
FOnButtonPressedEvent OnNextPressed;
/** Called when the "Next" button is released */
UPROPERTY(BlueprintAssignable, Category="Next Button | Event")
FOnButtonReleasedEvent OnNextReleased;
/** Called when the "Next" button is hovered */
UPROPERTY(BlueprintAssignable, Category="Next Button | Event")
FOnButtonHoverEvent OnNextHovered;
/** Called when the "Next" button is unhovered */
UPROPERTY(BlueprintAssignable, Category="Next Button | Event")
FOnButtonHoverEvent OnNextUnhovered;
/** The type of mouse action required by the user to trigger the buttons' 'Click' */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Interaction", AdvancedDisplay)
TEnumAsByte<EButtonClickMethod::Type> ClickMethod;
/** The type of touch action required by the user to trigger the buttons' 'Click' */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Interaction", AdvancedDisplay)
TEnumAsByte<EButtonTouchMethod::Type> TouchMethod;
/** The type of keyboard/gamepad button press action required by the user to trigger the buttons' 'Click' */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Interaction", AdvancedDisplay)
TEnumAsByte<EButtonPressMethod::Type> PressMethod;
/** Sometimes a button should only be mouse-clickable and never keyboard focusable. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Interaction")
uint8 bIsFocusable : 1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Interaction")
uint8 bIsPressable : 1;
/** Horizontal alignment box for our compound widget */
TSharedPtr<SHorizontalBox> ParentHBox;
/** Widgets to comprise the "Previous" button */
TSharedPtr<SButton> PreviousButton;
TSharedPtr<STextBlock> PreviousButtonText;
/** Button to let the spinner act as a button in itself */
TSharedPtr<SButton> OptionButton;
TSharedPtr<class SCustomTextBlock> OptionText;
/** Widgets to comprise the "Next" button */
TSharedPtr<SButton> NextButton;
TSharedPtr<STextBlock> NextButtonText;
#if WITH_EDITOR
virtual const FText GetPaletteCategory() override { return NSLOCTEXT("TextSpinner", "ControllerMenu", "ControllerMenu"); }
#endif
protected:
/** BEGIN UWidget Interface */
virtual TSharedRef<SWidget> RebuildWidget() override;
virtual void SynchronizeProperties() override;
/** END UWidget Interface */
/** BEGIN UVisual Interface */
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
/** END UVisual Interface */
FReply SlateHandleClicked();
void SlateHandlePressed();
void SlateHandleReleased();
void SlateHandleHovered();
void SlateHandleUnhovered();
FReply SlateHandleClickedPrevious();
void SlateHandlePressedPrevious();
void SlateHandleReleasedPrevious();
void SlateHandleHoveredPrevious();
void SlateHandleUnhoveredPrevious();
FReply SlateHandleClickedNext();
void SlateHandlePressedNext();
void SlateHandleReleasedNext();
void SlateHandleHoveredNext();
void SlateHandleUnhoveredNext();
private:
struct FButtonStyle* DefaultSpinnerButtonStyle = nullptr;
int32 SelectedItemIndex = 0;
FString PreviousTextString;
FString NextTextString;
ETextSpinnerState OptionButtonState = ETextSpinnerState::Normal;
};

View File

@ -0,0 +1,43 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#pragma once
#include "CoreMinimal.h"
#include "Widgets/ControllerMenuWidget.h"
#include "ControllerMenuMessageBoxWidget.generated.h"
/**
* Display a message box with accept and cancel buttons
*/
UCLASS()
class CONTROLLERMENU_API UControllerMenuMessageBoxWidget : public UControllerMenuWidget
{
GENERATED_BODY()
public:
void SetMessageBody(const FText& Message);
void SetAcceptText(const FText& Accept);
void SetCancelText(const FText& Cancel);
UFUNCTION() void Accepted();
UFUNCTION() void Cancelled();
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMessageBoxChoiceEvent);
UPROPERTY(BlueprintAssignable) FMessageBoxChoiceEvent OnAccepted;
UPROPERTY(BlueprintAssignable) FMessageBoxChoiceEvent OnCancelled;
protected:
virtual bool Initialize() override;
UPROPERTY(BlueprintReadWrite, meta=(BindWidget)) class UControllerButton* AcceptButton = nullptr;
UPROPERTY(BlueprintReadWrite, meta=(BindWidget)) class UControllerButton* CancelButton = nullptr;
UPROPERTY(BlueprintReadWrite, meta=(BindWidget)) class UTextBlock* MessageBody = nullptr;
UPROPERTY(BlueprintReadWrite, meta=(BindWidget)) class UTextBlock* AcceptText = nullptr;
UPROPERTY(BlueprintReadWrite, meta=(BindWidget)) class UTextBlock* CancelText = nullptr;
};

View File

@ -0,0 +1,346 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "ControllerMenuWidget.generated.h"
USTRUCT()
struct FControllerWidgetFocusMap
{
GENERATED_BODY()
UWidget* Up = nullptr;
UWidget* Down = nullptr;
UWidget* Left = nullptr;
UWidget* Right = nullptr;
UWidget* Previous = nullptr;
UWidget* Next = nullptr;
};
UENUM(BlueprintType)
enum class EControllerMenuInputDevice : uint8
{
None UMETA(DisplayName="None"),
Mouse UMETA(DisplayName="Mouse"),
Touchscreen UMETA(DisplayName="Touchscreen"),
Keyboard UMETA(DisplayName="Keyboard"),
Controller UMETA(DisplayName="Controller")
};
/**
* Static helper functions for working with widgets
*/
UCLASS()
class CONTROLLERMENU_API UControllerMenuWidgetHelperFunctions : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintPure, Category = "User Interface|Geometry")
static FVector2D GetAbsolutePosition(const FGeometry& Geometry) { return Geometry.GetAbsolutePosition(); }
};
/**
* Parent class for all in-game menus
*/
UCLASS()
class CONTROLLERMENU_API UControllerMenuWidget : public UUserWidget
{
GENERATED_UCLASS_BODY()
public:
/** Open and display the menu at the specified depth */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void OpenMenu(int32 Depth = 0);
/** Close the menu and emit a signal notifying other connected menus */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void ExitMenu();
/** Sets which button should exit the menu. The Cancel
button will automatically jump to this button when
pressed, and will exit the menu if pressed again. */
UFUNCTION(BlueprintCallable)
void SetCancelButton(class UWidget *Button);
/** Up button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnUpPressed();
/** Down button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnDownPressed();
/** Left button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnLeftPressed();
/** Right button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnRightPressed();
/** Previous button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnPreviousPressed();
/** Next button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnNextPressed();
/** Accept button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnAcceptPressed();
/** Cancel button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnCancelPressed();
/** Pause button press event */
UFUNCTION(BlueprintImplementableEvent)
void OnPausePressed();
/** Custom button press events */
UFUNCTION(BlueprintImplementableEvent)
void OnCustomPressed(const FName &CustomAction);
/** Sends the currently focused widget to a Blueprint event when the focus changes */
UFUNCTION(BlueprintImplementableEvent)
void FocusChanged(UWidget *FocusedWidget);
/** Set input focus to the given widget */
UFUNCTION(BlueprintCallable)
void SetWidgetFocus(UWidget *NewWidget);
/** Check if this widget has input focus */
UFUNCTION(BlueprintPure)
bool HasWidgetFocus(UWidget *Widget) const;
/** Clear input focus */
UFUNCTION(BlueprintCallable)
void ClearWidgetFocus();
/** Check current widget focus and refocus if necessary, such as if the focused widget has been disabled */
UFUNCTION(BlueprintCallable)
void Refocus(const UWidget *FocusedWidget);
/** Get the currently focused widget */
UFUNCTION(BlueprintPure)
UWidget* GetFocusedWidget() const { if(this->FocusedWidgetIndex>=0&&this->FocusedWidgetIndex<this->FocusableWidgetArray.Num()){return this->FocusableWidgetArray[this->FocusedWidgetIndex];}else{return nullptr;} }
/** Get the index value of the currently focused widget */
UFUNCTION(BlueprintPure)
int32 GetFocusedWidgetIndex() const { return this->FocusedWidgetIndex; }
UFUNCTION(BlueprintPure)
TArray<UWidget*> GetFocusableWidgets() const { return this->FocusableWidgetArray; }
/** Get the current input device */
UFUNCTION(BlueprintPure)
EControllerMenuInputDevice GetInputDevice() const { return this->LastInputDevice; }
/** Get the name of the current input device */
UFUNCTION(BlueprintPure)
FName GetInputDeviceName() const;
/** Event called when the input device has changed */
UFUNCTION(BlueprintImplementableEvent)
void InputDeviceChanged(const EControllerMenuInputDevice &InputDevice);
/** List of names for custom input actions */
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Actions")
TArray<FName> CustomActions;
UPROPERTY(BlueprintReadWrite, Transient, meta=(BindWidgetAnim))
UWidgetAnimation *OpenAnimation = nullptr;
UPROPERTY(BlueprintReadWrite, Transient, meta=(BindWidgetAnim))
UWidgetAnimation *CloseAnimation = nullptr;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOpenCloseEvent);
/** Event called when the menu is requested to open */
UPROPERTY(BlueprintAssignable)
FOpenCloseEvent OnMenuOpened;
/** Event called when the menu is finished transitioning in */
UPROPERTY(BlueprintAssignable)
FOpenCloseEvent OnMenuShown;
/** Event called when the menu is set to be exited */
UPROPERTY(BlueprintAssignable)
FOpenCloseEvent OnMenuExited;
/** Event called when the menu is finished shutting down */
UPROPERTY(BlueprintAssignable)
FOpenCloseEvent OnMenuClosed;
protected:
void InitializeMenuActions();
void BindMenuActions();
void UnbindMenuActions();
virtual void OnOpenOverride(){}
virtual void OnCloseOverride(){}
/** Add focusable widgets arranged in a grid layout panel */
UFUNCTION(BlueprintCallable, meta=(AdvancedDisplay="1"))
void AddGridPanelWidgets(class UGridPanel *GridPanel);
/** Add a focusable widget beneath the previously added widget */
UFUNCTION(BlueprintCallable, meta=(AdvancedDisplay="1"))
void AddVerticalFocusableWidget(class UWidget* Widget, class UWidget* Left = nullptr, class UWidget* Right = nullptr);
/** Add a focusable widget to the right of the previously added widget */
UFUNCTION(BlueprintCallable, meta=(AdvancedDisplay="1"))
void AddHorizontalFocusableWidget(class UWidget* Widget, class UWidget* Up = nullptr, class UWidget* Down = nullptr);
/** Add a focusable widget to the focus stack, and add custom focus widgets for each input action */
UFUNCTION(BlueprintCallable, meta=(AdvancedDisplay="1"))
void AddFocusableWidgetCustom(class UWidget* Widget, class UWidget* Up = nullptr, class UWidget* Down = nullptr, class UWidget* Left = nullptr, class UWidget* Right = nullptr, class UWidget* Previous = nullptr, class UWidget* Next = nullptr);
UFUNCTION(BlueprintCallable, meta = (AdvancedDisplay = "1"))
void EditWidgetFocus(class UWidget* Widget, class UWidget* Up = nullptr, class UWidget* Down = nullptr, class UWidget* Left = nullptr, class UWidget* Right = nullptr, class UWidget* Previous = nullptr, class UWidget* Next = nullptr);
/** Event called when the menu been opened */
UFUNCTION(BlueprintImplementableEvent)
void MenuOpened();
/** Event called when the menu has finished transitioning in */
UFUNCTION(BlueprintImplementableEvent)
void MenuShown();
/** Event called when the menu has been asked to close */
UFUNCTION(BlueprintImplementableEvent)
void MenuExited();
/** Event called when the menu has finished closing */
UFUNCTION(BlueprintImplementableEvent)
void MenuClosed();
/** Event called when a child menu has been opened */
UFUNCTION(BlueprintImplementableEvent)
void ChildMenuOpened();
/** Event called when the child menu has been asked to close */
UFUNCTION(BlueprintImplementableEvent)
void ChildMenuExited();
/** Event called when the child menu has finished closing */
UFUNCTION(BlueprintImplementableEvent)
void ChildMenuClosed();
/** Event called when a message box has been opened */
UFUNCTION(BlueprintImplementableEvent)
void MessageBoxOpened();
/** Event called when the message box has been asked to close */
UFUNCTION(BlueprintImplementableEvent)
void MessageBoxExited();
/** Event called when the message box has finished closing */
UFUNCTION(BlueprintImplementableEvent)
void MessageBoxClosed();
/** Open a submenu over the current menu, and switch focus */
UFUNCTION(BlueprintCallable)
void OpenChildMenu(UControllerMenuWidget* Child, bool TransitionOut=true);
UFUNCTION(BlueprintCallable)
class UControllerMenuMessageBoxWidget* CreateMessageBox(const TSubclassOf<UControllerMenuWidget> Class, const FText Message, const FText AcceptText, const FText CancelText);
virtual void NativeOnInitialized() override;
virtual FReply NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override;
virtual FReply NativeOnKeyUp(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override;
virtual FReply NativeOnMouseMove(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
virtual FReply NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
virtual void NativeOnUpPressed();
virtual void NativeOnDownPressed();
virtual void NativeOnLeftPressed();
virtual void NativeOnRightPressed();
virtual void NativeOnPreviousPressed();
virtual void NativeOnNextPressed();
virtual void NativeOnAcceptPressed();
virtual void NativeOnCancelPressed();
virtual void NativeOnPausePressed(){}
virtual void NativeOnCustomPressed(const FName& CustomAction){}
virtual void NativeOnAcceptReleased();
virtual void NativeOnCancelReleased();
uint8 bIsInteractable : 1;
uint8 bIsChildMenu : 1;
private:
void OnAxisYEvent(const float AxisValue);
void OnAxisXEvent(const float AxisValue);
void OnUpPressedEvent();
void OnDownPressedEvent();
void OnLeftPressedEvent();
void OnRightPressedEvent();
void OnPreviousPressedEvent();
void OnNextPressedEvent();
void OnAcceptPressedEvent();
void OnCancelPressedEvent();
void OnPausePressedEvent();
void OnCustomPressedEvent(const FName CustomAction);
void OnAcceptReleasedEvent();
void OnCancelReleasedEvent();
virtual void ChildMenuExitedEvent();
virtual void ChildMenuClosedEvent();
virtual void MessageBoxExitedEvent();
virtual void MessageBoxClosedEvent();
void SetNewInputDevice(const EControllerMenuInputDevice& NewInputDevice);
UFUNCTION() void OpenAnimationFinished();
UFUNCTION() void CloseAnimationFinished();
void FindParentScrollBoxRecursive(UWidget *FocusedWidget, UWidget *WidgetParent);
UControllerMenuWidget* ChildMenu = nullptr;
class UControllerMenuMessageBoxWidget* MessageBox = nullptr;
uint32 WidgetDepth = 0;
int32 FocusedWidgetIndex = 0;
TArray<UWidget*> FocusableWidgetArray;
TArray<FControllerWidgetFocusMap> WidgetFocusMapArray;
class UWidget* CancelButton = nullptr;
bool CancelConfirm = true;
TMap<UWidget*, FSlateBrush> NormalStyles;
TMap<UWidget*, FSlateBrush> HoveredStyles;
TMap<UWidget*, FSlateBrush> PressedStyles;
TMap<UWidget*, FMargin> NormalPaddings;
TMap<UWidget*, FMargin> PressedPaddings;
EControllerMenuInputDevice LastInputDevice = EControllerMenuInputDevice::None;
FVector2D MouseMovementStartPosition = FVector2D::ZeroVector;
/** Sets the movement threshold for joystick axes when moving in the menu */
float AxisMovementThreshold = 0.75;
/** Flags for when an axis has already moved and additional movements should be ignored */
uint8 bAxisYHasMoved : 1;
uint8 bAxisXHasMoved : 1;
/** Sets the distance the mouse needs to move before the menu passes control to it */
float MouseMovementThreshold = 2.0;
FInputAxisBinding AxisYBinding;
FInputAxisBinding AxisXBinding;
FInputActionBinding UpActionBinding;
FInputActionBinding DownActionBinding;
FInputActionBinding LeftActionBinding;
FInputActionBinding RightActionBinding;
FInputActionBinding PreviousActionBinding;
FInputActionBinding NextActionBinding;
FInputActionBinding AcceptPressActionBinding;
FInputActionBinding CancelPressActionBinding;
FInputActionBinding PauseActionBinding;
//FInputActionBinding CustomActionBinding;
FInputActionBinding AcceptReleaseActionBinding;
FInputActionBinding CancelReleaseActionBinding;
DECLARE_MULTICAST_DELEGATE(FOnPressedEvent);
FOnPressedEvent OnUpPressedDelegate;
FOnPressedEvent OnDownPressedDelegate;
FOnPressedEvent OnLeftPressedDelegate;
FOnPressedEvent OnRightPressedDelegate;
FOnPressedEvent OnPreviousPressedDelegate;
FOnPressedEvent OnNextPressedDelegate;
FOnPressedEvent OnAcceptPressedDelegate;
FOnPressedEvent OnCancelPressedDelegate;
FOnPressedEvent OnPausePressedDelegate;
//DECLARE_MULTICAST_DELEGATE_OneParam(FOnPressedEventOneParam, FName);
//FOnPressedEventOneParam OnCustomPressedEvent;
DECLARE_DELEGATE(FChildMenuClosedEvent);
FChildMenuClosedEvent ChildMenuExitedDelegate;
FChildMenuClosedEvent ChildMenuClosedDelegate;
TArray<FInputActionBinding> StoredPlayerActionBindings;
TArray<FInputAxisBinding> StoredPlayerAxisBindings;
};

View File

@ -0,0 +1,29 @@
/**
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
**/
#pragma once
#include "CoreMinimal.h"
#include "Widgets/Text/STextBlock.h"
/**
* A simple static text widget, altered to suit custom widgets such as UTextSpinner
*/
class SCustomTextBlock : public STextBlock
{
public:
void SetPreventDisable(bool bInPreventDisable) { this->bPreventDisable = bInPreventDisable; }
// SWidget interface
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override
{
return STextBlock::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, !this->bPreventDisable || bParentEnabled);
}
// End of SWidget interface
private:
uint8 bPreventDisable : 1;
};