fix: corregir padding asimétrico en HelpOverlay con getGlyphHeight()

Añade TextRenderer::getGlyphHeight() (ascent - descent, sin line_gap)
y lo usa en calculateTextDimensions() para descontar el gap sobrante
de la última línea, aproximando padding superior e inferior simétricos.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 19:29:35 +01:00
parent b9b5f0b29f
commit dcea4ebbab
3 changed files with 63 additions and 47 deletions

View File

@@ -361,3 +361,11 @@ int TextRenderer::getTextHeight() {
return TTF_GetFontHeight(font_); return TTF_GetFontHeight(font_);
} }
int TextRenderer::getGlyphHeight() {
if (!isInitialized()) {
return 0;
}
return TTF_GetFontAscent(font_) - TTF_GetFontDescent(font_);
}

View File

@@ -42,9 +42,12 @@ public:
// Útil para notificaciones y elementos UI de tamaño fijo // Útil para notificaciones y elementos UI de tamaño fijo
int getTextWidthPhysical(const char* text); int getTextWidthPhysical(const char* text);
// Obtiene la altura de la fuente // Obtiene la altura de la fuente (incluye line_gap)
int getTextHeight(); int getTextHeight();
// Obtiene la altura real del glifo (ascender + |descendente|, sin line_gap)
int getGlyphHeight();
// Verifica si está inicializado correctamente // Verifica si está inicializado correctamente
bool isInitialized() const { return font_ != nullptr && renderer_ != nullptr; } bool isInitialized() const { return font_ != nullptr && renderer_ != nullptr; }

View File

