home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1993 #2 / Image.iso / database / kbrows.zip / KEVBROWS.PRG < prev    next >
Text File  |  1993-05-30  |  50KB  |  1,428 lines

  1. ******************************************************************************
  2. * KBROWSE - Kevin's Rapid Access File Browser
  3. *
  4. * m_list = Kbrowse(<tlr>,<tlc>,<brr>,<brc>,<array>,<retexp>,;
  5. *                  <headsep>,<colsep>,@<marked>,<frozen>)
  6. *
  7. *   <tlr>        = top left row coordinate; default = 0
  8. *   <tlc>        = top left column coordinate; default = 0
  9. *   <brr>        = bottom right row coordinate; default = 24
  10. *   <brc>        = bottom right column coordinate; default = 79
  11. *   <array>      = multi-dimensional array of display information:
  12. *                  <array>[x][1] = column title
  13. *                  <array>[x][2] = code block to return column contents
  14. *                Optional array elements:
  15. *                  <array>[x][3] = index order if active searching
  16. *                  <array>[x][4] = search string picture clause
  17. *                  <array>[x][5] = upper key value if limiting the browse
  18. *                  <array>[x][6] = lower key value if limiting the browse
  19. *   <retexp>     = code block to return an expression to the caller
  20. *   <headsep>    = string of header separators
  21. *   <colsep>     = string of column separators
  22. *   @<marked>    = array to hold marked RECNO()'s, null for no marking
  23. *   <frozen>     = number of columns to freeze from left to right
  24. *
  25. * Source Code Example:
  26. *
  27. * m_tlr = 04
  28. * m_tlc = 01
  29. * m_brr = 20
  30. * m_brc = 78
  31. * m_headsep = "═╤═"
  32. * m_colsep = " │ "
  33. * m_freeze = 0
  34. * m_marked = {}
  35. * m_retexp = { || A->lastname}
  36. * m_array = {;
  37. *   { "Last Name"     , { || A->lastname}, 1, "@!" },;   && use index 1, uppercase the search string
  38. *   { "First Name"    , { || A->firstname} },;
  39. *   { "I"             , { || A->initial}   },;
  40. *   { "Marked"        , { || IIF(ASCAN(m_marked,RECNO()) = 0," ","√") } };  && a marked record display function
  41. * }
  42. * m_retval = Kbrowse(m_tlr,m_tlc,m_brr,m_brc,m_array,m_retexp,;
  43. *                    m_headsep,m_colsep,@m_marked,m_freeze)
  44. ******************************************************************************
  45. FUNCTION Kbrowse(nParTlr,nParTlc,nParBrr,nParBrc,aColInfo,cRetExp,;
  46.                  cHeadSep,cColSep,aMarked,nFreeze)
  47.  
  48.   * memvar declarations
  49.   LOCAL cSaveColor     && stores current color setting
  50.   LOCAL nSaveCursor    && stores current cursor setting
  51.   LOCAL nTlr           && top left screen row coordinate
  52.   LOCAL nTlc           && top left screen column coordinate
  53.   LOCAL nBrr           && bottom right screen row coordinate
  54.   LOCAL nBrc           && bottom right screen column coordinate
  55.   LOCAL nPtr1          && general purpose counter
  56.   LOCAL nPtr2          && general purpose counter
  57.   LOCAL aFldArray      && used to load the structure of a database file
  58.   LOCAL aCtrlArray     && array of parsed column information
  59.   LOCAL nCtrlTop       && pointer to leftmost displayed column
  60.   LOCAL nCtrlPtr       && pointer to current displayed column
  61.   LOCAL nCtrlBot       && pointer to rightmost displayed column
  62.   LOCAL nRowTop        && top screen row for database info
  63.   LOCAL nRowPtr        && current screen row for database info
  64.   LOCAL nRowBot        && bottom screen row for database info
  65.   LOCAL nColTop        && left screen column for database info
  66.   LOCAL nColBot        && right screen row for database info
  67.   LOCAL nRecordTop     && number of top displayed record
  68.   LOCAL nRecordPtr     && number of current displayed record
  69.   LOCAL nRecordBot     && number of bottom displayed record
  70.   LOCAL nRecRowBot     && last used lower screen row
  71.   LOCAL nHeadRow       && screen row for header information
  72.   LOCAL nKeyPress      && holds operator keystroke
  73.     LOCAL cSeekVar       && holds current seek string
  74.     LOCAL nOldRecno      && pointer to previous record prior to seek
  75.     LOCAL nNtxOrder      && holds the current index order
  76.     LOCAL nNewOrder      && used to test for index order change
  77.     LOCAL nPickPtr       && used during ASCAN of marked record array
  78.   LOCAL cDataType      && used to parse the type of column expression
  79.   LOCAL nDataLen       && used to parse the maximum length of the column
  80.   LOCAL cNtxPicture    && used to parse the search column picture clause
  81.   LOCAL cNtxTopKey     && used to parse the search column top key value 
  82.   LOCAL cNtxBotKey     && used to parse the search column bottom key value
  83.   LOCAL lHeaders       && indicates the need to draw headers or not
  84.  
  85.   * assign screen coordinates
  86.   nTlr = IIF(nParTlr = NIL, 0,  nParTlr)
  87.   nTlc = IIF(nParTlc = NIL, 0,  nParTlc)
  88.   nBrr = IIF(nParBrr = NIL, 24, nParBrr)
  89.   nBrc = IIF(nParBrc = NIL, 79, nParBrc)
  90.  
  91.   * load the control array
  92.   aCtrlArray = {}
  93.   IF aColInfo <> NIL
  94.     * load the control array from the passed array
  95.     FOR nPtr1 = 1 TO LEN(aColInfo)
  96.       IF VALTYPE(aColInfo[nPtr1]) <> "A"
  97.         LOOP
  98.       ENDIF
  99.       IF LEN(aColInfo[nPtr1]) >= 2
  100.         cDataType = VALTYPE(EVAL(aColInfo[nPtr1][2]))
  101.         nDataLen = 0
  102.         nNtxOrder = 0
  103.         cNtxPicture = ""
  104.         cNtxTopKey = ""
  105.         cNtxBotKey = ""
  106.         DO CASE
  107.         CASE cDataType = "C"
  108.           nDataLen = LEN(EVAL(aColInfo[nPtr1][2]))
  109.         CASE cDataType = "D"
  110.           nDataLen = LEN(DTOC(DATE()))
  111.         CASE cDataType = "N"
  112.           nDataLen = LEN(STR(EVAL(aColInfo[nPtr1][2])))
  113.         CASE cDataType = "L"
  114.           nDataLen = 1
  115.         ENDCASE
  116.         IF nDataLen > 0
  117.           IF LEN(aColInfo[nPtr1][1]) > nDataLen
  118.             nDataLen = LEN(aColInfo[nPtr1][1])
  119.           ENDIF
  120.           IF LEN(aColInfo[nPtr1]) >= 4
  121.             nNtxOrder = aColInfo[nPtr1][3]
  122.             cNtxPicture = aColInfo[nPtr1][4]
  123.           ENDIF
  124.           IF LEN(aColInfo[nPtr1]) >= 5
  125.             cNtxTopKey = aColInfo[nPtr1][5]
  126.             IF LEN(aColInfo[nPtr1]) >= 6
  127.               cNtxBotKey = aColInfo[nPtr1][6]
  128.             ELSE
  129.               cNtxBotKey = cNtxTopKey
  130.             ENDIF
  131.           ENDIF
  132.         ENDIF
  133.         AADD(aCtrlArray, { -1,;                    && display column number
  134.                            nDataLen,;              && width of the column
  135.                            aColInfo[nPtr1][1],;    && column title text
  136.                            aColInfo[nPtr1][2],;    && column item expression
  137.                            nNtxOrder,;             && search index order
  138.                            cNtxPicture,;           && search index picture
  139.                            cNtxTopKey,;            && upper key value
  140.                            cNtxBotKey;             && lower key value
  141.                          } )
  142.       ENDIF
  143.     NEXT
  144.   ENDIF
  145.   IF LEN(aCtrlArray) = 0
  146.     * load the control array from database fields
  147.     aFldArray = DBSTRUCT()
  148.     FOR nPtr1 = 1 TO LEN(aFldArray)
  149.       IF aFldArray[nPtr1][2] $ "CDLN"
  150.         IF LEN(aFldArray[nPtr1][1]) > aFldArray[nPtr1][3]
  151.           AADD(aCtrlArray, { -1,;
  152.                              LEN(aFldArray[nPtr1][1]),;
  153.                              aFldArray[nPtr1][1],;
  154.                              &("{|| " + aFldArray[nPtr1][1] + "}"),;
  155.                              0,;
  156.                              "",;
  157.                              "",;
  158.                              "";
  159.                            } )
  160.         ELSE
  161.           AADD(aCtrlArray, { -1,;
  162.                              aFldArray[nPtr1][3],;
  163.                              aFldArray[nPtr1][1],;
  164.                              &("{|| " + aFldArray[nPtr1][1] + "}"),;
  165.                              0,;
  166.                              "",;
  167.                              "",;
  168.                              "";
  169.                            } )
  170.         ENDIF
  171.       ENDIF
  172.     NEXT
  173.   ENDIF
  174.   IF LEN(aCtrlArray) = 0
  175.     RETURN ""
  176.   ENDIF
  177.   * scan for column headers
  178.   lHeaders = .F.
  179.   FOR nPtr1 = 1 TO LEN(aCtrlArray)
  180.     IF LEN(aCtrlArray[nPtr1][3]) <> 0
  181.       lHeaders = .T.
  182.       EXIT
  183.     ENDIF
  184.   NEXT
  185.   * check the rest of the parameters
  186.   IF cRetExp = NIL
  187.     cRetExp = { || RECNO() }
  188.   ENDIF
  189.   IF cHeadSep = NIL
  190.     cHeadSep = "═╤═"
  191.   ENDIF
  192.   IF cColSep = NIL
  193.     cColSep = " │ "
  194.   ENDIF
  195.   IF aMarked = NIL
  196.     aMarked = ""
  197.   ENDIF
  198.   IF nFreeze = NIL
  199.     nFreeze = 0
  200.   ENDIF
  201.  
  202.   * initialize working memvars
  203.   nCtrlTop = 1          
  204.   nCtrlPtr = 1
  205.   nCtrlBot = 1
  206.   nRowTop = nTlr 
  207.   nRowPtr = nTlr
  208.   nRowBot = nBrr
  209.   nColTop = nTlc
  210.   nColBot = nBrc
  211.   nHeadRow = nTlr
  212.   nRecordTop = RECNO()
  213.   nRecordPtr = RECNO()
  214.   nRecordBot = RECNO()
  215.   IF lHeaders
  216.     * adjust display to allow for headers
  217.     nRowTop += 2
  218.     nRowPtr = nRowTop
  219.   ENDIF
  220.   nRecRowBot = nRowTop
  221.   cSeekVar = ""
  222.     nNtxOrder = INDEXORD()
  223.   cNtxTopKey = ""
  224.   cNtxBotKey = ""
  225.     nNewOrder = nNtxOrder
  226.   cSaveColor = SETCOLOR()
  227.   nSaveCursor = SETCURSOR()
  228.  
  229.   * check for an index key limit
  230.   IF nNtxOrder <> 0
  231.     FOR nPtr1 = 1 TO LEN(aCtrlArray)
  232.       IF aCtrlArray[nPtr1][5] = nNtxOrder
  233.         cNtxTopKey = aCtrlArray[nPtr1][7]
  234.         cNtxBotKey = aCtrlArray[nPtr1][8]
  235.         EXIT
  236.       ENDIF
  237.     NEXT
  238.   ENDIF
  239.   * see if re-positioning is needed
  240.   IF LEN(cNtxTopKey) <> 0
  241.     IF &(INDEXKEY(0)) < cNtxTopKey .OR. &(INDEXKEY(0)) > cNtxBotKey
  242.       SEEK cNtxTopKey
  243.     ENDIF
  244.     nRecordTop = RECNO()
  245.     nRecordPtr = RECNO()
  246.     nRecordBot = RECNO()
  247.   ENDIF
  248.  
  249.   * initial screen setup
  250.   SETCURSOR(0)
  251.   DISPBEGIN()
  252.     * calculate the column screen positions
  253.     KbrowseScr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  254.                @nColTop,@nColBot,@cColSep)
  255.     IF lHeaders
  256.       * draw the headers and column seperators
  257.       KbrowseHdr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  258.                  @nRowTop,@nColTop,@nRowBot,@nColBot,;
  259.                  @nHeadRow,@cHeadSep,@cColSep)
  260.     ENDIF
  261.     * refresh the browse data
  262.     KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  263.                @nRowTop,@nRowBot,@nRowPtr,;
  264.                @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  265.                @cNtxTopKey,@cNtxBotKey)
  266.     GO nRecordPtr
  267.   DISPEND()
  268.  
  269.   * main program loop
  270.   DO WHILE .T.
  271.     * check for an index order switch and process it
  272.     IF aCtrlArray[nCtrlPtr][5] <> 0
  273.       DISPBEGIN()
  274.         nNewOrder = aCtrlArray[nCtrlPtr][5]
  275.         IF nNewOrder <> nNtxOrder
  276.           cSeekVar = ""
  277.           nNtxOrder = nNewOrder
  278.           SET ORDER TO nNtxOrder
  279.           GO nRecordPtr
  280.           cNtxTopKey = ""
  281.           cNtxBotKey = ""
  282.           FOR nPtr1 = 1 TO LEN(aCtrlArray)
  283.             IF aCtrlArray[nPtr1][5] = nNtxOrder
  284.               cNtxTopKey = aCtrlArray[nPtr1][7]
  285.               cNtxBotKey = aCtrlArray[nPtr1][8]
  286.               EXIT
  287.             ENDIF
  288.           NEXT
  289.           IF LEN(cNtxTopKey) <> 0
  290.             IF &(INDEXKEY(0)) < cNtxTopKey .OR. &(INDEXKEY(0)) > cNtxBotKey
  291.               SEEK cNtxTopKey
  292.             ENDIF
  293.           ENDIF
  294.           FOR nPtr1 = nRowTop TO nRowPtr -1
  295.             SKIP - 1
  296.             IF KbrowseBof(cNtxTopKey,cNtxBotKey)
  297.               EXIT
  298.             ENDIF
  299.           NEXT
  300.           IF KbrowseBof(cNtxTopKey,cNtxBotKey)
  301.             KbrowseTop(cNtxTopKey,cNtxBotKey)
  302.           ENDIF
  303.           nRecordTop = RECNO()
  304.           FOR nPtr1 = nRowTop TO nRowBot
  305.             IF KbrowseEof(cNtxTopKey,cNtxBotKey)
  306.               EXIT
  307.             ENDIF
  308.             IF nFreeze > 0
  309.               FOR nPtr2 = 1 TO nFreeze
  310.                 @ nPtr1,aCtrlArray[nPtr2][1] SAY EVAL(aCtrlArray[nPtr2][4])
  311.               NEXT
  312.             ENDIF
  313.             FOR nPtr2 = nCtrlTop TO nCtrlBot
  314.               @ nPtr1,aCtrlArray[nPtr2][1] SAY EVAL(aCtrlArray[nPtr2][4])
  315.             NEXT
  316.             nRecordBot = RECNO()
  317.             nRecRowBot = nPtr1
  318.             SKIP
  319.           NEXT
  320.           FOR nPtr1 = nPtr1 TO nRowBot
  321.             IF nFreeze > 0
  322.               FOR nPtr2 = 1 TO nFreeze
  323.                 @ nPtr1,aCtrlArray[nPtr2][1] SAY SPACE(aCtrlArray[nPtr2][2])
  324.               NEXT
  325.             ENDIF
  326.             FOR nPtr2 = nCtrlTop TO nCtrlBot
  327.               @ nPtr1,aCtrlArray[nPtr2][1] SAY SPACE(aCtrlArray[nPtr2][2])
  328.             NEXT
  329.           NEXT
  330.           GO nRecordTop
  331.           nRowPtr = nRowTop
  332.           DO WHILE RECNO() <> nRecordPtr .AND. .NOT. EOF()
  333.             nRowPtr++
  334.             SKIP
  335.           ENDDO
  336.           nRecordPtr = RECNO()
  337.           COLORSELECT(1)
  338.           @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  339.           COLORSELECT(0)
  340.         ENDIF
  341.         IF LEN(cSeekVar) <> 0
  342.           SETCOLOR("W+/N")
  343.           @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY cSeekVar
  344.           SETCOLOR(cSaveColor)
  345.         ENDIF
  346.       DISPEND()
  347.     ENDIF
  348.  
  349.     * wait for a keystroke
  350.     nKeyPress = 0
  351.     DO WHILE nKeyPress = 0
  352.       nKeyPress = INKEY()
  353.       IF nKeyPress <> 0
  354.         IF SETKEY(nKeyPress) <> NIL
  355.           EVAL(SETKEY(nKeyPress), PROCNAME(), PROCLINE(), "NKEYPRESS")
  356.           nKeyPress = 0
  357.         ENDIF
  358.         IF nKeyPress <> 0
  359.           EXIT
  360.         ENDIF
  361.       ENDIF
  362.     ENDDO
  363.  
  364.     DO CASE
  365.       CASE nKeyPress = 5   && uparrow
  366.       cSeekVar = ""
  367.       KbrowseUp(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  368.                 @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  369.                 @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  370.                 @cNtxTopKey,@cNtxBotKey,;
  371.                 @nHeadrow,@cHeadSep,@cColSep)
  372.       CASE nKeyPress = 24  && downarrow
  373.       cSeekVar = ""
  374.       KbrowseDn(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  375.                 @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  376.                 @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  377.                 @cNtxTopKey,@cNtxBotKey,;
  378.                 @nHeadrow,@cHeadSep,@cColSep)
  379.       CASE nKeyPress = 18  && pgup
  380.       cSeekVar = ""
  381.       KbrowsePu(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  382.                 @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  383.                 @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  384.                 @cNtxTopKey,@cNtxBotKey,;
  385.                 @nHeadrow,@cHeadSep,@cColSep)
  386.       CASE nKeyPress = 3   && pgdn
  387.       cSeekVar = ""
  388.       KbrowsePd(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  389.                 @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  390.                 @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  391.                 @cNtxTopKey,@cNtxBotKey,;
  392.                 @nHeadrow,@cHeadSep,@cColSep)
  393.       CASE nKeyPress = 19  && leftarrow
  394.       cSeekVar = ""
  395.       KbrowseLf(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  396.                 @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  397.                 @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  398.                 @cNtxTopKey,@cNtxBotKey,;
  399.                 @nHeadrow,@cHeadSep,@cColSep)
  400.       CASE nKeyPress = 4   && rightarrow
  401.       cSeekVar = ""
  402.       KbrowseRt(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  403.                 @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  404.                 @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  405.                 @cNtxTopKey,@cNtxBotKey,;
  406.                 @nHeadrow,@cHeadSep,@cColSep)
  407.       CASE nKeyPress = 1   && home
  408.       cSeekVar = ""
  409.       KbrowseHom(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  410.                  @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  411.                  @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  412.                  @cNtxTopKey,@cNtxBotKey,;
  413.                  @nHeadrow,@cHeadSep,@cColSep)
  414.       CASE nKeyPress = 6   && end
  415.       cSeekVar = ""
  416.       KbrowseEnd(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  417.                 @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  418.                 @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  419.                 @cNtxTopKey,@cNtxBotKey,;
  420.                 @nHeadrow,@cHeadSep,@cColSep)
  421.       CASE nKeyPress = 26  && ctrl-left
  422.       cSeekVar = ""
  423.       IF nCtrlPtr > 1
  424.         KbrowseCLf(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  425.                    @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  426.                    @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  427.                    @cNtxTopKey,@cNtxBotKey,;
  428.                    @nHeadrow,@cHeadSep,@cColSep)
  429.       ENDIF
  430.       CASE nKeyPress = 2   && ctrl-right
  431.       cSeekVar = ""
  432.       IF nCtrlPtr < LEN(aCtrlArray)
  433.         KbrowseCRt(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  434.                    @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  435.                    @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  436.                    @cNtxTopKey,@cNtxBotKey,;
  437.                    @nHeadrow,@cHeadSep,@cColSep)
  438.       ENDIF
  439.       CASE nKeyPress = 31  && ctrl-pgup
  440.       cSeekVar = ""
  441.       KbrowseCPu(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  442.                  @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  443.                  @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  444.                  @cNtxTopKey,@cNtxBotKey,;
  445.                  @nHeadrow,@cHeadSep,@cColSep)
  446.       CASE nKeyPress = 30  && ctrl-pgdn
  447.       cSeekVar = ""
  448.       KbrowseCPd(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  449.                  @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  450.                  @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  451.                  @cNtxTopKey,@cNtxBotKey,;
  452.                  @nHeadrow,@cHeadSep,@cColSep)
  453.       CASE nKeyPress = 13  && enter
  454.       SETCOLOR(cSaveColor)
  455.       SETCURSOR(nSaveCursor)
  456.       RETURN EVAL(cRetExp)
  457.       CASE nKeyPress = 27  && esc
  458.       SETCOLOR(cSaveColor)
  459.       SETCURSOR(nSaveCursor)
  460.       RETURN ""
  461.     CASE VALTYPE(aMarked) = "A" .AND. nKeyPress = 32
  462.       cSeekVar = ""
  463.       nPickPtr = ASCAN(aMarked,RECNO())
  464.       IF nPickPtr = 0
  465.         AADD(aMarked,RECNO())
  466.       ELSE
  467.         ADEL(aMarked,nPickPtr)
  468.         ASIZE(aMarked,LEN(aMarked)-1)
  469.       ENDIF
  470.       DISPBEGIN()
  471.         FOR nPtr1 = nCtrlTop TO nCtrlBot
  472.           @ nRowPtr,aCtrlArray[nPtr1][1] SAY EVAL(aCtrlArray[nPtr1][4])
  473.         NEXT
  474.         SKIP
  475.         IF KbrowseEof(cNtxTopKey,cNtxBotKey)
  476.           KbrowseBot(cNtxTopKey,cNtxBotKey)
  477.           COLORSELECT(1)
  478.           @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  479.           COLORSELECT(0)
  480.         ELSE
  481.           SKIP -1
  482.           KbrowseDn(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  483.                     @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  484.                     @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  485.                     @cNtxTopKey,@cNtxBotKey,;
  486.                     @nHeadrow,@cHeadSep,@cColSep)
  487.         ENDIF
  488.         CLEAR TYPEAHEAD
  489.       DISPEND()
  490.     CASE aCtrlArray[nCtrlPtr][5] <> 0 .AND. ((nKeyPress >= 32 .AND. nKeyPress <= 122) .OR. nKeyPress = 8)
  491.       IF LEN(cNtxTopKey) = 0
  492.         KbrowseSrc(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  493.                    @nRowTop,@nRowBot,@nColTop,@nColBot,@nRowPtr,;
  494.                    @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  495.                    @cNtxTopKey,@cNtxBotKey,;
  496.                    @nHeadrow,@cHeadSep,@cColSep,;
  497.                    @nKeyPress,@cSeekVar,@cSaveColor)
  498.       ENDIF
  499.     ENDCASE
  500.   ENDDO
  501.   SETCOLOR(cSaveColor)
  502.   SETCURSOR(nSaveCursor)
  503. RETURN ""
  504.  
  505. ******************************************************************************
  506. * KbrowseScr - calculates the displayable columns and screen column positions
  507. ******************************************************************************
  508. FUNCTION KbrowseScr(aCtrlArray,nCtrlTop,nCtrlBot,nFreeze,;
  509.                     nColTop,nColBot,cColSep)
  510.   LOCAL nScrnCol
  511.   LOCAL nFreezeWidth
  512.   LOCAL nWidth
  513.   LOCAL nPtr1
  514.   nScrnCol = nColTop
  515.   nFreezeWidth = 0
  516.   IF nFreeze > 0
  517.     nFreezeWidth = 1
  518.     nScrnCol++
  519.     FOR nPtr1 = 1 TO nFreeze
  520.       IF nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  521.         EXIT
  522.       ENDIF
  523.       aCtrlArray[nPtr1][1] = nScrnCol
  524.       nScrnCol = nScrnCol + aCtrlArray[nPtr1][2] + LEN(cColSep)
  525.       nFreezeWidth = nFreezeWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  526.     NEXT
  527.     IF nCtrlTop <= nFreeze
  528.       nCtrlTop = nFreeze + 1
  529.     ENDIF
  530.     IF nCtrlBot <= nFreeze
  531.       nCtrlBot = nFreeze + 1
  532.     ENDIF
  533.   ENDIF
  534.   nWidth = 0
  535.   FOR nPtr1 = nCtrlTop TO LEN(aCtrlArray)
  536.     IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  537.       EXIT
  538.     ENDIF
  539.     aCtrlArray[nPtr1][1] = nScrnCol
  540.     nScrnCol = nScrnCol + aCtrlArray[nPtr1][2] + LEN(cColSep)
  541.     nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  542.     nCtrlBot = nPtr1
  543.   NEXT
  544.   nWidth = nWidth - LEN(cColSep)
  545.   nScrnCol = (nColBot-nColTop-nFreezeWidth+1) - nWidth
  546.   IF nScrnCol >= 2
  547.     nScrnCol = INT((nScrnCol)/2)
  548.     FOR nPtr1 = nCtrlTop TO nCtrlBot
  549.       aCtrlArray[nPtr1][1] = aCtrlArray[nPtr1][1] + nScrnCol
  550.     NEXT
  551.   ENDIF
  552. RETURN NIL
  553.  
  554. ******************************************************************************
  555. * KbrowseHdr - clears screen, draws column headers and separators
  556. ******************************************************************************
  557. FUNCTION KbrowseHdr(aCtrlArray,nCtrlTop,nCtrlBot,nFreeze,;
  558.                     nRowTop,nColTop,nRowBot,nColBot,;
  559.                     nHeadRow,cHeadSep,cColSep)
  560.   LOCAL nPtr1
  561.   LOCAL nPtr2
  562.   @ nHeadRow,nColTop CLEAR TO nRowBot,nColBot
  563.   IF nFreeze > 0
  564.     FOR nPtr1 = 1 TO nFreeze
  565.       @ nHeadRow,aCtrlArray[nPtr1][1] SAY aCtrlArray[nPtr1][3]
  566.     NEXT
  567.   ENDIF
  568.   FOR nPtr1 = nCtrlTop TO nCtrlBot
  569.     @ nHeadRow,aCtrlArray[nPtr1][1] SAY aCtrlArray[nPtr1][3]
  570.   NEXT
  571.   @ nHeadRow+1,nColTop SAY REPLICATE(SUBSTR(cHeadSep,1,1),nColBot-nColTop+1)
  572.   IF nFreeze > 0
  573.     FOR nPtr1 = 1 TO nFreeze
  574.       @ nHeadRow+1,aCtrlArray[nPtr1][1] + aCtrlArray[nPtr1][2] SAY cHeadSep
  575.     NEXT
  576.   ENDIF
  577.   FOR nPtr1 = nCtrlTop TO nCtrlBot-1
  578.     @ nHeadRow+1,aCtrlArray[nPtr1][1] + aCtrlArray[nPtr1][2] SAY cHeadSep
  579.   NEXT
  580.   FOR nPtr1 = nRowTop TO nRowBot 
  581.     IF nFreeze > 0
  582.       FOR nPtr2 = 1 TO nFreeze
  583.         @ nPtr1,aCtrlArray[nPtr2][1] + aCtrlArray[nPtr2][2] SAY cColSep
  584.       NEXT
  585.     ENDIF
  586.     FOR nPtr2 = nCtrlTop TO nCtrlBot-1
  587.       @ nPtr1,aCtrlArray[nPtr2][1] + aCtrlArray[nPtr2][2] SAY cColSep
  588.     NEXT
  589.   NEXT
  590. RETURN NIL
  591.  
  592. ******************************************************************************
  593. * KbrowseDat - refreshes all displayed data, highlights item
  594. ******************************************************************************
  595. FUNCTION KbrowseDat(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  596.                     nRowTop,nRowBot,nRowPtr,;
  597.                     nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  598.                     cNtxTopKey,cNtxBotKey)
  599.   LOCAL nPtr1
  600.   LOCAL nPtr2
  601.   LOCAL nPtr3
  602.   GO nRecordTop
  603.   nRecordPtr = -1
  604.   FOR nPtr1 = nRowTop TO nRowBot
  605.     IF KbrowseEof(cNtxTopKey,cNtxBotKey)
  606.       EXIT
  607.     ENDIF
  608.     IF nFreeze > 0
  609.       FOR nPtr2 = 1 TO nFreeze
  610.         @ nPtr1,aCtrlArray[nPtr2][1] SAY EVAL(aCtrlArray[nPtr2][4])
  611.       NEXT
  612.     ENDIF
  613.     FOR nPtr2 = nCtrlTop TO nCtrlBot
  614.       @ nPtr1,aCtrlArray[nPtr2][1] SAY EVAL(aCtrlArray[nPtr2][4])
  615.     NEXT
  616.     IF nPtr1 = nRowPtr
  617.       nRecordPtr = RECNO()
  618.       COLORSELECT(1)
  619.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  620.       COLORSELECT(0)
  621.     ENDIF
  622.     nRecordBot = RECNO()
  623.     nRecRowBot = nPtr1
  624.     SKIP
  625.   NEXT
  626.   IF nRecordPtr < 0
  627.     nRecordPtr = nRecordBot
  628.     nRowPtr = nRecRowBot
  629.     GO nRecordBot
  630.     COLORSELECT(1)
  631.     @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  632.     COLORSELECT(0)
  633.   ENDIF
  634.   FOR nPtr1 = nPtr1 TO nRowBot
  635.     IF nFreeze > 0
  636.       FOR nPtr2 = 1 TO nFreeze
  637.         @ nPtr1,aCtrlArray[nPtr2][1] SAY SPACE(aCtrlArray[nPtr2][2])
  638.       NEXT
  639.     ENDIF
  640.     FOR nPtr2 = nCtrlTop TO nCtrlBot
  641.       @ nPtr1,aCtrlArray[nPtr2][1] SAY SPACE(aCtrlArray[nPtr2][2])
  642.     NEXT
  643.   NEXT
  644. RETURN NIL
  645.  
  646. ******************************************************************************
  647. * KbrowseSrc - incremental search routine
  648. ******************************************************************************
  649. FUNCTION KbrowseSrc(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  650.                     nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  651.                     nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  652.                     cNtxTopKey,cNtxBotKey,;
  653.                     nHeadrow,cHeadSep,cColSep,;
  654.                     nKeyPress,cSeekVar,cSaveColor)
  655.   LOCAL cTestVar
  656.   DISPBEGIN()
  657.     BEGIN SEQUENCE
  658.       IF nKeyPress = 8  && backspace
  659.         IF LEN(cSeekVar) <> 0
  660.           cSeekVar = SUBSTR(cSeekVar,1,LEN(cSeekVar)-1)
  661.           IF LEN(cSeekVar) = 0
  662.             BREAK
  663.           ENDIF
  664.           SEEK cSeekVar
  665.           IF .NOT. FOUND()
  666.             GO nRecordPtr
  667.             BREAK
  668.           ENDIF
  669.         ENDIF
  670.       ELSE
  671.         cTestVar = TRANSFORM(cSeekVar + CHR(nKeyPress),aCtrlArray[nCtrlPtr][6])
  672.         IF cTestVar = &(INDEXKEY(0))
  673.           cSeekVar = cTestVar
  674.           BREAK
  675.         ENDIF
  676.         SEEK cTestVar
  677.         IF .NOT. FOUND()
  678.           GO nRecordPtr
  679.           BREAK
  680.         ENDIF
  681.         cSeekVar = cTestVar
  682.       ENDIF
  683.       IF RECNO() <> nRecordPtr
  684.         nRecordTop = RECNO()
  685.         nRecordPtr = RECNO()
  686.         nRowPtr = nRowTop
  687.         KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  688.                   @nRowTop,@nRowBot,@nRowPtr,;
  689.                   @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  690.                   @cNtxTopKey,@cNtxBotKey)
  691.         GO nRecordPtr
  692.       ENDIF
  693.     END SEQUENCE
  694.     COLORSELECT(1)
  695.     @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  696.     COLORSELECT(0)
  697.     IF LEN(cSeekVar) <> 0
  698.       SETCOLOR("W+/N")
  699.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY cSeekVar
  700.       SETCOLOR(cSaveColor)
  701.     ENDIF
  702.   DISPEND()
  703. RETURN NIL
  704.  
  705. ******************************************************************************
  706. * KbrowseUp - up arrow handler
  707. ******************************************************************************
  708. FUNCTION KbrowseUp(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  709.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  710.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  711.                    cNtxTopKey,cNtxBotKey,;
  712.                    nHeadrow,cHeadSep,cColSep)
  713.   LOCAL nPtr1
  714.   DO WHILE .T.
  715.     SKIP -1
  716.     IF KbrowseBof(cNtxTopKey,cNtxBotKey)
  717.       KbrowseTop(cNtxTopKey,cNtxBotKey)
  718.       RETURN NIL
  719.     ENDIF
  720.     SKIP
  721.     DISPBEGIN()
  722.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  723.       SKIP -1
  724.       nRecordPtr = RECNO()
  725.       nRowPtr--
  726.       IF nRowPtr < nRowTop
  727.         nRowPtr = nRowTop
  728.         GO nRecordTop
  729.         SKIP -1
  730.         nRecordTop = RECNO()
  731.         IF nRecRowBot < nRowBot
  732.           nRecRowBot++
  733.         ELSE
  734.           GO nRecordBot
  735.           SKIP -1
  736.           nRecordBot = RECNO()
  737.         ENDIF
  738.         GO nRecordPtr
  739.         SCROLL(nRowTop,nColTop,nRowBot,nColBot,-1)
  740.         IF nFreeze > 0
  741.           FOR nPtr1 = 1 TO nFreeze
  742.             @ nRowPtr,aCtrlArray[nPtr1][1] SAY EVAL(aCtrlArray[nPtr1][4])
  743.           NEXT
  744.           FOR nPtr1 = 1 TO nFreeze
  745.             @ nRowPtr,aCtrlArray[nPtr1][1] + aCtrlArray[nPtr1][2] SAY cColSep
  746.           NEXT
  747.         ENDIF
  748.         FOR nPtr1 = nCtrlTop TO nCtrlBot
  749.           @ nRowPtr,aCtrlArray[nPtr1][1] SAY EVAL(aCtrlArray[nPtr1][4])
  750.         NEXT
  751.         FOR nPtr1 = nCtrlTop TO nCtrlBot-1
  752.           @ nRowPtr,aCtrlArray[nPtr1][1] + aCtrlArray[nPtr1][2] SAY cColSep
  753.         NEXT
  754.       ENDIF
  755.       COLORSELECT(1)
  756.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  757.       COLORSELECT(0)
  758.     DISPEND()
  759.     IF NEXTKEY() <> 5
  760.       EXIT
  761.     ENDIF
  762.     INKEY()
  763.   ENDDO
  764. RETURN NIL
  765.  
  766. ******************************************************************************
  767. * KbrowseDn - down arrow handler
  768. ******************************************************************************
  769. FUNCTION KbrowseDn(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  770.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  771.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  772.                    cNtxTopKey,cNtxBotKey,;
  773.                    nHeadrow,cHeadSep,cColSep)
  774.   LOCAL nPtr1
  775.   DO WHILE .T.
  776.     SKIP
  777.     IF KbrowseEof(cNtxTopKey,cNtxBotKey)
  778.       KbrowseBot(cNtxTopKey,cNtxBotKey)
  779.       RETURN NIL
  780.     ENDIF
  781.     SKIP -1
  782.     DISPBEGIN()
  783.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  784.       SKIP
  785.       nRecordPtr = RECNO()
  786.       nRowPtr++
  787.       IF nRowPtr > nRowBot
  788.         nRowPtr = nRowBot
  789.         GO nRecordTop
  790.         SKIP
  791.         nRecordTop = RECNO()
  792.         GO nRecordBot
  793.         SKIP
  794.         nRecordBot = RECNO()
  795.         GO nRecordPtr
  796.         SCROLL(nRowTop,nColTop,nRowBot,nColBot,1)
  797.         IF nFreeze > 0
  798.           FOR nPtr1 = 1 TO nFreeze
  799.             @ nRowPtr,aCtrlArray[nPtr1][1] SAY EVAL(aCtrlArray[nPtr1][4])
  800.           NEXT
  801.           FOR nPtr1 = 1 TO nFreeze
  802.             @ nRowPtr,aCtrlArray[nPtr1][1] + aCtrlArray[nPtr1][2] SAY cColSep
  803.           NEXT
  804.         ENDIF
  805.         FOR nPtr1 = nCtrlTop TO nCtrlBot
  806.           @ nRowPtr,aCtrlArray[nPtr1][1] SAY EVAL(aCtrlArray[nPtr1][4]) 
  807.         NEXT
  808.         FOR nPtr1 = nCtrlTop TO nCtrlBot-1
  809.           @ nRowPtr,aCtrlArray[nPtr1][1] + aCtrlArray[nPtr1][2] SAY cColSep
  810.         NEXT
  811.       ENDIF
  812.       COLORSELECT(1)
  813.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  814.       COLORSELECT(0)
  815.     DISPEND()
  816.     IF NEXTKEY() <> 24
  817.       EXIT
  818.     ENDIF
  819.     INKEY()
  820.   ENDDO
  821. RETURN NIL
  822.  
  823. ******************************************************************************
  824. * KbrowsePu - page up handler
  825. ******************************************************************************
  826. FUNCTION KbrowsePu(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  827.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  828.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  829.                    cNtxTopKey,cNtxBotKey,;
  830.                    nHeadrow,cHeadSep,cColSep)
  831.   LOCAL nPtr1
  832.   GO nRecordTop
  833.   SKIP -1
  834.   IF KbrowseBof(cNtxTopKey,cNtxBotKey)
  835.     KbrowseTop(cNtxTopKey,cNtxBotKey)
  836.     IF nRowPtr = nRowTop
  837.       RETURN NIL
  838.     ENDIF
  839.     DISPBEGIN()
  840.       GO nRecordPtr
  841.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  842.       nRecordPtr = nRecordTop
  843.       nRowPtr = nRowTop
  844.       GO nRecordPtr
  845.       COLORSELECT(1)
  846.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  847.       COLORSELECT(0)
  848.     DISPEND()
  849.     RETURN NIL
  850.   ENDIF
  851.   DISPBEGIN()
  852.     SKIP (nRowBot - nRowTop) * -1
  853.     IF KbrowseBof(cNtxTopKey,cNtxBotKey)
  854.       KbrowseTop(cNtxTopKey,cNtxBotKey)
  855.     ENDIF
  856.     nRecordTop = RECNO()
  857.     KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  858.                @nRowTop,@nRowBot,@nRowPtr,;
  859.                @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  860.                @cNtxTopKey,@cNtxBotKey)
  861.     GO nRecordPtr
  862.     CLEAR TYPEAHEAD
  863.   DISPEND()
  864. RETURN NIL
  865.  
  866. ******************************************************************************
  867. * KbrowsePd - page down handler
  868. ******************************************************************************
  869. FUNCTION KbrowsePd(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  870.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  871.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  872.                    cNtxTopKey,cNtxBotKey,;
  873.                    nHeadrow,cHeadSep,cColSep)
  874.   LOCAL nPtr1
  875.   LOCAL nPtr2
  876.   GO nRecordBot
  877.   SKIP
  878.   IF KbrowseEof(cNtxTopKey,cNtxBotKey)
  879.     KbrowseBot(cNtxTopKey,cNtxBotKey)
  880.     IF nRecordPtr = RECNO()
  881.       RETURN NIL
  882.     ENDIF
  883.     DISPBEGIN()
  884.       GO nRecordPtr
  885.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  886.       DO WHILE .T.
  887.         SKIP
  888.         IF KbrowseEof(cNtxTopKey,cNtxBotKey)
  889.           EXIT
  890.         ENDIF
  891.         nRowPtr++
  892.       ENDDO
  893.       KbrowseBot(cNtxTopKey,cNtxBotKey)
  894.       nRecordPtr = RECNO()
  895.       COLORSELECT(1)
  896.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  897.       COLORSELECT(0)
  898.     DISPEND()
  899.     RETURN NIL
  900.   ENDIF
  901.   DISPBEGIN()
  902.     nRecordTop = RECNO()
  903.     KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  904.                @nRowTop,@nRowBot,@nRowPtr,;
  905.                @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  906.                @cNtxTopKey,@cNtxBotKey)
  907.     GO nRecordPtr
  908.     CLEAR TYPEAHEAD
  909.   DISPEND()
  910. RETURN NIL
  911.  
  912. ******************************************************************************
  913. * KbrowseLf - left arrow handler
  914. ******************************************************************************
  915. FUNCTION KbrowseLf(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  916.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  917.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  918.                    cNtxTopKey,cNtxBotKey,;
  919.                    nHeadrow,cHeadSep,cColSep)
  920.   LOCAL nPtr1
  921.   LOCAL nWidth
  922.   LOCAL nFreezeWidth
  923.   LOCAL nTmpCtrlPtr := nCtrlPtr
  924.   LOCAL nTmpCtrlTop := nCtrlTop
  925.   LOCAL nTmpCtrlBot := nCtrlBot
  926.   DO CASE
  927.   CASE nTmpCtrlPtr = 1
  928.     RETURN NIL
  929.   CASE nTmpCtrlPtr > nTmpCtrlTop .OR. nTmpCtrlPtr <= nFreeze
  930.     nTmpCtrlPtr--
  931.   CASE nFreeze = 0 .AND. nTmpCtrlTop > 1
  932.     nTmpCtrlTop--
  933.     nTmpCtrlPtr = nTmpCtrlTop
  934.     nTmpCtrlBot = nTmpCtrlTop
  935.   CASE nFreeze > 0 .AND. nTmpCtrlPtr = nFreeze + 1
  936.     nTmpCtrlPtr = nFreeze
  937.   CASE nFreeze > 0 .AND. nTmpCtrlTop > nFreeze + 1
  938.     nTmpCtrlTop--
  939.     nTmpCtrlPtr = nTmpCtrlTop
  940.     nTmpCtrlBot = nTmpCtrlTop
  941.   OTHERWISE
  942.     RETURN NIL
  943.   ENDCASE
  944.   IF nTmpCtrlTop = nCtrlTop
  945.     DISPBEGIN()
  946.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  947.       nCtrlPtr = nTmpCtrlPtr
  948.       COLORSELECT(1)
  949.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  950.       COLORSELECT(0)
  951.     DISPEND()
  952.     RETURN NIL
  953.   ENDIF
  954.   IF nTmpCtrlTop <> nCtrlTop
  955.     nCtrlTop = nTmpCtrlTop
  956.     nCtrlPtr = nTmpCtrlPtr
  957.     nCtrlBot = nTmpCtrlBot
  958.     nWidth = 0
  959.     nFreezeWidth = 0
  960.     IF nFreeze > 0
  961.       nFreezeWidth = 1
  962.       FOR nPtr1 = 1 TO nFreeze
  963.         IF nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  964.           EXIT
  965.         ENDIF
  966.         nFreezeWidth = nFreezeWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  967.       NEXT
  968.     ENDIF
  969.     FOR nPtr1 = nCtrlTop TO LEN(aCtrlArray)
  970.       IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  971.         EXIT
  972.       ENDIF
  973.       nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  974.       nCtrlBot = nPtr1
  975.     NEXT
  976.     FOR nPtr1 = nCtrlTop-1 TO 1 + nFreeze STEP -1
  977.       IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  978.         EXIT
  979.       ENDIF
  980.       nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  981.       nCtrlTop = nPtr1
  982.     NEXT
  983.     DISPBEGIN()
  984.       KbrowseScr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  985.                  @nColTop,@nColBot,@cColSep)
  986.       KbrowseHdr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  987.                  @nRowTop,@nColTop,@nRowBot,@nColBot,;
  988.                  @nHeadRow,@cHeadSep,@cColSep)
  989.       KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  990.                  @nRowTop,@nRowBot,@nRowPtr,;
  991.                  @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  992.                  @cNtxTopKey,@cNtxBotKey)
  993.       GO nRecordPtr
  994.     DISPEND()
  995.   ENDIF
  996. RETURN NIL
  997.  
  998. ******************************************************************************
  999. * KbrowseRt - right arrow handler
  1000. ******************************************************************************
  1001. FUNCTION KbrowseRt(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  1002.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  1003.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  1004.                    cNtxTopKey,cNtxBotKey,;
  1005.                    nHeadrow,cHeadSep,cColSep)
  1006.   LOCAL nPtr1
  1007.   LOCAL nWidth
  1008.   LOCAL nFreezeWidth
  1009.   LOCAL nTmpCtrlPtr := nCtrlPtr
  1010.   LOCAL nTmpCtrlTop := nCtrlTop
  1011.   LOCAL nTmpCtrlBot := nCtrlBot
  1012.   DO CASE
  1013.   CASE nTmpCtrlPtr = LEN(aCtrlArray)
  1014.     RETURN NIL
  1015.   CASE nFreeze = 0 .AND. nTmpCtrlPtr < nTmpCtrlBot
  1016.     nTmpCtrlPtr++
  1017.   CASE nFreeze > 0 .AND. nTmpCtrlPtr < nFreeze
  1018.     nTmpCtrlPtr++
  1019.   CASE nFreeze > 0 .AND. nTmpCtrlPtr = nFreeze
  1020.     nTmpCtrlPtr = nTmpCtrlTop
  1021.   CASE nFreeze > 0 .AND. nTmpCtrlPtr < nTmpCtrlBot
  1022.     nTmpCtrlPtr++
  1023.   CASE nTmpCtrlBot < LEN(aCtrlArray)
  1024.     nTmpCtrlTop = nTmpCtrlBot + 1
  1025.     nTmpCtrlPtr = nTmpCtrlTop
  1026.     nTmpCtrlBot = nTmpCtrlTop
  1027.   OTHERWISE
  1028.     RETURN NIL
  1029.   ENDCASE
  1030.   IF nTmpCtrlTop = nCtrlTop
  1031.     DISPBEGIN()
  1032.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1033.       nCtrlPtr = nTmpCtrlPtr
  1034.       COLORSELECT(1)
  1035.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1036.       COLORSELECT(0)
  1037.     DISPEND()
  1038.     RETURN NIL
  1039.   ENDIF
  1040.   IF nTmpCtrlTop <> nCtrlTop
  1041.     nCtrlTop = nTmpCtrlTop
  1042.     nCtrlPtr = nTmpCtrlPtr
  1043.     nCtrlBot = nTmpCtrlBot
  1044.     nWidth = 0
  1045.     nFreezeWidth = 0
  1046.     IF nFreeze > 0
  1047.       nFreezeWidth = 1
  1048.       FOR nPtr1 = 1 TO nFreeze
  1049.         IF nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1050.           EXIT
  1051.         ENDIF
  1052.         nFreezeWidth = nFreezeWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1053.       NEXT
  1054.     ENDIF
  1055.     FOR nPtr1 = nCtrlBot TO 1 + nFreeze STEP - 1
  1056.       IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1057.         EXIT
  1058.       ENDIF
  1059.       nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1060.       nCtrlTop = nPtr1
  1061.     NEXT
  1062.     FOR nPtr1 = nCtrlBot+1 TO LEN(aCtrlArray)
  1063.       IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1064.         EXIT
  1065.       ENDIF
  1066.       nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1067.       nCtrlBot = nPtr1
  1068.     NEXT
  1069.     DISPBEGIN()
  1070.       KbrowseScr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  1071.                  @nColTop,@nColBot,@cColSep)
  1072.       KbrowseHdr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  1073.                  @nRowTop,@nColTop,@nRowBot,@nColBot,;
  1074.                  @nHeadRow,@cHeadSep,@cColSep)
  1075.       KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  1076.                  @nRowTop,@nRowBot,@nRowPtr,;
  1077.                  @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  1078.                  @cNtxTopKey,@cNtxBotKey)
  1079.       GO nRecordPtr
  1080.     DISPEND()
  1081.   ENDIF
  1082. RETURN NIL
  1083.  
  1084. ******************************************************************************
  1085. * KbrowseHom - home handler
  1086. ******************************************************************************
  1087. FUNCTION KbrowseHom(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  1088.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  1089.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  1090.                    cNtxTopKey,cNtxBotKey,;
  1091.                    nHeadrow,cHeadSep,cColSep)
  1092.   IF nCtrlPtr > nCtrlTop .OR. (nFreeze > 0 .AND. nCtrlPtr > 1)
  1093.     DISPBEGIN()
  1094.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1095.       IF nFreeze > 0
  1096.         nCtrlPtr = 1
  1097.       ELSE
  1098.         nCtrlPtr = nCtrlTop
  1099.       ENDIF
  1100.       COLORSELECT(1)
  1101.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1102.       COLORSELECT(0)
  1103.     DISPEND()
  1104.   ENDIF
  1105. RETURN NIL
  1106.  
  1107. ******************************************************************************
  1108. * KbrowseEnd - end handler
  1109. ******************************************************************************
  1110. FUNCTION KbrowseEnd(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  1111.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  1112.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  1113.                    cNtxTopKey,cNtxBotKey,;
  1114.                    nHeadrow,cHeadSep,cColSep)
  1115.   IF nCtrlPtr < nCtrlBot
  1116.     DISPBEGIN()
  1117.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1118.       nCtrlPtr = nCtrlBot
  1119.       COLORSELECT(1)
  1120.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1121.       COLORSELECT(0)
  1122.     DISPEND()
  1123.   ENDIF
  1124. RETURN NIL
  1125.  
  1126. ******************************************************************************
  1127. * KbrowseCLf - ctrl-left arrow handler
  1128. ******************************************************************************
  1129. FUNCTION KbrowseCLf(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  1130.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  1131.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  1132.                    cNtxTopKey,cNtxBotKey,;
  1133.                    nHeadrow,cHeadSep,cColSep)
  1134.   LOCAL nPtr1
  1135.   LOCAL nWidth
  1136.   LOCAL nFreezeWidth
  1137.   IF nCtrlTop = 1 .OR. (nFreeze > 0 .AND. nCtrlTop = nFreeze + 1)
  1138.     DISPBEGIN()
  1139.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1140.       nCtrlPtr = 1
  1141.       COLORSELECT(1)
  1142.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1143.       COLORSELECT(0)
  1144.     DISPEND()
  1145.     RETURN NIL
  1146.   ENDIF
  1147.   nCtrlBot = nCtrlTop - 1
  1148.   nCtrlPtr = nCtrlTop - 1
  1149.   nCtrlTop = nCtrlTop - 1
  1150.   nFreezeWidth = 0
  1151.   IF nFreeze > 0
  1152.     nFreezeWidth = 1
  1153.     FOR nPtr1 = 1 TO nFreeze
  1154.       IF nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1155.         EXIT
  1156.       ENDIF
  1157.       nFreezeWidth = nFreezeWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1158.     NEXT
  1159.   ENDIF
  1160.   nWidth = 0
  1161.   FOR nPtr1 = nCtrlBot TO 1 + nFreeze STEP - 1
  1162.     IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1163.       EXIT
  1164.     ENDIF
  1165.     nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1166.     nCtrlTop = nPtr1
  1167.     nCtrlPtr = nPtr1
  1168.   NEXT
  1169.   FOR nPtr1 = nCtrlBot+1 TO LEN(aCtrlArray)
  1170.     IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1171.       EXIT
  1172.     ENDIF
  1173.     nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1174.     nCtrlBot = nPtr1
  1175.   NEXT
  1176.   DISPBEGIN()
  1177.     KbrowseScr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  1178.                @nColTop,@nColBot,@cColSep)
  1179.     KbrowseHdr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  1180.                @nRowTop,@nColTop,@nRowBot,@nColBot,;
  1181.                @nHeadRow,@cHeadSep,@cColSep)
  1182.     KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  1183.                @nRowTop,@nRowBot,@nRowPtr,;
  1184.                @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  1185.                @cNtxTopKey,@cNtxBotKey)
  1186.     GO nRecordPtr
  1187.   DISPEND()
  1188. RETURN NIL
  1189.  
  1190. ******************************************************************************
  1191. * KbrowseCRt - ctrl-right arrow handler
  1192. ******************************************************************************
  1193. FUNCTION KbrowseCRt(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  1194.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  1195.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  1196.                    cNtxTopKey,cNtxBotKey,;
  1197.                    nHeadrow,cHeadSep,cColSep)
  1198.   LOCAL nPtr1
  1199.   LOCAL nWidth
  1200.   LOCAL nFreezeWidth
  1201.   IF nCtrlBot = LEN(aCtrlArray)
  1202.     DISPBEGIN()
  1203.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1204.       nCtrlPtr = nCtrlBot
  1205.       COLORSELECT(1)
  1206.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1207.       COLORSELECT(0)
  1208.     DISPEND()
  1209.     RETURN NIL
  1210.   ENDIF
  1211.   nCtrlTop = nCtrlBot + 1
  1212.   nCtrlPtr = nCtrlBot + 1
  1213.   nFreezeWidth = 0
  1214.   IF nFreeze > 0
  1215.     nFreezeWidth = 1
  1216.     FOR nPtr1 = 1 TO nFreeze
  1217.       IF nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1218.         EXIT
  1219.       ENDIF
  1220.       nFreezeWidth = nFreezeWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1221.     NEXT
  1222.   ENDIF
  1223.   nWidth = 0
  1224.   FOR nPtr1 = nCtrlTop TO LEN(aCtrlArray)
  1225.     IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1226.       EXIT
  1227.     ENDIF
  1228.     nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1229.     nCtrlBot = nPtr1
  1230.   NEXT
  1231.   FOR nPtr1 = nCtrlTop-1 TO 1 + nFreeze STEP - 1
  1232.     IF nWidth + nFreezeWidth + aCtrlArray[nPtr1][2] > nColBot-nColTop
  1233.       EXIT
  1234.     ENDIF
  1235.     nWidth = nWidth + aCtrlArray[nPtr1][2] + LEN(cColSep)
  1236.     nCtrlTop = nPtr1
  1237.   NEXT
  1238.   DISPBEGIN()
  1239.     KbrowseScr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  1240.                @nColTop,@nColBot,@cColSep)
  1241.     KbrowseHdr(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nFreeze,;
  1242.                @nRowTop,@nColTop,@nRowBot,@nColBot,;
  1243.                @nHeadRow,@cHeadSep,@cColSep)
  1244.     KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  1245.                @nRowTop,@nRowBot,@nRowPtr,;
  1246.                @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  1247.                @cNtxTopKey,@cNtxBotKey)
  1248.     GO nRecordPtr
  1249.   DISPEND()
  1250. RETURN NIL
  1251.  
  1252. ******************************************************************************
  1253. * KbrowseCPu - ctrl-page up handler
  1254. ******************************************************************************
  1255. FUNCTION KbrowseCPu(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  1256.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  1257.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  1258.                    cNtxTopKey,cNtxBotKey,;
  1259.                    nHeadrow,cHeadSep,cColSep)
  1260.   GO nRecordTop
  1261.   SKIP -1
  1262.   IF KbrowseBof(cNtxTopKey,cNtxBotKey)
  1263.     KbrowseTop(cNtxTopKey,cNtxBotKey)
  1264.     IF nRowPtr = nRowTop
  1265.       RETURN NIL
  1266.     ENDIF
  1267.     DISPBEGIN()
  1268.       GO nRecordPtr
  1269.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1270.       nRecordPtr = nRecordTop
  1271.       nRowPtr = nRowTop
  1272.       GO nRecordPtr
  1273.       COLORSELECT(1)
  1274.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1275.       COLORSELECT(0)
  1276.     DISPEND()
  1277.     RETURN NIL
  1278.   ENDIF
  1279.   KbrowseTop(cNtxTopKey,cNtxBotKey)
  1280.   DISPBEGIN()
  1281.     nRecordTop = RECNO()
  1282.     nRowPtr = nRowTop
  1283.     nRecordPtr = RECNO()
  1284.     KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  1285.                @nRowTop,@nRowBot,@nRowPtr,;
  1286.                @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  1287.                @cNtxTopKey,@cNtxBotKey)
  1288.     GO nRecordPtr
  1289.   DISPEND()
  1290. RETURN NIL
  1291.  
  1292. ******************************************************************************
  1293. * KbrowseCPd - ctrl-page down handler
  1294. ******************************************************************************
  1295. FUNCTION KbrowseCPd(aCtrlArray,nCtrlTop,nCtrlBot,nCtrlPtr,nFreeze,;
  1296.                    nRowTop,nRowBot,nColTop,nColBot,nRowPtr,;
  1297.                    nRecordTop,nRecordBot,nRecordPtr,nRecRowBot,;
  1298.                    cNtxTopKey,cNtxBotKey,;
  1299.                    nHeadrow,cHeadSep,cColSep)
  1300.   LOCAL nPtr1
  1301.   GO nRecordBot
  1302.   SKIP
  1303.   IF KbrowseEof(cNtxTopKey,cNtxBotKey)
  1304.     KbrowseBot(cNtxTopKey,cNtxBotKey)
  1305.     IF nRecordPtr = RECNO()
  1306.       RETURN NIL
  1307.     ENDIF
  1308.     DISPBEGIN()
  1309.       GO nRecordPtr
  1310.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1311.       DO WHILE .T.
  1312.         SKIP
  1313.         IF KbrowseEof(cNtxTopKey,cNtxBotKey)
  1314.           EXIT
  1315.         ENDIF
  1316.         nRowPtr++
  1317.       ENDDO
  1318.       KbrowseBot(cNtxTopKey,cNtxBotKey)
  1319.       nRecordPtr = RECNO()
  1320.       COLORSELECT(1)
  1321.       @ nRowPtr,aCtrlArray[nCtrlPtr][1] SAY EVAL(aCtrlArray[nCtrlPtr][4])
  1322.       COLORSELECT(0)
  1323.     DISPEND()
  1324.     RETURN NIL
  1325.   ENDIF
  1326.   DISPBEGIN()
  1327.     nRowPtr = nRowBot
  1328.     KbrowseBot(cNtxTopKey,cNtxBotKey)
  1329.     nRecordPtr = RECNO()
  1330.     FOR nPtr1 = nRowTop TO nRowBot -1
  1331.       SKIP - 1
  1332.       IF KbrowseBof(cNtxTopKey,cNtxBotKey)
  1333.         EXIT
  1334.       ENDIF
  1335.     NEXT
  1336.     IF KbrowseBof(cNtxTopKey,cNtxBotKey)
  1337.       KbrowseTop(cNtxTopKey,cNtxBotKey)
  1338.     ENDIF
  1339.     nRecordTop = RECNO()
  1340.     KbrowseDat(@aCtrlArray,@nCtrlTop,@nCtrlBot,@nCtrlPtr,@nFreeze,;
  1341.                @nRowTop,@nRowBot,@nRowPtr,;
  1342.                @nRecordTop,@nRecordBot,@nRecordPtr,@nRecRowBot,;
  1343.                @cNtxTopKey,@cNtxBotKey)
  1344.     GO nRecordPtr
  1345.   DISPEND()
  1346. RETURN NIL
  1347.  
  1348. ******************************************************************************
  1349. * KbrowseEof - test for EOF()
  1350. ******************************************************************************
  1351. FUNCTION KbrowseEof(cNtxTopKey,cNtxBotKey) 
  1352.   IF EOF()
  1353.     RETURN .T.
  1354.   ENDIF
  1355.   IF LEN(cNtxTopKey) <> 0
  1356.     IF &(INDEXKEY(0)) < cNtxTopKey
  1357.       RETURN .T.
  1358.     ENDIF
  1359.   ENDIF
  1360.   IF LEN(cNtxBotKey) <> 0
  1361.     IF &(INDEXKEY(0)) > cNtxBotKey
  1362.       RETURN .T.
  1363.     ENDIF
  1364.   ENDIF
  1365. RETURN .F.
  1366.  
  1367. ******************************************************************************
  1368. * KbrowseBof - test for BOF()
  1369. ******************************************************************************
  1370. FUNCTION KbrowseBof(cNtxTopKey,cNtxBotKey) 
  1371.   IF BOF()
  1372.     RETURN .T.
  1373.   ENDIF
  1374.   IF LEN(cNtxTopKey) <> 0
  1375.     IF &(INDEXKEY(0)) < cNtxTopKey
  1376.       RETURN .T.
  1377.     ENDIF
  1378.   ENDIF
  1379.   IF LEN(cNtxBotKey) <> 0
  1380.     IF &(INDEXKEY(0)) > cNtxBotKey
  1381.       RETURN .T.
  1382.     ENDIF
  1383.   ENDIF
  1384. RETURN .F.
  1385.  
  1386. ******************************************************************************
  1387. * KbrowseTop - GO TOP processor
  1388. ******************************************************************************
  1389. FUNCTION KbrowseTop(cNtxTopKey,cNtxBotKey) 
  1390.   IF LEN(cNtxTopKey) = 0
  1391.     GO TOP
  1392.     RETURN NIL
  1393.   ENDIF
  1394.   IF LEN(cNtxTopKey) <> 0
  1395.     SEEK cNtxTopKey
  1396.   ENDIF
  1397. RETURN NIL
  1398.  
  1399. ******************************************************************************
  1400. * KbrowseBot - GO BOTTOM processor
  1401. ******************************************************************************
  1402. FUNCTION KbrowseBot(cNtxTopKey,cNtxBotKey) 
  1403.   LOCAL cSeekType
  1404.   LOCAL cSeekVar
  1405.   IF LEN(cNtxTopKey) = 0
  1406.     GO BOTTOM
  1407.     RETURN NIL
  1408.   ENDIF
  1409.   cSeekVar = cNtxBotKey
  1410.     cSeekType := VALTYPE(cSeekVar)
  1411.     DO CASE
  1412.     CASE cSeekType == "C"
  1413.         cSeekVar := STUFF(cSeekVar,LEN(cSeekVar),1,CHR(ASC(RIGHT(cSeekVar,1))+1))
  1414.     CASE cSeekType == "N"
  1415.         cSeekVar++
  1416.     CASE cSeekType == "D"
  1417.         cSeekVar++
  1418.     ENDCASE
  1419.   SET SOFTSEEK ON
  1420.   SEEK cSeekVar
  1421.   SET SOFTSEEK OFF
  1422.   IF .NOT. EOF()
  1423.     SKIP -1
  1424.   ENDIF
  1425. RETURN NIL
  1426.  
  1427.  
  1428.