Retro exit modal styling and shortcuts

This commit is contained in:
2025-11-22 19:56:07 +01:00
parent aed1cb62e7
commit c0bee9296a
7 changed files with 389 additions and 239 deletions

View File

@ -3,6 +3,7 @@
#include "../graphics/Font.h"
#include "../gameplay/LineEffect.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdio>
@ -421,60 +422,88 @@ void GameRenderer::renderPlayingState(
pixelFont->draw(renderer, logicalW * 0.5f - 120, logicalH * 0.5f + 30, "Press P to resume", 0.8f, {200, 200, 220, 255});
}
// Exit confirmation popup
if (showExitConfirmPopup) {
float popupW = 420.0f, popupH = 180.0f;
float popupX = (logicalW - popupW) * 0.5f;
float popupY = (logicalH - popupH) * 0.5f;
// Dim entire window (do not change viewport/scales here)
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 200);
SDL_FRect fullWin{0.f, 0.f, winW, winH};
SDL_RenderFillRect(renderer, &fullWin);
// Draw popup box in logical coords with content offsets
drawRectWithOffset(popupX - 4.0f, popupY - 4.0f, popupW + 8.0f, popupH + 8.0f, {60, 70, 90, 255});
drawRectWithOffset(popupX, popupY, popupW, popupH, {20, 22, 28, 240});
const float panelW = 640.0f;
const float panelH = 320.0f;
SDL_FRect panel{
(logicalW - panelW) * 0.5f + contentOffsetX,
(logicalH - panelH) * 0.5f + contentOffsetY,
panelW,
panelH
};
// Text content (measure to perfectly center)
const std::string title = "Exit game?";
const std::string line1 = "Are you sure you want to";
const std::string line2 = "leave the current game?";
SDL_FRect shadow{panel.x + 6.0f, panel.y + 10.0f, panel.w, panel.h};
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 140);
SDL_RenderFillRect(renderer, &shadow);
for (int i = 0; i < 5; ++i) {
SDL_FRect glow{panel.x - float(i * 2), panel.y - float(i * 2), panel.w + float(i * 4), panel.h + float(i * 4)};
SDL_SetRenderDrawColor(renderer, 0, 180, 255, Uint8(44 - i * 7));
SDL_RenderRect(renderer, &glow);
}
int wTitle=0,hTitle=0; pixelFont->measure(title, 1.6f, wTitle, hTitle);
int wL1=0,hL1=0; pixelFont->measure(line1, 0.9f, wL1, hL1);
int wL2=0,hL2=0; pixelFont->measure(line2, 0.9f, wL2, hL2);
SDL_SetRenderDrawColor(renderer, 18, 30, 52, 255);
SDL_RenderFillRect(renderer, &panel);
SDL_SetRenderDrawColor(renderer, 70, 120, 210, 255);
SDL_RenderRect(renderer, &panel);
float titleX = popupX + (popupW - (float)wTitle) * 0.5f + contentOffsetX;
float l1X = popupX + (popupW - (float)wL1) * 0.5f + contentOffsetX;
float l2X = popupX + (popupW - (float)wL2) * 0.5f + contentOffsetX;
SDL_FRect inner{panel.x + 24.0f, panel.y + 98.0f, panel.w - 48.0f, panel.h - 146.0f};
SDL_SetRenderDrawColor(renderer, 16, 24, 40, 235);
SDL_RenderFillRect(renderer, &inner);
SDL_SetRenderDrawColor(renderer, 40, 80, 140, 235);
SDL_RenderRect(renderer, &inner);
pixelFont->draw(renderer, titleX, popupY + contentOffsetY + 20.0f, title, 1.6f, {255, 220, 0, 255});
pixelFont->draw(renderer, l1X, popupY + contentOffsetY + 60.0f, line1, 0.9f, {220, 220, 230, 255});
pixelFont->draw(renderer, l2X, popupY + contentOffsetY + 84.0f, line2, 0.9f, {220, 220, 230, 255});
const std::string title = "EXIT GAME?";
int titleW = 0, titleH = 0;
const float titleScale = 1.8f;
pixelFont->measure(title, titleScale, titleW, titleH);
pixelFont->draw(renderer, panel.x + (panel.w - titleW) * 0.5f, panel.y + 30.0f, title, titleScale, {255, 230, 140, 255});
// Buttons
float btnW = 140.0f, btnH = 46.0f;
float yesX = popupX + popupW * 0.25f - btnW * 0.5f;
float noX = popupX + popupW * 0.75f - btnW * 0.5f;
float btnY = popupY + popupH - 60.0f;
std::array<std::string, 2> lines = {
"Are you sure you want to quit?",
"Current progress will be lost."
};
float lineY = inner.y + 22.0f;
const float lineScale = 1.05f;
for (const auto& line : lines) {
int lineW = 0, lineH = 0;
pixelFont->measure(line, lineScale, lineW, lineH);
float textX = panel.x + (panel.w - lineW) * 0.5f;
pixelFont->draw(renderer, textX, lineY, line, lineScale, SDL_Color{210, 220, 240, 255});
lineY += lineH + 10.0f;
}
// YES button
drawRectWithOffset(yesX - 2.0f, btnY - 2.0f, btnW + 4.0f, btnH + 4.0f, {100, 120, 140, 255});
drawRectWithOffset(yesX, btnY, btnW, btnH, {200, 60, 60, 255});
const std::string yes = "YES";
int wYes=0,hYes=0; pixelFont->measure(yes, 1.0f, wYes, hYes);
pixelFont->draw(renderer, yesX + (btnW - (float)wYes) * 0.5f + contentOffsetX,
btnY + (btnH - (float)hYes) * 0.5f + contentOffsetY,
yes, 1.0f, {255, 255, 255, 255});
const float horizontalPad = 28.0f;
const float buttonGap = 32.0f;
const float buttonH = 66.0f;
float buttonW = (inner.w - horizontalPad * 2.0f - buttonGap) * 0.5f;
float buttonY = inner.y + inner.h - buttonH - 24.0f;
// NO button
drawRectWithOffset(noX - 2.0f, btnY - 2.0f, btnW + 4.0f, btnH + 4.0f, {100, 120, 140, 255});
drawRectWithOffset(noX, btnY, btnW, btnH, {80, 140, 80, 255});
const std::string no = "NO";
int wNo=0,hNo=0; pixelFont->measure(no, 1.0f, wNo, hNo);
pixelFont->draw(renderer, noX + (btnW - (float)wNo) * 0.5f + contentOffsetX,
btnY + (btnH - (float)hNo) * 0.5f + contentOffsetY,
no, 1.0f, {255, 255, 255, 255});
auto drawButton = [&](float x, const char* label, SDL_Color base) {
SDL_FRect btn{x, buttonY, buttonW, buttonH};
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 120);
SDL_FRect btnShadow{btn.x + 4.0f, btn.y + 6.0f, btn.w, btn.h};
SDL_RenderFillRect(renderer, &btnShadow);
SDL_SetRenderDrawColor(renderer, base.r, base.g, base.b, base.a);
SDL_RenderFillRect(renderer, &btn);
SDL_SetRenderDrawColor(renderer, 90, 130, 200, 255);
SDL_RenderRect(renderer, &btn);
int textW = 0, textH = 0;
const float labelScale = 1.4f;
pixelFont->measure(label, labelScale, textW, textH);
float textX = btn.x + (btn.w - textW) * 0.5f;
float textY = btn.y + (btn.h - textH) * 0.5f;
pixelFont->draw(renderer, textX, textY, label, labelScale, SDL_Color{255, 255, 255, 255});
};
float yesX = inner.x + horizontalPad;
float noX = yesX + buttonW + buttonGap;
drawButton(yesX, "YES", SDL_Color{185, 70, 70, 255});
drawButton(noX, "NO", SDL_Color{60, 95, 150, 255});
}
}

