1 /* Public Domain Curses */
2 
3 #include "pdcsdl.h"
4 
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #ifdef CHTYPE_LONG
9 
10 #ifdef PDC_WIDE
11    #define USE_UNICODE_ACS_CHARS 1
12 #else
13    #define USE_UNICODE_ACS_CHARS 0
14 #endif
15 
16 #include "acs_defs.h"
17 
18 #endif
19 
20 Uint32 pdc_lastupdate = 0;
21 
22 #define MAXRECT 200     /* maximum number of rects to queue up before
23                            an update is forced; the number was chosen
24                            arbitrarily */
25 
26 static SDL_Rect uprect[MAXRECT];       /* table of rects to update */
27 static chtype oldch = (chtype)(-1);    /* current attribute */
28 static int rectcount = 0;              /* index into uprect */
29 static short foregr = -2, backgr = -2; /* current foreground, background */
30 
31 /* do the real updates on a delay */
32 
PDC_update_rects(void)33 void PDC_update_rects(void)
34 {
35     if (rectcount)
36     {
37         /* if the maximum number of rects has been reached, we're
38            probably better off doing a full screen update */
39 
40         if (rectcount == MAXRECT)
41             SDL_Flip(pdc_screen);
42         else
43             SDL_UpdateRects(pdc_screen, rectcount, uprect);
44 
45         pdc_lastupdate = SDL_GetTicks();
46         rectcount = 0;
47     }
48 }
49 
50 /* set the font colors to match the chtype's attribute */
51 
_set_attr(chtype ch)52 static void _set_attr(chtype ch)
53 {
54     ch &= (A_COLOR|A_BOLD|A_BLINK|A_REVERSE);
55 
56     if (oldch != ch)
57     {
58         short newfg, newbg;
59 
60         if (SP->mono)
61             return;
62 
63         PDC_pair_content(PAIR_NUMBER(ch), &newfg, &newbg);
64 
65         newfg |= (ch & A_BOLD) ? 8 : 0;
66         newbg |= (ch & A_BLINK) ? 8 : 0;
67 
68         if (ch & A_REVERSE)
69         {
70             short tmp = newfg;
71             newfg = newbg;
72             newbg = tmp;
73         }
74 
75         if (newfg != foregr)
76         {
77 #ifndef PDC_WIDE
78             SDL_SetPalette(pdc_font, SDL_LOGPAL,
79                            pdc_color + newfg, pdc_flastc, 1);
80 #endif
81             foregr = newfg;
82         }
83 
84         if (newbg != backgr)
85         {
86 #ifndef PDC_WIDE
87             if (newbg == -1)
88                 SDL_SetColorKey(pdc_font, SDL_SRCCOLORKEY, 0);
89             else
90             {
91                 if (backgr == -1)
92                     SDL_SetColorKey(pdc_font, 0, 0);
93 
94                 SDL_SetPalette(pdc_font, SDL_LOGPAL,
95                                pdc_color + newbg, 0, 1);
96             }
97 #endif
98             backgr = newbg;
99         }
100 
101         oldch = ch;
102     }
103 }
104 
105 /* draw a cursor at (y, x) */
106 
PDC_gotoyx(int row,int col)107 void PDC_gotoyx(int row, int col)
108 {
109     SDL_Rect src, dest;
110     chtype ch;
111     int oldrow, oldcol;
112 #ifdef PDC_WIDE
113     Uint16 chstr[2] = {0, 0};
114 #endif
115 
116     PDC_LOG(("PDC_gotoyx() - called: row %d col %d from row %d col %d\n",
117              row, col, SP->cursrow, SP->curscol));
118 
119     if (SP->mono)
120         return;
121 
122     oldrow = SP->cursrow;
123     oldcol = SP->curscol;
124 
125     /* clear the old cursor */
126 
127     PDC_transform_line(oldrow, oldcol, 1, curscr->_y[oldrow] + oldcol);
128 
129     if (!SP->visibility)
130         return;
131 
132     /* draw a new cursor by overprinting the existing character in
133        reverse, either the full cell (when visibility == 2) or the
134        lowest quarter of it (when visibility == 1) */
135 
136     ch = curscr->_y[row][col] ^ A_REVERSE;
137 
138     _set_attr(ch);
139 
140 #ifdef CHTYPE_LONG
141     if (ch & A_ALTCHARSET && !(ch & 0xff80))
142         ch = acs_map[ch & 0x7f];
143 #endif
144     src.h = (SP->visibility == 1) ? pdc_fheight >> 2 : pdc_fheight;
145     src.w = pdc_fwidth;
146 
147     dest.y = (row + 1) * pdc_fheight - src.h + pdc_yoffset;
148     dest.x = col * pdc_fwidth + pdc_xoffset;
149 
150 #ifdef PDC_WIDE
151     chstr[0] = ch & A_CHARTEXT;
152 
153     pdc_font = TTF_RenderUNICODE_Solid(pdc_ttffont, chstr, pdc_color[foregr]);
154     if (pdc_font)
155     {
156         dest.h = src.h;
157         dest.w = src.w;
158         src.x = 0;
159         src.y = 0;
160         SDL_SetColorKey(pdc_font, 0, 0);
161         SDL_SetPalette(pdc_font, SDL_LOGPAL, pdc_color + backgr, 0, 1);
162         SDL_BlitSurface(pdc_font, &src, pdc_screen, &dest);
163         SDL_FreeSurface(pdc_font);
164         pdc_font = NULL;
165     }
166 #else
167 
168     src.x = (ch & 0xff) % 32 * pdc_fwidth;
169     src.y = (ch & 0xff) / 32 * pdc_fheight + (pdc_fheight - src.h);
170 
171     SDL_BlitSurface(pdc_font, &src, pdc_screen, &dest);
172 #endif
173 
174     if (oldrow != row || oldcol != col)
175     {
176         if (rectcount == MAXRECT)
177             PDC_update_rects();
178 
179         uprect[rectcount++] = dest;
180     }
181 }
182 
183 /* handle the A_*LINE attributes */
184 
_highlight(SDL_Rect * src,SDL_Rect * dest,chtype ch)185 static void _highlight(SDL_Rect *src, SDL_Rect *dest, chtype ch)
186 {
187     short col = SP->line_color;
188 #ifdef PDC_WIDE
189     Uint16 chstr[2] = {'_', 0};
190 #endif
191 
192     if (SP->mono)
193         return;
194 
195     if (ch & (A_UNDERLINE | A_OVERLINE | A_STRIKEOUT))
196     {
197 #ifdef PDC_WIDE
198         if (col == -1)
199             col = foregr;
200 
201         pdc_font = TTF_RenderUNICODE_Solid(pdc_ttffont, chstr, pdc_color[col]);
202         if (pdc_font)
203         {
204            src->x = 0;
205            src->y = 0;
206 
207            if (backgr != -1)
208                SDL_SetColorKey(pdc_font, SDL_SRCCOLORKEY, 0);
209 
210            if( ch & A_UNDERLINE)
211                 SDL_BlitSurface(pdc_font, src, pdc_screen, dest);
212            if( ch & A_OVERLINE)
213            {
214                 dest->y -= pdc_fheight - 1;
215                 SDL_BlitSurface(pdc_font, src, pdc_screen, dest);
216                 dest->y += pdc_fheight - 1;
217            }
218            if( ch & A_STRIKEOUT)
219            {
220                 dest->y -= pdc_fheight / 2;
221                 SDL_BlitSurface(pdc_font, src, pdc_screen, dest);
222                 dest->y += pdc_fheight / 2;
223            }
224            SDL_FreeSurface(pdc_font);
225            pdc_font = NULL;
226         }
227 #else
228         if (col != -1)
229             SDL_SetPalette(pdc_font, SDL_LOGPAL,
230                            pdc_color + col, pdc_flastc, 1);
231 
232         src->x = '_' % 32 * pdc_fwidth;
233         src->y = '_' / 32 * pdc_fheight;
234 
235         if (backgr != -1)
236             SDL_SetColorKey(pdc_font, SDL_SRCCOLORKEY, 0);
237 
238         if( ch & A_UNDERLINE)
239             SDL_BlitSurface(pdc_font, src, pdc_screen, dest);
240         if( ch & A_OVERLINE)
241         {
242            dest->y -= pdc_fheight - 1;
243            SDL_BlitSurface(pdc_font, src, pdc_screen, dest);
244            dest->y += pdc_fheight - 1;
245         }
246         if( ch & A_STRIKEOUT)
247         {
248            dest->y -= pdc_fheight / 2;
249            SDL_BlitSurface(pdc_font, src, pdc_screen, dest);
250            dest->y += pdc_fheight / 2;
251         }
252 
253         if (backgr != -1)
254             SDL_SetColorKey(pdc_font, 0, 0);
255 
256         if (col != -1)
257             SDL_SetPalette(pdc_font, SDL_LOGPAL,
258                            pdc_color + foregr, pdc_flastc, 1);
259 #endif
260     }
261 
262     if (ch & (A_LEFTLINE|A_RIGHTLINE))
263     {
264         if (col == -1)
265             col = foregr;
266 
267         dest->w = 1;
268 
269         if (ch & A_LEFTLINE)
270             SDL_FillRect(pdc_screen, dest, pdc_mapped[col]);
271 
272         if (ch & A_RIGHTLINE)
273         {
274             dest->x += pdc_fwidth - 1;
275             SDL_FillRect(pdc_screen, dest, pdc_mapped[col]);
276             dest->x -= pdc_fwidth - 1;
277         }
278 
279         dest->w = pdc_fwidth;
280     }
281 }
282 
283 /* update the given physical line to look like the corresponding line in
284    curscr */
285 
PDC_transform_line(int lineno,int x,int len,const chtype * srcp)286 void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
287 {
288     SDL_Rect src, dest, lastrect;
289     int j;
290 #ifdef PDC_WIDE
291     Uint16 chstr[2] = {0, 0};
292 #endif
293 
294     PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno));
295 
296     if (rectcount == MAXRECT)
297         PDC_update_rects();
298 
299     src.h = pdc_fheight;
300     src.w = pdc_fwidth;
301 
302     dest.y = pdc_fheight * lineno + pdc_yoffset;
303     dest.x = pdc_fwidth * x + pdc_xoffset;
304     dest.h = pdc_fheight;
305     dest.w = pdc_fwidth * len;
306 
307     /* if the previous rect was just above this one, with the same width
308        and horizontal position, then merge the new one with it instead
309        of adding a new entry */
310 
311     if (rectcount)
312         lastrect = uprect[rectcount - 1];
313 
314     if (rectcount && lastrect.x == dest.x && lastrect.w == dest.w)
315     {
316         if (lastrect.y + lastrect.h == dest.y)
317             uprect[rectcount - 1].h = lastrect.h + pdc_fheight;
318         else
319             if (lastrect.y != dest.y)
320                 uprect[rectcount++] = dest;
321     }
322     else
323         uprect[rectcount++] = dest;
324 
325     dest.w = pdc_fwidth;
326 
327 #ifdef PDC_WIDE
328     src.x = 0;
329     src.y = 0;
330 #endif
331 
332     for (j = 0; j < len; j++)
333     {
334         chtype ch = srcp[j];
335 
336         _set_attr(ch);
337 #ifdef CHTYPE_LONG
338         if (ch & A_ALTCHARSET && !(ch & 0xff80))
339             ch = (ch & (A_ATTRIBUTES ^ A_ALTCHARSET)) | acs_map[ch & 0x7f];
340 #endif
341         if (backgr == -1)
342             SDL_LowerBlit(pdc_tileback, &dest, pdc_screen, &dest);
343 
344 #ifdef PDC_WIDE
345         chstr[0] = ch & A_CHARTEXT;
346         pdc_font = TTF_RenderUNICODE_Solid(pdc_ttffont, chstr,
347                                            pdc_color[foregr]);
348 
349         if (pdc_font)
350         {
351             if (backgr != -1)
352             {
353                 SDL_SetColorKey(pdc_font, 0, 0);
354                 SDL_SetPalette(pdc_font, SDL_LOGPAL,
355                                pdc_color + backgr, 0, 1);
356             }
357             SDL_BlitSurface(pdc_font, &src, pdc_screen, &dest);
358             SDL_FreeSurface(pdc_font);
359             pdc_font = NULL;
360         }
361 #else
362         src.x = (ch & 0xff) % 32 * pdc_fwidth;
363         src.y = (ch & 0xff) / 32 * pdc_fheight;
364 
365         SDL_LowerBlit(pdc_font, &src, pdc_screen, &dest);
366 #endif
367 
368         if (ch & (A_UNDERLINE|A_LEFTLINE|A_RIGHTLINE|A_OVERLINE|A_STRIKEOUT))
369             _highlight(&src, &dest, ch);
370 
371         dest.x += pdc_fwidth;
372     }
373 }
374