new: treballant en Console 2.0
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include <cctype> // Para toupper
|
#include <cctype> // Para toupper
|
||||||
#include <functional> // Para function
|
#include <functional> // Para function
|
||||||
#include <iostream> // Para std::cout
|
#include <iostream> // Para std::cout
|
||||||
|
#include <sstream> // Para std::istringstream
|
||||||
#include <string> // Para string
|
#include <string> // Para string
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
@@ -787,17 +788,50 @@ static const std::vector<ConsoleCommand> COMMANDS = {
|
|||||||
return std::to_string(w) + "x" + std::to_string(h);
|
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 {
|
{.keyword = "HELP", .execute = [](const std::vector<std::string>&) -> std::string {
|
||||||
printHelp();
|
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 {
|
{.keyword = "?", .execute = [](const std::vector<std::string>&) -> std::string {
|
||||||
printHelp();
|
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 ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
// [SINGLETON]
|
// [SINGLETON]
|
||||||
@@ -822,13 +856,11 @@ auto Console::get() -> Console* {
|
|||||||
// Constructor
|
// Constructor
|
||||||
Console::Console(const std::string& font_name)
|
Console::Console(const std::string& font_name)
|
||||||
: text_(Resource::Cache::get()->getText(font_name)) {
|
: text_(Resource::Cache::get()->getText(font_name)) {
|
||||||
const int TEXT_SIZE = 6;
|
msg_lines_ = {std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION)};
|
||||||
const int PADDING_IN_V = TEXT_SIZE / 2;
|
height_ = calcTargetHeight(static_cast<int>(msg_lines_.size()));
|
||||||
height_ = static_cast<float>((TEXT_SIZE * 2) + (PADDING_IN_V * 2));
|
target_height_ = height_;
|
||||||
y_ = -height_;
|
y_ = -height_;
|
||||||
|
|
||||||
msg_line_ = std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION);
|
|
||||||
|
|
||||||
buildSurface();
|
buildSurface();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -849,9 +881,9 @@ void Console::buildSurface() {
|
|||||||
// Redibuja el texto dinámico sobre la surface (fondo + borde + líneas)
|
// Redibuja el texto dinámico sobre la surface (fondo + borde + líneas)
|
||||||
void Console::redrawText() {
|
void Console::redrawText() {
|
||||||
const float WIDTH = Options::game.width;
|
const float WIDTH = Options::game.width;
|
||||||
const int TEXT_SIZE = 6;
|
constexpr int TEXT_SIZE = 6;
|
||||||
const int PADDING_IN_H = TEXT_SIZE;
|
constexpr int PADDING_IN_H = TEXT_SIZE;
|
||||||
const int PADDING_IN_V = TEXT_SIZE / 2;
|
constexpr int PADDING_IN_V = TEXT_SIZE / 2;
|
||||||
|
|
||||||
auto previous_renderer = Screen::get()->getRendererSurface();
|
auto previous_renderer = Screen::get()->getRendererSurface();
|
||||||
Screen::get()->setRendererSurface(surface_);
|
Screen::get()->setRendererSurface(surface_);
|
||||||
@@ -861,13 +893,17 @@ void Console::redrawText() {
|
|||||||
SDL_FRect rect = {.x = 0, .y = 0, .w = WIDTH, .h = height_};
|
SDL_FRect rect = {.x = 0, .y = 0, .w = WIDTH, .h = height_};
|
||||||
surface_->drawRectBorder(&rect, BORDER_COLOR);
|
surface_->drawRectBorder(&rect, BORDER_COLOR);
|
||||||
|
|
||||||
// Línea 1: mensajes
|
// Líneas de mensaje (una o más); las que no caben en la Surface no se dibujan
|
||||||
text_->writeColored(PADDING_IN_H, PADDING_IN_V, msg_line_, MSG_COLOR);
|
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 bool SHOW_CURSOR = cursor_visible_ && (static_cast<int>(input_line_.size()) < MAX_LINE_CHARS);
|
||||||
const std::string INPUT_STR = "> " + input_line_ + (SHOW_CURSOR ? "_" : "");
|
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);
|
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
|
// Redibujar texto cada frame
|
||||||
redrawText();
|
redrawText();
|
||||||
|
|
||||||
@@ -914,6 +975,7 @@ void Console::update(float delta_time) {
|
|||||||
|
|
||||||
SDL_FRect rect = {.x = 0, .y = y_, .w = Options::game.width, .h = height_};
|
SDL_FRect rect = {.x = 0, .y = y_, .w = Options::game.width, .h = height_};
|
||||||
sprite_->setPosition(rect);
|
sprite_->setPosition(rect);
|
||||||
|
sprite_->setClip({.x = 0.0F, .y = 0.0F, .w = Options::game.width, .h = height_});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renderiza la consola
|
// Renderiza la consola
|
||||||
@@ -928,21 +990,34 @@ void Console::render() {
|
|||||||
void Console::toggle() {
|
void Console::toggle() {
|
||||||
switch (status_) {
|
switch (status_) {
|
||||||
case Status::HIDDEN:
|
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;
|
status_ = Status::RISING;
|
||||||
input_line_.clear();
|
input_line_.clear();
|
||||||
cursor_timer_ = 0.0F;
|
cursor_timer_ = 0.0F;
|
||||||
cursor_visible_ = true;
|
cursor_visible_ = true;
|
||||||
SDL_StartTextInput(SDL_GetKeyboardFocus());
|
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); }
|
if (on_toggle) { on_toggle(true); }
|
||||||
break;
|
break;
|
||||||
case Status::ACTIVE:
|
case Status::ACTIVE:
|
||||||
|
// Al cerrar: resetear a 1 línea para el próximo ciclo; cerrar con la altura actual
|
||||||
status_ = Status::VANISHING;
|
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;
|
history_index_ = -1;
|
||||||
saved_input_.clear();
|
saved_input_.clear();
|
||||||
SDL_StopTextInput(SDL_GetKeyboardFocus());
|
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); }
|
if (on_toggle) { on_toggle(false); }
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1009,20 +1084,31 @@ void Console::processCommand() {
|
|||||||
if (!TOKENS.empty()) {
|
if (!TOKENS.empty()) {
|
||||||
const std::string& cmd = TOKENS[0];
|
const std::string& cmd = TOKENS[0];
|
||||||
const std::vector<std::string> ARGS(TOKENS.begin() + 1, TOKENS.end());
|
const std::vector<std::string> ARGS(TOKENS.begin() + 1, TOKENS.end());
|
||||||
|
std::string result;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (const auto& command : COMMANDS) {
|
for (const auto& command : COMMANDS) {
|
||||||
if (command.keyword == cmd) {
|
if (command.keyword == cmd) {
|
||||||
msg_line_ = command.execute(ARGS);
|
result = command.execute(ARGS);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) { result = "Unknown: " + cmd; }
|
||||||
msg_line_ = "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_lines_.push_back(std::move(line));
|
||||||
msg_line_.resize(MAX_LINE_CHARS);
|
|
||||||
}
|
}
|
||||||
|
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();
|
input_line_.clear();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <functional> // Para function
|
#include <functional> // Para function
|
||||||
#include <memory> // Para shared_ptr
|
#include <memory> // Para shared_ptr
|
||||||
#include <string> // Para string
|
#include <string> // Para string
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
class Surface;
|
class Surface;
|
||||||
class Sprite;
|
class Sprite;
|
||||||
@@ -77,11 +78,15 @@ class Console {
|
|||||||
float height_{0.0F}; // Altura del panel
|
float height_{0.0F}; // Altura del panel
|
||||||
|
|
||||||
// Estado de la entrada de texto
|
// 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_;
|
std::string input_line_;
|
||||||
float cursor_timer_{0.0F};
|
float cursor_timer_{0.0F};
|
||||||
bool cursor_visible_{true};
|
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)
|
// Historial de comandos (navegable con flechas arriba/abajo)
|
||||||
std::deque<std::string> history_;
|
std::deque<std::string> history_;
|
||||||
int history_index_{-1}; // -1 = en la entrada actual (presente)
|
int history_index_{-1}; // -1 = en la entrada actual (presente)
|
||||||
|
|||||||
Reference in New Issue
Block a user