|
@@ -29,25 +29,30 @@ namespace FTDI {
|
29
|
29
|
* be broken so that the display width is less than w. The line will also
|
30
|
30
|
* be broken after a '\n'. Returns the display width of the line.
|
31
|
31
|
*/
|
32
|
|
- static uint16_t find_line_break(const FontMetrics &fm, uint16_t w, const char *str, const char *&end) {
|
33
|
|
- w -= fm.get_char_width(' ');
|
|
32
|
+ static uint16_t find_line_break(const FontMetrics &utf8_fm, const CLCD::FontMetrics &clcd_fm, const uint16_t w, const char *str, const char *&end, bool use_utf8) {
|
34
|
33
|
const char *p = str;
|
35
|
34
|
end = str;
|
36
|
35
|
uint16_t lw = 0, result = 0;
|
37
|
36
|
for (;;) {
|
38
|
|
- utf8_char_t c = get_utf8_char_and_inc(p);
|
39
|
|
- if (c == ' ' || c == '\n' || c == '\0') {
|
40
|
|
- if (lw < w || end == str) {
|
41
|
|
- end = (c == '\0') ? p-1 : p;
|
|
37
|
+ const char *next = p;
|
|
38
|
+ utf8_char_t c = get_utf8_char_and_inc(next);
|
|
39
|
+ // Decide whether to break the string at this location
|
|
40
|
+ if (c == '\n' || c == '\0' || c == ' ') {
|
|
41
|
+ end = p;
|
|
42
|
+ result = lw;
|
|
43
|
+ }
|
|
44
|
+ if (c == '\n' || c == '\0') break;
|
|
45
|
+ // Now add the length of the current character to the tally.
|
|
46
|
+ lw += use_utf8 ? utf8_fm.get_char_width(c) : clcd_fm.char_widths[(uint8_t)c];
|
|
47
|
+ // Stop processing once string exceeds the display width
|
|
48
|
+ if (lw >= w) {
|
|
49
|
+ if (end == str) {
|
|
50
|
+ end = p;
|
42
|
51
|
result = lw;
|
43
|
52
|
}
|
44
|
|
- if (c == '\0' || c == '\n') break;
|
|
53
|
+ break;
|
45
|
54
|
}
|
46
|
|
- lw += fm.get_char_width(c);
|
47
|
|
- }
|
48
|
|
- if (end == str) {
|
49
|
|
- end = p-1;
|
50
|
|
- result = lw;
|
|
55
|
+ p = next;
|
51
|
56
|
}
|
52
|
57
|
return result;
|
53
|
58
|
}
|
|
@@ -55,17 +60,18 @@ namespace FTDI {
|
55
|
60
|
/**
|
56
|
61
|
* This function returns a measurements of the word-wrapped text box.
|
57
|
62
|
*/
|
58
|
|
- static void measure_text_box(const FontMetrics &fm, const char *str, uint16_t &width, uint16_t &height) {
|
|
63
|
+ static void measure_text_box(const FontMetrics &utf8_fm, const CLCD::FontMetrics &clcd_fm, const char *str, uint16_t &width, uint16_t &height, bool use_utf8) {
|
59
|
64
|
const char *line_start = (const char*)str;
|
60
|
65
|
const char *line_end;
|
61
|
66
|
const uint16_t wrap_width = width;
|
62
|
67
|
width = height = 0;
|
63
|
68
|
for (;;) {
|
64
|
|
- uint16_t line_width = find_line_break(fm, wrap_width, line_start, line_end);
|
65
|
|
- if (line_end == line_start) break;
|
|
69
|
+ uint16_t line_width = find_line_break(utf8_fm, clcd_fm, wrap_width, line_start, line_end, use_utf8);
|
66
|
70
|
width = max(width, line_width);
|
67
|
|
- height += fm.get_height();
|
|
71
|
+ height += utf8_fm.get_height();
|
68
|
72
|
line_start = line_end;
|
|
73
|
+ if (line_start[0] == '\n' || line_start[0] == ' ') line_start++;
|
|
74
|
+ if (line_start[0] == '\0') break;
|
69
|
75
|
}
|
70
|
76
|
}
|
71
|
77
|
|
|
@@ -73,41 +79,45 @@ namespace FTDI {
|
73
|
79
|
* This function draws text inside a bounding box, doing word wrapping and using the largest font that will fit.
|
74
|
80
|
*/
|
75
|
81
|
void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options, uint8_t font) {
|
|
82
|
+ #if ENABLED(TOUCH_UI_USE_UTF8)
|
|
83
|
+ const bool use_utf8 = has_utf8_chars(str);
|
|
84
|
+ #else
|
|
85
|
+ constexpr bool use_utf8 = false;
|
|
86
|
+ #endif
|
76
|
87
|
uint16_t box_width, box_height;
|
77
|
88
|
|
78
|
|
- FontMetrics fm(font);
|
|
89
|
+ FontMetrics utf8_fm(font);
|
|
90
|
+ CLCD::FontMetrics clcd_fm;
|
|
91
|
+ clcd_fm.load(font);
|
79
|
92
|
|
80
|
93
|
// Shrink the font until we find a font that fits
|
81
|
94
|
for (;;) {
|
82
|
95
|
box_width = w;
|
83
|
|
- measure_text_box(fm, str, box_width, box_height);
|
|
96
|
+ measure_text_box(utf8_fm, clcd_fm, str, box_width, box_height, use_utf8);
|
84
|
97
|
if (box_width <= (uint16_t)w && box_height <= (uint16_t)h) break;
|
85
|
98
|
if (font == 26) break;
|
86
|
|
- fm.load(--font);
|
|
99
|
+ utf8_fm.load(--font);
|
|
100
|
+ clcd_fm.load(font);
|
87
|
101
|
}
|
88
|
102
|
|
89
|
103
|
const uint16_t dx = (options & OPT_RIGHTX) ? w :
|
90
|
|
- (options & OPT_CENTERX) ? w/2 : 0;
|
91
|
|
- const uint16_t dy = (options & OPT_BOTTOMY) ? (h - box_height) :
|
92
|
|
- (options & OPT_CENTERY) ? (h - box_height)/2 : 0;
|
|
104
|
+ (options & OPT_CENTERX) ? w / 2 : 0,
|
|
105
|
+ dy = (options & OPT_BOTTOMY) ? (h - box_height) :
|
|
106
|
+ (options & OPT_CENTERY) ? (h - box_height) / 2 : 0;
|
93
|
107
|
|
94
|
|
- const char *line_start = str;
|
95
|
|
- const char *line_end;
|
|
108
|
+ const char *line_start = str, *line_end;
|
96
|
109
|
for (;;) {
|
97
|
|
- find_line_break(fm, w, line_start, line_end);
|
98
|
|
- if (line_end == line_start) break;
|
|
110
|
+ find_line_break(utf8_fm, clcd_fm, w, line_start, line_end, use_utf8);
|
99
|
111
|
|
100
|
112
|
const size_t line_len = line_end - line_start;
|
101
|
113
|
if (line_len) {
|
102
|
114
|
char line[line_len + 1];
|
103
|
115
|
strncpy(line, line_start, line_len);
|
104
|
116
|
line[line_len] = 0;
|
105
|
|
- if (line[line_len - 1] == '\n' || line[line_len - 1] == ' ')
|
106
|
|
- line[line_len - 1] = 0;
|
107
|
117
|
|
108
|
118
|
#if ENABLED(TOUCH_UI_USE_UTF8)
|
109
|
|
- if (has_utf8_chars(line)) {
|
110
|
|
- draw_utf8_text(cmd, x + dx, y + dy, line, fm.fs, options & ~(OPT_CENTERY | OPT_BOTTOMY));
|
|
119
|
+ if (use_utf8) {
|
|
120
|
+ draw_utf8_text(cmd, x + dx, y + dy, line, utf8_fm.fs, options & ~(OPT_CENTERY | OPT_BOTTOMY));
|
111
|
121
|
} else
|
112
|
122
|
#endif
|
113
|
123
|
{
|
|
@@ -115,9 +125,11 @@ namespace FTDI {
|
115
|
125
|
cmd.CLCD::CommandFifo::str(line);
|
116
|
126
|
}
|
117
|
127
|
}
|
118
|
|
- y += fm.get_height();
|
|
128
|
+ y += utf8_fm.get_height();
|
119
|
129
|
|
120
|
130
|
line_start = line_end;
|
|
131
|
+ if (line_start[0] == '\n' || line_start[0] == ' ') line_start++;
|
|
132
|
+ if (line_start[0] == '\0') break;
|
121
|
133
|
}
|
122
|
134
|
}
|
123
|
135
|
|