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