home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / qc / qc20 / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-12-14  |  10.9 KB  |  324 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 unknown 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,
  136.                  TRUE, aItem[iCur], cchItem - acchItem[iCur] );
  137.         Itemize( row + iPrev, col,
  138.                  FALSE, aItem[iPrev], cchItem - acchItem[iPrev] );
  139.     }
  140. }
  141.  
  142. /* Box - Draw menu box, filling interior with blanks of the border color.
  143.  *
  144.  * Params: row and col - upper left of box
  145.  *         rowLast and colLast - height and width
  146.  *
  147.  * Return: None
  148.  *
  149.  * Uses:   mnuAtrib
  150.  */
  151. void Box( int row, int col, int rowLast, int colLast )
  152. {
  153.     int i;
  154.     char achT[MAXITEM + 2];         /* Temporary array of characters */
  155.  
  156.     /* Set color and position. */
  157.     _settextposition( row, col );
  158.     _settextcolor( mnuAtrib.fgBorder );
  159.     _setbkcolor( mnuAtrib.bgBorder );
  160.  
  161.     /* Draw box top. */
  162.     achT[0] = mnuAtrib.chNW;
  163.     memset( achT + 1, mnuAtrib.chEW, colLast );
  164.     achT[colLast + 1] = mnuAtrib.chNE;
  165.     achT[colLast + 2] = 0;
  166.     _outtext( achT );
  167.  
  168.     /* Draw box sides and center. */
  169.     achT[0] = mnuAtrib.chNS;
  170.     memset( achT + 1, ' ', colLast );
  171.     achT[colLast + 1] = mnuAtrib.chNS;
  172.     achT[colLast + 2] = 0;
  173.     for( i = 1; i <= rowLast; ++i )
  174.     {
  175.         _settextposition( row + i, col );
  176.         _outtext( achT );
  177.     }
  178.  
  179.     /* Draw box bottom. */
  180.     _settextposition( row + rowLast + 1, col );
  181.     achT[0] = mnuAtrib.chSW;
  182.     memset( achT + 1, mnuAtrib.chEW, colLast );
  183.     achT[colLast + 1] = mnuAtrib.chSE;
  184.     achT[colLast + 2] = 0;
  185.     _outtext( achT );
  186. }
  187.  
  188. /* Itemize - Display one selection (item) of a menu. This function
  189.  * is normally only used internally by Menu.
  190.  *
  191.  * Params: row and col - top left of menu
  192.  *         fCur - flag set if item is current selection
  193.  *         itm - structure containing item text and index of highlight
  194.  *         cBlank - count of blanks to fill
  195.  *
  196.  * Return: none
  197.  *
  198.  * Uses:   mnuAtrib
  199.  */
  200. void Itemize( int row, int col, int fCur, struct ITEM itm, int cBlank )
  201. {
  202.     int i;
  203.     char achT[MAXITEM];             /* Temporary array of characters */
  204.  
  205.     /* Set text position and color. */
  206.     _settextposition( row, col );
  207.     if( fCur )
  208.     {
  209.         _settextcolor( mnuAtrib.fgSelect );
  210.         _setbkcolor( mnuAtrib.bgSelect );
  211.     }
  212.     else
  213.     {
  214.         _settextcolor( mnuAtrib.fgNormal );
  215.         _setbkcolor( mnuAtrib.bgNormal );
  216.     }
  217.  
  218.     /* Display item and fill blanks. */
  219.     strcat( strcpy( achT, " " ), itm.achItem );
  220.     _outtext( achT );
  221.     memset( achT, ' ', cBlank-- );
  222.     achT[cBlank] = 0;
  223.     _outtext( achT );
  224.  
  225.     /* Set position and color of highlight character, then display it. */
  226.     i = itm.iHilite;
  227.     _settextposition( row, col + i + 1 );
  228.     if( fCur )
  229.     {
  230.         _settextcolor( mnuAtrib.fgSelHilite );
  231.         _setbkcolor( mnuAtrib.bgSelHilite );
  232.     }
  233.     else
  234.     {
  235.         _settextcolor( mnuAtrib.fgNormHilite );
  236.         _setbkcolor( mnuAtrib.bgNormHilite );
  237.     }
  238.     _outchar( itm.achItem[i] );
  239. }
  240.  
  241. /* GetKey - Gets a key from the keyboard. This routine distinguishes
  242.  * between ASCII keys and function or control keys with different shift
  243.  * states. It also accepts a flag to return immediately if no key is
  244.  * available.
  245.  *
  246.  * Params: fWait - Code to indicate how to handle keyboard buffer:
  247.  *   NO_WAIT     Return 0 if no key in buffer, else return key
  248.  *   WAIT        Return first key if available, else wait for key
  249.  *   CLEAR_WAIT  Throw away any key in buffer and wait for new key
  250.  *
  251.  * Return: One of the following:
  252.  *
  253.  *   Keytype                                High Byte    Low Byte
  254.  *   -------                                ---------    --------
  255.  *   No key available (only with NO_WAIT)       0           0
  256.  *   ASCII value                                0        ASCII code
  257.  *   Unshifted function or keypad               1        scan code
  258.  *   Shifted function or keypad                 2        scan code
  259.  *   CTRL function or keypad                    3        scan code
  260.  *   ALT function or keypad                     4        scan code
  261.  *
  262.  * Note:   getkey cannot return codes for keys not recognized by BIOS
  263.  *         int 16, such as the CTRL-UP or the 5 key on the numeric keypad.
  264.  */
  265. unsigned GetKey( int fWait )
  266. {
  267.     unsigned uKey, uShift;
  268.  
  269.     /* If CLEAR_WAIT, drain the keyboard buffer. */
  270.     if( fWait == CLEAR_WAIT )
  271.         while( _bios_keybrd( _KEYBRD_READY ) )
  272.             _bios_keybrd( _KEYBRD_READ );
  273.  
  274.     /* If NO_WAIT, return 0 if there is no key ready. */
  275.     if( !fWait && !_bios_keybrd( _KEYBRD_READY ) )
  276.         return FALSE;
  277.  
  278.     /* Get key code. */
  279.     uKey = _bios_keybrd( _KEYBRD_READ );
  280.  
  281.     /* If low byte is not zero, it's an ASCII key. Check scan code to see
  282.      * if it's on the numeric keypad. If not, clear high byte and return.
  283.      */
  284.     if( uKey & 0x00ff )
  285.         if( (uKey >> 8) < 69 )
  286.             return( uKey & 0x00ff );
  287.  
  288.     /* For function keys and numeric keypad, put scan code in low byte
  289.      * and shift state codes in high byte.
  290.      */
  291.     uKey >>= 8;
  292.     uShift = _bios_keybrd( _KEYBRD_SHIFTSTATUS ) & 0x000f;
  293.     switch( uShift )
  294.     {
  295.         case 0:
  296.             return( 0x0100 | uKey );  /* None (1)    */
  297.         case 1:
  298.         case 2:
  299.         case 3:
  300.             return( 0x0200 | uKey );  /* Shift (2)   */
  301.         case 4:
  302.             return( 0x0300 | uKey );  /* Control (3) */
  303.         case 8:
  304.             return( 0x0400 | uKey );  /* Alt (4)     */
  305.     }
  306. }
  307.  
  308. /* _outchar - Display a character. This is the character equivalent of
  309.  * _outtext. It is affected by _settextposition, _settextcolor, and
  310.  * _setbkcolor. It should not be used in loops. Build strings and then
  311.  * _outtext to show multiple characters.
  312.  *
  313.  * Params: out - character to be displayed
  314.  *
  315.  * Return: none
  316.  */
  317. void _outchar( char out )
  318. {
  319.     static char achT[2] = " ";      /* Temporary array of characters */
  320.  
  321.     achT[0] = out;
  322.     _outtext( achT );
  323. }
  324.