@@ -30,7 +30,7 @@ HelpOverlay::HelpOverlay()
{"SIMULACIÓN", ""}, {"SIMULACIÓN", ""},
{"1-8", "Escenarios (10 a 50.000 pelotas)"}, {"1-8", "Escenarios (10 a 50.000 pelotas)"},
{"F", "Cambia entre figura y física"}, {"F", "Cambia entre figura y física"},
{"B", "Modo Boids"}, {"B", "Cambia entre boids y física"},
{"ESPACIO", "Impulso contra gravedad"}, {"ESPACIO", "Impulso contra gravedad"},
{"G", "Activar / Desactivar gravedad"}, {"G", "Activar / Desactivar gravedad"},
{"CURSORES", "Dirección de gravedad"}, {"CURSORES", "Dirección de gravedad"},
@@ -47,9 +47,9 @@ HelpOverlay::HelpOverlay()
// COLUMNA 2: MODOS // COLUMNA 2: MODOS
{"MODOS", ""}, {"MODOS", ""},
{"D", "Modo demo"}, {"D", "Activar / Desactivar modo demo"},
{"L", "Modo demo lite"}, {"L", "Activar / Desactivar modo demo lite"},
{"K", "Modo logo"}, {"K", "Activar / Desactivar modo logo"},
{"", ""}, // Separador {"", ""}, // Separador
// COLUMNA 2: VISUAL // COLUMNA 2: VISUAL
@@ -202,14 +202,14 @@ void HelpOverlay::calculateTextDimensions(int& max_width, int& total_height) {
column2_width_ = max_col2_width; column2_width_ = max_col2_width;
column3_width_ = max_col3_width; column3_width_ = max_col3_width;
// Ancho total: 3 columnas + 4 paddings (izq, entre cols x2, der) // Gap entre columnas: doble del padding para dar más respiro
max_width = max_col1_width + max_col2_width + max_col3_width + padding * 4; int col_gap = padding * 2;
// Altura: contar unidades de altura por columna (en "medias líneas" para precisión) // Ancho total: 3 columnas + padding izq/der + 2 gaps entre columnas
// - línea normal = 2 unidades, encabezado = 2 unidades (+2px ignorados aquí), separador = 1 unidad max_width = max_col1_width + max_col2_width + max_col3_width + padding * 2 + col_gap * 2;
int col1_half_lines = 0;
int col2_half_lines = 0; // Calcular altura real simulando exactamente lo que hace el render
int col3_half_lines = 0; int col_heights[3] = {0, 0, 0};
current_column = 0; current_column = 0;
for (const auto& binding : key_bindings_) { for (const auto& binding : key_bindings_) {
@@ -218,23 +218,23 @@ void HelpOverlay::calculateTextDimensions(int& max_width, int& total_height) {
continue; continue;
} }
int units = (binding.key[0] == '\0') ? 1 : 2; // separador = 1, línea/encabezado = 2 if (binding.key[0] == '\0') {
col_heights[current_column] += line_height; // separador vacío
if (current_column == 0) { } else if (binding.description[0] == '\0') {
col1_half_lines += units; col_heights[current_column] += line_height; // encabezado
} else if (current_column == 1) {
col2_half_lines += units;
} else { } else {
col3_half_lines += units; col_heights[current_column] += line_height; // línea normal
} }
} }
// Convertir a altura real: unidades * (line_height / 2) int content_height = std::max({col_heights[0], col_heights[1], col_heights[2]});
int max_half_lines = std::max({col1_half_lines, col2_half_lines, col3_half_lines});
int content_height = max_half_lines * line_height / 2;
// Altura: título (2 líneas) + contenido + padding superior e inferior // Eliminar el line_gap de la última línea: ese gap es espacio entre líneas,
total_height = line_height * 2 + content_height + padding * 2; // pero la última línea no tiene siguiente, así que queda como padding muerto.
int glyph_height = text_renderer_->getGlyphHeight();
int visual_content_height = content_height - (line_height - glyph_height);
total_height = visual_content_height + padding * 2;
} }
void HelpOverlay::calculateBoxDimensions() { void HelpOverlay::calculateBoxDimensions() {
@@ -341,31 +341,28 @@ void HelpOverlay::rebuildCachedTexture() {
// Configuración de espaciado // Configuración de espaciado
int line_height = text_renderer_->getTextHeight(); int line_height = text_renderer_->getTextHeight();
// Padding dinámico basado en altura física: 25px para >= 600px, escalado proporcionalmente para menores
int padding = (physical_height_ >= 600) ? 25 : std::max(10, physical_height_ / 24); int padding = (physical_height_ >= 600) ? 25 : std::max(10, physical_height_ / 24);
int col_gap = padding * 2;
// Posición X de inicio de cada columna
int col_start[3];
col_start[0] = padding;
col_start[1] = padding + column1_width_ + col_gap;
col_start[2] = padding + column1_width_ + col_gap + column2_width_ + col_gap;
// Ancho de cada columna (para centrado interno)
int col_width[3] = {column1_width_, column2_width_, column3_width_};
int current_x = padding; // Coordenadas relativas a la textura (0,0)
int current_y = padding; int current_y = padding;
int current_column = 0; int current_column = 0;
// Título principal
const char* title = "CONTROLES - ViBe3 Physics";
int title_width = text_renderer_->getTextWidthPhysical(title);
text_renderer_->printAbsolute(box_width_ / 2 - title_width / 2, current_y, title, category_color);
current_y += line_height * 2;
int content_start_y = current_y; int content_start_y = current_y;
// Renderizar cada línea // Renderizar cada línea
for (const auto& binding : key_bindings_) { for (const auto& binding : key_bindings_) {
if (strcmp(binding.key, "[new_col]") == 0 && binding.description[0] == '\0') { if (strcmp(binding.key, "[new_col]") == 0 && binding.description[0] == '\0') {
if (current_column == 0) { if (current_column < 2) {
current_column = 1; current_column++;
current_x = padding + column1_width_ + padding;
current_y = content_start_y;
} else if (current_column == 1) {
current_column = 2;
current_x = padding + column1_width_ + padding + column2_width_ + padding;
current_y = content_start_y; current_y = content_start_y;
} }
continue; continue;
@@ -376,22 +373,30 @@ void HelpOverlay::rebuildCachedTexture() {
continue; continue;
} }
int cx = col_start[current_column];
int cw = col_width[current_column];
if (binding.description[0] == '\0') { if (binding.description[0] == '\0') {
if (binding.key[0] == '\0') { if (binding.key[0] == '\0') {
// Separador vacío: avanzar media línea // Separador vacío: avanzar una línea completa
current_y += line_height / 2; current_y += line_height;
} else { } else {
// Encabezado de sección // Encabezado de sección — centrado en la columna
text_renderer_->printAbsolute(current_x, current_y, binding.key, category_color); int w = text_renderer_->getTextWidthPhysical(binding.key);
current_y += line_height + 2; text_renderer_->printAbsolute(cx + (cw - w) / 2, current_y, binding.key, category_color);
current_y += line_height;
} }
continue; continue;
} }
// Tecla en category_color, descripción en content_color // Par tecla+descripción — centrado como bloque en la columna
text_renderer_->printAbsolute(current_x, current_y, binding.key, category_color);
int key_width = text_renderer_->getTextWidthPhysical(binding.key); int key_width = text_renderer_->getTextWidthPhysical(binding.key);
text_renderer_->printAbsolute(current_x + key_width + 10, current_y, binding.description, content_color); int desc_width = text_renderer_->getTextWidthPhysical(binding.description);
int total_width = key_width + 10 + desc_width;
int line_x = cx + (cw - total_width) / 2;
text_renderer_->printAbsolute(line_x, current_y, binding.key, category_color);
text_renderer_->printAbsolute(line_x + key_width + 10, current_y, binding.description, content_color);
current_y += line_height; current_y += line_height;
} }