/*
 * Author....: Paul Ferrara
 * CIS ID....: 76702,556
 *
 * This is an original work by Paul Ferrara and is placed in the
 * public domain.
 *
 * Modification history:
 * ---------------------
 *
 *    Rev 1.2   15 Aug 1991 23:04:42   GLENN
 * Forest Belt proofread/edited/cleaned up doc
 *
 *    Rev 1.1   14 Jun 1991 19:52:12   GLENN
 * Minor edit to file header
 *
 *    Rev 1.0   01 Apr 1991 01:01:40   GLENN
 * Nanforum Toolkit
 *
 */

/*
     For the sample program:

     Compile with "/n /dFT_TEST" SWITCHES AND LINK.

     PASS "MONO" OR "MONO" AS A COMMAND LINE PARAMETER TO FORCE MONO MODE.

     PASS "NOSNOW" OR "NOSNOW" AS A COMMAND LINE PARAMETER ON A CGA.

     PASS "VGA" OR "VGA" AS A COMMAND LINE PARAMETER FOR 50-LINE MODE.
 */

#include "achoice.ch"
#include "inkey.ch"
#include "setcurs.ch"

#define DISABLE     0
#define ENABLE      1

THREAD STATIC t_aChoices := {}
THREAD STATIC t_aValidKeys := {}
THREAD STATIC t_nHPos
THREAD STATIC t_nVPos
THREAD STATIC t_nMaxRow
THREAD STATIC t_nMaxCol

