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