From 2adc683044d849ec60df0658c6ed94a9b8640e3e Mon Sep 17 00:00:00 2001 From: nathan Date: Mon, 18 May 2026 21:19:00 -0700 Subject: [PATCH] Add MVP accessibility basics --- AGRARIAN_DEVELOPMENT_ROADMAP.md | 2 +- Scripts/verify_mvp_accessibility_basics.py | 64 +++++++++++++++++++ Source/AgrarianGame/AgrarianDebugHUD.cpp | 1 + .../AgrarianGamePlayerController.cpp | 31 +++++++++ .../AgrarianGamePlayerController.h | 6 ++ .../AgrarianMvpFrontendWidget.cpp | 21 +++++- .../AgrarianGame/AgrarianMvpFrontendWidget.h | 9 +++ 7 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 Scripts/verify_mvp_accessibility_basics.py diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index dc5d297..a160165 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -804,7 +804,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe - [x] Add interaction prompts. Promoted the existing centered interactable prompt renderer into the 0.1.N UI pass with `AgrarianToggleInteractionPrompts`, keeping prompt text driven by focused interactables. - [x] Add death/respawn UI. Added a dedicated dead-state MVP panel with last death reason, Ground Zero respawn context, and `AgrarianToggleDeathRespawnUI` while preserving the existing server-authoritative respawn command. - [x] Add debug/dev menu. Added a toggleable `bShowDebugDevMenu` HUD panel plus `AgrarianToggleDebugDevMenu`, listing the core MVP frontend, UI, persistence, and recovery commands for tester/admin use. -- [ ] Add accessibility basics. +- [x] Add accessibility basics. Added runtime MVP UI scaling with `AgrarianSetUiScale 0.75-1.5` and a frontend high-contrast mode with `AgrarianToggleHighContrastUI`, applying scale to the native frontend and HUD text surfaces. - [ ] Ensure UI scales on common resolutions. ## 0.1.O MVP Audio And Atmosphere diff --git a/Scripts/verify_mvp_accessibility_basics.py b/Scripts/verify_mvp_accessibility_basics.py new file mode 100644 index 0000000..f101a3b --- /dev/null +++ b/Scripts/verify_mvp_accessibility_basics.py @@ -0,0 +1,64 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +FILES = { + "AgrarianMvpFrontendWidget.h": ROOT / "Source" / "AgrarianGame" / "AgrarianMvpFrontendWidget.h", + "AgrarianMvpFrontendWidget.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianMvpFrontendWidget.cpp", + "AgrarianGamePlayerController.h": ROOT / "Source" / "AgrarianGame" / "AgrarianGamePlayerController.h", + "AgrarianGamePlayerController.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianGamePlayerController.cpp", + "AgrarianDebugHUD.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianDebugHUD.cpp", + "AGRARIAN_DEVELOPMENT_ROADMAP.md": ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md", +} + +EXPECTED = { + "AgrarianMvpFrontendWidget.h": [ + "bUseHighContrast", + "SetUiScale", + "SetHighContrastMode", + ], + "AgrarianMvpFrontendWidget.cpp": [ + "FMath::Clamp(NewUiScale, 0.75f, 1.5f)", + "BackdropColor = bUseHighContrast", + "PanelColor = bUseHighContrast", + "AccentColor = bUseHighContrast", + ], + "AgrarianGamePlayerController.h": [ + "AgrarianSetUiScale", + "AgrarianToggleHighContrastUI", + ], + "AgrarianGamePlayerController.cpp": [ + "AgrarianSetUiScale", + "SetUiScale(ClampedScale)", + "CriticalStatsTextScale = ClampedScale", + "PromptTextScale = ClampedScale", + "AgrarianToggleHighContrastUI", + "SetHighContrastMode", + ], + "AgrarianDebugHUD.cpp": [ + "AgrarianSetUiScale 0.75-1.5 / ToggleHighContrastUI", + ], + "AGRARIAN_DEVELOPMENT_ROADMAP.md": [ + "[x] Add accessibility basics.", + "`AgrarianSetUiScale 0.75-1.5`", + "`AgrarianToggleHighContrastUI`", + ], +} + + +def main(): + missing = [] + for label, path in FILES.items(): + text = path.read_text(encoding="utf-8") + for snippet in EXPECTED[label]: + if snippet not in text: + missing.append(f"{label}: {snippet}") + + if missing: + raise RuntimeError("MVP accessibility basics verification failed: " + "; ".join(missing)) + + print("Agrarian MVP accessibility basics verification complete.") + + +if __name__ == "__main__": + main() diff --git a/Source/AgrarianGame/AgrarianDebugHUD.cpp b/Source/AgrarianGame/AgrarianDebugHUD.cpp index b21b273..82dd612 100644 --- a/Source/AgrarianGame/AgrarianDebugHUD.cpp +++ b/Source/AgrarianGame/AgrarianDebugHUD.cpp @@ -93,6 +93,7 @@ void AAgrarianDebugHUD::DrawDebugDevMenu() DrawScaledLine(TEXT("AgrarianSelectCharacter male|female"), TextX, Y, 0.78f * Scale, FColor(215, 225, 205)); DrawScaledLine(TEXT("AgrarianToggleInventoryUI / CraftingUI"), TextX, Y, 0.78f * Scale, FColor(215, 225, 205)); DrawScaledLine(TEXT("AgrarianToggleInteractionPrompts"), TextX, Y, 0.78f * Scale, FColor(215, 225, 205)); + DrawScaledLine(TEXT("AgrarianSetUiScale 0.75-1.5 / ToggleHighContrastUI"), TextX, Y, 0.78f * Scale, FColor(215, 225, 205)); DrawScaledLine(TEXT("AgrarianSaveWorld / AgrarianLoadWorld"), TextX, Y, 0.78f * Scale, FColor(215, 225, 205)); DrawScaledLine(TEXT("AgrarianRespawn / AgrarianHeal"), TextX, Y, 0.78f * Scale, FColor(215, 225, 205)); } diff --git a/Source/AgrarianGame/AgrarianGamePlayerController.cpp b/Source/AgrarianGame/AgrarianGamePlayerController.cpp index 5710660..6e5294a 100644 --- a/Source/AgrarianGame/AgrarianGamePlayerController.cpp +++ b/Source/AgrarianGame/AgrarianGamePlayerController.cpp @@ -346,6 +346,37 @@ void AAgrarianGamePlayerController::AgrarianToggleDebugDevMenu() ClientMessage(AgrarianHUD->bShowDebugDevMenu ? TEXT("MVP debug/dev menu shown.") : TEXT("MVP debug/dev menu hidden.")); } +void AAgrarianGamePlayerController::AgrarianSetUiScale(float NewUiScale) +{ + const float ClampedScale = FMath::Clamp(NewUiScale, 0.75f, 1.5f); + if (MvpFrontendWidget) + { + MvpFrontendWidget->SetUiScale(ClampedScale); + } + + if (AAgrarianDebugHUD* AgrarianHUD = GetHUD()) + { + AgrarianHUD->TextScale = ClampedScale; + AgrarianHUD->CriticalStatsTextScale = ClampedScale; + AgrarianHUD->InventoryTextScale = ClampedScale; + AgrarianHUD->PromptTextScale = ClampedScale; + } + + ClientMessage(FString::Printf(TEXT("MVP UI scale set to %.2f."), ClampedScale)); +} + +void AAgrarianGamePlayerController::AgrarianToggleHighContrastUI() +{ + if (!MvpFrontendWidget) + { + ClientMessage(TEXT("No MVP frontend widget is active.")); + return; + } + + MvpFrontendWidget->SetHighContrastMode(!MvpFrontendWidget->bUseHighContrast); + ClientMessage(MvpFrontendWidget->bUseHighContrast ? TEXT("MVP high contrast UI enabled.") : TEXT("MVP high contrast UI disabled.")); +} + void AAgrarianGamePlayerController::AgrarianSelectCharacter(FName Archetype) { if (!MvpFrontendWidget) diff --git a/Source/AgrarianGame/AgrarianGamePlayerController.h b/Source/AgrarianGame/AgrarianGamePlayerController.h index 0c5f58e..a6777f8 100644 --- a/Source/AgrarianGame/AgrarianGamePlayerController.h +++ b/Source/AgrarianGame/AgrarianGamePlayerController.h @@ -106,6 +106,12 @@ public: UFUNCTION(Exec) void AgrarianToggleDebugDevMenu(); + UFUNCTION(Exec) + void AgrarianSetUiScale(float NewUiScale); + + UFUNCTION(Exec) + void AgrarianToggleHighContrastUI(); + UFUNCTION(Exec) void AgrarianSelectCharacter(FName Archetype); diff --git a/Source/AgrarianGame/AgrarianMvpFrontendWidget.cpp b/Source/AgrarianGame/AgrarianMvpFrontendWidget.cpp index 42ceb1a..9d7fff5 100644 --- a/Source/AgrarianGame/AgrarianMvpFrontendWidget.cpp +++ b/Source/AgrarianGame/AgrarianMvpFrontendWidget.cpp @@ -67,6 +67,18 @@ void UAgrarianMvpFrontendWidget::SetSelectedCharacterArchetype(EAgrarianMvpChara InvalidateLayoutAndVolatility(); } +void UAgrarianMvpFrontendWidget::SetUiScale(float NewUiScale) +{ + UiScale = FMath::Clamp(NewUiScale, 0.75f, 1.5f); + InvalidateLayoutAndVolatility(); +} + +void UAgrarianMvpFrontendWidget::SetHighContrastMode(bool bNewUseHighContrast) +{ + bUseHighContrast = bNewUseHighContrast; + InvalidateLayoutAndVolatility(); +} + int32 UAgrarianMvpFrontendWidget::NativePaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, @@ -80,6 +92,9 @@ int32 UAgrarianMvpFrontendWidget::NativePaint( const FVector2D Size = AllottedGeometry.GetLocalSize(); const float Scale = FMath::Clamp(UiScale, 0.75f, 1.5f); + 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); FSlateDrawElement::MakeBox( OutDrawElements, @@ -87,7 +102,7 @@ int32 UAgrarianMvpFrontendWidget::NativePaint( AllottedGeometry.ToPaintGeometry(FVector2f(Size), FSlateLayoutTransform(FVector2f::ZeroVector)), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, - FLinearColor(0.015f, 0.018f, 0.014f, 0.92f)); + BackdropColor); const FVector2D PanelSize( FMath::Min(Size.X - 48.0f, 780.0f * Scale), @@ -102,7 +117,7 @@ int32 UAgrarianMvpFrontendWidget::NativePaint( AllottedGeometry.ToPaintGeometry(FVector2f(PanelSize), FSlateLayoutTransform(FVector2f(PanelPosition))), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, - FLinearColor(0.035f, 0.045f, 0.034f, 0.96f)); + PanelColor); FSlateDrawElement::MakeBox( OutDrawElements, @@ -110,7 +125,7 @@ int32 UAgrarianMvpFrontendWidget::NativePaint( AllottedGeometry.ToPaintGeometry(FVector2f(PanelSize.X, 4.0f * Scale), FSlateLayoutTransform(FVector2f(PanelPosition))), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, - FLinearColor(0.45f, 0.72f, 0.40f, 1.0f)); + AccentColor); if (ActiveScreen == EAgrarianMvpFrontendScreen::MainMenu) { diff --git a/Source/AgrarianGame/AgrarianMvpFrontendWidget.h b/Source/AgrarianGame/AgrarianMvpFrontendWidget.h index e426108..196c4fc 100644 --- a/Source/AgrarianGame/AgrarianMvpFrontendWidget.h +++ b/Source/AgrarianGame/AgrarianMvpFrontendWidget.h @@ -49,12 +49,21 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI", meta = (ClampMin = "0.75", ClampMax = "1.5")) float UiScale = 1.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|MVP UI") + bool bUseHighContrast = false; + UFUNCTION(BlueprintCallable, Category = "Agrarian|MVP UI") void SetActiveScreen(EAgrarianMvpFrontendScreen NewScreen); UFUNCTION(BlueprintCallable, Category = "Agrarian|MVP UI") void SetSelectedCharacterArchetype(EAgrarianMvpCharacterArchetype NewArchetype); + UFUNCTION(BlueprintCallable, Category = "Agrarian|MVP UI") + void SetUiScale(float NewUiScale); + + UFUNCTION(BlueprintCallable, Category = "Agrarian|MVP UI") + void SetHighContrastMode(bool bNewUseHighContrast); + protected: virtual void NativeConstruct() override;