added buttons to main state
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
// Use dynamic logical dimensions from GlobalState instead of hardcoded values
|
||||
@ -22,38 +23,115 @@ MenuState::MenuState(StateContext& ctx) : State(ctx) {}
|
||||
|
||||
void MenuState::onEnter() {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "MenuState::onEnter called");
|
||||
if (ctx.showExitConfirmPopup) {
|
||||
*ctx.showExitConfirmPopup = false;
|
||||
}
|
||||
if (ctx.exitPopupSelectedButton) {
|
||||
*ctx.exitPopupSelectedButton = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void MenuState::onExit() {
|
||||
if (ctx.showExitConfirmPopup) {
|
||||
*ctx.showExitConfirmPopup = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MenuState::handleEvent(const SDL_Event& e) {
|
||||
// Keyboard navigation for menu buttons
|
||||
if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) {
|
||||
auto setExitSelection = [&](int value) {
|
||||
if (ctx.exitPopupSelectedButton) {
|
||||
*ctx.exitPopupSelectedButton = value;
|
||||
}
|
||||
};
|
||||
auto getExitSelection = [&]() -> int {
|
||||
return ctx.exitPopupSelectedButton ? *ctx.exitPopupSelectedButton : 1;
|
||||
};
|
||||
auto isExitPromptVisible = [&]() -> bool {
|
||||
return ctx.showExitConfirmPopup && *ctx.showExitConfirmPopup;
|
||||
};
|
||||
auto setExitPrompt = [&](bool visible) {
|
||||
if (ctx.showExitConfirmPopup) {
|
||||
*ctx.showExitConfirmPopup = visible;
|
||||
}
|
||||
};
|
||||
|
||||
if (isExitPromptVisible()) {
|
||||
switch (e.key.scancode) {
|
||||
case SDL_SCANCODE_LEFT:
|
||||
case SDL_SCANCODE_UP:
|
||||
setExitSelection(0);
|
||||
return;
|
||||
case SDL_SCANCODE_RIGHT:
|
||||
case SDL_SCANCODE_DOWN:
|
||||
setExitSelection(1);
|
||||
return;
|
||||
case SDL_SCANCODE_RETURN:
|
||||
case SDL_SCANCODE_KP_ENTER:
|
||||
case SDL_SCANCODE_SPACE:
|
||||
if (getExitSelection() == 0) {
|
||||
setExitPrompt(false);
|
||||
if (ctx.requestQuit) {
|
||||
ctx.requestQuit();
|
||||
} else {
|
||||
SDL_Event quit{};
|
||||
quit.type = SDL_EVENT_QUIT;
|
||||
SDL_PushEvent(&quit);
|
||||
}
|
||||
} else {
|
||||
setExitPrompt(false);
|
||||
}
|
||||
return;
|
||||
case SDL_SCANCODE_ESCAPE:
|
||||
setExitPrompt(false);
|
||||
setExitSelection(1);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (e.key.scancode) {
|
||||
case SDL_SCANCODE_LEFT:
|
||||
case SDL_SCANCODE_UP:
|
||||
selectedButton = 0; // PLAY
|
||||
{
|
||||
const int total = 4;
|
||||
selectedButton = (selectedButton + total - 1) % total;
|
||||
break;
|
||||
}
|
||||
case SDL_SCANCODE_RIGHT:
|
||||
case SDL_SCANCODE_DOWN:
|
||||
selectedButton = 1; // LEVEL
|
||||
{
|
||||
const int total = 4;
|
||||
selectedButton = (selectedButton + 1) % total;
|
||||
break;
|
||||
}
|
||||
case SDL_SCANCODE_RETURN:
|
||||
case SDL_SCANCODE_KP_ENTER:
|
||||
case SDL_SCANCODE_SPACE:
|
||||
// Activate selected button
|
||||
if (selectedButton == 0) {
|
||||
// PLAY button - transition to Playing state
|
||||
if (ctx.stateManager) {
|
||||
ctx.stateManager->setState(AppState::Playing);
|
||||
}
|
||||
} else {
|
||||
// LEVEL button - transition to LevelSelector state
|
||||
if (ctx.stateManager) {
|
||||
ctx.stateManager->setState(AppState::LevelSelector);
|
||||
}
|
||||
if (!ctx.stateManager) {
|
||||
break;
|
||||
}
|
||||
switch (selectedButton) {
|
||||
case 0:
|
||||
ctx.stateManager->setState(AppState::Playing);
|
||||
break;
|
||||
case 1:
|
||||
ctx.stateManager->setState(AppState::LevelSelector);
|
||||
break;
|
||||
case 2:
|
||||
ctx.stateManager->setState(AppState::Options);
|
||||
break;
|
||||
case 3:
|
||||
setExitPrompt(true);
|
||||
setExitSelection(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_ESCAPE:
|
||||
setExitPrompt(true);
|
||||
setExitSelection(1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -204,32 +282,88 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
|
||||
char levelBtnText[32];
|
||||
int startLevel = ctx.startLevelSelection ? *ctx.startLevelSelection : 0;
|
||||
std::snprintf(levelBtnText, sizeof(levelBtnText), "LEVEL %d", startLevel);
|
||||
// Draw simple styled buttons (replicating menu_drawMenuButton)
|
||||
|
||||
auto drawMenuButtonLocal = [&](SDL_Renderer* r, FontAtlas& font, float cx, float cy, float w, float h, const std::string& label, SDL_Color bg, SDL_Color border, bool selected){
|
||||
float x = cx - w/2; float y = cy - h/2;
|
||||
|
||||
// If selected, draw a glow effect
|
||||
if (selected) {
|
||||
SDL_SetRenderDrawColor(r, 255, 220, 0, 100);
|
||||
SDL_SetRenderDrawColor(r, 255, 220, 0, 110);
|
||||
SDL_FRect glow{ x-10, y-10, w+20, h+20 };
|
||||
SDL_RenderFillRect(r, &glow);
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(r, border.r, border.g, border.b, border.a);
|
||||
SDL_FRect br{ x-6, y-6, w+12, h+12 }; SDL_RenderFillRect(r, &br);
|
||||
SDL_SetRenderDrawColor(r, 255,255,255,255); SDL_FRect br2{ x-4, y-4, w+8, h+8 }; SDL_RenderFillRect(r, &br2);
|
||||
SDL_SetRenderDrawColor(r, bg.r, bg.g, bg.b, bg.a); SDL_FRect br3{ x, y, w, h }; SDL_RenderFillRect(r, &br3);
|
||||
float textScale = 1.6f; float approxCharW = 12.0f * textScale; float textW = label.length() * approxCharW; float tx = x + (w - textW) / 2.0f; float ty = y + (h - 20.0f * textScale) / 2.0f;
|
||||
font.draw(r, tx+2, ty+2, label, textScale, SDL_Color{0,0,0,180});
|
||||
float textScale = 1.5f; float approxCharW = 12.0f * textScale; float textW = label.length() * approxCharW; float tx = x + (w - textW) / 2.0f; float ty = y + (h - 20.0f * textScale) / 2.0f;
|
||||
font.draw(r, tx+2, ty+2, label, textScale, SDL_Color{0,0,0,200});
|
||||
font.draw(r, tx, ty, label, textScale, SDL_Color{255,255,255,255});
|
||||
};
|
||||
drawMenuButtonLocal(renderer, *ctx.pixelFont, btnX - btnW * 0.6f, btnY, btnW, btnH, std::string("PLAY"), SDL_Color{60,180,80,255}, SDL_Color{30,120,40,255}, selectedButton == 0);
|
||||
{
|
||||
|
||||
struct MenuButtonDef {
|
||||
SDL_Color bg;
|
||||
SDL_Color border;
|
||||
std::string label;
|
||||
};
|
||||
|
||||
std::array<MenuButtonDef, 4> buttons = {
|
||||
MenuButtonDef{ SDL_Color{60,180,80,255}, SDL_Color{30,120,40,255}, "PLAY" },
|
||||
MenuButtonDef{ SDL_Color{40,140,240,255}, SDL_Color{20,100,200,255}, levelBtnText },
|
||||
MenuButtonDef{ SDL_Color{130,80,210,255}, SDL_Color{90,40,170,255}, "OPTIONS" },
|
||||
MenuButtonDef{ SDL_Color{200,70,70,255}, SDL_Color{150,40,40,255}, "EXIT" }
|
||||
};
|
||||
|
||||
float spacing = isSmall ? btnW * 1.15f : btnW * 1.05f;
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
float offset = (static_cast<float>(i) - 1.5f) * spacing;
|
||||
float cx = btnX + offset;
|
||||
drawMenuButtonLocal(renderer, *ctx.pixelFont, cx, btnY, btnW, btnH, buttons[i].label, buttons[i].bg, buttons[i].border, selectedButton == static_cast<int>(i));
|
||||
}
|
||||
drawMenuButtonLocal(renderer, *ctx.pixelFont, btnX + btnW * 0.6f, btnY, btnW, btnH, std::string(levelBtnText), SDL_Color{40,140,240,255}, SDL_Color{20,100,200,255}, selectedButton == 1);
|
||||
{
|
||||
FILE* f = fopen("tetris_trace.log", "a"); if (f) { fprintf(f, "MenuState::render after draw LEVEL button\n"); fclose(f); }
|
||||
}
|
||||
|
||||
if (ctx.showExitConfirmPopup && *ctx.showExitConfirmPopup) {
|
||||
int selection = ctx.exitPopupSelectedButton ? *ctx.exitPopupSelectedButton : 1;
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 150);
|
||||
SDL_FRect overlay{contentOffsetX, contentOffsetY, LOGICAL_W, LOGICAL_H};
|
||||
SDL_RenderFillRect(renderer, &overlay);
|
||||
|
||||
float popupW = 420.0f;
|
||||
float popupH = 230.0f;
|
||||
float popupX = (LOGICAL_W - popupW) * 0.5f + contentOffsetX;
|
||||
float popupY = (LOGICAL_H - popupH) * 0.5f + contentOffsetY;
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, 20, 30, 50, 240);
|
||||
SDL_FRect popup{popupX, popupY, popupW, popupH};
|
||||
SDL_RenderFillRect(renderer, &popup);
|
||||
SDL_SetRenderDrawColor(renderer, 90, 140, 220, 255);
|
||||
SDL_RenderRect(renderer, &popup);
|
||||
|
||||
FontAtlas* titleFont = ctx.font ? ctx.font : ctx.pixelFont;
|
||||
if (titleFont) {
|
||||
titleFont->draw(renderer, popupX + 40.0f, popupY + 30.0f, "EXIT GAME?", 1.8f, SDL_Color{255, 230, 140, 255});
|
||||
titleFont->draw(renderer, popupX + 40.0f, popupY + 80.0f, "Are you sure you want to quit?", 1.1f, SDL_Color{200, 210, 230, 255});
|
||||
}
|
||||
|
||||
auto drawChoice = [&](const char* label, float cx, int idx) {
|
||||
float btnW2 = 140.0f;
|
||||
float btnH2 = 50.0f;
|
||||
float x = cx - btnW2 / 2.0f;
|
||||
float y = popupY + popupH - btnH2 - 30.0f;
|
||||
bool selected = (selection == idx);
|
||||
SDL_Color bg = selected ? SDL_Color{220, 180, 60, 255} : SDL_Color{80, 110, 160, 255};
|
||||
SDL_Color border = selected ? SDL_Color{255, 220, 120, 255} : SDL_Color{40, 60, 100, 255};
|
||||
SDL_SetRenderDrawColor(renderer, border.r, border.g, border.b, border.a);
|
||||
SDL_FRect br{ x-4, y-4, btnW2+8, btnH2+8 };
|
||||
SDL_RenderFillRect(renderer, &br);
|
||||
SDL_SetRenderDrawColor(renderer, bg.r, bg.g, bg.b, bg.a);
|
||||
SDL_FRect body{ x, y, btnW2, btnH2 };
|
||||
SDL_RenderFillRect(renderer, &body);
|
||||
if (titleFont) {
|
||||
titleFont->draw(renderer, x + 20.0f, y + 10.0f, label, 1.2f, SDL_Color{15, 20, 35, 255});
|
||||
}
|
||||
};
|
||||
drawChoice("YES", popupX + popupW * 0.3f, 0);
|
||||
drawChoice("NO", popupX + popupW * 0.7f, 1);
|
||||
}
|
||||
|
||||
// Popups (settings only - level popup is now a separate state)
|
||||
|
||||
Reference in New Issue
Block a user