IMPLEMENTATION MODULE StrInput; (* * REPERTOIRE * Release 1.6 * By Charles Bradford and Cole Brecheen * (c) Copyright 1985-1992 PMI * Green Bay, Wisconsin * All rights reserved * (414) 468-6040 * * $Header: D:/logfiles/mods/strinput.mov 1.7 10 Mar 1991 15:33:36 coleb $ * *) (*EntryDiag: IMPORT Diagnostics; :EntryDiag*) IMPORT BigSets; IMPORT ErrorManager; IMPORT KbdInput; IMPORT Key; IMPORT LowLevel; IMPORT M2Strings; IMPORT Numbers; IMPORT PosUtils; IMPORT Spkr; IMPORT StrConv; IMPORT StrEdit; IMPORT SYSTEM; IMPORT VWindows; VAR Initialized : BOOLEAN; PROCEDURE Init(); BEGIN IF Initialized THEN RETURN; ELSE Initialized := TRUE; END; (*EntryDiag: Diagnostics.Init(); :EntryDiag*) BigSets.Init(); ErrorManager.Init(); KbdInput.Init(); Key.Init(); LowLevel.Init(); M2Strings.Init(); Numbers.Init(); PosUtils.Init(); Spkr.Init(); StrConv.Init(); StrEdit.Init(); VWindows.Init(); (*EntryDiag: Diagnostics.diagS( 'Entering StrInput', '' ); :EntryDiag*) BeepAtNumbers := TRUE; (*EntryDiag: Diagnostics.diagS( 'Exiting StrInput', '' ); :EntryDiag*) END Init; CONST Minus = 45; (* ORD('-') *) DecimalKey = 46; (* ORD('.') *) CurrencySymbol = '$'; blank = ' '; PROCEDURE ReadWithEdits( WindowHandle: VWindows.AWindowHandle; VAR TheStr : ARRAY OF CHAR; col1, row1, FieldWidth: CARDINAL; VAR CursorPos: CARDINAL; VAR InsertMode: BOOLEAN; scrolling: BOOLEAN; VAR LastKey : CARDINAL; VAR LegalKeys, ExitKeys : KbdInput.KeyNumSet ); VAR bufch : CHAR; done, RedrawNeeded : BOOLEAN; SavedHeight, StrNdx, CharsScrolled, TheStrLen : CARDINAL; AllOkKeys: KbdInput.KeyNumSet; (* CursorPos = current offset of cursor from start of field *) PROCEDURE redraw( BeginningAt: CARDINAL ); VAR TmpStr: ARRAY [0..79] OF CHAR; BEGIN IF (BeginningAt < CharsScrolled) THEN HALT(); END; M2Strings.Copy( TheStr, BeginningAt, M2Strings.Length(TheStr) - BeginningAt, TmpStr ); BeginningAt := BeginningAt - CharsScrolled; StrEdit.SetLength( TmpStr, FieldWidth - BeginningAt ); IF (BeginningAt < FieldWidth) THEN VWindows.DrawStr( WindowHandle, col1 + BeginningAt, row1, SYSTEM.ADR(TmpStr), FieldWidth - BeginningAt ); RedrawNeeded := FALSE; END; END redraw; PROCEDURE MoveToPos( StrOffset: CARDINAL ); BEGIN WHILE (CursorPos + CharsScrolled) > StrOffset DO (* we are moving backwards *) IF CursorPos > 0 THEN DEC( CursorPos ); ELSE RedrawNeeded := TRUE; DEC( CharsScrolled ); END; DEC( StrNdx ); END; WHILE (CursorPos + CharsScrolled) < StrOffset DO (* we are moving forewards *) IF CursorPos < FieldWidth THEN INC( CursorPos ); ELSE RedrawNeeded := TRUE; INC( CharsScrolled ); END; INC( StrNdx ); END; END MoveToPos; PROCEDURE LeftToChar( TheChar: CHAR ); BEGIN WHILE (StrNdx > 0) AND (TheStr[ StrNdx ] # TheChar) DO MoveToPos( StrNdx - 1 ); END; END LeftToChar; PROCEDURE RightToChar( TheChar: CHAR ); BEGIN WHILE (StrNdx < TheStrLen) AND (TheStr[ StrNdx ] # TheChar) DO MoveToPos( StrNdx + 1 ); END; END RightToChar; PROCEDURE SkipLeftOver( TheChar: CHAR ); BEGIN WHILE (StrNdx > 0) AND (TheStr[ StrNdx ] = TheChar) DO MoveToPos( StrNdx - 1 ); END; END SkipLeftOver; PROCEDURE SkipRightOver( TheChar: CHAR ); BEGIN WHILE (StrNdx < TheStrLen) AND (TheStr[ StrNdx ] = TheChar) DO MoveToPos( StrNdx + 1 ); END; END SkipRightOver; BEGIN (* ReadWithEdits *) SavedHeight := VWindows.GetCursorHeight(WindowHandle); TheStrLen := M2Strings.Length( TheStr ); BigSets.SetUnion( LegalKeys, ExitKeys, AllOkKeys); FieldWidth := Numbers.Min( HIGH(TheStr) + 1, FieldWidth ); IF FieldWidth = 0 THEN (* This means you can pass 0 to FieldWidth if your only width concern is preventing overflow of TheStr. *) FieldWidth := HIGH( TheStr ) + 1; IF FieldWidth > (VWindows.EndCol(WindowHandle) - col1) THEN FieldWidth := VWindows.EndCol(WindowHandle) - col1; END; END; WHILE TheStrLen < FieldWidth DO StrEdit.Append( TheStr, blank ); INC( TheStrLen ); END; IF (NOT scrolling) AND (TheStrLen > FieldWidth) THEN StrEdit.SetLength( TheStr, FieldWidth ); TheStrLen := FieldWidth; END; CharsScrolled := 0; StrNdx := CursorPos; VWindows.GotoXY( WindowHandle, col1 + CursorPos, row1); IF InsertMode THEN VWindows.SetCursorHeight( WindowHandle, 6 ) ELSE VWindows.SetCursorHeight( WindowHandle, 2); END; (*turns on cursor*) done := FALSE; RedrawNeeded := TRUE; REPEAT IF RedrawNeeded THEN redraw( CharsScrolled ); END; VWindows.GotoXY( WindowHandle, col1 + CursorPos, row1); LastKey := KbdInput.KeyHit( AllOkKeys); CASE LastKey OF Key.Left : (* move to prior character position *) IF StrNdx > 0 THEN MoveToPos( StrNdx - 1 ); ELSE IF BigSets.InSet( ExitKeys, LastKey ) THEN (* left arrow at start moves to prior field if Key.Left in ExitKeys *) done := TRUE; END; END; | Key.Right : (* move to next character position *) IF StrNdx + 1 < TheStrLen THEN MoveToPos( StrNdx + 1 ); ELSE IF BigSets.InSet( ExitKeys, LastKey ) THEN (* left arrow at end moves to next field if Key.Right in ExitKeys *) done := TRUE; END; END; | Key.Del : (* Delete char under cursor *) M2Strings.Delete( TheStr, StrNdx, 1 ); StrEdit.Append( TheStr, blank ); redraw( StrNdx ); | Key.Home : (* Go to beginning of field *) IF BigSets.InSet( ExitKeys, LastKey ) THEN done := TRUE; ELSE MoveToPos( 0 ); END; | Key.End : (* Go past last character written *) IF BigSets.InSet( ExitKeys, LastKey ) THEN done := TRUE; ELSE MoveToPos( TheStrLen - 1 ); SkipLeftOver( blank ); RightToChar( blank ); END; | Key.CtrlRight, Key.Tab : (* Go to next word *) IF ((StrNdx = TheStrLen) OR (LastKey = Key.Tab)) AND BigSets.InSet( ExitKeys, LastKey ) THEN (* Tab or no next word found, so exit *) done := TRUE; ELSE IF TheStr[ StrNdx ] = blank THEN SkipRightOver( blank ); ELSE RightToChar( blank ); SkipRightOver( blank ); END; END; | Key.CtrlLeft, Key.BackTab : (* Go to previous word *) IF ((StrNdx = 0) OR (LastKey = Key.BackTab)) AND BigSets.InSet( ExitKeys, LastKey ) THEN (* BackTab or no previous word, so exit *) done := TRUE; ELSE IF TheStr[ StrNdx ] # blank THEN LeftToChar( blank ); END; SkipLeftOver( blank ); LeftToChar( blank ); SkipRightOver( blank ); END; | Key.AltD : (* Erase the entire entry *) LowLevel.Fill( SYSTEM.ADR( TheStr ), TheStrLen, blank ); MoveToPos( 0 ); RedrawNeeded := TRUE; | Key.AltE : (* Erase to the end of the field *) LowLevel.Fill( LowLevel.AddAddr( SYSTEM.ADR(TheStr), StrNdx), TheStrLen - StrNdx, blank ); redraw( StrNdx ); | Key.Ins : (* Toggle insert mode on and off *) InsertMode := NOT InsertMode; IF InsertMode THEN VWindows.SetCursorHeight( WindowHandle, 6 ) ELSE VWindows.SetCursorHeight(WindowHandle, 2); END; | Key.Escape : done := TRUE; (* Unconditionally exit if the user presses ESC. *) | Key.BackSpace : IF (StrNdx > 0) THEN MoveToPos( StrNdx - 1 ); IF InsertMode THEN M2Strings.Delete( TheStr, StrNdx, 1 ); StrEdit.Append( TheStr, blank ); ELSE TheStr[ StrNdx ] := blank; END; redraw( StrNdx ); ELSIF BigSets.InSet( ExitKeys, LastKey ) THEN done := TRUE; END; ELSE IF BigSets.InSet( ExitKeys, LastKey ) THEN done := TRUE; ELSIF (StrNdx < TheStrLen) AND (LastKey < KbdInput.Extended) THEN (* normal key pressed and cursor is not past end *) IF InsertMode THEN IF NOT scrolling THEN M2Strings.Delete( TheStr, TheStrLen - 1, 1 ); END; bufch := CHR( LastKey ); M2Strings.Insert( bufch, TheStr, StrNdx ); ELSE TheStr[ StrNdx ] := CHR( LastKey ); END; redraw( StrNdx ); MoveToPos( StrNdx + 1 ); ELSE Spkr.Noise( Spkr.Warble, Spkr.Normal, Spkr.Short); END; END; UNTIL done; StrEdit.SetLength( TheStr, FieldWidth ); (*We do this because TheStr may have gotten longer if we've been scrolling.*) VWindows.SetCursorHeight( WindowHandle, SavedHeight ); END ReadWithEdits; PROCEDURE ReadNumeric( WindowHandle: VWindows.AWindowHandle; VAR TheStr : ARRAY OF CHAR; col1, row1, FieldWidth: CARDINAL; DecimalPlaces: CARDINAL; FloatingPoint: BOOLEAN; VAR InDecimals: BOOLEAN; VAR LastKey : CARDINAL; VAR ExitKeys : KbdInput.KeyNumSet ); VAR SavedHeight, cnt, DecimalSpot, InsertionPoint, NonBlankLength: CARDINAL; AtLeadingZero: BOOLEAN; LegalKeys, AllOkKeys: KbdInput.KeyNumSet; DumStr: ARRAY [0..0] OF CHAR; BEGIN (* First we make sure the FieldWidth is okay. *) IF FieldWidth = 0 THEN FieldWidth := HIGH( TheStr ) + 1; ELSE FieldWidth := Numbers.Min( HIGH(TheStr) + 1, FieldWidth ); END; FieldWidth := Numbers.Min( VWindows.EndCol(WindowHandle) - col1, FieldWidth ); StrEdit.RightJustify( TheStr, FieldWidth ); SavedHeight := VWindows.GetCursorHeight(WindowHandle); VWindows.SetCursorHeight( WindowHandle, 2 ); (* Now we make sure DecimalPlaces is consistent with TheStr; if it's not, the number of DecimalPlaces in TheStr overrides. If there's no decimal point in TheStr at all, however, we'll make it consistent with DecimalPlaces. *) IF PosUtils.PresentPos( CHR(DecimalKey), TheStr, DecimalSpot ) THEN IF (DecimalSpot + 1) # (FieldWidth - DecimalPlaces) THEN DecimalPlaces := (FieldWidth - DecimalSpot) - 1; END; ELSIF (DecimalPlaces > 0) OR FloatingPoint THEN IF DecimalPlaces = 0 THEN (*We're here because FloatingPoint was true.*) DecimalPlaces := 1; (*Makes sure that we've at least got 0.0 in TheStr if FloatingPoint is true; prevents InsertionPoint from incrementing beyond FieldWidth, below.*) END; IF PosUtils.IsBlank( TheStr ) THEN StrEdit.InsertRightJustified( '0', TheStr, FieldWidth ); END; StrEdit.InsertRightJustified( '.', TheStr, FieldWidth ); FOR cnt := 1 TO DecimalPlaces DO StrEdit.InsertRightJustified( '0', TheStr, FieldWidth ); END; DecimalSpot := PosUtils.Pos( CHR(DecimalKey), TheStr ); ELSE DecimalSpot := M2Strings.Length( TheStr ); IF PosUtils.IsBlank( TheStr ) THEN (* Mike McCarthy's bug fix. *) StrEdit.InsertRightJustified( '0', TheStr, FieldWidth ); END; END; (* Now force FloatingPoint to false if CurrencySymbol is in TheStr. *) IF PosUtils.Present( CurrencySymbol, TheStr ) THEN FloatingPoint := FALSE; END; (* Now we find the insertion point. *) InsertionPoint := DecimalSpot; IF InDecimals THEN REPEAT INC( InsertionPoint ); UNTIL (InsertionPoint >= FieldWidth) OR (TheStr[InsertionPoint] = '0'); ELSE IF (TheStr[ InsertionPoint - 1 ] = '0') AND ( (InsertionPoint <= 1) OR (NOT PosUtils.Present(TheStr[InsertionPoint - 2], '0123456789'))) THEN AtLeadingZero := TRUE; ELSE AtLeadingZero := FALSE; END; END; BigSets.InitSet( LegalKeys ); BigSets.AppendSet( LegalKeys, "{8, 331, '.', '-', '0'..'9'}" ); BigSets.SetUnion( LegalKeys, ExitKeys, AllOkKeys); REPEAT VWindows.DrawStr( WindowHandle, col1, row1, SYSTEM.ADR(TheStr), 0 ); VWindows.GotoXY( WindowHandle, col1 + InsertionPoint, row1 ); LastKey := KbdInput.KeyHit( AllOkKeys); CASE LastKey OF 48..57: (* ASCII values of '0' to '9' *) IF InDecimals THEN IF (InsertionPoint = FieldWidth) THEN IF FloatingPoint AND (TheStr[0] = blank) THEN DumStr[0] := CHR(LastKey); IF BeepAtNumbers THEN Spkr.TimedNoise( (LastKey * 100) - 4400, 2 ); END; StrEdit.InsertRightJustified( DumStr, TheStr, InsertionPoint ); DEC( DecimalSpot ); ELSE Spkr.Noise( Spkr.Warble, Spkr.Normal, Spkr.Short); END; ELSE IF BeepAtNumbers THEN Spkr.TimedNoise( (LastKey * 100) - 4400, 2 ); END; TheStr[ InsertionPoint ] := CHR( LastKey ); INC( InsertionPoint ); END; ELSE IF AtLeadingZero THEN IF CHR(LastKey) # '0' THEN IF BeepAtNumbers THEN Spkr.TimedNoise( (LastKey * 100) - 4400, 2 ); END; TheStr[ InsertionPoint - 1 ] := CHR( LastKey ); AtLeadingZero := FALSE; END ELSE IF TheStr[0] = blank THEN DumStr[0] := CHR(LastKey); IF BeepAtNumbers THEN Spkr.TimedNoise( (LastKey * 100) - 4400, 2 ); END; StrEdit.InsertRightJustified( DumStr, TheStr, InsertionPoint ); ELSE Spkr.Noise( Spkr.Warble, Spkr.Normal, Spkr.Short); END; END; END; | Minus: (* '-' *) IF AtLeadingZero AND (InsertionPoint > 1) THEN IF (TheStr[InsertionPoint - 2] # '-') THEN TheStr[ InsertionPoint - 1 ] := CHR( LastKey ); StrEdit.InsertRightJustified( '0', TheStr, InsertionPoint ); (* Note that we're still AtLeadingZero here. *) END; END; | DecimalKey: IF (NOT InDecimals) AND (FloatingPoint OR (DecimalPlaces > 0)) THEN InDecimals := TRUE; INC( InsertionPoint ); END; | Key.BackSpace: IF InDecimals THEN IF InsertionPoint = (DecimalSpot + 1) THEN InDecimals := FALSE; DEC( InsertionPoint ); IF (NOT PosUtils.Present(TheStr[InsertionPoint - 1], '0123456789')) THEN AtLeadingZero := TRUE; StrEdit.InsertRightJustified( '0', TheStr, InsertionPoint ); END; ELSE IF FloatingPoint THEN IF (InsertionPoint = FieldWidth) THEN IF (InsertionPoint > (DecimalSpot + 1) ) THEN StrEdit.DeleteRightJustified( TheStr, InsertionPoint - 1, 1 ); INC( DecimalSpot ); ELSE InDecimals := FALSE; DEC( InsertionPoint ); END; ELSE TheStr[ InsertionPoint - 1 ] := '0'; DEC( InsertionPoint ); END; ELSE TheStr[ InsertionPoint - 1 ] := '0'; DEC( InsertionPoint ); END; END; ELSE IF NOT AtLeadingZero THEN StrEdit.DeleteRightJustified( TheStr, InsertionPoint - 1, 1 ); IF (NOT PosUtils.Present(TheStr[InsertionPoint - 1], '0123456789')) THEN AtLeadingZero := TRUE; IF TheStr[InsertionPoint - 1] = '-' THEN (*Get rid of the minus sign, if it's there.*) StrEdit.DeleteRightJustified( TheStr, InsertionPoint - 1, 1 ); END; StrEdit.InsertRightJustified( '0', TheStr, InsertionPoint ); END; END; END; ELSE END; UNTIL BigSets.InSet( ExitKeys, LastKey ); VWindows.SetCursorHeight( WindowHandle, SavedHeight ); END ReadNumeric; BEGIN Initialized := FALSE; Init(); END StrInput.