113 lines
3.9 KiB
C++
113 lines
3.9 KiB
C++
// service_menu.hpp - Menu de servei (singleton)
|
|
// © 2026 JailDesigner
|
|
//
|
|
// Overlay de configuracio global accessible amb F12 des de qualsevol escena
|
|
// (LOGO, TITLE, GAME). Captura tots els KEY_DOWN excepte F1-F12 i ESC, que
|
|
// continuen arribant a GlobalEvents. Mentre esta obert, GameScene::update()
|
|
// fa early return per pausar el joc; LOGO i TITLE continuen renderitzant-se
|
|
// sota el menu.
|
|
//
|
|
// Arquitectura inspirada en aee_arcade service_menu.{hpp,cpp}: pila de
|
|
// pagines amb cursor, animacio open/close amb easing easeOutQuad i clipping
|
|
// del contingut mentre la caixa creix/decreix.
|
|
//
|
|
// API singleton equivalent a Notifier: init() al startup amb un renderer,
|
|
// get() retorna el punter, destroy() al teardown.
|
|
|
|
#pragma once
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "core/graphics/vector_text.hpp"
|
|
#include "core/rendering/render_context.hpp"
|
|
|
|
namespace System {
|
|
|
|
class ServiceMenu {
|
|
public:
|
|
// Tipus d'item de menu. En aquesta iteracio nomes s'usen SUBMENU i
|
|
// LABEL; la resta queden reservats per a iteracions futures (toggles
|
|
// de vsync/zoom, picker d'idioma, restart, exit...).
|
|
enum class Kind : std::uint8_t {
|
|
LABEL, // No interactiu, nomes es dibuixa
|
|
TOGGLE, // bool flip — reservat
|
|
CYCLE, // index amb modul — reservat
|
|
INT_RANGE, // step ± — reservat
|
|
SUBMENU, // pushPage en activar — usat
|
|
ACTION // call al lambda en activar — reservat
|
|
};
|
|
|
|
struct Item {
|
|
Kind kind = Kind::LABEL;
|
|
std::string label_key; // Clau de locale
|
|
bool selectable = true;
|
|
std::function<void()> on_activate;
|
|
};
|
|
|
|
struct Page {
|
|
std::string title_key;
|
|
std::vector<Item> items;
|
|
std::size_t cursor = 0;
|
|
};
|
|
|
|
// Inicialitza el singleton amb el renderer global (propietat del
|
|
// Director via SDLManager). Posterior get() retorna instancia valida.
|
|
static void init(Rendering::Renderer* renderer);
|
|
static void destroy();
|
|
[[nodiscard]] static auto get() -> ServiceMenu*;
|
|
|
|
// F12: alterna obrir/tancar amb animacio.
|
|
void toggle();
|
|
[[nodiscard]] auto isOpen() const -> bool;
|
|
|
|
void update(float delta_time);
|
|
void draw() const;
|
|
|
|
// Processa el KEY_DOWN. Retorna true si l'ha consumit (UP/DOWN/ENTER/
|
|
// RIGHT/BACKSPACE/LEFT mentre esta obert). false en qualsevol altre cas.
|
|
auto handleEvent(const SDL_Event& event) -> bool;
|
|
|
|
private:
|
|
explicit ServiceMenu(Rendering::Renderer* renderer);
|
|
|
|
void buildRootPage();
|
|
void pushSubmenuPlaceholder(const std::string& title_key);
|
|
void pushPage(Page page);
|
|
void popPage();
|
|
void moveCursor(int direction);
|
|
void activateCurrent();
|
|
|
|
// Alçada objectiu de la caixa per a la pagina superior (sense animacio).
|
|
[[nodiscard]] auto computeTargetHeight() const -> float;
|
|
|
|
// Y (top) de l'item index dins una caixa col·locada a box_y.
|
|
[[nodiscard]] static auto computeItemTopY(float box_y, std::size_t index) -> float;
|
|
|
|
Rendering::Renderer* renderer_;
|
|
Graphics::VectorText text_;
|
|
|
|
std::vector<Page> stack_;
|
|
bool open_ = false;
|
|
bool closing_ = false;
|
|
float open_anim_ = 0.0F; // 0..1 raw (sense easing)
|
|
float animated_h_ = 0.0F; // Alçada animada amb smoothing exponencial
|
|
|
|
// Estat del highlight (rectangle del cursor). Es lerpa cap a l'item
|
|
// actiu amb ease-out exponencial; quan el cursor "salta" (open o
|
|
// push/pop de pagina), s'enganxa directament al nou objectiu.
|
|
float highlight_y_ = 0.0F;
|
|
float highlight_h_ = 0.0F;
|
|
bool highlight_snap_ = true;
|
|
|
|
static std::unique_ptr<ServiceMenu> instance;
|
|
};
|
|
|
|
} // namespace System
|