diff options
Diffstat (limited to 'contrib/ncurses/misc/ncurses-intro.doc')
-rw-r--r-- | contrib/ncurses/misc/ncurses-intro.doc | 2530 |
1 files changed, 0 insertions, 2530 deletions
diff --git a/contrib/ncurses/misc/ncurses-intro.doc b/contrib/ncurses/misc/ncurses-intro.doc deleted file mode 100644 index e45ca3530f20..000000000000 --- a/contrib/ncurses/misc/ncurses-intro.doc +++ /dev/null @@ -1,2530 +0,0 @@ - - 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); - -main(int argc, char *argv[]) -{ - /* 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) noecho(); /* don't echo input */ - - if (has_colors()) - { - start_color(); - - /* - * Simple color assignment, often all we need. - */ - init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK); - init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK); - init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK); - init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK); - init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK); - init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK); - init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK); - init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK); - } - - for (;;) - { - int c = getch(); /* refresh, accept single keystroke of input */ - - /* 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. |