Fix MVP menu startup and mouse flow

This commit is contained in:
2026-05-18 22:14:17 -07:00
parent 5566d846e1
commit 3aac902142
10 changed files with 321 additions and 35 deletions
+214 -24
View File
@@ -2,6 +2,7 @@
#include "AgrarianMvpFrontendWidget.h"
#include "GameFramework/PlayerController.h"
#include "InputCoreTypes.h"
#include "Rendering/DrawElements.h"
#include "Styling/CoreStyle.h"
@@ -32,7 +33,7 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
{
SetActiveScreen(EAgrarianMvpFrontendScreen::JoinServer);
ContinueFromActiveScreen();
return FReply::Handled();
}
}
@@ -41,13 +42,22 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
const FKey Key = InKeyEvent.GetKey();
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
{
SetActiveScreen(EAgrarianMvpFrontendScreen::Loading);
ContinueFromActiveScreen();
return FReply::Handled();
}
if (Key == EKeys::BackSpace || Key == EKeys::Escape)
{
SetActiveScreen(EAgrarianMvpFrontendScreen::CharacterSelection);
ReturnFromActiveScreen();
return FReply::Handled();
}
}
else if (ActiveScreen == EAgrarianMvpFrontendScreen::Loading)
{
const FKey Key = InKeyEvent.GetKey();
if (Key == EKeys::Enter || Key == EKeys::SpaceBar)
{
ContinueFromActiveScreen();
return FReply::Handled();
}
}
@@ -55,6 +65,89 @@ FReply UAgrarianMvpFrontendWidget::NativeOnKeyDown(const FGeometry& InGeometry,
return Super::NativeOnKeyDown(InGeometry, InKeyEvent);
}
FReply UAgrarianMvpFrontendWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
if (InMouseEvent.GetEffectingButton() != EKeys::LeftMouseButton)
{
return Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
}
const FVector2D LocalMousePosition = InGeometry.AbsoluteToLocal(InMouseEvent.GetScreenSpacePosition());
float Scale = 1.0f;
FVector2D PanelPosition = FVector2D::ZeroVector;
FVector2D PanelSize = FVector2D::ZeroVector;
if (!GetPanelLayout(InGeometry.GetLocalSize(), Scale, PanelPosition, PanelSize))
{
return Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
}
const float ContentX = PanelPosition.X + (44.0f * Scale);
const float ContentWidth = PanelSize.X - (88.0f * Scale);
if (ActiveScreen == EAgrarianMvpFrontendScreen::CharacterSelection)
{
const FVector2D CardSize((ContentWidth - (24.0f * Scale)) * 0.5f, 206.0f * Scale);
const FVector2D MaleCardPosition(ContentX, PanelPosition.Y + (142.0f * Scale));
const FVector2D FemaleCardPosition(ContentX + CardSize.X + (24.0f * Scale), MaleCardPosition.Y);
const FVector2D ButtonPosition(ContentX, PanelPosition.Y + PanelSize.Y - (88.0f * Scale));
const FVector2D ButtonSize(FMath::Min(ContentWidth, 280.0f * Scale), 52.0f * Scale);
if (IsPointInside(LocalMousePosition, MaleCardPosition, CardSize))
{
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultMale);
return FReply::Handled();
}
if (IsPointInside(LocalMousePosition, FemaleCardPosition, CardSize))
{
SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype::YoungAdultFemale);
return FReply::Handled();
}
if (IsPointInside(LocalMousePosition, ButtonPosition, ButtonSize))
{
ContinueFromActiveScreen();
return FReply::Handled();
}
}
else if (ActiveScreen == EAgrarianMvpFrontendScreen::JoinServer)
{
const float JoinContentX = PanelPosition.X + (48.0f * Scale);
const float JoinContentWidth = PanelSize.X - (96.0f * Scale);
const FVector2D ButtonPosition(JoinContentX, PanelPosition.Y + (300.0f * Scale));
const FVector2D ButtonSize(FMath::Min(JoinContentWidth, 330.0f * Scale), 58.0f * Scale);
const FVector2D BackButtonPosition(ButtonPosition.X + ButtonSize.X + (16.0f * Scale), ButtonPosition.Y);
const FVector2D BackButtonSize(FMath::Min(JoinContentWidth - ButtonSize.X - (16.0f * Scale), 180.0f * Scale), ButtonSize.Y);
if (IsPointInside(LocalMousePosition, ButtonPosition, ButtonSize))
{
ContinueFromActiveScreen();
return FReply::Handled();
}
if (BackButtonSize.X > 96.0f && IsPointInside(LocalMousePosition, BackButtonPosition, BackButtonSize))
{
ReturnFromActiveScreen();
return FReply::Handled();
}
}
else if (ActiveScreen == EAgrarianMvpFrontendScreen::Loading)
{
const float LoadingContentX = PanelPosition.X + (48.0f * Scale);
const float LoadingContentWidth = PanelSize.X - (96.0f * Scale);
const FVector2D ButtonPosition(LoadingContentX, PanelPosition.Y + (318.0f * Scale));
const FVector2D ButtonSize(FMath::Min(LoadingContentWidth, 310.0f * Scale), 56.0f * Scale);
if (IsPointInside(LocalMousePosition, ButtonPosition, ButtonSize))
{
ContinueFromActiveScreen();
return FReply::Handled();
}
}
return FReply::Handled();
}
void UAgrarianMvpFrontendWidget::SetActiveScreen(EAgrarianMvpFrontendScreen NewScreen)
{
ActiveScreen = NewScreen;
@@ -91,13 +184,10 @@ int32 UAgrarianMvpFrontendWidget::NativePaint(
LayerId = Super::NativePaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
const FVector2D Size = AllottedGeometry.GetLocalSize();
const float Scale = FMath::Clamp(UiScale, 0.75f, 1.5f);
constexpr float MinimumPanelMargin = 24.0f;
constexpr float PreferredPanelWidth = 780.0f;
constexpr float PreferredPanelHeight = 430.0f;
const FVector2D AvailablePanelSize(
FMath::Max(320.0f, Size.X - (MinimumPanelMargin * 2.0f)),
FMath::Max(240.0f, Size.Y - (MinimumPanelMargin * 2.0f)));
float Scale = 1.0f;
FVector2D PanelPosition = FVector2D::ZeroVector;
FVector2D PanelSize = FVector2D::ZeroVector;
GetPanelLayout(Size, Scale, PanelPosition, PanelSize);
const FLinearColor BackdropColor = bUseHighContrast ? FLinearColor(0.0f, 0.0f, 0.0f, 0.96f) : FLinearColor(0.015f, 0.018f, 0.014f, 0.92f);
const FLinearColor PanelColor = bUseHighContrast ? FLinearColor(0.0f, 0.0f, 0.0f, 0.98f) : FLinearColor(0.035f, 0.045f, 0.034f, 0.96f);
const FLinearColor AccentColor = bUseHighContrast ? FLinearColor(0.95f, 0.95f, 0.30f, 1.0f) : FLinearColor(0.45f, 0.72f, 0.40f, 1.0f);
@@ -110,13 +200,6 @@ int32 UAgrarianMvpFrontendWidget::NativePaint(
ESlateDrawEffect::None,
BackdropColor);
const FVector2D PanelSize(
FMath::Min(AvailablePanelSize.X, PreferredPanelWidth * Scale),
FMath::Min(AvailablePanelSize.Y, PreferredPanelHeight * Scale));
const FVector2D PanelPosition(
(Size.X - PanelSize.X) * 0.5f,
(Size.Y - PanelSize.Y) * 0.5f);
FSlateDrawElement::MakeBox(
OutDrawElements,
++LayerId,
@@ -153,6 +236,73 @@ int32 UAgrarianMvpFrontendWidget::NativePaint(
return LayerId;
}
bool UAgrarianMvpFrontendWidget::GetPanelLayout(const FVector2D& WidgetSize, float& OutScale, FVector2D& OutPanelPosition, FVector2D& OutPanelSize) const
{
OutScale = FMath::Clamp(UiScale, 0.75f, 1.5f);
constexpr float MinimumPanelMargin = 24.0f;
constexpr float PreferredPanelWidth = 780.0f;
constexpr float PreferredPanelHeight = 430.0f;
const FVector2D AvailablePanelSize(
FMath::Max(320.0f, WidgetSize.X - (MinimumPanelMargin * 2.0f)),
FMath::Max(240.0f, WidgetSize.Y - (MinimumPanelMargin * 2.0f)));
OutPanelSize = FVector2D(
FMath::Min(AvailablePanelSize.X, PreferredPanelWidth * OutScale),
FMath::Min(AvailablePanelSize.Y, PreferredPanelHeight * OutScale));
OutPanelPosition = FVector2D(
(WidgetSize.X - OutPanelSize.X) * 0.5f,
(WidgetSize.Y - OutPanelSize.Y) * 0.5f);
return WidgetSize.X > 0.0f && WidgetSize.Y > 0.0f;
}
bool UAgrarianMvpFrontendWidget::IsPointInside(const FVector2D& Point, const FVector2D& Position, const FVector2D& Size) const
{
return Point.X >= Position.X
&& Point.Y >= Position.Y
&& Point.X <= Position.X + Size.X
&& Point.Y <= Position.Y + Size.Y;
}
void UAgrarianMvpFrontendWidget::ContinueFromActiveScreen()
{
if (ActiveScreen == EAgrarianMvpFrontendScreen::CharacterSelection)
{
SetActiveScreen(EAgrarianMvpFrontendScreen::JoinServer);
return;
}
if (ActiveScreen == EAgrarianMvpFrontendScreen::JoinServer)
{
SetActiveScreen(EAgrarianMvpFrontendScreen::Loading);
return;
}
if (ActiveScreen == EAgrarianMvpFrontendScreen::Loading)
{
CompleteFrontendFlow();
}
}
void UAgrarianMvpFrontendWidget::ReturnFromActiveScreen()
{
if (ActiveScreen == EAgrarianMvpFrontendScreen::JoinServer)
{
SetActiveScreen(EAgrarianMvpFrontendScreen::CharacterSelection);
}
}
void UAgrarianMvpFrontendWidget::CompleteFrontendFlow()
{
if (APlayerController* PlayerController = GetOwningPlayer())
{
PlayerController->SetInputMode(FInputModeGameOnly());
PlayerController->bShowMouseCursor = false;
}
RemoveFromParent();
}
void UAgrarianMvpFrontendWidget::DrawMainMenu(
FSlateWindowElementList& OutDrawElements,
int32& LayerId,
@@ -200,8 +350,8 @@ void UAgrarianMvpFrontendWidget::DrawCharacterSelection(
const FSlateFontInfo CardTitleFont = FCoreStyle::GetDefaultFontStyle("Bold", FMath::RoundToInt(22.0f * Scale));
const FSlateFontInfo LabelFont = FCoreStyle::GetDefaultFontStyle("Regular", FMath::RoundToInt(15.0f * Scale));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Choose your first settler")), FVector2D(ContentX, PanelPosition.Y + (34.0f * Scale)), ContentWidth, TitleFont, FLinearColor(0.92f, 0.98f, 0.84f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("MVP placeholder landing page before entering Ground Zero.")), FVector2D(ContentX + (2.0f * Scale), PanelPosition.Y + (82.0f * Scale)), ContentWidth, BodyFont, FLinearColor(0.72f, 0.80f, 0.68f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Choose your first pioneer")), FVector2D(ContentX, PanelPosition.Y + (34.0f * Scale)), ContentWidth, TitleFont, FLinearColor(0.92f, 0.98f, 0.84f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Select the person who will step into Ground Zero.")), FVector2D(ContentX + (2.0f * Scale), PanelPosition.Y + (82.0f * Scale)), ContentWidth, BodyFont, FLinearColor(0.72f, 0.80f, 0.68f, 1.0f));
const FVector2D CardSize((ContentWidth - (24.0f * Scale)) * 0.5f, 206.0f * Scale);
const FVector2D MaleCardPosition(ContentX, PanelPosition.Y + (142.0f * Scale));
@@ -254,7 +404,18 @@ void UAgrarianMvpFrontendWidget::DrawCharacterSelection(
DrawCharacterCard(MaleCardPosition, FText::FromString(TEXT("Young adult male")), FText::FromString(TEXT("Average proportions, survival baseline, placeholder visual.")), FLinearColor(0.36f, 0.58f, 0.78f, 1.0f), SelectedCharacterArchetype == EAgrarianMvpCharacterArchetype::YoungAdultMale);
DrawCharacterCard(FemaleCardPosition, FText::FromString(TEXT("Young adult female")), FText::FromString(TEXT("Average proportions, survival baseline, placeholder visual.")), FLinearColor(0.56f, 0.68f, 0.46f, 1.0f), SelectedCharacterArchetype == EAgrarianMvpCharacterArchetype::YoungAdultFemale);
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::Format(FText::FromString(TEXT("Selected: {0}. Use Left/Right or A/D to choose; both choices enter the same MVP survival baseline.")), GetSelectedCharacterLabel()), FVector2D(ContentX, PanelPosition.Y + PanelSize.Y - (46.0f * Scale)), ContentWidth, LabelFont, FLinearColor(0.62f, 0.68f, 0.58f, 1.0f));
const FVector2D ButtonPosition(ContentX, PanelPosition.Y + PanelSize.Y - (88.0f * Scale));
const FVector2D ButtonSize(FMath::Min(ContentWidth, 280.0f * Scale), 52.0f * Scale);
FSlateDrawElement::MakeBox(
OutDrawElements,
++LayerId,
AllottedGeometry.ToPaintGeometry(FVector2f(ButtonSize), FSlateLayoutTransform(FVector2f(ButtonPosition))),
FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")),
ESlateDrawEffect::None,
FLinearColor(0.35f, 0.58f, 0.30f, 0.95f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Continue")), ButtonPosition + FVector2D(22.0f * Scale, 10.0f * Scale), ButtonSize.X - (44.0f * Scale), CardTitleFont, FLinearColor(0.96f, 1.0f, 0.90f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::Format(FText::FromString(TEXT("Selected {0}: {1}. Click a card or use Left/Right, then continue.")), GetSelectedRoleLabel(), GetSelectedCharacterLabel()), FVector2D(ContentX, PanelPosition.Y + PanelSize.Y - (26.0f * Scale)), ContentWidth, LabelFont, FLinearColor(0.62f, 0.68f, 0.58f, 1.0f));
}
void UAgrarianMvpFrontendWidget::DrawJoinServer(
@@ -273,7 +434,7 @@ void UAgrarianMvpFrontendWidget::DrawJoinServer(
const FSlateFontInfo HintFont = FCoreStyle::GetDefaultFontStyle("Regular", FMath::RoundToInt(15.0f * Scale));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Join MVP server")), FVector2D(ContentX, PanelPosition.Y + (44.0f * Scale)), ContentWidth, TitleFont, FLinearColor(0.92f, 0.98f, 0.84f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::Format(FText::FromString(TEXT("Character: {0}")), GetSelectedCharacterLabel()), FVector2D(ContentX + (2.0f * Scale), PanelPosition.Y + (94.0f * Scale)), ContentWidth, BodyFont, FLinearColor(0.72f, 0.80f, 0.68f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::Format(FText::FromString(TEXT("{0}: {1}")), GetSelectedRoleLabel(), GetSelectedCharacterLabel()), FVector2D(ContentX + (2.0f * Scale), PanelPosition.Y + (94.0f * Scale)), ContentWidth, BodyFont, FLinearColor(0.72f, 0.80f, 0.68f, 1.0f));
const FVector2D AddressPanelPosition(ContentX, PanelPosition.Y + (164.0f * Scale));
const FVector2D AddressPanelSize(ContentWidth, 96.0f * Scale);
@@ -299,7 +460,20 @@ void UAgrarianMvpFrontendWidget::DrawJoinServer(
FLinearColor(0.35f, 0.58f, 0.30f, 0.95f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Continue to loading")), ButtonPosition + FVector2D(22.0f * Scale, 12.0f * Scale), ButtonSize.X - (44.0f * Scale), AddressFont, FLinearColor(0.96f, 1.0f, 0.90f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Press Backspace or Escape to return to character selection.")), FVector2D(ContentX, PanelPosition.Y + PanelSize.Y - (46.0f * Scale)), ContentWidth, HintFont, FLinearColor(0.62f, 0.68f, 0.58f, 1.0f));
const FVector2D BackButtonPosition(ButtonPosition.X + ButtonSize.X + (16.0f * Scale), ButtonPosition.Y);
const FVector2D BackButtonSize(FMath::Min(ContentWidth - ButtonSize.X - (16.0f * Scale), 180.0f * Scale), ButtonSize.Y);
if (BackButtonSize.X > 96.0f)
{
FSlateDrawElement::MakeBox(
OutDrawElements,
++LayerId,
AllottedGeometry.ToPaintGeometry(FVector2f(BackButtonSize), FSlateLayoutTransform(FVector2f(BackButtonPosition))),
FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")),
ESlateDrawEffect::None,
FLinearColor(0.12f, 0.15f, 0.11f, 0.95f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Back")), BackButtonPosition + FVector2D(22.0f * Scale, 12.0f * Scale), BackButtonSize.X - (44.0f * Scale), AddressFont, FLinearColor(0.82f, 0.88f, 0.76f, 1.0f));
}
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Click continue, press Enter, or press Backspace/Escape to revise your pioneer.")), FVector2D(ContentX, PanelPosition.Y + PanelSize.Y - (46.0f * Scale)), ContentWidth, HintFont, FLinearColor(0.62f, 0.68f, 0.58f, 1.0f));
}
void UAgrarianMvpFrontendWidget::DrawLoading(
@@ -337,8 +511,19 @@ void UAgrarianMvpFrontendWidget::DrawLoading(
ESlateDrawEffect::None,
FLinearColor(0.45f, 0.72f, 0.40f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::Format(FText::FromString(TEXT("Character: {0} | Server: {1}")), GetSelectedCharacterLabel(), JoinServerAddress), FVector2D(ContentX, PanelPosition.Y + (270.0f * Scale)), ContentWidth, BodyFont, FLinearColor(0.78f, 0.84f, 0.72f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("MVP loading placeholder; final connection and map handoff will attach here.")), FVector2D(ContentX, PanelPosition.Y + PanelSize.Y - (46.0f * Scale)), ContentWidth, HintFont, FLinearColor(0.62f, 0.68f, 0.58f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::Format(FText::FromString(TEXT("{0}: {1} | Server: {2}")), GetSelectedRoleLabel(), GetSelectedCharacterLabel(), JoinServerAddress), FVector2D(ContentX, PanelPosition.Y + (270.0f * Scale)), ContentWidth, BodyFont, FLinearColor(0.78f, 0.84f, 0.72f, 1.0f));
const FVector2D ButtonPosition(ContentX, PanelPosition.Y + (318.0f * Scale));
const FVector2D ButtonSize(FMath::Min(ContentWidth, 310.0f * Scale), 56.0f * Scale);
FSlateDrawElement::MakeBox(
OutDrawElements,
++LayerId,
AllottedGeometry.ToPaintGeometry(FVector2f(ButtonSize), FSlateLayoutTransform(FVector2f(ButtonPosition))),
FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")),
ESlateDrawEffect::None,
FLinearColor(0.35f, 0.58f, 0.30f, 0.95f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Enter Ground Zero")), ButtonPosition + FVector2D(22.0f * Scale, 11.0f * Scale), ButtonSize.X - (44.0f * Scale), BodyFont, FLinearColor(0.96f, 1.0f, 0.90f, 1.0f));
DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Click or press Enter to close the MVP menu and begin testing.")), FVector2D(ContentX, PanelPosition.Y + PanelSize.Y - (46.0f * Scale)), ContentWidth, HintFont, FLinearColor(0.62f, 0.68f, 0.58f, 1.0f));
}
FText UAgrarianMvpFrontendWidget::GetSelectedCharacterLabel() const
@@ -348,6 +533,11 @@ FText UAgrarianMvpFrontendWidget::GetSelectedCharacterLabel() const
: FText::FromString(TEXT("young adult male"));
}
FText UAgrarianMvpFrontendWidget::GetSelectedRoleLabel() const
{
return FText::FromString(TEXT("Pioneer"));
}
void UAgrarianMvpFrontendWidget::DrawTextAt(
FSlateWindowElementList& OutDrawElements,
int32& LayerId,