'$INCLUDE: 'dialog.bi'
' prints a button
'
SUB btnPrintItem (Info() AS ButtonItemType, Item AS INTEGER, High AS INTEGER)
COLOR 0, 7
LOCATE Info(Item).Row, Info(Item).Col
PRINT "< "; RTRIM$(Info(Item).Caption); " >";
IF High THEN
COLOR 15, 7
LOCATE Info(Item).Row, Info(Item).Col + 1 + Info(Item).HotKey
PRINT MID$(Info(Item).Caption, Info(Item).HotKey, 1);
END IF
LOCATE Info(Item).Row, Info(Item).Col + 2, 1, 6, 7
END SUB
SUB DirList (Array() AS STRING, parent AS STRING, ReturnValue AS INTEGER, FileName AS STRING)
' Function ReturnValues
' ---------------------
' 0 = All
' 1 = Directories only
' 2 = Files only
DIM ch1 AS STRING * 1
cm$ = ","
sp$ = " "
' remove the final slash (it would cause an error)
IF RIGHT$(parent, 1) = "/" OR RIGHT$(parent, 1) = "\" THEN MID$(parent, LEN(parent), 1) = " "
' use DOS to build the file list
' group directories, sort by name, wide format
SHELL "dir /o:gn /w " + parent + " > filelist.txt"
' format the file to read every record sequentially
OPEN "filelist.txt" FOR BINARY AS #1
FOR x = 1 TO LOF(1)
GET #1, x, ch1
IF ch1 = CHR$(9) OR ch1 = CHR$(10) THEN PUT #1, x, cm$
IF ch1 = CHR$(1) OR ch1 = CHR$(13) THEN PUT #1, x, sp$
NEXT x
CLOSE
' open the file to read the file names
OPEN "filelist.txt" FOR INPUT AS #1
' get a record count. subtract 7 records for the header and trailer
allcount = -7
DO UNTIL EOF(1)
INPUT #1, xr$
allcount = allcount + 1
LOOP
SEEK #1, 1
' exit the sub if an error occured
IF allcount > 0 THEN
' allocate temporary memory
DIM temparray(1 TO allcount) AS STRING
' skip the header
FOR x = 1 TO 5
INPUT #1, xr$
NEXT x
' read the files into the array, stop before trailer
FOR x = 1 TO allcount
INPUT #1, temparray(x)
NEXT x
' count the number of directories in the list
FOR x = 1 TO allcount
IF LEFT$(temparray(x), 1) = "[" AND INSTR(temparray(x), "]") THEN
dircount = dircount + 1
ELSE
EXIT FOR
END IF
NEXT x
' determine the data to return
SELECT CASE ReturnValue
CASE 0 ' All
start = 1
finish = allcount
CASE 1 ' Directories only
start = 1
finish = dircount
CASE 2 ' Files only
start = dircount + 1
finish = allcount
END SELECT
' copy the appropriate data
REDIM Array(1 TO finish - start + 1) AS STRING
FOR x = start TO finish
Array(x - start + 1) = temparray(x)
NEXT x
ReturnValue = finish - start + 1
END IF
' save the data in a file if specified
IF FileName > "" THEN
OPEN FileName FOR OUTPUT AS #2
FOR x = 1 TO UBOUND(Array, 1)
WRITE #2, Array(x)
NEXT x
END IF
CLOSE
KILL "filelist.txt"
END SUB
' prints an input box
'
SUB inpPrintItem (Info AS InputType)
DIM a AS STRING
IF Info.Border THEN CALL scrBox(Info.Corner.T, Info.Corner.L, Info.Corner.B, Info.Corner.R, Info.Shadow)
COLOR 0, 7
IF NOT Null(Info.Caption) THEN
LOCATE Info.Corner.T, Info.Corner.L + 1
PRINT " "; RTRIM$(Info.Caption); " ";
END IF
END SUB
' returns TRUE if either ALT key is pressed
'
FUNCTION kbALT%
IF PEEK(1047) AND 8 THEN kbALT = TRUE
END FUNCTION
' returns TRUE if either CTRL key is pressed
'
FUNCTION kbCTRL%
IF PEEK(1047) AND 4 THEN kbCTRL = TRUE
END FUNCTION
' flushes the keyboard buffer
'
SUB kbFlush
DEF SEG = 0
POKE 1052, PEEK(1050)
END SUB
' returns TRUE if the LEFT SHIFT key is pressed
'
FUNCTION kbLSHIFT%
IF PEEK(1047) AND 1 THEN kbLSHIFT = TRUE
END FUNCTION
' returns TRUE if the RIGHT SHIFT key is pressed
'
FUNCTION kbRSHIFT%
IF PEEK(1047) AND 2 THEN kbRSHIFT = TRUE
END FUNCTION
' returns TRUE if the key requested (by scan code) is being pressed
'
FUNCTION kbScan% (k AS INTEGER)
kbScan = FALSE
IF INP(96) = k THEN kbScan = TRUE
kbFlush
END FUNCTION
' returns the letter value of the given scan code
'
FUNCTION kbScanKey$ (code%)
IF code% = 0 THEN code% = INP(96)
kbScanKey$ = ""
SELECT CASE code%
CASE &H10 TO &H19
kbScanKey$ = MID$("qwertyuiop", code% - &HF, 1)
CASE &H1E TO &H26
kbScanKey$ = MID$("asdfghjkl", code% - &H1D, 1)
CASE &H2C TO &H32
kbScanKey$ = MID$("zxcvbnm", code% - &H2B, 1)
END SELECT
END FUNCTION
' returns TRUE if either SHIFT key is pressed
'
FUNCTION kbSHIFT%
Tx = PEEK(1047) AND 15
IF Tx AND 1 OR Tx AND 2 THEN kbSHIFT = TRUE
END FUNCTION
' scans the list for which hot key was pressed
'
FUNCTION lstHotKey (Array() AS ListBoxItemType, Info AS ListBoxGroupType, kb$)
DIM x AS INTEGER
FOR x = 1 TO Info.ItemCount
IF Array(x).HotKey > 0 THEN
IF LCASE$(MID$(Array(x).Caption, Array(x).HotKey, 1)) = kb$ THEN
Info.ItemCurrent = x
lstHotKey = TRUE
EXIT FOR
END IF
END IF
NEXT x
END FUNCTION
' loads the list from the specified file
'
SUB lstLoad (Array() AS ListBoxItemType, Info AS ListBoxGroupType)
DIM x AS INTEGER
DIM Pointer AS INTEGER
DIM Readin AS STRING
' find list size and reallocate memory
CALL lstMaxData(Info)
REDIM Array(1 TO Info.ItemCount + 1) AS ListBoxItemType
IF Info.FileName > "" THEN
' open the data file
DIM FileNum AS INTEGER
FileNum = FREEFILE
OPEN Info.FileName FOR INPUT AS FileNum
END IF
' load the items
FOR x = 1 TO Info.ItemCount
IF FileNum > 0 THEN
INPUT #FileNum, Readin
ELSE
READ Readin
END IF
' trim the list item
Readin = LTRIM$(RTRIM$(Readin))
' isolate the hot key
Pointer = INSTR(Readin, "&")
IF Pointer > 0 THEN
Array(x).HotKey = Pointer
Readin = LEFT$(Readin, Pointer - 1) + MID$(Readin, Pointer + 1)
END IF
' save the item
Array(x).Caption = Readin
' find max width for mulitiple columns
IF LEN(Readin) > Info.ColWidth THEN Info.ColWidth = LEN(Readin)
NEXT x
' adjust the column width
BoxWidth = Info.Corner.R - Info.Corner.L
IF NOT Info.ColMulti THEN
Info.ColWidth = BoxWidth
ELSE
Info.ColWidth = Info.ColWidth + 4
END IF
' cancel mutlicol or narrow single column if box width is not big enough
IF Info.ColWidth > BoxWidth THEN
Info.ColMulti = FALSE
Info.ColWidth = BoxWidth
END IF
' set the Row and Col for each item relative to the box
Info.MaxSet = Info.Corner.B - Info.Corner.T - 1
Col = 1
Row = 1
FOR x = 1 TO Info.ItemCount + 1
Array(x).Col = Col
Array(x).Row = Row
Row = Row + 1
IF Info.ColMulti THEN
IF Row > Info.MaxSet THEN
Col = Col + 1
Row = 1
END IF
END IF
NEXT x
' save/set default data
Info.ColTop = 1
Info.ColCount = Col
Info.ColShow = INT((Info.Corner.R - Info.Corner.L - 1) \ Info.ColWidth + .999)
Info.ColCurrent = 1
Info.ItemTop = 1
Info.ItemCurrent = 1
' error checking
IF Info.ColShow < 1 THEN Info.ColShow = 1
' set last indice to blank
Array(Info.ItemCount + 1).HotKey = -1
IF FileNum > 0 THEN CLOSE FileNum
END SUB
' finds the list size and reallocates memory
'
SUB lstMaxData (Info AS ListBoxGroupType)
DIM x AS INTEGER
DIM Readin AS STRING
DIM FileNum AS INTEGER
' open the data file
IF Info.FileName > "" THEN
FileNum = FREEFILE
OPEN Info.FileName FOR INPUT AS #FileNum
INPUT #FileNum, Readin
ELSE
READ Readin
END IF
' read all items in the file
DO UNTIL Readin = "EOF" OR EOF(FileNum)
' keep count of all items
Info.ItemCount = Info.ItemCount + 1
IF FileNum THEN
INPUT #FileNum, Readin
ELSE
READ Readin
END IF
LOOP
IF FileNum THEN CLOSE FileNum
END SUB
' prints a single list item
'
SUB lstPrintItem (Item AS ListBoxItemType, Info AS ListBoxGroupType, High AS INTEGER)
IF Info.ItemCount < 1 OR Info.ItemCurrent < 1 OR Info.ColWidth < 1 THEN EXIT SUB
' find the position relative to the screen
IF Info.ColMulti THEN
Col = Info.Corner.L
Col = Col + ((Info.ColCurrent - Info.ColTop) * Info.ColWidth) + 1
Row = Info.Corner.T + Item.Row
IF Item.HotKey = -1 THEN
FOR x = Row TO Info.Corner.B - 1
LOCATE x, Col
PRINT SPACE$(Info.ColWidth);
NEXT x
EXIT SUB
END IF
ELSE
Row = Info.Corner.T + Item.Row - Info.ItemTop + 1
Col = Info.Corner.L + Item.Col
END IF
LOCATE Row, Col
IF Info.ListType = cstOPT OR Item.ListType = cstOPT THEN
COLOR 0, 7
PRINT " ( ) "; RTRIM$(Item.Caption); SPC(Info.ColWidth - LEN(RTRIM$(Item.Caption)) - 7); " ";
IF High THEN
LOCATE Row, Col + 2
CALL scrPrint(7, 0, 7)
END IF
IF Item.HotKey > 0 THEN
COLOR 15
LOCATE Row, Col + 4 + Item.HotKey
PRINT MID$(Item.Caption, Item.HotKey, 1);
END IF
LOCATE Row, Col + 2, 1
ELSEIF Info.ListType = cstCHECK OR Item.ListType = cstCHECK THEN
COLOR 0, 7
PRINT " [ ] "; RTRIM$(Item.Caption); SPC(Info.ColWidth - LEN(RTRIM$(Item.Caption)) - 7); " ";
LOCATE Row, Col + 2
IF Item.ItemCurrent THEN PRINT "X";
IF Item.HotKey > 0 THEN
COLOR 15
LOCATE Row, Col + 4 + Item.HotKey
PRINT MID$(Item.Caption, Item.HotKey, 1);
END IF
LOCATE Row, Col + 2, 1
ELSE
IF High THEN COLOR 7, 0 ELSE COLOR 0, 7
PRINT " "; RTRIM$(Item.Caption); SPC(Info.ColWidth - LEN(RTRIM$(Item.Caption)) - 3); " ";
IF Item.HotKey > 0 THEN
COLOR 15
LOCATE Row, Col + Item.HotKey
PRINT MID$(Item.Caption, Item.HotKey, 1);
END IF
LOCATE Row, Col + 1, 1
END IF
END SUB
' prints the list
'
SUB lstShow (Array() AS ListBoxItemType, Info AS ListBoxGroupType, ItemsOnly)
STATIC FirstCall AS INTEGER
DIM x AS INTEGER
DIM OldSelect AS INTEGER
IF Info.ItemTop < 1 AND Info.ItemCount > 1 THEN Info.ItemTop = 1
IF NOT Info.NoBorder AND NOT FirstCall THEN
CALL scrBox(Info.Corner.T, Info.Corner.L, Info.Corner.B, Info.Corner.R, TRUE)
IF NOT Null(Info.Title) THEN
LOCATE Info.Corner.T, Info.Corner.L + 1
COLOR 0, 7
PRINT " "; RTRIM$(Info.Title); " ";
END IF
IF Info.VScrollBar THEN
' print arrows
LOCATE Info.Corner.T + 1, Info.Corner.R
CALL scrPrint(24, 0, 7)
LOCATE Info.Corner.B - 1, Info.Corner.R
CALL scrPrint(25, 0, 7)
' print scroll bar
FOR x = Info.Corner.T + 2 TO Info.Corner.B - 2
LOCATE x, Info.Corner.R
PRINT CHR$(176);
NEXT x
END IF
' remember this routine was already called
FirstCall = TRUE
END IF
' print as many items as possible
IF Info.ItemCount > 0 THEN
IF Info.ColMulti THEN
OldTop = Info.ItemTop
OldCol = Info.ColCurrent
FOR y = Info.ColTop TO Info.ColTop + Info.ColShow - 1
Info.ColCurrent = y
Info.ItemTop = (Info.ColCurrent - 1) * Info.MaxSet + 1
FOR x = Info.ItemTop TO Info.ItemTop + Info.MaxSet - 1
IF x > Info.ItemCount THEN
CALL lstPrintItem(Array(Info.ItemCount + 1), Info, FALSE)
ELSE
CALL lstPrintItem(Array(x), Info, FALSE)
END IF
NEXT x
NEXT y
Info.ItemTop = OldTop
Info.ColCurrent = OldCol
ELSE
FOR x = Info.ItemTop TO Info.ItemTop + Info.MaxSet - 1
CALL lstPrintItem(Array(x), Info, FALSE)
NEXT x
END IF
END IF
END SUB
' main routine for the 'BUTTON' element
'
SUB Main.Button (Array() AS ButtonItemType, Info AS ButtonGroupType)
DIM High AS INTEGER
DIM x AS INTEGER
x = Info.Current
LOCATE Array(x).Row, Array(x).Col + 2, 1, 6, 7
DO
kb$ = INKEY$
IF kbALT THEN
CALL btnPrintItem(Array(), x, TRUE)
WHILE kbALT
kb$ = INKEY$
IF LCASE$(RIGHT$(kb$, 1)) = LCASE$(MID$(Array(x).Caption, Array(x).HotKey, 1)) THEN
Info.Selected = x
EXIT DO
END IF
WEND
END IF
IF kb$ = CHR$(cstENTER) THEN
Info.Selected = x
EXIT DO
ELSEIF LCASE$(RIGHT$(kb$, 1)) = LCASE$(MID$(Array(x).Caption, Array(x).HotKey, 1)) THEN
Info.Selected = x
EXIT DO
END IF
LOOP UNTIL kb$ = CHR$(cstTAB) OR kb$ = CHR$(cstESC)
END SUB
' main routine for the 'INPUTBOX' element
'
FUNCTION Main.InputBox$ (Info AS InputType, Text AS STRING)
DIM kb AS STRING
DIM Cursor AS INTEGER
DIM Begin AS INTEGER
DIM MaxWidth AS INTEGER
DIM OverWrite AS INTEGER
' consider any optional text inside the box
tLen = 1
tLen = tLen + LEN(RTRIM$(Info.Text))
IF tLen > 1 THEN
COLOR 0, 7
LOCATE Info.Corner.T + 1, Info.Corner.L + 1, 1
PRINT RTRIM$(Info.Text);
tLen = tLen + 1
END IF
' find the max width of the input field
MaxWidth = Info.Corner.R - Info.Corner.L - tLen
cTop = 6
Cursor = 1
Begin = 1
' place default text in the input field
IF Text > "" THEN
Cursor = LEN(Text$) + 1
IF Cursor > MaxWidth THEN Begin = Cursor - MaxWidth + 1
COLOR 7, 0
LOCATE Info.Corner.T + 1, Info.Corner.L + tLen, 1, cTop, 7
PRINT MID$(Text$, Begin, MaxWidth);
spa = MaxWidth - (LEN(Text$) - Begin) - 1
Reject = TRUE
END IF
COLOR 0, 7
DO
LOCATE Info.Corner.T + 1, Info.Corner.L + (Cursor - Begin) + tLen, 1, cTop, 7
DO
kb$ = INKEY$
LOOP WHILE kb$ = ""
IF LEFT$(kb$, 1) = CHR$(0) THEN
SELECT CASE RIGHT$(kb$, 1)
CASE CHR$(cstLEFT)
IF Cursor > 1 THEN Cursor = Cursor - 1
IF Cursor < Begin THEN Begin = Begin - 1
Reject = FALSE
CASE CHR$(cstRIGHT)
IF Cursor < Info.Maxlen THEN Cursor = Cursor + 1
IF Cursor > LEN(Text$) THEN Cursor = LEN(Text$) + 1
IF Cursor - Begin >= MaxWidth THEN Begin = Begin + 1
Reject = FALSE
CASE CHR$(cstHOME)
Cursor = 1
Begin = 1
Reject = FALSE
CASE CHR$(cstEND)
Cursor = LEN(Text$) + 1
IF Cursor - Begin > MaxWidth THEN Begin = Cursor - MaxWidth + 1
Reject = FALSE
CASE CHR$(cstDELETE)
IF Reject THEN
Text$ = ""
Begin = 1
Cursor = 1
ELSE
Text$ = LEFT$(Text$, Cursor - 1) + MID$(Text$, Cursor + 1)
END IF
Reject = FALSE
CASE CHR$(cstINSERT)
OverWrite = NOT OverWrite
cTop = cTop XOR 7
END SELECT
ELSE
SELECT CASE kb$
CASE CHR$(cstENTER), CHR$(cstTAB), CHR$(cstESC)
EXIT DO
CASE CHR$(cstBKSP)
IF Reject THEN
Text$ = ""
Begin = 1
Cursor = 1
ELSE
IF Cursor = 2 THEN
Text$ = MID$(Text$, Cursor)
ELSEIF Cursor > 2 THEN
Text$ = LEFT$(Text$, Cursor - 2) + MID$(Text$, Cursor)
END IF
Cursor = Cursor - 1
IF Cursor = 0 THEN Cursor = 1
IF Cursor < Begin THEN Begin = Cursor
END IF
Reject = FALSE
CASE ELSE
IF Reject THEN
Text$ = ""
Begin = 1
Cursor = 1
END IF
IF Cursor <= Info.Maxlen THEN
IF NOT OverWrite THEN
Text$ = LEFT$(Text$, Cursor - 1) + kb$ + MID$(Text$, Cursor)
ELSE
IF Cursor > LEN(Text$) AND LEN(Text$) < Info.Maxlen THEN Text$ = Text$ + " "
MID$(Text$, Cursor, 1) = kb$
END IF
IF Cursor <= Info.Maxlen THEN Cursor = Cursor + 1
IF Cursor - Begin + 1 > MaxWidth THEN Begin = Begin + 1
END IF
IF LEN(Text$) > Info.Maxlen THEN Text$ = LEFT$(Text$, Info.Maxlen)
Reject = FALSE
END SELECT
END IF
LOCATE Info.Corner.T + 1, Info.Corner.L + tLen
PRINT MID$(Text$, Begin, MaxWidth);
spa% = MaxWidth - (LEN(Text$) - Begin) - 1
PRINT SPC(spa%);
LOOP UNTIL kb$ = CHR$(cstESC)
Main.InputBox$ = Text$
END FUNCTION
FUNCTION Main.List% (Array() AS ListBoxItemType, Info AS ListBoxGroupType)
DIM kb AS STRING
IF Info.ItemCount < 1 THEN EXIT FUNCTION
kb = ""
Main.List = FALSE
DO
' remember the current item so it may not have to be redrawn
Last = Info.ItemCurrent
CALL lstPrintItem(Array(Info.ItemCurrent), Info, TRUE)
DO
kb$ = INKEY$
LOOP WHILE kb$ = ""
IF LEFT$(kb$, 1) = CHR$(0) THEN
CALL lstPrintItem(Array(Info.ItemCurrent), Info, FALSE)
SELECT CASE RIGHT$(kb$, 1)
CASE CHR$(cstHOME)
Info.ItemTop = 1
Info.ItemCurrent = 1
Info.ColTop = 1
Info.ColCurrent = 1
IF Info.ItemCurrent <> Last THEN CALL lstShow(Array(), Info, TRUE)
CASE CHR$(cstEND)
Info.ItemCurrent = Info.ItemCount
Info.ColCurrent = Info.ColCount
IF Info.ColMulti THEN
Info.ColTop = Info.ColCount - Info.ColShow + 1
Info.ItemTop = (Info.ColCount - Info.ColShow) * Info.MaxSet
CALL lstShow(Array(), Info, TRUE)
ELSE
Info.ItemTop = Info.ItemCount - Info.MaxSet + 1
END IF
IF Info.ItemCurrent <> Last THEN CALL lstShow(Array(), Info, TRUE)
CASE CHR$(cstUP)
IF Info.ItemCurrent > 1 THEN Info.ItemCurrent = Info.ItemCurrent - 1
IF Info.ColMulti THEN
IF Info.ItemCurrent = (Info.ColCurrent - 1) * Info.MaxSet THEN
IF Info.ColCurrent > 1 THEN
Info.ColCurrent = Info.ColCurrent - 1
Info.ItemCurrent = Info.ColCurrent * Info.MaxSet
IF Info.ColCurrent < Info.ColTop THEN
Info.ColTop = Info.ColTop - 1
CALL lstShow(Array(), Info, TRUE)
END IF
END IF
END IF
ELSE
IF Info.ItemCurrent < Info.ItemTop AND Info.ItemTop > 1 THEN
Info.ItemTop = Info.ItemTop - 1
CALL lstShow(Array(), Info, TRUE)
END IF
END IF
CASE CHR$(cstDOWN)
IF Info.ItemCurrent < Info.ItemCount THEN Info.ItemCurrent = Info.ItemCurrent + 1
IF Info.ColMulti THEN
IF Info.ItemCurrent > Info.ColCurrent * Info.MaxSet THEN
' find the next item
IF Info.ItemCurrent > Info.ItemCount THEN Info.ItemCurrent = Info.ItemCount
Info.ItemTop = Info.ItemTop + Info.MaxSet
IF Info.ItemTop > Info.ItemCount THEN Info.ItemTop = Info.ItemCount - (Info.ItemCount \ Info.ColCount - 1)
' find the proper row
IF Info.ColCurrent < Info.ColCount THEN
Info.ColCurrent = Info.ColCurrent + 1
IF Info.ColCurrent > Info.ColTop + Info.ColShow - 1 THEN
Info.ColTop = Info.ColTop + 1
CALL lstShow(Array(), Info, TRUE)
END IF
END IF
END IF
ELSE
IF Info.ItemCurrent > Info.ItemTop + Info.MaxSet - 1 THEN
Info.ItemTop = Info.ItemTop + 1
CALL lstShow(Array(), Info, TRUE)
END IF
END IF
CASE CHR$(cstLEFT)
IF Info.ColMulti THEN
Info.ItemCurrent = Info.ItemCurrent - Info.MaxSet
IF Info.ItemCurrent < 1 THEN Info.ItemCurrent = 1
IF Info.ItemCurrent < Info.ItemTop THEN
Info.ItemTop = Info.ItemTop - Info.MaxSet
IF Info.ItemTop < 1 THEN Info.ItemTop = 1
END IF
IF Info.ColCurrent > 1 THEN
Info.ColCurrent = Info.ColCurrent - 1
IF Info.ColCurrent < Info.ColTop THEN
Info.ColTop = Info.ColTop - 1
IF Info.ColTop < 1 THEN Info.ColTop = 1
CALL lstShow(Array(), Info, TRUE)
END IF
END IF
ELSE
IF Info.ItemCurrent > 1 THEN Info.ItemCurrent = Info.ItemCurrent - 1
IF Info.ItemCurrent < Info.ItemTop AND Info.ItemTop > 1 THEN
Info.ItemTop = Info.ItemTop - 1
CALL lstShow(Array(), Info, TRUE)
END IF
END IF
CASE CHR$(cstRIGHT)
IF Info.ColMulti THEN
' find the next item
Info.ItemCurrent = Info.ItemCurrent + Info.MaxSet
IF Info.ItemCurrent > Info.ItemCount THEN Info.ItemCurrent = Info.ItemCount
' find the proper column
IF Info.ColCurrent < Info.ColCount THEN
Info.ColCurrent = Info.ColCurrent + 1
IF Info.ColCurrent = Info.ColTop + Info.ColShow THEN Info.ColTop = Info.ColTop + 1
CALL lstShow(Array(), Info, TRUE)
END IF
ELSE
IF Info.ItemCurrent < Info.ItemCount THEN Info.ItemCurrent = Info.ItemCurrent + 1
IF Info.ItemCurrent > Info.ItemTop + Info.MaxSet - 1 THEN
Info.ItemTop = Info.ItemTop + 1
CALL lstShow(Array(), Info, TRUE)
END IF
END IF
CASE CHR$(cstPGUP)
IF Info.ColMulti THEN
Info.ItemCurrent = Info.ItemCurrent - Info.MaxSet * Info.ColShow
IF Info.ItemCurrent < 1 THEN Info.ItemCurrent = 1
IF Info.ItemCurrent < Info.ItemTop THEN
Info.ItemTop = Info.ItemTop - Info.MaxSet * Info.ColShow
IF Info.ItemTop < 1 THEN Info.ItemTop = 1
END IF
IF Info.ColCurrent > 1 THEN
Info.ColCurrent = Info.ColCurrent - Info.ColShow
IF Info.ColCurrent < 1 THEN Info.ColCurrent = 1
Info.ColTop = Info.ColTop - Info.ColShow
IF Info.ColTop < 1 THEN Info.ColTop = 1
CALL lstShow(Array(), Info, TRUE)
END IF
ELSE
Info.ItemCurrent = Info.ItemCurrent - Info.MaxSet
IF Info.ItemCurrent < 1 THEN Info.ItemCurrent = 1
Info.ItemTop = Info.ItemTop - Info.MaxSet
IF Info.ItemTop < 1 THEN Info.ItemTop = 1
CALL lstShow(Array(), Info, TRUE)
END IF
CASE CHR$(cstPGDN)
IF Info.ColMulti THEN
' find the next item
Info.ItemCurrent = Info.ItemCurrent + Info.MaxSet * Info.ColShow
IF Info.ItemCurrent > Info.ItemCount THEN Info.ItemCurrent = Info.ItemCount
' find the proper column
IF Info.ColCurrent < Info.ColCount THEN
Info.ColCurrent = Info.ColCurrent + Info.ColShow
IF Info.ColCurrent > Info.ColCount THEN Info.ColCurrent = Info.ColCount
Info.ColTop = Info.ColCurrent - Info.ColShow + 1
CALL lstShow(Array(), Info, TRUE)
END IF
ELSE
IF Info.ItemCurrent < Info.ItemCount THEN Info.ItemCurrent = Info.ItemCurrent + Info.MaxSet
IF Info.ItemCurrent > Info.ItemTop + Info.MaxSet - 1 THEN
Info.ItemTop = Info.ItemTop + Info.MaxSet
CALL lstShow(Array(), Info, TRUE)
END IF
END IF
END SELECT
ELSE
IF kb$ = CHR$(cstENTER) OR kb$ = CHR$(cstTAB) THEN
Main.List = Info.ItemCurrent
EXIT DO
ELSEIF kb$ = CHR$(cstSPACE) THEN
IF Info.ListType = cstCHECK OR Array(Info.ItemCurrent).ListType = cstCHECK THEN
Array(Info.ItemCurrent).ItemCurrent = NOT Array(Info.ItemCurrent).ItemCurrent
ELSE
Main.List = Info.ItemCurrent
EXIT DO
END IF
ELSEIF lstHotKey(Array(), Info, kb$) THEN
Main.List = Info.ItemCurrent
EXIT DO
END IF
END IF
LOOP UNTIL kb$ = CHR$(cstESC)
END FUNCTION
' main routine for the 'MENUBAR' element
'
FUNCTION Main.Menu% (Info AS MenuGroupType, MenuIdx() AS MenuIdxType, MenuItem() AS MenuItemType)
DIM KeyHit AS STRING
DIM Idx AS INTEGER
DIM State AS INTEGER
DIM Selected AS INTEGER
DIM x AS INTEGER
DIM ptr AS INTEGER
' save screen and set initial values
PCOPY 0, 1
Idx = 1
ptr = 1
State = LOW
Selected = FALSE
' save cursor position and turn cursor off
CALL scrCursorOn(FALSE)
DO
DO
KeyHit$ = INKEY$
IF kbALT THEN EXIT DO
LOOP WHILE KeyHit$ = ""
' check for shortcut keys
IF LEN(KeyHit$) = 1 THEN KeyHit$ = mnuHotKey(Idx, ptr, State, KeyHit$, MenuIdx(), MenuItem(), Info)
' check for ALT key pressed
IF kbALT THEN
' user pressed ALT to enter menu
IF State = LOW THEN
' turn on index short keys
FOR x = 1 TO Info.Idx
CALL mnuPrintItem(x, ROOT, LOMED, MenuIdx(), MenuItem())
NEXT x
END IF
' wait for user to release ALT key
DO WHILE kbALT
' check for ALTed shortcut keys
KeyHit$ = INKEY$
IF LEN(KeyHit$) = 1 THEN
State = LOMED
KeyHit$ = mnuHotKey(Idx, ptr, State, KeyHit$, MenuIdx(), MenuItem(), Info)
END IF
LOOP
' user pressed ALT to exit menu
IF State = HIMED THEN
KeyHit$ = CHR$(cstESC)
ELSEIF State = HI THEN
' turn on index short keys
PCOPY 1, 0
FOR x = 1 TO Info.Idx
CALL mnuPrintItem(x, ROOT, LOMED, MenuIdx(), MenuItem())
NEXT x
END IF
IF State <> HIMED THEN
' turn on initial index
State = HIMED
CALL mnuPrintItem(Idx, ROOT, HIMED, MenuIdx(), MenuItem())
END IF
END IF
' check for regular keys
IF LEFT$(KeyHit$, 1) = CHR$(0) THEN
SELECT CASE RIGHT$(KeyHit$, 1)
CASE CHR$(cstUP)
CALL mnuPrintItem(Idx, ptr, LOMED, MenuIdx(), MenuItem())
IF State = HIMED THEN
KeyHit$ = CHR$(cstENTER)
ELSE
ptr = ptr - 1
IF ptr < MenuIdx(Idx).IdxStart THEN ptr = MenuIdx(Idx).IdxStart + MenuIdx(Idx).MaxItem - 1
IF MenuItem(ptr).ShortKey = 0 THEN ptr = ptr - 1
END IF
CALL mnuPrintItem(Idx, ptr, HIMED, MenuIdx(), MenuItem())
CASE CHR$(cstDOWN)
CALL mnuPrintItem(Idx, ptr, LOMED, MenuIdx(), MenuItem())
IF State = HIMED THEN
KeyHit$ = CHR$(cstENTER)
ELSE
ptr = ptr + 1
IF ptr > MenuIdx(Idx).IdxStart + MenuIdx(Idx).MaxItem - 1 THEN ptr = MenuIdx(Idx).IdxStart
IF MenuItem(ptr).ShortKey = 0 THEN ptr = ptr + 1
END IF
CALL mnuPrintItem(Idx, ptr, HIMED, MenuIdx(), MenuItem())
CASE CHR$(cstLEFT)
IF State = HIMED THEN
CALL mnuPrintItem(Idx, ROOT, LOMED, MenuIdx(), MenuItem())
Idx = Idx - 1
IF Idx = 0 THEN Idx = Info.Idx
CALL mnuPrintItem(Idx, ROOT, HIMED, MenuIdx(), MenuItem())
ELSEIF State = HI THEN
Idx = Idx - 1
IF Idx = 0 THEN Idx = Info.Idx
CALL mnuPrintMenu(Idx, MenuIdx(), MenuItem())
END IF
ptr = MenuIdx(Idx).IdxStart
CASE CHR$(cstRIGHT)
IF State = HIMED THEN
CALL mnuPrintItem(Idx, ROOT, LOMED, MenuIdx(), MenuItem())
Idx = Idx + 1
IF Idx > Info.Idx THEN Idx = 1
CALL mnuPrintItem(Idx, ROOT, HIMED, MenuIdx(), MenuItem())
ELSE
Idx = Idx + 1
IF Idx > Info.Idx THEN Idx = 1
CALL mnuPrintMenu(Idx, MenuIdx(), MenuItem())
END IF
ptr = MenuIdx(Idx).IdxStart
END SELECT
ELSEIF KeyHit$ = CHR$(cstESC) THEN
State = HI
KeyHit$ = CHR$(cstENTER)
Main.Menu = 0
Selected = TRUE
END IF
' ENTER
IF KeyHit$ = CHR$(cstENTER) THEN
' made a selection
IF State = HI THEN
IF NOT MenuItem(ptr).Disabled AND NOT MenuIdx(Idx).Disabled THEN
Main.Menu = ptr
Selected = TRUE
END IF
' turn on menu
ELSEIF State = HIMED THEN
State = HI
CALL mnuPrintMenu(Idx, MenuIdx(), MenuItem())
ptr = MenuIdx(Idx).IdxStart
END IF
' if user is holding ALT, wait for release
WHILE GetKey$ = CHR$(cstALT): WEND
END IF
LOOP UNTIL Selected%
' restore initial screen and cursor
PCOPY 1, 0
CALL scrCursorOn(TRUE)
END FUNCTION
' main routine for the 'TEXTBOX' element
'
SUB Main.TextBox (Info AS TextBoxType, TBoxPtr() AS INTEGER, TBoxArr() AS STRING, TBoxTxt AS STRING)
IF Info.Top < 1 THEN Info.Top = 1
CALL txtFill(Info, TBoxTxt$, TBoxPtr(), TBoxArr())
IF Info.Cursor < 1 THEN Info.Cursor = 1
IF Info.Col < 1 THEN Info.Col = 1
IF Info.Row < 1 THEN Info.Row = 1
TBoxHeight = Info.Corner.B - Info.Corner.T - 2
DO
' print status bar
Inf$ = " " + LTRIM$(STR$(Info.Row)) + " : " + LTRIM$(STR$(Info.Col)) + " "
LOCATE Info.Corner.B, Info.Corner.R - 13
PRINT STRING$(12 - LEN(Inf$), CHR$(196)); Inf$;
' determine the height of the Info.Cursor
IF Info.Insert THEN
LOCATE Info.Corner.T + Info.Row - Info.Top + 1, Info.Corner.L + Info.Col, 1, 6, 7
ELSE
LOCATE Info.Corner.T + Info.Row - Info.Top + 1, Info.Corner.L + Info.Col, 1, 1, 7
END IF
DO
kb$ = INKEY$
WHILE kbCTRL
IF kbScan(&H47) THEN ' CTRL+HOME
Info.Top = 1
Info.Row = 1
Info.Cursor = 1
Info.Col = 1
CALL txtPrintItem(Info, TBoxPtr(), TBoxArr())
ELSEIF kbScan(&H4F) THEN ' CTRL+END
Info.Top = Info.MaxLines - TBoxHeight
IF Info.Top < 1 THEN Info.Top = 1
Info.Row = Info.MaxLines
Info.Cursor = LEN(TBoxTxt)
Info.Col = txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt)
CALL txtPrintItem(Info, TBoxPtr(), TBoxArr())
END IF
IF Info.Insert THEN
LOCATE Info.Corner.T + Info.Row - Info.Top + 1, Info.Corner.L + Info.Col, 1, 6, 7
ELSE
LOCATE Info.Corner.T + Info.Row - Info.Top + 1, Info.Corner.L + Info.Col, 1, 1, 7
END IF
WEND
IF kbALT THEN EXIT SUB
LOOP WHILE kb$ = ""
OldInfo.Top = Info.Top
IF LEFT$(kb$, 1) = CHR$(0) THEN
SELECT CASE RIGHT$(kb$, 1)
CASE CHR$(cstLEFT)
IF Info.Cursor > 1 THEN
Info.Cursor = Info.Cursor - 1
Info.Col = Info.Col - 1
IF Info.Col < 1 THEN
IF Info.Row > Info.Top THEN
Info.Row = Info.Row - 1
Info.Col = txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt)
ELSEIF Info.Top > 1 THEN
Info.Top = Info.Top - 1
Info.Row = Info.Row - 1
Info.Col = txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt)
ELSE
Info.Col = 1
END IF
END IF
END IF
CASE CHR$(cstRIGHT)
IF Info.Cursor < LEN(TBoxTxt$) THEN
Info.Cursor = Info.Cursor + 1
Info.Col = Info.Col + 1
IF Info.Col > txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt) THEN
Info.Col = 1
Info.Row = Info.Row + 1
END IF
IF Info.Row - Info.Top + 1 > Info.Corner.B - Info.Corner.T - 1 THEN Info.Top = Info.Top + 1
END IF
CASE CHR$(cstUP)
IF Info.Row > Info.Top THEN
Info.Row = Info.Row - 1
IF Info.Col > txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt) THEN Info.Col = txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt)
Info.Cursor = TBoxPtr(Info.Row) + Info.Col - 1
ELSEIF Info.Top > 1 AND Info.MaxLines > 1 THEN
Info.Top = Info.Top - 1
Info.Row = Info.Row - 1
IF Info.Row < 1 THEN Info.Row = 1
Info.Cursor = TBoxPtr(Info.Row) + Info.Col - 1
END IF
CASE CHR$(cstDOWN)
IF Info.Row < Info.MaxLines THEN
Info.Row = Info.Row + 1
IF Info.Col > txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt) THEN Info.Col = txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt)
Info.Cursor = TBoxPtr(Info.Row) + Info.Col - 1
IF Info.Row - Info.Top + 1 > Info.Corner.B - Info.Corner.T - 1 THEN Info.Top = Info.Top + 1
END IF
CASE CHR$(cstHOME)
Info.Cursor = TBoxPtr(Info.Row)
Info.Col = 1
CASE CHR$(cstEND)
Info.Col = txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt)
Info.Cursor = TBoxPtr(Info.Row) + Info.Col - 1
CASE CHR$(cstINSERT)
Info.Insert = NOT Info.Insert
CASE CHR$(cstDELETE)
TBoxTxt$ = LEFT$(TBoxTxt$, Info.Cursor - 1) + MID$(TBoxTxt$, Info.Cursor + 1)
CALL txtFill(Info, TBoxTxt$, TBoxPtr(), TBoxArr())
CASE CHR$(cstPGUP)
Info.Top = Info.Top - TBoxHeight
Info.Row = Info.Row - TBoxHeight
IF Info.Top < 1 THEN Info.Top = 1
IF Info.Row < 1 THEN Info.Row = 1
IF Info.Col > txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt) THEN Info.Col = txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt)
Info.Cursor = TBoxPtr(Info.Row) + Info.Col - 1
CASE CHR$(cstPGDN)
Info.Top = Info.Top + TBoxHeight
Info.Row = Info.Row + TBoxHeight
IF Info.Row > Info.MaxLines THEN Info.Row = Info.MaxLines
IF Info.Top + TBoxHeight > Info.MaxLines THEN Info.Top = Info.MaxLines - TBoxHeight
IF Info.Col > txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt) THEN Info.Col = txtWidth(Info.Row, Info, TBoxPtr(), TBoxTxt)
Info.Cursor = TBoxPtr(Info.Row) + Info.Col - 1
END SELECT
ELSEIF kb$ = CHR$(cstBKSP) THEN
IF Info.Cursor > 1 THEN
TBoxTxt$ = LEFT$(TBoxTxt$, Info.Cursor - 2) + MID$(TBoxTxt$, Info.Cursor)
Info.Cursor = Info.Cursor - 1
CALL txtFill(Info, TBoxTxt$, TBoxPtr(), TBoxArr())
IF Info.Col < 1 THEN END
END IF
ELSEIF kb$ = CHR$(cstTAB) THEN
TBoxTxt$ = LEFT$(TBoxTxt$, Info.Cursor - 1) + SPACE$(3) + MID$(TBoxTxt$, Info.Cursor)
Info.Cursor = Info.Cursor + 3
CALL txtFill(Info, TBoxTxt$, TBoxPtr(), TBoxArr())
ELSEIF kb$ <> CHR$(cstESC) THEN
' place new character in the string
IF Info.Insert OR kb$ = CHR$(cstENTER) THEN
TBoxTxt$ = LEFT$(TBoxTxt$, Info.Cursor - 1) + kb$ + MID$(TBoxTxt$, Info.Cursor)
ELSE
MID$(TBoxTxt$, Info.Cursor, 1) = kb$
END IF
Info.Cursor = Info.Cursor + 1
CALL txtFill(Info, TBoxTxt$, TBoxPtr(), TBoxArr())
END IF
' scroll the text
IF Info.Top <> OldInfo.Top THEN CALL txtPrintItem(Info, TBoxPtr(), TBoxArr())
LOOP UNTIL kb$ = CHR$(cstESC)
END SUB
' scans the menu for a short cut key
'
FUNCTION mnuHotKey$ (Idx, ptr, State, KeyHit$, MenuIdx() AS MenuIdxType, MenuItem() AS MenuItemType, Info AS MenuGroupType)
DIM x AS INTEGER
' assign default value
mnuHotKey = KeyHit$
' scan for menu index keys
IF State = HIMED OR State = LOMED THEN
FOR x = 1 TO Info.Idx
IF LCASE$(KeyHit$) = LCASE$(MID$(MenuIdx(x).Label, MenuIdx(x).ShortKey, 1)) THEN
Idx = x
mnuHotKey = CHR$(13)
EXIT FOR
END IF
NEXT x
' scan for menu item keys
ELSEIF State = HI THEN
FOR x = MenuIdx(Idx).IdxStart TO MenuIdx(Idx).IdxStart + MenuIdx(Idx).MaxItem - 1
IF MenuItem(x).ShortKey > 0 THEN
IF LCASE$(KeyHit$) = LCASE$(MID$(MenuItem(x).Label, MenuItem(x).ShortKey, 1)) THEN
CALL mnuPrintItem(Idx, ptr, LOMED, MenuIdx(), MenuItem())
ptr = x
CALL mnuPrintItem(Idx, ptr, HIMED, MenuIdx(), MenuItem())
mnuHotKey = CHR$(13)
EXIT FOR
END IF
END IF
NEXT x
END IF
END FUNCTION
' loads the menu from DATA into array
'
SUB mnuLoad (Info AS MenuGroupType, MenuIdx() AS MenuIdxType, MenuItem() AS MenuItemType)
DIM Label AS STRING
DIM Alignment AS STRING * 1
DIM Idx AS INTEGER
DIM IdxColumnR AS INTEGER
DIM IdxColumnL AS INTEGER
DIM x AS INTEGER
DIM ptr AS INTEGER
' redimension arrays
REDIM MenuIdx(1 TO Info.Idx) AS MenuIdxType
REDIM MenuItem(1 TO Info.Item) AS MenuItemType
' initial setting for index alignment
IdxColumnL = 3
IdxColumnR = 80
' open the data file
IF Info.FileName > "" THEN
OPEN Info.FileName FOR INPUT AS #1
INPUT #1, Label
ELSE
READ Label
END IF
DO UNTIL Label = "/EOF"
IF LEFT$(Label, 1) = "/" OR LEFT$(Label, 1) = "\" THEN
Alignment = LEFT$(Label, 1)
Idx = Idx + 1
' find shortcut key
FOR x = 1 TO LEN(Label)
IF MID$(Label, x, 1) = "&" THEN
MenuIdx(Idx).ShortKey = x - 1
EXIT FOR
END IF
NEXT x
' assign label and increase counter
Label = LEFT$(Label, x - 1) + MID$(Label, x + 1)
Label = MID$(Label, 2)
MenuIdx(Idx).Label = Label
' assign menu IdxColumn
IF Alignment = "/" THEN
MenuIdx(Idx).IdxColumn = IdxColumnL
IdxColumnL = IdxColumnL + LEN(Label) + 2
ELSE
IdxColumnR = IdxColumnR - LEN(Label) - 2
MenuIdx(Idx).IdxColumn = IdxColumnR
END IF
' read item
ELSEIF LEFT$(Label, 3) = "..." THEN
' move index pointer
ptr = ptr + 1
IF MenuIdx(Idx).IdxStart = 0 THEN MenuIdx(Idx).IdxStart = ptr
' increment max items count
MenuIdx(Idx).MaxItem = MenuIdx(Idx).MaxItem + 1
' find shortcut key
x = INSTR(Label, "&")
IF x > 0 THEN MenuItem(ptr).ShortKey = x - 3 ELSE x = LEN(Label)
' clean up label
Label = LEFT$(Label, x - 1) + MID$(Label, x + 1)
Label = MID$(Label, 4)
MenuItem(ptr).Label = Label
' set max length
IF LEN(Label) > MenuIdx(Idx).MaxWidth THEN MenuIdx(Idx).MaxWidth = LEN(Label)
' set items box starting column
IF MenuIdx(Idx).IdxColumn + MenuIdx(Idx).MaxWidth > 76 THEN
MenuIdx(Idx).StartCol = 76 - MenuIdx(Idx).MaxWidth
ELSE
MenuIdx(Idx).StartCol = MenuIdx(Idx).IdxColumn
END IF
END IF
IF Info.FileName > "" THEN
INPUT #1, Label
ELSE
READ Label
END IF
LOOP
CLOSE #1
END SUB
' finds the max required array bounds of the menu
'
SUB mnuMaxData (Info AS MenuGroupType)
DIM Label AS STRING
DIM FileNum AS INTEGER
IF Info.FileName > "" THEN
FileNum = FREEFILE
OPEN Info.FileName FOR INPUT AS FileNum
INPUT #1, Label
ELSE
READ Label
END IF
DO UNTIL Label = "/EOF"
IF LEFT$(Label, 1) = "/" OR LEFT$(Label, 1) = "\" THEN
Info.Idx = Info.Idx + 1
ELSEIF LEFT$(Label, 3) = "..." THEN
Info.Item = Info.Item + 1
END IF
IF Info.FileName > "" THEN
INPUT #1, Label
ELSE
READ Label
END IF
LOOP
IF Info.FileName > "" THEN CLOSE FileNum
END SUB
' prints menu index and item labels
'
SUB mnuPrintItem (Idx, ptr, State, MenuIdx() AS MenuIdxType, MenuItem() AS MenuItemType)
DIM Fore AS INTEGER
DIM Back AS INTEGER
DIM Item AS INTEGER
Fore = 0
Back = 7
' account for menu being disabled
IF MenuIdx(Idx).Disabled THEN Fore = 8
IF ptr > ROOT THEN IF MenuItem(ptr).Disabled THEN Fore = 8
' select proper colors
IF State > LOMED THEN SWAP Fore, Back
COLOR Fore, Back
' print item
IF ptr = ROOT THEN
Item = 0
' print label
LOCATE Item + 1, MenuIdx(Idx).IdxColumn
PRINT " "; RTRIM$(MenuIdx(Idx).Label); " ";
' set cursor for short key
LOCATE Item + 1, MenuIdx(Idx).IdxColumn + MenuIdx(Idx).ShortKey
ELSE
Item = ptr - MenuIdx(Idx).IdxStart + 1
' print label
LOCATE Item + 2, MenuIdx(Idx).StartCol
IF MenuItem(ptr).ShortKey = BREAK THEN
LOCATE , POS(0) - 1
PRINT CHR$(195); STRING$(MenuIdx(Idx).MaxWidth + 2, CHR$(196)); CHR$(180);
ELSE
PRINT " "; LEFT$(MenuItem(ptr).Label, MenuIdx(Idx).MaxWidth); " ";
END IF
' print bullet
IF MenuItem(ptr).Bullet THEN
LOCATE Item + 2, MenuIdx(Idx).StartCol
CALL scrPrint(7, Fore, Back)
END IF
' set cursor for short key
LOCATE Item + 2, MenuIdx(Idx).StartCol + MenuItem(ptr).ShortKey
END IF
' select color for short key (short key only on in MED states)
SELECT CASE State
CASE LOMED: COLOR 15, 7
CASE HIMED: COLOR 15, 0
END SELECT
' print short key if not disabled
IF NOT MenuIdx(Idx).Disabled THEN
IF ptr = ROOT THEN
PRINT MID$(MenuIdx(Idx).Label, MenuIdx(Idx).ShortKey, 1);
ELSEIF MenuItem(ptr).ShortKey <> BREAK AND NOT MenuItem(ptr).Disabled THEN
PRINT MID$(MenuItem(ptr).Label, MenuItem(ptr).ShortKey, 1);
END IF
END IF
END SUB
' prints specified menu
'
SUB mnuPrintMenu (Idx, MenuIdx() AS MenuIdxType, MenuItem() AS MenuItemType)
DIM x AS INTEGER
' turn off old menu
PCOPY 1, 0
' print box
CALL scrBox(2, MenuIdx(Idx).StartCol - 1, MenuIdx(Idx).MaxItem + 3, MenuIdx(Idx).StartCol + MenuIdx(Idx).MaxWidth + 2, TRUE)
' fill box with items
FOR x = MenuIdx(Idx).IdxStart TO MenuIdx(Idx).IdxStart + MenuIdx(Idx).MaxItem - 1
CALL mnuPrintItem(Idx, x, LOMED, MenuIdx(), MenuItem())
NEXT x
' highlight index
CALL mnuPrintItem(Idx, ROOT, HI, MenuIdx(), MenuItem())
' highlight initial item
CALL mnuPrintItem(Idx, MenuIdx(Idx).IdxStart, HIMED, MenuIdx(), MenuItem())
' "��ó��ڿ"
END SUB
' prints menu index on top line
'
SUB mnuShow (Info AS MenuGroupType, MenuIdx() AS MenuIdxType, MenuItem() AS MenuItemType)
DIM x AS INTEGER
' print white line on top of screen
COLOR 0, 7
LOCATE 1, 1: PRINT SPACE$(80);
' print the menu index values
FOR x = 1 TO Info.Idx
CALL mnuPrintItem(x, ROOT, LOW, MenuIdx(), MenuItem())
NEXT x
END SUB
' determines if a fixed length string has any data
'
FUNCTION Null (Text AS STRING)
DIM x AS INTEGER
Null = TRUE
FOR x = 1 TO LEN(Text)
IF MID$(Text, x, 1) <> CHR$(0) AND MID$(Text, x, 1) <> CHR$(32) THEN
Null = FALSE
EXIT FOR
END IF
NEXT x
END FUNCTION
' opens a pop-up alert box and awaits input
'
FUNCTION scrAlert$ (Title AS STRING, Text AS STRING, MaxWidth AS INTEGER, Height AS INTEGER)
DIM aData AS TextBoxType
DIM aValues(0) AS INTEGER
DIM aStrings(0) AS STRING
aData.Corner.T = 10
aData.Corner.L = 25
aData.Corner.R = 55
aData.Corner.B = 14
aData.Top = 1
aData.Cursor = 1
aData.Shadow = TRUE
IF MaxWidth > 0 THEN
aData.Corner.L = 40 - MaxWidth \ 2
aData.Corner.R = 40 + MaxWidth \ 2
END IF
IF Height > 0 THEN
aData.Corner.T = 11 - (Height \ 2)
aData.Corner.B = aData.Corner.T + Height + 1
END IF
CALL scrBox(aData.Corner.T, aData.Corner.L, aData.Corner.B, aData.Corner.R, TRUE)
LOCATE aData.Corner.T, aData.Corner.L + (aData.Corner.R - aData.Corner.L) \ 2 - LEN(Title) \ 2 - 2
COLOR 0, 7
PRINT " "; RTRIM$(Title); " ";
CALL txtFill(aData, " " + Text, aValues(), aStrings())
Alert$ = INPUT$(1)
COLOR 7, 0
END FUNCTION
' draws a single line box at specified coordinates, with shadowing
'
SUB scrBox (Row1%, Col1%, Row2%, Col2%, Shadow%)
DIM x AS INTEGER
' print box
COLOR 0, 7
LOCATE Row1, Col1
PRINT CHR$(218); STRING$(Col2 - Col1 - 1, CHR$(196)); CHR$(191);
FOR x = Row1 TO Row2 - 1
COLOR 0, 7
LOCATE x + 1, Col1
PRINT CHR$(179); SPACE$(Col2 - Col1 - 1); CHR$(179);
' print shadowing
IF Shadow% THEN
COLOR 8, 0
LOCATE x + 1, Col2 + 1: PRINT CHR$(SCREEN(x + 1, Col2 + 1));
PRINT CHR$(SCREEN(x + 1, Col2 + 2));
END IF
NEXT x
COLOR 0, 7
LOCATE Row2, Col1
PRINT CHR$(192); STRING$(Col2 - Col1 - 1, CHR$(196)); CHR$(217);
' print shadowing
IF Shadow% THEN
COLOR 8, 0
FOR x = Col1 TO Col2
LOCATE Row2 + 1, x + 2
PRINT CHR$(SCREEN(Row2 + 1, x + 2));
NEXT x
COLOR 0, 7
END IF
END SUB
' toggles the cursor while saving it's position and height
'
SUB scrCursorOn (OnOff%) STATIC
DIM CursorLine AS INTEGER
DIM CursorColumn AS INTEGER
DIM Top AS INTEGER
DIM Bottom AS INTEGER
DIM Status AS INTEGER
IF OnOff THEN
' restore cursor settings
LOCATE CursorLine, CursorColumn, Status, Top, Bottom
ELSE
' save cursor settings
Top = PEEK(1121) AND 31
Bottom = PEEK(1120) AND 31
IF PEEK(1121) AND 32 THEN Status = FALSE ELSE Status = 1
CursorLine = CSRLIN
CursorColumn = POS(0)
LOCATE , , 0
END IF
END SUB
' draws a simple background
'
SUB scrCurtain
COLOR 0, 3
FOR x = 1 TO 25
LOCATE x, 1
PRINT STRING$(80, CHR$(176));
NEXT x
END SUB
' puts any ASCII (0-255) character on the screen, with colors
'
SUB scrPrint (ch%, Fore%, Back%)
DEF SEG = 47104
POKE (160 * (CSRLIN - 1) + 2 * (POS(0) - 1)), ch%
POKE (160 * (CSRLIN - 1) + 2 * (POS(0) - 1) + 1), Back% * 16 + Fore%
DEF SEG = 0
END SUB
' word wrap the text and save it in the array
'
SUB txtFill (Info AS TextBoxType, TBoxTxt AS STRING, TBoxPtr() AS INTEGER, TBoxArr() AS STRING)
' find the width of the box
IF Info.Corner.R < 1 THEN Info.Corner.R = 78
IF Info.Corner.L < 1 THEN Info.Corner.L = 1
wi = Info.Corner.R - Info.Corner.L - 1
DIM MaxLines AS INTEGER
MaxLines = 32767 \ wi ' use 32767, max string length
' pad the string with a space and position the cursor appropriately
IF RIGHT$(TBoxTxt$, 1) <> " " THEN TBoxTxt$ = TBoxTxt$ + " "
DIM x AS INTEGER
DIM arTBoxTxt(1 TO MaxLines) AS STRING
DIM arNum(1 TO MaxLines) AS INTEGER
x = 1
cRow = 0
COLOR 0, 7
Info.MaxLines = 0
' process the entire string everytime
DO
' move down the box
Info.MaxLines = Info.MaxLines + 1
' grab a line of TBoxTxt and save the beginning position
kt$ = MID$(TBoxTxt$, x, wi)
arNum(Info.MaxLines) = x
' look for a carraige return
ent = INSTR(kt$, CHR$(cstENTER))
IF ent THEN
IF ent = 1 THEN ' replace just the crlf with a space
kt$ = " "
ELSE
kt$ = LEFT$(kt$, ent - 1) + " " ' chop off the crlf and use a space
END IF
ELSE
' else chop the string until a space is reached
' or keep the whole thing if there is no space
ko$ = kt$
DO UNTIL RIGHT$(kt$, 1) = " "
kt$ = LEFT$(kt$, LEN(kt$) - 1)
LOOP
IF kt$ = "" THEN kt$ = ko$
END IF
' move the counter for the beginning of the next line (string)
x = x + LEN(kt$)
' store the actual string in the array
kt$ = kt$ + SPACE$(wi - LEN(kt$))
arTBoxTxt(Info.MaxLines) = kt$
LOOP UNTIL x > LEN(TBoxTxt$)
' reallocate space and store the data
REDIM TBoxArr(1 TO Info.MaxLines) AS STRING
REDIM TBoxPtr(1 TO Info.MaxLines) AS INTEGER
FOR x = 1 TO Info.MaxLines
TBoxArr(x) = arTBoxTxt(x)
TBoxPtr(x) = arNum(x)
NEXT x
' error checking
IF Info.Top < 1 THEN Info.Top = 1
IF Info.Top > UBOUND(TBoxPtr, 1) THEN Info.Top = UBOUND(TBoxPtr, 1)
IF Info.Cursor > LEN(TBoxTxt$) THEN Info.Cursor = LEN(TBoxTxt$)
IF Info.Cursor < 1 THEN Info.Cursor = 1
IF Info.Cursor < TBoxPtr(Info.Top) THEN
IF Info.Top > 1 THEN Info.Top = Info.Top - 1
Info.Cursor = txtWidth(Info.Top, Info, TBoxPtr(), TBoxTxt)
END IF
IF Info.Row < Info.Top THEN Info.Row = Info.Top
IF Info.Row > Info.MaxLines THEN Info.Row = Info.MaxLines
' reset line counter and Column to find the cursor
x = 0
Info.Col = 0
DO UNTIL Info.Col > 0
x = x + 1
' locate the cursor within this line
FOR p = TBoxPtr(x) TO TBoxPtr(x) + txtWidth(x, Info, TBoxPtr(), TBoxTxt) - 1
IF p = Info.Cursor THEN
Info.Row = x
Info.Col = p - TBoxPtr(x) + 1
EXIT FOR
END IF
NEXT p
LOOP
' account for the scrolling of the text as it is typed in
IF Info.Row - Info.Top > Info.Corner.B - Info.Corner.T - 2 THEN
Info.Top = Info.Top + 1
IF Info.Row < Info.Top THEN
IF Info.Top > 1 THEN Info.Top = Info.Top - 1
ELSE
'Info.Top = 1
END IF
END IF
' print the text in the box
CALL txtPrintItem(Info, TBoxPtr(), TBoxArr())
END SUB
' Opens a text file and loads it to a variable length string
'
FUNCTION txtLoad$ (FileName AS STRING)
OPEN FileName FOR BINARY AS #1
DIM B AS STRING * 1
DIM Text AS STRING
' read every character, ignore line feeds and replace tabs
FOR x% = 1 TO LOF(1)
GET 1, x%, B$
IF B$ = CHR$(9) THEN Text$ = Text$ + SPACE$(3)
IF B$ <> CHR$(10) THEN Text$ = Text$ + B$
NEXT x%
txtLoad$ = Text$
CLOSE #1
END FUNCTION
' print the "wrapped" text in the box
'
SUB txtPrintItem (Info AS TextBoxType, TBoxPtr() AS INTEGER, TBoxArr() AS STRING)
' print the string
COLOR 0, 7
LOCATE , , 0
IF Info.Corner.B < 1 THEN Info.Corner.B = 24
FOR cRow = 1 TO Info.Corner.B - Info.Corner.T - 1
IF Info.Top + cRow - 1 > Info.MaxLines THEN EXIT FOR
LOCATE Info.Corner.T + cRow, Info.Corner.L + 1
PRINT TBoxArr(Info.Top + cRow - 1);
NEXT cRow
' clear the rest of the box
FOR x = Info.Corner.T + cRow TO Info.Corner.B - 1
LOCATE x, Info.Corner.L + 1
PRINT SPACE$(Info.Corner.R - Info.Corner.L - 1);
NEXT x
END SUB
SUB txtSave (Info AS TextBoxType, Text AS STRING)
OPEN Info.FileName FOR BINARY AS #1 LEN = 1
DIM a AS STRING * 1
FOR x% = 1 TO LEN(Text)
a = MID$(Text, x%, 1)
PUT #1, , a
IF a = CHR$(13) THEN
a = CHR$(10)
PUT #1, , a
END IF
NEXT x%
CLOSE
END SUB
' returns the length of text on the specified row in the box
'
FUNCTION txtWidth% (pRow AS INTEGER, Info AS TextBoxType, TBoxPtr() AS INTEGER, TBoxTxt AS STRING)
IF pRow = Info.MaxLines THEN
' return the length of the TBox1Txt minus the beginning of the current row
txtWidth = LEN(TBoxTxt$) - TBoxPtr(pRow) + 1
ELSEIF pRow > 0 THEN
' if there is another line of TBox1Txt then return the value of
' the beginning of the next line minus the beginning of the current line
txtWidth = TBoxPtr(pRow + 1) - TBoxPtr(pRow)
END IF
END FUNCTION