The QBNews Page 14 Volume 3, Number 2 June 29, 1992 A powerful line editor for QB by Larry Stone I use QB's INPUT statement to quickly test code. However, I find that its limitation of 255 characters, the fact that it will automatically wrap at the eightieth column, its inability to pre-size a window or work within a virtual window, it's complete lack of character masking, and the fact that the floating point library is loaded with it, when- ever it is used, whether needed or not, leaves the QB INPUT statement well short of a desirable routine to use with a "finished" program. Although I have, and use, an effective substitute routine written in ASM, the idea of a pure QB routine remained a fancy for quite a while. The opportunity to do a pure QB routine came as I was trying to come up with a project for the class I taught at the local community col- lege. I teach (part-time) "Introduction to Modular Programming" and the compiler we use to teach modular programming is, you guessed it, QB. The project began in the Fall term - a simple line editor to use in lieu of QB's INPUT statement. My Winter term students were required to expand its capabilities to include virtual windowing and automatic exiting when the end of the input line is reached (an optional feature used with field entries such as, zip codes and telephone numbers). The result of our effort (well - mostly my effort) is LINEEDIT.BAS, an extremely effective line editor ready to include with your code. With LINEEDIT.BAS are two other highly useful modules, KEYBOARD.BAS and VIDTOOLS.BAS (These two routines have been abbreviated for brevity). The KEYBOARD module must be loaded with LINEEDIT. The VIDTOOLS module is not necessary but is included because the test program, EDITDEMO, makes calls to two of its routines. The main module, EDITDEMO.BAS is a test vehicle for the editor and illustrates how to setup parameters needed to call the editor. LineEdit has twelve parameters in its parameter list. Row%, Col%, A$, and DisplayLen% are required. You must tell LineEdit what row to work on and what column to display the string from. You must also supply a string to edit (A$), and define the length of the display (better than QB's automatic, 255 character length that is guaranteed to wreck havoc on your nicely designed screen form). Let's review some of LineEdit's other parameters - the ones that turn a simple line editor into a power-packed routine. VwindowSize%, if defined as less than the string's DisplayLen, has no effect on LineEdit. However, if it is a larger number than DisplayLen then it defines a virtual window. Let's say that DisplayLen is defined for 60 characters. If VwindowSize% is smaller then the maximum string size allowed is 60 characters. But, if we define VwindowSize% as 300 characters then we can now edit a string up to 300 characters within a 60 character window. The displayed string will simply slide left or right 10 characters at a time, when we reach the end of the display. Separaters$, when non-null, tells LineEdit what characters are word separaters for jumping the cursor between words (use Ctrl plus arrow). The QBNews Page 15 Volume 3, Number 2 June 29, 1992 An effective Separaters$ string might be, " .:-()\/". Terminators%() MUST BE DIMmed by your controlling program. It is an array defining what key presses to exit the editor. Escape, up & down arrows, PgUp and PgDn, are examples of terminator keys. The zeroeth element of the array informs LineEdit what the last terminator is.This allows extreme flexibility. Let's say you have defined 7 terminators, Escape, Up, Down, PgUp, PgDn, Ctrl + PgUp, and Ctrl + PgDn. Now let's say that your first screen contains a single edit item - all you need is the escape key. You LET Terminators%(0) = 1. Your first terminator is escape and that is now the only terminator that LineEdit will use. Your next screen has five edit items. You now need to use up, down, PgUp and, PgDn so that your user can navigate between the strings. You LET Terminators%(0) = 5. If you have multiple screens of edit strings you would LET Terminators%(0) = 7 so that Ctrl + PgUp sends the cursor to the first string of the first screen and Ctrl + PgDn goes to the end string on the last screen. EditMask$ when null has no effect. However when filled with character A's, tells LineEdit to force every key stroke to upper case. If the EditMask$ looked like, "Aaaaa" then LineEdit would force the 1st char to upper case and the next four characters to lower case. CurPos% and CurOffset% are input/output parameters. They can be used to send the cursor to the same position it was in or, set them to zero for fresh starts at the beginning of the edit string. Kee% is a value that defines what keystroke terminated LineEdit. You would treat Kee = 13 (enter key) differently than Kee = 27 (escape). While we are on the subject of Kee%, LineEdit uses a routine from KEY- BOARD.BAS to handle all keyboard activity. The routine, KeyPressed%, returns extended keystrokes as negative numbers. In other words, down is returned as the value -80 (not CHR$(0) + CHR$(80) as QB does). This means that you must define them this way for you Terminators%() array. Below is a listing of LineEdit's built-in capabilities: Backspace Deletes character to left of cursor Delete Deletes character under cursor Ctrl + Home Deletes from cursor to beginning of line Ctrl + End Deletes from cursor to end of line Ctrl + Right Move to word on right (skips separaters) Ctrl + Left Move to word on left (skips separaters) Home Move to beginning of string End Move to space after last char of string Right Move cursor one character to right The LineEdit code is self-explanatory. However, one section of code deals with word seperaters and is constructed a little different. StepValue is set to -1 when the user presses Ctrl + Left and StepValue is set to 1 when the user presses Ctrl + Right. The code reads: The QBNews Page 16 Volume 3, Number 2 June 29, 1992 IF StepValue < False THEN X = 1 ELSE X = LEN(A$) FOR N = StrPos TO X STEP StepValue '---- Look into A$, one character at a time - is it a seperater? J = INSTR(Separaters$, MID$(A$, N, 1)) IF J THEN 'Found a separater character FoundSeparater = J 'Save J's value '---- Move our cursor to this separater position FOR i = StrPos TO N STEP StepValue IF StepValue < False THEN GOSUB CursorLeft ELSE _ GOSUB CursorRight NEXT EXIT FOR 'Cursor is on a separater so exit the loop END IF NEXT This loop simply steps through the string, one char at a time, then looks into Separaters$ to see if this one character has been defined as a word separater. If it is a separater, its location in the sepa- rater string is saved and the cursor is moved to that character in the string being edited. '---- If a separater was found, skip any repeating sequences of it. DO WHILE J 'Loop while Separater has been found N = N + StepValue 'Increment or Decrement N IF N = False THEN EXIT DO 'Prevent error with MID$() function '---- Only looking for repeating sequences of FoundSeparater J = INSTR(MID$(Separaters$, FoundSeparater, 1), MID$(A$, N, 1)) IF J THEN 'If we found another seperater IF StepValue < False THEN GOSUB CursorLeft ELSE _ GOSUB CursorRight END IF IF N >= LEN(A$) THEN EXIT DO LOOP This next loop simply looks to see if the found separater character is repeated. While it is repeated, the cursor is moved left or right. Once past the found separater, the loop is exited. In other words, if you have defined the space character (ASCII 32) as a separater, and the string has a word followed by ten spaces followed by another word, LineEdit will jump across all ten spaces with a Ctrl + left or right arrow keys (a slick little trick). To see how to use LineEdit, load and run its test program, EDITDEMO. Final note. LineEdit has no code for the Tab key. I leave that to you to encode into the routine. The QBNews Page 17 Volume 3, Number 2 June 29, 1992 Code for this article appears in LINEDIT.ZIP.