Fix UTF filename scroll (#20121)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
		| @@ -461,8 +461,8 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop | ||||
|  | ||||
|     void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) { | ||||
|       if (mark_as_selected(row, sel)) { | ||||
|         const uint8_t maxlen = LCD_WIDTH - isDir; | ||||
|         if (isDir) lcd_put_wchar(LCD_STR_FOLDER[0]); | ||||
|         constexpr uint8_t maxlen = LCD_WIDTH - 1; | ||||
|         const pixel_len_t pixw = maxlen * (MENU_FONT_WIDTH); | ||||
|         pixel_len_t n = pixw - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), pixw); | ||||
|         while (n > MENU_FONT_WIDTH) n -= lcd_put_wchar(' '); | ||||
|   | ||||
| @@ -75,6 +75,11 @@ int pf_bsearch_r(void *userdata, size_t num_data, pf_bsearch_cb_comp_t cb_comp, | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| /* Returns true if passed byte is first byte of UTF-8 char sequence */ | ||||
| static inline bool utf8_is_start_byte_of_char(const uint8_t b) { | ||||
|   return 0x80 != (b & 0xC0); | ||||
| } | ||||
|  | ||||
| /* This function gets the character at the pstart position, interpreting UTF8 multibyte sequences | ||||
|    and returns the pointer to the next character */ | ||||
| uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t *pval) { | ||||
| @@ -131,8 +136,8 @@ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t | ||||
|       p++; | ||||
|     } | ||||
|   #endif | ||||
|   else if (0x80 == (0xC0 & valcur)) | ||||
|     for (; 0x80 == (0xC0 & valcur); ) { p++; valcur = cb_read_byte(p); } | ||||
|   else if (!utf8_is_start_byte_of_char(valcur)) | ||||
|     for (; !utf8_is_start_byte_of_char(valcur); ) { p++; valcur = cb_read_byte(p); } | ||||
|   else | ||||
|     for (; 0xFC < (0xFE & valcur); ) { p++; valcur = cb_read_byte(p); } | ||||
|  | ||||
| @@ -143,12 +148,12 @@ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t | ||||
|  | ||||
| static inline uint8_t utf8_strlen_cb(const char *pstart, read_byte_cb_t cb_read_byte) { | ||||
|   uint8_t cnt = 0; | ||||
|   uint8_t *pnext = (uint8_t *)pstart; | ||||
|   uint8_t *p = (uint8_t *)pstart; | ||||
|   for (;;) { | ||||
|     wchar_t ch; | ||||
|     pnext = get_utf8_value_cb(pnext, cb_read_byte, &ch); | ||||
|     if (!ch) break; | ||||
|     cnt++; | ||||
|     const uint8_t b = cb_read_byte(p); | ||||
|     if (!b) break; | ||||
|     if (utf8_is_start_byte_of_char(b)) cnt++; | ||||
|     p++; | ||||
|   } | ||||
|   return cnt; | ||||
| } | ||||
| @@ -160,3 +165,26 @@ uint8_t utf8_strlen(const char *pstart) { | ||||
| uint8_t utf8_strlen_P(PGM_P pstart) { | ||||
|   return utf8_strlen_cb(pstart, read_byte_rom); | ||||
| } | ||||
|  | ||||
| static inline uint8_t utf8_byte_pos_by_char_num_cb(const char *pstart, read_byte_cb_t cb_read_byte, const uint8_t charnum) { | ||||
|   uint8_t *p = (uint8_t *)pstart; | ||||
|   uint8_t char_idx = 0; | ||||
|   uint8_t byte_idx = 0; | ||||
|   for (;;) { | ||||
|     const uint8_t b = cb_read_byte(p + byte_idx); | ||||
|     if (!b) return byte_idx; // Termination byte of string | ||||
|     if (utf8_is_start_byte_of_char(b)) { | ||||
|       char_idx++; | ||||
|       if (char_idx == charnum + 1) return byte_idx; | ||||
|     } | ||||
|     byte_idx++; | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t utf8_byte_pos_by_char_num(const char *pstart, const uint8_t charnum) { | ||||
|   return utf8_byte_pos_by_char_num_cb(pstart, read_byte_ram, charnum); | ||||
| } | ||||
|  | ||||
| uint8_t utf8_byte_pos_by_char_num_P(PGM_P pstart, const uint8_t charnum) { | ||||
|   return utf8_byte_pos_by_char_num_cb(pstart, read_byte_rom, charnum); | ||||
| } | ||||
|   | ||||
| @@ -41,3 +41,7 @@ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t | ||||
| /* Returns length of string in CHARACTERS, NOT BYTES */ | ||||
| uint8_t utf8_strlen(const char *pstart); | ||||
| uint8_t utf8_strlen_P(PGM_P pstart); | ||||
|  | ||||
| /* Returns start byte position of desired char number */ | ||||
| uint8_t utf8_byte_pos_by_char_num(const char *pstart, const uint8_t charnum); | ||||
| uint8_t utf8_byte_pos_by_char_num_P(PGM_P pstart, const uint8_t charnum); | ||||
|   | ||||
| @@ -208,10 +208,13 @@ millis_t MarlinUI::next_button_update_ms; // = 0 | ||||
|             filename_scroll_pos = 0;                                       // Reset scroll to the start | ||||
|             lcd_status_update_delay = 8;                                   // Don't scroll right away | ||||
|           } | ||||
|           outstr += filename_scroll_pos; | ||||
|           // Advance byte position corresponding to filename_scroll_pos char position | ||||
|           outstr += TERN(UTF_FILENAME_SUPPORT, utf8_byte_pos_by_char_num(outstr, filename_scroll_pos), filename_scroll_pos); | ||||
|         } | ||||
|       #else | ||||
|         theCard.longFilename[maxlen] = '\0'; // cutoff at screen edge | ||||
|         theCard.longFilename[ | ||||
|           TERN(UTF_FILENAME_SUPPORT, utf8_byte_pos_by_char_num(theCard.longFilename, maxlen), maxlen) | ||||
|         ] = '\0'; // cutoff at screen edge | ||||
|       #endif | ||||
|     } | ||||
|     return outstr; | ||||
| @@ -1006,11 +1009,8 @@ void MarlinUI::update() { | ||||
|       // If scrolling of long file names is enabled and we are in the sd card menu, | ||||
|       // cause a refresh to occur until all the text has scrolled into view. | ||||
|       if (currentScreen == menu_media && !lcd_status_update_delay--) { | ||||
|         lcd_status_update_delay = 4; | ||||
|         if (++filename_scroll_pos > filename_scroll_max) { | ||||
|           filename_scroll_pos = 0; | ||||
|           lcd_status_update_delay = 12; | ||||
|         } | ||||
|         lcd_status_update_delay = ++filename_scroll_pos >= filename_scroll_max ? 12 : 4; // Long delay at end and start | ||||
|         if (filename_scroll_pos > filename_scroll_max) filename_scroll_pos = 0; | ||||
|         refresh(LCDVIEW_REDRAW_NOW); | ||||
|         RESET_STATUS_TIMEOUT(); | ||||
|       } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user