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
ANSITerm.h
- Committer:
- dansummers
- Date:
- 2012-09-18
- Revision:
- 0:863811463610
- Child:
- 1:e3403c93f864
File content as of revision 0:863811463610:
/** * @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