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);
|
||||
}
|
||||
|
||||
FMenuSystem* UStevesGameSubsystem::GetMenuSystem()
|
||||
{
|
||||
return &MenuSystem;
|
||||
}
|
||||
|
||||
UStevesGameSubsystem::FInputModeDetector::FInputModeDetector()
|
||||
{
|
||||
// 4 local players should be plenty usually (will expand if necessary)
|
||||
|
@ -131,12 +131,17 @@ void UMenuBase::Open(bool bIsRegain)
|
||||
break;
|
||||
}
|
||||
|
||||
TakeFocusIfDesired();
|
||||
|
||||
}
|
||||
|
||||
void UMenuBase::TakeFocusIfDesired()
|
||||
{
|
||||
auto GS = GetStevesGameSubsystem(GetWorld());
|
||||
if (bRequestFocus &&
|
||||
GS && (GS->GetLastInputModeUsed() != EInputMode::Gamepad || GS->GetLastInputModeUsed() != EInputMode::Keyboard))
|
||||
{
|
||||
SetFocusProperly();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "StevesGameSubsystem.h"
|
||||
#include "StevesUEHelpers.h"
|
||||
#include "StevesUI/MenuBase.h"
|
||||
#include "Framework/Application/SlateApplication.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
|
||||
@ -180,6 +179,9 @@ void UMenuStack::PushMenuByObject(UMenuBase* NewMenu)
|
||||
}
|
||||
Menus.Add(NewMenu);
|
||||
NewMenu->AddedToStack(this);
|
||||
|
||||
if (Menus.Num() == 1)
|
||||
FirstMenuOpened();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
RemoveFromParent();
|
||||
RemoveFromParent(); // this will do MenuSystem interaction
|
||||
OnClosed.Broadcast(this, bWasCancel);
|
||||
|
||||
ApplyInputModeChange(InputModeSettingOnClose);
|
||||
@ -228,6 +249,7 @@ void UMenuStack::LastMenuClosed(bool bWasCancel)
|
||||
|
||||
}
|
||||
|
||||
|
||||
void UMenuStack::CloseAll(bool bWasCancel)
|
||||
{
|
||||
// We don't go through normal pop sequence, this is a shot circuit
|
||||
@ -239,6 +261,19 @@ void UMenuStack::CloseAll(bool 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()
|
||||
{
|
||||
// Delegate to top menu
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "InputCoreTypes.h"
|
||||
#include "Framework/Application/IInputProcessor.h"
|
||||
#include "StevesHelperCommon.h"
|
||||
#include "StevesUI/MenuSystem.h"
|
||||
#include "StevesUI/UiTheme.h"
|
||||
|
||||
#include "StevesGameSubsystem.generated.h"
|
||||
@ -91,6 +92,7 @@ protected:
|
||||
|
||||
protected:
|
||||
TSharedPtr<FInputModeDetector> InputDetector;
|
||||
FMenuSystem MenuSystem;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
UUiTheme* DefaultUiTheme;
|
||||
@ -120,4 +122,7 @@ public:
|
||||
|
||||
/// Changes the default theme to a different one
|
||||
void SetDefaultUiTheme(UUiTheme* NewTheme) { DefaultUiTheme = NewTheme; }
|
||||
|
||||
/// Get the global menu system
|
||||
FMenuSystem* GetMenuSystem();
|
||||
};
|
||||
|
@ -76,7 +76,13 @@ public:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
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 RemovedFromStack(UMenuStack* Parent);
|
||||
|
@ -16,7 +16,11 @@ class UMenuBase;
|
||||
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"
|
||||
/// 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
|
||||
/// 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.
|
||||
@ -33,6 +37,7 @@ protected:
|
||||
|
||||
TArray<UMenuBase*> Menus;
|
||||
|
||||
virtual void FirstMenuOpened();
|
||||
virtual void LastMenuClosed(bool bWasCancel);
|
||||
|
||||
virtual void NativeConstruct() override;
|
||||
@ -48,6 +53,12 @@ protected:
|
||||
void InputModeChanged(int PlayerIndex, EInputMode NewMode);
|
||||
|
||||
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
|
||||
/// 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.
|
||||
@ -107,7 +118,16 @@ public:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
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;
|
||||
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