1409 lines
46 KiB
C++
1409 lines
46 KiB
C++
/**
|
|
* Copyright ©2019 Batty Bovine Productions, LLC. All Rights Reserved.
|
|
**/
|
|
|
|
#include "ControllerMenuWidget.h"
|
|
|
|
#include "ConstructorHelpers.h"
|
|
#include "ContentWidget.h"
|
|
#include "IControllerMenu_Implementation.h"
|
|
#include "PanelWidget.h"
|
|
|
|
#include "Blueprint/WidgetTree.h"
|
|
#include "Components/Button.h"
|
|
#include "Components/ComboBox.h"
|
|
#include "Components/GridPanel.h"
|
|
#include "Components/GridSlot.h"
|
|
#include "Components/ScrollBox.h"
|
|
#include "Components/TextSpinner.h"
|
|
#include "GameFramework/GameModeBase.h"
|
|
#include "GameFramework/PlayerInput.h"
|
|
#include "Kismet/GameplayStatics.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
#include "Widgets/ControllerMenuMessageBoxWidget.h"
|
|
|
|
|
|
UControllerMenuWidget::UControllerMenuWidget(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
this->bIsFocusable = false;
|
|
this->bIsChildMenu = false;
|
|
|
|
if (GConfig)
|
|
{
|
|
GConfig->GetFloat(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("AxisMovementThreshold"), this->AxisMovementThreshold, GGameIni);
|
|
GConfig->GetFloat(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("MouseMovementThreshold"), this->MouseMovementThreshold, GGameIni);
|
|
GConfig->GetBool(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("CancelConfirm"), this->CancelConfirm, GGameIni);
|
|
}
|
|
|
|
this->bAxisYHasMoved = this->bAxisXHasMoved = false;
|
|
|
|
//this->InputComponent = CreateDefaultSubobject<UInputComponent>(TEXT("MenuInput"));
|
|
//this->InputComponent->RegisterComponent();
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::NativeOnInitialized()
|
|
{
|
|
Super::NativeOnInitialized();
|
|
|
|
// HACK: Enable focus for this widget, focus, then reset focus setting.
|
|
// This allows us to keep focus inside the widget while preventing Slate
|
|
// from using its own input handling, and also bypasses a warning about
|
|
// setting focus to an unfocusable widget.
|
|
this->bIsFocusable = true;
|
|
this->SetKeyboardFocus();
|
|
this->bIsFocusable = false;
|
|
|
|
// Bind both the close and open animation events now
|
|
if (this->OpenAnimation)
|
|
{
|
|
FWidgetAnimationDynamicEvent OpenEvent;
|
|
OpenEvent.BindDynamic(this, &UControllerMenuWidget::OpenAnimationFinished);
|
|
this->BindToAnimationFinished(this->OpenAnimation, OpenEvent);
|
|
}
|
|
if (this->CloseAnimation)
|
|
{
|
|
FWidgetAnimationDynamicEvent CloseEvent;
|
|
CloseEvent.BindDynamic(this, &UControllerMenuWidget::CloseAnimationFinished);
|
|
this->BindToAnimationFinished(this->CloseAnimation, CloseEvent);
|
|
}
|
|
|
|
this->InitializeMenuActions();
|
|
}
|
|
|
|
FReply UControllerMenuWidget::NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent)
|
|
{
|
|
if (InKeyEvent.GetKey().GetDisplayName().ToString().StartsWith("Gamepad"))
|
|
{
|
|
if (this->LastInputDevice != EControllerMenuInputDevice::Controller)
|
|
{
|
|
this->SetNewInputDevice(EControllerMenuInputDevice::Controller);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this->LastInputDevice != EControllerMenuInputDevice::Keyboard)
|
|
{
|
|
this->SetNewInputDevice(EControllerMenuInputDevice::Keyboard);
|
|
}
|
|
}
|
|
|
|
//FReply Reply = Super::NativeOnKeyDown(InGeometry, InKeyEvent);
|
|
//this->ResetUserFocus();
|
|
//return Reply;
|
|
return Super::NativeOnKeyDown(InGeometry, InKeyEvent);
|
|
}
|
|
|
|
FReply UControllerMenuWidget::NativeOnKeyUp(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent)
|
|
{
|
|
if (InKeyEvent.GetKey().GetDisplayName().ToString().StartsWith("Gamepad"))
|
|
{
|
|
if (this->LastInputDevice != EControllerMenuInputDevice::Controller)
|
|
{
|
|
this->SetNewInputDevice(EControllerMenuInputDevice::Controller);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this->LastInputDevice != EControllerMenuInputDevice::Keyboard)
|
|
{
|
|
this->SetNewInputDevice(EControllerMenuInputDevice::Keyboard);
|
|
}
|
|
}
|
|
|
|
//FReply Reply = Super::NativeOnKeyUp(InGeometry, InKeyEvent);
|
|
//this->ResetUserFocus();
|
|
//return Reply;
|
|
return Super::NativeOnKeyUp(InGeometry, InKeyEvent);
|
|
}
|
|
|
|
FReply UControllerMenuWidget::NativeOnMouseMove(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
|
|
{
|
|
if (this->LastInputDevice != EControllerMenuInputDevice::Mouse)
|
|
{
|
|
if (this->MouseMovementStartPosition == FVector2D::ZeroVector)
|
|
{
|
|
this->MouseMovementStartPosition = InMouseEvent.GetLastScreenSpacePosition();
|
|
}
|
|
const float MouseMovementDistance = (InMouseEvent.GetScreenSpacePosition() - this->MouseMovementStartPosition).Size();
|
|
if (MouseMovementDistance >= this->MouseMovementThreshold)
|
|
{
|
|
this->ClearWidgetFocus();
|
|
this->SetNewInputDevice(EControllerMenuInputDevice::Mouse);
|
|
}
|
|
}
|
|
|
|
return Super::NativeOnMouseMove(InGeometry, InMouseEvent);
|
|
}
|
|
|
|
FReply UControllerMenuWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
|
|
{
|
|
if (this->LastInputDevice != EControllerMenuInputDevice::Mouse)
|
|
{
|
|
this->SetNewInputDevice(EControllerMenuInputDevice::Mouse);
|
|
}
|
|
|
|
//FReply Reply = Super::NativeOnMouseMove(InGeometry, InMouseEvent);
|
|
//this->ResetUserFocus();
|
|
//return Reply;
|
|
return Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
|
|
}
|
|
|
|
FReply UControllerMenuWidget::NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
|
|
{
|
|
if (this->LastInputDevice != EControllerMenuInputDevice::Mouse)
|
|
{
|
|
this->SetNewInputDevice(EControllerMenuInputDevice::Mouse);
|
|
}
|
|
|
|
//FReply Reply = Super::NativeOnMouseMove(InGeometry, InMouseEvent);
|
|
//this->ResetUserFocus();
|
|
//return Reply;
|
|
return Super::NativeOnMouseButtonUp(InGeometry, InMouseEvent);
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::OpenMenu_Implementation(int32 Depth)
|
|
{
|
|
if (!this->IsInViewport())
|
|
{
|
|
this->AddToViewport(Depth);
|
|
this->WidgetDepth = Depth;
|
|
}
|
|
|
|
this->PlayAnimation(this->OpenAnimation);
|
|
|
|
// Enable menu actions after menu is opened
|
|
this->BindMenuActions();
|
|
|
|
this->OnOpenOverride();
|
|
|
|
this->MenuOpened();
|
|
this->OnMenuOpened.Broadcast();
|
|
}
|
|
|
|
void UControllerMenuWidget::OpenAnimationFinished()
|
|
{
|
|
this->bIsInteractable = true;
|
|
if (this->FocusableWidgetArray.Num() > 0)
|
|
{
|
|
this->SetWidgetFocus(this->FocusableWidgetArray[0]);
|
|
}
|
|
|
|
this->MenuShown();
|
|
this->OnMenuShown.Broadcast();
|
|
}
|
|
|
|
void UControllerMenuWidget::OpenChildMenu(UControllerMenuWidget *Child, bool TransitionOut)
|
|
{
|
|
if (Child)
|
|
{
|
|
this->UnbindMenuActions();
|
|
|
|
this->ChildMenu = Child;
|
|
this->ChildMenu->bIsChildMenu = true;
|
|
this->ChildMenu->OpenMenu(this->WidgetDepth+1);
|
|
this->ChildMenu->ChildMenuExitedDelegate.BindUObject(this, &UControllerMenuWidget::ChildMenuExitedEvent);
|
|
this->ChildMenu->ChildMenuClosedDelegate.BindUObject(this, &UControllerMenuWidget::ChildMenuClosedEvent);
|
|
this->ChildMenuOpened();
|
|
this->bIsInteractable = false;
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::ChildMenuExitedEvent()
|
|
{
|
|
// Switch the pressed button back to the hovered style when coming back to this menu
|
|
this->SetWidgetFocus(this->GetFocusedWidget());
|
|
|
|
this->ChildMenuExited();
|
|
}
|
|
|
|
void UControllerMenuWidget::ChildMenuClosedEvent()
|
|
{
|
|
this->bIsInteractable = true;
|
|
this->ChildMenu->RemoveFromParent();
|
|
this->ChildMenu = nullptr;
|
|
|
|
this->BindMenuActions();
|
|
|
|
this->ChildMenuClosed();
|
|
}
|
|
|
|
void UControllerMenuWidget::ExitMenu_Implementation()
|
|
{
|
|
this->ClearWidgetFocus();
|
|
|
|
this->PlayAnimation(this->CloseAnimation);
|
|
|
|
this->OnCloseOverride();
|
|
|
|
this->MenuExited();
|
|
this->OnMenuExited.Broadcast();
|
|
|
|
this->ChildMenuExitedDelegate.ExecuteIfBound();
|
|
}
|
|
|
|
void UControllerMenuWidget::CloseAnimationFinished()
|
|
{
|
|
// Remove menu actions after closing the menu
|
|
this->UnbindMenuActions();
|
|
|
|
this->RemoveFromParent();
|
|
this->bIsInteractable = false;
|
|
|
|
this->MenuClosed();
|
|
this->OnMenuClosed.Broadcast();
|
|
|
|
this->ChildMenuClosedDelegate.ExecuteIfBound();
|
|
}
|
|
|
|
|
|
UControllerMenuMessageBoxWidget* UControllerMenuWidget::CreateMessageBox(const TSubclassOf<UControllerMenuWidget> Class, const FText Message, const FText AcceptText, const FText CancelText)
|
|
{
|
|
this->MessageBox = CreateWidget<UControllerMenuMessageBoxWidget>(this->GetGameInstance(), Class);
|
|
if (!this->MessageBox)
|
|
{
|
|
UE_LOG(ControllerMenuLog, Error, TEXT("Message Box could not be loaded"));
|
|
return nullptr;
|
|
}
|
|
|
|
this->UnbindMenuActions();
|
|
|
|
this->MessageBox->bIsChildMenu = true;
|
|
this->MessageBox->SetMessageBody(Message);
|
|
this->MessageBox->SetAcceptText(AcceptText);
|
|
this->MessageBox->SetCancelText(CancelText);
|
|
this->MessageBox->OpenMenu(this->WidgetDepth + 1);
|
|
this->MessageBox->ChildMenuExitedDelegate.BindUObject(this, &UControllerMenuWidget::MessageBoxExitedEvent);
|
|
this->MessageBox->ChildMenuClosedDelegate.BindUObject(this, &UControllerMenuWidget::MessageBoxClosedEvent);
|
|
this->bIsInteractable = false;
|
|
this->MessageBoxOpened();
|
|
return this->MessageBox;
|
|
}
|
|
|
|
void UControllerMenuWidget::MessageBoxExitedEvent()
|
|
{
|
|
// Switch the pressed button back to the hovered style when coming back to this menu
|
|
this->SetWidgetFocus(this->GetFocusedWidget());
|
|
|
|
this->MessageBoxExited();
|
|
}
|
|
|
|
void UControllerMenuWidget::MessageBoxClosedEvent()
|
|
{
|
|
this->bIsInteractable = true;
|
|
this->MessageBox->RemoveFromParent();
|
|
this->MessageBox = nullptr;
|
|
|
|
this->BindMenuActions();
|
|
|
|
this->MessageBoxClosed();
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::AddGridPanelWidgets(UGridPanel* GridPanel)
|
|
{
|
|
const TArray<UPanelSlot*> Slots = GridPanel->GetSlots();
|
|
|
|
// Find the number of rows and columns in this grid panel
|
|
int32 MaxColumn = 0;
|
|
int32 MaxRow = 0;
|
|
for (UPanelSlot* LocalSlot : Slots)
|
|
{
|
|
if (UGridSlot* GridSlot = Cast<UGridSlot>(LocalSlot))
|
|
{
|
|
if (GridSlot->GetColumn() > MaxColumn)
|
|
{
|
|
MaxColumn = GridSlot->GetColumn();
|
|
}
|
|
if (GridSlot->GetRow() > MaxRow)
|
|
{
|
|
MaxRow = GridSlot->GetRow();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create an array of widgets for us to fill out
|
|
UWidget*** OrderedWidgetArray = new UWidget**[MaxRow+1];
|
|
for(int32 i = 0; i <= MaxRow; i++)
|
|
{
|
|
OrderedWidgetArray[i] = new UWidget*[MaxColumn+1];
|
|
for (int32 j = 0; j <= MaxColumn; j++)
|
|
{
|
|
OrderedWidgetArray[i][j] = nullptr;
|
|
}
|
|
}
|
|
//TArray< TArray<UWidget*> > OrderedWidgetArray;
|
|
//OrderedWidgetArray.SetNum(MaxColumn);
|
|
//for(int32 i = 0; i < MaxColumn; i++)
|
|
//{
|
|
// OrderedWidgetArray[i].SetNumZeroed(MaxRow);
|
|
//}
|
|
|
|
// Add the widgets to the array in the appropriate slots
|
|
const TArray<UWidget*> Widgets = GridPanel->GetAllChildren();
|
|
for (UWidget* Widget : Widgets)
|
|
{
|
|
UGridSlot* GridSlot = Cast<UGridSlot>(Widget->Slot);
|
|
OrderedWidgetArray[GridSlot->GetRow()][GridSlot->GetColumn()] = Widget;
|
|
}
|
|
|
|
// Finally, add each widget to the focus map
|
|
for (int Row = 0; Row <= MaxRow; Row++)
|
|
{
|
|
UWidget** ColumnArray = OrderedWidgetArray[Row];
|
|
for (int Column = 0; Column <= MaxColumn; Column++)
|
|
{
|
|
UWidget* Widget = ColumnArray[Column];
|
|
if (Widget)
|
|
{
|
|
FControllerWidgetFocusMap FocusMap;
|
|
{
|
|
if (Row > 0)
|
|
{
|
|
UWidget* Up = OrderedWidgetArray[Row - 1][Column];
|
|
if (Cast<ITakesControllerFocus>(Up) || Cast<UButton>(Up))
|
|
{
|
|
FocusMap.Up = Up;
|
|
}
|
|
}
|
|
|
|
if (Row < MaxRow)
|
|
{
|
|
UWidget* Down = OrderedWidgetArray[Row + 1][Column];
|
|
if (Cast<ITakesControllerFocus>(Down) || Cast<UButton>(Down))
|
|
{
|
|
FocusMap.Down = Down;
|
|
}
|
|
}
|
|
|
|
if (Column > 0)
|
|
{
|
|
UWidget* Left = ColumnArray[Column - 1];
|
|
if (Cast<ITakesControllerFocus>(Left) || Cast<UButton>(Left))
|
|
{
|
|
FocusMap.Left = Left;
|
|
}
|
|
}
|
|
|
|
if (Column < MaxColumn)
|
|
{
|
|
UWidget* Right = ColumnArray[Column + 1];
|
|
if (Cast<ITakesControllerFocus>(Right) || Cast<UButton>(Right))
|
|
{
|
|
FocusMap.Right = Right;
|
|
}
|
|
}
|
|
|
|
if ((((MaxRow+1) * Column) + Row) > 0)
|
|
{
|
|
if (Row > 0)
|
|
{
|
|
UWidget* Previous = OrderedWidgetArray[Row - 1][Column];
|
|
if (Cast<ITakesControllerFocus>(Previous) || Cast<UButton>(Previous))
|
|
{
|
|
FocusMap.Previous = Previous;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UWidget* Previous = OrderedWidgetArray[Row][Column - 1];
|
|
if (Cast<ITakesControllerFocus>(Previous) || Cast<UButton>(Previous))
|
|
{
|
|
FocusMap.Previous = Previous;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UWidget* Previous = OrderedWidgetArray[MaxRow][MaxColumn];
|
|
if (Cast<ITakesControllerFocus>(Previous) || Cast<UButton>(Previous))
|
|
{
|
|
FocusMap.Previous = Previous;
|
|
}
|
|
}
|
|
|
|
if ((((MaxRow+1) * Column) + Row) < ((MaxRow+1) * (MaxColumn+1)) - 1)
|
|
{
|
|
if (Row < MaxRow)
|
|
{
|
|
UWidget* Next = OrderedWidgetArray[Row + 1][Column];
|
|
if (Cast<ITakesControllerFocus>(Next) || Cast<UButton>(Next))
|
|
{
|
|
FocusMap.Next = Next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UWidget* Next = OrderedWidgetArray[0][Column + 1];
|
|
if (Cast<ITakesControllerFocus>(Next) || Cast<UButton>(Next))
|
|
{
|
|
FocusMap.Next = Next;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UWidget* Next = OrderedWidgetArray[0][0];
|
|
if (Cast<ITakesControllerFocus>(Next) || Cast<UButton>(Next))
|
|
{
|
|
FocusMap.Next = Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ITakesControllerFocus* ControllerWidget = Cast<ITakesControllerFocus>(Widget))
|
|
{
|
|
this->FocusableWidgetArray.Add(Widget);
|
|
this->WidgetFocusMapArray.Add(FocusMap);
|
|
this->NormalStyles.Emplace(Widget, ControllerWidget->Execute_GetNormalStyle(Widget));
|
|
this->HoveredStyles.Emplace(Widget, ControllerWidget->Execute_GetHoveredStyle(Widget));
|
|
this->PressedStyles.Emplace(Widget, ControllerWidget->Execute_GetPressedStyle(Widget));
|
|
this->NormalPaddings.Emplace(Widget, ControllerWidget->Execute_GetNormalPadding(Widget));
|
|
this->PressedPaddings.Emplace(Widget, ControllerWidget->Execute_GetPressedPadding(Widget));
|
|
ControllerWidget->Execute_SetFocusable(Widget, false);
|
|
}
|
|
else if (UButton* Button = Cast<UButton>(Widget))
|
|
{
|
|
this->FocusableWidgetArray.Add(Widget);
|
|
this->WidgetFocusMapArray.Add(FocusMap);
|
|
this->NormalStyles.Emplace(Widget, Button->WidgetStyle.Normal);
|
|
this->HoveredStyles.Emplace(Widget, Button->WidgetStyle.Hovered);
|
|
this->PressedStyles.Emplace(Widget, Button->WidgetStyle.Pressed);
|
|
this->NormalPaddings.Emplace(Widget, Button->WidgetStyle.NormalPadding);
|
|
this->PressedPaddings.Emplace(Widget, Button->WidgetStyle.PressedPadding);
|
|
Button->IsFocusable = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::AddFocusableWidgetCustom(UWidget* Widget, UWidget* Up, UWidget* Down, UWidget* Left, UWidget* Right, UWidget* Previous, UWidget* Next)
|
|
{
|
|
this->FocusableWidgetArray.Add(Widget);
|
|
|
|
FControllerWidgetFocusMap WidgetFocusMap;
|
|
WidgetFocusMap.Up = Up;
|
|
WidgetFocusMap.Down = Down;
|
|
WidgetFocusMap.Left = Left;
|
|
WidgetFocusMap.Right = Right;
|
|
WidgetFocusMap.Previous = Previous;
|
|
WidgetFocusMap.Next = Next;
|
|
this->WidgetFocusMapArray.Add(WidgetFocusMap);
|
|
|
|
if (ITakesControllerFocus* ControllerWidget = Cast<ITakesControllerFocus>(Widget))
|
|
{
|
|
this->NormalStyles.Emplace(Widget, ControllerWidget->Execute_GetNormalStyle(Widget));
|
|
this->HoveredStyles.Emplace(Widget, ControllerWidget->Execute_GetHoveredStyle(Widget));
|
|
this->PressedStyles.Emplace(Widget, ControllerWidget->Execute_GetPressedStyle(Widget));
|
|
this->NormalPaddings.Emplace(Widget, ControllerWidget->Execute_GetNormalPadding(Widget));
|
|
this->PressedPaddings.Emplace(Widget, ControllerWidget->Execute_GetPressedPadding(Widget));
|
|
ControllerWidget->Execute_SetFocusable(Widget, false);
|
|
}
|
|
else if (UButton* Button = Cast<UButton>(Widget))
|
|
{
|
|
this->NormalStyles.Emplace(Widget, Button->WidgetStyle.Normal);
|
|
this->HoveredStyles.Emplace(Widget, Button->WidgetStyle.Hovered);
|
|
this->PressedStyles.Emplace(Widget, Button->WidgetStyle.Pressed);
|
|
this->NormalPaddings.Emplace(Widget, Button->WidgetStyle.NormalPadding);
|
|
this->PressedPaddings.Emplace(Widget, Button->WidgetStyle.PressedPadding);
|
|
Button->IsFocusable = false;
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::AddVerticalFocusableWidget(UWidget* Widget, UWidget* Left, UWidget* Right)
|
|
{
|
|
FControllerWidgetFocusMap WidgetFocusMap;
|
|
const int32 ArraySize = this->FocusableWidgetArray.Num();
|
|
if (ArraySize > 0)
|
|
{
|
|
WidgetFocusMap.Up = WidgetFocusMap.Previous = this->FocusableWidgetArray[ArraySize - 1];
|
|
WidgetFocusMap.Down = WidgetFocusMap.Next = this->FocusableWidgetArray[0];
|
|
this->WidgetFocusMapArray[0].Up = this->WidgetFocusMapArray[0].Previous = Widget;
|
|
this->WidgetFocusMapArray[ArraySize - 1].Down = this->WidgetFocusMapArray[ArraySize - 1].Next = Widget;
|
|
}
|
|
WidgetFocusMap.Left = Left;
|
|
WidgetFocusMap.Right = Right;
|
|
this->FocusableWidgetArray.Add(Widget);
|
|
this->WidgetFocusMapArray.Add(WidgetFocusMap);
|
|
|
|
if (ITakesControllerFocus* ControllerWidget = Cast<ITakesControllerFocus>(Widget))
|
|
{
|
|
this->NormalStyles.Emplace(Widget, ControllerWidget->Execute_GetNormalStyle(Widget));
|
|
this->HoveredStyles.Emplace(Widget, ControllerWidget->Execute_GetHoveredStyle(Widget));
|
|
this->PressedStyles.Emplace(Widget, ControllerWidget->Execute_GetPressedStyle(Widget));
|
|
this->NormalPaddings.Emplace(Widget, ControllerWidget->Execute_GetNormalPadding(Widget));
|
|
this->PressedPaddings.Emplace(Widget, ControllerWidget->Execute_GetPressedPadding(Widget));
|
|
ControllerWidget->Execute_SetFocusable(Widget, false);
|
|
}
|
|
else if (UButton* Button = Cast<UButton>(Widget))
|
|
{
|
|
this->NormalStyles.Emplace(Widget, Button->WidgetStyle.Normal);
|
|
this->HoveredStyles.Emplace(Widget, Button->WidgetStyle.Hovered);
|
|
this->PressedStyles.Emplace(Widget, Button->WidgetStyle.Pressed);
|
|
this->NormalPaddings.Emplace(Widget, Button->WidgetStyle.NormalPadding);
|
|
this->PressedPaddings.Emplace(Widget, Button->WidgetStyle.PressedPadding);
|
|
Button->IsFocusable = false;
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::AddHorizontalFocusableWidget(UWidget* Widget, UWidget* Up, UWidget* Down)
|
|
{
|
|
FControllerWidgetFocusMap WidgetFocusMap;
|
|
const int32 ArraySize = this->FocusableWidgetArray.Num();
|
|
if (ArraySize > 0)
|
|
{
|
|
WidgetFocusMap.Left = WidgetFocusMap.Previous = this->FocusableWidgetArray[ArraySize - 1];
|
|
WidgetFocusMap.Right = WidgetFocusMap.Next = this->FocusableWidgetArray[0];
|
|
this->WidgetFocusMapArray[0].Left = this->WidgetFocusMapArray[0].Previous = Widget;
|
|
this->WidgetFocusMapArray[ArraySize - 1].Right = this->WidgetFocusMapArray[ArraySize - 1].Next = Widget;
|
|
}
|
|
WidgetFocusMap.Up = Up;
|
|
WidgetFocusMap.Down = Down;
|
|
this->FocusableWidgetArray.Add(Widget);
|
|
this->WidgetFocusMapArray.Add(WidgetFocusMap);
|
|
|
|
if (ITakesControllerFocus* ControllerWidget = Cast<ITakesControllerFocus>(Widget))
|
|
{
|
|
this->NormalStyles.Emplace(Widget, ControllerWidget->Execute_GetNormalStyle(Widget));
|
|
this->HoveredStyles.Emplace(Widget, ControllerWidget->Execute_GetHoveredStyle(Widget));
|
|
this->PressedStyles.Emplace(Widget, ControllerWidget->Execute_GetPressedStyle(Widget));
|
|
this->NormalPaddings.Emplace(Widget, ControllerWidget->Execute_GetNormalPadding(Widget));
|
|
this->PressedPaddings.Emplace(Widget, ControllerWidget->Execute_GetPressedPadding(Widget));
|
|
ControllerWidget->Execute_SetFocusable(Widget, false);
|
|
}
|
|
else if (UButton* Button = Cast<UButton>(Widget))
|
|
{
|
|
this->NormalStyles.Emplace(Widget, Button->WidgetStyle.Normal);
|
|
this->HoveredStyles.Emplace(Widget, Button->WidgetStyle.Hovered);
|
|
this->PressedStyles.Emplace(Widget, Button->WidgetStyle.Pressed);
|
|
this->NormalPaddings.Emplace(Widget, Button->WidgetStyle.NormalPadding);
|
|
this->PressedPaddings.Emplace(Widget, Button->WidgetStyle.PressedPadding);
|
|
Button->IsFocusable = false;
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::EditWidgetFocus(UWidget* Widget, UWidget* Up, UWidget* Down, UWidget* Left, UWidget* Right, UWidget* Previous, UWidget* Next)
|
|
{
|
|
const int32 WidgetIndex = this->FocusableWidgetArray.Find(Widget);
|
|
if (WidgetIndex != INDEX_NONE)
|
|
{
|
|
FControllerWidgetFocusMap& Map = this->WidgetFocusMapArray[WidgetIndex];
|
|
Map.Up = Up ? Up : Map.Up;
|
|
Map.Down = Down ? Down : Map.Down;
|
|
Map.Left = Left ? Left : Map.Left;
|
|
Map.Right = Right ? Right : Map.Right;
|
|
Map.Previous = Previous ? Previous : Map.Previous;
|
|
Map.Next = Next ? Next : Map.Next;
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::SetCancelButton(UWidget* Button)
|
|
{
|
|
this->CancelButton = Button;
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::InitializeMenuActions()
|
|
{
|
|
if (GConfig)
|
|
{
|
|
FString AxisYAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("AxisYAction"), AxisYAction, GGameIni);
|
|
if (AxisYAction.IsEmpty())
|
|
{
|
|
FString UpAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("UpAction"), UpAction, GGameIni);
|
|
this->UpActionBinding = FInputActionBinding(FName(*UpAction), EInputEvent::IE_Pressed);
|
|
this->UpActionBinding.bExecuteWhenPaused = true;
|
|
this->UpActionBinding.bConsumeInput = true;
|
|
this->UpActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnUpPressedEvent);
|
|
|
|
FString DownAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("DownAction"), DownAction, GGameIni);
|
|
this->DownActionBinding = FInputActionBinding(FName(*DownAction), EInputEvent::IE_Pressed);
|
|
this->DownActionBinding.bExecuteWhenPaused = true;
|
|
this->DownActionBinding.bConsumeInput = true;
|
|
this->DownActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnDownPressedEvent);
|
|
}
|
|
else
|
|
{
|
|
this->AxisYBinding = FInputAxisBinding(FName(*AxisYAction));
|
|
this->AxisYBinding.bExecuteWhenPaused = true;
|
|
this->AxisYBinding.bConsumeInput = true;
|
|
this->AxisYBinding.AxisDelegate.BindDelegate(this, &UControllerMenuWidget::OnAxisYEvent);
|
|
}
|
|
|
|
FString AxisXAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("AxisXAction"), AxisXAction, GGameIni);
|
|
if (AxisXAction.IsEmpty())
|
|
{
|
|
FString LeftAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("LeftAction"), LeftAction, GGameIni);
|
|
this->LeftActionBinding = FInputActionBinding(FName(*LeftAction), EInputEvent::IE_Pressed);
|
|
this->LeftActionBinding.bExecuteWhenPaused = true;
|
|
this->LeftActionBinding.bConsumeInput = true;
|
|
this->LeftActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnLeftPressedEvent);
|
|
|
|
FString RightAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("RightAction"), RightAction, GGameIni);
|
|
this->RightActionBinding = FInputActionBinding(FName(*RightAction), EInputEvent::IE_Pressed);
|
|
this->RightActionBinding.bExecuteWhenPaused = true;
|
|
this->RightActionBinding.bConsumeInput = true;
|
|
this->RightActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnRightPressedEvent);
|
|
}
|
|
else
|
|
{
|
|
this->AxisXBinding = FInputAxisBinding(FName(*AxisXAction));
|
|
this->AxisXBinding.bExecuteWhenPaused = true;
|
|
this->AxisXBinding.bConsumeInput = true;
|
|
this->AxisXBinding.AxisDelegate.BindDelegate(this, &UControllerMenuWidget::OnAxisXEvent);
|
|
}
|
|
|
|
FString PreviousAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("PreviousAction"), PreviousAction, GGameIni);
|
|
this->PreviousActionBinding = FInputActionBinding(FName(*PreviousAction), EInputEvent::IE_Pressed);
|
|
this->PreviousActionBinding.bExecuteWhenPaused = true;
|
|
this->PreviousActionBinding.bConsumeInput = true;
|
|
this->PreviousActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnPreviousPressedEvent);
|
|
|
|
FString NextAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("NextAction"), NextAction, GGameIni);
|
|
this->NextActionBinding = FInputActionBinding(FName(*NextAction), EInputEvent::IE_Pressed);
|
|
this->NextActionBinding.bExecuteWhenPaused = true;
|
|
this->NextActionBinding.bConsumeInput = true;
|
|
this->NextActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnNextPressedEvent);
|
|
|
|
FString AcceptAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("AcceptAction"), AcceptAction, GGameIni);
|
|
const FName AcceptActionName(*AcceptAction);
|
|
this->AcceptPressActionBinding = FInputActionBinding(AcceptActionName, EInputEvent::IE_Pressed);
|
|
this->AcceptPressActionBinding.bExecuteWhenPaused = true;
|
|
this->AcceptPressActionBinding.bConsumeInput = true;
|
|
this->AcceptPressActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnAcceptPressedEvent);
|
|
this->AcceptReleaseActionBinding = FInputActionBinding(AcceptActionName, EInputEvent::IE_Released);
|
|
this->AcceptReleaseActionBinding.bExecuteWhenPaused = true;
|
|
this->AcceptReleaseActionBinding.bConsumeInput = true;
|
|
this->AcceptReleaseActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnAcceptReleasedEvent);
|
|
|
|
FString CancelAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("CancelAction"), CancelAction, GGameIni);
|
|
const FName CancelActionName(*CancelAction);
|
|
this->CancelPressActionBinding = FInputActionBinding(CancelActionName, EInputEvent::IE_Pressed);
|
|
this->CancelPressActionBinding.bExecuteWhenPaused = true;
|
|
this->CancelPressActionBinding.bConsumeInput = true;
|
|
this->CancelPressActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnCancelPressedEvent);
|
|
this->CancelReleaseActionBinding = FInputActionBinding(CancelActionName, EInputEvent::IE_Released);
|
|
this->CancelReleaseActionBinding.bExecuteWhenPaused = true;
|
|
this->CancelReleaseActionBinding.bConsumeInput = true;
|
|
this->CancelReleaseActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnCancelReleasedEvent);
|
|
|
|
FString PauseAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("PauseAction"), PauseAction, GGameIni);
|
|
this->PauseActionBinding = FInputActionBinding(FName(*PauseAction), EInputEvent::IE_Pressed);
|
|
this->PauseActionBinding.bExecuteWhenPaused = true;
|
|
this->PauseActionBinding.bConsumeInput = true;
|
|
this->PauseActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnPausePressedEvent);
|
|
|
|
//for (const FName CustomAction : this->CustomActions)
|
|
//{
|
|
// this->CustomActionBinding = FInputActionBinding(CustomAction, EInputEvent::IE_Pressed);
|
|
// this->CustomActionBinding.bExecuteWhenPaused = true;
|
|
// this->CustomActionBinding.bConsumeInput = false;
|
|
// this->CustomActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnCustomPressedEvent, CustomAction);
|
|
//}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::BindMenuActions()
|
|
{
|
|
if (!this->InputComponent)
|
|
{
|
|
this->InitializeInputComponent();
|
|
if (!this->InputComponent)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (this->AxisYBinding.AxisName.IsNone())
|
|
{
|
|
this->InputComponent->AddActionBinding(this->UpActionBinding);
|
|
this->InputComponent->AddActionBinding(this->DownActionBinding);
|
|
}
|
|
else
|
|
{
|
|
this->InputComponent->AxisBindings.Emplace(this->AxisYBinding);
|
|
}
|
|
|
|
if (this->AxisXBinding.AxisName.IsNone())
|
|
{
|
|
this->InputComponent->AddActionBinding(this->LeftActionBinding);
|
|
this->InputComponent->AddActionBinding(this->RightActionBinding);
|
|
}
|
|
else
|
|
{
|
|
this->InputComponent->AxisBindings.Emplace(this->AxisXBinding);
|
|
}
|
|
|
|
this->InputComponent->AddActionBinding(this->PreviousActionBinding);
|
|
this->InputComponent->AddActionBinding(this->NextActionBinding);
|
|
this->InputComponent->AddActionBinding(this->AcceptPressActionBinding);
|
|
this->InputComponent->AddActionBinding(this->AcceptReleaseActionBinding);
|
|
this->InputComponent->AddActionBinding(this->CancelPressActionBinding);
|
|
this->InputComponent->AddActionBinding(this->CancelReleaseActionBinding);
|
|
this->InputComponent->AddActionBinding(this->PauseActionBinding);
|
|
|
|
//for (const FName CustomAction : this->CustomActions)
|
|
//{
|
|
// this->InputComponent->AddActionBinding(this->CustomActionBinding);
|
|
//}
|
|
}
|
|
|
|
void UControllerMenuWidget::UnbindMenuActions()
|
|
{
|
|
APlayerController* Controller = this->GetOwningPlayer();
|
|
if (Controller && GConfig)
|
|
{
|
|
FString AxisYAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("AxisYAction"), AxisYAction, GGameIni);
|
|
if (AxisYAction.IsEmpty())
|
|
{
|
|
FString UpAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("UpAction"), UpAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*UpAction, EInputEvent::IE_Pressed);
|
|
|
|
FString DownAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("DownAction"), DownAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*DownAction, EInputEvent::IE_Pressed);
|
|
}
|
|
else
|
|
{
|
|
const int32 LastBinding = this->InputComponent->AxisBindings.Num() - 1;
|
|
for (int32 i = LastBinding; i >= 0; i--)
|
|
{
|
|
FInputAxisBinding &Binding = this->InputComponent->AxisBindings[i];
|
|
if ((Binding.AxisName == this->AxisYBinding.AxisName) &&
|
|
(Binding.AxisDelegate.GetDelegateForManualSet().GetHandle() == this->AxisYBinding.AxisDelegate.GetDelegateForManualSet().GetHandle()))
|
|
{
|
|
this->InputComponent->AxisBindings.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
FString AxisXAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("AxisXAction"), AxisXAction, GGameIni);
|
|
if (AxisXAction.IsEmpty())
|
|
{
|
|
FString LeftAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("LeftAction"), LeftAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*LeftAction, EInputEvent::IE_Pressed);
|
|
|
|
FString RightAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("RightAction"), RightAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*RightAction, EInputEvent::IE_Pressed);
|
|
}
|
|
else
|
|
{
|
|
const int32 LastBinding = this->InputComponent->AxisBindings.Num() - 1;
|
|
for (int32 i = LastBinding; i >= 0; i--)
|
|
{
|
|
FInputAxisBinding &Binding = this->InputComponent->AxisBindings[i];
|
|
if ((Binding.AxisName == this->AxisXBinding.AxisName) &&
|
|
(Binding.AxisDelegate.GetDelegateForManualSet().GetHandle() == this->AxisXBinding.AxisDelegate.GetDelegateForManualSet().GetHandle()))
|
|
{
|
|
this->InputComponent->AxisBindings.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
FString PreviousAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("PreviousAction"), PreviousAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*PreviousAction, EInputEvent::IE_Pressed);
|
|
|
|
FString NextAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("NextAction"), NextAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*NextAction, EInputEvent::IE_Pressed);
|
|
|
|
FString AcceptAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("AcceptAction"), AcceptAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*AcceptAction, EInputEvent::IE_Pressed);
|
|
this->InputComponent->RemoveActionBinding(*AcceptAction, EInputEvent::IE_Released);
|
|
|
|
FString CancelAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("CancelAction"), CancelAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*CancelAction, EInputEvent::IE_Pressed);
|
|
this->InputComponent->RemoveActionBinding(*CancelAction, EInputEvent::IE_Released);
|
|
|
|
FString PauseAction;
|
|
GConfig->GetString(TEXT("/Script/ControllerMenu.ControllerMenuGlobalSettings"), TEXT("PauseAction"), PauseAction, GGameIni);
|
|
this->InputComponent->RemoveActionBinding(*PauseAction, EInputEvent::IE_Pressed);
|
|
|
|
//for (const FName CustomAction : this->CustomActions)
|
|
//{
|
|
// this->CustomActionBinding = FInputActionBinding(CustomAction, EInputEvent::IE_Pressed);
|
|
// this->CustomActionBinding.bExecuteWhenPaused = true;
|
|
// this->CustomActionBinding.bConsumeInput = true;
|
|
// this->CustomActionBinding.ActionDelegate.BindDelegate(this, &UControllerMenuWidget::OnCustomPressedEvent, CustomAction);
|
|
// this->InputComponent->AddActionBinding(this->CustomActionBinding);
|
|
//}
|
|
}
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::OnAxisYEvent(const float AxisValue)
|
|
{
|
|
if (!this->bAxisYHasMoved)
|
|
{
|
|
if (AxisValue >= this->AxisMovementThreshold)
|
|
{
|
|
this->OnUpPressedEvent();
|
|
this->bAxisYHasMoved = true;
|
|
}
|
|
else if (AxisValue <= -this->AxisMovementThreshold)
|
|
{
|
|
this->OnDownPressedEvent();
|
|
this->bAxisYHasMoved = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FMath::Abs(AxisValue) < this->AxisMovementThreshold)
|
|
{
|
|
this->bAxisYHasMoved = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnAxisXEvent(const float AxisValue)
|
|
{
|
|
if (!this->bAxisXHasMoved)
|
|
{
|
|
if (AxisValue >= this->AxisMovementThreshold)
|
|
{
|
|
this->OnRightPressedEvent();
|
|
this->bAxisXHasMoved = true;
|
|
}
|
|
else if (AxisValue <= -this->AxisMovementThreshold)
|
|
{
|
|
this->OnLeftPressedEvent();
|
|
this->bAxisXHasMoved = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FMath::Abs(AxisValue) < this->AxisMovementThreshold)
|
|
{
|
|
this->bAxisXHasMoved = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::NativeOnUpPressed()
|
|
{
|
|
if (this->FocusableWidgetArray.Num() > 0)
|
|
{
|
|
if (this->FocusedWidgetIndex >= 0 && this->FocusedWidgetIndex < this->FocusableWidgetArray.Num())
|
|
{
|
|
this->SetWidgetFocus(this->WidgetFocusMapArray[this->FocusedWidgetIndex].Up);
|
|
}
|
|
else
|
|
{
|
|
this->FocusedWidgetIndex = 0;
|
|
this->SetWidgetFocus(this->FocusableWidgetArray[this->FocusedWidgetIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::NativeOnDownPressed()
|
|
{
|
|
if (this->FocusableWidgetArray.Num() > 0)
|
|
{
|
|
if (this->FocusedWidgetIndex >= 0 && this->FocusedWidgetIndex < this->FocusableWidgetArray.Num())
|
|
{
|
|
this->SetWidgetFocus(this->WidgetFocusMapArray[this->FocusedWidgetIndex].Down);
|
|
}
|
|
else
|
|
{
|
|
this->FocusedWidgetIndex = 0;
|
|
this->SetWidgetFocus(this->FocusableWidgetArray[this->FocusedWidgetIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::NativeOnLeftPressed()
|
|
{
|
|
if (this->FocusableWidgetArray.Num() > 0)
|
|
{
|
|
if (this->FocusedWidgetIndex >= 0 && this->FocusedWidgetIndex < this->FocusableWidgetArray.Num())
|
|
{
|
|
this->SetWidgetFocus(this->WidgetFocusMapArray[this->FocusedWidgetIndex].Left);
|
|
}
|
|
else
|
|
{
|
|
this->FocusedWidgetIndex = 0;
|
|
this->SetWidgetFocus(this->FocusableWidgetArray[this->FocusedWidgetIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::NativeOnRightPressed()
|
|
{
|
|
if (this->FocusableWidgetArray.Num() > 0)
|
|
{
|
|
if (this->FocusedWidgetIndex >= 0 && this->FocusedWidgetIndex < this->FocusableWidgetArray.Num())
|
|
{
|
|
this->SetWidgetFocus(this->WidgetFocusMapArray[this->FocusedWidgetIndex].Right);
|
|
}
|
|
else
|
|
{
|
|
this->FocusedWidgetIndex = 0;
|
|
this->SetWidgetFocus(this->FocusableWidgetArray[this->FocusedWidgetIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::NativeOnPreviousPressed()
|
|
{
|
|
if (this->FocusableWidgetArray.Num() > 0)
|
|
{
|
|
if (this->FocusedWidgetIndex >= 0 && this->FocusedWidgetIndex < this->FocusableWidgetArray.Num())
|
|
{
|
|
this->SetWidgetFocus(this->WidgetFocusMapArray[this->FocusedWidgetIndex].Previous);
|
|
}
|
|
else
|
|
{
|
|
this->FocusedWidgetIndex = 0;
|
|
this->SetWidgetFocus(this->FocusableWidgetArray[this->FocusedWidgetIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::NativeOnNextPressed()
|
|
{
|
|
if (this->FocusableWidgetArray.Num() > 0)
|
|
{
|
|
if (this->FocusedWidgetIndex >= 0 && this->FocusedWidgetIndex < this->FocusableWidgetArray.Num())
|
|
{
|
|
this->SetWidgetFocus(this->WidgetFocusMapArray[this->FocusedWidgetIndex].Next);
|
|
}
|
|
else
|
|
{
|
|
this->FocusedWidgetIndex = 0;
|
|
this->SetWidgetFocus(this->FocusableWidgetArray[this->FocusedWidgetIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::NativeOnAcceptPressed()
|
|
{
|
|
if (UWidget* PressedWidget = this->GetFocusedWidget())
|
|
{
|
|
if (ITakesControllerFocus* PressedControllerWidget = Cast<ITakesControllerFocus>(PressedWidget))
|
|
{
|
|
PressedControllerWidget->Execute_Press(PressedWidget);
|
|
}
|
|
else if (UButton* PressedButton = Cast<UButton>(PressedWidget))
|
|
{
|
|
PressedButton->WidgetStyle.Normal = this->PressedStyles[PressedWidget];
|
|
PressedButton->WidgetStyle.NormalPadding = this->PressedPaddings[PressedWidget];
|
|
PressedButton->OnPressed.Broadcast();
|
|
}
|
|
this->Refocus(PressedWidget);
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::NativeOnCancelPressed()
|
|
{
|
|
if (this->CancelButton)
|
|
{
|
|
if (this->CancelConfirm && !this->HasWidgetFocus(this->CancelButton))
|
|
{
|
|
this->SetWidgetFocus(this->CancelButton);
|
|
return;
|
|
}
|
|
else if (ITakesControllerFocus* PressedControllerWidget = Cast<ITakesControllerFocus>(this->CancelButton))
|
|
{
|
|
UWidget* FocusedWidget = this->GetFocusedWidget();
|
|
if (ITakesControllerFocus* FocusedControllerWidget = Cast<ITakesControllerFocus>(FocusedWidget))
|
|
{
|
|
FocusedControllerWidget->Execute_Unhover(FocusedWidget);
|
|
}
|
|
else if (UButton* FocusedButton = Cast<UButton>(FocusedWidget))
|
|
{
|
|
FocusedButton->WidgetStyle.Normal = this->NormalStyles[this->CancelButton];
|
|
FocusedButton->WidgetStyle.NormalPadding = this->NormalPaddings[this->CancelButton];
|
|
}
|
|
PressedControllerWidget->Execute_Press(this->CancelButton);
|
|
}
|
|
else if (UButton* PressedButton = Cast<UButton>(this->CancelButton))
|
|
{
|
|
UWidget* FocusedWidget = this->GetFocusedWidget();
|
|
if (ITakesControllerFocus* FocusedControllerWidget = Cast<ITakesControllerFocus>(FocusedWidget))
|
|
{
|
|
FocusedControllerWidget->Execute_Unhover(FocusedWidget);
|
|
}
|
|
else if (UButton* FocusedButton = Cast<UButton>(FocusedWidget))
|
|
{
|
|
FocusedButton->WidgetStyle.Normal = this->NormalStyles[this->CancelButton];
|
|
FocusedButton->WidgetStyle.NormalPadding = this->NormalPaddings[this->CancelButton];
|
|
}
|
|
PressedButton->WidgetStyle.Normal = this->PressedStyles[this->CancelButton];
|
|
PressedButton->WidgetStyle.NormalPadding = this->PressedPaddings[this->CancelButton];
|
|
PressedButton->OnPressed.Broadcast();
|
|
}
|
|
this->Refocus(this->CancelButton);
|
|
}
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::NativeOnAcceptReleased()
|
|
{
|
|
if (UWidget* ReleasedWidget = this->GetFocusedWidget())
|
|
{
|
|
if (ITakesControllerFocus* ReleasedControllerWidget = Cast<ITakesControllerFocus>(ReleasedWidget))
|
|
{
|
|
ReleasedControllerWidget->Execute_Release(ReleasedWidget);
|
|
}
|
|
else if (UButton* ReleasedButton = Cast<UButton>(ReleasedWidget))
|
|
{
|
|
ReleasedButton->WidgetStyle.Normal = this->HoveredStyles[ReleasedWidget];
|
|
ReleasedButton->WidgetStyle.NormalPadding = this->NormalPaddings[ReleasedWidget];
|
|
ReleasedButton->OnReleased.Broadcast();
|
|
}
|
|
this->Refocus(ReleasedWidget);
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::NativeOnCancelReleased()
|
|
{
|
|
if (this->CancelButton && this->HasWidgetFocus(this->CancelButton))
|
|
{
|
|
if (ITakesControllerFocus* ReleasedControllerWidget = Cast<ITakesControllerFocus>(this->CancelButton))
|
|
{
|
|
ReleasedControllerWidget->Execute_Release(this->CancelButton);
|
|
}
|
|
else if (UButton* ReleasedButton = Cast<UButton>(this->CancelButton))
|
|
{
|
|
ReleasedButton->WidgetStyle.Normal = this->HoveredStyles[this->CancelButton];
|
|
ReleasedButton->WidgetStyle.NormalPadding = this->NormalPaddings[this->CancelButton];
|
|
ReleasedButton->OnReleased.Broadcast();
|
|
}
|
|
this->Refocus(this->CancelButton);
|
|
}
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::OnUpPressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
//const FControllerWidgetFocusMap &WidgetFocusMap = this->WidgetFocusMapArray[this->FocusedWidgetIndex];
|
|
//if (WidgetFocusMap.Up)
|
|
//{
|
|
// this->FocusedWidgetIndex = this->FocusableWidgetArray.Find(WidgetFocusMap.Up);
|
|
// this->ResetFocus();
|
|
//}
|
|
|
|
this->NativeOnUpPressed();
|
|
this->OnUpPressed();
|
|
this->OnUpPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnDownPressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
//const FControllerWidgetFocusMap &WidgetFocusMap = this->WidgetFocusMapArray[this->FocusedWidgetIndex];
|
|
//if (WidgetFocusMap.Down)
|
|
//{
|
|
// this->FocusedWidgetIndex = this->FocusableWidgetArray.Find(WidgetFocusMap.Down);
|
|
// this->ResetFocus();
|
|
//}
|
|
|
|
this->NativeOnDownPressed();
|
|
this->OnDownPressed();
|
|
this->OnDownPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnLeftPressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable && this->FocusedWidgetIndex >= 0)
|
|
{
|
|
const FControllerWidgetFocusMap& WidgetFocusMap = this->WidgetFocusMapArray[this->FocusedWidgetIndex];
|
|
if (!WidgetFocusMap.Left)
|
|
{
|
|
if (UTextSpinner* TextSpinner = Cast<UTextSpinner>(this->GetFocusedWidget()))
|
|
{
|
|
TextSpinner->PreviousItem();
|
|
}
|
|
}
|
|
|
|
this->NativeOnLeftPressed();
|
|
this->OnLeftPressed();
|
|
this->OnLeftPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnRightPressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable && this->FocusedWidgetIndex >= 0)
|
|
{
|
|
const FControllerWidgetFocusMap& WidgetFocusMap = this->WidgetFocusMapArray[this->FocusedWidgetIndex];
|
|
if (!WidgetFocusMap.Right)
|
|
{
|
|
if (UTextSpinner* TextSpinner = Cast<UTextSpinner>(this->GetFocusedWidget()))
|
|
{
|
|
TextSpinner->NextItem();
|
|
}
|
|
}
|
|
|
|
this->NativeOnRightPressed();
|
|
this->OnRightPressed();
|
|
this->OnRightPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnPreviousPressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
//const FControllerWidgetFocusMap &WidgetFocusMap = this->WidgetFocusMapArray[this->FocusedWidgetIndex];
|
|
//if (WidgetFocusMap.Previous)
|
|
//{
|
|
// this->FocusedWidgetIndex = this->FocusableWidgetArray.Find(WidgetFocusMap.Previous);
|
|
// this->ResetFocus();
|
|
//}
|
|
|
|
this->NativeOnPreviousPressed();
|
|
this->OnPreviousPressed();
|
|
this->OnPreviousPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnNextPressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
//const FControllerWidgetFocusMap &WidgetFocusMap = this->WidgetFocusMapArray[this->FocusedWidgetIndex];
|
|
//if (WidgetFocusMap.Next)
|
|
//{
|
|
// this->FocusedWidgetIndex = this->FocusableWidgetArray.Find(WidgetFocusMap.Next);
|
|
// this->ResetFocus();
|
|
//}
|
|
|
|
this->NativeOnNextPressed();
|
|
this->OnNextPressed();
|
|
this->OnNextPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnAcceptPressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
this->NativeOnAcceptPressed();
|
|
this->OnAcceptPressed();
|
|
this->OnAcceptPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnCancelPressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
this->NativeOnCancelPressed();
|
|
this->OnCancelPressed();
|
|
this->OnCancelPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnPausePressedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
this->NativeOnPausePressed();
|
|
this->OnPausePressed();
|
|
this->OnPausePressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnCustomPressedEvent(const FName CustomAction)
|
|
{
|
|
if (this->bIsInteractable)
|
|
{
|
|
this->NativeOnCustomPressed(CustomAction);
|
|
this->OnCustomPressed(CustomAction);
|
|
//this->OnCustomPressedDelegate.Broadcast();
|
|
}
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::OnAcceptReleasedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
this->NativeOnAcceptReleased();
|
|
}
|
|
}
|
|
|
|
void UControllerMenuWidget::OnCancelReleasedEvent()
|
|
{
|
|
if (!this->IsAnyAnimationPlaying() && this->bIsInteractable)
|
|
{
|
|
this->NativeOnCancelReleased();
|
|
}
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::SetWidgetFocus(UWidget *NewWidget)
|
|
{
|
|
if (NewWidget && (NewWidget->IsVisible() && NewWidget->GetIsEnabled()))
|
|
{
|
|
if (UWidget *FocusedWidget = this->GetFocusedWidget())
|
|
{
|
|
if (ITakesControllerFocus *FocusedControllerWidget = Cast<ITakesControllerFocus>(FocusedWidget))
|
|
{
|
|
FocusedControllerWidget->Execute_Unhover(FocusedWidget);
|
|
}
|
|
else if (UButton *FocusedButton = Cast<UButton>(FocusedWidget))
|
|
{
|
|
FocusedButton->WidgetStyle.Normal = this->NormalStyles[FocusedWidget];
|
|
FocusedButton->WidgetStyle.NormalPadding = this->NormalPaddings[FocusedWidget];
|
|
FocusedButton->OnUnhovered.Broadcast();
|
|
}
|
|
}
|
|
|
|
this->FocusedWidgetIndex = this->FocusableWidgetArray.Find(NewWidget);
|
|
if (UWidget *FocusedWidget = this->GetFocusedWidget())
|
|
{
|
|
if (ITakesControllerFocus *FocusedControllerWidget = Cast<ITakesControllerFocus>(FocusedWidget))
|
|
{
|
|
FocusedControllerWidget->Execute_Hover(FocusedWidget);
|
|
}
|
|
else if (UButton *FocusedButton = Cast<UButton>(FocusedWidget))
|
|
{
|
|
FocusedButton->WidgetStyle.Normal = this->HoveredStyles[FocusedWidget];
|
|
FocusedButton->WidgetStyle.NormalPadding = this->NormalPaddings[FocusedWidget];
|
|
FocusedButton->OnHovered.Broadcast();
|
|
}
|
|
}
|
|
|
|
this->FocusChanged(this->GetFocusedWidget());
|
|
}
|
|
|
|
// HACK: Enable focus for this widget, focus, then reset focus setting.
|
|
// This allows us to keep focus inside the widget while preventing Slate
|
|
// from using its own input handling, and also bypasses a warning about
|
|
// setting focus to an unfocusable widget.
|
|
this->bIsFocusable = true;
|
|
this->SetKeyboardFocus();
|
|
this->bIsFocusable = false;
|
|
|
|
if (UWidget *FocusedWidget = this->GetFocusedWidget())
|
|
{
|
|
this->FindParentScrollBoxRecursive(FocusedWidget, FocusedWidget->GetParent());
|
|
}
|
|
}
|
|
void UControllerMenuWidget::FindParentScrollBoxRecursive(UWidget *FocusedWidget, UWidget *WidgetParent)
|
|
{
|
|
if (WidgetParent != nullptr)
|
|
{
|
|
if (UScrollBox *ScrollBox = Cast<UScrollBox>(WidgetParent))
|
|
{
|
|
ScrollBox->ScrollWidgetIntoView(FocusedWidget, true);
|
|
}
|
|
else
|
|
{
|
|
this->FindParentScrollBoxRecursive(FocusedWidget, WidgetParent->GetParent());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UControllerMenuWidget::HasWidgetFocus(UWidget* Widget) const
|
|
{
|
|
if (Widget)
|
|
{
|
|
return this->FocusedWidgetIndex == this->FocusableWidgetArray.Find(Widget);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void UControllerMenuWidget::ClearWidgetFocus()
|
|
{
|
|
if (UWidget* Widget = this->GetFocusedWidget())
|
|
{
|
|
if (ITakesControllerFocus* FocusedControllerWidget = Cast<ITakesControllerFocus>(Widget))
|
|
{
|
|
FocusedControllerWidget->Execute_Unhover(Widget);
|
|
}
|
|
else if (UButton* FocusedButton = Cast<UButton>(Widget))
|
|
{
|
|
FocusedButton->WidgetStyle.Normal = this->NormalStyles[Widget];
|
|
FocusedButton->WidgetStyle.NormalPadding = this->NormalPaddings[Widget];
|
|
}
|
|
}
|
|
this->FocusedWidgetIndex = -1;
|
|
|
|
this->FocusChanged(nullptr);
|
|
|
|
// HACK: Enable focus for this widget, focus, then reset focus setting.
|
|
// This allows us to keep focus inside the widget while preventing Slate
|
|
// from using its own input handling, and also bypasses a warning about
|
|
// setting focus to an unfocusable widget.
|
|
this->bIsFocusable = true;
|
|
this->SetKeyboardFocus();
|
|
this->bIsFocusable = false;
|
|
}
|
|
|
|
void UControllerMenuWidget::Refocus(const UWidget* FocusedWidget)
|
|
{
|
|
// If the current widget is not in focus any more, find a new widget to focus on
|
|
if (!FocusedWidget->GetIsEnabled())
|
|
{
|
|
const FControllerWidgetFocusMap& FocusMap = this->WidgetFocusMapArray[this->FocusedWidgetIndex];
|
|
if (FocusMap.Down) { this->SetWidgetFocus(FocusMap.Down); }
|
|
else if (FocusMap.Right) { this->SetWidgetFocus(FocusMap.Right); }
|
|
else if (FocusMap.Up) { this->SetWidgetFocus(FocusMap.Up); }
|
|
else if (FocusMap.Left) { this->SetWidgetFocus(FocusMap.Left); }
|
|
else if (FocusMap.Next) { this->SetWidgetFocus(FocusMap.Next); }
|
|
else if (FocusMap.Previous) { this->SetWidgetFocus(FocusMap.Previous); }
|
|
else { this->SetWidgetFocus(*this->FocusableWidgetArray.begin()); }
|
|
}
|
|
}
|
|
|
|
|
|
void UControllerMenuWidget::SetNewInputDevice(const EControllerMenuInputDevice& NewInputDevice)
|
|
{
|
|
if (this->LastInputDevice != NewInputDevice)
|
|
{
|
|
this->LastInputDevice = NewInputDevice;
|
|
if (NewInputDevice != EControllerMenuInputDevice::Mouse)
|
|
{
|
|
this->MouseMovementStartPosition = FVector2D::ZeroVector;
|
|
}
|
|
this->InputDeviceChanged(NewInputDevice);
|
|
}
|
|
}
|
|
|
|
FName UControllerMenuWidget::GetInputDeviceName() const
|
|
{
|
|
switch (this->LastInputDevice)
|
|
{
|
|
case EControllerMenuInputDevice::Mouse:
|
|
return TEXT("Mouse");
|
|
case EControllerMenuInputDevice::Touchscreen:
|
|
return TEXT("Touchscreen");
|
|
case EControllerMenuInputDevice::Keyboard:
|
|
return TEXT("Keyboard");
|
|
case EControllerMenuInputDevice::Controller:
|
|
return TEXT("Controller");
|
|
}
|
|
return TEXT("None");
|
|
}
|