Inspired by Simon Ford's "Terminal" library, this is a clean-room reimplementation that supports a larger set of the ANSI escape sequences and includes a few handy drawing routines. Useful for making console UIs for your projects. The box-drawing stuff requires your terminal to be set to codepage 850.
Fork of ANSITerm by
Diff: ANSITerm.cpp
- Revision:
- 0:863811463610
- Child:
- 2:a681bda60db7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ANSITerm.cpp Tue Sep 18 18:58:19 2012 +0000 @@ -0,0 +1,174 @@ +/* +Copyright (c) 2012 dansummers + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +#include "ANSITerm.h" +#include "mbed.h" + +//Box styles +/* topleft, topright, bottomleft, bottomright, horiz, vert, uptee, downtee, lefttee, righttee,cross */ +const char ANSITerm::two_lines[11] = {0xC9,0xBB,0xC8,0xBC,0xCD,0xBA,0xCA,0xCB,0xB9,0xCC,0xCE}; +const char ANSITerm::one_line[11] = {0xDA,0xBF,0xC0,0xD9,0xC4,0xB3,0xC1,0xC2,0xB4,0xC3,0xC5}; +const char ANSITerm::simple[11] = {'+','+','+','+','-','|','+','+','+','+','+'}; + +ANSITerm::ANSITerm(PinName tx, PinName rx) : Serial(tx, rx) {current_style = 0;} + +/* Device Status Report (Returns CSIn;mR, where n,m is the coordinates of the cursor). */ +void ANSITerm::ansi_dsr(int* x_coord, int* y_coord) +{ + char _r; bool reading_x = false; bool reading_y = false; + this->puts("6n"); wait(0.02); + + /* detect presence of symbol "CMSIS_OS_RTX", and switch on thread safety if we spot it (mutexes, thread.wait instead of wait, etc) */ + /* TODO: Make thread-safe at some point. */ + /*Reply format is "\033[<ycoord>;<xcoord>R" */ + *x_coord = 0; *y_coord = 0; + while(this->readable() == 1) + { + _r = this->getc(); + switch(_r) { + case 033: + //ignore, start of DSR + break; + case '[': + //next char starts the y-coordinate + reading_y = true; + break; + default: + //this is probably a numeric: check and, if so, subtract 48 to decode the ASCII to int. + if((_r>47) && (_r<58)) { + if(reading_x == true) { + *x_coord = ((*x_coord)*10) + (_r-48); + } else if(reading_y == true) { + *y_coord = ((*y_coord)*10) + (_r-48); + } + } else { + /* Not a numeric, ignore it.*/ + } + break; + case ';': + //next char starts the x-coordinate + reading_y = false; reading_x = true; + break; + case 'R': + //end of ANSI-DSR reply + return; + } + } +} + +/* Select Graphic Rendition - Make the output bold, underlined, coloured... all manner of things.*/ +void ANSITerm::ansi_sgr(bool reset, char text_style, char text_colour, char background_colour) +{ + bool needs_sep = false; + if(reset) { this->putc('0'); } + else + { + /* text style (select many) */ + // These two are mutually exclusive + if((text_style & SGR_BOLD) == SGR_BOLD) { this->putc('1'); } + else if ((text_style & SGR_FAINT) == SGR_FAINT){ this->putc('2'); } + else{ this->puts("22"); } + this->putc(';'); + + if((text_style & SGR_ITALIC) == SGR_ITALIC) { this->putc('3'); } + else{ this->puts("23"); } + this->putc(';'); + + if((text_style & SGR_UNDERLINE) == SGR_UNDERLINE) { this->putc('4'); } + else{ this->puts("24"); } + this->putc(';'); + + // These two are mutually exclusive + if((text_style & SGR_BLINK_SLOW) == SGR_BLINK_SLOW) { this->putc('5'); } + else if ((text_style & SGR_BLINK_RAPID) == SGR_BLINK_RAPID) { this->putc('6'); } + else{ this->puts("25"); } + this->putc(';'); + + if((text_style & SGR_IMAGE_NEGATIVE) == SGR_IMAGE_NEGATIVE) { this->putc('7'); } + else{ this->puts("27"); } + this->putc(';'); + + if((text_style & SGR_CROSSED_OUT) == SGR_CROSSED_OUT) { this->putc('9'); } + else{ this->puts("29"); } + needs_sep = true; + + /* text colour (select 1) */ + if(text_colour != 0) + { + if(needs_sep) { this->putc(';'); }/* Emit a separator if needed. */ + if ((text_colour & SGR_BLACK) == SGR_BLACK) { this->puts("30"); } + else if((text_colour & SGR_RED) == SGR_RED) { this->puts("31"); } + else if((text_colour & SGR_GREEN) == SGR_GREEN) { this->puts("32"); } + else if((text_colour & SGR_YELLOW) == SGR_YELLOW) { this->puts("33"); } + else if((text_colour & SGR_BLUE) == SGR_BLUE) { this->puts("34"); } + else if((text_colour & SGR_MAGENTA) == SGR_MAGENTA) { this->puts("35"); } + else if((text_colour & SGR_CYAN) == SGR_CYAN) { this->puts("36"); } + else if((text_colour & SGR_WHITE) == SGR_WHITE) { this->puts("37"); } + } + /* background_colour (select 1) */ + if(background_colour != 0) + { + if(needs_sep) { this->putc(';'); needs_sep = false; } + if ((background_colour & SGR_BLACK) == SGR_BLACK) { this->puts("40"); } + else if((background_colour & SGR_RED) == SGR_RED) { this->puts("41"); } + else if((background_colour & SGR_GREEN) == SGR_GREEN) { this->puts("42"); } + else if((background_colour & SGR_YELLOW) == SGR_YELLOW) { this->puts("43"); } + else if((background_colour & SGR_BLUE) == SGR_BLUE) { this->puts("44"); } + else if((background_colour & SGR_MAGENTA) == SGR_MAGENTA) { this->puts("45"); } + else if((background_colour & SGR_CYAN) == SGR_CYAN) { this->puts("46"); } + else if((background_colour & SGR_WHITE) == SGR_WHITE) { this->puts("47"); } + } + } + putc('m'); +} + +/* + Draw a box with the specified top-left and bottom-right points (these are the coords of the box, not its contents!) + Style is an array of chars to use to draw the box, [topleft, topright, bottomleft, bottomright, horiz, vert, uptee, downtee, lefttee, righttee,cross]. + if clear_inner is set, the 'contents' of the box onscreen will be erased. If it's clear, they won't be. + */ +void ANSITerm::draw_box(int x1, int y1, int x2, int y2, const char* style, bool clear_inner) +{ + this->set_cursor_position(x1,y1); + //draw the top row + this->putc(style[0]); for(int i = x1; i<(x2-1);i++) this->putc(style[4]); this->putc(style[1]); + + for(int i=(y1+1); i<(y2);i++) + { + this->set_cursor_position(x1,i); + this->putc(style[5]);//draw the left-hand side of this row + this->set_cursor_position(x2,i); + this->putc(style[5]);//draw the right-hand side of this row + } + + if(clear_inner) + { + for(int i = (y1+1);i<(y2);i++) + { + this->set_cursor_position((x1+1),i); //position at the start of this row + for(int j=x1;j<(x2-1);j++) this->putc(' '); //fill it with spaces + } + } + + this->set_cursor_position(x1,y2); + //draw the bottom row + this->putc(style[2]); for(int i = x1; i<(x2-1);i++) this->putc(style[4]); this->putc(style[3]); +} \ No newline at end of file