🚸 Fix MarlinUI expanded label alignment (#26339)

Co-authored-by: ellensp <530024+ellensp@users.noreply.github.com>
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
Keith Bennett 2023-10-22 13:15:38 -07:00 committed by GitHub
parent 156e7c1c54
commit 797ea5efa7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 106 additions and 82 deletions

View file

@ -1170,23 +1170,38 @@ void MarlinUI::draw_status_screen() {
int8_t n = LCD_WIDTH; int8_t n = LCD_WIDTH;
const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL);
const int8_t plen = ftpl ? utf8_strlen(ftpl) : 0,
vlen = vstr ? utf8_strlen(vstr) : 0; // Value length, if any
int8_t pad = (center || full) ? n - plen - vlen : 0; int8_t vlen = vstr ? utf8_strlen(vstr) : 0;
// Expanded label string and width in chars
char estr[calculateWidth(ftpl) + 3] = "\0";
int8_t llen = ftpl ? expand_u8str(estr, ftpl, itemIndex, itemStringC, itemStringF, n - vlen) : 0;
bool mv_colon = false;
if (vlen) {
// Move the leading colon from the value to the label below
mv_colon = (*vstr == ':');
// Shorter value, wider label
if (mv_colon) { vstr++; vlen--; llen++; }
// Remove leading spaces from the value and shorten
while (*vstr == ' ') { vstr++; vlen--; }
}
// Padding for center or full justification
int8_t pad = (center || full) ? n - llen - vlen : 0;
// SS_CENTER: Pad with half of the unused space first // SS_CENTER: Pad with half of the unused space first
if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) { lcd_put_u8str(F(" ")); n--; } if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad, --pad, --n) lcd_put_u8str(F(" "));
// Draw as much of the label as fits // Draw as much of the label as fits (without the relocated colon, drawn below)
if (plen) n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n - vlen); if (llen) n -= lcd_put_u8str_max(estr, n - vlen);
if (vlen && n > 0) { if (vlen && n > 0) {
// SS_FULL: Pad with enough space to justify the value // SS_FULL: Pad with enough space to justify the value
if (full && !center) { if (full && !center) {
// Move the leading colon from the value to the label // Move the leading colon from the value to the label
if (*vstr == ':') { n -= lcd_put_u8str(F(":")); vstr++; } if (mv_colon) n -= lcd_put_u8str(F(":"));
// Move spaces to the padding
while (*vstr == ' ') { vstr++; pad++; }
// Pad in-between // Pad in-between
for (; pad > 0; --pad) { lcd_put_u8str(F(" ")); n--; } for (; pad > 0; --pad) { lcd_put_u8str(F(" ")); n--; }
} }

View file

@ -975,23 +975,36 @@ void MarlinUI::draw_status_screen() {
uint8_t n = LCD_WIDTH; uint8_t n = LCD_WIDTH;
const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL);
const int8_t plen = ftpl ? utf8_strlen(ftpl) : 0,
vlen = vstr ? utf8_strlen(vstr) : 0; // Value length, if any
int8_t pad = (center || full) ? n - plen - vlen : 0; int8_t vlen = vstr ? utf8_strlen(vstr) : 0;
char estr[utf8_strlen(ftpl) + 3] = "\0";
int8_t llen = ftpl ? expand_u8str(estr, ftpl, itemIndex, itemStringC, itemStringF, n - vlen) : 0;
bool mv_colon = false;
if (vlen) {
// Move the leading colon from the value to the label below
mv_colon = (*vstr == ':');
// Shorter value, wider label
if (mv_colon) { vstr++; vlen--; llen++; }
// Remove leading spaces from the value and shorten
while (*vstr == ' ') { vstr++; vlen--; }
}
int8_t pad = (center || full) ? n - llen - vlen : 0;
// SS_CENTER: Pad with half of the unused space first // SS_CENTER: Pad with half of the unused space first
if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) { lcd.write(' '); n--; } if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) { lcd.write(' '); n--; }
// Draw as much of the label as fits // Draw as much of the label as fits
if (plen) n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n - vlen); if (llen) n -= lcd_put_u8str_max(estr, n - vlen);
if (vlen && n > 0) { if (vlen && n > 0) {
// SS_FULL: Pad with enough space to justify the value // SS_FULL: Pad with enough space to justify the value
if (full && !center) { if (full && !center) {
// Move the leading colon from the value to the label // Move the leading colon from the value to the label
if (*vstr == ':') { lcd.write(':'); vstr++; n--; } if (mv_colon) { lcd.write(':'); n--; }
// Move spaces to the padding
while (*vstr == ' ') { vstr++; pad++; }
// Pad in-between // Pad in-between
for (; pad > 0; --pad) { lcd.write(' '); n--; } for (; pad > 0; --pad) { lcd.write(' '); n--; }
} }

View file

@ -414,30 +414,46 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
if (!mark_as_selected(row, style & SS_INVERT)) return; if (!mark_as_selected(row, style & SS_INVERT)) return;
pixel_len_t n = LCD_PIXEL_WIDTH; // pixel width of string allowed pixel_len_t n = LCD_PIXEL_WIDTH; // pixel width of string allowed
const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL);
const int pwide = ftpl ? calculateWidth(ftpl) : 0,
vlen = vstr ? utf8_strlen(vstr) : 0; char estr[calculateWidth(ftpl) + 3] = "\0";
int pad = (center || full) ? ((LCD_PIXEL_WIDTH) - pwide - vlen * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH) : 0; pixel_len_t lwide = ftpl ? (MENU_FONT_WIDTH) * expand_u8str(estr, ftpl, itemIndex, itemStringC, itemStringF, (LCD_PIXEL_WIDTH) / (MENU_FONT_WIDTH)) : 0;
// Value length, if any
int8_t vlen = vstr ? utf8_strlen(vstr) : 0;
bool mv_colon = false;
if (vlen) {
// Move the leading colon from the value to the label below
mv_colon = (*vstr == ':');
// Shorter value, wider label
if (mv_colon) { vstr++; vlen--; lwide += MENU_FONT_WIDTH; }
// Remove leading spaces from the value and shorten
while (*vstr == ' ') { vstr++; vlen--; }
}
// Padding for center or full justification
int8_t pad = (center || full) ? ((LCD_PIXEL_WIDTH) - lwide - vlen * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH) : 0;
// SS_CENTER: Pad with half of the unused space first // SS_CENTER: Pad with half of the unused space first
if (center) for (int lpad = pad / 2; lpad > 0; --lpad) n -= lcd_put_u8str(F(" ")); if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) n -= lcd_put_u8str(F(" "));
// Draw as much of the label as fits // Draw as much of the label as fits (without the relocated colon, drawn below)
if (pwide) n -= lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, n / (MENU_FONT_WIDTH)) * (MENU_FONT_WIDTH); if (lwide) lcd_put_u8str_max(estr, n);
// Value string?
if (vlen) { if (vlen) {
// SS_FULL: Pad with enough space to justify the value // SS_FULL: Pad with enough space to justify the value
if (full && !center && n > MENU_FONT_WIDTH) { if (full && !center && n > MENU_FONT_WIDTH) {
// Move the leading colon from the value to the label // Draw the leading colon moved from the value to the label
if (*vstr == ':') { n -= lcd_put_u8str(F(":")); vstr++; } if (mv_colon) n -= lcd_put_u8str(F(":"));
// Move spaces to the padding
while (*vstr == ' ') { vstr++; pad++; }
// Pad in-between // Pad in-between
for (; pad > 0; --pad) n -= lcd_put_u8str(F(" ")); for (; pad > 0; --pad) n -= lcd_put_u8str(F(" "));
} }
// Draw the value string
n -= lcd_put_u8str_max(vstr, n); n -= lcd_put_u8str_max(vstr, n);
} }
// Always fill out the rest with spaces
while (n > MENU_FONT_WIDTH) n -= lcd_put_u8str(F(" ")); while (n > MENU_FONT_WIDTH) n -= lcd_put_u8str(F(" "));
} }

