adamdunkels | b9614dc | 2004-08-09 20:33:51 +0000 | [diff] [blame] | 1 | #include "libconio.h" |
| 2 | #include "ctk-term-int.h" |
| 3 | #include <string.h> |
| 4 | #include <stdio.h> // sprintf |
| 5 | |
| 6 | #define PRINTF(x) |
| 7 | |
| 8 | /*-----------------------------------------------------------------------------------*/ |
| 9 | /* |
| 10 | * #defines and enums |
| 11 | */ |
| 12 | /*-----------------------------------------------------------------------------------*/ |
| 13 | |
| 14 | #define CHARS_WIDTH LIBCONIO_CONF_SCREEN_WIDTH |
| 15 | #define CHARS_HEIGHT LIBCONIO_CONF_SCREEN_HEIGHT |
| 16 | |
| 17 | /*-----------------------------------------------------------------------------------*/ |
| 18 | /* |
| 19 | * Local variables |
| 20 | */ |
| 21 | /*-----------------------------------------------------------------------------------*/ |
| 22 | |
| 23 | /* ANSI/VT100 colors |
| 24 | 0 - None |
| 25 | 1 - Bold (inc. inten) |
| 26 | 4 - Underscore |
| 27 | 7 - Reverse |
| 28 | x0 - black |
| 29 | x1 - red |
| 30 | x2 - green |
| 31 | x3 - yellow |
| 32 | x4 - blue |
| 33 | x5 - magenta |
| 34 | x6 - cyan |
| 35 | x7 - white |
| 36 | x = 3 fg x = 4 bg |
| 37 | */ |
| 38 | #if 0 /* Colorfull theme */ |
| 39 | static const char backgroundcolor[] = "\033[0;37;40m"; |
| 40 | |
| 41 | static const char wincol[] = "\033[0;37;40m"; |
| 42 | static const char wincol_f[] = "\033[0;1;37;40m"; |
| 43 | static const char wincol_d[] = "\033[0;30;47m"; |
| 44 | |
| 45 | static const char sepcol[] = "\033[0;37;40m"; |
| 46 | static const char sepcol_f[] = "\033[0;1;37;40m"; |
| 47 | static const char sepcol_d[] = "\033[0;30;47m"; |
| 48 | |
| 49 | static const char labcol[] = "\033[0;37;40m"; |
| 50 | static const char labcol_f[] = "\033[1;37;40m"; |
| 51 | static const char labcol_d[] = "\033[0;30;47m"; |
| 52 | |
| 53 | static const char butcol[] = "\033[0;37;40m"; |
| 54 | static const char butcol_w[] = "\033[0;30;47m"; |
| 55 | static const char butcol_f[] = "\033[0;1;37;40m"; |
| 56 | static const char butcol_fw[] = "\033[0;1;37;46m"; |
| 57 | static const char butcol_d[] = "\033[0;30;47m"; |
| 58 | static const char butcol_dw[] = "\033[0;37;46m"; |
| 59 | |
| 60 | static const char hlcol[] = "\033[0;4;36;40m"; |
| 61 | static const char hlcol_w[] = "\033[0;4;30;47m"; |
| 62 | static const char hlcol_f[] = "\033[0;1;4;36;40m"; |
| 63 | static const char hlcol_fw[] = "\033[0;1;4;37;46m"; |
| 64 | static const char hlcol_d[] = "\033[0;4;34;47m"; |
| 65 | static const char hlcol_dw[] = "\033[0;4;37;46m"; |
| 66 | |
| 67 | static const char iconcol[] = "\033[0;32;40m"; |
| 68 | static const char iconcol_w[] = "\033[0;30;42m"; |
| 69 | |
| 70 | static const char menucolor[] = "\033[0;37;43m"; |
| 71 | static const char activemenucolor[] = "\033[0;1;37;43m"; |
| 72 | #endif |
| 73 | |
| 74 | #if 1 /* B/W theme */ |
| 75 | static const char backgroundcolor[] = "\033[0m"; |
| 76 | |
| 77 | static const char wincol[] = "\033[0m"; |
| 78 | static const char wincol_f[] = "\033[0;1m"; |
| 79 | static const char wincol_d[] = "\033[0;7m"; |
| 80 | |
| 81 | static const char sepcol[] = "\033[0m"; |
| 82 | static const char sepcol_f[] = "\033[0;1m"; |
| 83 | static const char sepcol_d[] = "\033[0;7m"; |
| 84 | |
| 85 | static const char labcol[] = "\033[0m"; |
| 86 | static const char labcol_f[] = "\033[0;1m"; |
| 87 | static const char labcol_d[] = "\033[0;7m"; |
| 88 | |
| 89 | static const char butcol[] = "\033[0m"; |
| 90 | static const char butcol_w[] = "\033[0m"; |
| 91 | static const char butcol_f[] = "\033[0;1m"; |
| 92 | static const char butcol_fw[] = "\033[0;1;7m"; |
| 93 | static const char butcol_d[] = "\033[0;7m"; |
| 94 | static const char butcol_dw[] = "\033[0m"; |
| 95 | |
| 96 | static const char hlcol[] = "\033[0;4m"; |
| 97 | static const char hlcol_w[] = "\033[0;4;7m"; |
| 98 | static const char hlcol_f[] = "\033[0;1;4m"; |
| 99 | static const char hlcol_fw[] = "\033[0;1;4;7m"; |
| 100 | static const char hlcol_d[] = "\033[0;4;7m"; |
| 101 | static const char hlcol_dw[] = "\033[0;4m"; |
| 102 | |
| 103 | static const char iconcol[] = "\033[0m"; |
| 104 | static const char iconcol_w[] = "\033[0;7m"; |
| 105 | |
| 106 | static const char menucolor[] = "\033[0;7m"; |
| 107 | static const char activemenucolor[] = "\033[0m"; |
| 108 | |
| 109 | #endif |
| 110 | |
| 111 | static const char* const colortheme[] = |
| 112 | { |
| 113 | backgroundcolor, |
| 114 | |
| 115 | /* Window colors */ |
| 116 | wincol, wincol, wincol_f, wincol_f, wincol_d, wincol_d, |
| 117 | |
| 118 | /* Separator colors. */ |
| 119 | sepcol, sepcol, sepcol_f, sepcol_f, sepcol_d, sepcol_d, |
| 120 | |
| 121 | /* Label colors. */ |
| 122 | labcol, labcol, labcol_f, labcol_f, labcol_d, labcol_d, |
| 123 | |
| 124 | /* Button colors. */ |
| 125 | butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw, |
| 126 | |
| 127 | /* Hyperlink colors. */ |
| 128 | hlcol, hlcol_w, hlcol_f, hlcol_fw, hlcol_d, hlcol_dw, |
| 129 | |
| 130 | /* Textentry colors. */ |
| 131 | butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw, |
| 132 | |
| 133 | /* Icon colors */ |
| 134 | iconcol, iconcol_w, iconcol, iconcol_w, iconcol, iconcol_w, |
| 135 | |
| 136 | /* Menu colors. */ |
| 137 | menucolor, activemenucolor, activemenucolor |
| 138 | }; |
| 139 | |
| 140 | static unsigned char |
| 141 | screen[CHARS_WIDTH * CHARS_HEIGHT], |
| 142 | colorscreen[CHARS_WIDTH * CHARS_HEIGHT]; |
| 143 | |
| 144 | /*-----------------------------------------------------------------------------------*/ |
| 145 | /* |
| 146 | * Add a character to the screen buffer |
| 147 | */ |
| 148 | /*-----------------------------------------------------------------------------------*/ |
| 149 | void |
| 150 | ctk_term_out_update_screen(unsigned char xpos, |
| 151 | unsigned char ypos, |
| 152 | unsigned char c, |
| 153 | unsigned char color) |
| 154 | { |
| 155 | if (c < 0x20) c = 0x20; |
| 156 | screen[xpos + ypos * CHARS_WIDTH] = c; |
| 157 | colorscreen[xpos + ypos * CHARS_WIDTH] = color; |
| 158 | } |
| 159 | |
| 160 | /*-----------------------------------------------------------------------------------*/ |
| 161 | /* |
| 162 | * Check if there are any updated pending. If so, make the first one current |
| 163 | */ |
| 164 | /*-----------------------------------------------------------------------------------*/ |
| 165 | static void |
| 166 | check_updates(struct ctk_term_state* ts) |
| 167 | { |
| 168 | if (ts->updates_current != NULL) return; |
| 169 | ts->updates_current = ctk_term_update_dequeue(ts); |
| 170 | if (ts->updates_current != NULL) { |
| 171 | ts->x = ts->updates_current->x; |
| 172 | ts->y = ts->updates_current->y; |
| 173 | ts->w = ts->updates_current->w; |
| 174 | ts->h = ts->updates_current->h; |
| 175 | ts->x1 = ts->x2 = ts->x; |
| 176 | ts->y1 = ts->y2 = ts->y; |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | /*-----------------------------------------------------------------------------------*/ |
| 181 | /** \internal |
| 182 | * Adds a cursor position change to buffer. Returns 0 if string doesn't fit else |
| 183 | * number of bytes actually written is returned. |
| 184 | * |
| 185 | * \param x X coordinate (screen coordinates) |
| 186 | * \param y Y coordinate (screen coordinates) |
| 187 | * \param buf Output buffer |
| 188 | * \param maxlen Maximum number of bytes to store in buffer |
| 189 | */ |
| 190 | /*-----------------------------------------------------------------------------------*/ |
| 191 | static unsigned short |
| 192 | move_to(unsigned char x, unsigned char y, unsigned char* buf, unsigned short maxlen) |
| 193 | { |
| 194 | if (maxlen < 14) return 0; |
| 195 | return (unsigned short)sprintf((char*)buf, "\033[%d;%dH", y+1, x+1); |
| 196 | } |
| 197 | |
| 198 | /*-----------------------------------------------------------------------------------*/ |
| 199 | /** \internal |
| 200 | * Adds a attribute string to buffer. Returns 0 if string doesn't fit else |
| 201 | * number of bytes actually written is returned. |
| 202 | * |
| 203 | * \param c Color number |
| 204 | * \param buf Output buffer |
| 205 | * \param maxlen Maximum number of bytes to store in buffer |
| 206 | */ |
| 207 | /*-----------------------------------------------------------------------------------*/ |
| 208 | static unsigned short |
| 209 | set_color(unsigned char c, unsigned char* buf, unsigned short maxlen) |
| 210 | { |
| 211 | int len = strlen((const char*)colortheme[c]); |
| 212 | if (maxlen < len) return 0; |
| 213 | memcpy(buf, colortheme[c], len); |
| 214 | return len; |
| 215 | } |
| 216 | |
| 217 | /*-----------------------------------------------------------------------------------*/ |
| 218 | /** |
| 219 | * Stores terminal data in buffer provided by caller. Returns number of bytes written |
| 220 | * to the output buffer. |
| 221 | * |
| 222 | * \param ts State information |
| 223 | * \param buf Output buffer |
| 224 | * \param maxlen Maximum number of bytes to store in buffer |
| 225 | */ |
| 226 | /*-----------------------------------------------------------------------------------*/ |
| 227 | unsigned short |
| 228 | ctk_term_send(struct ctk_term_state* ts, |
| 229 | unsigned char* buf, |
| 230 | unsigned short maxlen) |
| 231 | { |
| 232 | unsigned char x, y, x0; |
| 233 | unsigned char col, c; |
| 234 | unsigned short tmp; |
| 235 | unsigned short totlen; |
| 236 | |
| 237 | check_updates(ts); |
| 238 | |
| 239 | if (ts->updates_current == NULL) return 0; |
| 240 | |
| 241 | x0 = ts->x1; |
| 242 | col = ts->c1; |
| 243 | totlen = 0; |
| 244 | /* Loop across the update region starting at (x1,y1) */ |
| 245 | for(y = ts->y1; y < ts->y + ts->h; ++y) { |
| 246 | for(x = x0; x < ts->x + ts->w; ++x) { |
| 247 | /* New line ? */ |
| 248 | if (x == ts->x) { |
| 249 | /* Move cursor to start of line */ |
| 250 | tmp = move_to(x,y,buf,maxlen); |
| 251 | if (tmp == 0) goto loopend; |
| 252 | buf += tmp; |
| 253 | totlen += tmp; |
| 254 | maxlen -= tmp; |
| 255 | } |
| 256 | /* Check color */ |
| 257 | c = colorscreen[x + y * CHARS_WIDTH]; |
| 258 | if (c != col) { |
| 259 | PRINTF(("colorchange at (%d, %d) to %d\n", x,y,c)); |
| 260 | /* Send new color information */ |
| 261 | tmp = set_color(c, buf, maxlen); |
| 262 | if (tmp == 0) goto loopend; |
| 263 | col = c; |
| 264 | buf += tmp; |
| 265 | totlen += tmp; |
| 266 | maxlen -= tmp; |
| 267 | } |
| 268 | /* Check remaining space */ |
| 269 | if (maxlen < 1) goto loopend; |
| 270 | /* Add character */ |
| 271 | *buf = screen[x + y * CHARS_WIDTH]; |
| 272 | buf++; |
| 273 | maxlen--; |
| 274 | totlen++; |
| 275 | } |
| 276 | x0 = ts->x; |
| 277 | } |
| 278 | loopend: |
| 279 | /* Always save current color state */ |
| 280 | ts->c2 = col; |
| 281 | PRINTF(("ending loop at (%d, %d)\n", x,y)); |
| 282 | /* Check if done */ |
| 283 | if (x == ts->x+ts->w && y == ts->y+ts->h) { |
| 284 | /* Signal done with this update */ |
| 285 | ts->x2 = ts->y2 = 0; |
| 286 | } |
| 287 | else { |
| 288 | /* Not done. Save state */ |
| 289 | ts->x2 = x; |
| 290 | ts->y2 = y; |
| 291 | } |
| 292 | return totlen; |
| 293 | } |
| 294 | |
| 295 | /*-----------------------------------------------------------------------------------*/ |
| 296 | /** |
| 297 | * Called by client when the data returned by ctk_term_send() are successfully sent. |
| 298 | * |
| 299 | * \param ts State information |
| 300 | */ |
| 301 | /*-----------------------------------------------------------------------------------*/ |
| 302 | void ctk_term_sent(struct ctk_term_state* ts) |
| 303 | { |
| 304 | if (ts->updates_current != NULL) { |
| 305 | /* Check if current update done */ |
| 306 | if (ts->x2 == 0 && ts->y2 == 0) { |
| 307 | /* Yes, free it */ |
| 308 | ctk_term_update_free(ts, ts->updates_current); |
| 309 | ts->updates_current = NULL; |
| 310 | } |
| 311 | else { |
| 312 | /* Nop. Update start posititions */ |
| 313 | ts->x1 = ts->x2; |
| 314 | ts->y1 = ts->y2; |
| 315 | } |
| 316 | ts->c1 = ts->c2; |
| 317 | } |
| 318 | } |