| #include "libconio.h" |
| #include "ctk-term-int.h" |
| #include <string.h> |
| #include <stdio.h> // sprintf |
| |
| #define PRINTF(x) |
| |
| /*-----------------------------------------------------------------------------------*/ |
| /* |
| * #defines and enums |
| */ |
| /*-----------------------------------------------------------------------------------*/ |
| |
| #define CHARS_WIDTH LIBCONIO_CONF_SCREEN_WIDTH |
| #define CHARS_HEIGHT LIBCONIO_CONF_SCREEN_HEIGHT |
| |
| /*-----------------------------------------------------------------------------------*/ |
| /* |
| * Local variables |
| */ |
| /*-----------------------------------------------------------------------------------*/ |
| |
| /* ANSI/VT100 colors |
| 0 - None |
| 1 - Bold (inc. inten) |
| 4 - Underscore |
| 7 - Reverse |
| x0 - black |
| x1 - red |
| x2 - green |
| x3 - yellow |
| x4 - blue |
| x5 - magenta |
| x6 - cyan |
| x7 - white |
| x = 3 fg x = 4 bg |
| */ |
| #if 0 /* Colorfull theme */ |
| static const char backgroundcolor[] = "\033[0;37;40m"; |
| |
| static const char wincol[] = "\033[0;37;40m"; |
| static const char wincol_f[] = "\033[0;1;37;40m"; |
| static const char wincol_d[] = "\033[0;30;47m"; |
| |
| static const char sepcol[] = "\033[0;37;40m"; |
| static const char sepcol_f[] = "\033[0;1;37;40m"; |
| static const char sepcol_d[] = "\033[0;30;47m"; |
| |
| static const char labcol[] = "\033[0;37;40m"; |
| static const char labcol_f[] = "\033[1;37;40m"; |
| static const char labcol_d[] = "\033[0;30;47m"; |
| |
| static const char butcol[] = "\033[0;37;40m"; |
| static const char butcol_w[] = "\033[0;30;47m"; |
| static const char butcol_f[] = "\033[0;1;37;40m"; |
| static const char butcol_fw[] = "\033[0;1;37;46m"; |
| static const char butcol_d[] = "\033[0;30;47m"; |
| static const char butcol_dw[] = "\033[0;37;46m"; |
| |
| static const char hlcol[] = "\033[0;4;36;40m"; |
| static const char hlcol_w[] = "\033[0;4;30;47m"; |
| static const char hlcol_f[] = "\033[0;1;4;36;40m"; |
| static const char hlcol_fw[] = "\033[0;1;4;37;46m"; |
| static const char hlcol_d[] = "\033[0;4;34;47m"; |
| static const char hlcol_dw[] = "\033[0;4;37;46m"; |
| |
| static const char iconcol[] = "\033[0;32;40m"; |
| static const char iconcol_w[] = "\033[0;30;42m"; |
| |
| static const char menucolor[] = "\033[0;37;43m"; |
| static const char activemenucolor[] = "\033[0;1;37;43m"; |
| #endif |
| |
| #if 1 /* B/W theme */ |
| static const char backgroundcolor[] = "\033[0m"; |
| |
| static const char wincol[] = "\033[0m"; |
| static const char wincol_f[] = "\033[0;1m"; |
| static const char wincol_d[] = "\033[0;7m"; |
| |
| static const char sepcol[] = "\033[0m"; |
| static const char sepcol_f[] = "\033[0;1m"; |
| static const char sepcol_d[] = "\033[0;7m"; |
| |
| static const char labcol[] = "\033[0m"; |
| static const char labcol_f[] = "\033[0;1m"; |
| static const char labcol_d[] = "\033[0;7m"; |
| |
| static const char butcol[] = "\033[0m"; |
| static const char butcol_w[] = "\033[0m"; |
| static const char butcol_f[] = "\033[0;1m"; |
| static const char butcol_fw[] = "\033[0;1;7m"; |
| static const char butcol_d[] = "\033[0;7m"; |
| static const char butcol_dw[] = "\033[0m"; |
| |
| static const char hlcol[] = "\033[0;4m"; |
| static const char hlcol_w[] = "\033[0;4;7m"; |
| static const char hlcol_f[] = "\033[0;1;4m"; |
| static const char hlcol_fw[] = "\033[0;1;4;7m"; |
| static const char hlcol_d[] = "\033[0;4;7m"; |
| static const char hlcol_dw[] = "\033[0;4m"; |
| |
| static const char iconcol[] = "\033[0m"; |
| static const char iconcol_w[] = "\033[0;7m"; |
| |
| static const char menucolor[] = "\033[0;7m"; |
| static const char activemenucolor[] = "\033[0m"; |
| |
| #endif |
| |
| static const char* const colortheme[] = |
| { |
| backgroundcolor, |
| |
| /* Window colors */ |
| wincol, wincol, wincol_f, wincol_f, wincol_d, wincol_d, |
| |
| /* Separator colors. */ |
| sepcol, sepcol, sepcol_f, sepcol_f, sepcol_d, sepcol_d, |
| |
| /* Label colors. */ |
| labcol, labcol, labcol_f, labcol_f, labcol_d, labcol_d, |
| |
| /* Button colors. */ |
| butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw, |
| |
| /* Hyperlink colors. */ |
| hlcol, hlcol_w, hlcol_f, hlcol_fw, hlcol_d, hlcol_dw, |
| |
| /* Textentry colors. */ |
| butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw, |
| |
| /* Icon colors */ |
| iconcol, iconcol_w, iconcol, iconcol_w, iconcol, iconcol_w, |
| |
| /* Menu colors. */ |
| menucolor, activemenucolor, activemenucolor |
| }; |
| |
| static unsigned char |
| screen[CHARS_WIDTH * CHARS_HEIGHT], |
| colorscreen[CHARS_WIDTH * CHARS_HEIGHT]; |
| |
| /*-----------------------------------------------------------------------------------*/ |
| /* |
| * Add a character to the screen buffer |
| */ |
| /*-----------------------------------------------------------------------------------*/ |
| void |
| ctk_term_out_update_screen(unsigned char xpos, |
| unsigned char ypos, |
| unsigned char c, |
| unsigned char color) |
| { |
| if (c < 0x20) c = 0x20; |
| screen[xpos + ypos * CHARS_WIDTH] = c; |
| colorscreen[xpos + ypos * CHARS_WIDTH] = color; |
| } |
| |
| /*-----------------------------------------------------------------------------------*/ |
| /* |
| * Check if there are any updated pending. If so, make the first one current |
| */ |
| /*-----------------------------------------------------------------------------------*/ |
| static void |
| check_updates(struct ctk_term_state* ts) |
| { |
| if (ts->updates_current != NULL) return; |
| ts->updates_current = ctk_term_update_dequeue(ts); |
| if (ts->updates_current != NULL) { |
| ts->x = ts->updates_current->x; |
| ts->y = ts->updates_current->y; |
| ts->w = ts->updates_current->w; |
| ts->h = ts->updates_current->h; |
| ts->x1 = ts->x2 = ts->x; |
| ts->y1 = ts->y2 = ts->y; |
| } |
| } |
| |
| /*-----------------------------------------------------------------------------------*/ |
| /** \internal |
| * Adds a cursor position change to buffer. Returns 0 if string doesn't fit else |
| * number of bytes actually written is returned. |
| * |
| * \param x X coordinate (screen coordinates) |
| * \param y Y coordinate (screen coordinates) |
| * \param buf Output buffer |
| * \param maxlen Maximum number of bytes to store in buffer |
| */ |
| /*-----------------------------------------------------------------------------------*/ |
| static unsigned short |
| move_to(unsigned char x, unsigned char y, unsigned char* buf, unsigned short maxlen) |
| { |
| if (maxlen < 14) return 0; |
| return (unsigned short)sprintf((char*)buf, "\033[%d;%dH", y+1, x+1); |
| } |
| |
| /*-----------------------------------------------------------------------------------*/ |
| /** \internal |
| * Adds a attribute string to buffer. Returns 0 if string doesn't fit else |
| * number of bytes actually written is returned. |
| * |
| * \param c Color number |
| * \param buf Output buffer |
| * \param maxlen Maximum number of bytes to store in buffer |
| */ |
| /*-----------------------------------------------------------------------------------*/ |
| static unsigned short |
| set_color(unsigned char c, unsigned char* buf, unsigned short maxlen) |
| { |
| int len = strlen((const char*)colortheme[c]); |
| if (maxlen < len) return 0; |
| memcpy(buf, colortheme[c], len); |
| return len; |
| } |
| |
| /*-----------------------------------------------------------------------------------*/ |
| /** |
| * Stores terminal data in buffer provided by caller. Returns number of bytes written |
| * to the output buffer. |
| * |
| * \param ts State information |
| * \param buf Output buffer |
| * \param maxlen Maximum number of bytes to store in buffer |
| */ |
| /*-----------------------------------------------------------------------------------*/ |
| unsigned short |
| ctk_term_send(struct ctk_term_state* ts, |
| unsigned char* buf, |
| unsigned short maxlen) |
| { |
| unsigned char x, y, x0; |
| unsigned char col, c; |
| unsigned short tmp; |
| unsigned short totlen; |
| |
| check_updates(ts); |
| |
| if (ts->updates_current == NULL) return 0; |
| |
| x0 = ts->x1; |
| col = ts->c1; |
| totlen = 0; |
| /* Loop across the update region starting at (x1,y1) */ |
| for(y = ts->y1; y < ts->y + ts->h; ++y) { |
| for(x = x0; x < ts->x + ts->w; ++x) { |
| /* New line ? */ |
| if (x == ts->x) { |
| /* Move cursor to start of line */ |
| tmp = move_to(x,y,buf,maxlen); |
| if (tmp == 0) goto loopend; |
| buf += tmp; |
| totlen += tmp; |
| maxlen -= tmp; |
| } |
| /* Check color */ |
| c = colorscreen[x + y * CHARS_WIDTH]; |
| if (c != col) { |
| PRINTF(("colorchange at (%d, %d) to %d\n", x,y,c)); |
| /* Send new color information */ |
| tmp = set_color(c, buf, maxlen); |
| if (tmp == 0) goto loopend; |
| col = c; |
| buf += tmp; |
| totlen += tmp; |
| maxlen -= tmp; |
| } |
| /* Check remaining space */ |
| if (maxlen < 1) goto loopend; |
| /* Add character */ |
| *buf = screen[x + y * CHARS_WIDTH]; |
| buf++; |
| maxlen--; |
| totlen++; |
| } |
| x0 = ts->x; |
| } |
| loopend: |
| /* Always save current color state */ |
| ts->c2 = col; |
| PRINTF(("ending loop at (%d, %d)\n", x,y)); |
| /* Check if done */ |
| if (x == ts->x+ts->w && y == ts->y+ts->h) { |
| /* Signal done with this update */ |
| ts->x2 = ts->y2 = 0; |
| } |
| else { |
| /* Not done. Save state */ |
| ts->x2 = x; |
| ts->y2 = y; |
| } |
| return totlen; |
| } |
| |
| /*-----------------------------------------------------------------------------------*/ |
| /** |
| * Called by client when the data returned by ctk_term_send() are successfully sent. |
| * |
| * \param ts State information |
| */ |
| /*-----------------------------------------------------------------------------------*/ |
| void ctk_term_sent(struct ctk_term_state* ts) |
| { |
| if (ts->updates_current != NULL) { |
| /* Check if current update done */ |
| if (ts->x2 == 0 && ts->y2 == 0) { |
| /* Yes, free it */ |
| ctk_term_update_free(ts, ts->updates_current); |
| ts->updates_current = NULL; |
| } |
| else { |
| /* Nop. Update start posititions */ |
| ts->x1 = ts->x2; |
| ts->y1 = ts->y2; |
| } |
| ts->c1 = ts->c2; |
| } |
| } |