View file

@ -317,26 +317,39 @@ void MarlinUI::draw_status_message(const bool blink) {
dwin_string.set(); dwin_string.set();
const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL); const bool center = bool(style & SS_CENTER), full = bool(style & SS_FULL);
const int8_t plen = ftpl ? utf8_strlen(ftpl) : 0, int8_t plen = ftpl ? utf8_strlen(ftpl) : 0;
vlen = vstr ? utf8_strlen(vstr) : 0; const int8_t olen = plen;
// Value length, if any
int8_t vlen = vstr ? utf8_strlen(vstr) : 0;
bool mv_colon = false;
if (vlen) {
// Move the leading colon from the value to the label below
mv_colon = (*vstr == ':');
// Shorter value, wider label
if (mv_colon) { vstr++; vlen--; plen++; }
// Remove leading spaces from the value and shorten
while (*vstr == ' ') { vstr++; vlen--; }
}
int8_t pad = (center || full) ? (LCD_WIDTH) - 1 - plen - vlen : 0; int8_t pad = (center || full) ? (LCD_WIDTH) - 1 - plen - vlen : 0;
// SS_CENTER: Pad with half of the unused space first // SS_CENTER: Pad with half of the unused space first
if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad) dwin_string.add(' '); if (center) for (int8_t lpad = pad / 2; lpad > 0; --lpad, --pad) dwin_string.add(' ');
// Append the templated label string
if (plen) { if (plen) {
// Append the templated label string
dwin_string.add(ftpl, itemIndex, itemStringC, itemStringF); dwin_string.add(ftpl, itemIndex, itemStringC, itemStringF);
pad -= dwin_string.length - plen; // Remove padding if the string was expanded
pad -= dwin_string.length - olen;
} }
// SS_FULL: Pad with enough space to justify the value // SS_FULL: Pad with enough space to justify the value
if (vlen) { if (vlen) {
if (full && !center) { if (full && !center) {
// Move the leading colon from the value to the label // Append the leading colon moved from the value to the label
if (*vstr == ':') { dwin_string.add(':'); vstr++; } if (mv_colon) dwin_string.add(':');
// Move spaces to the padding
while (*vstr == ' ') { vstr++; pad++; }
// Pad in-between // Pad in-between
for (; pad > 0; --pad) dwin_string.add(' '); for (; pad > 0; --pad) dwin_string.add(' ');
} }
@ -345,7 +358,7 @@ void MarlinUI::draw_status_message(const bool blink) {
} }
// SS_CENTER: Pad the rest of the string // SS_CENTER: Pad the rest of the string
if (center) for (int8_t rpad = pad - (pad / 2); rpad > 0; --rpad) dwin_string.add(' '); if (center) while (pad--) dwin_string.add(' ');
lcd_moveto(1, row); lcd_moveto(1, row);
lcd_put_dwin_string(); lcd_put_dwin_string();

View file

@ -123,50 +123,10 @@ lcd_uint_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t in
* Return the number of characters emitted * Return the number of characters emitted
*/ */
lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) { lcd_uint_t lcd_put_u8str_P(PGM_P const ptpl, const int8_t ind, const char *cstr/*=nullptr*/, FSTR_P const fstr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) {
const uint8_t prop = USE_WIDE_GLYPH ? 2 : 1; char estr[maxlen + 2];
const uint8_t *p = (uint8_t*)ptpl; const lcd_uint_t outlen = expand_u8str_P(estr, ptpl, ind, cstr, fstr, maxlen);
int8_t n = maxlen; lcd_put_u8str_max(estr, maxlen * (MENU_FONT_WIDTH));
while (n > 0) { return outlen;
lchar_t wc;
p = get_utf8_value_cb(p, read_byte_rom, wc);
if (!wc) break;
if (wc == '{' || wc == '~' || wc == '*') {
if (ind >= 0) {
if (wc == '*') { lcd_put_u8str(F("E")); n--; }
if (n) {
int8_t inum = ind + ((wc == '{') ? 0 : LCD_FIRST_TOOL);
if (inum >= 10) {
lcd_put_lchar('0' + (inum / 10)); n--;
inum %= 10;
}
if (n) { lcd_put_lchar('0' + inum); n--; }
}
}
else {
PGM_P const b = ind == -2 ? GET_TEXT(MSG_CHAMBER) : GET_TEXT(MSG_BED);
n -= lcd_put_u8str_max_P(b, n * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH);
}
if (n) {
n -= lcd_put_u8str_max_P((PGM_P)p, n * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH);
break;
}
}
else if (wc == '$' && fstr) {
n -= lcd_put_u8str_max_P(FTOP(fstr), n * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH);
}
else if (wc == '$' && cstr) {
n -= lcd_put_u8str_max(cstr, n * (MENU_FONT_WIDTH)) / (MENU_FONT_WIDTH);
}
else if (wc == '@') {
lcd_put_lchar(AXIS_CHAR(ind));
n--;
}
else {
lcd_put_lchar(wc);
n -= wc > 255 ? prop : 1;
}
}
return maxlen - n;
} }
// Calculate UTF8 width with a simple check // Calculate UTF8 width with a simple check

