mirror of
https://github.com/sinbad/StevesUEHelpers.git
synced 2025-02-23 17:45:23 +00:00
Add MenuSystem which is capable of handling to focus between multiple MenuStacks, so that a closed stack can give focus back to the next most important stack automatically
This commit is contained in:
parent
f75706abc4
commit
5af66f2243
@ -87,6 +87,11 @@ void UStevesGameSubsystem::OnInputDetectorModeChanged(int PlayerIndex, EInputMod
|
|||||||
OnInputModeChanged.Broadcast(PlayerIndex, NewMode);
|
OnInputModeChanged.Broadcast(PlayerIndex, NewMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FMenuSystem* UStevesGameSubsystem::GetMenuSystem()
|
||||||
|
{
|
||||||
|
return &MenuSystem;
|
||||||
|
}
|
||||||
|
|
||||||
UStevesGameSubsystem::FInputModeDetector::FInputModeDetector()
|
UStevesGameSubsystem::FInputModeDetector::FInputModeDetector()
|
||||||
{
|
{
|
||||||
// 4 local players should be plenty usually (will expand if necessary)
|
// 4 local players should be plenty usually (will expand if necessary)
|
||||||
|
@ -131,12 +131,17 @@ void UMenuBase::Open(bool bIsRegain)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TakeFocusIfDesired();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void UMenuBase::TakeFocusIfDesired()
|
||||||
|
{
|
||||||
auto GS = GetStevesGameSubsystem(GetWorld());
|
auto GS = GetStevesGameSubsystem(GetWorld());
|
||||||
if (bRequestFocus &&
|
if (bRequestFocus &&
|
||||||
GS && (GS->GetLastInputModeUsed() != EInputMode::Gamepad || GS->GetLastInputModeUsed() != EInputMode::Keyboard))
|
GS && (GS->GetLastInputModeUsed() != EInputMode::Gamepad || GS->GetLastInputModeUsed() != EInputMode::Keyboard))
|
||||||
{
|
{
|
||||||
SetFocusProperly();
|
SetFocusProperly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include "StevesGameSubsystem.h"
|
#include "StevesGameSubsystem.h"
|
||||||
#include "StevesUEHelpers.h"
|
#include "StevesUEHelpers.h"
|
||||||
#include "StevesUI/MenuBase.h"
|
#include "StevesUI/MenuBase.h"
|
||||||
#include "Framework/Application/SlateApplication.h"
|
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
|
|
||||||
|
|
||||||
@ -180,6 +179,9 @@ void UMenuStack::PushMenuByObject(UMenuBase* NewMenu)
|
|||||||
}
|
}
|
||||||
Menus.Add(NewMenu);
|
Menus.Add(NewMenu);
|
||||||
NewMenu->AddedToStack(this);
|
NewMenu->AddedToStack(this);
|
||||||
|
|
||||||
|
if (Menus.Num() == 1)
|
||||||
|
FirstMenuOpened();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UMenuStack::PopMenu(bool bWasCancel)
|
void UMenuStack::PopMenu(bool bWasCancel)
|
||||||
@ -217,9 +219,28 @@ void UMenuStack::PopMenuIfTop(UMenuBase* UiMenuBase, bool bWasCancel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UMenuStack::FirstMenuOpened()
|
||||||
|
{
|
||||||
|
// tell menu system
|
||||||
|
auto GS = GetStevesGameSubsystem(GetWorld());
|
||||||
|
GS->GetMenuSystem()->MenuStackOpened(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UMenuStack::RemoveFromParent()
|
||||||
|
{
|
||||||
|
Super::RemoveFromParent();
|
||||||
|
|
||||||
|
// tell menu system if we're in-game (this gets called in editor too)
|
||||||
|
auto GS = GetStevesGameSubsystem(GetWorld());
|
||||||
|
if (GS)
|
||||||
|
GS->GetMenuSystem()->MenuStackClosed(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void UMenuStack::LastMenuClosed(bool bWasCancel)
|
void UMenuStack::LastMenuClosed(bool bWasCancel)
|
||||||
{
|
{
|
||||||
RemoveFromParent();
|
RemoveFromParent(); // this will do MenuSystem interaction
|
||||||
OnClosed.Broadcast(this, bWasCancel);
|
OnClosed.Broadcast(this, bWasCancel);
|
||||||
|
|
||||||
ApplyInputModeChange(InputModeSettingOnClose);
|
ApplyInputModeChange(InputModeSettingOnClose);
|
||||||
@ -228,6 +249,7 @@ void UMenuStack::LastMenuClosed(bool bWasCancel)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UMenuStack::CloseAll(bool bWasCancel)
|
void UMenuStack::CloseAll(bool bWasCancel)
|
||||||
{
|
{
|
||||||
// We don't go through normal pop sequence, this is a shot circuit
|
// We don't go through normal pop sequence, this is a shot circuit
|
||||||
@ -239,6 +261,19 @@ void UMenuStack::CloseAll(bool bWasCancel)
|
|||||||
LastMenuClosed(bWasCancel);
|
LastMenuClosed(bWasCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UMenuStack::IsRequestingFocus() const
|
||||||
|
{
|
||||||
|
return Menus.Num() > 0 && Menus.Last()->IsRequestingFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UMenuStack::TakeFocusIfDesired()
|
||||||
|
{
|
||||||
|
if (IsRequestingFocus())
|
||||||
|
{
|
||||||
|
Menus.Last()->TakeFocusIfDesired();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UMenuStack::SetFocusProperly_Implementation()
|
void UMenuStack::SetFocusProperly_Implementation()
|
||||||
{
|
{
|
||||||
// Delegate to top menu
|
// Delegate to top menu
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "InputCoreTypes.h"
|
#include "InputCoreTypes.h"
|
||||||
#include "Framework/Application/IInputProcessor.h"
|
#include "Framework/Application/IInputProcessor.h"
|
||||||
#include "StevesHelperCommon.h"
|
#include "StevesHelperCommon.h"
|
||||||
|
#include "StevesUI/MenuSystem.h"
|
||||||
#include "StevesUI/UiTheme.h"
|
#include "StevesUI/UiTheme.h"
|
||||||
|
|
||||||
#include "StevesGameSubsystem.generated.h"
|
#include "StevesGameSubsystem.generated.h"
|
||||||
@ -91,6 +92,7 @@ protected:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
TSharedPtr<FInputModeDetector> InputDetector;
|
TSharedPtr<FInputModeDetector> InputDetector;
|
||||||
|
FMenuSystem MenuSystem;
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
UPROPERTY(BlueprintReadWrite)
|
||||||
UUiTheme* DefaultUiTheme;
|
UUiTheme* DefaultUiTheme;
|
||||||
@ -120,4 +122,7 @@ public:
|
|||||||
|
|
||||||
/// Changes the default theme to a different one
|
/// Changes the default theme to a different one
|
||||||
void SetDefaultUiTheme(UUiTheme* NewTheme) { DefaultUiTheme = NewTheme; }
|
void SetDefaultUiTheme(UUiTheme* NewTheme) { DefaultUiTheme = NewTheme; }
|
||||||
|
|
||||||
|
/// Get the global menu system
|
||||||
|
FMenuSystem* GetMenuSystem();
|
||||||
};
|
};
|
||||||
|
@ -76,7 +76,13 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
void Close(bool bWasCancel);
|
void Close(bool bWasCancel);
|
||||||
|
|
||||||
TWeakObjectPtr<UMenuStack> GetParentStack() const { return ParentStack; };
|
/// Triggers this menu to take focus if appropriate
|
||||||
|
/// This means if the menu both requests focus, and gamepad or keyboard is in use
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
void TakeFocusIfDesired();
|
||||||
|
|
||||||
|
TWeakObjectPtr<UMenuStack> GetParentStack() const { return ParentStack; }
|
||||||
|
bool IsRequestingFocus() const { return bRequestFocus; }
|
||||||
|
|
||||||
void AddedToStack(UMenuStack* Parent);
|
void AddedToStack(UMenuStack* Parent);
|
||||||
void RemovedFromStack(UMenuStack* Parent);
|
void RemovedFromStack(UMenuStack* Parent);
|
||||||
|
@ -16,7 +16,11 @@ class UMenuBase;
|
|||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMenuStackClosed, class UMenuStack*, Stack, bool, bWasCancel);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMenuStackClosed, class UMenuStack*, Stack, bool, bWasCancel);
|
||||||
|
|
||||||
/// Represents a modal stack of menus which take focus and have a concept of "Back"
|
/// Represents a modal stack of menus which take focus and have a concept of "Back"
|
||||||
/// Each level is a MenuBase
|
/// Each level within is a MenuBase, which must be "pushed" on to the stack.
|
||||||
|
/// Contained within MenuSystem (multiple menu stacks supported)
|
||||||
|
/// Has a Priority so that when multiple menu stacks are open, higher priority gets focus,
|
||||||
|
/// and when closed, next highest priority gets focus back. Focus is given when the first MenuBase is pushed onto the stack,
|
||||||
|
/// and given up when the last one is popped.
|
||||||
/// You can style this widget to be the general surrounds in which all MenuBase levels live inside
|
/// You can style this widget to be the general surrounds in which all MenuBase levels live inside
|
||||||
/// Create a Blueprint subclass of this and make sure you include a UContentWidget with the name
|
/// Create a Blueprint subclass of this and make sure you include a UContentWidget with the name
|
||||||
/// "MenuContainer" somewhere in the tree, which is where the menu contents will be placed.
|
/// "MenuContainer" somewhere in the tree, which is where the menu contents will be placed.
|
||||||
@ -33,6 +37,7 @@ protected:
|
|||||||
|
|
||||||
TArray<UMenuBase*> Menus;
|
TArray<UMenuBase*> Menus;
|
||||||
|
|
||||||
|
virtual void FirstMenuOpened();
|
||||||
virtual void LastMenuClosed(bool bWasCancel);
|
virtual void LastMenuClosed(bool bWasCancel);
|
||||||
|
|
||||||
virtual void NativeConstruct() override;
|
virtual void NativeConstruct() override;
|
||||||
@ -48,6 +53,12 @@ protected:
|
|||||||
void InputModeChanged(int PlayerIndex, EInputMode NewMode);
|
void InputModeChanged(int PlayerIndex, EInputMode NewMode);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// The focus priority of this stack compared to others. When a MenuStack is opened, if it has higher priority than
|
||||||
|
/// any existing MenuStack open, it will be given focus. When a MenuStack with focus is closed, the next highest
|
||||||
|
/// priority one will be given focus.
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Behaviour")
|
||||||
|
int FocusPriority = 0;
|
||||||
|
|
||||||
/// This property will bind to a blueprint variable of the same name to contain the actual menu content
|
/// This property will bind to a blueprint variable of the same name to contain the actual menu content
|
||||||
/// If not set, or the UiMenuBase is set to not use this container, levels are added independently to viewport
|
/// If not set, or the UiMenuBase is set to not use this container, levels are added independently to viewport
|
||||||
/// Use a NamedSlot for this most of the time, it gives you the most layout flexibility.
|
/// Use a NamedSlot for this most of the time, it gives you the most layout flexibility.
|
||||||
@ -107,7 +118,16 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
void CloseAll(bool bWasCancel);
|
void CloseAll(bool bWasCancel);
|
||||||
|
|
||||||
|
/// Whether the top MenuBase on this stack is requesting focus
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
bool IsRequestingFocus() const;
|
||||||
|
|
||||||
|
/// Triggers this stack to take focus (specifically its topmost MenuBase) if appropriate
|
||||||
|
/// This means if both top menu on the stack requests focus, and gamepad or keyboard is in use
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
void TakeFocusIfDesired();
|
||||||
|
|
||||||
virtual void SetFocusProperly_Implementation() override;
|
virtual void SetFocusProperly_Implementation() override;
|
||||||
void PopMenuIfTop(UMenuBase* UiMenuBase, bool bWasCancel);
|
virtual void PopMenuIfTop(UMenuBase* UiMenuBase, bool bWasCancel);
|
||||||
|
virtual void RemoveFromParent() override;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user