CS248 Menu Buttons

UNIX Programming

"Chapter Six - Curses"

Chapter Outline

Lecture Notes

Curses

For many programs a higher-level interface would be desirable. We would like to be able to simply draw on the screen and use a library of functions to take care of terminal dependencies automatically.

We now look at the curses library used to write full screen character-based output.

It's used by the people's pet-hate text editor, vi.

Topics include:

Compiling with curses

Since curses is alibrary, to use it we must include both a header file and functions and macros from an appro[riate system library.

ncurses, an improved alternative to curses is included in Mandrake 8.x Linux.

To compile a program that includes curses, such as screen1.c, in the Next Try It Out section, by typing:

Then to run the program, type:

Concepts

The curses routine work on screens, windows and subwindows.

The curses library maintains two data structures that act like a map of the terminnal screen: stdscr and curscr.

Thus, the process for output of characters in a curses program is:

The layout of the logical screen is a character array, arranged by lines and columns, with the screen positon (0,0) at the top left-hand corner.

Try It Out - A Simple curses Program

1. We add in the curses.h header file and in the main function we make calls to initialize and reset the curses library:

2. Inbetween, move the cursor to (5,15), print 'Hello World', refresh, and suspend of call sleep(2) so you can see the output.

Here is what the output looks like! It is there for only two seconds!

Basic Output Features

Now to look in more detail at the principal curses fetures available for screen display.

Initialization and Termination

All curses programs must start with initscr and end with endwin.

The WINDOW structure is simply the structure that curses uses to store the intended screen display. This structure is opaque, i.e. curses doesn't give access to its internals.

Output

There are severla basic functions provided for updating the screen. These are:

Notice that curses has its own character type, chtype.

The add.. functions add the character or string specified at the current location.

The printw function formats a string and adds it to the current location.

The refresh function causes the physical screen to be updated.

The box function allows you to draw a box around a window.

The insch function inserts a character, moving existing characters right.

The insertln inserts a blank line, moving existing lines down by one.

The two delete are analogous to the two insert functions.

The beep is called to make a sound.

The flash causes the screen to flash.

Reading the Screen

We can read characters from the screen. It's done with the following functions:

Clearing

There are four principal ways of clearing an area of the screen. These are:

Moving

A single function is provided for moving the cursor, with an additional command for controlling where curses leaves the cursor after screen updates:

Attributes

Each curses character can have certain attributes, which control how it's displayed on the screen.

The defined attributes are:

Ypu can use these functions to set attributes singly or collectively.

Try It Out - Moving, Inserting and Attributes

The next program, moveadd.c includes several calls to refresh and sleep.

1. We include the following header files, define some character arrays and a pointer to those arrays and then initialize the curses structure.

2. Now for the three initial sets of text that appear at intervals on the screen. Note the on and off flagging of text attributes.

Lastly, the actors are identified and their names are inserted a character at the time. We also add the reset function at the end of the main function:

When we run this program the final screen looks like this:

The Keyboard

As well as providing an easier interface to controlling the screen, curses also provides an easier method for controlling the keyboard.

Keyboard Modes

The keyboard reading routines are controlled by modes. The functions that set the modes are:

Keyboard Input

Reading the keyboard is very simple. The principal functions are:

Try It Out - Keyboard Modes and Input

Here's a short program, ipmode.c to show how to handle the keyboard.

1. First, we set up the program and the initial curses calls:

2. When the user enters their password, we need to stop the password being echoed to the screen. Then we check the password against xyzzy:

3. Finally, we re-enable the keyboard echo and print out success or failure:

How It Works

The echo of the password is stopped. A region of memory is set up for the password. Each character of the passward is processed immediately and a * is shown at the next position of the screen. strcmp is used to compare the two strings of the real password and the entered password.

Multiple Windows

Using curses we can display multiple windows of different sizes concurrently on the physical screen.

The WINDOW Structure

The stdscr is just a special case of the WINDOW structure.

We can create and destroy windows using the newwin and delwin calls:

Generalized Functions

The addch and printw functions can have prefixes: w for window, mv for move, or mvw for move and window.

As an example, here is the full set of prototypes for just the addch and printw sets of functions:

Moving and Updating a Window

Here are a few simple commands for manipulating windows. These allow us to move and redraw windows:


Try It Out - Multiple Windows

The program, multiw1.c, shows the use of multiple windows.

1. Here are our definitions

2. We fill the base window with characters, refreshing the actual screen once the logical screen has been filled:


3. We create a new 10x20 Window and add some text to it before drawing it on the screen:

4. We change the contents of the background window and, when we refresh the screen, the window pointed to by new_window_ptr is obscured:

5. If we make a call to refresh the new window, nothing wil change, because we haven't changed hte new window.

6. But if we touch the window first and trick curses into thinking that the window has been changed, the next call to wrefresh will bring the new window to the front again.

7. Next, we add another overlapping window with a box around it:

8. then we fiddle with the new and pop-up windows before clearing and deleting them:

Here is a screenshot of part of the output.

Optimizing Screen Refreshes

It is improtant to minimize the number of characters drawn on the screen, since, on slow links, screen draws can be uncomfortably slow.

curses provides a special way of doing this, with a pair of functions: wnoutrefresh and doupdate.

Subwindows

Now we look at a special case of multiple windows called subwindows. We create and destroy subwindows with the calls:

The need to scroll a small subsection of the screen is surprisingly common when writing a curses program. Bu making this a subwindow and then scrolling the subwindow, we achieve the desired result:

Try It Out - Subwindows

Here's a modified version of the previous example, now called subscl.c. It shows a subwindow scrolling independently of the parent window.

1. The initial code section. The base window display is initialized with some text.

2. We now create the new scrolling subwindow and, as asvised, we must 'touch' the parent window before refreshing the screen.

3. Then we erase the contents of the subwindows, print text to it and refresh it. The scrolling text is achieved by a loop:

4. Having finished this loop, we delete the subwindow. Then we refresh the base screen:

Towards the end of the program, we see the output:

How It Works

After arranging for the sub_window_ptr tp point to the result of the subwin call, we make the subwindow scrollable.

The Keyboard

curses provides an elegant facility for managing function keys.

The translation between the sequences of characters send and the logical keys is disabled when curses starts and has to be turned on by the keypad functon.

There are three slight restrictions when using Keypad mode:

Try It Out - Using the Keyboard

Here's a short program, keypad.c, showing how the Keypad mode can be used.

1. HAving initialized the program and the curses library, we set the Keypad mode TRUE:

Next, turn ECHO off, clear the screen, and display some text.


Color

Color is fairly standard and is supported in ncurses.

We define the foreground and background colors of a character as a pair, called, not surprisingly, a color pair.

First check that the current terminal supports color and then initialize the curses color routines.

For this, you use a pair of routines, has_colors and start_color.

Before you can use colors as attributes, you must initialize the color pairs that you wish to use.

You do this with the init_pair function.

Color attributes are accessed with the COLOR_PAIR function.

To define color pair number 1 to be red on green, we would use:

We can then access this color pair as an attribute, using COLOR_PAIR like this:

We can often access screen high intensity colors by combining the COLOR_PAIR attribbute with the additional attribute A_BOLD, by using a bitwise OR of the attributes:

Try It Out - Colors

Let's check these functions in an example, color.c.

1. First, we check whether the program's display terminal supports color. If it does, we start the color display.


2. we can now print out the allowed number of colors and color pairs. We create seven color pairs and display them one a t a time.

This example give the following output:

Redefining Colors

curses supports redefining the colors available with the init_color function.

Advanced Topic: Pads

It's sometimes easier to build a logical screen and then output all or part of it to the physical screen later.

A pad is a special data structure for manipulating logical screen information that doesn't fit within a normal screen.

We create pads in much the same way that we create normal windows:

Pads do have different routines for refreshing. We do this with the prefresh function:

Try It Out -Using a Pad

Let's check these out with a quick program, pad.c.

1. We initialize the pad structure and then create a pad. We add characters to fill the pad structure.

2. We can now draw different areas of the pad on the screen at different locations, before quitting.

Running the program, you should see something like this:

The CD Collection Application

Here we use the curses library for more clearly displaying the information and for scrolling the track listings.

Try It Out - A New CD Collection Application

1. First, we include all those header files and then some global constants:

2. Next, we need some global variables.

3. Some file names are now declared. These files are fixed in this version to keep it simple.


4. Now, finally, we get onto the function prototypes:


5. We need some structures for the menus.

That's the initialization done with.

now for the sixteen program functions. The split into functions to:


Try It Out- Looking at main

main allows us to make selections form the menu until we select quit:

Try It Out - The Menu

1. The getchoice function called by main is the principal function in this section.


2. Note how there are two more local functions called from within getchoice: clear_all_screen and draw_menu. We'll look at draw_menu first:

And clear_all_screen clears the screen and rewrites the title. If a CD is selected, its information is displayed.


Try It Out - Database File Manipulation

Now we look at the functions which add to or delete the CD database.

1. How do we add a new CD record to the database?


2. Let's look at get_string. This function prompts for and reads in a string at the current screen position. It also deletes any trailing newline.

3. get_confirm prompts and reads user confirmation.

4. Lastly, we look at insert_title. This adds a title to the CD database by appending the title string to the end of the titles file.

5. The update_cd function uses a scrolling, boxed subwindow and needs some constants, which we define globally, because they will be needed later for the list_tracks function. These are:

update_cd allows the user to re-enter the tracks for the current CD.

We enter information in a scrolling, boxed window by setting up a subwindow, draaw a box around the edge, then add a new, scrolling, subwindow just inside the boxed subwindow.

6. The last function called from main is remove_cd:


7. We now need only list remove_tracks, the function which deletes the tracks from the current CD. It's called by both update_cd and remove_cd.

Try It Out - Querying the CD Database

1. First youu want to know what CDs your have. Next you want to know about the tracks on each CD.

2. You forget the tracks on your favorite CD. You can get a track listing using find_cd. It prompts for a substring to match in the database and sets tthe global variable current_cd to the CD title found.


3. Lastly we need to be able to list the selected CD's tracks on the screen. We make use of the #defines for the subwindows used in update_cd in the last section:



4. The last two functions call get_return, which prompts for and reads a carriage return.

If you run this program, you should see something like:

Summary

This chapter explored the curses library, which provides a good way for text-based programs to control the screen and read the keyboard.


CS 248 - UNIX Programming Web Site Menu
Information | Syllabus | Schedule | Online "Lectures" | Projects | Quizzes | Web Board



Copyright © 2001 by James L. Fuller, all rights reserved.