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.h
- Revision:
- 0:863811463610
- Child:
- 1:e3403c93f864
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ANSITerm.h Tue Sep 18 18:58:19 2012 +0000 @@ -0,0 +1,334 @@ +/** + * @file ANSITerm.h + * @author Dan Summers [ https://mbed.org/users/dansummers ] + * @date 20120918 + */ +/* +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. + */ + +#ifndef _ANSITERM_ +#define _ANSITERM_ + +#define _ANSITERM_CP850_ /* Use CodePage 850 for box-drawing. */ + +#include "mbed.h" + +/** ANSI Terminal control library, inheriting from Serial. + * + * ANSITerm encapsulates a large portion of the ANSI escape sequence set, + * so that a user unfamiliar with the escape sequences can manipulate the + * terminal. It also provides a tidy point of abstraction, should it be + * necessary to support multiple different escape sets in the future. + * + * ANSITerm assumes that the terminal being manipulated implements the + * ANSI-standard escapes. The terminal is divided into cells, each one + * the size of a character (a typical "default" terminal will have 25 rows of + * cells, each with 80 character cells in it, but this will change if the + * terminal is resized.) + * + * The box-drawing functions currently assume that the terminal is using + * CodePage 850 to interpret received characters. It is untested under + * UNIX and MacOS (fixing this is on the TODO list). + * + * Example: + * @code + * terminal.clear_screen(); + * terminal.hide_cursor(); + * terminal.set_display_style(ANSITerm::SGR_NONE); + * terminal.set_text_colour(ANSITerm::SGR_RED); + * terminal.draw_box(3,3,19,5,ANSITerm::simple,false); + * terminal.set_text_colour(ANSITerm::SGR_WHITE); + * terminal.set_display_style(ANSITerm::SGR_BOLD); + * terminal.set_cursor_position(5,4); + * terminal.printf("ANSI Terminal"); + * @endcode + */ +class ANSITerm : public Serial +{ + public: + /* Internal buffer for the SGR style flagset currently in use. */ + char current_style; + + /** SGR "flag" indicating the default text style. */ + const static char SGR_NONE = 0; + + /** SGR flag to request bold text. */ + const static char SGR_BOLD = 1; + + /** SGR flag to request faint text. */ + const static char SGR_FAINT = 2; + + /** SGR flag to request italic text. */ + const static char SGR_ITALIC = 4; + + /** SGR flag to request underlined text. */ + const static char SGR_UNDERLINE = 8; + + /** SGR flag to request slow-blinking text (not always supported). */ + const static char SGR_BLINK_SLOW = 16; + + /** SGR flag to request fast-flashing text (not always supported). */ + const static char SGR_BLINK_RAPID = 32; + + /** SGR flag to request inverse-video. */ + const static char SGR_IMAGE_NEGATIVE = 64; /* Switch on inverse video */ + + /** SGR flag to request struck-through text (not commonly supported).*/ + const static char SGR_CROSSED_OUT = 128; + + /* SGR colours */ + /** SGR colour indicator for ANSI Black.*/ + const static char SGR_BLACK = 1; //30 + + /** SGR colour indicator for ANSI Red.*/ + const static char SGR_RED = 2; //31 + + /** SGR colour indicator for ANSI Green.*/ + const static char SGR_GREEN = 4; //32 + + /** SGR colour indicator for ANSI Yellow.*/ + const static char SGR_YELLOW = 8; //33 + + /** SGR colour indicator for ANSI Blue.*/ + const static char SGR_BLUE = 16; //34 + + /** SGR colour indicator for ANSI Magenta.*/ + const static char SGR_MAGENTA = 32; //35 + + /** SGR colour indicator for ANSI Cyan.*/ + const static char SGR_CYAN = 64; //36 + + /** SGR colour indicator for ANSI White.*/ + const static char SGR_WHITE = 128; //37 + + /* Box styles */ +#ifdef _ANSITERM_CP850_ + /** Box-drawing style using ASCII two-line box-drawing characters. */ + static const char two_lines[11]; + + /** Box-drawing style using ASCII one-line box-drawing characters. */ + static const char one_line[11]; + + /** Box-drawing style using pluses, minuses and pipes (low-ASCII, should work anywhere).*/ + static const char simple[11]; +#endif + + ANSITerm(PinName tx, PinName rx); + + /* Emit a Control Sequence Initiator (which is the header for an ANSI escape sequence). */ + inline void ansi_csi() { this->putc(0x1B); this->putc('['); } + /* Cursor Up by n rows. */ + inline void ansi_cuu(int n) { this->printf("%dA", n); } + /* Cursor Down by n rows. */ + inline void ansi_cud(int n) { this->printf("%dB", n); } + /* Cursor Forward by n columns. */ + inline void ansi_cuf(int n) { this->printf("%dC", n); } + /* Cursor Back by n columns. */ + inline void ansi_cub(int n) { this->printf("%dD", n); } + /* Cursor Next Line (moves the cursor to the start of the line n lines down). */ + inline void ansi_cnl(int n) { this->printf("%dE", n); } + /* Cursor Previous Line (moves the cursor to the start of the line n lines up). */ + inline void ansi_cpl(int n) { this->printf("%dF", n); } + /* Cursor Horizontal Absolute (moves the cursor to column n). */ + inline void ansi_cha(int n) { this->printf("%dG", n); } + /* Cursor Position (positions the cursor at column x, row y, on a 1-based grid starting top-left). */ + inline void ansi_cup(int x, int y) { this->printf("%d;%dH", y, x); } + /* Erase Data (0 = from cursor to end of screen, 1 = from cursor to beginning of screen, 2 = entire screen) */ + inline void ansi_ed(int n) { this->printf("%dJ", n); } + /* Erase in Line (0 = from cursor to end of screen, 1 = from cursor to beginning of screen, 2 = entire screen) */ + inline void ansi_el(int n) { this->printf("%dK", n); } + /* Scroll Up by n lines. */ + inline void ansi_su(int n) { this->printf("%dS", n); } + /* Scroll Down by n lines. */ + inline void ansi_sd(int n) { this->printf("%dT", n); } + /* Horizontal and Vertical Position (positions the cursor at column x, row y, on a 1-based grid starting top-left). */ + inline void ansi_hvp(int y, int x) { this->printf("%d;%dH", y, x); } + /* Save Cursor Position */ + inline void ansi_scp() { this->putc('s'); } + /* Restore Cursor Position */ + inline void ansi_rcp() { this->putc('u'); } + /*DEC Terminal Cursor Enable Mode - hide cursor */ + inline void ansi_dectcem_hide() { this->printf("?25l"); } + /*DEC Terminal Cursor Enable Mode - show cursor */ + inline void ansi_dectcem_show() { this->printf("?25h"); } + + /* Select Graphic Rendition - Make the output bold, underlined, coloured... all manner of things.*/ + /* + reset = 1 to reset to defaults. 0 to read and apply the rest of the inputs. + text_style is an OR of SGR_{BOLD,FAINT,ITALIC,UNDERLINE,BLINK_SLOW,BLINK_RAPID,IMAGE_NEGATIVE,CROSSED_OUT} + text_colour is one of SGR_{BLACK,RED,GREEN,YELLOW,BLUE,MAGENTA,CYAN,WHITE} + background_colour is one of SGR_{BLACK,RED,GREEN,YELLOW,BLUE,MAGENTA,CYAN,WHITE} + */ + void ansi_sgr(bool reset, char text_style, char text_colour, char background_colour); + + /* Device Status Report (Returns CSIn;mR, where n,m is the coordinates of the cursor). */ + void ansi_dsr(int* x_coord, int* y_coord); + + /** Position the cursor at the requested coordinates, relative to the terminal frame. + * Coordinates are calculated from the top left of the frame, using character + * cells as the unit, and start at an origin of (1,1). + * @param x_coord the x-coordinate (column number) in which to place the cursor, starting at 1. + * @param y_coord the y coordinate (row number) in which to place the cursor, starting at 1. + */ + inline void set_cursor_position(int x_coord, int y_coord) + { + this->ansi_csi(); + this->ansi_cup(x_coord, y_coord); + } + + /** Get the current position of the cursor, relative to the terminal frame. + * Coordinates are calculated from the top left of the frame, using character + * cells as the unit, and start at an origin of (1,1). + * @param x_coord A pointer into which the current x-coordinate of the cursor should be written. + * @param y_coord A pointer into which the current y-coordinate of the cursor should be written. + */ + inline void get_cursor_position(int* x_coord, int* y_coord) + { + this->ansi_csi(); + this->ansi_dsr(x_coord, y_coord); + } + + /** Blank all cells on the screen. + */ + inline void clear_screen() + { + this->ansi_csi(); + this->ansi_ed(2); + } + + /** Draw a box with these top-left and bottom-right points. Various styling options exist. + * @param x1 The x-coordinate of the top-left point. + * @param y1 The y-coordinate of the top-left point. + * @param x2 The x-coordinate of the bottom-right point. + * @param style The style of box-drawing to use (an 11-cell array of glyphs to use: three sets are defined above). + * The styles are stored as arrays of eleven glyphs, with the following descriptive names: + * [0]top-left corner, [1]top-right corner, [2]bottom-left corner, [3]bottom-right corner, + * [4]horizontal bar, [5]vertical bar, + * [6]upward-pointing tee, [7]downward-pointing tee, [8]left-pointing tee, [9]right-pointing tee, + * [10]cross + * @param clear_inner If true, the space contained within the box will be overwritten with space characters. If not, it will be unmodified. + */ + void draw_box(int x1, int y1, int x2, int y2, const char* style, bool clear_inner); + + /** Draw a box containing these top-left and bottom-right points. Various styling options exist. + * @param x1 The x-coordinate of the top-left point. + * @param y1 The y-coordinate of the top-left point. + * @param x2 The x-coordinate of the bottom-right point. + * @param style The style of box-drawing to use (an 11-cell array of glyphs to use: three sets are defined above). + * The styles are stored as arrays of eleven glyphs, with the following descriptive names: + * [0]top-left corner, [1]top-right corner, [2]bottom-left corner, [3]bottom-right corner, + * [4]horizontal bar, [5]vertical bar, + * [6]upward-pointing tee, [7]downward-pointing tee, [8]left-pointing tee, [9]right-pointing tee, + * [10]cross + * @param clear_inner If true, the space contained within the box will be overwritten with space characters. If not, it will be unmodified. + * + * draw_enclosing_box differs from draw_box because it draws around a space + * rather than inscribing it. If draw_box and draw_enclosing_box are given + * the same parameters, they will draw concentric boxes and the box from + * draw_box will be two cells smaller in both dimensions. + */ + inline void draw_enclosing_box(int x1, int y1, int x2, int y2, const char* style, bool clear_inner) + { + draw_box((x1-1), (y1-1), (x2+1), (y2+1), style, clear_inner); + } + + /** Set the SGR display style for subsequent characters. + * @param style A flagset ORred together from the SGR parameters above. + * Flags that are set in the flagset will be turned on, + * flags that are clear will be turned off. + * + * Example: + * @code + * terminal.printf("Some text."); + * terminal.set_display_style(SGR_BOLD|SGR_UNDERLINE); + * terminal.printf("Some very important text!"); + * terminal.set_display_style(SGR_NONE); + * terminal.printf("Some more normal text."); + * @endcode + */ + inline void set_display_style(char style) + { + this->current_style = style; + this->ansi_csi(); + this->ansi_sgr(false, style, 0, 0); + } + + /** Set the colour of subsequent characters. + * @param sgr_colour One of the SGR Colours defined above (Black, Red, Green, Yellow, Blue, Magenta, Cyan, White). + * + * Example: + * @code + * terminal.printf("Some text in the default terminal colour."); + * terminal.set_display_text_colour(SGR_RED); + * terminal.printf("Some text in red.); + * @endcode + */ + inline void set_text_colour(char sgr_colour) + { + this->ansi_csi(); + this->ansi_sgr(false, this->current_style, sgr_colour, 0); + } + + /** Set the background colour for subsequent characters. + * @param sgr_colour One of the SGR Colours defined above (Black, Red, Green, Yellow, Blue, Magenta, Cyan, White). + * + * Example: + * @code + * terminal.printf("Some text in the default terminal colour."); + * terminal.set_display_background_colour(SGR_RED); + * terminal.printf("Some text on a red background.); + * @endcode + */ + inline void set_background_colour(char sgr_colour) + { + this->ansi_csi(); + this->ansi_sgr(false, this->current_style, 0, sgr_colour); + } + + /** Tell the terminal not to display the cursor. + */ + inline void hide_cursor() + { + this->ansi_csi(); + this->ansi_dectcem_hide(); + } + + /** Tell the terminal to display the cursor. + */ + inline void show_cursor() + { + this->ansi_csi(); + this->ansi_dectcem_show(); + } + + /** Reset the display to its default parameters (clearing all text styling and colour settings). + */ + inline void set_display_to_defaults() + { + this->ansi_csi(); + this->ansi_sgr(true, 0, 0, 0); + } + +}; + + +#endif \ No newline at end of file