home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / c / other / utility / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-29  |  10.8 KB  |  322 lines

  1. /* MENU - Module of functions to put menus on the screen and handle keyboard
  2.  * input. To use it, include the MENU.H file in your program. The following
  3.  * functions are public:
  4.  *
  5.  *   Menu       -   Puts a menu on screen and reads input for it
  6.  *   Box        -   Puts a box on screen (fill it yourself)
  7.  *   GetKey     -   Gets ASCII or function key
  8.  *   _outchar   -   Displays character using current text position and color
  9.  *
  10.  * The following structures are defined:
  11.  *
  12.  *   MENU       -   Defines menu colors, box type, and centering
  13.  *   ITEM       -   Defines text of menu item and index of highlight character
  14.  *
  15.  * The global variable "mnuAtrib" has type MENU. Change this variable to
  16.  * change menu appearance.
  17.  */
  18.  
  19. #include <string.h>
  20. #include <stddef.h>
  21. #include <ctype.h>
  22. #include <graph.h>
  23. #include <bios.h>
  24. #include "menu.h"
  25.  
  26. /* Default menu attribute. The default works for color or B&W. You can
  27.  * override the default value by defining your own MENU variable and
  28.  * assigning it to mnuAtrib. Or you can modify specific fields at
  29.  * run time. For example, you could use a different attribute for color
  30.  * than for black and white.
  31.  */
  32. struct MENU mnuAtrib =
  33. {
  34.     _TBLACK, _TBLACK, _TWHITE, _TBRIGHTWHITE, _TBRIGHTWHITE,
  35.     _TWHITE, _TWHITE, _TBLACK, _TWHITE, _TBLACK,
  36.     TRUE,
  37.     '┌', '┐', '┘', '└', '│', '─'
  38. };
  39.  
  40. /* Menu - Puts menu on screen and reads menu input from keyboard. When a
  41.  * highlighted hot key or ENTER is pressed, returns the index of the
  42.  * selected menu item.
  43.  *
  44.  * Params: row and col - If "fCentered" attribute of "mnuAtrib" is true,
  45.  *           center row and column of menu; otherwise top left of menu
  46.  *         aItem - array of structure containing the text of each item
  47.  *           and the index of the highlighted hot key
  48.  *         iCur - index of the current selection--pass 0 for first item,
  49.  *           or maintain a static value
  50.  *
  51.  * Return: The index of the selected item
  52.  *
  53.  * Uses:   mnuAtrib
  54.  */
  55. int Menu( int row, int col, struct ITEM aItem[], int iCur )
  56. {
  57.     int cItem, cchItem = 2; /* Counts of items and chars per item       */
  58.     int i, iPrev;           /* Indexes - temporary and previous         */
  59.     int acchItem[MAXITEM];  /* Array of counts of character in items    */
  60.     char *pchT;             /* Temporary character pointer              */
  61.     char achHilite[36];     /* Array for highlight characters           */
  62.     unsigned uKey;          /* Unsigned key code                        */
  63.     long bgColor;           /* Screen color, position, and cursor       */
  64.     short fgColor;
  65.     struct rccoord rc;
  66.     unsigned fCursor;
  67.  
  68.     /* Save screen information. */
  69.     fCursor = _displaycursor( _GCURSOROFF );
  70.     bgColor = _getbkcolor();
  71.     fgColor = _gettextcolor();
  72.     rc = _gettextposition();
  73.  
  74.     /* Count items, find longest, and put count of each in array. Also,
  75.      * put the highlighted character from each in a string.
  76.      */
  77.     for( cItem = 0; aItem[cItem].achItem[0]; cItem++ )
  78.     {
  79.         acchItem[cItem] = strlen( aItem[cItem].achItem );
  80.         cchItem = (acchItem[cItem] > cchItem) ? acchItem[cItem] : cchItem;
  81.         i = aItem[cItem].iHilite;
  82.         achHilite[cItem] = aItem[cItem].achItem[i];
  83.     }
  84.     cchItem += 2;
  85.     achHilite[cItem] = 0;          /* Null-terminate and lowercase string  */
  86.     strlwr( achHilite );
  87.  
  88.     /* Adjust if centered, and draw menu box. */
  89.     if( mnuAtrib.fCentered )
  90.     {
  91.         row -= cItem / 2;
  92.         col -= cchItem / 2;
  93.     }
  94.     Box( row++, col++, cItem, cchItem );
  95.  
  96.     /* Put items on menu. */
  97.     for( i = 0; i < cItem; i++ )
  98.     {
  99.         if( i == iCur )
  100.             Itemize( row + i, col, TRUE, aItem[i], cchItem - acchItem[i] );
  101.         else
  102.             Itemize( row + i, col, FALSE, aItem[i], cchItem - acchItem[i] );
  103.     }
  104.  
  105.     while( TRUE )
  106.     {
  107.         /* Wait until a uKey is pressed, then evaluate it. */
  108.         uKey = GetKey( WAIT );
  109.         switch( uKey )
  110.         {
  111.             case U_UP:                      /* Up key       */
  112.                 iPrev = iCur;
  113.                 iCur = (iCur > 0) ? (--iCur % cItem) : cItem - 1;
  114.                 break;
  115.             case U_DN:                      /* Down key     */
  116.                 iPrev = iCur;
  117.                 iCur = (iCur < cItem) ? (++iCur % cItem) : 0;
  118.                 break;
  119.             default:
  120.                 if( uKey > 256 )             /* Ignore unknown function key  */
  121.                     continue;
  122.                 pchT = strchr( achHilite, (char)tolower( uKey ) );
  123.                 if( pchT != NULL )          /* If in highlight string,      */
  124.                     iCur = pchT - achHilite;/*   evaluate and fall through  */
  125.                 else
  126.                     continue;               /* Ignore unkown ASCII key      */
  127.             case ENTER:
  128.                 _setbkcolor( bgColor );
  129.                 _settextcolor( fgColor );
  130.                 _settextposition( rc.row, rc.col );
  131.                 _displaycursor( fCursor );
  132.                 return iCur;
  133.         }
  134.         /* Redisplay current and previous. */
  135.         Itemize( row + iCur, col, TRUE, aItem[iCur], cchItem - acchItem[iCur] );
  136.         Itemize( row + iPrev, col, FALSE, aItem[iPrev], cchItem - acchItem[iPrev] );
  137.     }
  138. }
  139.  
  140. /* Box - Draw menu box, filling interior with blanks of the border color.
  141.  *
  142.  * Params: row and col - upper left of box
  143.  *         rowLast and colLast - height and width
  144.  *
  145.  * Return: None
  146.  *
  147.  * Uses:   mnuAtrib
  148.  */
  149. void Box( int row, int col, int rowLast, int colLast )
  150. {
  151.     int i;
  152.     char achT[MAXITEM + 2];         /* Temporary array of characters */
  153.  
  154.     /* Set color and position. */
  155.     _settextposition( row, col );
  156.     _settextcolor( mnuAtrib.fgBorder );
  157.     _setbkcolor( mnuAtrib.bgBorder );
  158.  
  159.     /* Draw box top. */
  160.     achT[0] = mnuAtrib.chNW;
  161.     memset( achT + 1, mnuAtrib.chEW, colLast );
  162.     achT[colLast + 1] = mnuAtrib.chNE;
  163.     achT[colLast + 2] = 0;
  164.     _outtext( achT );
  165.  
  166.     /* Draw box sides and center. */
  167.     achT[0] = mnuAtrib.chNS;
  168.     memset( achT + 1, ' ', colLast );
  169.     achT[colLast + 1] = mnuAtrib.chNS;
  170.     achT[colLast + 2] = 0;
  171.     for( i = 1; i <= rowLast; ++i )
  172.     {
  173.         _settextposition( row + i, col );
  174.         _outtext( achT );
  175.     }
  176.  
  177.     /* Draw box bottom. */
  178.     _settextposition( row + rowLast + 1, col );
  179.     achT[0] = mnuAtrib.chSW;
  180.     memset( achT + 1, mnuAtrib.chEW, colLast );
  181.     achT[colLast + 1] = mnuAtrib.chSE;
  182.     achT[colLast + 2] = 0;
  183.     _outtext( achT );
  184. }
  185.  
  186. /* Itemize - Display one (item) selection of a menu. This function
  187.  * is normally only used internally by Menu.
  188.  *
  189.  * Params: row and col - top left of menu
  190.  *         fCur - flag set if item is current selection
  191.  *         itm - structure containing item text and index of highlight
  192.  *         cBlank - count of blanks to fill
  193.  *
  194.  * Return: none
  195.  *
  196.  * Uses:   mnuAtrib
  197.  */
  198. void Itemize( int row, int col, int fCur, struct ITEM itm, int cBlank )
  199. {
  200.     int i;
  201.     char achT[MAXITEM];             /* Temporary array of characters */
  202.  
  203.     /* Set text position and color. */
  204.     _settextposition( row, col );
  205.     if( fCur )
  206.     {
  207.         _settextcolor( mnuAtrib.fgSelect );
  208.         _setbkcolor( mnuAtrib.bgSelect );
  209.     }
  210.     else
  211.     {
  212.         _settextcolor( mnuAtrib.fgNormal );
  213.         _setbkcolor( mnuAtrib.bgNormal );
  214.     }
  215.  
  216.     /* Display item and fill blanks. */
  217.     strcat( strcpy( achT, " " ), itm.achItem );
  218.     _outtext( achT );
  219.     memset( achT, ' ', cBlank-- );
  220.     achT[cBlank] = 0;
  221.     _outtext( achT );
  222.  
  223.     /* Set position and color of highlight character, then display it. */
  224.     i = itm.iHilite;
  225.     _settextposition( row, col + i + 1 );
  226.     if( fCur )
  227.     {
  228.         _settextcolor( mnuAtrib.fgSelHilite );
  229.         _setbkcolor( mnuAtrib.bgSelHilite );
  230.     }
  231.     else
  232.     {
  233.         _settextcolor( mnuAtrib.fgNormHilite );
  234.         _setbkcolor( mnuAtrib.bgNormHilite );
  235.     }
  236.     _outchar( itm.achItem[i] );
  237. }
  238.  
  239. /* GetKey - Gets a key from the keyboard. This routine distinguishes
  240.  * between ASCII keys and function or control keys with different shift
  241.  * states. It also accepts a flag to return immediately if no key is
  242.  * available.
  243.  *
  244.  * Params: fWait - Code to indicate how to handle keyboard buffer:
  245.  *   NO_WAIT     Return 0 if no key in buffer, else return key
  246.  *   WAIT        Return first key if available, else wait for key
  247.  *   CLEAR_WAIT  Throw away any key in buffer and wait for new key
  248.  *
  249.  * Return: One of the following:
  250.  *
  251.  *   Keytype                                High Byte    Low Byte
  252.  *   -------                                ---------    --------
  253.  *   No key available (only with NO_WAIT)       0           0
  254.  *   ASCII value                                0        ASCII code
  255.  *   Unshifted function or keypad               1        scan code
  256.  *   Shifted function or keypad                 2        scan code
  257.  *   CTRL function or keypad                    3        scan code
  258.  *   ALT function or keypad                     4        scan code
  259.  *
  260.  * Note:   getkey cannot return codes for keys not recognized by BIOS
  261.  *         int 16, such as the CTRL-UP or the 5 key on the numeric keypad.
  262.  */
  263. unsigned GetKey( int fWait )
  264. {
  265.     unsigned uKey, uShift;
  266.  
  267.     /* If CLEAR_WAIT, drain the keyboard buffer. */
  268.     if( fWait == CLEAR_WAIT )
  269.         while( _bios_keybrd( _KEYBRD_READY ) )
  270.             _bios_keybrd( _KEYBRD_READ );
  271.  
  272.     /* If NO_WAIT, return 0 if there is no key ready. */
  273.     if( !fWait && !_bios_keybrd( _KEYBRD_READY ) )
  274.         return FALSE;
  275.  
  276.     /* Get key code. */
  277.     uKey = _bios_keybrd( _KEYBRD_READ );
  278.  
  279.     /* If low byte is not zero, its an ASCII key. Check scan code to see
  280.      * if it's on the numeric keypad. If not, clear high byte and return.
  281.      */
  282.     if( uKey & 0x00ff )
  283.         if( (uKey >> 8) < 69 )
  284.             return( uKey & 0x00ff );
  285.  
  286.     /* For function keys and numeric keypad, put scan code in low byte
  287.      * and shift state codes in high byte.
  288.      */
  289.     uKey >>= 8;
  290.     uShift = _bios_keybrd( _KEYBRD_SHIFTSTATUS ) & 0x000f;
  291.     switch( uShift )
  292.     {
  293.         case 0:
  294.             return( 0x0100 | uKey );  /* None (1)    */
  295.         case 1:
  296.         case 2:
  297.         case 3:
  298.             return( 0x0200 | uKey );  /* Shift (2)   */
  299.         case 4:
  300.             return( 0x0300 | uKey );  /* Control (3) */
  301.         case 8:
  302.             return( 0x0400 | uKey );  /* Alt (4)     */
  303.     }
  304. }
  305.  
  306. /* _outchar - Display a character. This is the character equivalent of
  307.  * _outtext. It is affected by _settextposition, _settextcolor, and
  308.  * _setbkcolor. It should not be used in loops. Build strings and then
  309.  * _outtext to show multiple characters.
  310.  *
  311.  * Params: out - character to be displayed
  312.  *
  313.  * Return: none
  314.  */
  315. void _outchar( char out )
  316. {
  317.     static char achT[2] = " ";      /* Temporary array of characters */
  318.  
  319.     achT[0] = out;
  320.     _outtext( achT );
  321. }
  322.