new: treballant en Console 2.0

This commit is contained in:
2026-03-30 19:11:24 +02:00
parent 9e1b2b8960
commit 0a740a5be2
2 changed files with 116 additions and 25 deletions

View File

@@ -5,6 +5,7 @@
#include <cctype> // Para toupper
#include <functional> // Para function
#include <iostream> // Para std::cout
#include <sstream> // Para std::istringstream
#include <string> // Para string
#include <vector> // Para vector
@@ -787,17 +788,50 @@ static const std::vector<ConsoleCommand> 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>&) -> 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>&) -> 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<float>((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<float>((TEXT_SIZE * 2) + (PADDING_IN_V * 2));
msg_lines_ = {std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION)};
height_ = calcTargetHeight(static_cast<int>(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<int>(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<int>(height_) - static_cast<int>(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<Surface>(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<int>(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<int>(height_)); }
if (Notifier::get() != nullptr) {
const int OFFSET = static_cast<int>(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<int>(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<std::string> 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 (!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<int>(line.size()) > MAX_LINE_CHARS) {
line.resize(MAX_LINE_CHARS);
}
if (static_cast<int>(msg_line_.size()) > MAX_LINE_CHARS) {
msg_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<int>(msg_lines_.size()));
}
}
input_line_.clear();

View File

@@ -6,6 +6,7 @@
#include <functional> // Para function
#include <memory> // Para shared_ptr
#include <string> // Para string
#include <vector> // 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<std::string> 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<std::string> history_;
int history_index_{-1}; // -1 = en la entrada actual (presente)