View File

@ -3,6 +3,7 @@
#include "../ui/Font.h"
#include "../../gameplay/effects/LineEffect.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdio>
@ -422,68 +423,96 @@ void GameRenderer::renderPlayingState(
pixelFont->draw(renderer, logicalW * 0.5f - 120, logicalH * 0.5f + 30, "Press P to resume", 0.8f, {200, 200, 220, 255});
}
// Exit confirmation popup
// Exit confirmation popup styled like other retro panels
if (showExitConfirmPopup) {
float popupW = 420.0f, popupH = 180.0f;
float popupX = (logicalW - popupW) * 0.5f;
float popupY = (logicalH - popupH) * 0.5f;
// Dim entire window (do not change viewport/scales here)
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 200);
SDL_FRect fullWin{0.f, 0.f, winW, winH};
SDL_RenderFillRect(renderer, &fullWin);
// Draw popup box in logical coords with content offsets
drawRectWithOffset(popupX - 4.0f, popupY - 4.0f, popupW + 8.0f, popupH + 8.0f, {60, 70, 90, 255});
drawRectWithOffset(popupX, popupY, popupW, popupH, {20, 22, 28, 240});
const float panelW = 640.0f;
const float panelH = 320.0f;
SDL_FRect panel{
(logicalW - panelW) * 0.5f + contentOffsetX,
(logicalH - panelH) * 0.5f + contentOffsetY,
panelW,
panelH
};
// Text content (measure to perfectly center)
const std::string title = "Exit game?";
const std::string line1 = "Are you sure you want to";
const std::string line2 = "leave the current game?";
SDL_FRect shadow{panel.x + 6.0f, panel.y + 10.0f, panel.w, panel.h};
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 140);
SDL_RenderFillRect(renderer, &shadow);
int wTitle=0,hTitle=0; pixelFont->measure(title, 1.6f, wTitle, hTitle);
int wL1=0,hL1=0; pixelFont->measure(line1, 0.9f, wL1, hL1);
int wL2=0,hL2=0; pixelFont->measure(line2, 0.9f, wL2, hL2);
float titleX = popupX + (popupW - (float)wTitle) * 0.5f + contentOffsetX;
float l1X = popupX + (popupW - (float)wL1) * 0.5f + contentOffsetX;
float l2X = popupX + (popupW - (float)wL2) * 0.5f + contentOffsetX;
pixelFont->draw(renderer, titleX, popupY + contentOffsetY + 20.0f, title, 1.6f, {255, 220, 0, 255});
pixelFont->draw(renderer, l1X, popupY + contentOffsetY + 60.0f, line1, 0.9f, {220, 220, 230, 255});
pixelFont->draw(renderer, l2X, popupY + contentOffsetY + 84.0f, line2, 0.9f, {220, 220, 230, 255});
// Buttons
float btnW = 140.0f, btnH = 46.0f;
float yesX = popupX + popupW * 0.25f - btnW * 0.5f;
float noX = popupX + popupW * 0.75f - btnW * 0.5f;
float btnY = popupY + popupH - 60.0f;
// YES button
if (exitPopupSelectedButton == 0) {
// Draw glow for selected YES button
drawRectWithOffset(yesX - 6.0f, btnY - 6.0f, btnW + 12.0f, btnH + 12.0f, {255, 220, 0, 100});
for (int i = 0; i < 5; ++i) {
SDL_FRect glow{panel.x - float(i * 2), panel.y - float(i * 2), panel.w + float(i * 4), panel.h + float(i * 4)};
SDL_SetRenderDrawColor(renderer, 0, 180, 255, Uint8(44 - i * 7));
SDL_RenderRect(renderer, &glow);
}
drawRectWithOffset(yesX - 2.0f, btnY - 2.0f, btnW + 4.0f, btnH + 4.0f, {100, 120, 140, 255});
drawRectWithOffset(yesX, btnY, btnW, btnH, {200, 60, 60, 255});
const std::string yes = "YES";
int wYes=0,hYes=0; pixelFont->measure(yes, 1.0f, wYes, hYes);
pixelFont->draw(renderer, yesX + (btnW - (float)wYes) * 0.5f + contentOffsetX,
btnY + (btnH - (float)hYes) * 0.5f + contentOffsetY,
yes, 1.0f, {255, 255, 255, 255});
// NO button
if (exitPopupSelectedButton == 1) {
// Draw glow for selected NO button
drawRectWithOffset(noX - 6.0f, btnY - 6.0f, btnW + 12.0f, btnH + 12.0f, {255, 220, 0, 100});
SDL_SetRenderDrawColor(renderer, 18, 30, 52, 255);
SDL_RenderFillRect(renderer, &panel);
SDL_SetRenderDrawColor(renderer, 70, 120, 210, 255);
SDL_RenderRect(renderer, &panel);
SDL_FRect inner{panel.x + 24.0f, panel.y + 98.0f, panel.w - 48.0f, panel.h - 146.0f};
SDL_SetRenderDrawColor(renderer, 16, 24, 40, 235);
SDL_RenderFillRect(renderer, &inner);
SDL_SetRenderDrawColor(renderer, 40, 80, 140, 235);
SDL_RenderRect(renderer, &inner);
const std::string title = "EXIT GAME?";
int titleW = 0, titleH = 0;
const float titleScale = 1.8f;
pixelFont->measure(title, titleScale, titleW, titleH);
pixelFont->draw(renderer, panel.x + (panel.w - titleW) * 0.5f, panel.y + 30.0f, title, titleScale, {255, 230, 140, 255});
std::array<std::string, 2> lines = {
"Are you sure you want to quit?",
"Current progress will be lost."
};
float lineY = inner.y + 22.0f;
const float lineScale = 1.05f;
for (const auto& line : lines) {
int lineW = 0, lineH = 0;
pixelFont->measure(line, lineScale, lineW, lineH);
float textX = panel.x + (panel.w - lineW) * 0.5f;
pixelFont->draw(renderer, textX, lineY, line, lineScale, SDL_Color{210, 220, 240, 255});
lineY += lineH + 10.0f;
}
drawRectWithOffset(noX - 2.0f, btnY - 2.0f, btnW + 4.0f, btnH + 4.0f, {100, 120, 140, 255});
drawRectWithOffset(noX, btnY, btnW, btnH, {80, 140, 80, 255});
const std::string no = "NO";
int wNo=0,hNo=0; pixelFont->measure(no, 1.0f, wNo, hNo);
pixelFont->draw(renderer, noX + (btnW - (float)wNo) * 0.5f + contentOffsetX,
btnY + (btnH - (float)hNo) * 0.5f + contentOffsetY,
no, 1.0f, {255, 255, 255, 255});
const float horizontalPad = 28.0f;
const float buttonGap = 32.0f;
const float buttonH = 66.0f;
float buttonW = (inner.w - horizontalPad * 2.0f - buttonGap) * 0.5f;
float buttonY = inner.y + inner.h - buttonH - 24.0f;
auto drawButton = [&](int idx, float x, const char* label) {
bool selected = (exitPopupSelectedButton == idx);
SDL_Color base = (idx == 0) ? SDL_Color{185, 70, 70, 255} : SDL_Color{60, 95, 150, 255};
SDL_Color body = selected ? SDL_Color{Uint8(std::min(255, base.r + 35)), Uint8(std::min(255, base.g + 35)), Uint8(std::min(255, base.b + 35)), 255} : base;
SDL_Color border = selected ? SDL_Color{255, 220, 120, 255} : SDL_Color{80, 110, 160, 255};
SDL_FRect btn{x, buttonY, buttonW, buttonH};
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 120);
SDL_FRect btnShadow{btn.x + 4.0f, btn.y + 6.0f, btn.w, btn.h};
SDL_RenderFillRect(renderer, &btnShadow);
SDL_SetRenderDrawColor(renderer, body.r, body.g, body.b, body.a);
SDL_RenderFillRect(renderer, &btn);
SDL_SetRenderDrawColor(renderer, border.r, border.g, border.b, border.a);
SDL_RenderRect(renderer, &btn);
int textW = 0, textH = 0;
const float labelScale = 1.4f;
pixelFont->measure(label, labelScale, textW, textH);
float textX = btn.x + (btn.w - textW) * 0.5f;
float textY = btn.y + (btn.h - textH) * 0.5f;
SDL_Color textColor = selected ? SDL_Color{255, 255, 255, 255} : SDL_Color{230, 235, 250, 255};
pixelFont->draw(renderer, textX, textY, label, labelScale, textColor);
};
float yesX = inner.x + horizontalPad;
float noX = yesX + buttonW + buttonGap;
drawButton(0, yesX, "YES");
drawButton(1, noX, "NO");
}
}