Merge branch 'master' of github.com:sinbad/StevesUEHelpers

This commit is contained in:
Steve Streeting 2020-10-23 11:57:33 +01:00
commit 0fd38e1869
10 changed files with 152 additions and 50 deletions

View File

@ -21,6 +21,8 @@ which makes a bunch of things better:
* Events raised whenever a player uses a different input method (in game, and in UI)
(Actually reliable and not dependent on vagaries of input mappings / differences between UI and game input)
:heart: **[Support my work on Patreon!](https://www.patreon.com/stevestreeting)**
## Installing this plugin
### Cloning

View File

@ -149,7 +149,11 @@ void UInputImage::UpdateImageFromTable(const FKey& InKey, const TSoftObjectPtr<U
// Rows are named the same as the key name
const auto SpriteRow = Table->FindRow<FKeySprite>(InKey.GetFName(), "Find Key Image");
if (SpriteRow)
SetBrushFromAtlasInterface(SpriteRow->Sprite);
{
// Match size is needed incase size has changed
// Need to make it update region in case inside a scale box or something else that needs to adjust
SetBrushFromAtlasInterface(SpriteRow->Sprite, true);
}
}
UUiTheme* UInputImage::GetTheme()

View File

@ -5,6 +5,7 @@
#include "StevesUEHelpers.h"
#include "StevesUI/MenuStack.h"
#include "Components/ContentWidget.h"
#include "Kismet/GameplayStatics.h"
void UMenuBase::Close(bool bWasCancel)
{
@ -13,26 +14,19 @@ void UMenuBase::Close(bool bWasCancel)
if (ParentStack.IsValid())
{
ParentStack->PopMenuIfTop(this, bWasCancel);
} else
{
// standalone mode
RemoveFromParent();
PreviousFocusWidget.Reset();
}
}
void UMenuBase::AddedToStack(UMenuStack* Parent)
{
ParentStack = MakeWeakObjectPtr(Parent);
if (bEmbedInParentContainer)
EmbedInParent();
else
AddToViewport();
SetVisibility(ESlateVisibility::Visible);
auto GS = GetStevesGameSubsystem(GetWorld());
if (bRequestFocus &&
GS && (GS->GetLastInputModeUsed() != EInputMode::Gamepad || GS->GetLastInputModeUsed() != EInputMode::Keyboard))
{
SetFocusProperly();
}
Open(false);
}
@ -73,16 +67,7 @@ void UMenuBase::SupercededInStack()
void UMenuBase::RegainedFocusInStack()
{
if (bEmbedInParentContainer)
EmbedInParent();
else
AddToViewport();
SetVisibility(ESlateVisibility::Visible);
if (bRequestFocus)
{
SetFocusProperly();
}
Open(true);
}
@ -94,6 +79,64 @@ void UMenuBase::EmbedInParent()
ParentStack->MenuContainer->SetContent(this);
}
else
UE_LOG(LogCustomUI, 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

@ -123,7 +123,7 @@ void UMenuStack::PopMenuIfTop(UMenuBase* UiMenuBase, bool bWasCancel)
}
else
{
UE_LOG(LogCustomUI, Error, TEXT("Tried to pop menu %s but it wasn't the top level"), *UiMenuBase->GetName());
UE_LOG(LogStevesUI, Error, TEXT("Tried to pop menu %s but it wasn't the top level"), *UiMenuBase->GetName());
}
}

View File

