diff options
Diffstat (limited to 'contrib/ncurses/doc/ncurses-intro.doc')
-rw-r--r-- | contrib/ncurses/doc/ncurses-intro.doc | 2502 |
1 files changed, 2502 insertions, 0 deletions
diff --git a/contrib/ncurses/doc/ncurses-intro.doc b/contrib/ncurses/doc/ncurses-intro.doc new file mode 100644 index 0000000..669b0b3 --- /dev/null +++ b/contrib/ncurses/doc/ncurses-intro.doc @@ -0,0 +1,2502 @@ + + Writing Programs with NCURSES + + by Eric S. Raymond and Zeyd M. Ben-Halim + updates since release 1.9.9e by Thomas Dickey + + Contents + + * Introduction + + A Brief History of Curses + + Scope of This Document + + Terminology + * The Curses Library + + An Overview of Curses + o Compiling Programs using Curses + o Updating the Screen + o Standard Windows and Function Naming Conventions + o Variables + + Using the Library + o Starting up + o Output + o Input + o Using Forms Characters + o Character Attributes and Color + o Mouse Interfacing + o Finishing Up + + Function Descriptions + o Initialization and Wrapup + o Causing Output to the Terminal + o Low-Level Capability Access + o Debugging + + Hints, Tips, and Tricks + o Some Notes of Caution + o Temporarily Leaving ncurses Mode + o Using ncurses under xterm + o Handling Multiple Terminal Screens + o Testing for Terminal Capabilities + o Tuning for Speed + o Special Features of ncurses + + Compatibility with Older Versions + o Refresh of Overlapping Windows + o Background Erase + + XSI Curses Conformance + * The Panels Library + + Compiling With the Panels Library + + Overview of Panels + + Panels, Input, and the Standard Screen + + Hiding Panels + + Miscellaneous Other Facilities + * The Menu Library + + Compiling with the menu Library + + Overview of Menus + + Selecting items + + Menu Display + + Menu Windows + + Processing Menu Input + + Miscellaneous Other Features + * The Forms Library + + Compiling with the forms Library + + Overview of Forms + + Creating and Freeing Fields and Forms + + Fetching and Changing Field Attributes + o Fetching Size and Location Data + o Changing the Field Location + o The Justification Attribute + o Field Display Attributes + o Field Option Bits + o Field Status + o Field User Pointer + + Variable-Sized Fields + + Field Validation + o TYPE_ALPHA + o TYPE_ALNUM + o TYPE_ENUM + o TYPE_INTEGER + o TYPE_NUMERIC + o TYPE_REGEXP + + Direct Field Buffer Manipulation + + Attributes of Forms + + Control of Form Display + + Input Processing in the Forms Driver + o Page Navigation Requests + o Inter-Field Navigation Requests + o Intra-Field Navigation Requests + o Scrolling Requests + o Field Editing Requests + o Order Requests + o Application Commands + + Field Change Hooks + + Field Change Commands + + Form Options + + Custom Validation Types + o Union Types + o New Field Types + o Validation Function Arguments + o Order Functions For Custom Types + o Avoiding Problems + _________________________________________________________________ + + Introduction + + This document is an introduction to programming with curses. It is not + an exhaustive reference for the curses Application Programming + Interface (API); that role is filled by the curses manual pages. + Rather, it is intended to help C programmers ease into using the + package. + + This document is aimed at C applications programmers not yet + specifically familiar with ncurses. If you are already an experienced + curses programmer, you should nevertheless read the sections on Mouse + Interfacing, Debugging, Compatibility with Older Versions, and Hints, + Tips, and Tricks. These will bring you up to speed on the special + features and quirks of the ncurses implementation. If you are not so + experienced, keep reading. + + The curses package is a subroutine library for terminal-independent + screen-painting and input-event handling which presents a high level + screen model to the programmer, hiding differences between terminal + types and doing automatic optimization of output to change one screen + full of text into another. Curses uses terminfo, which is a database + format that can describe the capabilities of thousands of different + terminals. + + The curses API may seem something of an archaism on UNIX desktops + increasingly dominated by X, Motif, and Tcl/Tk. Nevertheless, UNIX + still supports tty lines and X supports xterm(1); the curses API has + the advantage of (a) back-portability to character-cell terminals, and + (b) simplicity. For an application that does not require bit-mapped + graphics and multiple fonts, an interface implementation using curses + will typically be a great deal simpler and less expensive than one + using an X toolkit. + +A Brief History of Curses + + Historically, the first ancestor of curses was the routines written to + provide screen-handling for the game rogue; these used the + already-existing termcap database facility for describing terminal + capabilities. These routines were abstracted into a documented library + and first released with the early BSD UNIX versions. + + System III UNIX from Bell Labs featured a rewritten and much-improved + curses library. It introduced the terminfo format. Terminfo is based + on Berkeley's termcap database, but contains a number of improvements + and extensions. Parameterized capabilities strings were introduced, + making it possible to describe multiple video attributes, and colors + and to handle far more unusual terminals than possible with termcap. + In the later AT&T System V releases, curses evolved to use more + facilities and offer more capabilities, going far beyond BSD curses in + power and flexibility. + +Scope of This Document + + This document describes ncurses, a free implementation of the System V + curses API with some clearly marked extensions. It includes the + following System V curses features: + * Support for multiple screen highlights (BSD curses could only + handle one `standout' highlight, usually reverse-video). + * Support for line- and box-drawing using forms characters. + * Recognition of function keys on input. + * Color support. + * Support for pads (windows of larger than screen size on which the + screen or a subwindow defines a viewport). + + Also, this package makes use of the insert and delete line and + character features of terminals so equipped, and determines how to + optimally use these features with no help from the programmer. It + allows arbitrary combinations of video attributes to be displayed, + even on terminals that leave ``magic cookies'' on the screen to mark + changes in attributes. + + The ncurses package can also capture and use event reports from a + mouse in some environments (notably, xterm under the X window system). + This document includes tips for using the mouse. + + The ncurses package was originated by Pavel Curtis. The original + maintainer of this package is Zeyd Ben-Halim <zmbenhal@netcom.com>. + Eric S. Raymond <esr@snark.thyrsus.com> wrote many of the new features + in versions after 1.8.1 and wrote most of this introduction. Jürgen + Pfeifer wrote all of the menu and forms code as well as the Ada95 + binding. Ongoing work is being done by Thomas Dickey and Jürgen + Pfeifer. Florian La Roche acts as the maintainer for the Free Software + Foundation, which holds the copyright on ncurses. Contact the current + maintainers at bug-ncurses@gnu.org. + + This document also describes the panels extension library, similarly + modeled on the SVr4 panels facility. This library allows you to + associate backing store with each of a stack or deck of overlapping + windows, and provides operations for moving windows around in the + stack that change their visibility in the natural way (handling window + overlaps). + + Finally, this document describes in detail the menus and forms + extension libraries, also cloned from System V, which support easy + construction and sequences of menus and fill-in forms. + +Terminology + + In this document, the following terminology is used with reasonable + consistency: + + window + A data structure describing a sub-rectangle of the screen + (possibly the entire screen). You can write to a window as + though it were a miniature screen, scrolling independently of + other windows on the physical screen. + + screens + A subset of windows which are as large as the terminal screen, + i.e., they start at the upper left hand corner and encompass + the lower right hand corner. One of these, stdscr, is + automatically provided for the programmer. + + terminal screen + The package's idea of what the terminal display currently looks + like, i.e., what the user sees now. This is a special screen. + + The Curses Library + +An Overview of Curses + + Compiling Programs using Curses + + In order to use the library, it is necessary to have certain types and + variables defined. Therefore, the programmer must have a line: + #include <curses.h> + + at the top of the program source. The screen package uses the Standard + I/O library, so <curses.h> includes <stdio.h>. <curses.h> also + includes <termios.h>, <termio.h>, or <sgtty.h> depending on your + system. It is redundant (but harmless) for the programmer to do these + includes, too. In linking with curses you need to have -lncurses in + your LDFLAGS or on the command line. There is no need for any other + libraries. + + Updating the Screen + + In order to update the screen optimally, it is necessary for the + routines to know what the screen currently looks like and what the + programmer wants it to look like next. For this purpose, a data type + (structure) named WINDOW is defined which describes a window image to + the routines, including its starting position on the screen (the (y, + x) coordinates of the upper left hand corner) and its size. One of + these (called curscr, for current screen) is a screen image of what + the terminal currently looks like. Another screen (called stdscr, for + standard screen) is provided by default to make changes on. + + A window is a purely internal representation. It is used to build and + store a potential image of a portion of the terminal. It doesn't bear + any necessary relation to what is really on the terminal screen; it's + more like a scratchpad or write buffer. + + To make the section of physical screen corresponding to a window + reflect the contents of the window structure, the routine refresh() + (or wrefresh() if the window is not stdscr) is called. + + A given physical screen section may be within the scope of any number + of overlapping windows. Also, changes can be made to windows in any + order, without regard to motion efficiency. Then, at will, the + programmer can effectively say ``make it look like this,'' and let the + package implementation determine the most efficient way to repaint the + screen. + + Standard Windows and Function Naming Conventions + + As hinted above, the routines can use several windows, but two are + automatically given: curscr, which knows what the terminal looks like, + and stdscr, which is what the programmer wants the terminal to look + like next. The user should never actually access curscr directly. + Changes should be made to through the API, and then the routine + refresh() (or wrefresh()) called. + + Many functions are defined to use stdscr as a default screen. For + example, to add a character to stdscr, one calls addch() with the + desired character as argument. To write to a different window. use the + routine waddch() (for `w'indow-specific addch()) is provided. This + convention of prepending function names with a `w' when they are to be + applied to specific windows is consistent. The only routines which do + not follow it are those for which a window must always be specified. + + In order to move the current (y, x) coordinates from one point to + another, the routines move() and wmove() are provided. However, it is + often desirable to first move and then perform some I/O operation. In + order to avoid clumsiness, most I/O routines can be preceded by the + prefix 'mv' and the desired (y, x) coordinates prepended to the + arguments to the function. For example, the calls + move(y, x); + addch(ch); + + can be replaced by + mvaddch(y, x, ch); + + and + wmove(win, y, x); + waddch(win, ch); + + can be replaced by + mvwaddch(win, y, x, ch); + + Note that the window description pointer (win) comes before the added + (y, x) coordinates. If a function requires a window pointer, it is + always the first parameter passed. + + Variables + + The curses library sets some variables describing the terminal + capabilities. + type name description + ------------------------------------------------------------------ + int LINES number of lines on the terminal + int COLS number of columns on the terminal + + The curses.h also introduces some #define constants and types of + general usefulness: + + bool + boolean type, actually a `char' (e.g., bool doneit;) + + TRUE + boolean `true' flag (1). + + FALSE + boolean `false' flag (0). + + ERR + error flag returned by routines on a failure (-1). + + OK + error flag returned by routines when things go right. + +Using the Library + + Now we describe how to actually use the screen package. In it, we + assume all updating, reading, etc. is applied to stdscr. These + instructions will work on any window, providing you change the + function names and parameters as mentioned above. + + Here is a sample program to motivate the discussion: +#include <curses.h> +#include <signal.h> + +static void finish(int sig); + +int +main(int argc, char *argv[]) +{ + int num = 0; + + /* initialize your non-curses data structures here */ + + (void) signal(SIGINT, finish); /* arrange interrupts to terminate */ + + (void) initscr(); /* initialize the curses library */ + keypad(stdscr, TRUE); /* enable keyboard mapping */ + (void) nonl(); /* tell curses not to do NL->CR/NL on output */ + (void) cbreak(); /* take input chars one at a time, no wait for \n */ + (void) echo(); /* echo input - in color */ + + if (has_colors()) + { + start_color(); + + /* + * Simple color assignment, often all we need. Color pair 0 cannot + * be redefined. This example uses the same value for the color + * pair as for the foreground color, though of course that is not + * necessary: + */ + init_pair(1, COLOR_RED, COLOR_BLACK); + init_pair(2, COLOR_GREEN, COLOR_BLACK); + init_pair(3, COLOR_YELLOW, COLOR_BLACK); + init_pair(4, COLOR_BLUE, COLOR_BLACK); + init_pair(5, COLOR_CYAN, COLOR_BLACK); + init_pair(6, COLOR_MAGENTA, COLOR_BLACK); + init_pair(7, COLOR_WHITE, COLOR_BLACK); + } + + for (;;) + { + int c = getch(); /* refresh, accept single keystroke of input */ + attrset(COLOR_PAIR(num % 8)); + num++; + + /* process the command keystroke */ + } + + finish(0); /* we're done */ +} + +static void finish(int sig) +{ + endwin(); + + /* do your non-curses wrapup here */ + + exit(0); +} + + Starting up + + In order to use the screen package, the routines must know about + terminal characteristics, and the space for curscr and stdscr must be + allocated. These function initscr() does both these things. Since it + must allocate space for the windows, it can overflow memory when + attempting to do so. On the rare occasions this happens, initscr() + will terminate the program with an error message. initscr() must + always be called before any of the routines which affect windows are + used. If it is not, the program will core dump as soon as either + curscr or stdscr are referenced. However, it is usually best to wait + to call it until after you are sure you will need it, like after + checking for startup errors. Terminal status changing routines like + nl() and cbreak() should be called after initscr(). + + Once the screen windows have been allocated, you can set them up for + your program. If you want to, say, allow a screen to scroll, use + scrollok(). If you want the cursor to be left in place after the last + change, use leaveok(). If this isn't done, refresh() will move the + cursor to the window's current (y, x) coordinates after updating it. + + You can create new windows of your own using the functions newwin(), + derwin(), and subwin(). The routine delwin() will allow you to get rid + of old windows. All the options described above can be applied to any + window. + + Output + + Now that we have set things up, we will want to actually update the + terminal. The basic functions used to change what will go on a window + are addch() and move(). addch() adds a character at the current (y, x) + coordinates. move() changes the current (y, x) coordinates to whatever + you want them to be. It returns ERR if you try to move off the window. + As mentioned above, you can combine the two into mvaddch() to do both + things at once. + + The other output functions, such as addstr() and printw(), all call + addch() to add characters to the window. + + After you have put on the window what you want there, when you want + the portion of the terminal covered by the window to be made to look + like it, you must call refresh(). In order to optimize finding + changes, refresh() assumes that any part of the window not changed + since the last refresh() of that window has not been changed on the + terminal, i.e., that you have not refreshed a portion of the terminal + with an overlapping window. If this is not the case, the routine + touchwin() is provided to make it look like the entire window has been + changed, thus making refresh() check the whole subsection of the + terminal for changes. + + If you call wrefresh() with curscr as its argument, it will make the + screen look like curscr thinks it looks like. This is useful for + implementing a command which would redraw the screen in case it get + messed up. + + Input + + The complementary function to addch() is getch() which, if echo is + set, will call addch() to echo the character. Since the screen package + needs to know what is on the terminal at all times, if characters are + to be echoed, the tty must be in raw or cbreak mode. Since initially + the terminal has echoing enabled and is in ordinary ``cooked'' mode, + one or the other has to changed before calling getch(); otherwise, the + program's output will be unpredictable. + + When you need to accept line-oriented input in a window, the functions + wgetstr() and friends are available. There is even a wscanw() function + that can do scanf()(3)-style multi-field parsing on window input. + These pseudo-line-oriented functions turn on echoing while they + execute. + + The example code above uses the call keypad(stdscr, TRUE) to enable + support for function-key mapping. With this feature, the getch() code + watches the input stream for character sequences that correspond to + arrow and function keys. These sequences are returned as + pseudo-character values. The #define values returned are listed in the + curses.h The mapping from sequences to #define values is determined by + key_ capabilities in the terminal's terminfo entry. + + Using Forms Characters + + The addch() function (and some others, including box() and border()) + can accept some pseudo-character arguments which are specially defined + by ncurses. These are #define values set up in the curses.h header; + see there for a complete list (look for the prefix ACS_). + + The most useful of the ACS defines are the forms-drawing characters. + You can use these to draw boxes and simple graphs on the screen. If + the terminal does not have such characters, curses.h will map them to + a recognizable (though ugly) set of ASCII defaults. + + Character Attributes and Color + + The ncurses package supports screen highlights including standout, + reverse-video, underline, and blink. It also supports color, which is + treated as another kind of highlight. + + Highlights are encoded, internally, as high bits of the + pseudo-character type (chtype) that curses.h uses to represent the + contents of a screen cell. See the curses.h header file for a complete + list of highlight mask values (look for the prefix A_). + + There are two ways to make highlights. One is to logical-or the value + of the highlights you want into the character argument of an addch() + call, or any other output call that takes a chtype argument. + + The other is to set the current-highlight value. This is logical-or'ed + with any highlight you specify the first way. You do this with the + functions attron(), attroff(), and attrset(); see the manual pages for + details. Color is a special kind of highlight. The package actually + thinks in terms of color pairs, combinations of foreground and + background colors. The sample code above sets up eight color pairs, + all of the guaranteed-available colors on black. Note that each color + pair is, in effect, given the name of its foreground color. Any other + range of eight non-conflicting values could have been used as the + first arguments of the init_pair() values. + + Once you've done an init_pair() that creates color-pair N, you can use + COLOR_PAIR(N) as a highlight that invokes that particular color + combination. Note that COLOR_PAIR(N), for constant N, is itself a + compile-time constant and can be used in initializers. + + Mouse Interfacing + + The ncurses library also provides a mouse interface. + + NOTE: this facility is specific to ncurses, it is not part of + either the XSI Curses standard, nor of System V Release 4, nor BSD + curses. System V Release 4 curses contains code with similar + interface definitions, however it is not documented. Other than by + disassembling the library, we have no way to determine exactly how + that mouse code works. Thus, we recommend that you wrap + mouse-related code in an #ifdef using the feature macro + NCURSES_MOUSE_VERSION so it will not be compiled and linked on + non-ncurses systems. + + Presently, mouse event reporting works in the following environments: + * xterm and similar programs such as rxvt. + * Linux console, when configured with gpm(1), Alessandro Rubini's + mouse server. + * OS/2 EMX + + The mouse interface is very simple. To activate it, you use the + function mousemask(), passing it as first argument a bit-mask that + specifies what kinds of events you want your program to be able to + see. It will return the bit-mask of events that actually become + visible, which may differ from the argument if the mouse device is not + capable of reporting some of the event types you specify. + + Once the mouse is active, your application's command loop should watch + for a return value of KEY_MOUSE from wgetch(). When you see this, a + mouse event report has been queued. To pick it off the queue, use the + function getmouse() (you must do this before the next wgetch(), + otherwise another mouse event might come in and make the first one + inaccessible). + + Each call to getmouse() fills a structure (the address of which you'll + pass it) with mouse event data. The event data includes zero-origin, + screen-relative character-cell coordinates of the mouse pointer. It + also includes an event mask. Bits in this mask will be set, + corresponding to the event type being reported. + + The mouse structure contains two additional fields which may be + significant in the future as ncurses interfaces to new kinds of + pointing device. In addition to x and y coordinates, there is a slot + for a z coordinate; this might be useful with touch-screens that can + return a pressure or duration parameter. There is also a device ID + field, which could be used to distinguish between multiple pointing + devices. + + The class of visible events may be changed at any time via + mousemask(). Events that can be reported include presses, releases, + single-, double- and triple-clicks (you can set the maximum + button-down time for clicks). If you don't make clicks visible, they + will be reported as press-release pairs. In some environments, the + event mask may include bits reporting the state of shift, alt, and + ctrl keys on the keyboard during the event. + + A function to check whether a mouse event fell within a given window + is also supplied. You can use this to see whether a given window + should consider a mouse event relevant to it. + + Because mouse event reporting will not be available in all + environments, it would be unwise to build ncurses applications that + require the use of a mouse. Rather, you should use the mouse as a + shortcut for point-and-shoot commands your application would normally + accept from the keyboard. Two of the test games in the ncurses + distribution (bs and knight) contain code that illustrates how this + can be done. + + See the manual page curs_mouse(3X) for full details of the + mouse-interface functions. + + Finishing Up + + In order to clean up after the ncurses routines, the routine endwin() + is provided. It restores tty modes to what they were when initscr() + was first called, and moves the cursor down to the lower-left corner. + Thus, anytime after the call to initscr, endwin() should be called + before exiting. + +Function Descriptions + + We describe the detailed behavior of some important curses functions + here, as a supplement to the manual page descriptions. + + Initialization and Wrapup + + initscr() + The first function called should almost always be initscr(). + This will determine the terminal type and initialize curses + data structures. initscr() also arranges that the first call to + refresh() will clear the screen. If an error occurs a message + is written to standard error and the program exits. Otherwise + it returns a pointer to stdscr. A few functions may be called + before initscr (slk_init(), filter(), ripofflines(), use_env(), + and, if you are using multiple terminals, newterm().) + + endwin() + Your program should always call endwin() before exiting or + shelling out of the program. This function will restore tty + modes, move the cursor to the lower left corner of the screen, + reset the terminal into the proper non-visual mode. Calling + refresh() or doupdate() after a temporary escape from the + program will restore the ncurses screen from before the escape. + + newterm(type, ofp, ifp) + A program which outputs to more than one terminal should use + newterm() instead of initscr(). newterm() should be called once + for each terminal. It returns a variable of type SCREEN * which + should be saved as a reference to that terminal. The arguments + are the type of the terminal (a string) and FILE pointers for + the output and input of the terminal. If type is NULL then the + environment variable $TERM is used. endwin() should called once + at wrapup time for each terminal opened using this function. + + set_term(new) + This function is used to switch to a different terminal + previously opened by newterm(). The screen reference for the + new terminal is passed as the parameter. The previous terminal + is returned by the function. All other calls affect only the + current terminal. + + delscreen(sp) + The inverse of newterm(); deallocates the data structures + associated with a given SCREEN reference. + + Causing Output to the Terminal + + refresh() and wrefresh(win) + These functions must be called to actually get any output on + the terminal, as other routines merely manipulate data + structures. wrefresh() copies the named window to the physical + terminal screen, taking into account what is already there in + order to do optimizations. refresh() does a refresh of + stdscr(). Unless leaveok() has been enabled, the physical + cursor of the terminal is left at the location of the window's + cursor. + + doupdate() and wnoutrefresh(win) + These two functions allow multiple updates with more efficiency + than wrefresh. To use them, it is important to understand how + curses works. In addition to all the window structures, curses + keeps two data structures representing the terminal screen: a + physical screen, describing what is actually on the screen, and + a virtual screen, describing what the programmer wants to have + on the screen. wrefresh works by first copying the named window + to the virtual screen (wnoutrefresh()), and then calling the + routine to update the screen (doupdate()). If the programmer + wishes to output several windows at once, a series of calls to + wrefresh will result in alternating calls to wnoutrefresh() and + doupdate(), causing several bursts of output to the screen. By + calling wnoutrefresh() for each window, it is then possible to + call doupdate() once, resulting in only one burst of output, + with fewer total characters transmitted (this also avoids a + visually annoying flicker at each update). + + Low-Level Capability Access + + setupterm(term, filenum, errret) + This routine is called to initialize a terminal's description, + without setting up the curses screen structures or changing the + tty-driver mode bits. term is the character string representing + the name of the terminal being used. filenum is the UNIX file + descriptor of the terminal to be used for output. errret is a + pointer to an integer, in which a success or failure indication + is returned. The values returned can be 1 (all is well), 0 (no + such terminal), or -1 (some problem locating the terminfo + database). + + The value of term can be given as NULL, which will cause the + value of TERM in the environment to be used. The errret pointer + can also be given as NULL, meaning no error code is wanted. If + errret is defaulted, and something goes wrong, setupterm() will + print an appropriate error message and exit, rather than + returning. Thus, a simple program can call setupterm(0, 1, 0) + and not worry about initialization errors. + + After the call to setupterm(), the global variable cur_term is + set to point to the current structure of terminal capabilities. + By calling setupterm() for each terminal, and saving and + restoring cur_term, it is possible for a program to use two or + more terminals at once. Setupterm() also stores the names + section of the terminal description in the global character + array ttytype[]. Subsequent calls to setupterm() will overwrite + this array, so you'll have to save it yourself if need be. + + Debugging + + NOTE: These functions are not part of the standard curses API! + + trace() + This function can be used to explicitly set a trace level. If + the trace level is nonzero, execution of your program will + generate a file called `trace' in the current working directory + containing a report on the library's actions. Higher trace + levels enable more detailed (and verbose) reporting -- see + comments attached to TRACE_ defines in the curses.h file for + details. (It is also possible to set a trace level by assigning + a trace level value to the environment variable NCURSES_TRACE). + + _tracef() + This function can be used to output your own debugging + information. It is only available only if you link with + -lncurses_g. It can be used the same way as printf(), only it + outputs a newline after the end of arguments. The output goes + to a file called trace in the current directory. + + Trace logs can be difficult to interpret due to the sheer volume of + data dumped in them. There is a script called tracemunch included with + the ncurses distribution that can alleviate this problem somewhat; it + compacts long sequences of similar operations into more succinct + single-line pseudo-operations. These pseudo-ops can be distinguished + by the fact that they are named in capital letters. + +Hints, Tips, and Tricks + + The ncurses manual pages are a complete reference for this library. In + the remainder of this document, we discuss various useful methods that + may not be obvious from the manual page descriptions. + + Some Notes of Caution + + If you find yourself thinking you need to use noraw() or nocbreak(), + think again and move carefully. It's probably better design to use + getstr() or one of its relatives to simulate cooked mode. The noraw() + and nocbreak() functions try to restore cooked mode, but they may end + up clobbering some control bits set before you started your + application. Also, they have always been poorly documented, and are + likely to hurt your application's usability with other curses + libraries. + + Bear in mind that refresh() is a synonym for wrefresh(stdscr). Don't + try to mix use of stdscr with use of windows declared by newwin(); a + refresh() call will blow them off the screen. The right way to handle + this is to use subwin(), or not touch stdscr at all and tile your + screen with declared windows which you then wnoutrefresh() somewhere + in your program event loop, with a single doupdate() call to trigger + actual repainting. + + You are much less likely to run into problems if you design your + screen layouts to use tiled rather than overlapping windows. + Historically, curses support for overlapping windows has been weak, + fragile, and poorly documented. The ncurses library is not yet an + exception to this rule. + + There is a panels library included in the ncurses distribution that + does a pretty good job of strengthening the overlapping-windows + facilities. + + Try to avoid using the global variables LINES and COLS. Use getmaxyx() + on the stdscr context instead. Reason: your code may be ported to run + in an environment with window resizes, in which case several screens + could be open with different sizes. + + Temporarily Leaving NCURSES Mode + + Sometimes you will want to write a program that spends most of its + time in screen mode, but occasionally returns to ordinary `cooked' + mode. A common reason for this is to support shell-out. This behavior + is simple to arrange in ncurses. + + To leave ncurses mode, call endwin() as you would if you were + intending to terminate the program. This will take the screen back to + cooked mode; you can do your shell-out. When you want to return to + ncurses mode, simply call refresh() or doupdate(). This will repaint + the screen. + + There is a boolean function, isendwin(), which code can use to test + whether ncurses screen mode is active. It returns TRUE in the interval + between an endwin() call and the following refresh(), FALSE otherwise. + + Here is some sample code for shellout: + addstr("Shelling out..."); + def_prog_mode(); /* save current tty modes */ + endwin(); /* restore original tty modes */ + system("sh"); /* run shell */ + addstr("returned.\n"); /* prepare return message */ + refresh(); /* restore save modes, repaint screen */ + + Using NCURSES under XTERM + + A resize operation in X sends SIGWINCH to the application running + under xterm. The ncurses library provides an experimental signal + handler, but in general does not catch this signal, because it cannot + know how you want the screen re-painted. You will usually have to + write the SIGWINCH handler yourself. Ncurses can give you some help. + + The easiest way to code your SIGWINCH handler is to have it do an + endwin, followed by an refresh and a screen repaint you code yourself. + The refresh will pick up the new screen size from the xterm's + environment. + + That is the standard way, of course (it even works with some vendor's + curses implementations). Its drawback is that it clears the screen to + reinitialize the display, and does not resize subwindows which must be + shrunk. Ncurses provides an extension which works better, the + resizeterm function. That function ensures that all windows are + limited to the new screen dimensions, and pads stdscr with blanks if + the screen is larger. + + Finally, ncurses can be configured to provide its own SIGWINCH + handler, based on resizeterm. + + Handling Multiple Terminal Screens + + The initscr() function actually calls a function named newterm() to do + most of its work. If you are writing a program that opens multiple + terminals, use newterm() directly. + + For each call, you will have to specify a terminal type and a pair of + file pointers; each call will return a screen reference, and stdscr + will be set to the last one allocated. You will switch between screens + with the set_term call. Note that you will also have to call + def_shell_mode and def_prog_mode on each tty yourself. + + Testing for Terminal Capabilities + + Sometimes you may want to write programs that test for the presence of + various capabilities before deciding whether to go into ncurses mode. + An easy way to do this is to call setupterm(), then use the functions + tigetflag(), tigetnum(), and tigetstr() to do your testing. + + A particularly useful case of this often comes up when you want to + test whether a given terminal type should be treated as `smart' + (cursor-addressable) or `stupid'. The right way to test this is to see + if the return value of tigetstr("cup") is non-NULL. Alternatively, you + can include the term.h file and test the value of the macro + cursor_address. + + Tuning for Speed + + Use the addchstr() family of functions for fast screen-painting of + text when you know the text doesn't contain any control characters. + Try to make attribute changes infrequent on your screens. Don't use + the immedok() option! + + Special Features of NCURSES + + The wresize() function allows you to resize a window in place. The + associated resizeterm() function simplifies the construction of + SIGWINCH handlers, for resizing all windows. + + The define_key() function allows you to define at runtime function-key + control sequences which are not in the terminal description. The + keyok() function allows you to temporarily enable or disable + interpretation of any function-key control sequence. + + The use_default_colors() function allows you to construct applications + which can use the terminal's default foreground and background colors + as an additional "default" color. Several terminal emulators support + this feature, which is based on ISO 6429. + + Ncurses supports up 16 colors, unlike SVr4 curses which defines only + 8. While most terminals which provide color allow only 8 colors, about + a quarter (including XFree86 xterm) support 16 colors. + +Compatibility with Older Versions + + Despite our best efforts, there are some differences between ncurses + and the (undocumented!) behavior of older curses implementations. + These arise from ambiguities or omissions in the documentation of the + API. + + Refresh of Overlapping Windows + + If you define two windows A and B that overlap, and then alternately + scribble on and refresh them, the changes made to the overlapping + region under historic curses versions were often not documented + precisely. + + To understand why this is a problem, remember that screen updates are + calculated between two representations of the entire display. The + documentation says that when you refresh a window, it is first copied + to to the virtual screen, and then changes are calculated to update + the physical screen (and applied to the terminal). But "copied to" is + not very specific, and subtle differences in how copying works can + produce different behaviors in the case where two overlapping windows + are each being refreshed at unpredictable intervals. + + What happens to the overlapping region depends on what wnoutrefresh() + does with its argument -- what portions of the argument window it + copies to the virtual screen. Some implementations do "change copy", + copying down only locations in the window that have changed (or been + marked changed with wtouchln() and friends). Some implementations do + "entire copy", copying all window locations to the virtual screen + whether or not they have changed. + + The ncurses library itself has not always been consistent on this + score. Due to a bug, versions 1.8.7 to 1.9.8a did entire copy. + Versions 1.8.6 and older, and versions 1.9.9 and newer, do change + copy. + + For most commercial curses implementations, it is not documented and + not known for sure (at least not to the ncurses maintainers) whether + they do change copy or entire copy. We know that System V release 3 + curses has logic in it that looks like an attempt to do change copy, + but the surrounding logic and data representations are sufficiently + complex, and our knowledge sufficiently indirect, that it's hard to + know whether this is reliable. It is not clear what the SVr4 + documentation and XSI standard intend. The XSI Curses standard barely + mentions wnoutrefresh(); the SVr4 documents seem to be describing + entire-copy, but it is possible with some effort and straining to read + them the other way. + + It might therefore be unwise to rely on either behavior in programs + that might have to be linked with other curses implementations. + Instead, you can do an explicit touchwin() before the wnoutrefresh() + call to guarantee an entire-contents copy anywhere. + + The really clean way to handle this is to use the panels library. If, + when you want a screen update, you do update_panels(), it will do all + the necessary wnoutrfresh() calls for whatever panel stacking order + you have defined. Then you can do one doupdate() and there will be a + single burst of physical I/O that will do all your updates. + + Background Erase + + If you have been using a very old versions of ncurses (1.8.7 or older) + you may be surprised by the behavior of the erase functions. In older + versions, erased areas of a window were filled with a blank modified + by the window's current attribute (as set by wattrset(), wattron(), + wattroff() and friends). + + In newer versions, this is not so. Instead, the attribute of erased + blanks is normal unless and until it is modified by the functions + bkgdset() or wbkgdset(). + + This change in behavior conforms ncurses to System V Release 4 and the + XSI Curses standard. + +XSI Curses Conformance + + The ncurses library is intended to be base-level conformant with the + XSI Curses standard from X/Open. Many extended-level features (in + fact, almost all features not directly concerned with wide characters + and internationalization) are also supported. + + One effect of XSI conformance is the change in behavior described + under "Background Erase -- Compatibility with Old Versions". + + Also, ncurses meets the XSI requirement that every macro entry point + have a corresponding function which may be linked (and will be + prototype-checked) if the macro definition is disabled with #undef. + + The Panels Library + + The ncurses library by itself provides good support for screen + displays in which the windows are tiled (non-overlapping). In the more + general case that windows may overlap, you have to use a series of + wnoutrefresh() calls followed by a doupdate(), and be careful about + the order you do the window refreshes in. It has to be bottom-upwards, + otherwise parts of windows that should be obscured will show through. + + When your interface design is such that windows may dive deeper into + the visibility stack or pop to the top at runtime, the resulting + book-keeping can be tedious and difficult to get right. Hence the + panels library. + + The panel library first appeared in AT&T System V. The version + documented here is the panel code distributed with ncurses. + +Compiling With the Panels Library + + Your panels-using modules must import the panels library declarations + with + #include <panel.h> + + and must be linked explicitly with the panels library using an -lpanel + argument. Note that they must also link the ncurses library with + -lncurses. Many linkers are two-pass and will accept either order, but + it is still good practice to put -lpanel first and -lncurses second. + +Overview of Panels + + A panel object is a window that is implicitly treated as part of a + deck including all other panel objects. The deck has an implicit + bottom-to-top visibility order. The panels library includes an update + function (analogous to refresh()) that displays all panels in the deck + in the proper order to resolve overlaps. The standard window, stdscr, + is considered below all panels. + + Details on the panels functions are available in the man pages. We'll + just hit the highlights here. + + You create a panel from a window by calling new_panel() on a window + pointer. It then becomes the top of the deck. The panel's window is + available as the value of panel_window() called with the panel pointer + as argument. + + You can delete a panel (removing it from the deck) with del_panel. + This will not deallocate the associated window; you have to do that + yourself. You can replace a panel's window with a different window by + calling replace_window. The new window may be of different size; the + panel code will re-compute all overlaps. This operation doesn't change + the panel's position in the deck. + + To move a panel's window, use move_panel(). The mvwin() function on + the panel's window isn't sufficient because it doesn't update the + panels library's representation of where the windows are. This + operation leaves the panel's depth, contents, and size unchanged. + + Two functions (top_panel(), bottom_panel()) are provided for + rearranging the deck. The first pops its argument window to the top of + the deck; the second sends it to the bottom. Either operation leaves + the panel's screen location, contents, and size unchanged. + + The function update_panels() does all the wnoutrefresh() calls needed + to prepare for doupdate() (which you must call yourself, afterwards). + + Typically, you will want to call update_panels() and doupdate() just + before accepting command input, once in each cycle of interaction with + the user. If you call update_panels() after each and every panel + write, you'll generate a lot of unnecessary refresh activity and + screen flicker. + +Panels, Input, and the Standard Screen + + You shouldn't mix wnoutrefresh() or wrefresh() operations with panels + code; this will work only if the argument window is either in the top + panel or unobscured by any other panels. + + The stsdcr window is a special case. It is considered below all + panels. Because changes to panels may obscure parts of stdscr, though, + you should call update_panels() before doupdate() even when you only + change stdscr. + + Note that wgetch automatically calls wrefresh. Therefore, before + requesting input from a panel window, you need to be sure that the + panel is totally unobscured. + + There is presently no way to display changes to one obscured panel + without repainting all panels. + +Hiding Panels + + It's possible to remove a panel from the deck temporarily; use + hide_panel for this. Use show_panel() to render it visible again. The + predicate function panel_hidden tests whether or not a panel is + hidden. + + The panel_update code ignores hidden panels. You cannot do top_panel() + or bottom_panel on a hidden panel(). Other panels operations are + applicable. + +Miscellaneous Other Facilities + + It's possible to navigate the deck using the functions panel_above() + and panel_below. Handed a panel pointer, they return the panel above + or below that panel. Handed NULL, they return the bottom-most or + top-most panel. + + Every panel has an associated user pointer, not used by the panel + code, to which you can attach application data. See the man page + documentation of set_panel_userptr() and panel_userptr for details. + + The Menu Library + + A menu is a screen display that assists the user to choose some subset + of a given set of items. The menu library is a curses extension that + supports easy programming of menu hierarchies with a uniform but + flexible interface. + + The menu library first appeared in AT&T System V. The version + documented here is the menu code distributed with ncurses. + +Compiling With the menu Library + + Your menu-using modules must import the menu library declarations with + #include <menu.h> + + and must be linked explicitly with the menus library using an -lmenu + argument. Note that they must also link the ncurses library with + -lncurses. Many linkers are two-pass and will accept either order, but + it is still good practice to put -lmenu first and -lncurses second. + +Overview of Menus + + The menus created by this library consist of collections of items + including a name string part and a description string part. To make + menus, you create groups of these items and connect them with menu + frame objects. + + The menu can then by posted, that is written to an associated window. + Actually, each menu has two associated windows; a containing window in + which the programmer can scribble titles or borders, and a subwindow + in which the menu items proper are displayed. If this subwindow is too + small to display all the items, it will be a scrollable viewport on + the collection of items. + + A menu may also be unposted (that is, undisplayed), and finally freed + to make the storage associated with it and its items available for + re-use. + + The general flow of control of a menu program looks like this: + 1. Initialize curses. + 2. Create the menu items, using new_item(). + 3. Create the menu using new_menu(). + 4. Post the menu using menu_post(). + 5. Refresh the screen. + 6. Process user requests via an input loop. + 7. Unpost the menu using menu_unpost(). + 8. Free the menu, using free_menu(). + 9. Free the items using free_item(). + 10. Terminate curses. + +Selecting items + + Menus may be multi-valued or (the default) single-valued (see the + manual page menu_opts(3x) to see how to change the default). Both + types always have a current item. + + From a single-valued menu you can read the selected value simply by + looking at the current item. From a multi-valued menu, you get the + selected set by looping through the items applying the item_value() + predicate function. Your menu-processing code can use the function + set_item_value() to flag the items in the select set. + + Menu items can be made unselectable using set_item_opts() or + item_opts_off() with the O_SELECTABLE argument. This is the only + option so far defined for menus, but it is good practice to code as + though other option bits might be on. + +Menu Display + + The menu library calculates a minimum display size for your window, + based on the following variables: + * The number and maximum length of the menu items + * Whether the O_ROWMAJOR option is enabled + * Whether display of descriptions is enabled + * Whatever menu format may have been set by the programmer + * The length of the menu mark string used for highlighting selected + items + + The function set_menu_format() allows you to set the maximum size of + the viewport or menu page that will be used to display menu items. You + can retrieve any format associated with a menu with menu_format(). The + default format is rows=16, columns=1. + + The actual menu page may be smaller than the format size. This depends + on the item number and size and whether O_ROWMAJOR is on. This option + (on by default) causes menu items to be displayed in a `raster-scan' + pattern, so that if more than one item will fit horizontally the first + couple of items are side-by-side in the top row. The alternative is + column-major display, which tries to put the first several items in + the first column. + + As mentioned above, a menu format not large enough to allow all items + to fit on-screen will result in a menu display that is vertically + scrollable. + + You can scroll it with requests to the menu driver, which will be + described in the section on menu input handling. + + Each menu has a mark string used to visually tag selected items; see + the menu_mark(3x) manual page for details. The mark string length also + influences the menu page size. + + The function scale_menu() returns the minimum display size that the + menu code computes from all these factors. There are other menu + display attributes including a select attribute, an attribute for + selectable items, an attribute for unselectable items, and a pad + character used to separate item name text from description text. These + have reasonable defaults which the library allows you to change (see + the menu_attribs(3x) manual page. + +Menu Windows + + Each menu has, as mentioned previously, a pair of associated windows. + Both these windows are painted when the menu is posted and erased when + the menu is unposted. + + The outer or frame window is not otherwise touched by the menu + routines. It exists so the programmer can associate a title, a border, + or perhaps help text with the menu and have it properly refreshed or + erased at post/unpost time. The inner window or subwindow is where the + current menu page is displayed. + + By default, both windows are stdscr. You can set them with the + functions in menu_win(3x). + + When you call menu_post(), you write the menu to its subwindow. When + you call menu_unpost(), you erase the subwindow, However, neither of + these actually modifies the screen. To do that, call wrefresh() or + some equivalent. + +Processing Menu Input + + The main loop of your menu-processing code should call menu_driver() + repeatedly. The first argument of this routine is a menu pointer; the + second is a menu command code. You should write an input-fetching + routine that maps input characters to menu command codes, and pass its + output to menu_driver(). The menu command codes are fully documented + in menu_driver(3x). + + The simplest group of command codes is REQ_NEXT_ITEM, REQ_PREV_ITEM, + REQ_FIRST_ITEM, REQ_LAST_ITEM, REQ_UP_ITEM, REQ_DOWN_ITEM, + REQ_LEFT_ITEM, REQ_RIGHT_ITEM. These change the currently selected + item. These requests may cause scrolling of the menu page if it only + partially displayed. + + There are explicit requests for scrolling which also change the + current item (because the select location does not change, but the + item there does). These are REQ_SCR_DLINE, REQ_SCR_ULINE, + REQ_SCR_DPAGE, and REQ_SCR_UPAGE. + + The REQ_TOGGLE_ITEM selects or deselects the current item. It is for + use in multi-valued menus; if you use it with O_ONEVALUE on, you'll + get an error return (E_REQUEST_DENIED). + + Each menu has an associated pattern buffer. The menu_driver() logic + tries to accumulate printable ASCII characters passed in in that + buffer; when it matches a prefix of an item name, that item (or the + next matching item) is selected. If appending a character yields no + new match, that character is deleted from the pattern buffer, and + menu_driver() returns E_NO_MATCH. + + Some requests change the pattern buffer directly: REQ_CLEAR_PATTERN, + REQ_BACK_PATTERN, REQ_NEXT_MATCH, REQ_PREV_MATCH. The latter two are + useful when pattern buffer input matches more than one item in a + multi-valued menu. + + Each successful scroll or item navigation request clears the pattern + buffer. It is also possible to set the pattern buffer explicitly with + set_menu_pattern(). + + Finally, menu driver requests above the constant MAX_COMMAND are + considered application-specific commands. The menu_driver() code + ignores them and returns E_UNKNOWN_COMMAND. + +Miscellaneous Other Features + + Various menu options can affect the processing and visual appearance + and input processing of menus. See menu_opts(3x) for details. + + It is possible to change the current item from application code; this + is useful if you want to write your own navigation requests. It is + also possible to explicitly set the top row of the menu display. See + mitem_current(3x). If your application needs to change the menu + subwindow cursor for any reason, pos_menu_cursor() will restore it to + the correct location for continuing menu driver processing. + + It is possible to set hooks to be called at menu initialization and + wrapup time, and whenever the selected item changes. See + menu_hook(3x). + + Each item, and each menu, has an associated user pointer on which you + can hang application data. See mitem_userptr(3x) and menu_userptr(3x). + + The Forms Library + + The form library is a curses extension that supports easy programming + of on-screen forms for data entry and program control. + + The form library first appeared in AT&T System V. The version + documented here is the form code distributed with ncurses. + +Compiling With the form Library + + Your form-using modules must import the form library declarations with + #include <form.h> + + and must be linked explicitly with the forms library using an -lform + argument. Note that they must also link the ncurses library with + -lncurses. Many linkers are two-pass and will accept either order, but + it is still good practice to put -lform first and -lncurses second. + +Overview of Forms + + A form is a collection of fields; each field may be either a label + (explanatory text) or a data-entry location. Long forms may be + segmented into pages; each entry to a new page clears the screen. + + To make forms, you create groups of fields and connect them with form + frame objects; the form library makes this relatively simple. + + Once defined, a form can be posted, that is written to an associated + window. Actually, each form has two associated windows; a containing + window in which the programmer can scribble titles or borders, and a + subwindow in which the form fields proper are displayed. + + As the form user fills out the posted form, navigation and editing + keys support movement between fields, editing keys support modifying + field, and plain text adds to or changes data in a current field. The + form library allows you (the forms designer) to bind each navigation + and editing key to any keystroke accepted by curses Fields may have + validation conditions on them, so that they check input data for type + and value. The form library supplies a rich set of pre-defined field + types, and makes it relatively easy to define new ones. + + Once its transaction is completed (or aborted), a form may be unposted + (that is, undisplayed), and finally freed to make the storage + associated with it and its items available for re-use. + + The general flow of control of a form program looks like this: + 1. Initialize curses. + 2. Create the form fields, using new_field(). + 3. Create the form using new_form(). + 4. Post the form using form_post(). + 5. Refresh the screen. + 6. Process user requests via an input loop. + 7. Unpost the form using form_unpost(). + 8. Free the form, using free_form(). + 9. Free the fields using free_field(). + 10. Terminate curses. + + Note that this looks much like a menu program; the form library + handles tasks which are in many ways similar, and its interface was + obviously designed to resemble that of the menu library wherever + possible. + + In forms programs, however, the `process user requests' is somewhat + more complicated than for menus. Besides menu-like navigation + operations, the menu driver loop has to support field editing and data + validation. + +Creating and Freeing Fields and Forms + + The basic function for creating fields is new_field(): +FIELD *new_field(int height, int width, /* new field size */ + int top, int left, /* upper left corner */ + int offscreen, /* number of offscreen rows */ + int nbuf); /* number of working buffers */ + + Menu items always occupy a single row, but forms fields may have + multiple rows. So new_field() requires you to specify a width and + height (the first two arguments, which mist both be greater than + zero). + + You must also specify the location of the field's upper left corner on + the screen (the third and fourth arguments, which must be zero or + greater). Note that these coordinates are relative to the form + subwindow, which will coincide with stdscr by default but need not be + stdscr if you've done an explicit set_form_window() call. + + The fifth argument allows you to specify a number of off-screen rows. + If this is zero, the entire field will always be displayed. If it is + nonzero, the form will be scrollable, with only one screen-full + (initially the top part) displayed at any given time. If you make a + field dynamic and grow it so it will no longer fit on the screen, the + form will become scrollable even if the offscreen argument was + initially zero. + + The forms library allocates one working buffer per field; the size of + each buffer is ((height + offscreen)*width + 1, one character for each + position in the field plus a NUL terminator. The sixth argument is the + number of additional data buffers to allocate for the field; your + application can use them for its own purposes. +FIELD *dup_field(FIELD *field, /* field to copy */ + int top, int left); /* location of new copy */ + + The function dup_field() duplicates an existing field at a new + location. Size and buffering information are copied; some attribute + flags and status bits are not (see the form_field_new(3X) for + details). +FIELD *link_field(FIELD *field, /* field to copy */ + int top, int left); /* location of new copy */ + + The function link_field() also duplicates an existing field at a new + location. The difference from dup_field() is that it arranges for the + new field's buffer to be shared with the old one. + + Besides the obvious use in making a field editable from two different + form pages, linked fields give you a way to hack in dynamic labels. If + you declare several fields linked to an original, and then make them + inactive, changes from the original will still be propagated to the + linked fields. + + As with duplicated fields, linked fields have attribute bits separate + from the original. + + As you might guess, all these field-allocations return NULL if the + field allocation is not possible due to an out-of-memory error or + out-of-bounds arguments. + + To connect fields to a form, use +FORM *new_form(FIELD **fields); + + This function expects to see a NULL-terminated array of field + pointers. Said fields are connected to a newly-allocated form object; + its address is returned (or else NULL if the allocation fails). + + Note that new_field() does not copy the pointer array into private + storage; if you modify the contents of the pointer array during forms + processing, all manner of bizarre things might happen. Also note that + any given field may only be connected to one form. + + The functions free_field() and free_form are available to free field + and form objects. It is an error to attempt to free a field connected + to a form, but not vice-versa; thus, you will generally free your form + objects first. + +Fetching and Changing Field Attributes + + Each form field has a number of location and size attributes + associated with it. There are other field attributes used to control + display and editing of the field. Some (for example, the O_STATIC bit) + involve sufficient complications to be covered in sections of their + own later on. We cover the functions used to get and set several basic + attributes here. + + When a field is created, the attributes not specified by the new_field + function are copied from an invisible system default field. In + attribute-setting and -fetching functions, the argument NULL is taken + to mean this field. Changes to it persist as defaults until your forms + application terminates. + + Fetching Size and Location Data + + You can retrieve field sizes and locations through: +int field_info(FIELD *field, /* field from which to fetch */ + int *height, *int width, /* field size */ + int *top, int *left, /* upper left corner */ + int *offscreen, /* number of offscreen rows */ + int *nbuf); /* number of working buffers */ + + This function is a sort of inverse of new_field(); instead of setting + size and location attributes of a new field, it fetches them from an + existing one. + + Changing the Field Location + + It is possible to move a field's location on the screen: +int move_field(FIELD *field, /* field to alter */ + int top, int left); /* new upper-left corner */ + + You can, of course. query the current location through field_info(). + + The Justification Attribute + + One-line fields may be unjustified, justified right, justified left, + or centered. Here is how you manipulate this attribute: +int set_field_just(FIELD *field, /* field to alter */ + int justmode); /* mode to set */ + +int field_just(FIELD *field); /* fetch mode of field */ + + The mode values accepted and returned by this functions are + preprocessor macros NO_JUSTIFICATION, JUSTIFY_RIGHT, JUSTIFY_LEFT, or + JUSTIFY_CENTER. + + Field Display Attributes + + For each field, you can set a foreground attribute for entered + characters, a background attribute for the entire field, and a pad + character for the unfilled portion of the field. You can also control + pagination of the form. + + This group of four field attributes controls the visual appearance of + the field on the screen, without affecting in any way the data in the + field buffer. +int set_field_fore(FIELD *field, /* field to alter */ + chtype attr); /* attribute to set */ + +chtype field_fore(FIELD *field); /* field to query */ + +int set_field_back(FIELD *field, /* field to alter */ + chtype attr); /* attribute to set */ + +chtype field_back(FIELD *field); /* field to query */ + +int set_field_pad(FIELD *field, /* field to alter */ + int pad); /* pad character to set */ + +chtype field_pad(FIELD *field); + +int set_new_page(FIELD *field, /* field to alter */ + int flag); /* TRUE to force new page */ + +chtype new_page(FIELD *field); /* field to query */ + + The attributes set and returned by the first four functions are normal + curses(3x) display attribute values (A_STANDOUT, A_BOLD, A_REVERSE + etc). The page bit of a field controls whether it is displayed at the + start of a new form screen. + + Field Option Bits + + There is also a large collection of field option bits you can set to + control various aspects of forms processing. You can manipulate them + with these functions: +int set_field_opts(FIELD *field, /* field to alter */ + int attr); /* attribute to set */ + +int field_opts_on(FIELD *field, /* field to alter */ + int attr); /* attributes to turn on */ + +int field_opts_off(FIELD *field, /* field to alter */ + int attr); /* attributes to turn off */ + +int field_opts(FIELD *field); /* field to query */ + + By default, all options are on. Here are the available option bits: + + O_VISIBLE + Controls whether the field is visible on the screen. Can be + used during form processing to hide or pop up fields depending + on the value of parent fields. + + O_ACTIVE + Controls whether the field is active during forms processing + (i.e. visited by form navigation keys). Can be used to make + labels or derived fields with buffer values alterable by the + forms application, not the user. + + O_PUBLIC + Controls whether data is displayed during field entry. If this + option is turned off on a field, the library will accept and + edit data in that field, but it will not be displayed and the + visible field cursor will not move. You can turn off the + O_PUBLIC bit to define password fields. + + O_EDIT + Controls whether the field's data can be modified. When this + option is off, all editing requests except REQ_PREV_CHOICE and + REQ_NEXT_CHOICE will fail. Such read-only fields may be useful + for help messages. + + O_WRAP + Controls word-wrapping in multi-line fields. Normally, when any + character of a (blank-separated) word reaches the end of the + current line, the entire word is wrapped to the next line + (assuming there is one). When this option is off, the word will + be split across the line break. + + O_BLANK + Controls field blanking. When this option is on, entering a + character at the first field position erases the entire field + (except for the just-entered character). + + O_AUTOSKIP + Controls automatic skip to next field when this one fills. + Normally, when the forms user tries to type more data into a + field than will fit, the editing location jumps to next field. + When this option is off, the user's cursor will hang at the end + of the field. This option is ignored in dynamic fields that + have not reached their size limit. + + O_NULLOK + Controls whether validation is applied to blank fields. + Normally, it is not; the user can leave a field blank without + invoking the usual validation check on exit. If this option is + off on a field, exit from it will invoke a validation check. + + O_PASSOK + Controls whether validation occurs on every exit, or only after + the field is modified. Normally the latter is true. Setting + O_PASSOK may be useful if your field's validation function may + change during forms processing. + + O_STATIC + Controls whether the field is fixed to its initial dimensions. + If you turn this off, the field becomes dynamic and will + stretch to fit entered data. + + A field's options cannot be changed while the field is currently + selected. However, options may be changed on posted fields that are + not current. + + The option values are bit-masks and can be composed with logical-or in + the obvious way. + +Field Status + + Every field has a status flag, which is set to FALSE when the field is + created and TRUE when the value in field buffer 0 changes. This flag + can be queried and set directly: +int set_field_status(FIELD *field, /* field to alter */ + int status); /* mode to set */ + +int field_status(FIELD *field); /* fetch mode of field */ + + Setting this flag under program control can be useful if you use the + same form repeatedly, looking for modified fields each time. + + Calling field_status() on a field not currently selected for input + will return a correct value. Calling field_status() on a field that is + currently selected for input may not necessarily give a correct field + status value, because entered data isn't necessarily copied to buffer + zero before the exit validation check. To guarantee that the returned + status value reflects reality, call field_status() either (1) in the + field's exit validation check routine, (2) from the field's or form's + initialization or termination hooks, or (3) just after a + REQ_VALIDATION request has been processed by the forms driver. + +Field User Pointer + + Each field structure contains one character pointer slot that is not + used by the forms library. It is intended to be used by applications + to store private per-field data. You can manipulate it with: +int set_field_userptr(FIELD *field, /* field to alter */ + char *userptr); /* mode to set */ + +char *field_userptr(FIELD *field); /* fetch mode of field */ + + (Properly, this user pointer field ought to have (void *) type. The + (char *) type is retained for System V compatibility.) + + It is valid to set the user pointer of the default field (with a + set_field_userptr() call passed a NULL field pointer.) When a new + field is created, the default-field user pointer is copied to + initialize the new field's user pointer. + +Variable-Sized Fields + + Normally, a field is fixed at the size specified for it at creation + time. If, however, you turn off its O_STATIC bit, it becomes dynamic + and will automatically resize itself to accommodate data as it is + entered. If the field has extra buffers associated with it, they will + grow right along with the main input buffer. + + A one-line dynamic field will have a fixed height (1) but variable + width, scrolling horizontally to display data within the field area as + originally dimensioned and located. A multi-line dynamic field will + have a fixed width, but variable height (number of rows), scrolling + vertically to display data within the field area as originally + dimensioned and located. + + Normally, a dynamic field is allowed to grow without limit. But it is + possible to set an upper limit on the size of a dynamic field. You do + it with this function: +int set_max_field(FIELD *field, /* field to alter (may not be NULL) */ + int max_size); /* upper limit on field size */ + + If the field is one-line, max_size is taken to be a column size limit; + if it is multi-line, it is taken to be a line size limit. To disable + any limit, use an argument of zero. The growth limit can be changed + whether or not the O_STATIC bit is on, but has no effect until it is. + + The following properties of a field change when it becomes dynamic: + * If there is no growth limit, there is no final position of the + field; therefore O_AUTOSKIP and O_NL_OVERLOAD are ignored. + * Field justification will be ignored (though whatever justification + is set up will be retained internally and can be queried). + * The dup_field() and link_field() calls copy dynamic-buffer sizes. + If the O_STATIC option is set on one of a collection of links, + buffer resizing will occur only when the field is edited through + that link. + * The call field_info() will retrieve the original static size of + the field; use dynamic_field_info() to get the actual dynamic + size. + +Field Validation + + By default, a field will accept any data that will fit in its input + buffer. However, it is possible to attach a validation type to a + field. If you do this, any attempt to leave the field while it + contains data that doesn't match the validation type will fail. Some + validation types also have a character-validity check for each time a + character is entered in the field. + + A field's validation check (if any) is not called when + set_field_buffer() modifies the input buffer, nor when that buffer is + changed through a linked field. + + The form library provides a rich set of pre-defined validation types, + and gives you the capability to define custom ones of your own. You + can examine and change field validation attributes with the following + functions: +int set_field_type(FIELD *field, /* field to alter */ + FIELDTYPE *ftype, /* type to associate */ + ...); /* additional arguments*/ + +FIELDTYPE *field_type(FIELD *field); /* field to query */ + + The validation type of a field is considered an attribute of the + field. As with other field attributes, Also, doing set_field_type() + with a NULL field default will change the system default for + validation of newly-created fields. + + Here are the pre-defined validation types: + + TYPE_ALPHA + + This field type accepts alphabetic data; no blanks, no digits, no + special characters (this is checked at character-entry time). It is + set up with: +int set_field_type(FIELD *field, /* field to alter */ + TYPE_ALPHA, /* type to associate */ + int width); /* maximum width of field */ + + The width argument sets a minimum width of data. Typically you'll want + to set this to the field width; if it's greater than the field width, + the validation check will always fail. A minimum width of zero makes + field completion optional. + + TYPE_ALNUM + + This field type accepts alphabetic data and digits; no blanks, no + special characters (this is checked at character-entry time). It is + set up with: +int set_field_type(FIELD *field, /* field to alter */ + TYPE_ALNUM, /* type to associate */ + int width); /* maximum width of field */ + + The width argument sets a minimum width of data. As with TYPE_ALPHA, + typically you'll want to set this to the field width; if it's greater + than the field width, the validation check will always fail. A minimum + width of zero makes field completion optional. + + TYPE_ENUM + + This type allows you to restrict a field's values to be among a + specified set of string values (for example, the two-letter postal + codes for U.S. states). It is set up with: +int set_field_type(FIELD *field, /* field to alter */ + TYPE_ENUM, /* type to associate */ + char **valuelist; /* list of possible values */ + int checkcase; /* case-sensitive? */ + int checkunique); /* must specify uniquely? */ + + The valuelist parameter must point at a NULL-terminated list of valid + strings. The checkcase argument, if true, makes comparison with the + string case-sensitive. + + When the user exits a TYPE_ENUM field, the validation procedure tries + to complete the data in the buffer to a valid entry. If a complete + choice string has been entered, it is of course valid. But it is also + possible to enter a prefix of a valid string and have it completed for + you. + + By default, if you enter such a prefix and it matches more than one + value in the string list, the prefix will be completed to the first + matching value. But the checkunique argument, if true, requires prefix + matches to be unique in order to be valid. + + The REQ_NEXT_CHOICE and REQ_PREV_CHOICE input requests can be + particularly useful with these fields. + + TYPE_INTEGER + + This field type accepts an integer. It is set up as follows: +int set_field_type(FIELD *field, /* field to alter */ + TYPE_INTEGER, /* type to associate */ + int padding, /* # places to zero-pad to */ + int vmin, int vmax); /* valid range */ + + Valid characters consist of an optional leading minus and digits. The + range check is performed on exit. If the range maximum is less than or + equal to the minimum, the range is ignored. + + If the value passes its range check, it is padded with as many leading + zero digits as necessary to meet the padding argument. + + A TYPE_INTEGER value buffer can conveniently be interpreted with the C + library function atoi(3). + + TYPE_NUMERIC + + This field type accepts a decimal number. It is set up as follows: +int set_field_type(FIELD *field, /* field to alter */ + TYPE_NUMERIC, /* type to associate */ + int padding, /* # places of precision */ + double vmin, double vmax); /* valid range */ + + Valid characters consist of an optional leading minus and digits. + possibly including a decimal point. If your system supports locale's, + the decimal point character used must be the one defined by your + locale. The range check is performed on exit. If the range maximum is + less than or equal to the minimum, the range is ignored. + + If the value passes its range check, it is padded with as many + trailing zero digits as necessary to meet the padding argument. + + A TYPE_NUMERIC value buffer can conveniently be interpreted with the C + library function atof(3). + + TYPE_REGEXP + + This field type accepts data matching a regular expression. It is set + up as follows: +int set_field_type(FIELD *field, /* field to alter */ + TYPE_REGEXP, /* type to associate */ + char *regexp); /* expression to match */ + + The syntax for regular expressions is that of regcomp(3). The check + for regular-expression match is performed on exit. + +Direct Field Buffer Manipulation + + The chief attribute of a field is its buffer contents. When a form has + been completed, your application usually needs to know the state of + each field buffer. You can find this out with: +char *field_buffer(FIELD *field, /* field to query */ + int bufindex); /* number of buffer to query */ + + Normally, the state of the zero-numbered buffer for each field is set + by the user's editing actions on that field. It's sometimes useful to + be able to set the value of the zero-numbered (or some other) buffer + from your application: +int set_field_buffer(FIELD *field, /* field to alter */ + int bufindex, /* number of buffer to alter */ + char *value); /* string value to set */ + + If the field is not large enough and cannot be resized to a + sufficiently large size to contain the specified value, the value will + be truncated to fit. + + Calling field_buffer() with a null field pointer will raise an error. + Calling field_buffer() on a field not currently selected for input + will return a correct value. Calling field_buffer() on a field that is + currently selected for input may not necessarily give a correct field + buffer value, because entered data isn't necessarily copied to buffer + zero before the exit validation check. To guarantee that the returned + buffer value reflects on-screen reality, call field_buffer() either + (1) in the field's exit validation check routine, (2) from the field's + or form's initialization or termination hooks, or (3) just after a + REQ_VALIDATION request has been processed by the forms driver. + +Attributes of Forms + + As with field attributes, form attributes inherit a default from a + system default form structure. These defaults can be queried or set by + of these functions using a form-pointer argument of NULL. + + The principal attribute of a form is its field list. You can query and + change this list with: +int set_form_fields(FORM *form, /* form to alter */ + FIELD **fields); /* fields to connect */ + +char *form_fields(FORM *form); /* fetch fields of form */ + +int field_count(FORM *form); /* count connect fields */ + + The second argument of set_form_fields() may be a NULL-terminated + field pointer array like the one required by new_form(). In that case, + the old fields of the form are disconnected but not freed (and + eligible to be connected to other forms), then the new fields are + connected. + + It may also be null, in which case the old fields are disconnected + (and not freed) but no new ones are connected. + + The field_count() function simply counts the number of fields + connected to a given from. It returns -1 if the form-pointer argument + is NULL. + +Control of Form Display + + In the overview section, you saw that to display a form you normally + start by defining its size (and fields), posting it, and refreshing + the screen. There is an hidden step before posting, which is the + association of the form with a frame window (actually, a pair of + windows) within which it will be displayed. By default, the forms + library associates every form with the full-screen window stdscr. + + By making this step explicit, you can associate a form with a declared + frame window on your screen display. This can be useful if you want to + adapt the form display to different screen sizes, dynamically tile + forms on the screen, or use a form as part of an interface layout + managed by panels. + + The two windows associated with each form have the same functions as + their analogues in the menu library. Both these windows are painted + when the form is posted and erased when the form is unposted. + + The outer or frame window is not otherwise touched by the form + routines. It exists so the programmer can associate a title, a border, + or perhaps help text with the form and have it properly refreshed or + erased at post/unpost time. The inner window or subwindow is where the + current form page is actually displayed. + + In order to declare your own frame window for a form, you'll need to + know the size of the form's bounding rectangle. You can get this + information with: +int scale_form(FORM *form, /* form to query */ + int *rows, /* form rows */ + int *cols); /* form cols */ + + The form dimensions are passed back in the locations pointed to by the + arguments. Once you have this information, you can use it to declare + of windows, then use one of these functions: +int set_form_win(FORM *form, /* form to alter */ + WINDOW *win); /* frame window to connect */ + +WINDOW *form_win(FORM *form); /* fetch frame window of form */ + +int set_form_sub(FORM *form, /* form to alter */ + WINDOW *win); /* form subwindow to connect */ + +WINDOW *form_sub(FORM *form); /* fetch form subwindow of form */ + + Note that curses operations, including refresh(), on the form, should + be done on the frame window, not the form subwindow. + + It is possible to check from your application whether all of a + scrollable field is actually displayed within the menu subwindow. Use + these functions: +int data_ahead(FORM *form); /* form to be queried */ + +int data_behind(FORM *form); /* form to be queried */ + + The function data_ahead() returns TRUE if (a) the current field is + one-line and has undisplayed data off to the right, (b) the current + field is multi-line and there is data off-screen below it. + + The function data_behind() returns TRUE if the first (upper left hand) + character position is off-screen (not being displayed). + + Finally, there is a function to restore the form window's cursor to + the value expected by the forms driver: +int pos_form_cursor(FORM *) /* form to be queried */ + + If your application changes the form window cursor, call this function + before handing control back to the forms driver in order to + re-synchronize it. + +Input Processing in the Forms Driver + + The function form_driver() handles virtualized input requests for form + navigation, editing, and validation requests, just as menu_driver does + for menus (see the section on menu input handling). +int form_driver(FORM *form, /* form to pass input to */ + int request); /* form request code */ + + Your input virtualization function needs to take input and then + convert it to either an alphanumeric character (which is treated as + data to be entered in the currently-selected field), or a forms + processing request. + + The forms driver provides hooks (through input-validation and + field-termination functions) with which your application code can + check that the input taken by the driver matched what was expected. + + Page Navigation Requests + + These requests cause page-level moves through the form, triggering + display of a new form screen. + + REQ_NEXT_PAGE + Move to the next form page. + + REQ_PREV_PAGE + Move to the previous form page. + + REQ_FIRST_PAGE + Move to the first form page. + + REQ_LAST_PAGE + Move to the last form page. + + These requests treat the list as cyclic; that is, REQ_NEXT_PAGE from + the last page goes to the first, and REQ_PREV_PAGE from the first page + goes to the last. + + Inter-Field Navigation Requests + + These requests handle navigation between fields on the same page. + + REQ_NEXT_FIELD + Move to next field. + + REQ_PREV_FIELD + Move to previous field. + + REQ_FIRST_FIELD + Move to the first field. + + REQ_LAST_FIELD + Move to the last field. + + REQ_SNEXT_FIELD + Move to sorted next field. + + REQ_SPREV_FIELD + Move to sorted previous field. + + REQ_SFIRST_FIELD + Move to the sorted first field. + + REQ_SLAST_FIELD + Move to the sorted last field. + + REQ_LEFT_FIELD + Move left to field. + + REQ_RIGHT_FIELD + Move right to field. + + REQ_UP_FIELD + Move up to field. + + REQ_DOWN_FIELD + Move down to field. + + These requests treat the list of fields on a page as cyclic; that is, + REQ_NEXT_FIELD from the last field goes to the first, and + REQ_PREV_FIELD from the first field goes to the last. The order of the + fields for these (and the REQ_FIRST_FIELD and REQ_LAST_FIELD requests) + is simply the order of the field pointers in the form array (as set up + by new_form() or set_form_fields() + + It is also possible to traverse the fields as if they had been sorted + in screen-position order, so the sequence goes left-to-right and + top-to-bottom. To do this, use the second group of four + sorted-movement requests. + + Finally, it is possible to move between fields using visual directions + up, down, right, and left. To accomplish this, use the third group of + four requests. Note, however, that the position of a form for purposes + of these requests is its upper-left corner. + + For example, suppose you have a multi-line field B, and two + single-line fields A and C on the same line with B, with A to the left + of B and C to the right of B. A REQ_MOVE_RIGHT from A will go to B + only if A, B, and C all share the same first line; otherwise it will + skip over B to C. + + Intra-Field Navigation Requests + + These requests drive movement of the edit cursor within the currently + selected field. + + REQ_NEXT_CHAR + Move to next character. + + REQ_PREV_CHAR + Move to previous character. + + REQ_NEXT_LINE + Move to next line. + + REQ_PREV_LINE + Move to previous line. + + REQ_NEXT_WORD + Move to next word. + + REQ_PREV_WORD + Move to previous word. + + REQ_BEG_FIELD + Move to beginning of field. + + REQ_END_FIELD + Move to end of field. + + REQ_BEG_LINE + Move to beginning of line. + + REQ_END_LINE + Move to end of line. + + REQ_LEFT_CHAR + Move left in field. + + REQ_RIGHT_CHAR + Move right in field. + + REQ_UP_CHAR + Move up in field. + + REQ_DOWN_CHAR + Move down in field. + + Each word is separated from the previous and next characters by + whitespace. The commands to move to beginning and end of line or field + look for the first or last non-pad character in their ranges. + + Scrolling Requests + + Fields that are dynamic and have grown and fields explicitly created + with offscreen rows are scrollable. One-line fields scroll + horizontally; multi-line fields scroll vertically. Most scrolling is + triggered by editing and intra-field movement (the library scrolls the + field to keep the cursor visible). It is possible to explicitly + request scrolling with the following requests: + + REQ_SCR_FLINE + Scroll vertically forward a line. + + REQ_SCR_BLINE + Scroll vertically backward a line. + + REQ_SCR_FPAGE + Scroll vertically forward a page. + + REQ_SCR_BPAGE + Scroll vertically backward a page. + + REQ_SCR_FHPAGE + Scroll vertically forward half a page. + + REQ_SCR_BHPAGE + Scroll vertically backward half a page. + + REQ_SCR_FCHAR + Scroll horizontally forward a character. + + REQ_SCR_BCHAR + Scroll horizontally backward a character. + + REQ_SCR_HFLINE + Scroll horizontally one field width forward. + + REQ_SCR_HBLINE + Scroll horizontally one field width backward. + + REQ_SCR_HFHALF + Scroll horizontally one half field width forward. + + REQ_SCR_HBHALF + Scroll horizontally one half field width backward. + + For scrolling purposes, a page of a field is the height of its visible + part. + + Editing Requests + + When you pass the forms driver an ASCII character, it is treated as a + request to add the character to the field's data buffer. Whether this + is an insertion or a replacement depends on the field's edit mode + (insertion is the default. + + The following requests support editing the field and changing the edit + mode: + + REQ_INS_MODE + Set insertion mode. + + REQ_OVL_MODE + Set overlay mode. + + REQ_NEW_LINE + New line request (see below for explanation). + + REQ_INS_CHAR + Insert space at character location. + + REQ_INS_LINE + Insert blank line at character location. + + REQ_DEL_CHAR + Delete character at cursor. + + REQ_DEL_PREV + Delete previous word at cursor. + + REQ_DEL_LINE + Delete line at cursor. + + REQ_DEL_WORD + Delete word at cursor. + + REQ_CLR_EOL + Clear to end of line. + + REQ_CLR_EOF + Clear to end of field. + + REQ_CLEAR_FIELD + Clear entire field. + + The behavior of the REQ_NEW_LINE and REQ_DEL_PREV requests is + complicated and partly controlled by a pair of forms options. The + special cases are triggered when the cursor is at the beginning of a + field, or on the last line of the field. + + First, we consider REQ_NEW_LINE: + + The normal behavior of REQ_NEW_LINE in insert mode is to break the + current line at the position of the edit cursor, inserting the portion + of the current line after the cursor as a new line following the + current and moving the cursor to the beginning of that new line (you + may think of this as inserting a newline in the field buffer). + + The normal behavior of REQ_NEW_LINE in overlay mode is to clear the + current line from the position of the edit cursor to end of line. The + cursor is then moved to the beginning of the next line. + + However, REQ_NEW_LINE at the beginning of a field, or on the last line + of a field, instead does a REQ_NEXT_FIELD. O_NL_OVERLOAD option is + off, this special action is disabled. + + Now, let us consider REQ_DEL_PREV: + + The normal behavior of REQ_DEL_PREV is to delete the previous + character. If insert mode is on, and the cursor is at the start of a + line, and the text on that line will fit on the previous one, it + instead appends the contents of the current line to the previous one + and deletes the current line (you may think of this as deleting a + newline from the field buffer). + + However, REQ_DEL_PREV at the beginning of a field is instead treated + as a REQ_PREV_FIELD. + + If the O_BS_OVERLOAD option is off, this special action is disabled + and the forms driver just returns E_REQUEST_DENIED. + + See Form Options for discussion of how to set and clear the overload + options. + + Order Requests + + If the type of your field is ordered, and has associated functions for + getting the next and previous values of the type from a given value, + there are requests that can fetch that value into the field buffer: + + REQ_NEXT_CHOICE + Place the successor value of the current value in the buffer. + + REQ_PREV_CHOICE + Place the predecessor value of the current value in the buffer. + + Of the built-in field types, only TYPE_ENUM has built-in successor and + predecessor functions. When you define a field type of your own (see + Custom Validation Types), you can associate our own ordering + functions. + + Application Commands + + Form requests are represented as integers above the curses value + greater than KEY_MAX and less than or equal to the constant + MAX_COMMAND. If your input-virtualization routine returns a value + above MAX_COMMAND, the forms driver will ignore it. + +Field Change Hooks + + It is possible to set function hooks to be executed whenever the + current field or form changes. Here are the functions that support + this: +typedef void (*HOOK)(); /* pointer to function returning void */ + +int set_form_init(FORM *form, /* form to alter */ + HOOK hook); /* initialization hook */ + +HOOK form_init(FORM *form); /* form to query */ + +int set_form_term(FORM *form, /* form to alter */ + HOOK hook); /* termination hook */ + +HOOK form_term(FORM *form); /* form to query */ + +int set_field_init(FORM *form, /* form to alter */ + HOOK hook); /* initialization hook */ + +HOOK field_init(FORM *form); /* form to query */ + +int set_field_term(FORM *form, /* form to alter */ + HOOK hook); /* termination hook */ + +HOOK field_term(FORM *form); /* form to query */ + + These functions allow you to either set or query four different hooks. + In each of the set functions, the second argument should be the + address of a hook function. These functions differ only in the timing + of the hook call. + + form_init + This hook is called when the form is posted; also, just after + each page change operation. + + field_init + This hook is called when the form is posted; also, just after + each field change + + field_term + This hook is called just after field validation; that is, just + before the field is altered. It is also called when the form is + unposted. + + form_term + This hook is called when the form is unposted; also, just + before each page change operation. + + Calls to these hooks may be triggered + 1. When user editing requests are processed by the forms driver + 2. When the current page is changed by set_current_field() call + 3. When the current field is changed by a set_form_page() call + + See Field Change Commands for discussion of the latter two cases. + + You can set a default hook for all fields by passing one of the set + functions a NULL first argument. + + You can disable any of these hooks by (re)setting them to NULL, the + default value. + +Field Change Commands + + Normally, navigation through the form will be driven by the user's + input requests. But sometimes it is useful to be able to move the + focus for editing and viewing under control of your application, or + ask which field it currently is in. The following functions help you + accomplish this: +int set_current_field(FORM *form, /* form to alter */ + FIELD *field); /* field to shift to */ + +FIELD *current_field(FORM *form); /* form to query */ + +int field_index(FORM *form, /* form to query */ + FIELD *field); /* field to get index of */ + + The function field_index() returns the index of the given field in the + given form's field array (the array passed to new_form() or + set_form_fields()). + + The initial current field of a form is the first active field on the + first page. The function set_form_fields() resets this. + + It is also possible to move around by pages. +int set_form_page(FORM *form, /* form to alter */ + int page); /* page to go to (0-origin) */ + +int form_page(FORM *form); /* return form's current page */ + + The initial page of a newly-created form is 0. The function + set_form_fields() resets this. + +Form Options + + Like fields, forms may have control option bits. They can be changed + or queried with these functions: +int set_form_opts(FORM *form, /* form to alter */ + int attr); /* attribute to set */ + +int form_opts_on(FORM *form, /* form to alter */ + int attr); /* attributes to turn on */ + +int form_opts_off(FORM *form, /* form to alter */ + int attr); /* attributes to turn off */ + +int form_opts(FORM *form); /* form to query */ + + By default, all options are on. Here are the available option bits: + + O_NL_OVERLOAD + Enable overloading of REQ_NEW_LINE as described in Editing + Requests. The value of this option is ignored on dynamic fields + that have not reached their size limit; these have no last + line, so the circumstances for triggering a REQ_NEXT_FIELD + never arise. + + O_BS_OVERLOAD + Enable overloading of REQ_DEL_PREV as described in Editing + Requests. + + The option values are bit-masks and can be composed with logical-or in + the obvious way. + +Custom Validation Types + + The form library gives you the capability to define custom validation + types of your own. Further, the optional additional arguments of + set_field_type effectively allow you to parameterize validation types. + Most of the complications in the validation-type interface have to do + with the handling of the additional arguments within custom validation + functions. + + Union Types + + The simplest way to create a custom data type is to compose it from + two preexisting ones: +FIELD *link_fieldtype(FIELDTYPE *type1, + FIELDTYPE *type2); + + This function creates a field type that will accept any of the values + legal for either of its argument field types (which may be either + predefined or programmer-defined). If a set_field_type() call later + requires arguments, the new composite type expects all arguments for + the first type, than all arguments for the second. Order functions + (see Order Requests) associated with the component types will work on + the composite; what it does is check the validation function for the + first type, then for the second, to figure what type the buffer + contents should be treated as. + + New Field Types + + To create a field type from scratch, you need to specify one or both + of the following things: + * A character-validation function, to check each character as it is + entered. + * A field-validation function to be applied on exit from the field. + + Here's how you do that: +typedef int (*HOOK)(); /* pointer to function returning int */ + +FIELDTYPE *new_fieldtype(HOOK f_validate, /* field validator */ + HOOK c_validate) /* character validator */ + + +int free_fieldtype(FIELDTYPE *ftype); /* type to free */ + + At least one of the arguments of new_fieldtype() must be non-NULL. The + forms driver will automatically call the new type's validation + functions at appropriate points in processing a field of the new type. + + The function free_fieldtype() deallocates the argument fieldtype, + freeing all storage associated with it. + + Normally, a field validator is called when the user attempts to leave + the field. Its first argument is a field pointer, from which it can + get to field buffer 0 and test it. If the function returns TRUE, the + operation succeeds; if it returns FALSE, the edit cursor stays in the + field. + + A character validator gets the character passed in as a first + argument. It too should return TRUE if the character is valid, FALSE + otherwise. + + Validation Function Arguments + + Your field- and character- validation functions will be passed a + second argument as well. This second argument is the address of a + structure (which we'll call a pile) built from any of the + field-type-specific arguments passed to set_field_type(). If no such + arguments are defined for the field type, this pile pointer argument + will be NULL. + + In order to arrange for such arguments to be passed to your validation + functions, you must associate a small set of storage-management + functions with the type. The forms driver will use these to synthesize + a pile from the trailing arguments of each set_field_type() argument, + and a pointer to the pile will be passed to the validation functions. + + Here is how you make the association: +typedef char *(*PTRHOOK)(); /* pointer to function returning (char *) */ +typedef void (*VOIDHOOK)(); /* pointer to function returning void */ + +int set_fieldtype_arg(FIELDTYPE *type, /* type to alter */ + PTRHOOK make_str, /* make structure from args */ + PTRHOOK copy_str, /* make copy of structure */ + VOIDHOOK free_str); /* free structure storage */ + + Here is how the storage-management hooks are used: + + make_str + This function is called by set_field_type(). It gets one + argument, a va_list of the type-specific arguments passed to + set_field_type(). It is expected to return a pile pointer to a + data structure that encapsulates those arguments. + + copy_str + This function is called by form library functions that allocate + new field instances. It is expected to take a pile pointer, + copy the pile to allocated storage, and return the address of + the pile copy. + + free_str + This function is called by field- and type-deallocation + routines in the library. It takes a pile pointer argument, and + is expected to free the storage of that pile. + + The make_str and copy_str functions may return NULL to signal + allocation failure. The library routines will that call them will + return error indication when this happens. Thus, your validation + functions should never see a NULL file pointer and need not check + specially for it. + + Order Functions For Custom Types + + Some custom field types are simply ordered in the same well-defined + way that TYPE_ENUM is. For such types, it is possible to define + successor and predecessor functions to support the REQ_NEXT_CHOICE and + REQ_PREV_CHOICE requests. Here's how: +typedef int (*INTHOOK)(); /* pointer to function returning int */ + +int set_fieldtype_arg(FIELDTYPE *type, /* type to alter */ + INTHOOK succ, /* get successor value */ + INTHOOK pred); /* get predecessor value */ + + The successor and predecessor arguments will each be passed two + arguments; a field pointer, and a pile pointer (as for the validation + functions). They are expected to use the function field_buffer() to + read the current value, and set_field_buffer() on buffer 0 to set the + next or previous value. Either hook may return TRUE to indicate + success (a legal next or previous value was set) or FALSE to indicate + failure. + + Avoiding Problems + + The interface for defining custom types is complicated and tricky. + Rather than attempting to create a custom type entirely from scratch, + you should start by studying the library source code for whichever of + the pre-defined types seems to be closest to what you want. + + Use that code as a model, and evolve it towards what you really want. + You will avoid many problems and annoyances that way. The code in the + ncurses library has been specifically exempted from the package + copyright to support this. + + If your custom type defines order functions, have do something + intuitive with a blank field. A useful convention is to make the + successor of a blank field the types minimum value, and its + predecessor the maximum. |