#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. void UlxPromptWidget::CalcAppearance(int32& OutIcon, FString& OutGlyph) const { UWorld* World = GetWorld(); APlayerController* PC = World ? World->GetFirstPlayerController() : nullptr; AlxPlayerControllerBase* LPC = Cast(PC); ElxInputMode Mode = LPC ? LPC->CurrentInputMode : ElxInputMode::KeyboardMouse; if (Mode == ElxInputMode::KeyboardMouse) { CalcKeyboardAppearance(OutIcon, OutGlyph); } else { CalcGamepadAppearance(Mode, OutIcon, OutGlyph); } } void UlxPromptWidget::CalcKeyboardAppearance(int32& OutIcon, FString& OutGlyph) const { // Fixed-icon keys: no glyph needed. if (KeyboardKey == EKeys::LeftMouseButton) { OutIcon = 1; OutGlyph = TEXT(""); return; } if (KeyboardKey == EKeys::MiddleMouseButton) { OutIcon = 2; OutGlyph = TEXT(""); return; } if (KeyboardKey == EKeys::RightMouseButton) { OutIcon = 3; OutGlyph = TEXT(""); return; } if (KeyboardKey == EKeys::SpaceBar) { OutIcon = 24; OutGlyph = TEXT(""); return; } if (KeyboardKey == EKeys::Down) { OutIcon = 16; OutGlyph = TEXT(""); return; } if (KeyboardKey == EKeys::Left) { OutIcon = 17; OutGlyph = TEXT(""); return; } if (KeyboardKey == EKeys::Up) { OutIcon = 18; OutGlyph = TEXT(""); return; } if (KeyboardKey == EKeys::Right) { OutIcon = 19; OutGlyph = TEXT(""); return; } // Generic keyboard key: blank icon with the key name as glyph. OutIcon = 0; OutGlyph = KeyboardKey.GetDisplayName().ToString(); } void UlxPromptWidget::CalcGamepadAppearance(ElxInputMode Mode, int32& OutIcon, FString& OutGlyph) const { OutGlyph = TEXT(""); // Triggers and shoulders. if (GamepadKey == EKeys::Gamepad_LeftTrigger) { OutIcon = 4; return; } if (GamepadKey == EKeys::Gamepad_RightTrigger) { OutIcon = 5; return; } if (GamepadKey == EKeys::Gamepad_LeftShoulder) { OutIcon = 6; return; } if (GamepadKey == EKeys::Gamepad_RightShoulder) { OutIcon = 7; return; } // Face buttons — Xbox vs PlayStation. bool bPS = (Mode == ElxInputMode::PlayStationGamepad); if (GamepadKey == EKeys::Gamepad_FaceButton_Bottom) { OutIcon = bPS ? 12 : 8; return; } if (GamepadKey == EKeys::Gamepad_FaceButton_Left) { OutIcon = bPS ? 13 : 9; return; } if (GamepadKey == EKeys::Gamepad_FaceButton_Top) { OutIcon = bPS ? 14 : 10; return; } if (GamepadKey == EKeys::Gamepad_FaceButton_Right) { OutIcon = bPS ? 15 : 11; return; } // DPad. if (GamepadKey == EKeys::Gamepad_DPad_Down) { OutIcon = 20; return; } if (GamepadKey == EKeys::Gamepad_DPad_Left) { OutIcon = 21; return; } if (GamepadKey == EKeys::Gamepad_DPad_Up) { OutIcon = 22; return; } if (GamepadKey == EKeys::Gamepad_DPad_Right) { OutIcon = 23; return; } // Fallback: blank key with name. OutIcon = 0; OutGlyph = GamepadKey.GetDisplayName().ToString(); } 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; CalcAppearance(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) { Size = InSize; SynchronizeProperties(); } void UlxPromptWidget::SetGlyphMargins(FMargin InMargins) { GlyphMargins = InMargins; SynchronizeProperties(); } void UlxPromptWidget::SetGlyphColor(FLinearColor InColor) { GlyphColor = InColor; SynchronizeProperties(); } void UlxPromptWidget::SetKeys(FKey InGamepadKey, FKey InKeyboardKey) { GamepadKey = InGamepadKey; KeyboardKey = InKeyboardKey; SynchronizeProperties(); } TSharedRef UlxPromptWidget::RebuildWidget() { int32 Icon = 0; FString Glyph; CalcAppearance(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; }