added helper menu

This commit is contained in:
2025-11-30 13:30:02 +01:00
parent 588f870b26
commit 55c40f0516
11 changed files with 272 additions and 26 deletions

View File

@ -0,0 +1,133 @@
#include "HelpOverlay.h"
#include "Font.h"
#include <array>
#include <algorithm>
namespace {
struct ShortcutEntry {
const char* combo;
const char* description;
};
void drawRect(SDL_Renderer* renderer, float x, float y, float w, float h, SDL_Color color) {
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_FRect rect{x, y, w, h};
SDL_RenderFillRect(renderer, &rect);
}
float fitScale(FontAtlas& font, const char* text, float initialScale, float maxWidth) {
int textW = 0, textH = 0;
float scale = initialScale;
font.measure(text, scale, textW, textH);
if (textW > maxWidth && textW > 0) {
float factor = maxWidth / static_cast<float>(textW);
scale = std::max(0.65f, scale * factor);
}
return scale;
}
}
namespace HelpOverlay {
void Render(
SDL_Renderer* renderer,
FontAtlas& font,
float logicalWidth,
float logicalHeight,
float offsetX,
float offsetY) {
if (!renderer) {
return;
}
const std::array<ShortcutEntry, 5> generalShortcuts{{
{"H", "Toggle this help overlay"},
{"ESC", "Back / cancel current popup"},
{"F11 or ALT+ENTER", "Toggle fullscreen"},
{"M", "Mute or unmute music"},
{"S", "Toggle sound effects"}
}};
const std::array<ShortcutEntry, 2> menuShortcuts{{
{"ARROW KEYS", "Navigate menu buttons"},
{"ENTER / SPACE", "Activate highlighted action"}
}};
const std::array<ShortcutEntry, 7> gameplayShortcuts{{
{"LEFT / RIGHT", "Move active piece"},
{"DOWN", "Soft drop (faster fall)"},
{"SPACE", "Hard drop / instant lock"},
{"UP", "Rotate clockwise"},
{"X", "Rotate counter-clockwise"},
{"P", "Pause or resume"},
{"ESC", "Open exit confirmation"}
}};
const float boxW = logicalWidth * 0.7f;
const float boxH = logicalHeight * 0.55f;
const float boxX = offsetX + (logicalWidth - boxW) * 0.5f;
const float boxY = offsetY + (logicalHeight - boxH) * 0.5f;
drawRect(renderer, boxX - 6.0f, boxY - 6.0f, boxW + 12.0f, boxH + 12.0f, {70, 90, 150, 255});
drawRect(renderer, boxX - 2.0f, boxY - 2.0f, boxW + 4.0f, boxH + 4.0f, {10, 12, 20, 255});
drawRect(renderer, boxX, boxY, boxW, boxH, {18, 22, 35, 240});
const float titleScale = 1.7f;
font.draw(renderer, boxX + 28.0f, boxY + 24.0f, "HELP & SHORTCUTS", titleScale, {255, 220, 0, 255});
const float contentPadding = 32.0f;
const float columnGap = 30.0f;
const float columnWidth = (boxW - contentPadding * 2.0f - columnGap) * 0.5f;
const float leftColumnX = boxX + contentPadding;
const float rightColumnX = leftColumnX + columnWidth + columnGap;
const float footerHeight = 46.0f;
const float footerPadding = 18.0f;
const float sectionTitleScale = 1.1f;
const float comboScale = 0.92f;
const float descBaseScale = 0.8f;
const float comboSpacing = 22.0f;
const float sectionSpacing = 14.0f;
auto drawSection = [&](float startX, float& cursorY, const char* title, const auto& entries) {
font.draw(renderer, startX, cursorY, title, sectionTitleScale, {180, 200, 255, 255});
cursorY += 26.0f;
for (const auto& entry : entries) {
font.draw(renderer, startX, cursorY, entry.combo, comboScale, {255, 255, 255, 255});
cursorY += comboSpacing;
float descScale = fitScale(font, entry.description, descBaseScale, columnWidth - 10.0f);
font.draw(renderer, startX, cursorY, entry.description, descScale, {200, 210, 230, 255});
int descW = 0, descH = 0;
font.measure(entry.description, descScale, descW, descH);
cursorY += static_cast<float>(descH) + 10.0f;
}
cursorY += sectionSpacing;
};
float leftCursorY = boxY + 80.0f;
float rightCursorY = boxY + 80.0f;
drawSection(leftColumnX, leftCursorY, "GENERAL", generalShortcuts);
drawSection(leftColumnX, leftCursorY, "MENUS", menuShortcuts);
drawSection(rightColumnX, rightCursorY, "GAMEPLAY", gameplayShortcuts);
SDL_FRect footerRect{
boxX + contentPadding,
boxY + boxH - contentPadding - footerHeight,
boxW - contentPadding * 2.0f,
footerHeight
};
drawRect(renderer, footerRect.x, footerRect.y, footerRect.w, footerRect.h, {24, 30, 50, 255});
SDL_SetRenderDrawColor(renderer, 90, 110, 170, 255);
SDL_RenderRect(renderer, &footerRect);
const char* closeLabel = "PRESS H TO CLOSE";
float closeScale = fitScale(font, closeLabel, 1.0f, footerRect.w - footerPadding * 2.0f);
int closeW = 0, closeH = 0;
font.measure(closeLabel, closeScale, closeW, closeH);
float closeX = footerRect.x + (footerRect.w - static_cast<float>(closeW)) * 0.5f;
float closeY = footerRect.y + (footerRect.h - static_cast<float>(closeH)) * 0.5f;
font.draw(renderer, closeX, closeY, closeLabel, closeScale, {215, 220, 240, 255});
}
} // namespace HelpOverlay

View File

@ -0,0 +1,16 @@
#pragma once
#include <SDL3/SDL.h>
class FontAtlas;
namespace HelpOverlay {
// Draws the help popup contents inside the logical coordinate space.
// Optional offsets allow aligning the box when the logical canvas is letterboxed.
void Render(
SDL_Renderer* renderer,
FontAtlas& font,
float logicalWidth,
float logicalHeight,
float offsetX = 0.0f,
float offsetY = 0.0f);
}