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