#include "ui/MenuLayout.h" #include "ui/UIConstants.h" #include #include #include namespace ui { std::array computeMenuButtonRects(const MenuLayoutParams& p) { const float LOGICAL_W = static_cast(p.logicalW); const float LOGICAL_H = static_cast(p.logicalH); float contentOffsetX = (p.winW - LOGICAL_W * p.logicalScale) * 0.5f / p.logicalScale; float contentOffsetY = (p.winH - LOGICAL_H * p.logicalScale) * 0.5f / p.logicalScale; // Cockpit HUD layout (matches main_screen art): // - Top row: PLAY / COOPERATE / CHALLENGE (big buttons) // - Second row: LEVEL / OPTIONS / HELP / ABOUT / EXIT (smaller buttons) const float marginX = std::max(24.0f, LOGICAL_W * 0.03f); const float marginBottom = std::max(26.0f, LOGICAL_H * 0.03f); const float availableW = std::max(120.0f, LOGICAL_W - marginX * 2.0f); float playW = std::min(220.0f, availableW * 0.25f); float playH = 36.0f; float bigGap = 28.0f; float smallW = std::min(210.0f, availableW * 0.22f); float smallH = 34.0f; float smallSpacing = 26.0f; // Scale down for narrow windows so nothing goes offscreen. const int bigCount = 3; const int smallCount = MENU_BTN_COUNT - bigCount; float smallTotal = smallW * static_cast(smallCount) + smallSpacing * static_cast(std::max(smallCount - 1, 0)); float topRowTotal = playW * static_cast(bigCount) + bigGap * static_cast(bigCount - 1); if (smallTotal > availableW || topRowTotal > availableW) { float s = availableW / std::max(std::max(smallTotal, topRowTotal), 1.0f); smallW *= s; smallH *= s; smallSpacing *= s; playW *= s; playH = std::max(26.0f, playH * std::max(0.75f, s)); bigGap *= s; playW = std::min(playW, availableW); } float centerX = LOGICAL_W * 0.5f + contentOffsetX; float bottomY = LOGICAL_H + contentOffsetY - marginBottom; float smallCY = bottomY - smallH * 0.5f; // Extra breathing room between PLAY and the bottom row (requested). const float rowGap = 34.0f; float playCY = smallCY - smallH * 0.5f - rowGap - playH * 0.5f; std::array rects{}; // Top row big buttons (PLAY / COOPERATE / CHALLENGE) float bigRowW = playW * static_cast(bigCount) + bigGap * static_cast(bigCount - 1); float leftBig = centerX - bigRowW * 0.5f; for (int i = 0; i < bigCount; ++i) { float x = leftBig + i * (playW + bigGap); rects[i] = SDL_FRect{ x, playCY - playH * 0.5f, playW, playH }; } float rowW = smallW * static_cast(smallCount) + smallSpacing * static_cast(smallCount - 1); float left = centerX - rowW * 0.5f; float minLeft = contentOffsetX + marginX; float maxRight = contentOffsetX + LOGICAL_W - marginX; if (left < minLeft) left = minLeft; if (left + rowW > maxRight) left = std::max(minLeft, maxRight - rowW); for (int i = 0; i < smallCount; ++i) { float x = left + i * (smallW + smallSpacing); rects[i + bigCount] = SDL_FRect{ x, smallCY - smallH * 0.5f, smallW, smallH }; } return rects; } int hitTestMenuButtons(const MenuLayoutParams& p, float localX, float localY) { auto rects = computeMenuButtonRects(p); for (int i = 0; i < MENU_BTN_COUNT; ++i) { const auto &r = rects[i]; if (localX >= r.x && localX <= r.x + r.w && localY >= r.y && localY <= r.y + r.h) return i; } return -1; } SDL_FRect settingsButtonRect(const MenuLayoutParams& p) { return SDL_FRect{SETTINGS_BTN_X, SETTINGS_BTN_Y, SETTINGS_BTN_W, SETTINGS_BTN_H}; } } // namespace ui