Enabling UMenuBase to set its own input mode, mouse pointer and game paused & to be used outside of UMenuStack

This commit is contained in:
Steve Streeting 2020-10-20 15:16:50 +01:00
parent f6cd57c5ee
commit 0f2c000939
2 changed files with 129 additions and 33 deletions

View File

@ -5,6 +5,7 @@
#include "StevesUEHelpers.h" #include "StevesUEHelpers.h"
#include "StevesUI/MenuStack.h" #include "StevesUI/MenuStack.h"
#include "Components/ContentWidget.h" #include "Components/ContentWidget.h"
#include "Kismet/GameplayStatics.h"
void UMenuBase::Close(bool bWasCancel) void UMenuBase::Close(bool bWasCancel)
{ {
@ -13,26 +14,19 @@ void UMenuBase::Close(bool bWasCancel)
if (ParentStack.IsValid()) if (ParentStack.IsValid())
{ {
ParentStack->PopMenuIfTop(this, bWasCancel); ParentStack->PopMenuIfTop(this, bWasCancel);
} else
{
// standalone mode
RemoveFromParent();
PreviousFocusWidget.Reset();
} }
} }
void UMenuBase::AddedToStack(UMenuStack* Parent) void UMenuBase::AddedToStack(UMenuStack* Parent)
{ {
ParentStack = MakeWeakObjectPtr(Parent); ParentStack = MakeWeakObjectPtr(Parent);
if (bEmbedInParentContainer)
EmbedInParent();
else
AddToViewport();
SetVisibility(ESlateVisibility::Visible);
auto GS = GetStevesGameSubsystem(GetWorld()); Open(false);
if (bRequestFocus &&
GS && (GS->GetLastInputModeUsed() != EInputMode::Gamepad || GS->GetLastInputModeUsed() != EInputMode::Keyboard))
{
SetFocusProperly();
}
} }
@ -73,16 +67,7 @@ void UMenuBase::SupercededInStack()
void UMenuBase::RegainedFocusInStack() void UMenuBase::RegainedFocusInStack()
{ {
if (bEmbedInParentContainer) Open(true);
EmbedInParent();
else
AddToViewport();
SetVisibility(ESlateVisibility::Visible);
if (bRequestFocus)
{
SetFocusProperly();
}
} }
@ -97,3 +82,61 @@ void UMenuBase::EmbedInParent()
UE_LOG(LogStevesUI, Error, TEXT("Cannot embed %s in parent, missing container"), *this->GetName()) UE_LOG(LogStevesUI, Error, TEXT("Cannot embed %s in parent, missing container"), *this->GetName())
} }
void UMenuBase::Open(bool bIsRegain)
{
if (ParentStack.IsValid() && bEmbedInParentContainer)
EmbedInParent();
else
AddToViewport();
SetVisibility(ESlateVisibility::Visible);
auto PC = GetOwningPlayer();
switch (InputModeSetting)
{
case EInputModeChange::DoNotChange:
break;
case EInputModeChange::UIOnly:
PC->SetInputMode(FInputModeUIOnly());
break;
case EInputModeChange::GameAndUI:
PC->SetInputMode(FInputModeGameAndUI());
break;
case EInputModeChange::GameOnly:
PC->SetInputMode(FInputModeGameOnly());
break;
}
switch (MousePointerVisibility)
{
case EMousePointerVisibilityChange::DoNotChange:
break;
case EMousePointerVisibilityChange::Visible:
PC->bShowMouseCursor = true;
break;
case EMousePointerVisibilityChange::Hidden:
PC->bShowMouseCursor = false;
break;
}
switch (GamePauseSetting)
{
case EGamePauseChange::DoNotChange:
break;
case EGamePauseChange::Paused:
UGameplayStatics::SetGamePaused(GetWorld(), true);
break;
case EGamePauseChange::Unpaused:
UGameplayStatics::SetGamePaused(GetWorld(), false);
break;
}
auto GS = GetStevesGameSubsystem(GetWorld());
if (bRequestFocus &&
GS && (GS->GetLastInputModeUsed() != EInputMode::Gamepad || GS->GetLastInputModeUsed() != EInputMode::Keyboard))
{
SetFocusProperly();
}
}

View File

