1 /*
2 * HT Editor
3 * display.cc
4 *
5 * Copyright (C) 1999-2004 Stefan Weyergraf (stefan@weyergraf.de)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <new>
22 #include <cstdarg>
23 #include <cstdlib>
24
25 #include "display.h"
26 #include "snprintf.h"
27
28 #if 0
29 static vc gInverseColors[8] = {
30 VC_WHITE, VC_YELLOW, VC_MAGENTA, VC_RED,
31 VC_CYAN, VC_GREEN, VC_BLUE, VC_BLACK
32 };
33 #define VC_GET_INVERSE(vc) gInverseColor[(vc)&7]
34 #else
35 #define VC_GET_INVERSE(vc) (7-((vc)&7))
36 #endif
37
mixSingleColor(vc base,vc layer)38 inline vc mixSingleColor(vc base, vc layer)
39 {
40 if (VC_GET_BASECOLOR(base) > 7) return layer;
41
42 switch (VC_GET_BASECOLOR(layer)) {
43 case VC_TRANSPARENT_EXCLUSIVE_DOM:
44 case VC_TRANSPARENT_EXCLUSIVE:
45 case VC_TRANSPARENT: return base;
46
47 case VC_DARKEN: return VC_GET_BASECOLOR(base);
48 case VC_LIGHTEN: return VC_LIGHT(base);
49
50 case VC_MONOCHROME: {
51 switch (base) {
52 case VC_CYAN:
53 case VC_MAGENTA:
54 case VC_YELLOW:
55 case VC_WHITE:
56 return VC_WHITE;
57 case VC_RED:
58 case VC_BLACK:
59 case VC_BLUE:
60 case VC_GREEN:
61 default:
62 return VC_BLACK;
63 }
64 }
65 case VC_INVERSE: return VC_GET_INVERSE(VC_GET_BASECOLOR(base));
66 }
67
68 return layer;
69 }
70
mixColors(vcp base,vcp layer)71 vcp mixColors(vcp base, vcp layer)
72 {
73 vc fg = mixSingleColor(VCP_FOREGROUND(base), VCP_FOREGROUND(layer));
74 vc bg = mixSingleColor(VCP_BACKGROUND(base), VCP_BACKGROUND(layer));
75
76 if (fg == bg) {
77 if (VC_GET_BASECOLOR(VCP_FOREGROUND(layer)) == VC_TRANSPARENT_EXCLUSIVE
78 || VC_GET_BASECOLOR(VCP_BACKGROUND(layer)) == VC_TRANSPARENT_EXCLUSIVE_DOM) {
79 int fglight = VC_GET_LIGHT(fg);
80 fg = VC_GET_INVERSE(VC_GET_BASECOLOR(bg)) | fglight;
81 fg = VC_BLACK;
82 } else if (VC_GET_BASECOLOR(VCP_BACKGROUND(layer)) == VC_TRANSPARENT_EXCLUSIVE
83 || VC_GET_BASECOLOR(VCP_FOREGROUND(layer)) == VC_TRANSPARENT_EXCLUSIVE_DOM) {
84 int bglight = VC_GET_LIGHT(bg);
85 bg = VC_GET_INVERSE(VC_GET_BASECOLOR(fg)) | bglight;
86 }
87 }
88 return VCP(fg, bg);
89 }
90
91 /*
92 * Display
93 */
assign(int x,int y,int w,int h)94 void Display::assign(int x, int y, int w, int h)
95 {
96 Bounds b(x, y, w, h);
97 setBounds(b);
98 }
99
fillAll(vcp color,char chr,Codepage cp)100 void Display::fillAll(vcp color, char chr, Codepage cp)
101 {
102 fill(0, 0, w, h, color, chr, cp);
103 }
104
move(int deltax,int deltay)105 void Display::move(int deltax, int deltay)
106 {
107 Bounds b(*this);
108 b.move(deltax, deltay);
109 setBounds(b);
110 }
111
resize(int deltaw,int deltah)112 void Display::resize(int deltaw, int deltah)
113 {
114 Bounds b(*this);
115 b.resize(deltaw, deltah);
116 setBounds(b);
117 }
118
nprintf(int x,int y,vcp color,int maxstrlen,Codepage cp,const char * format,...)119 int Display::nprintf(int x, int y, vcp color, int maxstrlen, Codepage cp, const char *format, ...)
120 {
121 char buf[512];
122 va_list ap;
123 va_start(ap, format);
124 ht_vsnprintf(buf, MIN((int)sizeof buf, maxstrlen), format, ap);
125 va_end(ap);
126 return print(x, y, color, buf, cp);
127 }
128
print(int x,int y,vc color,const char * str,Codepage cp)129 int Display::print(int x, int y, vc color, const char *str, Codepage cp)
130 {
131 return nprint(x, y, color, str, 0x7fffffff, cp);
132 }
133
printW(int x,int y,vcp color,const AbstractChar * widestr)134 int Display::printW(int x, int y, vcp color, const AbstractChar *widestr)
135 {
136 const AbstractChar *owidestr = widestr;
137 // FIXME: speed ?
138 while (widestr->codepage != CP_INVALID) {
139 if (!printChar(x++, y, color, widestr->chr, widestr->codepage)) break;
140 widestr++;
141 }
142 return widestr-owidestr;
143 }
144
nprintW(int x,int y,vcp color,const AbstractChar * widestr,int maxstrlen)145 int Display::nprintW(int x, int y, vcp color, const AbstractChar *widestr, int maxstrlen)
146 {
147 const AbstractChar *owidestr = widestr;
148 // FIXME: speed ?
149 while (widestr->codepage != CP_INVALID && maxstrlen--) {
150 if (!printChar(x++, y, color, widestr->chr, widestr->codepage)) break;
151 widestr++;
152 }
153 return widestr-owidestr;
154 }
155
printChar(int x,int y,vcp color,char chr,Codepage cp)156 int Display::printChar(int x, int y, vcp color, char chr, Codepage cp)
157 {
158 // FIXME: speed ?
159 fill(x, y, 1, 1, color, chr, cp);
160 return 1;
161 }
162
printf(int x,int y,vcp color,Codepage cp,const char * format,...)163 int Display::printf(int x, int y, vcp color, Codepage cp, const char *format, ...)
164 {
165 char buf[512];
166 va_list ap;
167 va_start(ap, format);
168 ht_vsnprintf(buf, sizeof buf, format, ap);
169 va_end(ap);
170 return print(x, y, color, buf, cp);
171 }
172
setBounds(const Bounds & b)173 void Display::setBounds(const Bounds &b)
174 {
175 Bounds::assign(b.x, b.y, b.w, b.h);
176 }
177
178 /* graphical extension */
179 #if 0
180 void Display::line(int px1, int py1, int px2, int py2, uint color)
181 {
182 }
183
184 void Display::putPixel(int px, int py, uint color)
185 {
186 }
187
188 void Display::textToPixelCoord(int tx, int ty, int &px, int &py) const
189 {
190 px = tx;
191 py = ty;
192 }
193
194 void Display::pixelToTextCoord(int px, int py, int &tx, int &ty) const
195 {
196 tx = px;
197 ty = py;
198 }
199 #endif
200
201 /*
202 * NullDisplay
203 */
NullRDisplay(const Bounds & b)204 NullRDisplay::NullRDisplay(const Bounds &b)
205 : RDisplay(b)
206 {
207 setCursor(0, 0, CURSOR_OFF);
208 }
209
fill(int x,int y,int w,int h,vcp color,char chr,Codepage cp)210 void NullRDisplay::fill(int x, int y, int w, int h, vcp color, char chr, Codepage cp)
211 {
212 }
213
getCursor(int & x,int & y) const214 void NullRDisplay::getCursor(int &x, int &y) const
215 {
216 x = cursorx;
217 y = cursory;
218 }
219
getCursorMode() const220 CursorMode NullRDisplay::getCursorMode() const
221 {
222 return cursorMode;
223 }
224
nprint(int ix,int iy,vcp color,const char * str,int maxstrlen,Codepage cp)225 int NullRDisplay::nprint(int ix, int iy, vcp color, const char *str, int maxstrlen, Codepage cp)
226 {
227 int i = 0;
228 // FIXME: more efficient impl
229 if (y < h) {
230 while ((ix+i < w) && (*str) && (i<maxstrlen)) {
231 i++;
232 }
233 }
234 return i;
235 }
236
read(uint & rawchar,vcp & color,int x,int y) const237 bool NullRDisplay::read(uint &rawchar, vcp &color, int x, int y) const
238 {
239 if ((x >= w) || (y >= h)) return false;
240 return true;
241 }
242
setCursor(int x,int y,CursorMode mode)243 void NullRDisplay::setCursor(int x, int y, CursorMode mode)
244 {
245 cursorx = x;
246 cursory = y;
247 setCursorMode(mode);
248 }
249
setCursorMode(CursorMode mode)250 void NullRDisplay::setCursorMode(CursorMode mode)
251 {
252 cursorMode = mode;
253 }
254
255 /*
256 * BufferedRDisplay
257 */
BufferedRDisplay(const Bounds & b)258 BufferedRDisplay::BufferedRDisplay(const Bounds &b)
259 : RDisplay(b)
260 {
261 buf = NULL;
262 setBounds(b);
263 setCursor(0, 0, CURSOR_OFF);
264 }
265
~BufferedRDisplay()266 BufferedRDisplay::~BufferedRDisplay()
267 {
268 free(buf);
269 }
270
fill(int x,int y,int w,int h,vcp color,char chr,Codepage cp)271 void BufferedRDisplay::fill(int x, int y, int w, int h, vcp color, char chr, Codepage cp)
272 {
273 uint rawchar = mapCharToSystemCP(chr, cp);
274 bool transparent = (cp == CP_GRAPHICAL && chr == GC_TRANSPARENT);
275 if (y < 0) {
276 h += y;
277 y = 0;
278 }
279 if (x < 0) {
280 w += x;
281 x = 0;
282 }
283 if (x+w > this->w) {
284 w = this->w - x;
285 }
286 if (y+h > this->h) {
287 h = this->h - y;
288 }
289 for (int iy = y; iy < y+h; iy++) {
290 ColoredChar *b = buf+x+ iy * this->w;
291 for (int ix = x; ix < x+w; ix++) {
292 if (!transparent) b->rawchar = rawchar;
293 b->color = mixColors(b->color, color);
294 b++;
295 }
296 }
297 }
298
getCursor(int & x,int & y) const299 void BufferedRDisplay::getCursor(int &x, int &y) const
300 {
301 x = cursorx;
302 y = cursory;
303 }
304
getCursorMode() const305 CursorMode BufferedRDisplay::getCursorMode() const
306 {
307 return cursorMode;
308 }
309
nprint(int ix,int iy,vcp color,const char * str,int maxstrlen,Codepage cp)310 int BufferedRDisplay::nprint(int ix, int iy, vcp color, const char *str, int maxstrlen, Codepage cp)
311 {
312 int i = 0;
313 ColoredChar *b = buf+ix+ iy * w;
314 if (iy < h) {
315 while (ix+i < w && str[i] && i < maxstrlen) {
316 bool transparent = (cp == CP_GRAPHICAL && str[i] == GC_TRANSPARENT);
317 if (!transparent) b->rawchar = mapCharToSystemCP(str[i], cp);
318 b->color = mixColors(b->color, color);
319 i++;
320 b++;
321 }
322 }
323 return i;
324 }
325
read(uint & rawchar,vcp & color,int x,int y) const326 bool BufferedRDisplay::read(uint &rawchar, vcp &color, int x, int y) const
327 {
328 if (!buf) return false;
329 if ((x >= w) || (y >= h)) return false;
330 ColoredChar *b = buf + x + y*w;
331 rawchar = b->rawchar;
332 color = b->color;
333 return true;
334 }
335
setBounds(const Bounds & b)336 void BufferedRDisplay::setBounds(const Bounds &b)
337 {
338 Bounds oldb = *(Bounds*)this;
339 RDisplay::setBounds(b);
340 ColoredChar *bufnew;
341 if (w * h) {
342 bufnew = ht_malloc(sizeof *buf * w * h);
343 if (!bufnew) throw std::bad_alloc();
344 ColoredChar *bb = bufnew;
345 for (int iy = 0; iy < h; iy++) {
346 for (int ix = 0; ix < w; ix++) {
347 if ((ix < oldb.w) && (iy < oldb.h) && buf) {
348 *bb = buf[ix+iy*oldb.w];
349 } else {
350 bb->rawchar = ' ';
351 bb->color = VCP(VC_TRANSPARENT, VC_TRANSPARENT);
352 }
353 bb++;
354 }
355 }
356 } else bufnew = NULL;
357 free(buf);
358 buf = bufnew;
359 }
360
setCursor(int x,int y,CursorMode mode)361 void BufferedRDisplay::setCursor(int x, int y, CursorMode mode)
362 {
363 cursorx = x;
364 cursory = y;
365 setCursorMode(mode);
366 }
367
setCursorMode(CursorMode mode)368 void BufferedRDisplay::setCursorMode(CursorMode mode)
369 {
370 cursorMode = mode;
371 }
372
373 /*
374 * SystemDisplay
375 */
SystemDisplay()376 SystemDisplay::SystemDisplay()
377 {
378 }
379
380 /*
381 * SystemRDisplay
382 */
SystemRDisplay(SystemDisplay * System_display,const Bounds & b)383 SystemRDisplay::SystemRDisplay(SystemDisplay *System_display, const Bounds &b)
384 : RDisplay(b)
385 {
386 system_display = System_display;
387 }
388
~SystemRDisplay()389 SystemRDisplay::~SystemRDisplay()
390 {
391 }
392
fill(int x,int y,int w,int h,vcp color,char chr,Codepage cp)393 void SystemRDisplay::fill(int x, int y, int w, int h, vcp color, char chr, Codepage cp)
394 {
395 x += this->x;
396 y += this->y;
397 system_display->fill(x, y, w, h, color, chr, cp);
398 }
399
getCursor(int & x,int & y) const400 void SystemRDisplay::getCursor(int &x, int &y) const
401 {
402 system_display->getCursor(x, y);
403 x -= this->x;
404 y -= this->y;
405 }
406
getCursorMode() const407 CursorMode SystemRDisplay::getCursorMode() const
408 {
409 return system_display->getCursorMode();
410 }
411
nprint(int x,int y,vcp color,const char * str,int maxstrlen,Codepage cp)412 int SystemRDisplay::nprint(int x, int y, vcp color, const char *str, int maxstrlen, Codepage cp)
413 {
414 x += this->x;
415 y += this->y;
416 return system_display->nprint(x, y, color, str, maxstrlen, cp);
417 }
418
read(uint & rawchar,vcp & color,int x,int y) const419 bool SystemRDisplay::read(uint &rawchar, vcp &color, int x, int y) const
420 {
421 x += this->x;
422 y += this->y;
423 return system_display->read(rawchar, color, x, y);
424 }
425
setBounds(const Bounds & b)426 void SystemRDisplay::setBounds(const Bounds &b)
427 {
428 RDisplay::setBounds(b);
429 }
430
setCursor(int x,int y,CursorMode mode)431 void SystemRDisplay::setCursor(int x, int y, CursorMode mode)
432 {
433 x += this->x;
434 y += this->y;
435 system_display->setCursor(x, y, mode);
436 }
437
setCursorMode(CursorMode mode)438 void SystemRDisplay::setCursorMode(CursorMode mode)
439 {
440 system_display->setCursorMode(mode);
441 }
442