Files
integration/Source/Integration/PromptWidget.cpp
2026-05-04 11:55:08 -04:00

193 lines
5.5 KiB
C++

#include "PromptWidget.h"
#include "PlayerControllerBase.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)
{
UWorld* World = GetWorld();
APlayerController* PC = World ? World->GetFirstPlayerController() : nullptr;
AlxPlayerControllerBase* LPC = Cast<AlxPlayerControllerBase>(PC);
ElxInputMode Mode = LPC ? LPC->CurrentInputMode : ElxInputMode::KeyboardMouse;
FKey Key = (Mode == ElxInputMode::KeyboardMouse) ? KeyboardKey : GamepadKey;
OutIcon = ChooseIcon(Mode == ElxInputMode::PlayStationGamepad, Key);
if (OutIcon == 0) OutGlyph = Key.GetDisplayName().ToString();
else OutGlyph = TEXT("");
}
FBox2f UlxPromptWidget::GetIconUVs(int32 IconIndex)
{
const float ColWidth = 1.0f / 4.0f;
const float RowHeight = 1.0f / 8.0f;
float U = (IconIndex % 4) * ColWidth;
float V = (IconIndex / 4) * 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();
MyImage->SetDesiredSizeOverride(Size);
MyGlyphSlot->SetPadding(GetScaledMargins());
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::SetKeys(FKey InGamepadKey, FKey InKeyboardKey)
{
if ((GamepadKey != InGamepadKey) || (KeyboardKey != InKeyboardKey))
{
GamepadKey = InGamepadKey;
KeyboardKey = InKeyboardKey;
SynchronizeProperties();
}
}
TSharedRef<SWidget> UlxPromptWidget::RebuildWidget()
{
int32 Icon = 0;
FString Glyph;
ChooseAppearance(Icon, Glyph);
MyBrush.SetResourceObject(ButtonAtlas);
MyBrush.ImageSize = Size;
MyBrush.SetUVRegion(GetIconUVs(Icon));
SAssignNew(MyImage, SImage).Image(&MyBrush);
EVisibility GlyphVisibility = Glyph.IsEmpty() ? EVisibility::Collapsed : EVisibility::HitTestInvisible;
SAssignNew(MyGlyph, STextBlock)
.Text(FText::FromString(Glyph))
.ColorAndOpacity(GlyphColor)
.Visibility(GlyphVisibility);
SAssignNew(MyScaleBox, SScaleBox)
.Stretch(EStretch::ScaleToFit)
[ MyGlyph.ToSharedRef() ];
MyOverlay = SNew(SOverlay)
+ SOverlay::Slot() [ MyImage.ToSharedRef() ];
MyOverlay->AddSlot().Padding(GetScaledMargins()).HAlign(HAlign_Fill).VAlign(VAlign_Fill).Expose(MyGlyphSlot)
[ MyScaleBox.ToSharedRef() ];
return MyOverlay.ToSharedRef();
}
void UlxPromptWidget::ReleaseSlateResources(bool bReleaseChildren)
{
Super::ReleaseSlateResources(bReleaseChildren);
MyOverlay.Reset();
MyImage.Reset();
MyScaleBox.Reset();
MyGlyph.Reset();
MyGlyphSlot = nullptr;
}