@ -10,10 +10,38 @@
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMenuClosed, UMenuBase*, Menu, bool, bWasCancelled); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMenuClosed, UMenuBase*, Menu, bool, bWasCancelled);
/// This class is one element of the UUiMenuStack and represents one level in the chain of
/// an assumed modal stack. It is responsible for implementing how it gets added UENUM(BlueprintType)
/// to the viewport or parent container, and removed again, and what it does when receiving enum class EInputModeChange : uint8
/// focus. {
DoNotChange UMETA(DisplayName="No Change"),
UIOnly UMETA(DisplayName="UI Only"),
GameAndUI UMETA(DisplayName="Game And UI"),
GameOnly UMETA(DisplayName="Game Only")
};
UENUM(BlueprintType)
enum class EMousePointerVisibilityChange : uint8
{
DoNotChange UMETA(DisplayName="No Change"),
Visible UMETA(DisplayName="Pointer Visible"),
Hidden UMETA(DisplayName="Pointer Hidden")
};
UENUM(BlueprintType)
enum class EGamePauseChange : uint8
{
DoNotChange UMETA(DisplayName="No Change"),
Paused UMETA(DisplayName="Pause Game"),
Unpaused UMETA(DisplayName="Unpause Game")
};
/// This class is a type of focusable panel designed for menus or other dialogs.
/// It can be added to a UMenuStack to put it in context of a larger navigable group,
/// and if so represents one level in the chain of an assumed modal stack. Use UMenuStack::PushMenuByClass/Object
/// to add an entry of this type to the stack
/// If you use this class standalone instead without a stack, then you must call Open() on this instance to
/// make it add itself to the viewport.
UCLASS(Abstract, BlueprintType) UCLASS(Abstract, BlueprintType)
class STEVESUEHELPERS_API UMenuBase : public UFocusablePanel class STEVESUEHELPERS_API UMenuBase : public UFocusablePanel
{ {
@ -29,23 +57,48 @@ protected:
/// Whether this menu should request focus when it is displayed /// Whether this menu should request focus when it is displayed
/// The widget which is focussed will either be the InitialFocusWidget on newly displayed, or /// The widget which is focussed will either be the InitialFocusWidget on newly displayed, or
/// the previously selected widget if regaining focus /// the previously selected widget if regaining focus
UPROPERTY(EditAnywhere, BlueprintReadWrite) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Focus")
bool bRequestFocus = true; bool bRequestFocus = true;
/// Set this property to true if you want this menu to embed itself in the parent UUiMenuStack's MenuContainer /// Set this property to true if you want this menu to embed itself in the parent UMenuStack's MenuContainer
/// If false, this Menu will be added to the viewport independently and can float over other menus in the stack /// If false, this Menu will be added to the viewport independently and can float over other menus in the stack
UPROPERTY(EditAnywhere, BlueprintReadWrite) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Layout")
bool bEmbedInParentContainer = true; bool bEmbedInParentContainer = true;
/// Whether to hide this menu when it's superceded by another in the stack. This property is only relevant /// Whether to hide this menu when it's superceded by another in the stack. This property is only relevant
/// when bEmbedInParentContainer = false, since only one menu can be embedded at once. /// when bEmbedInParentContainer = false, since only one menu can be embedded at once.
UPROPERTY(EditAnywhere, BlueprintReadWrite) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Behavior")
bool bHideWhenSuperceded = true; bool bHideWhenSuperceded = true;
void EmbedInParent(); /// How this menu should set the input mode when it becomes the top of the stack
/// This can be useful if your menus have variable input settings between levels in the stack
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Behavior")
EInputModeChange InputModeSetting = EInputModeChange::DoNotChange;
/// How this menu should set the mouse pointer visibility when it becomes the top of the stack
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Behavior")
EMousePointerVisibilityChange MousePointerVisibility = EMousePointerVisibilityChange::DoNotChange;
/// How this menu should set the game pause state when it becomes top of the stack
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Behavior")
EGamePauseChange GamePauseSetting = EGamePauseChange::DoNotChange;
virtual void EmbedInParent();
public: public:
/// Close this menu level
/**
* @brief Open this menu. You should only call this if you're NOT using this in a UMenuStack, because the stack will
* call it for you when you add this menu to it
* @param bIsRegainedFocus Set this to true if the reason this menu is opening is that it regained focus in a stack
*/
UFUNCTION(BlueprintCallable)
void Open(bool bIsRegainedFocus = false);
/**
* @brief Close this menu.
* @param bWasCancel Set this to true if the reason for closure was a cancellation action
*/
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void Close(bool bWasCancel); void Close(bool bWasCancel);