Add support for ANSI like escape sequences to control display color and attributes in a GWIN console.
Updated the console demo to demonstrate this.
This commit is contained in:
parent
43527de2c0
commit
c110548507
6 changed files with 199 additions and 10 deletions
|
@ -52,6 +52,7 @@
|
||||||
/* Features for the GWIN subsystem. */
|
/* Features for the GWIN subsystem. */
|
||||||
#define GWIN_NEED_WINDOWMANAGER TRUE
|
#define GWIN_NEED_WINDOWMANAGER TRUE
|
||||||
#define GWIN_NEED_CONSOLE TRUE
|
#define GWIN_NEED_CONSOLE TRUE
|
||||||
|
#define GWIN_CONSOLE_ESCSEQ TRUE
|
||||||
|
|
||||||
#endif /* _GFXCONF_H */
|
#endif /* _GFXCONF_H */
|
||||||
|
|
||||||
|
|
|
@ -75,17 +75,17 @@ int main(void) {
|
||||||
|
|
||||||
/* Output some data on the first console */
|
/* Output some data on the first console */
|
||||||
for(i = 0; i < 10; i++) {
|
for(i = 0; i < 10; i++) {
|
||||||
gwinPrintf(GW1, "Hello uGFX!\r\n");
|
gwinPrintf(GW1, "Hello \033buGFX\033B!\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output some data on the second console */
|
/* Output some data on the second console */
|
||||||
for(i = 0; i < 16; i++) {
|
for(i = 0; i < 16; i++) {
|
||||||
gwinPrintf(GW2, "Message Nr.: %d\r\n", i+1);
|
gwinPrintf(GW2, "Message Nr.: \0331\033b%d\033B\033C\r\n", i+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output some data on the third console */
|
/* Output some data on the third console */
|
||||||
for(i = 0; i < 18; i++) {
|
for(i = 0; i < 18; i++) {
|
||||||
gwinPrintf(GW3, "Message Nr.: %d\r\n", i+1);
|
gwinPrintf(GW3, "Message Nr.: \033u%d\033U\r\n", i+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(TRUE) {
|
while(TRUE) {
|
||||||
|
|
|
@ -129,6 +129,7 @@
|
||||||
#define GWIN_CONSOLE_USE_HISTORY FALSE
|
#define GWIN_CONSOLE_USE_HISTORY FALSE
|
||||||
#define GWIN_CONSOLE_HISTORY_AVERAGING FALSE
|
#define GWIN_CONSOLE_HISTORY_AVERAGING FALSE
|
||||||
#define GWIN_CONSOLE_HISTORY_ATCREATE FALSE
|
#define GWIN_CONSOLE_HISTORY_ATCREATE FALSE
|
||||||
|
#define GWIN_CONSOLE_ESCSEQ FALSE
|
||||||
#define GWIN_CONSOLE_USE_BASESTREAM FALSE
|
#define GWIN_CONSOLE_USE_BASESTREAM FALSE
|
||||||
#define GWIN_CONSOLE_USE_FLOAT FALSE
|
#define GWIN_CONSOLE_USE_FLOAT FALSE
|
||||||
#define GWIN_NEED_GRAPH FALSE
|
#define GWIN_NEED_GRAPH FALSE
|
||||||
|
|
|
@ -26,6 +26,14 @@
|
||||||
#define GCONSOLE_FLG_NOSTORE (GWIN_FIRST_CONTROL_FLAG<<0)
|
#define GCONSOLE_FLG_NOSTORE (GWIN_FIRST_CONTROL_FLAG<<0)
|
||||||
#define GCONSOLE_FLG_OVERRUN (GWIN_FIRST_CONTROL_FLAG<<1)
|
#define GCONSOLE_FLG_OVERRUN (GWIN_FIRST_CONTROL_FLAG<<1)
|
||||||
|
|
||||||
|
// Meaning of our attribute bits.
|
||||||
|
#define ESC_REDBIT 0x01
|
||||||
|
#define ESC_GREENBIT 0x02
|
||||||
|
#define ESC_BLUEBIT 0x04
|
||||||
|
#define ESC_USECOLOR 0x08
|
||||||
|
#define ESC_UNDERLINE 0x10
|
||||||
|
#define ESC_BOLD 0x20
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stream interface implementation. The interface is write only
|
* Stream interface implementation. The interface is write only
|
||||||
*/
|
*/
|
||||||
|
@ -58,6 +66,68 @@
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
// Convert escape sequences to attributes
|
||||||
|
static bool_t ESCtoAttr(char c, uint8_t *pattr) {
|
||||||
|
uint8_t attr;
|
||||||
|
|
||||||
|
attr = pattr[0];
|
||||||
|
switch(c) {
|
||||||
|
case '0': case '1': case '2': case '3':
|
||||||
|
case '4': case '5': case '6': case '7':
|
||||||
|
attr &= ~(ESC_REDBIT|ESC_GREENBIT|ESC_BLUEBIT);
|
||||||
|
attr |= (c - '0') | ESC_USECOLOR;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
attr &= ~(ESC_REDBIT|ESC_GREENBIT|ESC_BLUEBIT|ESC_USECOLOR);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
attr |= ESC_UNDERLINE;
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
attr &= ~ESC_UNDERLINE;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
attr |= ESC_BOLD;
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
attr &= ~ESC_BOLD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (attr == pattr[0])
|
||||||
|
return FALSE;
|
||||||
|
pattr[0] = attr;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static color_t ESCPrintColor(GConsoleObject *gcw) {
|
||||||
|
switch(gcw->currattr & (ESC_REDBIT|ESC_GREENBIT|ESC_BLUEBIT|ESC_USECOLOR)) {
|
||||||
|
case (ESC_USECOLOR):
|
||||||
|
return Black;
|
||||||
|
case (ESC_USECOLOR|ESC_REDBIT):
|
||||||
|
return Red;
|
||||||
|
case (ESC_USECOLOR|ESC_GREENBIT):
|
||||||
|
return Green;
|
||||||
|
case (ESC_USECOLOR|ESC_REDBIT|ESC_GREENBIT):
|
||||||
|
return Yellow;
|
||||||
|
case (ESC_USECOLOR|ESC_BLUEBIT):
|
||||||
|
return Blue;
|
||||||
|
case (ESC_USECOLOR|ESC_REDBIT|ESC_BLUEBIT):
|
||||||
|
return Magenta;
|
||||||
|
case (ESC_USECOLOR|ESC_GREENBIT|ESC_BLUEBIT):
|
||||||
|
return Cyan;
|
||||||
|
case (ESC_USECOLOR|ESC_REDBIT|ESC_GREENBIT|ESC_BLUEBIT):
|
||||||
|
return White;
|
||||||
|
default:
|
||||||
|
return gcw->g.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define ESCPrintColor(gcw) ((gcw)->g.color)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if GWIN_CONSOLE_USE_HISTORY
|
#if GWIN_CONSOLE_USE_HISTORY
|
||||||
static void HistoryDestroy(GWindowObject *gh) {
|
static void HistoryDestroy(GWindowObject *gh) {
|
||||||
#define gcw ((GConsoleObject *)gh)
|
#define gcw ((GConsoleObject *)gh)
|
||||||
|
@ -90,6 +160,11 @@
|
||||||
gcw->cx = 0;
|
gcw->cx = 0;
|
||||||
gcw->cy = 0;
|
gcw->cy = 0;
|
||||||
|
|
||||||
|
// Reset the current attributes
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
gcw->currattr = gcw->startattr;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Print the buffer
|
// Print the buffer
|
||||||
gwinPutCharArray(gh, gcw->buffer, gcw->bufpos);
|
gwinPutCharArray(gh, gcw->buffer, gcw->bufpos);
|
||||||
|
|
||||||
|
@ -115,7 +190,7 @@
|
||||||
|
|
||||||
// Do we have enough space in the buffer
|
// Do we have enough space in the buffer
|
||||||
if (gcw->bufpos >= gcw->bufsize) {
|
if (gcw->bufpos >= gcw->bufsize) {
|
||||||
char * p;
|
char *p, *ep;
|
||||||
size_t dp;
|
size_t dp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,7 +205,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Remove one line from the start
|
// Remove one line from the start
|
||||||
for(p = gcw->buffer; *p && *p != '\n'; p++);
|
ep = gcw->buffer+gcw->bufpos;
|
||||||
|
for(p = gcw->buffer; p < ep && *p != '\n'; p++) {
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
if (*p == 27)
|
||||||
|
ESCtoAttr(p[1], &gcw->startattr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Was there a newline?
|
// Was there a newline?
|
||||||
if (*p != '\n')
|
if (*p != '\n')
|
||||||
|
@ -153,7 +234,7 @@
|
||||||
* Scroll the history buffer by one line
|
* Scroll the history buffer by one line
|
||||||
*/
|
*/
|
||||||
static void scrollBuffer(GConsoleObject *gcw) {
|
static void scrollBuffer(GConsoleObject *gcw) {
|
||||||
char * p;
|
char *p, *ep;
|
||||||
size_t dp;
|
size_t dp;
|
||||||
|
|
||||||
// Only scroll if we need to
|
// Only scroll if we need to
|
||||||
|
@ -167,7 +248,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove one line from the start
|
// Remove one line from the start
|
||||||
for(p = gcw->buffer; *p && *p != '\n'; p++);
|
ep = gcw->buffer+gcw->bufpos;
|
||||||
|
for(p = gcw->buffer; p < ep && *p != '\n'; p++) {
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
if (*p == 27)
|
||||||
|
ESCtoAttr(p[1], &gcw->startattr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Was there a newline, if not delete everything.
|
// Was there a newline, if not delete everything.
|
||||||
if (*p != '\n') {
|
if (*p != '\n') {
|
||||||
|
@ -205,6 +292,9 @@ static void AfterClear(GWindowObject *gh) {
|
||||||
gcw->cx = 0;
|
gcw->cx = 0;
|
||||||
gcw->cy = 0;
|
gcw->cy = 0;
|
||||||
clearBuffer(gcw);
|
clearBuffer(gcw);
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
gcw->startattr = gcw->currattr;
|
||||||
|
#endif
|
||||||
#undef gcw
|
#undef gcw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +329,11 @@ GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *p
|
||||||
gc->cx = 0;
|
gc->cx = 0;
|
||||||
gc->cy = 0;
|
gc->cy = 0;
|
||||||
|
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
gc->startattr = gc->currattr = 0;
|
||||||
|
gc->escstate = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
gwinSetVisible((GHandle)gc, pInit->show);
|
gwinSetVisible((GHandle)gc, pInit->show);
|
||||||
|
|
||||||
return (GHandle)gc;
|
return (GHandle)gc;
|
||||||
|
@ -314,12 +409,53 @@ void gwinPutChar(GHandle gh, char c) {
|
||||||
gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
|
gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
/**
|
||||||
|
* Handle escape sequences
|
||||||
|
* ESC color Change subsequent text color
|
||||||
|
* color: "0" = black, "1" = red, "2" = green, "3" = yellow, "4" = blue,
|
||||||
|
* "5" = magenta, "6" = cyan, "7" = white
|
||||||
|
* ESC C Revert subsequent text color to the window default
|
||||||
|
* ESC u Turn on underline
|
||||||
|
* ESC U Turn off underline
|
||||||
|
* ESC b Turn on bold
|
||||||
|
* ESC B Turn off bold
|
||||||
|
* ESC J Clear the window
|
||||||
|
*/
|
||||||
|
switch (gcw->escstate) {
|
||||||
|
case 1:
|
||||||
|
gcw->escstate = 0;
|
||||||
|
if (ESCtoAttr(c, &gcw->currattr)) {
|
||||||
|
if (gcw->cx == 0 && gcw->cy == 0)
|
||||||
|
gcw->startattr = gcw->currattr;
|
||||||
|
else {
|
||||||
|
putCharInBuffer(gcw, 27);
|
||||||
|
putCharInBuffer(gcw, c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(c) {
|
||||||
|
case 'J':
|
||||||
|
// Clear the console and reset the cursor
|
||||||
|
clearBuffer(gcw);
|
||||||
|
gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
|
||||||
|
gcw->cx = 0;
|
||||||
|
gcw->cy = 0;
|
||||||
|
gcw->startattr = gcw->currattr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Special Characters:
|
* Special Characters:
|
||||||
*
|
*
|
||||||
* Carriage returns and line feeds (\r & \n) are handled in unix terminal cooked mode; that is,
|
* Carriage returns and line feeds (\r & \n) are handled in unix terminal cooked mode; that is,
|
||||||
* line feeds perform both actions and carriage-returns are ignored.
|
* line feeds perform both actions and carriage-returns are ignored.
|
||||||
*
|
*
|
||||||
|
* if GWIN_CONSOLE_ESCSEQ is turned on then ESC is trapped ready for the escape command.
|
||||||
|
*
|
||||||
* All other characters are treated as printable.
|
* All other characters are treated as printable.
|
||||||
*/
|
*/
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -339,12 +475,24 @@ void gwinPutChar(GHandle gh, char c) {
|
||||||
case '\r':
|
case '\r':
|
||||||
// gcw->cx = 0;
|
// gcw->cx = 0;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
case 27: // ESC
|
||||||
|
gcw->escstate = 1;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Characters with no width are ignored
|
// Characters with no width are ignored
|
||||||
if (!(width = gdispGetCharWidth(c, gh->font)))
|
if (!(width = gdispGetCharWidth(c, gh->font)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Allow space for (very crude) bold
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
if ((gcw->currattr & ESC_BOLD))
|
||||||
|
width++;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Do we need to go to the next line to fit this character?
|
// Do we need to go to the next line to fit this character?
|
||||||
if (gcw->cx + width >= gh->width) {
|
if (gcw->cx + width >= gh->width) {
|
||||||
gcw->cx = 0;
|
gcw->cx = 0;
|
||||||
|
@ -378,6 +526,9 @@ void gwinPutChar(GHandle gh, char c) {
|
||||||
gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
|
gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
|
||||||
gcw->cx = 0;
|
gcw->cx = 0;
|
||||||
gcw->cy = 0;
|
gcw->cy = 0;
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
gcw->startattr = gcw->currattr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -390,12 +541,23 @@ void gwinPutChar(GHandle gh, char c) {
|
||||||
|
|
||||||
// Draw the character
|
// Draw the character
|
||||||
#if GWIN_CONSOLE_USE_FILLED_CHARS
|
#if GWIN_CONSOLE_USE_FILLED_CHARS
|
||||||
gdispGFillChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor);
|
gdispGFillChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw), gh->bgcolor);
|
||||||
#else
|
#else
|
||||||
gdispGDrawChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color);
|
gdispGDrawChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw));
|
||||||
#endif
|
#endif
|
||||||
putCharInBuffer(gcw, c);
|
putCharInBuffer(gcw, c);
|
||||||
|
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
// Draw the underline
|
||||||
|
if ((gcw->currattr & ESC_UNDERLINE))
|
||||||
|
gdispGDrawLine(gh->display, gh->x + gcw->cx, gh->y + gcw->cy + fy - gdispGetFontMetric(gh->font, fontDescendersHeight),
|
||||||
|
gh->x + gcw->cx + width + gdispGetFontMetric(gh->font, fontCharPadding), gh->y + gcw->cy + fy - gdispGetFontMetric(gh->font, fontDescendersHeight),
|
||||||
|
ESCPrintColor(gcw));
|
||||||
|
// Bold (very crude)
|
||||||
|
if ((gcw->currattr & ESC_BOLD))
|
||||||
|
gdispGDrawChar(gh->display, gh->x + gcw->cx + 1, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw));
|
||||||
|
#endif
|
||||||
|
|
||||||
// Update the cursor
|
// Update the cursor
|
||||||
gcw->cx += width + gdispGetFontMetric(gh->font, fontCharPadding);
|
gcw->cx += width + gdispGetFontMetric(gh->font, fontCharPadding);
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,12 @@ typedef struct GConsoleObject {
|
||||||
GWindowObject g;
|
GWindowObject g;
|
||||||
coord_t cx, cy; // Cursor position
|
coord_t cx, cy; // Cursor position
|
||||||
|
|
||||||
|
#if GWIN_CONSOLE_ESCSEQ
|
||||||
|
uint8_t startattr; // ANSI-like escape sequences
|
||||||
|
uint8_t currattr;
|
||||||
|
uint16_t escstate;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if GWIN_CONSOLE_USE_HISTORY
|
#if GWIN_CONSOLE_USE_HISTORY
|
||||||
char * buffer; // buffer to store console content
|
char * buffer; // buffer to store console content
|
||||||
size_t bufsize; // size of buffer
|
size_t bufsize; // size of buffer
|
||||||
|
|
|
@ -159,6 +159,25 @@
|
||||||
#ifndef GWIN_CONSOLE_USE_FLOAT
|
#ifndef GWIN_CONSOLE_USE_FLOAT
|
||||||
#define GWIN_CONSOLE_USE_FLOAT FALSE
|
#define GWIN_CONSOLE_USE_FLOAT FALSE
|
||||||
#endif
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief Console windows support escape sequences to control display
|
||||||
|
* @details Defaults to FALSE
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Currently supported:
|
||||||
|
* ESC color Change subsequent text color
|
||||||
|
* color: "0" = black, "1" = red, "2" = green, "3" = yellow, "4" = blue,
|
||||||
|
* "5" = magenta, "6" = cyan, "7" = white
|
||||||
|
* ESC C Revert subsequent text color to the window default
|
||||||
|
* ESC u Turn on underline
|
||||||
|
* ESC U Turn off underline
|
||||||
|
* ESC b Turn on bold
|
||||||
|
* ESC B Turn off bold
|
||||||
|
* ESC J Clear the window
|
||||||
|
*/
|
||||||
|
#ifndef GWIN_CONSOLE_ESCSEQ
|
||||||
|
#define GWIN_CONSOLE_ESCSEQ FALSE
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* @brief Console Windows need BaseStreamSequential support (ChibiOS only)
|
* @brief Console Windows need BaseStreamSequential support (ChibiOS only)
|
||||||
* @details Defaults to FALSE
|
* @details Defaults to FALSE
|
||||||
|
|
Loading…
Add table
Reference in a new issue