home *** CD-ROM | disk | FTP | other *** search
- /*
- * File......: MENUTO.PRG
- * Author....: Ted Means
- * Date......: $Date: 15 Aug 1991 23:03:54 $
- * Revision..: $Revision: 1.2 $
- * Log file..: $Logfile: E:/nanfor/src/menuto.prv $
- *
- * This is an original work by Ted Means and is placed in the
- * public domain.
- *
- * Modification history:
- * ---------------------
- *
- * $Log: E:/nanfor/src/menuto.prv $
- *
- * Rev 1.2 15 Aug 1991 23:03:54 GLENN
- * Forest Belt proofread/edited/cleaned up doc
- *
- * Rev 1.1 14 Jun 1991 19:52:16 GLENN
- * Minor edit to file header
- *
- * Rev 1.0 01 Apr 1991 01:01:42 GLENN
- * Nanforum Toolkit
- *
- */
-
-
- /* $DOC$
- * $FUNCNAME$
- * MENU TO
- * $CATEGORY$
- * Menus/Prompts
- * $ONELINER$
- * Execute light bar menu using prompts created with @...PROMPT
- * $SYNTAX$
- * #include "FTMENUTO.CH"
- *
- * MENU TO <var> [NOSNOW] [KEEP] [COLD]
- * $ARGUMENTS$
- * <var> is the name of the variable to assign the result of the
- * menu selection.
- *
- * ^bNOSNOW^b implements snow-suppression on CGA monitors. If not
- * specified, no snow-suppression will occur. This option is only
- * meaningful for CGA displays.
- *
- * ^bKEEP^b causes the prompt list to be retained after the menu
- * has been executed, allowing the menu to be executed multiple
- * times without redefining the prompts. If not specified, the
- * prompts will be destroyed once the menu has executed.
- *
- * ^bCOLD^b suppresses automatic menu termination when a prompt's
- * hotkey is pressed. If this clause is present, pressing
- * a prompt's hotkey will move the highlight to the proper menu
- * selection but will not terminate the menu. If not present,
- * pressing a hot key will terminate the menu, as it does in the
- * standard Clipper MENU TO command.
- * $DESCRIPTION$
- * This enhanced version of MENU TO requires the inclusion of
- * the header file FTMENUTO.CH in any source file that uses it.
- * It is compatible with, and may be used in place of, the standard
- * Clipper MENU TO command.
- *
- * This command is very similar to the Clipper version. The
- * main differences are that you have more control over hotkey
- * operation, and you can keep the prompts alive after the menu
- * has executed, if you so desire. Please be aware that this
- * function does not qualify as a "wait state" and so do not
- * expect any wait state-associated activity to occur.
- * Nevertheless, I have included support for any SET KEY
- * redirections through the magic of code blocks. A loop is
- * used to check to every possible INKEY() value to see if it
- * has been redirected. This is necessary because Clipper
- * provides no way to check SET KEY status. If you're
- * interested in improving performance, alter the source code
- * to receive an array of keys that have been redirected, and
- * remove the previously mentioned loop. Using the loop does
- * make the routine a bit more generic, so it's a trade-off.
- * Your call, do as you see fit.
- *
- * Note that this command can also be called using function-style
- * syntax. See the entry for FT_MENUTO() for further details.
- *
- * Also note that this command calls an internal routine called
- * __FTMENUTO(). __FTMENUTO() was written in assembler. Check
- * the file TMENU.ASM if you're interested in seeing the
- * assembler source code.
- *
- * Header file: FTMENUTO.CH
- * $EXAMPLES$
- * #include "FTMENUTO.CH" // NECESSARY!
- * // Simple command
- * MENU TO memvar
- *
- * // Implement snow-checking for CGA
- * MENU TO memvar NOSNOW
- *
- * // Keep the prompts alive when finished
- * MENU TO memvar KEEP
- *
- * // Use "cold" hotkeys
- * MENU TO memvar COLD
- * $INCLUDE$
- * FTMENUTO.CH
- * $SEEALSO$
- * "@...PROMPT" FT_MENUTO() FT_PROMPT()
- * $END$
- */
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_MENUTO()
- * $CATEGORY$
- * Menus/Prompts
- * $ONELINER$
- * Execute light bar menu using prompts created with FT_PROMPT()
- * $SYNTAX$
- * FT_MENUTO( <bVarNameBlock>, <cVarName>, ;
- * [ <lNoSnow> ], [ <lKeep> ], [ <lCold> ]) -> nChoice
- * $ARGUMENTS$
- * <bVarNameBlock> is a "get-set" code block which allows the
- * retrieval and assignment of the variable which will receive
- * the return value. Its initial value is used to determine the
- * initial active prompt.
- *
- * The code block must be in the form:
- *
- * {|_1| IIF( _1 == NIL, <var>, <var> := _1 ) }
- *
- * For example, if the variable to receive the return value is
- * named "nChoice", the code block would look like:
- *
- * {|_1| IIF( _1 == NIL, nChoice, nChoice := _1 ) }
- *
- * Although it is good practice to always declare your variables,
- * the variable to receive the return value does not need to exist
- * before calling FT_MENUTO(). If it does exist and is a numeric,
- * its value will be used to determine the initial prompt. If it
- * does not exist, the initial prompt will default to the first one.
- *
- * If you use this function by way of the MENU TO command along with
- * the FTMENUTO.CH header file, this code block will automatically
- * be created for you by the preprocessor.
- *
- * <cVarName> is the name of the memvar to which the menu
- * choice is returned.
- *
- * <lNoSnow> is optional and specifies whether or not to
- * implement snow-suppression on CGA monitors. The default is
- * .F., meaning that no snow-suppression will occur. This
- * option is only meaningful for CGA displays.
- *
- * <lKeep> is optional and indicates whether or not to destroy
- * the prompt list once the menu has been executed. If .T.,
- * then the prompts will be kept, allowing the menu to be
- * executed multiple times without redefining the prompts. The
- * default is .F., meaning the prompts will be destroyed once
- * the menu has executed.
- *
- * <lCold> is optional and controls the operation of the
- * hotkeys. If .T., then pressing a hotkey will not result in
- * a menu selection. Instead, it merely changes the active
- * prompt. This allows more than one prompt to have the same
- * hotkey. The default is .F., meaning the hotkeys will
- * function the same way they do in Clipper.
- * $RETURNS$
- * A numeric value representing the menu choice selected, or zero
- * if the ESC key was used to exit the menu.
- * $DESCRIPTION$
- * This function is a replacement for Clipper's MENU TO
- * command. In fact, you may wish to consult TMENU.CH, which
- * contains a user-defined command that closely adheres to
- * standard Clipper syntax and makes this function infinitely
- * easier to use. I strongly recommend using the command
- * version because it is complementary to the associated
- * @...PROMPT command.
- *
- * This function is very similar to the Clipper version. The
- * main differences are that you have more control over hotkey
- * operation, and you can keep the prompts alive after the menu
- * has executed, if you so desire. Please be aware that this
- * function does not qualify as a "wait state" and so do not
- * expect any wait state-associated activity to occur.
- * Nevertheless, I have included support for any SET KEY
- * redirections through the magic of code blocks. A loop is
- * used to check to every possible INKEY() value to see if it
- * has been redirected. This is necessary because Clipper
- * provides no way to check SET KEY status. If you're
- * interested in improving performance, alter the source code
- * to receive an array of keys that have been redirected, and
- * remove the previously mentioned loop. Using the loop does
- * make the routine a bit more generic, so it's a trade-off.
- * Your call, do as you see fit.
- *
- * Note that this function calls an internal routine called
- * __FTMENUTO(). __FTMENUTO() was written in assembler. Check
- * the file TMENU.ASM if you're interested in seeing the
- * assembler source code.
- *
- * All the examples below use the command version. If you're
- * interested in seeing the function version, compile the
- * examples with the /P switch and then examine the resulting
- * .PPO file.
- * $EXAMPLES$
- * #include "FTMENUTO.CH"
- * // Simple command
- * MENU TO memvar
- *
- * // Implement snow-checking for CGA
- * MENU TO memvar NOSNOW
- *
- * // Keep the prompts alive when finished
- * MENU TO memvar KEEP
- *
- * // Use "cold" hotkeys
- * MENU TO memvar COLD
- * $SEEALSO$
- * FT_PROMPT()
- * $END$
- */
-
- #include "set.ch"
- #include "inkey.ch"
- #include "error.ch"
-
- function FT_MenuTo( bReadvar, cReadVar, lNoSnow, lKeep, lCold )
-
- local nFlags, aKey := {}, aKBlock := {}, bKBlock, i, nScanCode
-
- local nActive, bErrorsys, oError
-
- if valtype(bReadvar) != "B"
- nActive := 1
- else
- bErrorsys := Errorblock( {|e| Break(e) } )
- BEGIN SEQUENCE
- nActive := Eval(bReadvar)
- RECOVER USING oError
- IF oError:gencode == EG_NOVAR
- nActive := 1
- ELSE
- Eval(bErrorsys,oError)
- ENDIF
- END SEQUENCE
- Errorblock(bErrorsys)
- endif
-
- if valtype(lNoSnow) != "L"
- lNoSnow := .F.
- endif
-
- if valtype(lKeep) != "L"
- lKeep := .F.
- endif
-
- if valtype(lCold) != "L"
- lCold := .F.
- endif
-
- nFlags := iif(lNoSnow, 1, 0) ;
- + iif(lKeep, 2, 0) ;
- + iif(lCold, 4, 0) ;
- + iif(set(_SET_WRAP), 8, 0)
-
- for i := -39 to 306
- if (bKBLock := SetKey(i)) != NIL
- _ftScanKey(i, aKey)
- while len(aKBlock) < len(aKey)
- AAdd(aKBlock, bKBlock)
- end
- endif
- next
-
- nScanCode := __ftMenuTo(nActive, nFlags, aKey)
- nActive := int(nScanCode % (2 ^ 16))
- nScanCode := int(nScanCode / (2 ^ 16))
-
- while (i := aScan(aKey, nScanCode)) > 0
-
- if valtype(bReadvar) == "B"
- eval(bReadvar,nActive)
- endif
-
- eval(aKBlock[i], ProcName(1), ProcLine(1), Upper(cReadVar))
-
- nFlags := iif(nFlags < 32, nFlags + 32, nFlags)
- nScanCode := __ftMenuTo(nActive, nFlags, aKey)
- nActive := int(nScanCode % (2 ^ 16))
- nScanCode := int(nScanCode / (2 ^ 16))
- end
-
- return nActive
-
-
- static function _ftScanKey(nInKey, aKey)
-
- do case
- case nInKey == K_DEL
- AAdd(aKey, 83 * 256)
- AAdd(aKey, 7)
-
- case nInKey == K_INS
- AAdd(aKey, 82 * 256)
- AAdd(aKey, 22)
-
- case nInKey == K_UP
- AAdd(aKey, 72 * 256)
- AAdd(aKey, 5)
-
- case nInKey == K_DOWN
- AAdd(aKey, 80 * 256)
- AAdd(aKey, 24)
-
- case nInKey == K_LEFT
- AAdd(aKey, 75 * 256)
- AAdd(aKey, 19)
-
- case nInKey == K_RIGHT
- AAdd(aKey, 77 * 256)
- AAdd(aKey, 4)
-
- case nInKey == K_HOME
- AAdd(aKey, 71 * 256)
- AAdd(aKey, 1)
-
- case nInKey == K_END
- AAdd(aKey, 79 * 256)
- AAdd(aKey, 6)
-
- case nInKey == K_PGUP
- AAdd(aKey, 73 * 256)
- AAdd(aKey, 18)
-
- case nInKey == K_PGDN
- AAdd(aKey, 81 * 256)
- AAdd(aKey, 3)
-
- case nInKey == K_CTRL_LEFT
- AAdd(aKey, 115 * 256)
- AAdd(aKey, 26)
-
- case nInKey == K_CTRL_RIGHT
- AAdd(aKey, 116 * 256)
- AAdd(aKey, 2)
-
- case nInKey == K_CTRL_HOME
- AAdd(aKey, 119 * 256)
- AAdd(aKey, 29)
-
- case nInKey == K_CTRL_END
- AAdd(aKey, 117 * 256)
- AAdd(aKey, 23)
-
- case nInKey == K_CTRL_PGUP
- AAdd(aKey, 132 * 256)
- AAdd(aKey, 31)
-
- case nInKey == K_CTRL_PGDN
- AAdd(aKey, 118 * 256)
- AAdd(aKey, 30)
-
- case nInKey >= K_ALT_F10 .and. nInKey <= K_SH_F1
- AAdd(aKey, (abs(nInKey) + 74) * 256)
-
- case nInkey >= K_F10 .and. nInkey <= K_F2
- AAdd(aKey, (abs(nInKey) + 59) * 256)
-
- case nInkey == 28
- AAdd(aKey, 59 * 256)
-
- case (nInKey >= K_SH_TAB .and. nInKey <= K_ALT_P) .or. ;
- (nInKey >= K_ALT_A .and. nInKey <= K_ALT_L) .or. ;
- (nInKey >= K_ALT_Z .and. nInKey <= K_ALT_M)
- AAdd(aKey, (nInKey - 256) * 256)
-
- case (nInKey >= 0 .and. nInKey <= 255)
- AAdd(aKey, nInKey)
- endcase
-
- return NIL
-