Patrick Georgi | 3b77b72 | 2011-07-07 15:41:53 +0200 | [diff] [blame] | 1 | /* Public Domain Curses */ |
| 2 | |
| 3 | #include "pdcsdl.h" |
| 4 | |
| 5 | RCSID("$Id: pdcdisp.c,v 1.35 2008/07/14 04:24:52 wmcbrine Exp $") |
| 6 | |
| 7 | #include <stdlib.h> |
| 8 | #include <string.h> |
| 9 | |
| 10 | #ifdef CHTYPE_LONG |
| 11 | |
| 12 | # define A(x) ((chtype)x | A_ALTCHARSET) |
| 13 | |
| 14 | chtype acs_map[128] = |
| 15 | { |
| 16 | A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), |
| 17 | A(10), A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18), |
| 18 | A(19), A(20), A(21), A(22), A(23), A(24), A(25), A(26), A(27), |
| 19 | A(28), A(29), A(30), A(31), ' ', '!', '"', '#', '$', '%', '&', |
| 20 | '\'', '(', ')', '*', |
| 21 | |
| 22 | A(0x1a), A(0x1b), A(0x18), A(0x19), |
| 23 | |
| 24 | '/', |
| 25 | |
| 26 | 0xdb, |
| 27 | |
| 28 | '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', |
| 29 | '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', |
| 30 | 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', |
| 31 | 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', |
| 32 | |
| 33 | A(0x04), 0xb1, |
| 34 | |
| 35 | 'b', 'c', 'd', 'e', |
| 36 | |
| 37 | 0xf8, 0xf1, 0xb0, A(0x0f), 0xd9, 0xbf, 0xda, 0xc0, 0xc5, 0x2d, |
| 38 | 0x2d, 0xc4, 0x2d, 0x5f, 0xc3, 0xb4, 0xc1, 0xc2, 0xb3, 0xf3, |
| 39 | 0xf2, 0xe3, 0xd8, 0x9c, 0xf9, |
| 40 | |
| 41 | A(127) |
| 42 | }; |
| 43 | |
| 44 | # undef A |
| 45 | |
| 46 | #endif |
| 47 | |
| 48 | Uint32 pdc_lastupdate = 0; |
| 49 | |
| 50 | #define MAXRECT 200 /* maximum number of rects to queue up before |
| 51 | an update is forced; the number was chosen |
| 52 | arbitrarily */ |
| 53 | |
| 54 | static SDL_Rect uprect[MAXRECT]; /* table of rects to update */ |
| 55 | static chtype oldch = (chtype)(-1); /* current attribute */ |
| 56 | static int rectcount = 0; /* index into uprect */ |
| 57 | static short foregr = -2, backgr = -2; /* current foreground, background */ |
| 58 | |
| 59 | /* do the real updates on a delay */ |
| 60 | |
| 61 | void PDC_update_rects(void) |
| 62 | { |
| 63 | if (rectcount) |
| 64 | { |
Stefan Reinauer | e11835e | 2011-10-31 12:54:00 -0700 | [diff] [blame] | 65 | /* if the maximum number of rects has been reached, we're |
Patrick Georgi | 3b77b72 | 2011-07-07 15:41:53 +0200 | [diff] [blame] | 66 | probably better off doing a full screen update */ |
| 67 | |
| 68 | if (rectcount == MAXRECT) |
| 69 | SDL_Flip(pdc_screen); |
| 70 | else |
| 71 | SDL_UpdateRects(pdc_screen, rectcount, uprect); |
| 72 | |
| 73 | pdc_lastupdate = SDL_GetTicks(); |
| 74 | rectcount = 0; |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | /* set the font colors to match the chtype's attribute */ |
| 79 | |
| 80 | static void _set_attr(chtype ch) |
| 81 | { |
| 82 | ch &= (A_COLOR|A_BOLD|A_BLINK|A_REVERSE); |
| 83 | |
| 84 | if (oldch != ch) |
| 85 | { |
| 86 | short newfg, newbg; |
| 87 | |
| 88 | if (SP->mono) |
| 89 | return; |
| 90 | |
| 91 | PDC_pair_content(PAIR_NUMBER(ch), &newfg, &newbg); |
| 92 | |
| 93 | newfg |= (ch & A_BOLD) ? 8 : 0; |
| 94 | newbg |= (ch & A_BLINK) ? 8 : 0; |
| 95 | |
| 96 | if (ch & A_REVERSE) |
| 97 | { |
| 98 | short tmp = newfg; |
| 99 | newfg = newbg; |
| 100 | newbg = tmp; |
| 101 | } |
| 102 | |
| 103 | if (newfg != foregr) |
| 104 | { |
Stefan Reinauer | e11835e | 2011-10-31 12:54:00 -0700 | [diff] [blame] | 105 | SDL_SetPalette(pdc_font, SDL_LOGPAL, |
Patrick Georgi | 3b77b72 | 2011-07-07 15:41:53 +0200 | [diff] [blame] | 106 | pdc_color + newfg, pdc_flastc, 1); |
| 107 | foregr = newfg; |
| 108 | } |
| 109 | |
| 110 | if (newbg != backgr) |
| 111 | { |
| 112 | if (newbg == -1) |
| 113 | SDL_SetColorKey(pdc_font, SDL_SRCCOLORKEY, 0); |
| 114 | else |
| 115 | { |
| 116 | if (backgr == -1) |
| 117 | SDL_SetColorKey(pdc_font, 0, 0); |
| 118 | |
| 119 | SDL_SetPalette(pdc_font, SDL_LOGPAL, |
| 120 | pdc_color + newbg, 0, 1); |
| 121 | } |
| 122 | |
| 123 | backgr = newbg; |
| 124 | } |
| 125 | |
| 126 | oldch = ch; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | /* draw a cursor at (y, x) */ |
| 131 | |
| 132 | void PDC_gotoyx(int row, int col) |
| 133 | { |
| 134 | SDL_Rect src, dest; |
| 135 | chtype ch; |
| 136 | int oldrow, oldcol; |
| 137 | |
| 138 | PDC_LOG(("PDC_gotoyx() - called: row %d col %d from row %d col %d\n", |
| 139 | row, col, SP->cursrow, SP->curscol)); |
| 140 | |
| 141 | if (SP->mono) |
| 142 | return; |
| 143 | |
| 144 | oldrow = SP->cursrow; |
| 145 | oldcol = SP->curscol; |
| 146 | |
| 147 | /* clear the old cursor */ |
| 148 | |
| 149 | PDC_transform_line(oldrow, oldcol, 1, curscr->_y[oldrow] + oldcol); |
| 150 | |
| 151 | if (!SP->visibility) |
| 152 | return; |
| 153 | |
Stefan Reinauer | e11835e | 2011-10-31 12:54:00 -0700 | [diff] [blame] | 154 | /* draw a new cursor by overprinting the existing character in |
| 155 | reverse, either the full cell (when visibility == 2) or the |
Patrick Georgi | 3b77b72 | 2011-07-07 15:41:53 +0200 | [diff] [blame] | 156 | lowest quarter of it (when visibility == 1) */ |
| 157 | |
| 158 | ch = curscr->_y[row][col] ^ A_REVERSE; |
| 159 | |
| 160 | _set_attr(ch); |
| 161 | |
| 162 | #ifdef CHTYPE_LONG |
| 163 | if (ch & A_ALTCHARSET && !(ch & 0xff80)) |
| 164 | ch = acs_map[ch & 0x7f]; |
| 165 | #endif |
| 166 | src.h = (SP->visibility == 1) ? pdc_fheight >> 2 : pdc_fheight; |
| 167 | src.w = pdc_fwidth; |
| 168 | |
| 169 | dest.y = (row + 1) * pdc_fheight - src.h + pdc_yoffset; |
| 170 | dest.x = col * pdc_fwidth + pdc_xoffset; |
| 171 | |
| 172 | src.x = (ch & 0xff) % 32 * pdc_fwidth; |
| 173 | src.y = (ch & 0xff) / 32 * pdc_fheight + (pdc_fheight - src.h); |
| 174 | |
| 175 | SDL_BlitSurface(pdc_font, &src, pdc_screen, &dest); |
| 176 | |
| 177 | if (oldrow != row || oldcol != col) |
| 178 | { |
| 179 | if (rectcount == MAXRECT) |
| 180 | PDC_update_rects(); |
| 181 | |
| 182 | uprect[rectcount++] = dest; |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | /* handle the A_*LINE attributes */ |
| 187 | |
| 188 | static void _highlight(SDL_Rect *src, SDL_Rect *dest, chtype ch) |
| 189 | { |
| 190 | short col = SP->line_color; |
| 191 | |
| 192 | if (SP->mono) |
| 193 | return; |
| 194 | |
| 195 | if (ch & A_UNDERLINE) |
| 196 | { |
| 197 | if (col != -1) |
| 198 | SDL_SetPalette(pdc_font, SDL_LOGPAL, |
| 199 | pdc_color + col, pdc_flastc, 1); |
| 200 | |
| 201 | src->x = '_' % 32 * pdc_fwidth; |
| 202 | src->y = '_' / 32 * pdc_fheight; |
| 203 | |
| 204 | if (backgr != -1) |
| 205 | SDL_SetColorKey(pdc_font, SDL_SRCCOLORKEY, 0); |
| 206 | |
| 207 | SDL_BlitSurface(pdc_font, src, pdc_screen, dest); |
| 208 | |
| 209 | if (backgr != -1) |
| 210 | SDL_SetColorKey(pdc_font, 0, 0); |
| 211 | |
| 212 | if (col != -1) |
| 213 | SDL_SetPalette(pdc_font, SDL_LOGPAL, |
| 214 | pdc_color + foregr, pdc_flastc, 1); |
| 215 | } |
| 216 | |
| 217 | if (ch & (A_LEFTLINE|A_RIGHTLINE)) |
| 218 | { |
| 219 | if (col == -1) |
| 220 | col = foregr; |
| 221 | |
| 222 | dest->w = 1; |
| 223 | |
| 224 | if (ch & A_LEFTLINE) |
| 225 | SDL_FillRect(pdc_screen, dest, pdc_mapped[col]); |
| 226 | |
| 227 | if (ch & A_RIGHTLINE) |
| 228 | { |
| 229 | dest->x += pdc_fwidth - 1; |
| 230 | SDL_FillRect(pdc_screen, dest, pdc_mapped[col]); |
| 231 | dest->x -= pdc_fwidth - 1; |
| 232 | } |
| 233 | |
| 234 | dest->w = pdc_fwidth; |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | /* update the given physical line to look like the corresponding line in |
| 239 | curscr */ |
| 240 | |
| 241 | void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) |
| 242 | { |
| 243 | SDL_Rect src, dest, lastrect; |
| 244 | int j; |
| 245 | |
| 246 | PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno)); |
| 247 | |
| 248 | if (rectcount == MAXRECT) |
| 249 | PDC_update_rects(); |
| 250 | |
| 251 | src.h = pdc_fheight; |
| 252 | src.w = pdc_fwidth; |
| 253 | |
| 254 | dest.y = pdc_fheight * lineno + pdc_yoffset; |
| 255 | dest.x = pdc_fwidth * x + pdc_xoffset; |
| 256 | dest.h = pdc_fheight; |
| 257 | dest.w = pdc_fwidth * len; |
| 258 | |
| 259 | /* if the previous rect was just above this one, with the same width |
| 260 | and horizontal position, then merge the new one with it instead |
| 261 | of adding a new entry */ |
| 262 | |
| 263 | if (rectcount) |
| 264 | lastrect = uprect[rectcount - 1]; |
| 265 | |
| 266 | if (rectcount && lastrect.x == dest.x && lastrect.w == dest.w) |
| 267 | { |
| 268 | if (lastrect.y + lastrect.h == dest.y) |
| 269 | uprect[rectcount - 1].h = lastrect.h + pdc_fheight; |
| 270 | else |
| 271 | if (lastrect.y != dest.y) |
| 272 | uprect[rectcount++] = dest; |
Stefan Reinauer | e11835e | 2011-10-31 12:54:00 -0700 | [diff] [blame] | 273 | } |
Patrick Georgi | 3b77b72 | 2011-07-07 15:41:53 +0200 | [diff] [blame] | 274 | else |
| 275 | uprect[rectcount++] = dest; |
| 276 | |
| 277 | dest.w = pdc_fwidth; |
| 278 | |
| 279 | for (j = 0; j < len; j++) |
| 280 | { |
| 281 | chtype ch = srcp[j]; |
| 282 | |
| 283 | _set_attr(ch); |
| 284 | #ifdef CHTYPE_LONG |
| 285 | if (ch & A_ALTCHARSET && !(ch & 0xff80)) |
| 286 | ch = (ch & (A_ATTRIBUTES ^ A_ALTCHARSET)) | acs_map[ch & 0x7f]; |
| 287 | #endif |
| 288 | if (backgr == -1) |
| 289 | SDL_LowerBlit(pdc_tileback, &dest, pdc_screen, &dest); |
| 290 | |
| 291 | src.x = (ch & 0xff) % 32 * pdc_fwidth; |
| 292 | src.y = (ch & 0xff) / 32 * pdc_fheight; |
| 293 | |
| 294 | SDL_LowerBlit(pdc_font, &src, pdc_screen, &dest); |
| 295 | |
| 296 | if (ch & (A_UNDERLINE|A_LEFTLINE|A_RIGHTLINE)) |
| 297 | _highlight(&src, &dest, ch); |
| 298 | |
| 299 | dest.x += pdc_fwidth; |
| 300 | } |
| 301 | } |