@ -19,29 +19,29 @@ void UOptionWidgetBase::NativeConstruct()
ClearOptions();
}
else
UE_LOG(LogCustomUI, Error, TEXT("StevesGameSubsystem is missing!"));
UE_LOG(LogStevesUI, Error, TEXT("StevesGameSubsystem is missing!"));
// Check we can bind everything we need, bind click
if (!MouseVersion)
UE_LOG(LogCustomUI, Error, TEXT("%s should have a MouseVersion instance."), *this->GetClass()->GetName());
UE_LOG(LogStevesUI, Error, TEXT("%s should have a MouseVersion instance."), *this->GetClass()->GetName());
if (!GamepadVersion)
UE_LOG(LogCustomUI, Error, TEXT("%s should have a GamepadVersion instance."), *this->GetClass()->GetName());
UE_LOG(LogStevesUI, Error, TEXT("%s should have a GamepadVersion instance."), *this->GetClass()->GetName());
if (MouseUpButton)
MouseUpButton->OnClicked.AddDynamic(this, &UOptionWidgetBase::MouseUpClicked);
else
UE_LOG(LogCustomUI, Error, TEXT("%s should have a MouseUpButton instance."), *this->GetClass()->GetName());
UE_LOG(LogStevesUI, Error, TEXT("%s should have a MouseUpButton instance."), *this->GetClass()->GetName());
if (MouseDownButton)
MouseDownButton->OnClicked.AddDynamic(this, &UOptionWidgetBase::MouseDownClicked);
else
UE_LOG(LogCustomUI, Error, TEXT("%s should have a MouseDownButton instance."), *this->GetClass()->GetName());
UE_LOG(LogStevesUI, Error, TEXT("%s should have a MouseDownButton instance."), *this->GetClass()->GetName());
if (!MouseUpImage)
UE_LOG(LogCustomUI, Error, TEXT("%s should have a MouseUpImage instance."), *this->GetClass()->GetName());
UE_LOG(LogStevesUI, Error, TEXT("%s should have a MouseUpImage instance."), *this->GetClass()->GetName());
if (!MouseDownImage)
UE_LOG(LogCustomUI, Error, TEXT("%s should have a MouseDownImage instance."), *this->GetClass()->GetName());
UE_LOG(LogStevesUI, Error, TEXT("%s should have a MouseDownImage instance."), *this->GetClass()->GetName());
if (!GamepadUpImage)
UE_LOG(LogCustomUI, Error, TEXT("%s should have a GamepadUpImage instance."), *this->GetClass()->GetName());
UE_LOG(LogStevesUI, Error, TEXT("%s should have a GamepadUpImage instance."), *this->GetClass()->GetName());
if (!GamepadDownImage)
UE_LOG(LogCustomUI, Error, TEXT("%s should have a GamepadDownImage instance."), *this->GetClass()->GetName());
UE_LOG(LogStevesUI, Error, TEXT("%s should have a GamepadDownImage instance."), *this->GetClass()->GetName());
}

View File

@ -7,7 +7,7 @@
#include "Components/PanelWidget.h"
#include "Components/Widget.h"
DEFINE_LOG_CATEGORY(LogCustomUI);
DEFINE_LOG_CATEGORY(LogStevesUI);
UWidget* FindWidgetFromSlate(SWidget* SW, UWidget* Parent)
{

View File

@ -5,7 +5,7 @@
class UWidget;
class SWidget;
DECLARE_LOG_CATEGORY_EXTERN(LogCustomUI, Warning, Warning)
DECLARE_LOG_CATEGORY_EXTERN(LogStevesUI, Warning, Warning)
/**

View File

@ -14,7 +14,7 @@ class STEVESUEHELPERS_API UFocusableUserWidget : public UUserWidget
public:
/// UWidget::SetFocus is not virtual FFS. This does the same as SetFocus by default but can be overridden,
/// e.g. to delegate focus to specific children
UFUNCTION(BlueprintNativeEvent)
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void SetFocusProperly();
};

View File

@ -10,10 +10,38 @@
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
/// to the viewport or parent container, and removed again, and what it does when receiving
/// focus.
UENUM(BlueprintType)
enum class EInputModeChange : uint8
{
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)
class STEVESUEHELPERS_API UMenuBase : public UFocusablePanel
{
@ -29,23 +57,48 @@ protected:
/// 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 previously selected widget if regaining focus
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Focus")
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
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Layout")
bool bEmbedInParentContainer = true;
/// 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.
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Behavior")
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:
/// 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)
void Close(bool bWasCancel);

View File

@ -9,7 +9,7 @@
"CreatedByURL" : "https://www.stevestreeting.com",
"DocsURL" : "",
"MarketplaceURL" : "",
"SupportURL" : "",
"SupportURL" : "https://github.com/sinbad/StevesUEHelpers",
"EnabledByDefault" : true,
"CanContainContent" : false,
"IsBetaVersion" : true,