#pragma once #include "CoreMinimal.h" #include "UI/DescentHudModel.h" /** One rectangle of the HUD, in UI units (origin top left). */ struct THEDESCENT_API FDescentHudRect { FName Name; float X = 0.f; float Y = 0.f; float W = 0.f; float H = 0.f; bool bVisible = false; float Right() const { return X + W; } float Bottom() const { return Y + H; } bool Intersects(const FDescentHudRect& O) const { return X < O.Right() && O.X < Right() && Y < O.Bottom() && O.Y < Bottom(); } bool InsideSize(const FVector2f& Size) const { return X >= 0.f && Y >= 0.f && Right() <= Size.X && Bottom() <= Size.Y; } }; /** * Where every region of the HUD sits (DESIGN_UE.md section 8.5 layout table and its narrow-screen rule). A pure function * of the layout size (UI units) and the HUD model, so a headless test can check that radio, prompt, vitals, hotbar, vehicle * panel, objective and depth panel never intersect at 1280 x 720, 1000 x 560 and 800 x 450, and the scenarios report the * same rectangles in `ui.widgets`. * * narrow (width < 900): gauges 56, radio moves under the depth panel, objective hidden unless unfolded (J) * compact (height < 640): shorter depth panel, objective and proximity rows */ struct THEDESCENT_API FDescentHudLayout { FVector2f Size = FVector2f(1280.f, 720.f); bool bNarrow = false; bool bCompact = false; float Gauge = 72.f; float Slot = 52.f; FDescentHudRect Depth, Objective, Toasts, Vitals, Vehicle, Hotbar, Radio, Prompt, BuildReason, Proximity, Warning; static FDescentHudLayout Compute(const FVector2f& LayoutSize, const FDescentHudModel& Model); /** All regions, visible or not, in a fixed order. */ TArray All() const; /** The ones a test must keep apart: radio, prompt, vitals, hotbar, vehicle, objective, depth (+ toasts, proximity, warning, build reason). */ TArray VisibleRects() const; /** The first pair of visible regions that overlap, or false. */ bool FindOverlap(FName& OutA, FName& OutB) const; };