Browse Source

Fix UTF filename scroll (#20121)

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
LinFor 3 years ago
parent
commit
99c377b4e4
No account linked to committer's email address

+ 1
- 1
Marlin/src/lcd/dogm/marlinui_DOGM.cpp View File

@@ -461,8 +461,8 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
461 461
 
462 462
     void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
463 463
       if (mark_as_selected(row, sel)) {
464
+        const uint8_t maxlen = LCD_WIDTH - isDir;
464 465
         if (isDir) lcd_put_wchar(LCD_STR_FOLDER[0]);
465
-        constexpr uint8_t maxlen = LCD_WIDTH - 1;
466 466
         const pixel_len_t pixw = maxlen * (MENU_FONT_WIDTH);
467 467
         pixel_len_t n = pixw - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), pixw);
468 468
         while (n > MENU_FONT_WIDTH) n -= lcd_put_wchar(' ');

+ 35
- 7
Marlin/src/lcd/fontutils.cpp View File

@@ -75,6 +75,11 @@ int pf_bsearch_r(void *userdata, size_t num_data, pf_bsearch_cb_comp_t cb_comp,
75 75
   return -1;
76 76
 }
77 77
 
78
+/* Returns true if passed byte is first byte of UTF-8 char sequence */
79
+static inline bool utf8_is_start_byte_of_char(const uint8_t b) {
80
+  return 0x80 != (b & 0xC0);
81
+}
82
+
78 83
 /* This function gets the character at the pstart position, interpreting UTF8 multibyte sequences
79 84
    and returns the pointer to the next character */
80 85
 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
131 136
       p++;
132 137
     }
133 138
   #endif
134
-  else if (0x80 == (0xC0 & valcur))
135
-    for (; 0x80 == (0xC0 & valcur); ) { p++; valcur = cb_read_byte(p); }
139
+  else if (!utf8_is_start_byte_of_char(valcur))
140
+    for (; !utf8_is_start_byte_of_char(valcur); ) { p++; valcur = cb_read_byte(p); }
136 141
   else
137 142
     for (; 0xFC < (0xFE & valcur); ) { p++; valcur = cb_read_byte(p); }
138 143
 
@@ -143,12 +148,12 @@ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t
143 148
 
144 149
 static inline uint8_t utf8_strlen_cb(const char *pstart, read_byte_cb_t cb_read_byte) {
145 150
   uint8_t cnt = 0;
146
-  uint8_t *pnext = (uint8_t *)pstart;
151
+  uint8_t *p = (uint8_t *)pstart;
147 152
   for (;;) {
148
-    wchar_t ch;
149
-    pnext = get_utf8_value_cb(pnext, cb_read_byte, &ch);
150
-    if (!ch) break;
151
-    cnt++;
153
+    const uint8_t b = cb_read_byte(p);
154
+    if (!b) break;
155
+    if (utf8_is_start_byte_of_char(b)) cnt++;
156
+    p++;
152 157
   }
153 158
   return cnt;
154 159
 }
@@ -160,3 +165,26 @@ uint8_t utf8_strlen(const char *pstart) {
160 165
 uint8_t utf8_strlen_P(PGM_P pstart) {
161 166
   return utf8_strlen_cb(pstart, read_byte_rom);
162 167
 }
168
+
169
+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) {
170
+  uint8_t *p = (uint8_t *)pstart;
171
+  uint8_t char_idx = 0;
172
+  uint8_t byte_idx = 0;
173
+  for (;;) {
174
+    const uint8_t b = cb_read_byte(p + byte_idx);
175
+    if (!b) return byte_idx; // Termination byte of string
176
+    if (utf8_is_start_byte_of_char(b)) {
177
+      char_idx++;
178
+      if (char_idx == charnum + 1) return byte_idx;
179
+    }
180
+    byte_idx++;
181
+  }
182
+}
183
+
184
+uint8_t utf8_byte_pos_by_char_num(const char *pstart, const uint8_t charnum) {
185
+  return utf8_byte_pos_by_char_num_cb(pstart, read_byte_ram, charnum);
186
+}
187
+
188
+uint8_t utf8_byte_pos_by_char_num_P(PGM_P pstart, const uint8_t charnum) {
189
+  return utf8_byte_pos_by_char_num_cb(pstart, read_byte_rom, charnum);
190
+}

+ 4
- 0
Marlin/src/lcd/fontutils.h View File

@@ -41,3 +41,7 @@ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t
41 41
 /* Returns length of string in CHARACTERS, NOT BYTES */
42 42
 uint8_t utf8_strlen(const char *pstart);
43 43
 uint8_t utf8_strlen_P(PGM_P pstart);
44
+
45
+/* Returns start byte position of desired char number */
46
+uint8_t utf8_byte_pos_by_char_num(const char *pstart, const uint8_t charnum);
47
+uint8_t utf8_byte_pos_by_char_num_P(PGM_P pstart, const uint8_t charnum);

+ 7
- 7
Marlin/src/lcd/marlinui.cpp View File

@@ -208,10 +208,13 @@ millis_t MarlinUI::next_button_update_ms; // = 0
208 208
             filename_scroll_pos = 0;                                       // Reset scroll to the start
209 209
             lcd_status_update_delay = 8;                                   // Don't scroll right away
210 210
           }
211
-          outstr += filename_scroll_pos;
211
+          // Advance byte position corresponding to filename_scroll_pos char position
212
+          outstr += TERN(UTF_FILENAME_SUPPORT, utf8_byte_pos_by_char_num(outstr, filename_scroll_pos), filename_scroll_pos);
212 213
         }
213 214
       #else
214
-        theCard.longFilename[maxlen] = '\0'; // cutoff at screen edge
215
+        theCard.longFilename[
216
+          TERN(UTF_FILENAME_SUPPORT, utf8_byte_pos_by_char_num(theCard.longFilename, maxlen), maxlen)
217
+        ] = '\0'; // cutoff at screen edge
215 218
       #endif
216 219
     }
217 220
     return outstr;
@@ -1006,11 +1009,8 @@ void MarlinUI::update() {
1006 1009
       // If scrolling of long file names is enabled and we are in the sd card menu,
1007 1010
       // cause a refresh to occur until all the text has scrolled into view.
1008 1011
       if (currentScreen == menu_media && !lcd_status_update_delay--) {
1009
-        lcd_status_update_delay = 4;
1010
-        if (++filename_scroll_pos > filename_scroll_max) {
1011
-          filename_scroll_pos = 0;
1012
-          lcd_status_update_delay = 12;
1013
-        }
1012
+        lcd_status_update_delay = ++filename_scroll_pos >= filename_scroll_max ? 12 : 4; // Long delay at end and start
1013
+        if (filename_scroll_pos > filename_scroll_max) filename_scroll_pos = 0;
1014 1014
         refresh(LCDVIEW_REDRAW_NOW);
1015 1015
         RESET_STATUS_TIMEOUT();
1016 1016
       }

Loading…
Cancel
Save