Updated bottom menu

This commit is contained in:
2025-12-17 20:12:06 +01:00
parent 122de2b36f
commit fe6c5e3c8a
7 changed files with 240 additions and 83 deletions

View File

@ -26,6 +26,7 @@
#include "../graphics/renderers/UIRenderer.h"
#include "../graphics/renderers/GameRenderer.h"
#include "../ui/MenuLayout.h"
#include "../ui/BottomMenu.h"
#include <SDL3_image/SDL_image.h>
// Frosted tint helper: draw a safe, inexpensive frosted overlay for the panel area.
@ -145,69 +146,16 @@ void MenuState::renderMainButtonTop(SDL_Renderer* renderer, float logicalScale,
logicalVP.h,
logicalScale
};
auto rects = ui::computeMenuButtonRects(params);
// Compose same button definition used in render()
char levelBtnText[32];
int startLevel = ctx.startLevelSelection ? *ctx.startLevelSelection : 0;
std::snprintf(levelBtnText, sizeof(levelBtnText), "LEVEL %d", startLevel);
ui::BottomMenu menu = ui::buildBottomMenu(params, startLevel);
struct MenuButtonDef { SDL_Color bg; SDL_Color border; std::string label; };
std::array<MenuButtonDef,5> 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,200,60,255}, SDL_Color{150,150,40,255}, "HELP" },
MenuButtonDef{ SDL_Color{200,70,70,255}, SDL_Color{150,40,40,255}, "EXIT" }
};
std::array<SDL_Texture*,5> icons = { playIcon, levelIcon, optionsIcon, helpIcon, exitIcon };
// Draw PLAY as a real glowing button, and the four bottom items as HUD buttons.
for (int i = 0; i < 5; ++i) {
const SDL_FRect& r = rects[i];
float cxCenter = r.x + r.w * 0.5f;
float cyCenter = r.y + r.h * 0.5f;
float btnW = r.w;
float btnH = r.h;
const bool isHovered = (ctx.hoveredButton && *ctx.hoveredButton == i);
const bool isSelected = (selectedButton == i);
double aMul = std::clamp(buttonGroupAlpha + buttonFlash * buttonFlashAmount, 0.0, 1.0);
if (i == 0) {
SDL_Color bgCol{ 18, 22, 28, static_cast<Uint8>(std::round(180.0 * aMul)) };
SDL_Color bdCol{ 255, 200, 70, static_cast<Uint8>(std::round(220.0 * aMul)) };
UIRenderer::drawButton(renderer, ctx.pixelFont, cxCenter, cyCenter, btnW, btnH,
buttons[i].label, isHovered, isSelected,
bgCol, bdCol, false, nullptr);
} else {
SDL_Color bgCol{ 20, 30, 42, static_cast<Uint8>(std::round(160.0 * aMul)) };
SDL_Color bdCol{ 120, 220, 255, static_cast<Uint8>(std::round(200.0 * aMul)) };
UIRenderer::drawButton(renderer, ctx.pixelFont, cxCenter, cyCenter, btnW, btnH,
buttons[i].label, isHovered, isSelected,
bgCol, bdCol, true, nullptr);
}
}
// Draw small '+' separators between the bottom HUD buttons (matches the reference vibe).
{
SDL_BlendMode prevBlend = SDL_BLENDMODE_NONE;
SDL_GetRenderDrawBlendMode(renderer, &prevBlend);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 120, 220, 255, 180);
float y = rects[1].y + rects[1].h * 0.5f;
for (int i = 1; i < 4; ++i) {
float x = (rects[i].x + rects[i].w + rects[i + 1].x) * 0.5f;
SDL_RenderLine(renderer, x - 4.0f, y, x + 4.0f, y);
SDL_RenderLine(renderer, x, y - 4.0f, x, y + 4.0f);
}
SDL_SetRenderDrawBlendMode(renderer, prevBlend);
}
const int hovered = (ctx.hoveredButton ? *ctx.hoveredButton : -1);
const double baseAlpha = 1.0;
// Pulse is encoded as a signed delta so PLAY can dim/brighten while focused.
const double pulseDelta = (buttonPulseAlpha - 1.0);
const double flashDelta = buttonFlash * buttonFlashAmount;
ui::renderBottomMenu(renderer, ctx.pixelFont, menu, hovered, selectedButton, baseAlpha, pulseDelta + flashDelta);
}
void MenuState::onExit() {
@ -226,6 +174,11 @@ void MenuState::onExit() {
void MenuState::handleEvent(const SDL_Event& e) {
// Keyboard navigation for menu buttons
if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) {
// When the player uses the keyboard, don't let an old mouse hover keep focus on a button.
if (ctx.hoveredButton) {
*ctx.hoveredButton = -1;
}
auto triggerPlay = [&]() {
if (ctx.startPlayTransition) {
ctx.startPlayTransition();
@ -622,7 +575,7 @@ void MenuState::update(double frameMs) {
}
}
// Update button group pulsing animation
// Update pulsing animation (used for PLAY emphasis)
if (buttonPulseEnabled) {
buttonPulseTime += frameMs;
double t = (buttonPulseTime * 0.001) * buttonPulseSpeed; // seconds * speed
@ -652,11 +605,14 @@ void MenuState::update(double frameMs) {
default:
s = (std::sin(t * 2.0 * 3.14159265358979323846) * 0.5) + 0.5;
}
buttonGroupAlpha = buttonPulseMinAlpha + s * (buttonPulseMaxAlpha - buttonPulseMinAlpha);
buttonPulseAlpha = buttonPulseMinAlpha + s * (buttonPulseMaxAlpha - buttonPulseMinAlpha);
} else {
buttonGroupAlpha = 1.0;
buttonPulseAlpha = 1.0;
}
// Keep the base group alpha stable; pulsing is applied selectively in the renderer.
buttonGroupAlpha = 1.0;
// Update flash decay
if (buttonFlash > 0.0) {
buttonFlash -= frameMs * buttonFlashDecay;

View File

@ -56,8 +56,9 @@ private:
double levelHighlightGlowAlpha = 0.70; // 0..1 base glow alpha
int levelHighlightThickness = 3; // inner outline thickness (px)
SDL_Color levelHighlightColor = SDL_Color{80, 200, 255, 200};
// Button group pulsing/fade parameters (applies to all four main buttons)
double buttonGroupAlpha = 1.0; // current computed alpha (0..1)
// Button pulsing/fade parameters (used for PLAY emphasis)
double buttonGroupAlpha = 1.0; // base alpha for the whole group (kept stable)
double buttonPulseAlpha = 1.0; // pulsing alpha (0..1), applied to PLAY only
double buttonPulseTime = 0.0; // accumulator in ms
bool buttonPulseEnabled = true; // enable/disable pulsing
double buttonPulseSpeed = 1.0; // multiplier for pulse frequency