home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BUG 4
/
BUGCD1997_05.BIN
/
aplic
/
clip4win
/
clip4win.exe
/
C4W30E.HUF
/
SOURCE
/
CONTRIB
/
WBROWS.ZIP
/
WBROWSE.PRG
Wrap
Text File
|
1993-05-26
|
43KB
|
1,091 lines
// WBrowse() - A "generic" tbrowse() routine for use with Clip4Win.
// By Hugh A. Lokey, 05/26/93
//
// With WBrowse() you can browse indexed files, files without indexes, and
// sub-sets of files. From within WBrowse() a user can Add a record, Delete
// a record, Edit a record, Find/Search for a record, and Print reports/
// lists. WBrowse() is "modeless" so a user can do anything you allow them
// to do while browsing. You can have as many browse windows open as
// memory allows. If you have multiple browse windows open at one time
// WBrowse() will update each window automatically each time Windows
// tells it to (fun to watch!).
//
// Calling conventions/param list:
//
// WBrowse(cPrompt,; String you want to appear on the statusbar
// bSearch,; Codeblock for searching
// cKey,; Search key for browsing sub-sets of a database
// bKeyBlk,; Codeblock to do searching for sub-sets
// aBrowFields,; Array containing the fields for the browse,
// has two dimensions, the first contains the field
// number or a codeblock. The second contains a
// string to use for the column header.
// bEDTUDF,; Codeblock to use when the user selects Edit.
// bDELUDF,; Codeblock to use when the user selects Delete.
// bADDUDF,; Codeblock to use when the user selects Add.
// bSELUDF,; Codeblock to use when the user selects View.
// bPRNUDF,; Codeblock to use when the user selects Print.
// cAlias,; Alias of database being browsed.
// cTitle,; Title for browse window.
// bDestroy) Optional codeblock to use when browse terminated.
// NOTES:
//
// 1. bSearch - If you are going to let the user do searchs you need
// to include a codeblock else just pass .F.. For an indexed database
// you use something like {|cSKey|DBSEEK(cSKey)}. For a database that
// is not indexed or you are going to browse in natural order you
// would use something like {|cStr|FindIt(cStr)} where FindIt(cStr)
// looks something like this:
// STATIC FUNCTION FindIt(cStr)
//
// LOCATE FOR cStr $ UPPER(SYSLOG->TEXT)
// RETURN(NIL)
// 2. cKey/bKeyBlk - This is an expression or database field that will be used
// to limit the scope of the browse to a sub-set of a database. The following
// example shows how cKey and cKeyBlk are used to limit the browse to
// a sub-set:
//STATIC FUNCTION HistViewer
// LOCAL bSELUDF := {||BViewHist()},;
// bEDTUDF := "",;
// bADDUDF := "",;
// bDELUDF := "",;
// bPRNUDF := {||BPrntStat()}
//
// LOCAL bKeyBlk :={||ACCTHIST->ACCT_NO}
// LOCAL aCols := {{{||DTOC(ACCTHIST->DATE)},"DATE"},;
// {{||Ptype(ACCTHIST->TYPE)},"TYPE"},;
// {{||STR(ACCTHIST->AMOUNT,7,2)},"AMOUNT"},;
// {{||LEFT(ACCTHIST->TXCODE,40)},"FOR"},;
// {{||PADL(ALLTRIM(TRANSFORM(ACCTHIST->BALANCE,'@B( 99999.99')),9)},"BALANCE"}}
//
//
// SELECT ACCTHIST
// WBrowse("ACCOUNT HISTORY FOR: "+PARENTS->(MakeName()),;
// .F.,;
// PARENTS->SSN,;
// bKeyBlk,;
// aCols,;
// bEDTUDF,;
// bDELUDF,;
// bADDUDF,;
// bSELUDF,;
// bPRNUDF,;
// "ACCTHIST",;
// "Review Account History",;
// .F.)
//
//RETURN(NIL)
//
// since we are already browsing a sub-set of a database then we do not
// have the luxury of allowing the user to perform searchs since we are
// moving the record pointer with seeks already.
// 3. aBrowFields - In the above example we use codeblocks in all of
// the browse field definitions. You can use either a field number or
// codeblock in the first position. The second position requires a
// string to use as the column header. If you are lazy and want to
// include all fields with their field names as column headers you
// use LdBrowFlds() as this param. LdBrowFlds() returns an array
// consisting of the field number and field name that WBrowse() can
// use. You can mix codeblocks and field numbers. The following
// example uses a relation in the browse and uses a mix of codeblocks
// and field numbers:
//STATIC FUNCTION BrowChld
// LOCAL bSELUDF := {||BViewChild()},;
// bEDTUDF := {||BEditChild(),;
// bDELUDF := {||BDelChild()},;
// bADDUDF := {||BAddChild()},;
// bPRNUDF := {||BPrnChild()}
//
// LOCAL aCols := {{{||MakeName()},"NAME"},;
// { 1,"ID#"},;
// { 16,"STATUS"},;
// { 19,"ROOM"},;
// { {||RATES->RATE_CODE+' '+RATES->DESCRIPT},"BILLING RATE"}}
//
// SELECT CHILD
// SET ORDER TO 2
// GO TOP
// SET RELATION TO RATE_CODE INTO RATES
// WBrowse("SEARCH KEY: LASTNAME",;
// {|cSkey|DBSEEK(cSkey)},;
// .F.,;
// .F.,;
// aCols,;
// bEDTUDF,;
// bDELUDF,;
// bADDUDF,;
// bSELUDF,;
// bPRNUDF,;
// "CHILD",;
// "Browse - Children",;
// {||MenuOnOff(.F.)})
//RETURN(NIL)
//
// MakeName() is a function that takes fields containing the lastname,
// firstname, MI, and turns them into a proper name. MenuOnOff() is
// a function that turns the menu items on/off on the menu from where
// Browse was selected. Called when the browse is terminated so the
// menu selections are re-enabled/turned back on.
// 4. bEDTUDF, bADDUDF, bDELUDF, bSELUDF, bPRNUDF - These are all
// optional codeblocks that are called to Edit the highlighted record,
// add a new record, delete the highlighted record, view the highlighted
// record, and to print reports/lists. If you pass something other than
// a codeblock ("", .F., etc.) then WBrowse() will automatically disable
// the button/key used to select that function.
// 5. bDestroy - This is an optional codeblock that is used by the
// DelHandler() routine I use. It is called when the browse is
// terminated. You will have to modifiy YOUR AddHandler() and DelHandler()
// routines to use it. My primary use is to turn off the menu selection
// that invoked the browse then turn it back on when the browse is
// finished. I don't want the user to have two instances of the same
// browse going at one time! I also turn off any other menu items
// that could cause potential havoc if envoked from within the browse.
// 6. General - I take the approach that in order for a user to edit
// an existing record, delete a record or view a record that they
// first must be provided with a way of selecting the record they want
// to work with. Why have the code overhead of providing a routine to
// just locate the record they want when you are going to provide a
// browse routine anyway? In both my DOS and Windows apps I always
// have a menu item labeled "Browse/Delete/Edit". This menu selection
// calls WBrowse() to do it all! Window size, colors, screen location,
// etc. are hard coded so that the browse window appears in the center
// of the window where the menu selection to invoke it is. The window
// size is NOT changeable by the user but they can minimize it or move
// it out of the way. Since I use valid clauses in most of my input
// fields (to prevent "garbage in garbage out"), I don't allow the user
// to edit one field/column in WBrowse() but provide a full screen
// input routine for both editing and adding a new record.
// Those functions that ARE NOT declared as being STATIC are used by
// other routines in my generic Windows Lib. If you don't make use
// of them elsewhere you can make them STATIC to save some table
// space.
// I am not real happy with the statusbar and horizontal scroll bits
// at this time. If someone out there comes up with something better
// please post it so all of us can take a look see.
// Any questions, comments, slurs, etc. will be appreciated.....
****************************************************************
//#include "caresw.ch"
//Modified version of include file included with C4W listed below:
//#define FORCE_FOCUS 6
//#define WIN_WANT_CLIPBOARD
//#define WIN_WANT_LBS
//#define WIN_WANT_HELP
//#define WIN_WANT_ALL
//#include "dbstruct.ch"
//#include "directry.ch"
//#include "error.ch"
//#include "getexit.ch"
//#include "inkey.ch"
//#include "windows.ch"
//#include "setcaret.ch"
//#include "font.ch"
//#include "commdlg.ch"
//#define C_RED RGB(255,0,0)
//#define C_BLUE RGB(0,0,128)
//#define C_GREEN RGB(0,255,0)
//#define C_MAGENTA RGB(255,0,255)
//#define C_BLACK RGB(0,0,0)
//#define APP_NAME "CARES For Windows"
FUNCTION WBrowse(cPrompt,; // Displayed on status bar
bSearch,; // code block to use for searching
cKey,; // key value for sub-sets
bKeyBlk,; // code block to evaluate key
aBrowFields,; // fields/codeblocks for browse
bEDTUDF,; // codeblock for editing
bDELUDF,; // codeblock for deleting
bADDUDF,; // codeblock for adding
bSELUDF,; // codeblock for viewing
bPRNUDF,; // codeblock for printing
cAlias,; // name of database/alias
cTitle,; // title for browse window
bDestroy) // codeblock for DelHandler() to use
LOCAL oB, nCtr, column, nNoFields, nId, hInst, hWnd, hVSb, hHSb
LOCAL aButtons[9][9], hOldWnd
hOldWnd := SelectWindow()
hWnd := WinNew(cTitle, ;
19, ; // x co-ordinate
80, ; // y co-ordinate
602, ; // width
327, ;
WS_BORDER+WS_CAPTION+WS_MINIMIZEBOX+WS_CLIPCHILDREN)
DBSELECTAREA(cAlias)
oB := TBrowseDB(1, 2, 17, 70)
oB:headSep := "┬─"
oB:colSep := "│"
oB:colorSpec := "N/W,W+/N,W+/N,W+/N"
FOR nCtr = 1 TO LEN(aBrowFields)
IF VALTYPE(aBrowFields[nCtr][1]) == 'N'
column := TBColumnNew(aBrowFields[nCtr][2], FieldBlock(FieldName(aBrowFields[nCtr][1])))
ELSE
column := TBColumnNew(aBrowFields[nCtr][2], aBrowFields[nCtr][1])
ENDIF
column:defColor := {1,2}
oB:addColumn(column)
NEXT
IF VALTYPE(bKeyBlk) = 'B'
oB:goBottomblock := {|| FindLast(cKey,bKeyBlk)}
oB:goTopblock := {|| FindFirst(cKey)}
oB:Skipblock := {|nSkip| SkipFor(nSkip,cKey,bKeyBlk)}
IF FindFirst(cKey) == .F.
DestroyWindow(hWnd)
SelectWindow(hOldWnd)
SetFocus(hOldWnd)
IF VALTYPE(bDestroy) == 'B'
EVAL(bDestroy)
ENDIF
RETURN(.F.)
ENDIF
ELSE
GO TOP
IF EOF()
EmptyErr()
DestroyWindow(hWnd)
SelectWindow(hOldWnd)
SetFocus(hOldWnd)
IF VALTYPE(bDestroy) == 'B'
EVAL(bDestroy)
ENDIF
RETURN(.F.)
ENDIF
ENDIF
hInst := _GetInstance()
WinBox(hWnd, 0, 0,600,360,1,2,0)
WinBox(hWnd,12, 8,588,236,1,2,2)
WinBox(hWnd,12,239,588,272,2,2,2)
Message(hWnd,"")
IF VALTYPE(bKeyBlk) != 'B'
WinBox(hWnd, 08,283,438,303,1,2,1,0,4)
WinBox(hWnd,438,283,518,303,1,2,1,0,6)
WinBox(hWnd,516,283,594,303,1,2,1,0,6)
UpdateStatusBar(hWnd,cPrompt,RECCOUNT())
ELSE
UpDateStatusBar(hWnd,cPrompt,0)
ENDIF
aButtons[1][1] := CreateWindow("BUTTON", "Top" ,WS_CHILD + WS_VISIBLE+BS_PUSHBUTTON, 22, 244, 60, 24,hWnd,1,hInst)
aButtons[2][1] := CreateWindow("BUTTON", "Bottom",WS_CHILD + WS_VISIBLE+BS_PUSHBUTTON, 84, 244, 60, 24,hWnd,2,hInst)
aButtons[3][1] := CreateWindow("BUTTON", "Add" ,WS_CHILD + IIF(VALTYPE(bADDUDF)=='B',0,WS_DISABLED)+WS_VISIBLE+BS_PUSHBUTTON, 146, 244, 60, 24,hWnd,3,hInst)
aButtons[4][1] := CreateWindow("BUTTON", "Delete",WS_CHILD + IIF(VALTYPE(bDELUDF)=='B',0,WS_DISABLED)+WS_VISIBLE+BS_PUSHBUTTON, 208, 244, 60, 24,hWnd,4,hInst)
aButtons[5][1] := CreateWindow("BUTTON", "Edit" ,WS_CHILD + IIF(VALTYPE(bEDTUDF)=='B',0,WS_DISABLED)+WS_VISIBLE+BS_PUSHBUTTON, 270, 244, 60, 24,hWnd,5,hInst)
aButtons[6][1] := CreateWindow("BUTTON", "Find" ,WS_CHILD + IIF(VALTYPE(bSearch)=='B',0,WS_DISABLED)+WS_VISIBLE+BS_PUSHBUTTON, 332, 244, 60, 24,hWnd,6,hInst)
aButtons[7][1] := CreateWindow("BUTTON", "Print" ,WS_CHILD + IIF(VALTYPE(bPRNUDF)=='B',0,WS_DISABLED)+WS_VISIBLE+BS_PUSHBUTTON, 394, 244, 60, 24,hWnd,7,hInst)
aButtons[8][1] := CreateWindow("BUTTON", "View" ,WS_CHILD + IIF(VALTYPE(bSELUDF)=='B',0,WS_DISABLED)+WS_VISIBLE+BS_PUSHBUTTON, 456, 244, 60, 24,hWnd,8,hInst)
aButtons[9][1] := CreateWindow("BUTTON", "Quit" ,WS_CHILD + WS_VISIBLE+BS_PUSHBUTTON, 518, 244, 60, 24,hWnd,9,hInst)
hVSb := CreateWindow("SCROLLBAR","" ,SBS_VERT + WS_CHILD + WS_VISIBLE, 569, 11, 17, 206,hWnd,-1,hInst)
hHSb := CreateWindow("SCROLLBAR","" ,SBS_HORZ + WS_CHILD + WS_VISIBLE, 15,216,571, 18,hWnd,-1,hInst)
SetScrollRange(hVSb,SB_CTL,0,100,.F.)
SetScrollRange(hHSb,SB_CTL,0,100,.F.)
IF oB:rightVisible == oB:colCount
EnableWindow(hHSB,.F.)
ENDIF
aButtons[1][2] := .T.
aButtons[2][2] := .T.
aButtons[3][2] := (VALTYPE(bADDUDF)=='B')
aButtons[4][2] := (VALTYPE(bDELUDF)=='B')
aButtons[5][2] := (VALTYPE(bEDTUDF)=='B')
aButtons[6][2] := (VALTYPE(bSearch)=='B')
aButtons[7][2] := (VALTYPE(bPRNUDF)=='B')
aButtons[8][2] := (VALTYPE(bSELUDF)=='B')
aButtons[9][2] := .T.
oB:cargo := {.T.,INDEXORD(),RECNO()}
nId := AddHandler(hWnd, {|nEvent| BrowseEvent(nEvent, hWnd, oB,;
cPrompt,;
bSearch,;
cKey,;
bKeyBlk,;
bEDTUDF,;
bDELUDF,;
bADDUDF,;
bSELUDF,;
bPRNUDF,;
nId,aButtons,hVSb,hHSb,cAlias)},bDestroy)
RETURN(NIL)
STATIC FUNCTION BrowseEvent(nEvent,hWnd,oB,;
cPrompt,;
bSearch,;
cKey,;
bKeyBlk,;
bEDTUDF,;
bDELUDF,;
bADDUDF,;
bSELUDF,;
bPRNUDF,;
nId,aButtons,hVSb,hHSb,cAlias)
LOCAL Foo, nCrec, nKey, nButton, nScrollCmd, hOldWnd
LOCAL nMaxRecs, nSkipCnt, nCur, nOrder, cOldAlias
cOldAlias := ALIAS()
DBSELECTAREA(cAlias)
nMaxRecs := RECCOUNT()
nOrder := INDEXORD()
nOldWnd := SelectWindow(hWnd)
nCur := oB:rightVisible
SET ORDER TO oB:cargo[2]
DO CASE
CASE nEvent == EVENT_KILLFOCUS
SET ORDER TO nOrder
oB:cargo[3] := RECNO()
SELECT (cOldAlias)
CASE nEvent == EVENT_REDRAW
IF oB:cargo[1] != .T.
WinBox(hWnd, 0, 0,600,360,1,2,0)
WinBox(hWnd,12, 8,588,236,1,2,2)
WinBox(hWnd,12,239,588,272,2,2,2)
Message(hWnd,"")
IF VALTYPE(bKeyBlk) != 'B'
WinBox(hWnd, 08,283,438,303,1,2,1,0,4)
WinBox(hWnd,438,283,518,303,1,2,1,0,6)
WinBox(hWnd,516,283,594,303,1,2,1,0,6)
ENDIF
GOTO oB:cargo[3]
oB:refreshAll()
ELSE
oB:cargo[1] := .F.
ENDIF
IF oB:rightVisible == oB:colCount .AND.;
oB:leftVisible == 1
EnableWindow(hHSb,.F.)
ENDIF
CASE nEvent == EVENT_KEY
oB:colorRect({ob:rowPos,1,ob:rowPos,ob:colCount},{1,2})
nKey := 0
DO WHILE nKey == 0
nKey := inkey()
IF nKey != 0
EXIT
ENDIF
ENDDO
DO CASE
CASE ( nKey == 43 ) // + key
IF !EMPTY(bADDUDF)
ButtonsOff(aButtons)
Foo := EVAL(bADDUDF)
SelectWindow(hWnd)
ButtonsOn(aButtons)
oB:goTop()
ENDIF
CASE ( nKey == K_RETURN )
IF !EMPTY(bSELUDF)
ButtonsOff(aButtons)
Foo := EVAL(bSELUDF)
SelectWindow(hWnd)
ButtonsOn(aButtons)
ENDIF
CASE ( nKey == K_INS )
IF !EMPTY(bEDTUDF)
ButtonsOff(aButtons)
Foo := EVAL(bEDTUDF)
SelectWindow(hWnd)
ButtonsOn(aButtons)
IF VALTYPE(bKeyBlk) = 'B'
FindFirst(cKey)
ENDIF
ENDIF
CASE ( nKey == K_DEL )
IF !EMPTY(bDELUDF)
Beep()
IF NRecLock()
IF ErrorMsg("Delete This Record?"+CHR(13)+&(INDEXKEY()),"W") == IDOK
DELETE
Foo := EVAL(bDELUDF)
UNLOCK
oB:goTop()
IF EOF()
EmptyErr()
DelHandler(nId)
DestroyWindow(hWnd)
RETURN(NIL)
ENDIF
ENDIF
ENDIF
SelectWindow(hWnd)
ENDIF
CASE ( nKey == K_RIGHT)
IF oB:colCount > oB:rightVisible
oB:panRight()
ELSE
Beep()
ENDIF
CASE ( nKey == K_LEFT)
IF oB:leftVisible > 1
oB:panLeft()
ELSE
Beep()
ENDIF
CASE ( nKey == K_CTRL_RIGHT)
oB:panEnd()
CASE ( nKey == K_CTRL_LEFT)
oB:panHome()
CASE ( nKey == K_CTRL_P )
IF VALTYPE(bPRNUDF) == 'B'
ButtonsOff(aButtons)
Foo := EVAL(bPRNUDF)
SelectWindow(hWnd)
BringWindowToTop(hWnd)
ButtonsOn(aButtons)
ENDIF
CASE ( nKey == K_F1 )
// help goes here when it is finished!
CASE ( nKey == K_DOWN )
oB:down()
CASE ( nKey == K_UP )
oB:up()
CASE ( nKey == K_PGDN )
oB:pageDown()
CASE ( nKey == K_PGUP )
oB:pageUp()
CASE ( nKey == K_HOME )
oB:goTop()
CASE ( nKey == K_END )
oB:goBottom()
CASE ( nKey == K_ESC )
DelHandler(nId)
DestroyWindow(hWnd)
SelectWindow(hOldWnd)
RETURN(NIL)
CASE ( nKey == K_F2 )
IF !EMPTY(bSearch)
QuickS(_GetInstance(),hWnd,bSearch)
SelectWindow(hWnd)
oB:refreshAll()
ENDIF
OTHERWISE
IF UPPER(CHR(nKey)) $ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
nCrec := RECNO()
SEEK UPPER(CHR(nKey))
IF !FOUND()
GOTO nCrec
ENDIF
oB:refreshAll()
ENDIF
ENDCASE
CASE nEvent == EVENT_CONTROL
nButton := _lastwParam()
SelectWindow(hWnd)
SetFocus(hWnd)
oB:colorRect({ob:rowPos,1,ob:rowPos,ob:colCount},{1,2})
DO CASE
CASE nButton == 1
oB:GoTop()
CASE nButton == 2
oB:GoBottom()
CASE nButton == 3
IF !EMPTY(bADDUDF)
ButtonsOff(aButtons)
Foo := EVAL(bADDUDF)
SelectWindow(hWnd)
ButtonsOn(aButtons)
oB:goTop()
ENDIF
CASE nButton == 4
IF !EMPTY(bDELUDF)
Beep()
IF NRecLock()
IF ErrorMsg("Delete This Record?"+CHR(13)+&(INDEXKEY()),"W") == IDOK
SelectWindow(hWnd)
DELETE
Foo := EVAL(bDELUDF)
UNLOCK
oB:goTop()
IF EOF()
EmptyErr()
DelHandler(nId)
DestroyWindow(hWnd)
SelectWindow(hOldWnd)
RETURN(NIL)
ENDIF
ENDIF
ENDIF
SelectWindow(hWnd)
ENDIF
CASE nButton == 5
IF !EMPTY(bEDTUDF)
ButtonsOff(aButtons)
Foo := EVAL(bEDTUDF)
SelectWindow(hWnd)
IF VALTYPE(bKeyBlk) = 'B'
FindFirst(cKey)
ENDIF
ButtonsOn(aButtons)
ENDIF
CASE nButton == 6
IF !EMPTY(bSearch)
QuickS(_GetInstance(),hWnd,bSearch)
SelectWindow(hWnd)
oB:refreshAll()
ENDIF
CASE nButton == 7
IF VALTYPE(bPRNUDF) == 'B'
ButtonsOff(aButtons)
Foo := EVAL(bPRNUDF)
SelectWindow(hWnd)
ButtonsOn(aButtons)
ENDIF
CASE nButton == 8
IF !EMPTY(bSELUDF)
ButtonsOff(aButtons)
Foo := EVAL(bSELUDF)
SelectWindow(hWnd)
ButtonsOn(aButtons)
ENDIF
CASE nButton == 9
DelHandler(nId)
DestroyWindow(hWnd)
SelectWindow(hOldWnd)
RETURN(NIL)
ENDCASE
CASE nEvent == EVENT_LCLICK
IF (MouseRow() > oB:nTop) .AND. (MouseRow() < oB:nBottom);
.AND. (MouseCol() >= oB:nLeft) .AND. (MouseCol() <= oB:nRight)
oB:deHilite()
oB:colorRect({oB:RowPos,1,oB:RowPos,oB:colCount},{1,2})
oB:rowPos := MouseRow() - 2
oB:colorRect({oB:RowPos,1,oB:RowPos,oB:colCount},{2,2})
oB:Hilite()
ENDIF
CASE nEvent == EVENT_VSCROLL
nScrollCmd := _lastwParam()
nCur := -1
DO CASE
CASE nScrollCmd == SB_LINEDOWN
oB:colorRect({ob:rowPos,1,ob:rowPos,ob:colCount},{1,2})
oB:down()
CASE nScrollCmd == SB_PAGEDOWN
oB:colorRect({ob:rowPos,1,ob:rowPos,ob:colCount},{1,2})
oB:PageDown()
CASE nScrollCmd == SB_LINEUP
oB:colorRect({ob:rowPos,1,ob:rowPos,ob:colCount},{1,2})
oB:Up()
CASE nScrollCmd == SB_PAGEUP
oB:colorRect({ob:rowPos,1,ob:rowPos,ob:colCount},{1,2})
oB:PageUp()
CASE nScrollCmd == SB_THUMBPOSITION .or. nScrollCmd == SB_THUMBTRACK
nCur := _lastlolParam() // from Windows
ENDCASE
IF nScrollCmd <> SB_THUMBTRACK
IF nCur != -1
oB:colorRect({ob:rowPos,1,ob:rowPos,ob:colCount},{1,2})
GO TOP
nSkipCnt := SkipWhat(nCur,nMaxRecs)
DO CASE
CASE nSkipCnt == -1
oB:goBottom()
CASE nSkipCnt == 0
oB:goTop()
OTHERWISE
SKIP nSkipCnt
ENDCASE
ENDIF
ENDIF
nCur := oB:rightVisible
CASE nEvent == EVENT_HSCROLL
nScrollCmd := _lastwParam()
nCur := oB:rightVisible
DO CASE
CASE nScrollCmd == SB_LINELEFT .OR.;
nScrollCmd == SB_PAGELEFT
IF oB:leftVisible > 1
oB:panLeft()
ELSE
Beep()
ENDIF
CASE nScrollCmd == SB_LINERIGHT .OR.;
nScrollCmd == SB_PAGERIGHT
IF nCur < oB:colCount
oB:panRight()
ELSE
Beep()
ENDIF
CASE nScrollCmd == SB_THUMBPOSITION
nCur := _lastlolParam()
nCur := INT((oB:colCount*nCur)/100)
IF nCur > oB:rightVisible
DO WHILE oB:rightVisible < nCur
oB:panRight()
ENDDO
nCur := oB:rightVisible
ELSE
IF oB:leftVisible > nCur
DO WHILE oB:leftVisible > nCur .AND.;
oB:leftVisible > 1
oB:panLeft()
ENDDO
ENDIF
nCur := oB:leftVisible
ENDIF
ENDCASE
ENDCASE
DO WHILE ( !oB:stabilize() )
ENDDO
IF oB:hitTop() .OR. oB:hitBottom()
Beep()
* MessageBeep()
* IF oB:hitTop
* MessageBox( , "You are at the top of the list!", ;
* "Message", MB_ICONHAND + MB_OK)
* ELSE
* MessageBox( , "You are at the bottom of the list!",;
* "Message", MB_ICONHAND + MB_OK)
* ENDIF
* oB:refreshAll()
* DO WHILE ( !oB:stabilize() )
* ENDDO
ENDIF
oB:colorRect({ob:rowPos,1,ob:rowPos,ob:colCount},{2,2})
UpdtVScrollbar(hVSb,nMaxRecs)
UpDtHScrollbar(hHSb,oB,nCur)
UpdateStatusBar(hWnd,cPrompt,IIF(VALTYPE(bKeyBlk) != 'B',nMaxRecs,0))
SelectWindow(hOldWnd)
RETURN(NIL)
STATIC FUNCTION UpdateStatusBar(hWnd,cPrompt,nMaxRecs)
LOCAL hDC := GetDC(hWnd)
LOCAL nOldBkClor := SetBkColor(hDC,RGB(192,192,192))
LOCAL nCur
DrawText(hDC,cPrompt,;
{22,285,400,300},DT_LEFT)
IF nMaxRecs > 0
IF INDEXORD() != 0
nCur := NtxPos(INDEXORD(),RECNO())
ELSE
nCur := RECNO()
ENDIF
DrawText(hDC,STRZERO(nCur,7), {451,285,524,301},DT_LEFT)
DrawText(hDC,STRZERO(nMaxRecs,7),{527,285,600,301},DT_LEFT)
ENDIF
SetBkColor(hDC,nOldBkClor)
ReleaseDC(hWnd,hDC)
RETURN(NIL)
FUNCTION UpdtVScrollbar(hWnd,nMax)
LOCAL nNewpos, nCur
IF INDEXORD() != 0
nCur := NtxPos(INDEXORD(),RECNO())
ELSE
nCur := RECNO()
ENDIF
DO CASE
CASE nCur == nMax
nNewPos := 100
CASE nCur == 1
nNewPos := 0
OTHERWISE
nNewPos := INT((nCur/nMax)*100)
ENDCASE
SetScrollPos(hWnd, SB_CTL, nNewpos, .T.)
RETURN(NIL)
STATIC FUNCTION UpdtHScrollbar(hWnd,oB,nCur)
LOCAL nNewPos
DO CASE
CASE oB:leftVisible == 1
nNewPos := 0
CASE oB:rightVisible == oB:colCount
nNewPos := 100
OTHERWISE
nNewPos := nCur
ENDCASE
SetScrollPos(hWnd, SB_CTL, nNewPos,.T.)
RETURN(NIL)
FUNCTION SkipWhat(nCur,nMax)
LOCAL nSkipCnt
DO CASE
CASE nCur == 100
RETURN(-1)
CASE nCur == 0
RETURN(0)
OTHERWISE
IF nCur > nMax
nSkipCnt := INT((nMax*nCur)*100)
ELSE
nSkipCnt := INT((nMax/100)*nCur)
ENDIF
ENDCASE
IF nSkipCnt >= nMax
RETURN(-1)
ENDIF
RETURN(nSkipCnt)
FUNCTION QuickS(hInst,hWnd,bSearch)
STATIC cSearchStr
LOCAL aDlg, nItem, nCrec := RECNO()
LOCAL cMsel, nOrder := INDEXORD()
IF nOrder < 1
aDlg := CreateDialog("Search Type?",;
DS_MODALFRAME+WS_POPUP+WS_CAPTION+WS_SYSMENU ,;
80, 28, 142, 72)
aDlg := AppendDialog(aDlg,'new', DLG_BUTTON,BS_AUTORADIOBUTTON+WS_CHILD+WS_VISIBLE+WS_TABSTOP, 24, 05, 97, 12,"Start New Search", )
aDlg := AppendDialog(aDlg,'old', DLG_BUTTON,BS_AUTORADIOBUTTON+WS_CHILD+WS_VISIBLE+WS_TABSTOP, 24, 17, 97, 12,"Continue Previous Search",)
aDlg := AppendDialog(aDlg,'stat',DLG_STATIC,WS_VISIBLE+WS_CHILD, 24, 29, 97, 8,"Current Search Value")
aDlg := AppendDialog(aDlg,'edit',DLG_EDIT, ES_UPPERCASE+WS_CHILD+WS_VISIBLE+WS_TABSTOP+WS_BORDER,24, 38, 95, 12, cSearchStr)
aDlg := AppendDialog(aDlg,"ok", DLG_BUTTON,WS_CHILD+WS_VISIBLE+WS_TABSTOP, 24, 55, 40, 12,"&Ok")
aDlg := AppendDialog(aDlg,"can", DLG_BUTTON,WS_CHILD+WS_VISIBLE+WS_TABSTOP, 80, 55, 40, 12,"&Cancel")
CheckDlgButton(aDlg,'new',1)
nItem := ModalDialog(aDlg,_GetInstance(),hWnd)
ELSE
cSearchStr := ""
aDlg := CreateDialog("Search For?",WS_POPUP + WS_CAPTION + WS_SYSMENU+WS_VISIBLE+128,;
100, 52, 113, 52 )
aDlg := AppendDialog(aDlg,"edit",DLG_EDIT,ES_UPPERCASE+;
WS_CHILD + WS_VISIBLE + WS_BORDER + WS_TABSTOP, 9, 19, 96, 12,cSearchStr)
aDlg := AppendDialog(aDlg,"text",DLG_STATIC, WS_CHILD + WS_VISIBLE + WS_TABSTOP,8, 6, 107, 12,"Enter item to find")
aDlg := AppendDialog(aDlg,"ok",DLG_BUTTON, WS_CHILD + WS_VISIBLE + WS_TABSTOP, 9, 35, 40, 12,"&Ok")
aDlg := AppendDialog(aDlg,"can",DLG_BUTTON, WS_CHILD + WS_VISIBLE + WS_TABSTOP, 65, 35, 40, 12,"&Cancel")
nItem := ModalDialog(aDlg,hInst,hWnd)
ENDIF
IF ( nItem != 0 .AND. GetDialogResult(aDlg,"can") != .T. )
cSearchStr := GetDialogResult(aDlg,"edit")
IF !EMPTY(cSearchStr)
cSearchStr := ALLTRIM(cSearchStr)
ENDIF
ELSE
RETURN(NIL)
ENDIF
IF nOrder != 0
SEEK cSearchStr
ELSE
IF GetDialogResult(aDlg,'new') == 1
EVAL(bSearch,cSearchStr)
ELSE
CONTINUE
ENDIF
ENDIF
IF !FOUND()
ErrorMsg("NO MATCHING RECORD FOUND!",'E')
GOTO nCrec
ENDIF
RETURN(NIL)
// LdBrowFlds() - Returns an array for use by WBrowse() that contains
// ALL fields in a database
FUNCTION LdBrowFlds
LOCAL nCtr
LOCAL aFldList := {}
LOCAL aStruct := DBSTRUCT()
FOR nCtr := 1 TO LEN(aStruct)
AADD(aFldList,{nCtr,aStruct[nCtr][1]})
NEXT
RETURN(aFldList)
// Turn off the WBrowse() buttons - don't want the user doing anything
// silly while we are doing something else from within this browse...
STATIC FUNCTION ButtonsOff(aButtons)
LOCAL nCtr
FOR nCtr := 1 TO 9
EnableWindow(aButtons[nCtr][1],.F.)
NEXT
RETURN(NIL)
// Turn the buttons back on when we return to the WBrowse()
STATIC FUNCTION ButtonsOn(aButtons)
LOCAL nCtr
FOR nCtr := 1 TO 9
EnableWindow(aButtons[nCtr][1],aButtons[nCtr][2])
NEXT
RETURN(NIL)
// Called by Message() to draw a sunken bar at the bottom of a window
FUNCTION MsgBar(hWnd)
LOCAL nLeft, nTop, nRight, nBottom, aCRect, hOldPen
LOCAL hDC, hColor, hBlackPen, hGreyPen, hWhitePen
hDc := GetDC(hWnd)
aCRect := GetClientRect(hWnd)
nLeft := 0
nTop := aCRect[4]-26
nRight := aCRect[3]
nBottom := nTop+26
hBlackPen := CreatePen(PS_SOLID,1,RGB(0,0,0))
hGreyPen := CreatePen(PS_SOLID,1,RGB(128,128,128))
hWhitePen := CreatePen(PS_SOLID,1,RGB(255,255,255))
hOldPen := SelectObject(hDC,hBlackPen)
Rectangle(hDC,nLeft,nTop,nRight,nBottom)
hColor := CreateSolidBrush(RGB(192,192,192))
FillRect(hDC,nLeft,nTop+1,nRight,nBottom,hColor)
SelectObject(hDC,hGreyPen)
MoveTo(hDC,nLeft+10,nBottom-4)
LineTo(hDC,nLeft+10,nTop+4)
LineTo(hDC,nRight-10,nTop+4)
SelectObject(hDC,hWhitePen)
LineTo(hDC,nRight-10,nBottom-4)
LineTo(hDC,nLeft+10,nBottom-4)
SelectObject(hDC,hOldPen)
ReleaseDC(hWnd,hDC)
DeleteObject(hColor)
DeleteObject(hBlackPen)
DeleteObject(hGreyPen)
DeleteObject(hWhitePen)
RETURN(NIL)
// Display a message in a sunken message bar at the bottom of a window
FUNCTION Message(hWnd,cText)
LOCAL nLeft, nTop, nRight, nBottom, aCRect, hDC
LOCAL nOldBkClor
aCRect := GetClientRect(hWnd)
nLeft := 0
nTop := aCRect[4]-26
nRight := aCRect[3]
nBottom := nTop+28
hDC := GetDC(hWnd)
nOldBkClor := SetBkColor(hDC,RGB(192,192,192))
MsgBar(hWnd)
DrawText(hDC,cText,;
{nLeft+10,nTop+5,nRight-11,nBottom-5},DT_CENTER)
SetBkColor(hDC,nOldBkClor)
ReleaseDC(hWnd,hDC)
RETURN(NIL)
// WinBox() - Draws sunken/raised boxes
// See WBrowse() for examples of usage
FUNCTION WinBox(hWnd,nX,nY,nCX,nCY,nStyle,nBorder,nPixHD,nTBbord,nLRBord)
LOCAL nLeft, nTop, nRight, nBottom, hOldPen, hTopPen, hBotPen
LOCAL hDC, hFillPen, hBlackPen, hGreyPen, hWhitePen, nCtr
hDc := GetDC(hWnd)
nLeft := nX
nTop := nY
nRight := nCX
nBottom := nCY
nStyle := IIF(nStyle == NIL, 1 , nStyle)
nBorder := IIF(nBorder == NIL, 1 , nBorder)
nPixHD := IIF(nPixHD == NIL, 1 , nPixHD)
hBlackPen := CreatePen(PS_SOLID,1,RGB(0,0,0))
hGreyPen := CreatePen(PS_SOLID,1,RGB(128,128,128))
hWhitePen := CreatePen(PS_SOLID,1,RGB(255,255,255))
hFillPen := CreateSolidBrush(RGB(192,192,192))
hOldPen := SelectObject(hDC,hBlackPen)
Rectangle(hDC,nLeft,nTop,nRight,nBottom)
IF nBorder == 1
FillRect(hDC,nLeft+1,nTop+1,nRight-1,nBottom-1,hFillPen)
nLeft += 1
nTop += 1
nRight -= 2
nBottom -= 2
ELSE
FillRect(hDC,nLeft,nTop,nRight,nBottom,hFillPen)
++nLeft
++nTop
--nRight
--nBottom
ENDIF
nLeft := IIF(nLRBord == NIL,nLeft,nLeft+nLRBord)
nRight := IIF(nLRBord == NIL,nRight,nRight-nLRBord)
nTop := IIF(nTBBord == NIL,nTop,nTop+nTBBord)
nBottom := IIF(nTBBord == NIL,nBottom,nBottom-nTBBord)
IF nStyle == 1
hTopPen := hGreyPen
hBotPen := hWhitePen
ELSE
hTopPen := hWhitePen
hBotPen := hGreyPen
ENDIF
FOR nCtr := 1 TO nPixHD
DrawWBox(hDC,hTopPen,hBotPen,nTop,nLeft,nBottom,nRight)
++nLeft
++nTop
--nRight
--nBottom
NEXT
SelectObject(hDC,hOldPen)
ReleaseDC(hWnd,hDC)
DeleteObject(hFillPen)
DeleteObject(hBlackPen)
DeleteObject(hGreyPen)
DeleteObject(hWhitePen)
RETURN(NIL)
STATIC FUNCTION DrawWBox(hDC,hTopPen,hBotPen,nTop,nLeft,nBottom,nRight)
SelectObject(hDC,hTopPen)
MoveTo(hDC,nLeft,nBottom)
LineTo(hDC,nLeft,nTop)
LineTo(hDC,nRight,nTop)
SelectObject(hDC,hBotPen)
LineTo(hDC,nRight,nBottom)
LineTo(hDC,nLeft,nBottom)
RETURN(NIL)
// SkipFor(), FindFirst(), FindLast() - Used when browsing a sub-set of
// a database
FUNCTION SkipFor(nSkip, xStart,i_co_bk)
LOCAL nMoved
nMoved := 0
IF ( LASTREC() == 0 )
RETURN (nMoved)
ENDIF
DO CASE
CASE ( nSkip == 0 )
SKIP 0
CASE ( nSkip > 0 )
// Because of non-unique index keys, we must actually move past end
// and then come back to make sure we're on the last record that
// is in the range.
DO WHILE ( nMoved <= nSkip .AND. EVAL(i_co_bk)=xStart ) .AND. !EOF()
SKIP 1
nMoved++
ENDDO
// Move back to last record that is in the range
SKIP -1
nMoved--
CASE ( nSkip < 0 )
// Because of non-unique index keys, we must actually move past end
// and then come back to make sure we're on the last record that
// is in the range.
DO WHILE ( nMoved > nSkip .AND. EVAL(i_co_bk) >= xStart )
SKIP -1
IF BOF()
EXIT
ENDIF
nMoved--
ENDDO
IF (EVAL(i_co_bk) < xStart)
SKIP
nMoved++
ENDIF
ENDCASE
RETURN(nMoved)
FUNCTION FindFirst( xValue )
LOCAL lSeek
lSeek := SET(_SET_SOFTSEEK,.T.)
SEEK xValue
IF !FOUND()
EmptyErr()
RETURN(.F.)
ENDIF
SET(_SET_SOFTSEEK, lSeek)
RETURN(.T.)
FUNCTION FindLast( xValue,i_co_bk )
LOCAL lSeek
lSeek := SET(_SET_SOFTSEEK,.T.)
SEEK xValue
IF !FOUND()
EmptyErr()
RETURN(.F.)
ENDIF
// Move through all matching index keys
DO WHILE EVAL(i_co_bk) <= xValue .AND. ! (EOF())
SKIP
ENDDO
// and come back to last record in range
SKIP -1
SET(_SET_SOFTSEEK, lSeek)
RETURN(NIL)
// Generic message display function. 'W' = Warning, 'E' = Error
// anything else is a prompt or just information for the user
FUNCTION ErrorMsg(cMarr,cType)
LOCAL nResponse
DO CASE
CASE cType = 'W'
MessageBeep(MB_ICONEXCLAMATION)
nResponse := MessageBox(GetFocus(),cMarr,"Caution!",;
MB_OKCANCEL+MB_ICONEXCLAMATION)
CASE cType = 'E'
MessageBeep(MB_ICONHAND)
nResponse := MessageBox(GetFocus(),cMarr,"Problem!",;
MB_OK+MB_ICONHAND)
OTHERWISE
MessageBeep(MB_OK)
nResponse := MessageBox(GetFocus(),cMarr,"Please!",;
MB_OKCANCEL+MB_ICONASTERISK)
ENDCASE
RETURN(nResponse)
// Called when you try to browse an empty database or the user
// deletes all records from within a browse
FUNCTION EmptyErr
ErrorMsg("FILE/LIST IS EMPTY",'E')
RETURN(NIL)