fix(ui): trunca el value al menú amb "..." quan se sol·lapa amb la label

This commit is contained in:
JailDesigner committed 2026-04-24 18:15:39 +02:00
1 parent 996ff0053e
commit f3977170b7
1 file changed
+48 -7
+48 -7
View File
@@ -35,6 +35,10 @@ namespace {
constexpr int PAD_X = 10; constexpr int PAD_X = 10;
constexpr int GAP_Y = 6; constexpr int GAP_Y = 6;
constexpr int ITEM_GAP_Y = 2; constexpr int ITEM_GAP_Y = 2;
// Mínim buit entre la label (a l'esquerra) i el value (a la dreta).
// Si amb el value sencer no queda aquest gap, truncam amb "..." des
// del final del value.
constexpr int MIN_LABEL_VALUE_GAP = 6;
// Les fonts display reserven ~2 px de descendent al fons de la seua // Les fonts display reserven ~2 px de descendent al fons de la seua
// caixa (per a `g`, `p`, `q`...). Quan el títol no porta cap d'aquests // caixa (per a `g`, `p`, `q`...). Quan el títol no porta cap d'aquests
// glifs, eixos 2 px queden buits i el gap visual sota el títol sembla // glifs, eixos 2 px queden buits i el gap visual sota el títol sembla
@@ -755,6 +759,48 @@ auto ServiceMenu::buildKeyboardControls() -> Page {
namespace { namespace {
// Trunca `text` amb "..." perquè la seua amplada renderitzada no
// supere `max_w` píxels amb la font i el kerning donats. Port del
// helper de coffee_crisis_arcade_edition: estimació inicial a partir
// de l'amplada mitjana per caràcter i ajust iteratiu mesurant amb
// `Text::length`, per a fonts d'amplada variable on l'estimació
// només és aproximada.
auto truncateToFit(const Text& font, const std::string& text, int max_w, int kerning) -> std::string {
if (font.length(text, kerning) <= max_w) { return text; }
static constexpr const char* ELLIPSIS = "...";
const int ELLIPSIS_W = font.length(ELLIPSIS, kerning);
if (max_w <= ELLIPSIS_W || text.empty()) { return ELLIPSIS; }
const auto TOTAL_W = static_cast<float>(font.length(text, kerning));
const auto AVG_CHAR_W = TOTAL_W / static_cast<float>(text.size());
auto keep = static_cast<std::size_t>(static_cast<float>(max_w - ELLIPSIS_W) / AVG_CHAR_W);
keep = std::min(keep, text.size());
std::string out = text.substr(0, keep) + ELLIPSIS;
while (keep > 0 && font.length(out, kerning) > max_w) {
--keep;
out = text.substr(0, keep) + ELLIPSIS;
}
return out;
}
// Dibuixa el value d'un item a la dreta del box, truncant-lo amb
// "..." si no cap a l'esquerra de la label. Extret de `renderPage`
// per a mantenir la complexitat cognitiva sota el llindar de
// clang-tidy.
void drawItemValue(Text& font, int box_x, int box_w, int cursor_y, int cursor_width, const std::string& label, const std::string& value, int kerning, Uint8 color) {
const int LABEL_W = font.length(label, kerning);
const int AVAILABLE_W = box_w - (2 * PAD_X) - cursor_width - LABEL_W - MIN_LABEL_VALUE_GAP;
if (AVAILABLE_W <= 0) { return; }
const std::string DISPLAY = truncateToFit(font, value, AVAILABLE_W, kerning);
if (DISPLAY.empty()) { return; }
const int VALUE_W = font.length(DISPLAY, kerning);
font.writeDX(Text::COLOR_FLAG,
box_x + box_w - PAD_X - VALUE_W,
cursor_y,
DISPLAY,
kerning,
color);
}
// Mandos visibles al cycle d'un jugador: tots els connectats // Mandos visibles al cycle d'un jugador: tots els connectats
// EXCEPTE els reclamats per l'altre jugador. Així l'usuari mai pot // EXCEPTE els reclamats per l'altre jugador. Així l'usuari mai pot
// assignar el mateix mando a dos jugadors des de la UI — per // assignar el mateix mando a dos jugadors des de la UI — per
@@ -1025,13 +1071,8 @@ void ServiceMenu::renderPage(const Page& page, int box_x, int box_y, int box_w)
// només tenen ACTION / LABEL); els Toggle/Cycle viuen en pàgines // només tenen ACTION / LABEL); els Toggle/Cycle viuen en pàgines
// d'opcions amb layout esquerra-dreta. // d'opcions amb layout esquerra-dreta.
if (!page.center_items && !VALUE.empty()) { if (!page.center_items && !VALUE.empty()) {
const int VALUE_W = items_font_->length(VALUE, ITEM_KERNING); const Uint8 VALUE_COLOR = SELECTED ? UiConfig::get().menuCursor() : UiConfig::get().menuValue();
items_font_->writeDX(Text::COLOR_FLAG, drawItemValue(*items_font_, box_x, box_w, cursor_y, CURSOR_WIDTH, LABEL_TEXT, VALUE, ITEM_KERNING, VALUE_COLOR);
box_x + box_w - PAD_X - VALUE_W,
cursor_y,
VALUE,
ITEM_KERNING,
SELECTED ? UiConfig::get().menuCursor() : UiConfig::get().menuValue());
} }
cursor_y += ITEM_H; cursor_y += ITEM_H;