Compare commits

..

4 Commits

7 changed files with 122 additions and 5 deletions

View File

@ -1,6 +1,7 @@
#include "StevesGameSubsystem.h"
#include "EngineUtils.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "StevesGameViewportClientBase.h"
#include "StevesPluginSettings.h"
@ -107,6 +108,34 @@ TSoftObjectPtr<UInputAction> UStevesGameSubsystem::FindEnhancedInputAction(const
return nullptr;
}
void UStevesGameSubsystem::RegisterInterestInEnhancedInputAction(const UInputAction* Action, ETriggerEvent TriggerEvent)
{
// Avoid registering duplicate interest
FEnhancedInputInterest Interest(Action, TriggerEvent);
if (!RegisteredEnhancedInputActionInterests.Contains(Interest))
{
if (auto GI = GetGameInstance())
{
if (auto PC = GI->GetFirstLocalPlayerController())
{
if (auto EIC = Cast<UEnhancedInputComponent>(PC->InputComponent))
{
EIC->BindAction(Action, TriggerEvent, this, &ThisClass::EnhancedInputActionTriggered);
RegisteredEnhancedInputActionInterests.Add(Interest);
}
}
}
}
}
void UStevesGameSubsystem::EnhancedInputActionTriggered(const FInputActionInstance& InputActionInstance)
{
OnEnhancedInputActionTriggered.Broadcast(InputActionInstance.GetSourceAction(), InputActionInstance.GetTriggerEvent());
}
void UStevesGameSubsystem::InitTheme()
{
DefaultUiTheme = LoadObject<UUiTheme>(nullptr, *DefaultUiThemePath, nullptr);

View File

@ -1,6 +1,7 @@
#include "StevesUI/FocusableButton.h"
#include "StevesUI/SFocusableButton.h"
#include "Components/ButtonSlot.h"
#include "Framework/Application/NavigationConfig.h"
UFocusableButton::UFocusableButton(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
@ -43,6 +44,31 @@ void UFocusableButton::RefreshFocussedStyle_Implementation()
FocussedStyle.Normal = FocussedStyle.Hovered;
}
void UFocusableButton::SimulatePress()
{
if (MyButton)
{
// In order to get the visual change we need to call SButton::Press() and SButton::Release(), but they're both private
// The only public method we can use to simulate the click properly is OnKeyDown/Up or OnMouseButtonDown/Up
// Use Virtual_Accept since that is general
FKeyEvent KeyEvent(EKeys::Virtual_Accept, FModifierKeysState(), 0, false, 0, 0);
MyButton->OnKeyDown(MyButton->GetCachedGeometry(), KeyEvent);
}
}
void UFocusableButton::SimulateRelease()
{
if (MyButton)
{
// In order to get the visual change we need to call SButton::Press() and SButton::Release(), but they're both private
// The only public method we can use to simulate the click properly is OnKeyDown/Up or OnMouseButtonDown/Up
// Use Virtual_Accept since that is general
FKeyEvent KeyEvent(EKeys::Virtual_Accept, FModifierKeysState(), 0, false, 0, 0);
MyButton->OnKeyUp(MyButton->GetCachedGeometry(), KeyEvent);
}
}
void UFocusableButton::SlateHandleFocusReceived()
{
ApplyFocusStyle();

View File

@ -27,6 +27,19 @@ bool UFocusableUserWidget::TakeFocusIfDesired_Implementation()
return false;
}
FReply UFocusableUserWidget::NativeOnFocusReceived(const FGeometry& InGeometry, const FFocusEvent& InFocusEvent)
{
FReply Reply = Super::NativeOnFocusReceived(InGeometry, InFocusEvent);
if (!Reply.IsEventHandled())
{
SetFocusProperly();
Reply.Handled();
}
return Reply;
}
void UFocusableUserWidget::NativeConstruct()
{
Super::NativeConstruct();

View File

@ -150,7 +150,7 @@ void UOptionWidgetBase::SetFocusProperly_Implementation()
if (GamepadVersion && GamepadVersion->IsVisible())
GamepadVersion->SetFocus();
else if (MouseUpButton && MouseDownButton)
MouseUpButton->GetIsEnabled() ? MouseUpButton->SetFocus() : MouseDownButton->SetFocus();
MouseUpButton->GetVisibility() == ESlateVisibility::Visible ? MouseUpButton->SetFocus() : MouseDownButton->SetFocus();
}
void UOptionWidgetBase::SetSelectedIndex(int NewIndex)
@ -168,9 +168,9 @@ void UOptionWidgetBase::SetSelectedIndex(int NewIndex)
const bool CanDecrease = SelectedIndex > 0;
const bool CanIncrease = SelectedIndex < Options.Num() - 1;
if (MouseDownButton)
MouseDownButton->SetIsEnabled(CanDecrease);
MouseDownButton->SetVisibility(CanDecrease ? ESlateVisibility::Visible : ESlateVisibility::Hidden);
if (MouseUpButton)
MouseUpButton->SetIsEnabled(CanIncrease);
MouseUpButton->SetVisibility(CanIncrease ? ESlateVisibility::Visible : ESlateVisibility::Hidden);
if (GamepadDownImage)
GamepadDownImage->SetVisibility(CanDecrease ? ESlateVisibility::Visible : ESlateVisibility::Hidden);
if (GamepadUpImage)

View File

@ -10,12 +10,14 @@
#include "StevesUI/FocusSystem.h"
#include "StevesUI/InputImage.h"
#include "StevesUI/UiTheme.h"
#include "Templates/TypeHash.h"
#include "StevesGameSubsystem.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInputModeChanged, int, PlayerIndex, EInputMode, InputMode);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnEnhancedInputMappingsChanged);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWindowForegroundChanged, bool, bFocussed);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnEnhancedInputActionTriggered, const UInputAction*, Action, ETriggerEvent, TriggeredEvent);
/// Entry point for all the top-level features of the helper system
UCLASS(Config=Game)
@ -33,7 +35,33 @@ protected:
/// so that it's included when packaging
UPROPERTY(Config)
FString DefaultUiThemePath;
struct FEnhancedInputInterest
{
TWeakObjectPtr<const UInputAction> Action;
ETriggerEvent Trigger;
FEnhancedInputInterest(const UInputAction* TheAction, ETriggerEvent TheTriggerEvent) : Action(TheAction), Trigger(TheTriggerEvent) {}
friend uint32 GetTypeHash(const FEnhancedInputInterest& Arg)
{
return HashCombine(GetTypeHash(Arg.Action), GetTypeHash(Arg.Trigger));
}
friend bool operator==(const FEnhancedInputInterest& Lhs, const FEnhancedInputInterest& RHS)
{
return Lhs.Action == RHS.Action
&& Lhs.Trigger == RHS.Trigger;
}
friend bool operator!=(const FEnhancedInputInterest& Lhs, const FEnhancedInputInterest& RHS)
{
return !(Lhs == RHS);
}
};
TSet<FEnhancedInputInterest> RegisteredEnhancedInputActionInterests;
public:
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
@ -143,7 +171,9 @@ protected:
TSoftObjectPtr<UDataTable> GetGamepadImages(int PlayerIndex, const UUiTheme* Theme);
UPaperSprite* GetImageSpriteFromTable(const FKey& Key, const TSoftObjectPtr<UDataTable>& Asset);
UFUNCTION()
void EnhancedInputActionTriggered(const FInputActionInstance& InputActionInstance);
public:
/// Event raised when main input mode changed between gamepad and keyboard / mouse (for any of axis / button events)
@ -167,6 +197,11 @@ public:
/// plugin provides NO events to monitor it (sigh)
UPROPERTY(BlueprintAssignable)
FOnEnhancedInputMappingsChanged OnEnhancedInputMappingsChanged;
/// Event fired when an enhanced input event that an interest has previously been registered in triggers.
/// Nothing will fire on this event unless you call RegisterInterestInEnhancedInputAction to listen for it.
UPROPERTY(BlueprintAssignable)
FOnEnhancedInputActionTriggered OnEnhancedInputActionTriggered;
/// Event raised when the game window's foreground status changes
UPROPERTY(BlueprintAssignable)
@ -301,4 +336,10 @@ public:
*/
TSoftObjectPtr<UInputAction> FindEnhancedInputAction(const FString& Name);
/// Register an interest in an enhanced input action. Calling this will result in OnEnhancedInputActionTriggered being called
/// when this action is triggered.
/// This is mainly for use in UI bindings. You only need to call it once for each UI-specific action.
UFUNCTION(BlueprintCallable)
void RegisterInterestInEnhancedInputAction(const UInputAction* Action, ETriggerEvent TriggerEvent);
};

View File

@ -38,6 +38,12 @@ public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
bool bTakeFocusOnHover = true;
// Simulate a button press
UFUNCTION(BlueprintCallable)
void SimulatePress();
// Simulate a button release
UFUNCTION(BlueprintCallable)
void SimulateRelease();
protected:
FButtonStyle FocussedStyle;

View File

@ -25,6 +25,8 @@ protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Focus")
int AutomaticFocusPriority = 0;
virtual FReply NativeOnFocusReceived(const FGeometry& InGeometry, const FFocusEvent& InFocusEvent) override;
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