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
@ -180,4 +182,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

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,