From 0a740a5be26d9c2eb690aebb25088d96b5e3cc62 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Mon, 30 Mar 2026 19:11:24 +0200 Subject: [PATCH] new: treballant en Console 2.0 --- source/game/ui/console.cpp | 134 ++++++++++++++++++++++++++++++------- source/game/ui/console.hpp | 7 +- 2 files changed, 116 insertions(+), 25 deletions(-) diff --git a/source/game/ui/console.cpp b/source/game/ui/console.cpp index 0f0670c..22cd623 100644 --- a/source/game/ui/console.cpp +++ b/source/game/ui/console.cpp @@ -5,6 +5,7 @@ #include // Para toupper #include // Para function #include // Para std::cout +#include // Para std::istringstream #include // Para string #include // Para vector @@ -787,17 +788,50 @@ static const std::vector COMMANDS = { return std::to_string(w) + "x" + std::to_string(h); }}, - // HELP / ? — Muestra ayuda en la terminal del sistema + // HELP / ? — Muestra ayuda en la terminal del sistema y lista de comandos en consola {.keyword = "HELP", .execute = [](const std::vector&) -> std::string { printHelp(); - return "Help printed to terminal"; + std::string result = + "Commands (see terminal):\n" + "fullscreen, zoom, intscale, vsync, driver\n" + "palette, audio, music, sound, set\n" + "restart, kiosk, exit, quit, show\n" + "hide, size, help\n"; + +#ifdef _DEBUG + result += "\n[debug] debug room scene"; + result += "\ncheat"; +#endif + return result; }}, {.keyword = "?", .execute = [](const std::vector&) -> std::string { printHelp(); - return "Help printed to terminal"; + std::string result = + "Commands (see terminal):\n" + "[video] fullscreen zoom\n" + "intscale vsync driver\n" + "palette\n" + "[audio] audio music sound\n" + "[game] set restart kiosk\n" + "exit quit\n" + "[info] show hide size help"; +#ifdef _DEBUG + result += "\n[debug] debug room scene"; + result += "\ncheat"; +#endif + return result; }}, }; +// ── Helpers ─────────────────────────────────────────────────────────────────── + +// Calcula la altura total de la consola para N líneas de mensaje (+ 1 línea de input) +static auto calcTargetHeight(int num_msg_lines) -> float { + constexpr int TEXT_SIZE = 6; + constexpr int PADDING_IN_V = TEXT_SIZE / 2; + return static_cast((TEXT_SIZE * (num_msg_lines + 1)) + (PADDING_IN_V * 2)); +} + // ── Singleton ───────────────────────────────────────────────────────────────── // [SINGLETON] @@ -822,13 +856,11 @@ auto Console::get() -> Console* { // Constructor Console::Console(const std::string& font_name) : text_(Resource::Cache::get()->getText(font_name)) { - const int TEXT_SIZE = 6; - const int PADDING_IN_V = TEXT_SIZE / 2; - height_ = static_cast((TEXT_SIZE * 2) + (PADDING_IN_V * 2)); + msg_lines_ = {std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION)}; + height_ = calcTargetHeight(static_cast(msg_lines_.size())); + target_height_ = height_; y_ = -height_; - msg_line_ = std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION); - buildSurface(); } @@ -849,9 +881,9 @@ void Console::buildSurface() { // Redibuja el texto dinámico sobre la surface (fondo + borde + líneas) void Console::redrawText() { const float WIDTH = Options::game.width; - const int TEXT_SIZE = 6; - const int PADDING_IN_H = TEXT_SIZE; - const int PADDING_IN_V = TEXT_SIZE / 2; + constexpr int TEXT_SIZE = 6; + constexpr int PADDING_IN_H = TEXT_SIZE; + constexpr int PADDING_IN_V = TEXT_SIZE / 2; auto previous_renderer = Screen::get()->getRendererSurface(); Screen::get()->setRendererSurface(surface_); @@ -861,13 +893,17 @@ void Console::redrawText() { SDL_FRect rect = {.x = 0, .y = 0, .w = WIDTH, .h = height_}; surface_->drawRectBorder(&rect, BORDER_COLOR); - // Línea 1: mensajes - text_->writeColored(PADDING_IN_H, PADDING_IN_V, msg_line_, MSG_COLOR); + // Líneas de mensaje (una o más); las que no caben en la Surface no se dibujan + int y_pos = PADDING_IN_V; + for (const auto& line : msg_lines_) { + text_->writeColored(PADDING_IN_H, y_pos, line, MSG_COLOR); + y_pos += TEXT_SIZE; + } - // Línea 2: prompt + input + cursor + // Línea de input (siempre la última) const bool SHOW_CURSOR = cursor_visible_ && (static_cast(input_line_.size()) < MAX_LINE_CHARS); const std::string INPUT_STR = "> " + input_line_ + (SHOW_CURSOR ? "_" : ""); - text_->writeColored(PADDING_IN_H, PADDING_IN_V + TEXT_SIZE, INPUT_STR, BORDER_COLOR); + text_->writeColored(PADDING_IN_H, y_pos, INPUT_STR, BORDER_COLOR); Screen::get()->setRendererSurface(previous_renderer); } @@ -888,6 +924,31 @@ void Console::update(float delta_time) { } } + // Animación de altura (resize cuando msg_lines_ cambia); solo en ACTIVE + if (status_ == Status::ACTIVE && height_ != target_height_) { + const float PREV_HEIGHT = height_; + if (height_ < target_height_) { + height_ = std::min(height_ + SLIDE_SPEED * delta_time, target_height_); + } else { + height_ = std::max(height_ - SLIDE_SPEED * delta_time, target_height_); + } + // Actualizar el Notifier incrementalmente con el delta de altura + if (Notifier::get() != nullptr) { + const int DELTA_PX = static_cast(height_) - static_cast(PREV_HEIGHT); + if (DELTA_PX > 0) { + Notifier::get()->addYOffset(DELTA_PX); + notifier_offset_applied_ += DELTA_PX; + } else if (DELTA_PX < 0) { + Notifier::get()->removeYOffset(-DELTA_PX); + notifier_offset_applied_ += DELTA_PX; + } + } + // Reconstruir la Surface al nuevo tamaño (pequeña: 256×~18-72px) + const float WIDTH = Options::game.width; + surface_ = std::make_shared(WIDTH, height_); + sprite_->setSurface(surface_); + } + // Redibujar texto cada frame redrawText(); @@ -914,6 +975,7 @@ void Console::update(float delta_time) { SDL_FRect rect = {.x = 0, .y = y_, .w = Options::game.width, .h = height_}; sprite_->setPosition(rect); + sprite_->setClip({.x = 0.0F, .y = 0.0F, .w = Options::game.width, .h = height_}); } // Renderiza la consola @@ -928,21 +990,34 @@ void Console::render() { void Console::toggle() { switch (status_) { case Status::HIDDEN: + // Al abrir: la consola siempre empieza con 1 línea de mensaje (altura base) + target_height_ = calcTargetHeight(static_cast(msg_lines_.size())); + height_ = target_height_; + y_ = -height_; status_ = Status::RISING; input_line_.clear(); cursor_timer_ = 0.0F; cursor_visible_ = true; SDL_StartTextInput(SDL_GetKeyboardFocus()); - if (Notifier::get() != nullptr) { Notifier::get()->addYOffset(static_cast(height_)); } + if (Notifier::get() != nullptr) { + const int OFFSET = static_cast(height_); + Notifier::get()->addYOffset(OFFSET); + notifier_offset_applied_ = OFFSET; + } if (on_toggle) { on_toggle(true); } break; case Status::ACTIVE: + // Al cerrar: resetear a 1 línea para el próximo ciclo; cerrar con la altura actual status_ = Status::VANISHING; - msg_line_ = std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION); + msg_lines_ = {std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION)}; + target_height_ = height_; // No animar durante VANISHING history_index_ = -1; saved_input_.clear(); SDL_StopTextInput(SDL_GetKeyboardFocus()); - if (Notifier::get() != nullptr) { Notifier::get()->removeYOffset(static_cast(height_)); } + if (Notifier::get() != nullptr) { + Notifier::get()->removeYOffset(notifier_offset_applied_); + notifier_offset_applied_ = 0; + } if (on_toggle) { on_toggle(false); } break; default: @@ -1009,20 +1084,31 @@ void Console::processCommand() { if (!TOKENS.empty()) { const std::string& cmd = TOKENS[0]; const std::vector ARGS(TOKENS.begin() + 1, TOKENS.end()); + std::string result; bool found = false; for (const auto& command : COMMANDS) { if (command.keyword == cmd) { - msg_line_ = command.execute(ARGS); + result = command.execute(ARGS); found = true; break; } } - if (!found) { - msg_line_ = "Unknown: " + cmd; - } - if (static_cast(msg_line_.size()) > MAX_LINE_CHARS) { - msg_line_.resize(MAX_LINE_CHARS); + if (!found) { result = "Unknown: " + cmd; } + + // Split en '\n' y truncar cada línea a MAX_LINE_CHARS + msg_lines_.clear(); + std::istringstream stream(result); + std::string line; + while (std::getline(stream, line)) { + if (static_cast(line.size()) > MAX_LINE_CHARS) { + line.resize(MAX_LINE_CHARS); + } + msg_lines_.push_back(std::move(line)); } + if (msg_lines_.empty()) { msg_lines_.push_back({}); } + + // Actualizar la altura objetivo para animar el resize + target_height_ = calcTargetHeight(static_cast(msg_lines_.size())); } } input_line_.clear(); diff --git a/source/game/ui/console.hpp b/source/game/ui/console.hpp index cd66267..64866b1 100644 --- a/source/game/ui/console.hpp +++ b/source/game/ui/console.hpp @@ -6,6 +6,7 @@ #include // Para function #include // Para shared_ptr #include // Para string +#include // Para vector class Surface; class Sprite; @@ -77,11 +78,15 @@ class Console { float height_{0.0F}; // Altura del panel // Estado de la entrada de texto - std::string msg_line_; // inicializado en constructor con CONSOLE_NAME + CONSOLE_VERSION + std::vector msg_lines_; // Líneas de mensaje (1 o más) std::string input_line_; float cursor_timer_{0.0F}; bool cursor_visible_{true}; + // Animación de altura dinámica + float target_height_{0.0F}; // Altura objetivo (según número de líneas de mensaje) + int notifier_offset_applied_{0}; // Acumulador del offset enviado al Notifier + // Historial de comandos (navegable con flechas arriba/abajo) std::deque history_; int history_index_{-1}; // -1 = en la entrada actual (presente)