1 #include "AppHdr.h"
2
3 #ifdef USE_TILE_LOCAL
4
5 #include "tilereg-text.h"
6
7 #include "tilefont.h"
8 #include "unicode.h"
9
10 int TextRegion::print_x;
11 int TextRegion::print_y;
12 TextRegion *TextRegion::text_mode = nullptr;
13 int TextRegion::text_col = 0;
14
15 TextRegion *TextRegion::cursor_region= nullptr;
16 int TextRegion::cursor_flag = 0;
17 int TextRegion::cursor_x;
18 int TextRegion::cursor_y;
19
TextRegion(FontWrapper * font_arg)20 TextRegion::TextRegion(FontWrapper *font_arg) :
21 cbuf(nullptr),
22 abuf(nullptr),
23 cx_ofs(0),
24 cy_ofs(0),
25 m_font(font_arg)
26 {
27 ASSERT(font_arg);
28
29 // warning: dx and dy are not guaranteed to be accurate for TextRegion
30 // because on high-dpi displays, glyphs may have fractional widths relative
31 // to logical pixels. Use `grid_width_to_pixels` etc instead, or use the
32 // functions on font().
33 dx = m_font->char_width();
34 dy = m_font->char_height();
35 }
36
font() const37 FontWrapper &TextRegion::font() const
38 {
39 ASSERT(m_font);
40 return *m_font;
41 }
42
on_resize()43 void TextRegion::on_resize()
44 {
45 delete[] cbuf;
46 delete[] abuf;
47
48 int size = mx * my;
49 cbuf = new char32_t[size];
50 abuf = new uint8_t[size];
51
52 for (int i = 0; i < size; i++)
53 {
54 cbuf[i] = ' ';
55 abuf[i] = 0;
56 }
57 }
58
~TextRegion()59 TextRegion::~TextRegion()
60 {
61 delete[] cbuf;
62 delete[] abuf;
63 }
64
addstr(const char * buffer)65 void TextRegion::addstr(const char *buffer)
66 {
67 char32_t buf2[1024], c;
68
69 int j = 0;
70
71 int clen;
72 do
73 {
74 buffer += clen = utf8towc(&c, buffer);
75 bool newline = false;
76
77 if (c == '\r')
78 continue;
79
80 if (c == '\n')
81 {
82 c = 0;
83 newline = true;
84 }
85 // TODO: use wcwidth() to handle widths!=1:
86 // * 2 for CJK chars -- add a zero-width blank?
87 // * 0 for combining characters -- would need extra support
88 // * -1 for non-printable stuff -- assert or ignore
89 buf2[j] = c;
90 j++;
91
92 if (c == 0 || j == ARRAYSZ(buf2))
93 {
94 if (j-1 != 0)
95 addstr_aux(buf2, j - 1); // draw it
96 if (newline)
97 {
98 print_x = cx_ofs;
99 print_y++;
100 j = 0;
101
102 if (print_y - cy_ofs == my)
103 scroll();
104 }
105 }
106 } while (clen);
107 if (cursor_flag)
108 cgotoxy(print_x+1, print_y+1);
109 }
110
addstr_aux(const char32_t * buffer,int len)111 void TextRegion::addstr_aux(const char32_t *buffer, int len)
112 {
113 int x = print_x - cx_ofs;
114 int y = print_y - cy_ofs;
115 int adrs = y * mx;
116
117 ASSERT(y < my);
118
119 for (int i = 0; i < len && x + i < mx; i++)
120 {
121 cbuf[adrs+x+i] = buffer[i];
122 abuf[adrs+x+i] = text_col;
123 }
124 print_x += len;
125 }
126
clear_to_end_of_line()127 void TextRegion::clear_to_end_of_line()
128 {
129 int cx = print_x - cx_ofs;
130 int cy = print_y - cy_ofs;
131 int col = text_col;
132 int adrs = cy * mx;
133
134 ASSERT(adrs + mx - 1 < mx * my);
135 for (int i = cx; i < mx; i++)
136 {
137 cbuf[adrs+i] = ' ';
138 abuf[adrs+i] = col;
139 }
140 }
141
putwch(char32_t ch)142 void TextRegion::putwch(char32_t ch)
143 {
144 // special case: check for '0' char: map to space
145 if (ch == 0)
146 ch = ' ';
147 addstr_aux(&ch, 1);
148 }
149
textcolour(int colour)150 void TextRegion::textcolour(int colour)
151 {
152 text_col = colour;
153 }
154
textbackground(int col)155 void TextRegion::textbackground(int col)
156 {
157 textcolour(col*16 + (text_col & 0xf));
158 }
159
cgotoxy(int x,int y)160 void TextRegion::cgotoxy(int x, int y)
161 {
162 ASSERT(x >= 1);
163 ASSERT(y >= 1);
164 print_x = x-1;
165 print_y = y-1;
166
167 if (cursor_flag)
168 {
169 cursor_x = print_x;
170 cursor_y = print_y;
171 cursor_region = text_mode;
172 }
173 }
174
wherex()175 int TextRegion::wherex()
176 {
177 return print_x + 1;
178 }
179
wherey()180 int TextRegion::wherey()
181 {
182 return print_y + 1;
183 }
184
grid_width_to_pixels(int x) const185 int TextRegion::grid_width_to_pixels(int x) const
186 {
187 return font().max_width(x);
188 }
189
grid_height_to_pixels(int y) const190 int TextRegion::grid_height_to_pixels(int y) const
191 {
192 return font().max_height(y);
193 }
194
calculate_grid_size(int inner_x,int inner_y)195 void TextRegion::calculate_grid_size(int inner_x, int inner_y)
196 {
197 // This can't be calculated perfectly using just dx, because on hidpi
198 // displays, font rendering may involve sub-logical-pixel advances.
199 mx = glmanager->logical_to_device(inner_x) / font().char_width(false);
200 my = glmanager->logical_to_device(inner_y) / font().char_height(false);
201 }
202
_setcursortype(int curstype)203 void TextRegion::_setcursortype(int curstype)
204 {
205 cursor_flag = curstype;
206 if (cursor_region != nullptr)
207 {
208 cursor_x = -1;
209 cursor_y = -1;
210 }
211
212 if (curstype)
213 {
214 cursor_x = print_x;
215 cursor_y = print_y;
216 cursor_region = text_mode;
217 }
218 }
219
render()220 void TextRegion::render()
221 {
222 #ifdef DEBUG_TILES_REDRAW
223 cprintf("rendering TextRegion\n");
224 #endif
225 if (this == TextRegion::cursor_region && cursor_x > 0 && cursor_y > 0)
226 {
227 int idx = cursor_x + mx * cursor_y;
228
229 char32_t char_back = cbuf[idx];
230 uint8_t col_back = abuf[idx];
231
232 cbuf[idx] = '_';
233 abuf[idx] = WHITE;
234
235 m_font->render_textblock(sx + ox, sy + oy, cbuf, abuf, mx, my);
236
237 cbuf[idx] = char_back;
238 abuf[idx] = col_back;
239 }
240 else
241 m_font->render_textblock(sx + ox, sy + oy, cbuf, abuf, mx, my);
242 }
243
clear()244 void TextRegion::clear()
245 {
246 for (int i = 0; i < mx * my; i++)
247 {
248 cbuf[i] = ' ';
249 abuf[i] = 0;
250 }
251 }
252
scroll()253 void TextRegion::scroll()
254 {
255 for (int idx = 0; idx < mx*(my-1); idx++)
256 {
257 cbuf[idx] = cbuf[idx + mx];
258 abuf[idx] = abuf[idx + mx];
259 }
260
261 for (int idx = mx*(my-1); idx < mx*my; idx++)
262 {
263 cbuf[idx] = ' ';
264 abuf[idx] = 0;
265 }
266
267 if (print_y > 0)
268 print_y -= 1;
269 if (cursor_y > 0)
270 cursor_y -= 1;
271 }
272
273 #endif
274