FUNCTION ft_Menu1( aBar, aOptions, aColors, nTopRow, lShadow )

   LOCAL nTtlUsed
   LOCAL sMainScrn, lCancMode, lLooping := .T.

   // column position for each item on the menu bar
   LOCAL aBarCol[ Len( aBar ) ]

   // inkey code for each item on menu bar
   LOCAL aBarKeys[ Len( aBar ) ]

   // inkey codes for A - Z
   LOCAL aKeyCodes := { ;
      K_ALT_A, ;
      K_ALT_B, ;
      K_ALT_C, ;
      K_ALT_D, ;
      K_ALT_E, ;
      K_ALT_F, ;
      K_ALT_G, ;
      K_ALT_H, ;
      K_ALT_I, ;
      K_ALT_J, ;
      K_ALT_K, ;
      K_ALT_L, ;
      K_ALT_M, ;
      K_ALT_N, ;
      K_ALT_O, ;
      K_ALT_P, ;
      K_ALT_Q, ;
      K_ALT_R, ;
      K_ALT_S, ;
      K_ALT_T, ;
      K_ALT_U, ;
      K_ALT_V, ;
      K_ALT_W, ;
      K_ALT_X, ;
      K_ALT_Y, ;
      K_ALT_Z }

   // Len() of widest array element for for each pulldown menu
   LOCAL aBarWidth[ Len( aBar ) ]

   // starting column for each box
   LOCAL aBoxLoc[ Len( aBar ) ]

   // last selection for each element
   LOCAL aLastSel[ Len( aBar ) ]

   // color memvars
   LOCAL cBorder  := aColors[ 1 ]
   LOCAL cBox     := aColors[ 2 ]
   LOCAL cBar     := aColors[ 3 ]
   LOCAL cCurrent := aColors[ 4 ]
   LOCAL cUnSelec := aColors[ 5 ]

   t_nMaxRow := MaxRow()
   t_nMaxCol := MaxCol()

   // row for menu bar
   __defaultNIL( @nTopRow, 0 )

   AFill( aLastSel, 1 )
   t_aChoices := aOptions

   // this is the routine that calculates the position of each item
   // on the menu bar.

   aBarCol[ 1 ] := 0
   nTtlUsed := Len( aBar[ 1 ] ) + 1
   AEval( aBar, ;
      {| x, i | HB_SYMBOL_UNUSED( x ), aBarcol[ i ] := nTtlUsed, nTtlUsed += ( Len( aBar[ i ] ) + 1 ) }, ;
      2, Len( aBar ) - 1 )

   // calculates widest element for each pulldown menu
   // see below for _ftWidest()
   AFill( aBarWidth, 1 )
   AEval( t_aChoices, {| x, i | HB_SYMBOL_UNUSED( x ), _ftWidest( @i, t_aChoices, @aBarWidth ) } )

   // box location for each pulldown menu
   // see below for _ftLocat()
   AEval( t_aChoices, {| x, i | HB_SYMBOL_UNUSED( x ), _ftLocat( i, aBarCol, aBarWidth, @aBoxLoc, t_nMaxCol ) } )

   // valid keys for each pulldown menu
   // see below for _ftValKeys()
   AEval( t_aChoices, {| x, i | HB_SYMBOL_UNUSED( x ), AAdd( t_aValidKeys, "" ), ;
      _ftValKeys( i, t_aChoices, @t_aValidKeys ) } )

   // display the menu bar
   SetColor( cBar )
   hb_Scroll( nTopRow, 0, nTopRow )
   AEval( aBar, {| x, i | HB_SYMBOL_UNUSED( x ), hb_DispOutAt( nTopRow, aBarCol[ i ], aBar[ i ] ) } )

   // store inkey code for each item on menu bar to aBarKeys
   AEval( aBarKeys, {| x, i | HB_SYMBOL_UNUSED( x ), aBarKeys[ i ] := ;
      aKeyCodes[ Asc( Upper( LTrim( aBar[ i ] ) ) ) - Asc( "@" ) ] } )

   // disable Alt-C and Alt-D
   lCancMode := SetCancel( .F. )
   AltD( DISABLE )

   // main menu loop
   SAVE SCREEN TO sMainScrn
   // which menu and which menu item
   t_nHPos := 1
   t_nVPos := 1
   DO WHILE lLooping
      RESTORE SCREEN FROM sMainScrn
      SetColor( cCurrent )
      hb_DispOutAt( nTopRow, aBarCol[ t_nHPos ], aBar[ t_nHPos ] )
      IF lShadow == NIL .OR. lShadow
         hb_Shadow( nTopRow + 1, aBoxLoc[ t_nHPos ], Len( t_aChoices[ t_nHPos, 1 ] ) + nTopRow + 2, aBarWidth[ t_nHPos ] + 3 + aBoxLoc[ t_nHPos ] )
      ENDIF
      hb_DispBox( nTopRow + 1, aBoxLoc[ t_nHPos ], Len( t_aChoices[ t_nHPos, 1 ] ) + nTopRow + 2, aBarWidth[ t_nHPos ] + 3 + aBoxLoc[ t_nHPos ], hb_UTF8ToStrBox( "╔═╗║╝═╚║ " ), cBorder )
      SetColor( cBox + "," + cCurrent + ",,," + cUnselec )
      t_nVPos := AChoice( nTopRow + 2, aBoxLoc[ t_nHPos ] + 2, Len( t_aChoices[ t_nHPos, 1 ] ) + nTopRow + 2, aBarWidth[ t_nHPos ] + 1 + aBoxLoc[ t_nHPos ], t_aChoices[ t_nHPos, 1 ], t_aChoices[ t_nHPos, 3 ], {| nMode | __ftAcUdf( nMode ) }, aLastSel[ t_nHPos ] )
      DO CASE
      CASE LastKey() == K_RIGHT .OR. LastKey() == K_TAB
         t_nHPos := iif( t_nHPos == Len( t_aChoices ), 1, t_nHPos + 1 )
      CASE LastKey() == K_LEFT .OR. LastKey() == K_SH_TAB
         t_nHPos := iif( t_nHPos == 1, Len( t_aChoices ), t_nHPos - 1 )
      CASE LastKey() == K_ESC
         lLooping := _ftBailOut( cBorder, cBox )
      CASE LastKey() == K_HOME
         t_nHPos := 1
      CASE LastKey() == K_END
         t_nHPos := Len( t_aChoices )
      CASE LastKey() == K_ENTER
         aLastSel[ t_nHPos ] := t_nVPos
         IF t_aChoices[ t_nHPos, 2, t_nVPos ] != NIL
            SetCancel( lCancMode )
            AltD( ENABLE )
            lLooping := Eval( t_aChoices[ t_nHPos, 2, t_nVPos ] )
            AltD( DISABLE )
            SetCancel( .F. )
         ENDIF
      CASE AScan( aBarKeys, LastKey() ) > 0
         t_nHPos := AScan( aBarKeys, LastKey() )
      ENDCASE
   ENDDO
   SetCancel( lCancMode )
   AltD( ENABLE )
   RESTORE SCREEN FROM sMainScrn

   RETURN NIL

