256 lines
7.3 KiB
C++
256 lines
7.3 KiB
C++
#include "PromptWidget.h"
|
|
#include "UtilityLibrary.h"
|
|
#include "PlayerControllerBase.h"
|
|
#include "Engine/Engine.h"
|
|
#include "GameFramework/InputDeviceSubsystem.h"
|
|
#include "InputAction.h"
|
|
#include "InputMappingContext.h"
|
|
#include "Widgets/SOverlay.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
#include "Widgets/Layout/SScaleBox.h"
|
|
|
|
//
|
|
// Atlas contents:
|
|
//
|
|
// Row 1: Keyboard Button no Glyph, Left Mouse, Middle Mouse, Right Mouse
|
|
// Row 2: Left Trigger, Right Trigger, Left Shoulder, Right Shoulder
|
|
// Row 3: XBFace Down, XBFace Left, XBFace Up, XBFace Right
|
|
// Row 4: PSFace Down, PSFace Left, PSFace Up, PSFace Right
|
|
// Row 5: Arrow Down, Arrow Left, Arrow Up, Arrow Right
|
|
// Row 6: DPad Down, DPad Left, DPad Up, DPad Right
|
|
// Row 7: Space Bar, unused, unused, unused
|
|
// Row 8: unused, unused, unused, unused.
|
|
|
|
int32 UlxPromptWidget::ChooseIcon(bool Playstation, FKey Key) const
|
|
{
|
|
// Mouse buttons (row 1)
|
|
if (Key == EKeys::LeftMouseButton) return 1;
|
|
if (Key == EKeys::MiddleMouseButton) return 2;
|
|
if (Key == EKeys::RightMouseButton) return 3;
|
|
|
|
// Gamepad triggers and shoulders (row 2)
|
|
if (Key == EKeys::Gamepad_LeftTrigger) return 4;
|
|
if (Key == EKeys::Gamepad_RightTrigger) return 5;
|
|
if (Key == EKeys::Gamepad_LeftShoulder) return 6;
|
|
if (Key == EKeys::Gamepad_RightShoulder) return 7;
|
|
|
|
// Gamepad Face buttons (rows 3 and 4)
|
|
if (Key == EKeys::Gamepad_FaceButton_Bottom) return Playstation ? 12 : 8;
|
|
if (Key == EKeys::Gamepad_FaceButton_Left) return Playstation ? 13 : 9;
|
|
if (Key == EKeys::Gamepad_FaceButton_Top) return Playstation ? 14 : 10;
|
|
if (Key == EKeys::Gamepad_FaceButton_Right) return Playstation ? 15 : 11;
|
|
|
|
// Arrow keys (row 5)
|
|
if (Key == EKeys::Down) return 16;
|
|
if (Key == EKeys::Left) return 17;
|
|
if (Key == EKeys::Up) return 18;
|
|
if (Key == EKeys::Right) return 19;
|
|
|
|
// Gamepad D-Pad (row 6)
|
|
if (Key == EKeys::Gamepad_DPad_Down) return 20;
|
|
if (Key == EKeys::Gamepad_DPad_Left) return 21;
|
|
if (Key == EKeys::Gamepad_DPad_Up) return 22;
|
|
if (Key == EKeys::Gamepad_DPad_Right) return 23;
|
|
|
|
// Space bar (row 7)
|
|
if (Key == EKeys::SpaceBar) return 24;
|
|
|
|
// No icon for this key. Use the blank icon with a label.
|
|
return 0;
|
|
}
|
|
|
|
void UlxPromptWidget::ChooseAppearance(int32 &OutIcon, FString &OutGlyph)
|
|
{
|
|
FKey Key = (ControllerType == ElxControllerType::KeyboardMouse) ? KeyboardKey : GamepadKey;
|
|
OutIcon = ChooseIcon(ControllerType == ElxControllerType::PlayStationGamepad, Key);
|
|
if (OutIcon == 0) OutGlyph = Key.GetDisplayName().ToString();
|
|
else OutGlyph = TEXT("");
|
|
}
|
|
|
|
void UlxPromptWidget::OnHardwareDeviceChanged(const FPlatformUserId UserId, const FInputDeviceId DeviceId)
|
|
{
|
|
ElxControllerType Type = UlxUtilityLibrary::DetectControllerType(GetOwningLocalPlayer());
|
|
if (ControllerType != Type)
|
|
{
|
|
ControllerType = Type;
|
|
SynchronizeProperties();
|
|
}
|
|
}
|
|
|
|
FBox2f UlxPromptWidget::GetIconUVs(int32 IconIndex)
|
|
{
|
|
const float ColWidth = 1.0f / 4.0f;
|
|
const float RowHeight = 1.0f / 8.0f;
|
|
int32 Col = IconIndex % 4;
|
|
int32 Row = IconIndex / 4;
|
|
float U = Col * ColWidth;
|
|
float V = Row * RowHeight;
|
|
return FBox2f(FVector2f(U, V), FVector2f(U + ColWidth, V + RowHeight));
|
|
}
|
|
|
|
FMargin UlxPromptWidget::GetScaledMargins() const
|
|
{
|
|
return FMargin(
|
|
GlyphMargins.Left * Size.X,
|
|
GlyphMargins.Top * Size.Y,
|
|
GlyphMargins.Right * Size.X,
|
|
GlyphMargins.Bottom * Size.Y);
|
|
}
|
|
|
|
void UlxPromptWidget::SynchronizeProperties()
|
|
{
|
|
Super::SynchronizeProperties();
|
|
if (!MyImage.IsValid()) return;
|
|
|
|
int32 Icon = 0;
|
|
FString Glyph;
|
|
ChooseAppearance(Icon, Glyph);
|
|
|
|
MyBrush.SetUVRegion(GetIconUVs(Icon));
|
|
MyImage->InvalidateImage();
|
|
MyBox->SetWidthOverride(Size.X);
|
|
MyBox->SetHeightOverride(Size.Y);
|
|
const float Extra = Depressed ? 0.05f : 0.0f;
|
|
const FMargin ExtraPadding(Extra * Size.X, Extra * Size.Y, Extra * Size.X, Extra * Size.Y);
|
|
MyImageSlot->SetPadding(ExtraPadding);
|
|
MyGlyphSlot->SetPadding(GetScaledMargins() + ExtraPadding);
|
|
MyGlyph->SetColorAndOpacity(GlyphColor);
|
|
|
|
if (!Glyph.IsEmpty())
|
|
{
|
|
MyGlyph->SetText(FText::FromString(Glyph));
|
|
MyGlyph->SetVisibility(EVisibility::HitTestInvisible);
|
|
}
|
|
else
|
|
{
|
|
MyGlyph->SetVisibility(EVisibility::Collapsed);
|
|
}
|
|
}
|
|
|
|
void UlxPromptWidget::SetSize(FVector2D InSize)
|
|
{
|
|
if (Size != InSize)
|
|
{
|
|
Size = InSize;
|
|
SynchronizeProperties();
|
|
}
|
|
}
|
|
|
|
void UlxPromptWidget::SetGlyphMargins(FMargin InMargins)
|
|
{
|
|
if (GlyphMargins != InMargins)
|
|
{
|
|
GlyphMargins = InMargins;
|
|
SynchronizeProperties();
|
|
}
|
|
}
|
|
|
|
void UlxPromptWidget::SetGlyphColor(FLinearColor InColor)
|
|
{
|
|
if (GlyphColor != InColor)
|
|
{
|
|
GlyphColor = InColor;
|
|
SynchronizeProperties();
|
|
}
|
|
}
|
|
|
|
void UlxPromptWidget::SetDepressed(bool InDepressed)
|
|
{
|
|
if (Depressed != InDepressed)
|
|
{
|
|
Depressed = InDepressed;
|
|
SynchronizeProperties();
|
|
}
|
|
}
|
|
|
|
void UlxPromptWidget::SetKeys(FKey InGamepadKey, FKey InKeyboardKey)
|
|
{
|
|
if ((GamepadKey != InGamepadKey) || (KeyboardKey != InKeyboardKey))
|
|
{
|
|
GamepadKey = InGamepadKey;
|
|
KeyboardKey = InKeyboardKey;
|
|
SynchronizeProperties();
|
|
}
|
|
}
|
|
|
|
void UlxPromptWidget::SetKeysFromBindings(const UInputMappingContext* InputMappingContext, const UInputAction* EnhancedInputAction)
|
|
{
|
|
check(InputMappingContext);
|
|
check(EnhancedInputAction);
|
|
|
|
FKey NewFirstKey;
|
|
FKey NewGamepadKey;
|
|
FKey NewKeyboardKey;
|
|
|
|
for (const FEnhancedActionKeyMapping& Mapping : InputMappingContext->GetMappings())
|
|
{
|
|
if (Mapping.Action != EnhancedInputAction) continue;
|
|
FKey Key = Mapping.Key;
|
|
if (Key.IsDigital())
|
|
{
|
|
if (!NewFirstKey.IsValid()) NewFirstKey = Mapping.Key;
|
|
if (Key.IsTouch()) { /* not supported */ }
|
|
else if (Key.IsGesture()) { /* not supported */ }
|
|
else if (Key.IsGamepadKey()) { if (!NewGamepadKey.IsValid()) NewGamepadKey = Key; }
|
|
else { if (!NewKeyboardKey.IsValid()) NewKeyboardKey = Key; }
|
|
}
|
|
}
|
|
|
|
if (!NewGamepadKey.IsValid()) NewGamepadKey = NewFirstKey;
|
|
if (!NewKeyboardKey.IsValid()) NewKeyboardKey = NewFirstKey;
|
|
SetKeys(NewGamepadKey, NewKeyboardKey);
|
|
}
|
|
|
|
TSharedRef<SWidget> UlxPromptWidget::RebuildWidget()
|
|
{
|
|
if (!IsDesignTime())
|
|
{
|
|
ControllerType = UlxUtilityLibrary::DetectControllerType(GetOwningLocalPlayer());
|
|
if (UInputDeviceSubsystem* IDS = GEngine->GetEngineSubsystem<UInputDeviceSubsystem>())
|
|
{
|
|
IDS->OnInputHardwareDeviceChanged.AddDynamic(this, &UlxPromptWidget::OnHardwareDeviceChanged);
|
|
}
|
|
}
|
|
|
|
MyBrush.SetResourceObject(ButtonAtlas.Get());
|
|
|
|
SAssignNew(MyImage, SImage).Image(&MyBrush);
|
|
|
|
SAssignNew(MyGlyph, STextBlock);
|
|
SAssignNew(MyScaleBox, SScaleBox)
|
|
.Stretch(EStretch::ScaleToFit)
|
|
[ MyGlyph.ToSharedRef() ];
|
|
|
|
MyOverlay = SNew(SOverlay);
|
|
MyOverlay->AddSlot().Expose(MyImageSlot)
|
|
[ MyImage.ToSharedRef() ];
|
|
MyOverlay->AddSlot().HAlign(HAlign_Fill).VAlign(VAlign_Fill).Expose(MyGlyphSlot)
|
|
[ MyScaleBox.ToSharedRef() ];
|
|
|
|
SAssignNew(MyBox, SBox)
|
|
[ MyOverlay.ToSharedRef() ];
|
|
|
|
SynchronizeProperties();
|
|
return MyBox.ToSharedRef();
|
|
}
|
|
|
|
void UlxPromptWidget::ReleaseSlateResources(bool bReleaseChildren)
|
|
{
|
|
Super::ReleaseSlateResources(bReleaseChildren);
|
|
if (!IsDesignTime())
|
|
{
|
|
if (UInputDeviceSubsystem* IDS = GEngine->GetEngineSubsystem<UInputDeviceSubsystem>())
|
|
{
|
|
IDS->OnInputHardwareDeviceChanged.RemoveDynamic(this, &UlxPromptWidget::OnHardwareDeviceChanged);
|
|
}
|
|
}
|
|
MyBox.Reset();
|
|
MyOverlay.Reset();
|
|
MyImage.Reset();
|
|
MyScaleBox.Reset();
|
|
MyGlyph.Reset();
|
|
MyImageSlot = nullptr;
|
|
MyGlyphSlot = nullptr;
|
|
}
|