View file

@ -104,7 +104,14 @@ void menu_advanced_settings();
#define __STOP_ITEM(F,S) PSTRING_ITEM_F_P(F, TEST(stops, S) ? PSTR(STR_ENDSTOP_HIT) : PSTR(STR_ENDSTOP_OPEN), SS_FULL); #define __STOP_ITEM(F,S) PSTRING_ITEM_F_P(F, TEST(stops, S) ? PSTR(STR_ENDSTOP_HIT) : PSTR(STR_ENDSTOP_OPEN), SS_FULL);
#define _STOP_ITEM(L,S) __STOP_ITEM(F(L), S) #define _STOP_ITEM(L,S) __STOP_ITEM(F(L), S)
#define STOP_ITEM(A,I,M,L) TERN(HAS_##A##I##_##M##_STATE, _STOP_ITEM, _IF_1_ELSE)(STRINGIFY(A) STRINGIFY(I) " " STRINGIFY(L), A##I##_##M) #if HAS_X2_STATE || HAS_Y2_STATE || HAS_Z2_STATE
#define _S1_EXP_ ~,
#define _S1_SP_(I) THIRD(I, " ", "")
#define S1_SPACE(I) _S1_SP_(_CAT(_S1_EXP_,I))
#else
#define S1_SPACE(I)
#endif
#define STOP_ITEM(A,I,M,L) TERN(HAS_##A##I##_##M##_STATE, _STOP_ITEM, _IF_1_ELSE)(STRINGIFY(A) STRINGIFY(I) S1_SPACE(I) " " L, A##I##_##M)
#define STOP_MINMAX(A,I) STOP_ITEM(A,I,MIN,"Min") STOP_ITEM(A,I,MAX,"Max") #define STOP_MINMAX(A,I) STOP_ITEM(A,I,MIN,"Min") STOP_ITEM(A,I,MAX,"Max")
#define FIL_ITEM(N) PSTRING_ITEM_N_P(N-1, MSG_FILAMENT_EN, (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) ? PSTR("PRESENT") : PSTR("out"), SS_FULL); #define FIL_ITEM(N) PSTRING_ITEM_N_P(N-1, MSG_FILAMENT_EN, (READ(FIL_RUNOUT##N##_PIN) != FIL_RUNOUT##N##_STATE) ? PSTR("PRESENT") : PSTR("out"), SS_FULL);