// AChoice() user function

STATIC FUNCTION __ftAcUdf( nMode )

   LOCAL nRtnVal := AC_CONT

   DO CASE
   CASE nMode == AC_HITTOP
      hb_keyPut( K_CTRL_END )
   CASE nMode == AC_HITBOTTOM
      hb_keyPut( K_CTRL_HOME )
   CASE nMode == AC_EXCEPT
      IF Upper( hb_keyChar( LastKey() ) ) $ t_aValidKeys[ t_nHPos ]
         IF t_aChoices[ t_nHPos, 3, At( Upper( hb_keyChar( LastKey() ) ), t_aValidKeys[ t_nHPos ] ) ]
            hb_keyPut( K_ENTER )
            nRtnVal := AC_GOTO
         ENDIF
      ELSE
         nRtnVal := AC_SELECT
      ENDIF
   ENDCASE

   RETURN nRtnVal

STATIC FUNCTION _ftWidest( i, t_aChoices, aBarWidth )

   AEval( t_aChoices[ i, 1 ], {| a, b | HB_SYMBOL_UNUSED( a ), aBarWidth[ i ] := ;
      Max( aBarWidth[ i ], Len( t_aChoices[ i, 1, b ] ) ) } )

   RETURN NIL

STATIC FUNCTION _ftLocat( i, aBarCol, aBarWidth, aBoxLoc, t_nMaxCol )

   aBoxLoc[ i ] := iif( aBarCol[ i ] + aBarWidth[ i ] + 4 > t_nMaxCol + 1, ;
      t_nMaxCol - 3 - aBarWidth[ i ], aBarCol[ i ] )

   RETURN NIL

STATIC FUNCTION _ftBailOut( cBorder, cBox )

   LOCAL sOldScreen, nKeyPress, nOldCursor

   nOldCursor := SetCursor( SC_NONE )
   sOldScreen := SaveScreen( t_nMaxRow / 2 - 1, 24, t_nMaxRow / 2 + 2, 55 )
   hb_Shadow( t_nMaxRow / 2 - 1, 24, t_nMaxRow / 2 + 2, 55 )
   hb_DispBox( t_nMaxRow / 2 - 1, 24, t_nMaxRow / 2 + 2, 55, hb_UTF8ToStrBox( "╔═╗║╝═╚║ " ), cBorder )
   hb_DispOutAt( t_nMaxRow / 2, 26, "Press ESCape To Confirm Exit", cBox )
   hb_DispOutAt( t_nMaxRow / 2 + 1, 27, "Or Any Other Key To Resume", cBox )
   nKeyPress := Inkey( 0 )
   RestScreen( t_nMaxRow / 2 - 1, 24, t_nMaxRow / 2 + 2, 55, sOldScreen )
   SetCursor( nOldCursor )

   RETURN nKeyPress != K_ESC

STATIC FUNCTION _ftValKeys( nNum, t_aChoices, t_aValidKeys )

   AEval( t_aChoices[ nNum, 1 ], {| x | t_aValidKeys[ nNum ] += Left( x, 1 ) } )

   RETURN NIL

FUNCTION ft_Fill( aArray, cMenuOption, bBlock, lAvailable )

   AAdd( aArray[ 1 ], cMenuOption )
   AAdd( aArray[ 2 ], bBlock )
   AAdd( aArray[ 3 ], lAvailable )

   RETURN NIL
