home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR14 / MENUTO.ZIP / MENUTO.PRG
Text File  |  1993-11-09  |  22KB  |  630 lines

  1. /*
  2.  * File......: MENUTO.PRG
  3.  * Author....: Ted Means
  4.  * Date......: $Date:   09 Nov 1993 18:00:00  $
  5.  * Revision..: $Revision:   1.8  $
  6.  * Log file..: $Logfile:   C:/nanfor/src/menuto.prv  $
  7.  * 
  8.  * This is an original work by Ted Means and is placed in the
  9.  * public domain.
  10.  *
  11.  * Modification history:
  12.  * ---------------------
  13.  *
  14.  * $Log:   C:/nanfor/src/menuto.prv  $
  15.  *
  16.  *    Rev 1.8   09 Nov 1993 18:00:00   SYLVAIN LARCHE
  17.  * When not initializing the variable in MENU TO <var> you get an error
  18.  * Sometime IE 667 Eval Stack Fault or BASE/1073 Argument error: <.
  19.  * The problem is that when the the preprocessor translate the MENU TO <var>
  20.  * it create a codeblock with NIL "{ || NIL }" and in the code it was testing
  21.  * if bGetSet == NIL then bGetSet := { || 1 } it should read
  22.  * if ( Eval( bGetSet ) == NIL ) then bGetSet := { || 1 }
  23.  *
  24.  * Also when using prompt with Col() for the next position where to output
  25.  * the prompt it did not work because the trigger display would change the
  26.  * cursor position thus not being the right column.
  27.  *
  28.  *  display( nRow, nCol - 1 + nTrigger, cTrigger, cTriggerColor )
  29.  *  SetPos( nRow, nCol + Len( cPrompt ) ) ==> add this line to reset Col()
  30.  *
  31.  *    Rev 1.7   02 Mar 1993 01:03:20   GLENN
  32.  * When you have SET MESSAGE x CENTER set and you do a
  33.  * 
  34.  *     @ x,y PROMPT "XXX" MESSAGE "mmmm"
  35.  * 
  36.  * the message is centered based upon the length of the prompt rather than
  37.  * the message. Gary F. Alderson 76666,357 found and fixed the bug.
  38.  * 
  39.  *    Rev 1.6   12 Jan 1993 08:57:08   GLENN
  40.  * Ted fixed a bug in which an array bounds error could occur if you
  41.  * used nested submenus.
  42.  * 
  43.  *    Rev 1.5   16 Oct 1992 00:20:28   GLENN
  44.  * Cleaned up documentation header.
  45.  * 
  46.  *    Rev 1.4   16 Oct 1992 00:08:44   GLENN
  47.  * Just making sure we had Ted's latest revision.
  48.  * 
  49.  *    Rev 1.3   13 Oct 1992 20:45:46   GLENN
  50.  * Complete rewrite by Ted Means, dumping assembler version for a
  51.  * Clipper version.
  52.  * 
  53.  *    Rev 1.2   15 Aug 1991 23:03:54   GLENN
  54.  * Forest Belt proofread/edited/cleaned up doc
  55.  * 
  56.  *    Rev 1.1   14 Jun 1991 19:52:16   GLENN
  57.  * Minor edit to file header
  58.  * 
  59.  *    Rev 1.0   01 Apr 1991 01:01:42   GLENN
  60.  * Nanforum Toolkit
  61.  *
  62.  */
  63.  
  64. /*  $DOC$
  65.  *  $FUNCNAME$
  66.  *     FT_Prompt()
  67.  *  $CATEGORY$
  68.  *     Menus/Prompts
  69.  *  $ONELINER$
  70.  *     Define a menu item for use with FT_MenuTo()
  71.  *  $SYNTAX$
  72.  *     #include "FTMENUTO.CH"
  73.  *
  74.  *     @ <nRow>, <nCol> PROMPT <cPrompt>                     ;
  75.  *                      [COLOR <cColor>]                     ;
  76.  *                      [MESSAGE <cMessage>]                 ;
  77.  *                      [MSGROW <nMsgRow>]                   ;
  78.  *                      [MSGCOL <nMsgCol>]                   ;
  79.  *                      [MSGCOLOR <cMsgColor>]               ;
  80.  *                      [TRIGGER <nTrigger>]                 ;
  81.  *                      [TRIGGERCOLOR <cTriggerColor>]       ;
  82.  *                      [HOME <nHome>]                       ;
  83.  *                      [END <nEnd>]                         ;
  84.  *                      [UP <nUp>]                           ;
  85.  *                      [DOWN <nDown>]                       ;
  86.  *                      [LEFT <nLeft>]                       ;
  87.  *                      [RIGHT <nRight>]                     ;
  88.  *                      [EXECUTE <bExec>]                    ;
  89.  *
  90.  *  $ARGUMENTS$
  91.  *     <nRow> is the row at which the prompt is to appear.
  92.  *
  93.  *     <nCol> is the column at which the prompt will appear.
  94.  *
  95.  *     <cPrompt> is the menu item string.
  96.  *
  97.  *     <cColor> is optional and is the color attribute of the prompt.  Note
  98.  *     that two colors are required; one for the standard setting and one
  99.  *     for the enhanced setting (i.e. the light bar color).  See the example
  100.  *     below if this isn't clear.  If <cColor> is not specified then the
  101.  *     current SetColor() value is used by default.
  102.  *
  103.  *     <cMessage> is optional and is the message associated with the
  104.  *     prompt. If not specified, then no message will be displayed.
  105.  *
  106.  *     <nMsgRow> is optional and is the row at which the message, if any,
  107.  *     will appear.  If not specified, the default is the current setting
  108.  *     of the SET MESSAGE TO command.
  109.  *
  110.  *     <nMsgCol> is optional and is the column at which the message, if
  111.  *     any, will appear.  If not specified, the default is either zero or
  112.  *     centered, depending on the current setting of the CENTER option of
  113.  *     the SET MESSAGE TO command.
  114.  *
  115.  *     <cMsgColor> is optional and is the color attribute of the message.
  116.  *     If not specified, the default is the same as the prompt color.
  117.  *
  118.  *     <nTrigger> is optional and is the position within the prompt string
  119.  *     where the trigger character is located.  If not specified, the
  120.  *     default is one.
  121.  *
  122.  *     <cTriggerColor> is optional and is the color attribute of the trigger
  123.  *     character.  Note that two colors are required; one for the standard
  124.  *     setting and one for the enhanced setting (i.e. the light bar color).
  125.  *     See the example below if this isn't clear.  If <cTriggerColor> is not
  126.  *     specified then the default is the same color as the rest of the
  127.  *     prompt.
  128.  *
  129.  *     <nHome> is optional and specifies which prompt becomes active
  130.  *     when the home key is pressed.  If not specified, the default is
  131.  *     the first prompt.
  132.  *
  133.  *     <nEnd> is optional and specifies which prompt becomes active
  134.  *     when the end key is pressed.  If not specified, the default is
  135.  *     the last prompt.
  136.  *
  137.  *     <nUp> is optional and specifies which prompt becomes active
  138.  *     when the up arrow key is pressed.  If not specified, the
  139.  *     default is the previous prompt.  The current setting of SET
  140.  *     WRAP TO is obeyed.
  141.  *
  142.  *     <nDown> is optional and specifies which prompt becomes
  143.  *     active when the down arrow key is pressed.  If not
  144.  *     specified, the default is the next prompt.  The current
  145.  *     setting of SET WRAP TO is obeyed.
  146.  *
  147.  *     <nRight> is optional and specifies which prompt becomes
  148.  *     active when the right arrow key is pressed.  If not
  149.  *     specified, the default is the next prompt.  The current
  150.  *     setting of SET WRAP TO is obeyed.
  151.  *
  152.  *     <nLeft> is optional and specifies which prompt becomes
  153.  *     active when the left arrow is pressed.  If not specified,
  154.  *     the default is the previous prompt.  The current setting of
  155.  *     SET WRAP TO is obeyed.
  156.  *
  157.  *     <bExec> is optional and is a code block to evaluate whenever
  158.  *     the menu item to which it belongs is selected.
  159.  *  $DESCRIPTION$
  160.  *     Clipper's @...PROMPT and MENU TO commands are fine as far as
  161.  *     they go.  But many times you need more flexibility.  As
  162.  *     you'll no doubt notice if you read the argument list, this
  163.  *     function is almost completely flexible. You can adjust
  164.  *     locations and colors for every part of the prompt and its
  165.  *     associated message.  In addition, since you can control the
  166.  *     effect of the arrow keys, you can allow both horizontal and
  167.  *     vertical movement, or even disable certain arrow keys if you
  168.  *     so desire.  Support for nested menus is also available, since
  169.  *     the prompts are stored in stack-based static arrays.
  170.  *
  171.  *     Note that this command can also be called using function-style
  172.  *     syntax.  See the entry for FT_PROMPT() for further details.
  173.  *
  174.  *     This enhanced version of @...PROMPT requires the inclusion of
  175.  *     the header file FTMENUTO.CH in any source file that uses it.
  176.  *     It is may be used in place of the standard Clipper @...PROMPT
  177.  *     command.  However, in the interests of functionality it is NOT
  178.  *     100% compatible.  No whining!  If compatibility is such a big
  179.  *     deal then use the standard Clipper commands.
  180.  *
  181.  *  $EXAMPLES$
  182.  *    #include "FTMENUTO.CH"
  183.  *
  184.  *    // Simple prompt
  185.  *    @ 1, 1 PROMPT "Menu choice #1"
  186.  *
  187.  *    // Prompt with color
  188.  *    @ 3, 1 PROMPT "Menu choice #2" COLOR "W+/R,W+/B"
  189.  *
  190.  *    // Prompt with a message
  191.  *    @ 5, 1 PROMPT "Menu choice #3" MESSAGE "Go to lunch"
  192.  *
  193.  *    // Prompt with pinpoint message control
  194.  *    @ 7, 1 PROMPT "Menu choice #4" MESSAGE "Drop Dead" ;
  195.  *                   MSGROW 22 MSGCOL 4 MSGCOLOR "GR+/N"
  196.  *
  197.  *    // Prompt with a trigger character ("#" character)
  198.  *    @11, 1 PROMPT "Menu choice #6" TRIGGER 13
  199.  *
  200.  *    // Prompt with trigger character color control
  201.  *    @13, 1 PROMPT "Menu Choice #7" TRIGGER 13 TRIGGERCOLOR "R+/BG,G+/N"
  202.  *
  203.  *    // Prompt with right and left arrow keys disabled
  204.  *    @15, 1 PROMPT "Menu Choice #8" RIGHT 8 LEFT 8
  205.  *  $INCLUDE$
  206.  *     FTMENUTO.CH
  207.  *  $SEEALSO$
  208.  *   
  209.  *  $END$
  210.  */
  211.  
  212. #include "SETCURS.CH"
  213. #include "INKEY.CH"
  214. #INCLUDE "Common.ch"
  215.  
  216. #xcommand if <true> then <action> => ;
  217.           if <true> ; <action> ; end
  218.  
  219. #xtranslate display( <row>, <col>, <stuff>, <color> ) => ;
  220.             setpos( <row>, <col> ) ; dispout( <stuff>, <color> )
  221.  
  222. #xtranslate EnhColor( <colorspec> ) => ;
  223.             substr( <colorspec>, at( ",", <colorspec> ) + 1 )
  224.  
  225. #xtranslate isOkay( <exp> ) => ;
  226.             ( <exp> \> 0 .and. <exp> \<= nCount )
  227.  
  228. #xtranslate isBetween( <val>, <lower>, <upper> ) => ;
  229.             ( <val> \>= <lower> .and. <val> \<= <upper> )
  230.  
  231. #define nTriggerInkey asc( upper( substr( cPrompt, nTrigger, 1 ) ) )
  232. #define cTrigger substr( cPrompt, nTrigger, 1 )
  233. #define nCurrent nMenu,nActive
  234. #define nLast nMenu,nPrev
  235.  
  236. // These arrays hold information about each menu item
  237.  
  238. static aRow          := {{}}
  239. static aCol          := {{}}
  240. static aPrompt       := {{}}
  241. static aColor        := {{}}
  242. static aMsgRow       := {{}}
  243. static aMsgCol       := {{}}
  244. static aMessage      := {{}}
  245. static aMsgColor     := {{}}
  246. static aTrigger      := {{}}
  247. static aTriggerInkey := {{}}
  248. static aTriggerColor := {{}}
  249. static aHome         := {{}}
  250. static aEnd          := {{}}
  251. static aUp           := {{}}
  252. static aDown         := {{}}
  253. static aLeft         := {{}}
  254. static aRight        := {{}}
  255. static aExecute      := {{}}
  256. static nLevel        := 1
  257.  
  258. function FT_Prompt( nRow,    nCol,    cPrompt,  cColor,      ;
  259.                     nMsgRow, nMsgCol, cMessage, cMsgColor,   ;
  260.                     nTrigger, cTriggerColor, nHome, nEnd,    ;
  261.                     nUp, nDown, nLeft, nRight, bExecute      )
  262.  
  263. // If the prompt color setting is not specified, use default
  264.  
  265. if cColor  == NIL then cColor  := setcolor()
  266.  
  267. // If no message is supplied, set message values to NIL
  268.  
  269. if cMessage == NIL
  270.  
  271.    nMsgRow := nMsgCol := cMsgColor := NIL
  272.  
  273. else
  274.  
  275.    // If message row not supplied, use the default
  276.  
  277.    if nMsgRow == NIL then nMsgRow := set( _SET_MESSAGE )
  278.  
  279.    // If message column not supplied, use the default
  280.  
  281.    if nMsgCol == NIL
  282.       if set( _SET_MCENTER )
  283.          nMsgCol := int( ( maxcol() + 1 - len( cMessage ) ) / 2 )
  284.       else
  285.          nMsgCol := 0
  286.       endif
  287.    endif
  288.  
  289.    // If message color not specified, use the default
  290.  
  291.    if cMsgColor == NIL then cMsgColor := cColor
  292. endif
  293.  
  294. // If trigger values not specifed, set the defaults
  295.  
  296. if nTrigger       == NIL then nTrigger      := 1
  297. if cTriggerColor  == NIL then cTriggerColor := cColor
  298.  
  299. // Now add elements to the static arrays -- nLevel indicates the recursion
  300. // level, which allows for nested menus.
  301.  
  302. aadd(          aRow[ nLevel ], nRow          )
  303. aadd(          aCol[ nLevel ], nCol          )
  304. aadd(       aPrompt[ nLevel ], cPrompt       )
  305. aadd(        aColor[ nLevel ], cColor        )
  306. aadd(       aMsgRow[ nLevel ], nMsgRow       )
  307. aadd(       aMsgCol[ nLevel ], nMsgCol       )
  308. aadd(      aMessage[ nLevel ], cMessage      )
  309. aadd(     aMsgColor[ nLevel ], cMsgColor     )
  310. aadd(      aTrigger[ nLevel ], nTrigger      )
  311. aadd( aTriggerInkey[ nLevel ], nTriggerInkey )
  312. aadd( aTriggerColor[ nLevel ], cTriggerColor )
  313. aadd(         aHome[ nLevel ], nHome         )
  314. aadd(          aEnd[ nLevel ], nEnd          )
  315. aadd(           aUp[ nLevel ], nUp           )
  316. aadd(         aDown[ nLevel ], nDown         )
  317. aadd(         aLeft[ nLevel ], nLeft         )
  318. aadd(        aRight[ nLevel ], nRight        )
  319. aadd(      aExecute[ nLevel ], bExecute      )
  320.  
  321. // Now display the prompt for the sake of compatibility
  322.  
  323. dispbegin()
  324. display( nRow, nCol, cPrompt, cColor )
  325. display( nRow, nCol - 1 + nTrigger, cTrigger, cTriggerColor )
  326. SetPos( nRow, nCol + Len( cPrompt ) )
  327. dispend()
  328.  
  329. return NIL
  330.  
  331.  
  332.  
  333. /*  $DOC$
  334.  *  $FUNCNAME$
  335.  *     FT_MenuTo()
  336.  *  $CATEGORY$
  337.  *     Menus/Prompts
  338.  *  $ONELINER$
  339.  *     Execute light bar menu using prompts created with @...PROMPT
  340.  *  $SYNTAX$
  341.  *     #include "FTMENUTO.CH"
  342.  *
  343.  *     MENU TO <var> [COLD]
  344.  *  $ARGUMENTS$
  345.  *     <var> is the name of the variable to which the result of the menu
  346.  *     selection should be assigned.
  347.  *
  348.  *     [COLD] is optional and if specified indicates that trigger characters
  349.  *     should be treated as "cold," i.e. rather than causing the menu item
  350.  *     to be selected it only causes the light bar to move to that selection.
  351.  *  $DESCRIPTION$
  352.  *     This enhanced version of MENU TO requires the inclusion of the header
  353.  *     file FTMENUTO.CH in any source file that uses it.  It may be used in
  354.  *     place of the standard Clipper MENU TO command.  However, in the
  355.  *     interests of functionality it is NOT 100% compatible (in particular,
  356.  *     you should make sure that the target memvar exists before executing
  357.  *     the menu -- the Clipper version will create a PRIVATE memvar for you
  358.  *     if it does not already exist, but this version does not).  No whining!
  359.  *     If compatibility is such a big deal then use the standard Clipper
  360.  *     command.
  361.  *
  362.  *     Note that this command can also be called using function-style
  363.  *     syntax.  See the entry for FT_MENUTO() for further details.
  364.  *  $EXAMPLES$
  365.  *    #include "FTMENUTO.CH"
  366.  *
  367.  *    // Simple command
  368.  *
  369.  *    MENU TO memvar
  370.  *
  371.  *  $INCLUDE$
  372.  *    FTMENUTO.CH
  373.  *  $SEEALSO$
  374.  *    "@...PROMPT"
  375.  *  $END$
  376.  */
  377.  
  378. function FT_MenuTo( bGetSet, cReadVar, lCold )
  379.  
  380. local nMenu   := nLevel++
  381. local nActive := 1
  382. local nCount  := len( aRow[ nMenu ] )
  383. local lChoice := .F.
  384. local nCursor := set( _SET_CURSOR,SC_NONE )
  385. local nKey,bKey,nScan,lWrap,cScreen,nPrev
  386.  
  387. // Validate the incoming parameters and assign some reasonable defaults
  388. // to prevent a crash later.
  389.  
  390. cReadVar := iif( cReadVar == NIL, "", upper( cReadVar ) )
  391.  
  392. if ( Eval( bGetSet ) == NIL ) then bGetSet := { || 1 }
  393.  
  394. // Eval the incoming getset block to initialize nActive, which indicates
  395. // the menu prompt which is to be active when the menu is first displayed.
  396. // If nActive is outside the appropriate limits, a value of 1 is assigned.
  397.  
  398. nActive := eval( bGetSet )
  399.  
  400. if ( nActive < 1 .or. nActive > nCount ) then nActive := 1
  401.  
  402. // Increment the recursion level in case a hotkey procedure
  403. // calls FT_Prompt().  This will cause a new set of prompts
  404. // to be created without disturbing the current set.
  405.  
  406. aadd(          aRow, {} ) 
  407. aadd(          aCol, {} )
  408. aadd(       aPrompt, {} )
  409. aadd(        aColor, {} )
  410. aadd(       aMsgRow, {} )
  411. aadd(       aMsgCol, {} )
  412. aadd(      aMessage, {} )
  413. aadd(     aMsgColor, {} )
  414. aadd(      aTrigger, {} )
  415. aadd( aTriggerInkey, {} )
  416. aadd( aTriggerColor, {} )
  417. aadd(         aHome, {} )
  418. aadd(          aEnd, {} )
  419. aadd(           aUp, {} )
  420. aadd(         aDown, {} )
  421. aadd(         aLeft, {} )
  422. aadd(        aRight, {} )
  423. aadd(      aExecute, {} )
  424.  
  425. // Loop until Enter or Esc is pressed
  426.  
  427. while .not. lChoice
  428.    
  429.    // Evaluate the getset block to update the target memory variable
  430.    // in case it needs to be examined by a hotkey procedure.
  431.  
  432.    eval( bGetSet,nActive )
  433.  
  434.    // Get the current setting of SET WRAP so that the desired menu behavior
  435.    // can be implemented.
  436.  
  437.    lWrap := set( _SET_WRAP )
  438.  
  439.    // If a message is to be displayed, save the current screen contents
  440.    // and then display the message, otherwise set the screen buffer to NIL.
  441.  
  442.    dispbegin()
  443.  
  444.    if aMessage[ nCurrent ] != NIL
  445.       cScreen := savescreen( aMsgRow[ nCurrent ], aMsgCol[ nCurrent ],  ;
  446.                              aMsgRow[ nCurrent ], aMsgCol[ nCurrent ] + ;
  447.                        len( aMessage[ nCurrent ] ) - 1 )
  448.  
  449.       display( aMsgRow[ nCurrent ],   aMsgCol[ nCurrent ], ;
  450.               aMessage[ nCurrent ], aMsgColor[ nCurrent ]  )
  451.  
  452.    else
  453.       cScreen := NIL
  454.    endif
  455.  
  456.    // Display the prompt using the designated colors for the prompt and
  457.    // the trigger character.
  458.  
  459.    display( aRow[ nCurrent ], aCol[ nCurrent ], ;
  460.          aPrompt[ nCurrent ], EnhColor( aColor[ nCurrent ] ) )
  461.  
  462.    display( aRow[ nCurrent ], ;
  463.             aCol[ nCurrent ] - 1 + aTrigger[ nCurrent ], ;
  464.             substr( aPrompt[ nCurrent ], aTrigger[ nCurrent ], 1 ), ;
  465.             EnhColor( aTriggerColor[ nCurrent ] ) )
  466.  
  467.    dispend()
  468.  
  469.    // Wait for a keystroke
  470.  
  471.    nKey := inkey( 0 )
  472.  
  473.    // If the key was an alphabetic char, convert to uppercase
  474.  
  475.    if isBetween( nKey,97,122 ) then nKey -= 32
  476.  
  477.    // Set nPrev to the currently active menu item
  478.  
  479.    nPrev := nActive
  480.  
  481.    do case
  482.  
  483.       // Check for a hotkey, and evaluate the associated block if present.
  484.  
  485.       case ( bKey := setkey( nKey ) ) != NIL
  486.          eval( bKey, ProcName( 1 ), ProcLine( 1 ), cReadVar )
  487.  
  488.       // If Enter was pressed, either exit the menu or evaluate the
  489.       // associated code block.
  490.  
  491.       case nKey == K_ENTER
  492.          if aExecute[ nCurrent ] != NIL
  493.             eval( aExecute[ nCurrent ] )
  494.          else
  495.             lChoice := .T.
  496.          endif   
  497.  
  498.       // If ESC was pressed, set the selected item to zero and exit.
  499.  
  500.       case nKey == K_ESC
  501.          lChoice := .T.
  502.          nActive := 0
  503.  
  504.       // If Home was pressed, go to the designated menu item.
  505.  
  506.       case nKey == K_HOME
  507.          nActive := iif( aHome[ nCurrent ] == NIL, 1, aHome[ nCurrent ] )
  508.  
  509.       // If End was pressed, go to the designated menu item.
  510.  
  511.       case nKey == K_END
  512.          nActive := iif( aEnd[ nCurrent ] == NIL, nCount, aEnd[ nCurrent ] )
  513.  
  514.       // If Up Arrow was pressed, go to the designated menu item.
  515.  
  516.       case nKey == K_UP
  517.          if aUp[ nCurrent ] == NIL
  518.             if --nActive < 1 then nActive := iif( lWrap, nCount, 1 )
  519.          else
  520.             if isOkay( aUp[ nCurrent ] ) then nActive := aUp[ nCurrent ]
  521.          endif
  522.  
  523.       // If Down Arrow was pressed, go to the designated menu item.
  524.  
  525.       case nKey == K_DOWN
  526.          if aDown[ nCurrent ] == NIL
  527.             if ++nActive > nCount then nActive := iif( lWrap, 1, nCount )
  528.          else
  529.             if isOkay( aDown[ nCurrent ] ) then nActive := aDown[ nCurrent ]
  530.          endif
  531.  
  532.       // If Left Arrow was pressed, go to the designated menu item.
  533.  
  534.       case nKey == K_LEFT
  535.          if aLeft[ nCurrent ] == NIL
  536.             if --nActive < 1 then nActive := iif( lWrap, nCount, 1 )
  537.          else
  538.             if isOkay( aLeft[ nCurrent ] ) then nActive := aLeft[ nCurrent ]
  539.          endif
  540.  
  541.       // If Right Arrow was pressed, go to the designated menu item.
  542.  
  543.       case nKey == K_RIGHT
  544.          if aRight[ nCurrent ] == NIL
  545.             if ++nActive > nCount then nActive := iif( lWrap, 1, nCount )
  546.          else
  547.             if isOkay( aRight[ nCurrent ] ) then nActive := aRight[ nCurrent ]
  548.          endif
  549.  
  550.       // If a trigger letter was pressed, handle it based on the COLD
  551.       // parameter.
  552.  
  553.       case ( nScan := ascan( aTriggerInkey[ nMenu ], nKey ) ) > 0
  554.          nActive := nScan
  555.          if .not. lCold then FT_PutKey( K_ENTER )
  556.    endcase
  557.  
  558.    // Erase the highlight bar in preparation for the next iteration
  559.  
  560.    if .not. lChoice
  561.       dispbegin()
  562.       display( aRow[ nLast ], aCol[ nLast ], ;
  563.             aPrompt[ nLast ], aColor[ nLast ] )
  564.  
  565.       display( aRow[ nLast ], aCol[ nLast ] - 1 + aTrigger[ nLast ], ;
  566.                substr( aPrompt[ nLast ], aTrigger[ nLast ], 1 ), ;
  567.                aTriggerColor[ nLast ] )
  568.  
  569.       
  570.       if cScreen != NIL then restscreen( aMsgRow[ nLast ], ;
  571.                                          aMsgCol[ nLast ], ;
  572.                                          aMsgRow[ nLast ], ;
  573.                                          aMsgCol[ nLast ]  ;
  574.                                          + len( aMessage[ nLast ] ) - 1, ;
  575.                                          cScreen )
  576.       dispend()
  577.       endif
  578. end
  579.  
  580. // Now that we're exiting, decrement the recursion level and erase all
  581. // the prompt information for the current invocation.
  582.  
  583. nLevel--
  584.  
  585. asize(          aRow, nLevel ) 
  586. asize(          aCol, nLevel )
  587. asize(       aPrompt, nLevel )
  588. asize(        aColor, nLevel )
  589. asize(       aMsgRow, nLevel )
  590. asize(       aMsgCol, nLevel )
  591. asize(      aMessage, nLevel )
  592. asize(     aMsgColor, nLevel )
  593. asize(      aTrigger, nLevel )
  594. asize( aTriggerInkey, nLevel )
  595. asize( aTriggerColor, nLevel )
  596. asize(         aHome, nLevel )
  597. asize(          aEnd, nLevel )
  598. asize(           aUp, nLevel )
  599. asize(         aDown, nLevel )
  600. asize(         aLeft, nLevel )
  601. asize(        aRight, nLevel )
  602. asize(      aExecute, nLevel )
  603.  
  604.          aRow[ nLevel ] := {}
  605.          aCol[ nLevel ] := {}
  606.       aPrompt[ nLevel ] := {}
  607.        aColor[ nLevel ] := {}
  608.       aMsgRow[ nLevel ] := {}
  609.       aMsgCol[ nLevel ] := {}
  610.      aMessage[ nLevel ] := {}
  611.     aMsgColor[ nLevel ] := {}
  612.      aTrigger[ nLevel ] := {}
  613. aTriggerInkey[ nLevel ] := {}
  614. aTriggerColor[ nLevel ] := {}
  615.         aHome[ nLevel ] := {}
  616.          aEnd[ nLevel ] := {}
  617.           aUp[ nLevel ] := {}
  618.         aDown[ nLevel ] := {}
  619.         aLeft[ nLevel ] := {}
  620.        aRight[ nLevel ] := {}
  621.      aExecute[ nLevel ] := {}
  622.  
  623. set( _SET_CURSOR, nCursor )
  624.  
  625. eval( bGetSet, nActive )
  626.  
  627. return nActive
  628.  
  629.  
  630.