ncurses¶
Introducing ncurses¶
ncurses is a library for interfacing with a computer terminal like the terminal emulator we have been using in class.
Here is a “Hello Curses!” program in a file named hello_curses.cpp:
#include <ncurses.h>
using namespace std;
int main() {
initscr();
move(11, 26);
printw("Hello CSC 222 from ncurses!");
refresh();
getch();
endwin();
return 0;
}
Notice that we are not including iostream, but are instead including
ncurses.h. This is because we are using ncurses for our user interface
instead of the standard input / output command line.
To compile this program we will need to link it to the ncurses library:
$ g++ hello_curses.cpp -o hello_curses -lncurses
The program calls initscr to create a screen, move to move the
curser to row 11 and column 26, printw to print the string
"Hello CSC 222 from ncurses!" beginning at the curser location onto the
screen, refresh to draw the screen to the terminal, getch to read a
character of user input, and endwin to close the screen.
We are using getch in this first example just to pause the screen to
allow for viewing. In our next example, read_chars.cpp, we will use it to
read the character entered and do something “useful” with it:
#include <ncurses.h>
using namespace std;
int main() {
char ch;
initscr();
noecho();
move(9, 25);
printw("Enter a character or '!' to quit: ");
refresh();
ch = getch();
while (ch != '!') {
clear();
mvprintw(9, 25, "Enter a character or '!' to quit: ");
mvprintw(
12, 18,
"You entered '%c', which has a numeric value of %d.",
ch, ch
);
move(9, 59);
refresh();
ch = getch();
}
endwin();
return 0;
}
The noecho function is called to turn off echoing of keyboard input. After
prompting the user to enter a character or '!' to quit, we enter a loop
which calls clear to erase everything in the screen. We then call
mvprintw, which combines move and printw into a single function, to
redraw the prompt that was just erased.
Another call to mvprintw displays the character typed along with its
numeric value. The move(9, 59) on the next line is used only for cosmetic
reasons. It looks nicer to have the cursor appear at the end of the prompt.
Finally refresh draws the screen and ch = getch() waits for the user
to enter another character.
Exploring the window environment¶
This next example, interrogate_env.cpp, uses several of the available
ncurses functions to get information about the window environment:
#include <ncurses.h>
#define COLOR_ORANGE 8
using namespace std;
int main() {
int rows, cols;
initscr();
noecho();
refresh();
WINDOW* win1 = newwin(5, 76, 1, 2);
WINDOW* win2 = newwin(15, 46, 6, 18);
wattron(win1, A_STANDOUT);
wmove(win1, 2, 22);
wprintw(win1, "ncurses");
wattroff(win1, A_STANDOUT);
wprintw(win1, " Environment Interrogator");
box(win1, 0, 0);
wrefresh(win1);
const char* colors = has_colors() ? "YES" : "NO";
wmove(win2, 2, 5);
wprintw(win2, "Supports color: ");
if (colors == "YES") {
start_color();
init_pair(1, COLOR_CYAN, COLOR_BLACK);
wattron(win2, COLOR_PAIR(1));
};
wprintw(win2, colors);
if (colors == "YES") {
wattroff(win2, COLOR_PAIR(1));
};
const char* change_color = can_change_color() ? "YES" : "NO";
wmove(win2, 4, 5);
wprintw(win2, "Supports change color: ");
if (change_color == "YES") {
init_color(COLOR_ORANGE, 1000, 500, 0);
init_pair(2, COLOR_ORANGE, COLOR_BLACK);
wattron(win2, COLOR_PAIR(2));
};
wprintw(win2, change_color);
if (change_color == "YES") {
wattroff(win2, COLOR_PAIR(2));
};
wmove(win2, 6, 5);
getmaxyx(stdscr, rows, cols);
wprintw(win2, "Main window size: %d by %d", rows, cols);
wmove(win2, 8, 5);
getmaxyx(win2, rows, cols);
wprintw(win2, "Current window size: %d by %d", rows, cols);
wmove(win2, 10, 5);
getmaxyx(win1, rows, cols);
wprintw(win2, "Top window size: %d by %d", rows, cols);
wmove(win2, 12, 5);
getbegyx(win2, rows, cols);
wprintw(win2, "Current window top left pos: %d, %d", rows, cols);
box(win2, 0, 0);
wrefresh(win2);
move(22, 25);
printw("Enter a character quit: ");
getch();
endwin();
return 0;
}
Running this will on a terminal that supports colors and color changes will produce a screen something like this: