Initial commit.
This commit is contained in:
commit
e6492ea0e3
20
ControllerMenu.uplugin
Normal file
20
ControllerMenu.uplugin
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
49
Source/ControllerMenu/ControllerMenu.Build.cs
Normal file
49
Source/ControllerMenu/ControllerMenu.Build.cs
Normal 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"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///
|
||||||
44
Source/ControllerMenu/Private/ControllerMenu.cpp
Normal file
44
Source/ControllerMenu/Private/ControllerMenu.cpp
Normal 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
|
||||||
@ -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
|
||||||
14
Source/ControllerMenu/Private/ControllerMenuPrivatePCH.h
Normal file
14
Source/ControllerMenu/Private/ControllerMenuPrivatePCH.h
Normal 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"
|
||||||
@ -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
|
||||||
476
Source/ControllerMenu/Private/Widgets/Components/TextSpinner.cpp
Normal file
476
Source/ControllerMenu/Private/Widgets/Components/TextSpinner.cpp
Normal 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
|
||||||
@ -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();
|
||||||
|
}
|
||||||
1408
Source/ControllerMenu/Private/Widgets/ControllerMenuWidget.cpp
Normal file
1408
Source/ControllerMenu/Private/Widgets/ControllerMenuWidget.cpp
Normal file
File diff suppressed because it is too large
Load Diff
147
Source/ControllerMenu/Public/ControllerMenuGlobalSettings.h
Normal file
147
Source/ControllerMenu/Public/ControllerMenuGlobalSettings.h
Normal 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
|
||||||
|
};
|
||||||
@ -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");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@ -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;
|
||||||
|
};
|
||||||
@ -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;
|
||||||
|
};
|
||||||
335
Source/ControllerMenu/Public/Widgets/Components/TextSpinner.h
Normal file
335
Source/ControllerMenu/Public/Widgets/Components/TextSpinner.h
Normal 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;
|
||||||
|
};
|
||||||
@ -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;
|
||||||
|
};
|
||||||
346
Source/ControllerMenu/Public/Widgets/ControllerMenuWidget.h
Normal file
346
Source/ControllerMenu/Public/Widgets/ControllerMenuWidget.h
Normal 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;
|
||||||
|
};
|
||||||
@ -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;
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user