fix(ui): trunca el value al menú amb "..." quan se sol·lapa amb la label
This commit is contained in:
1 parent
996ff0053e
commit
f3977170b7
1 file changed
+48
-7
@@ -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;
|
||||||
|
|||||||
Reference in new issue
Block a user