IMPLEMENTATION MODULE InputManager; (* * 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/inputman.mov 1.5 10 Mar 1991 15:28:34 coleb $ * *) IMPORT BigSets; IMPORT ErrorManager; IMPORT ErrorNames; IMPORT FieldTypes; IMPORT FrameManager; IMPORT FramePainter; IMPORT GenLists; IMPORT KbdInput; IMPORT Key; IMPORT ListUtils; IMPORT M2Strings; IMPORT MsgBox2; IMPORT Numbers; IMPORT PosUtils; IMPORT Rectangles; IMPORT ScrnTypes; IMPORT ScrnUtl1; IMPORT StrConv; IMPORT StrEdit; IMPORT SYSTEM; IMPORT UserOps; IMPORT VWindows; VAR Initialized : BOOLEAN; PROCEDURE Init(); BEGIN IF Initialized THEN RETURN; ELSE Initialized := TRUE; END; BigSets.Init(); ErrorManager.Init(); ErrorNames.Init(); FieldTypes.Init(); FrameManager.Init(); FramePainter.Init(); GenLists.Init(); KbdInput.Init(); Key.Init(); ListUtils.Init(); M2Strings.Init(); MsgBox2.Init(); Numbers.Init(); PosUtils.Init(); Rectangles.Init(); ScrnTypes.Init(); ScrnUtl1.Init(); StrConv.Init(); StrEdit.Init(); UserOps.Init(); VWindows.Init(); END Init; CONST RequiredMessage = "This field must be filled in. Press Return to continue."; PROCEDURE GetScrollableArea(TheFrame : ScrnTypes.DisplayFrame; VAR ScrollRect : Rectangles.ARectangle); (* Returns a rectangle with the absolute field coordinates of the scrollable area in the frame *) BEGIN ScrnUtl1.GetVisibleArea(TheFrame, ScrollRect); (* Gets physical screen coordinates of visible part of frame. *) IF TheFrame^.headline > 0 THEN IF NOT ScrnUtl1.BoxInFrame(TheFrame) THEN INC(ScrollRect.row1, TheFrame^.headline) ELSE INC(ScrollRect.row1, TheFrame^.headline-1) END; END; END GetScrollableArea; PROCEDURE ClosestField( TheFrame: ScrnTypes.DisplayFrame; TheField, col, row: CARDINAL; direction: VWindows.Compass ): CARDINAL; (*Returns the number of the field closest to TheField in the direction specified. If you pass 0 to col and row, it figures out where TheField is automatically. If you pass 0 to TheField, it assumes the cursor is presently outside of a field, and that col and row indicate where it is.*) VAR dist, FieldCount, BestGuess, BestDistance, ListStart, ListEnd, StartField, OldField: CARDINAL; p1, p2, BestPoint: Rectangles.APoint; PROCEDURE Candidate( TheFrame: ScrnTypes.DisplayFrame; TheField: CARDINAL; VAR Cursor, FieldSpot: Rectangles.APoint; direction: VWindows.Compass; VAR dist: CARDINAL ): BOOLEAN; VAR tmpcol, tmprow: CARDINAL; BEGIN tmpcol := ScrnUtl1.VirtualFieldCol( TheFrame, TheField ); tmprow := ScrnUtl1.VirtualFieldRow( TheFrame, TheField ); FieldSpot.col := INTEGER(tmpcol); FieldSpot.row := INTEGER(tmprow); CASE direction OF VWindows.North, VWindows.NE, VWindows.NW: IF (tmprow >= CARDINAL(Cursor.row)) THEN RETURN FALSE; END ELSE END; CASE direction OF VWindows.South, VWindows.SE, VWindows.SW: IF (tmprow <= CARDINAL(Cursor.row)) THEN RETURN FALSE; END; ELSE END; CASE direction OF VWindows.East, VWindows.SE, VWindows.NE: IF (tmpcol <= CARDINAL(Cursor.col)) THEN RETURN FALSE; END ELSE END; CASE direction OF VWindows.West, VWindows.NW, VWindows.SW: IF (tmpcol >= CARDINAL(Cursor.col)) THEN RETURN FALSE; END; ELSE END; dist := Rectangles.Distance( Cursor, p2 ); RETURN TRUE; END Candidate; BEGIN (*ClosestField*) OldField := TheFrame^.CurrentField; IF TheField # 0 THEN col := ScrnUtl1.VirtualFieldCol( TheFrame, TheField ); row := ScrnUtl1.VirtualFieldRow( TheFrame, TheField ); ELSE TheFrame^.CurrentField := 0; END; p1.col := INTEGER(col); p1.row := INTEGER(row); BestGuess := 0; BestDistance := 65535; CASE direction OF VWindows.East, VWindows.SW, VWindows.South, VWindows.SE: ListEnd := LastInputField(TheFrame); FieldCount := NextInputField( TheFrame, 0 ); BestPoint.col := 32767; BestPoint.row := 32767; LOOP IF TheFrame^.CurrentField = ListEnd THEN EXIT END; IF Candidate( TheFrame, FieldCount, p1, p2, direction, dist ) THEN IF (dist < BestDistance) THEN BestDistance := dist; BestPoint := p2; BestGuess := FieldCount; END; IF (direction = VWindows.South) AND (p2.row > BestPoint.row) THEN EXIT ELSIF (direction = VWindows.East) AND ((p2.col > BestPoint.col) OR (p2.row > BestPoint.row)) THEN EXIT END; END; TheFrame^.CurrentField := FieldCount; FieldCount := NextInputField( TheFrame, 0 ); END; ELSE ListStart := FirstInputField(TheFrame); FieldCount := PrevInputField( TheFrame, 0 ); BestPoint.col := 0; BestPoint.row := 0; LOOP IF TheFrame^.CurrentField = ListStart THEN EXIT END; IF Candidate( TheFrame, FieldCount, p1, p2, direction, dist ) THEN IF (dist < BestDistance) THEN BestDistance := dist; BestPoint := p2; BestGuess := FieldCount; END; IF (direction = VWindows.North) AND (p2.row < BestPoint.row) THEN EXIT ELSIF (direction = VWindows.West) AND ((p2.col < BestPoint.col) OR (p2.row < BestPoint.row)) THEN EXIT END; END; TheFrame^.CurrentField := FieldCount; FieldCount := PrevInputField( TheFrame, 0 ); END; END; TheFrame^.CurrentField := OldField; (* Preserve current field *) IF BestGuess # 0 THEN RETURN BestGuess; ELSE RETURN TheField; END; END ClosestField; PROCEDURE InSameRow( TheFrame: ScrnTypes.DisplayFrame; Field1, Field2: CARDINAL ): BOOLEAN; BEGIN RETURN (ScrnUtl1.VirtualFieldRow(TheFrame, Field1) = ScrnUtl1.VirtualFieldRow(TheFrame, Field2) ); END InSameRow; PROCEDURE InSameCol( TheFrame: ScrnTypes.DisplayFrame; Field1, Field2: CARDINAL ): BOOLEAN; BEGIN RETURN (ScrnUtl1.VirtualFieldCol(TheFrame, Field1) = ScrnUtl1.VirtualFieldCol(TheFrame, Field2) ); END InSameCol; (*Probably ought to move following two procedures to MakeFrame and add Horizontal boolean to FieldRecType.*) PROCEDURE InHorizGroup( TheFrame: ScrnTypes.DisplayFrame; TheField: CARDINAL ): BOOLEAN; BEGIN IF ScrnUtl1.FieldType( TheFrame, TheField ) # ScrnTypes.GroupMember THEN RETURN FALSE; END; IF ScrnUtl1.ChoiceNumber( TheFrame, TheField ) < ScrnUtl1.NumberOfChoices( TheFrame, TheField ) THEN IF (NOT InSameRow( TheFrame, TheField, TheField + 1 )) THEN RETURN FALSE; END; END; IF ScrnUtl1.ChoiceNumber( TheFrame, TheField ) > 1 THEN IF (NOT InSameRow( TheFrame, TheField, TheField - 1 )) THEN RETURN FALSE; END; END; RETURN TRUE; END InHorizGroup; PROCEDURE InVerticalGroup( TheFrame: ScrnTypes.DisplayFrame; TheField: CARDINAL ): BOOLEAN; BEGIN IF ScrnUtl1.FieldType( TheFrame, TheField ) # ScrnTypes.GroupMember THEN RETURN FALSE; END; IF ScrnUtl1.ChoiceNumber( TheFrame, TheField ) < ScrnUtl1.NumberOfChoices( TheFrame, TheField ) THEN IF (NOT InSameCol( TheFrame, TheField, TheField + 1 )) THEN RETURN FALSE; END; END; IF ScrnUtl1.ChoiceNumber( TheFrame, TheField ) > 1 THEN IF (NOT InSameCol( TheFrame, TheField, TheField - 1 )) THEN RETURN FALSE; END; END; RETURN TRUE; END InVerticalGroup; PROCEDURE NextSelection( TheFrame: ScrnTypes.DisplayFrame; TheField: CARDINAL ): CARDINAL; VAR TmpPtr: ScrnTypes.InputFieldPtr; BEGIN ScrnUtl1.GetFieldPtr( TheFrame, TheField, TmpPtr ); IF TmpPtr^.GroupID = TmpPtr^.GroupSize THEN RETURN ScrnUtl1.FirstMember( TheFrame, TheField ); ELSE RETURN TheField + 1; END; END NextSelection; PROCEDURE PrevSelection( TheFrame: ScrnTypes.DisplayFrame; TheField: CARDINAL ): CARDINAL; VAR TmpPtr: ScrnTypes.InputFieldPtr; BEGIN ScrnUtl1.GetFieldPtr( TheFrame, TheField, TmpPtr ); IF TmpPtr^.GroupID = 1 THEN RETURN ScrnUtl1.FirstMember( TheFrame, TheField ) + TmpPtr^.GroupSize - 1; ELSE RETURN TheField - 1; END; END PrevSelection; PROCEDURE SelectionKeyMatch( TheFrame: ScrnTypes.DisplayFrame; KeyHit: CARDINAL; VAR SelectedFieldNum: CARDINAL ): BOOLEAN; VAR found: BOOLEAN; ListEnd, cnt: CARDINAL; FieldPtr: ScrnTypes.InputFieldPtr; BEGIN IF KeyHit = 0 THEN (*Jonathan March's 21 Jun 88 fix.*) RETURN FALSE; END; cnt := 0; found := FALSE; ListEnd := GenLists.ListLength( TheFrame^.FieldList ); WHILE (NOT found) AND (cnt < ListEnd) DO INC( cnt ); ScrnUtl1.GetFieldPtr( TheFrame, cnt, FieldPtr ); IF FieldPtr^.typ = ScrnTypes.GotoCode THEN found := KbdInput.CAPkey(KeyHit) = KbdInput.CAPkey(FieldPtr^.MenuKey); ELSIF FieldPtr^.typ = ScrnTypes.GroupMember THEN found := KbdInput.CAPkey(KeyHit) = KbdInput.CAPkey(FieldPtr^.ChoiceKey); END; END; IF found THEN SelectedFieldNum := cnt; END; RETURN found; END SelectionKeyMatch; PROCEDURE InSameGroup( TheFrame: ScrnTypes.DisplayFrame; Field1, Field2: CARDINAL ): BOOLEAN; BEGIN IF (ScrnUtl1.FieldType(TheFrame, Field1) # ScrnTypes.GroupMember) OR (ScrnUtl1.FieldType(TheFrame, Field2) # ScrnTypes.GroupMember) THEN RETURN FALSE; END; RETURN ScrnUtl1.FirstMember( TheFrame, Field1 ) = ScrnUtl1.FirstMember( TheFrame, Field2 ); END InSameGroup; PROCEDURE MoveToSelected( VAR TheFrame: ScrnTypes.DisplayFrame; VAR TheField: CARDINAL ); (* Pass this routine any field number that's a GroupMember, and it moves TheFrame^.CurrentField to the selected member of the group (and also sets TheField to the field number of that member). We assume the caller has sense enough not to call this for fields that are not GroupMembers. *) VAR cnt, FieldNum: CARDINAL; TmpPtr: ScrnTypes.InputFieldPtr; BEGIN FieldNum := ScrnUtl1.FirstMember( TheFrame, TheField ); TheField := FieldNum; (*Save the number of the first choice in TheField, in case we don't find one that's selected.*) cnt := 1; LOOP ScrnUtl1.GetFieldPtr( TheFrame, FieldNum, TmpPtr ); IF (cnt = TmpPtr^.GroupSize) OR (TmpPtr^.selected) THEN EXIT; END; INC( FieldNum ); INC( cnt ); END; IF TmpPtr^.selected THEN TheFrame^.CurrentField := FieldNum; TheField := FieldNum; ELSE TheFrame^.CurrentField := TheField; ScrnUtl1.GetFieldPtr( TheFrame, TheField, TmpPtr ); (* 28 Dec 88: added this to guarantee that we're setting the ^.selected field of the first choice field rather than the last one. Fix contributed by Ulrik Schmidt. *) TmpPtr^.selected := TRUE; END; END MoveToSelected; PROCEDURE RequiredFilled( FrameRec: ScrnTypes.DisplayFrame; VAR FieldNum: CARDINAL ): BOOLEAN; VAR LocalList : GenLists.GenList; TmpPtr: ScrnTypes.InputFieldPtr; ImagePtr: ScrnTypes.ImageElmtPtr; ListEnd : CARDINAL; BEGIN ListEnd := ScrnUtl1.FieldListTotal( FrameRec ); FieldNum := 1; WHILE FieldNum <= ListEnd DO (* look at each required field, until one is not filled *) ScrnUtl1.GetFieldPtr( FrameRec, FieldNum, TmpPtr ); IF (TmpPtr^.typ = ScrnTypes.EditorCode) AND TmpPtr^.req THEN (*We've got a required Editor field*) IF ScrnUtl1.ListFromEdField( FrameRec, FrameRec^.CurrentField, LocalList ) AND ListUtils.IsBlankList( LocalList ) THEN RETURN FALSE; END; ELSIF TmpPtr^.req THEN ScrnUtl1.GetFieldImagePtr( FrameRec, FieldNum, ImagePtr ); (* if field is required and not filled, flag it and exit *) IF PosUtils.IsBlank( ImagePtr^.text ) THEN RETURN FALSE; END; END; INC( FieldNum ); END; FieldNum := 0; RETURN TRUE; END RequiredFilled; PROCEDURE MakeLegalKeys( TheFrame: ScrnTypes.DisplayFrame; VAR NewLegalKeys: KbdInput.KeyNumSet ); (* construct the sets of legal keys for the field types *) VAR tmpkey, ListEnd, cnt: CARDINAL; FieldPtr: ScrnTypes.InputFieldPtr; BEGIN BigSets.SetUnion( UserOps.ScreenKeySet, UserOps.FunctKeySet, NewLegalKeys ); (*Add the FunctKeySet to the ScreenKeySet.*) ListEnd := ScrnUtl1.FieldListTotal( TheFrame ); IF ListEnd = 0 THEN RETURN; END; FOR cnt := 1 TO ListEnd DO ScrnUtl1.GetFieldPtr( TheFrame, cnt, FieldPtr ); CASE FieldPtr^.typ OF ScrnTypes.GotoCode, ScrnTypes.GroupMember: IF FieldPtr^.typ = ScrnTypes.GotoCode THEN tmpkey := FieldPtr^.MenuKey; ELSE tmpkey := FieldPtr^.ChoiceKey; END; IF (tmpkey >= ORD('a')) AND (tmpkey <= ORD('z')) THEN (*This stuff gives us case insensitivity in selection characters.*) BigSets.InclSet( NewLegalKeys, tmpkey ); BigSets.InclSet( NewLegalKeys, KbdInput.CAPkey(tmpkey) ); ELSIF (tmpkey >= ORD('A')) AND (tmpkey <= ORD('Z')) THEN BigSets.InclSet( NewLegalKeys, tmpkey ); BigSets.InclSet( NewLegalKeys, tmpkey + 32 ); ELSE BigSets.InclSet( NewLegalKeys, tmpkey ); END; ELSE (* fall through *) END; END; END MakeLegalKeys; PROCEDURE MovePointerBar( FrameRec: ScrnTypes.DisplayFrame; NewField : CARDINAL ); VAR TmpStr : ARRAY [0..80] OF CHAR; NewRowsScrolled, NewColsScrolled : CARDINAL; FirstFieldCol, FirstFieldRow, LastFieldCol, LastFieldRow : CARDINAL; FirstVisibleRow, FirstVisibleCol, LastVisibleRow, LastVisibleCol : CARDINAL; Vis : Rectangles.ARectangle; PROCEDURE ChangeSelection( TheFrame: ScrnTypes.DisplayFrame; NewField: CARDINAL ); VAR FieldPtr: ScrnTypes.InputFieldPtr; BEGIN ScrnUtl1.GetFieldPtr( TheFrame, TheFrame^.CurrentField, FieldPtr ); FieldPtr^.selected := FALSE; FramePainter.RedrawField( FrameRec, FrameRec^.CurrentField, FALSE ); (* Takes the pointer bar off the old field. *) FramePainter.RedrawField( TheFrame, NewField, TRUE ); TheFrame^.CurrentField := NewField; ScrnUtl1.GetFieldPtr( TheFrame, TheFrame^.CurrentField, FieldPtr ); FieldPtr^.selected := TRUE; IF UserOps.DoPrompting THEN GetPromptStr( FrameRec, FrameRec^.CurrentField, TmpStr ); ShowPrompt( FrameRec, TmpStr ); END; END ChangeSelection; BEGIN (* MovePointerBar *) IF NewField < FirstInputField(FrameRec) THEN NewField := LastInputField(FrameRec); ELSIF NewField > LastInputField( FrameRec ) THEN NewField := FirstInputField(FrameRec); ELSIF (ScrnUtl1.FieldType(FrameRec, NewField) = ScrnTypes.DispCode) THEN NewField := NextInputField( FrameRec, 0 ); END; IF NewField = FrameRec^.CurrentField THEN RETURN; ELSIF FrameRec^.CurrentField = 0 THEN FrameRec^.CurrentField := FirstInputField(FrameRec); ELSIF InSameGroup( FrameRec, FrameRec^.CurrentField, NewField) THEN ChangeSelection( FrameRec, NewField ); RETURN; ELSE FramePainter.RedrawField( FrameRec, FrameRec^.CurrentField, FALSE ); (* Takes the pointer bar off the old field. This is in the ELSE clause because, if CurrentField is 0, we're placing the first pointer bar, and we don't need to take it off any other field.*) END; IF ScrnUtl1.FieldType(FrameRec, NewField) = ScrnTypes.GroupMember THEN (* This doesn't actually redraw the new field with the pointer bar on it. It just sets the variables that will put us on the right field if we're moving into a group from somewhere outside it; notice that we RETURN above if we're moving inside the same group. *) MoveToSelected( FrameRec, NewField ); END; FrameRec^.CurrentField := NewField; (* Now we've lost track of what the old field was. *) (* Check and see if scrolling is needed *) IF NOT ScrnUtl1.EntirelyVisible(FrameRec, NewField) THEN GetScrollableArea(FrameRec, Vis); FirstVisibleRow := CARDINAL(Vis.row1) + FrameRec^.RowsScrolled - FrameRec^.startrow; LastVisibleRow := CARDINAL(Vis.row2) + FrameRec^.RowsScrolled - FrameRec^.startrow; FirstVisibleCol := CARDINAL(Vis.col1) + FrameRec^.ColsScrolled - FrameRec^.startcol; LastVisibleCol := CARDINAL(Vis.col2) + FrameRec^.ColsScrolled - FrameRec^.startcol; FirstFieldRow := ScrnUtl1.VirtualFieldRow(FrameRec, NewField); FirstFieldCol := ScrnUtl1.VirtualFieldCol(FrameRec, NewField); LastFieldRow := FirstFieldRow + ScrnUtl1.FieldHeight(FrameRec, NewField) - 1; LastFieldCol := FirstFieldCol + ScrnUtl1.FieldWidth(FrameRec, NewField) - 1; (* Default to no scrolling *) NewRowsScrolled := FrameRec^.RowsScrolled; NewColsScrolled := FrameRec^.ColsScrolled; (* Vertical *) IF FirstFieldRow < FirstVisibleRow THEN IF ScrnUtl1.InputFieldsAbove(FrameRec, NewField) THEN DEC(NewRowsScrolled, FirstVisibleRow-FirstFieldRow); ELSE (* Make sure any text above first input field is visible. *) NewRowsScrolled := 0; END (* if *); ELSIF LastFieldRow > LastVisibleRow THEN IF ScrnUtl1.InputFieldsBelow(FrameRec, NewField) THEN INC(NewRowsScrolled, LastFieldRow-LastVisibleRow); ELSE (* Scroll to bottom of frame *) INC(NewRowsScrolled, ScrnUtl1.PartOutside(FrameRec, Vis, VWindows.South)); END; END (* if *); (* Horizontal *) IF FirstFieldCol < FirstVisibleCol THEN IF ScrnUtl1.InputFieldsToLeft(FrameRec, NewField) THEN DEC(NewColsScrolled, FirstVisibleCol-FirstFieldCol); ELSE NewColsScrolled := 0; END; ELSIF LastFieldCol > LastVisibleCol THEN IF ScrnUtl1.InputFieldsToRight(FrameRec, NewField) THEN INC(NewColsScrolled, LastFieldCol-LastVisibleCol); ELSE INC(NewColsScrolled, ScrnUtl1.PartOutside(FrameRec, Vis, VWindows.East)); END; END (* if *); SlideFrame(FrameRec, FrameRec^.ColsScrolled, NewColsScrolled, FrameRec^.RowsScrolled, NewRowsScrolled); END (* if not entirely visible *); IF ScrnUtl1.FieldType(FrameRec, NewField) # ScrnTypes.EditorCode THEN FramePainter.RedrawField(FrameRec, NewField, TRUE); (* Hightlight field *) END; IF UserOps.DoPrompting THEN GetPromptStr( FrameRec, FrameRec^.CurrentField, TmpStr ); ShowPrompt( FrameRec, TmpStr ); END; END MovePointerBar; PROCEDURE PageDown(TheFrame : ScrnTypes.DisplayFrame); (* Move to the field nearest to one scroll height below the current one. *) VAR Vis : Rectangles.ARectangle; NewField, ScrollHeight, NewRow, NewCol, Distance : CARDINAL; BEGIN IF ScrnUtl1.EntirelyVisible( TheFrame, LastInputField(TheFrame) ) THEN MovePointerBar( TheFrame, LastInputField(TheFrame) ); RETURN; END; (* The next field isn't currently visible, need to repaint the entire frame *) GetScrollableArea(TheFrame, Vis); ScrollHeight := CARDINAL(Vis.row2-Vis.row1)+1; NewRow := ScrnUtl1.VirtualFieldRow(TheFrame, TheFrame^.CurrentField) + ScrollHeight; NewCol := ScrnUtl1.VirtualFieldCol(TheFrame, TheFrame^.CurrentField); NewField := ClosestField(TheFrame, 0, NewCol, NewRow+1, VWindows.North); MovePointerBar( TheFrame, NewField ); END PageDown; PROCEDURE PageUp(TheFrame : ScrnTypes.DisplayFrame); (* Move to the field nearest to one scroll height above the current one. *) VAR Vis : Rectangles.ARectangle; NewField, vrow, ScrollHeight, NewRow, NewCol: CARDINAL; BEGIN GetScrollableArea(TheFrame, Vis); ScrollHeight := CARDINAL(Vis.row2-Vis.row1)+1; IF TheFrame^.RowsScrolled = 0 THEN MovePointerBar( TheFrame, FirstInputField(TheFrame) ); ELSE vrow := ScrnUtl1.VirtualFieldRow(TheFrame, TheFrame^.CurrentField); NewRow := Numbers.IntMax( 1, INTEGER(vrow) - INTEGER(ScrollHeight) ); NewCol := ScrnUtl1.VirtualFieldCol(TheFrame, TheFrame^.CurrentField); NewField := ClosestField(TheFrame, 0, NewCol, NewRow-1, VWindows.South); MovePointerBar( TheFrame, NewField ); END; END PageUp; (*================== Exported Procedures ========================*) PROCEDURE FirstInputField(FrameRec : ScrnTypes.DisplayFrame) : CARDINAL; VAR LastField, NewField : CARDINAL; BEGIN LastField := ScrnUtl1.FieldListTotal(FrameRec); NewField := 1; WHILE (ScrnUtl1.FieldType(FrameRec, NewField) = ScrnTypes.DispCode) DO IF NewField < LastField THEN INC(NewField); ELSE RETURN 1; END; END (* while *); RETURN NewField; END FirstInputField; PROCEDURE LastInputField(FrameRec : ScrnTypes.DisplayFrame) : CARDINAL; VAR NewField : CARDINAL; BEGIN NewField := ScrnUtl1.FieldListTotal(FrameRec); WHILE (ScrnUtl1.FieldType(FrameRec, NewField) = ScrnTypes.DispCode) DO IF NewField > 1 THEN DEC(NewField); ELSE RETURN ScrnUtl1.FieldListTotal(FrameRec); END (* if *); END (* while *); RETURN NewField; END LastInputField; PROCEDURE NextInputField( FrameRec : ScrnTypes.DisplayFrame; skip: CARDINAL ): CARDINAL; VAR LastField, NewField : CARDINAL; BEGIN LastField := ScrnUtl1.FieldListTotal(FrameRec); IF FrameRec^.CurrentField < (LastField - skip) THEN NewField := FrameRec^.CurrentField + skip + 1; ELSE NewField := 1; END; WHILE (ScrnUtl1.FieldType(FrameRec, NewField) = ScrnTypes.DispCode) AND (NewField # FrameRec^.CurrentField) DO IF NewField < LastField THEN INC(NewField); ELSE NewField := 1; END; END (* while *); RETURN NewField; END NextInputField; PROCEDURE PrevInputField( VAR FrameRec : ScrnTypes.DisplayFrame; skip: CARDINAL ) : CARDINAL; VAR NewField : CARDINAL; BEGIN IF (FrameRec^.CurrentField + skip) > 1 THEN NewField := (FrameRec^.CurrentField - skip) - 1; ELSE NewField := ScrnUtl1.FieldListTotal(FrameRec); END; WHILE (ScrnUtl1.FieldType(FrameRec, NewField) = ScrnTypes.DispCode) AND (NewField # FrameRec^.CurrentField) DO IF NewField > 1 THEN DEC(NewField); ELSE NewField := ScrnUtl1.FieldListTotal(FrameRec); END; END (* while *); RETURN NewField; END PrevInputField; PROCEDURE HiLiteSelChars( TheFrame: ScrnTypes.DisplayFrame ); VAR FieldListEnd, cnt: CARDINAL; TmpType : CHAR; BEGIN FieldListEnd := ScrnUtl1.FieldListTotal( TheFrame ); FOR cnt := 1 TO FieldListEnd DO TmpType := ScrnUtl1.FieldType( TheFrame, cnt ); IF (TmpType = ScrnTypes.GotoCode) OR (TmpType = ScrnTypes.GroupMember) THEN IF ScrnUtl1.EntirelyVisible( TheFrame, cnt ) THEN FramePainter.RedrawField( TheFrame, cnt, FALSE ); END; END; END; END HiLiteSelChars; PROCEDURE LookAlive( TheFrame: ScrnTypes.DisplayFrame ); VAR TmpStr: ARRAY [0..127] OF CHAR; fldtype : CHAR; BEGIN IF TheFrame^.action <= 'Z' THEN (* We are temporarily lowercasing the .action character to tell us whether the frame is under the control of ControlFrame. We use this to disable LookAlive when it is called in places where it probably shouldn't be. Not good. *) RETURN; END; HiLiteSelChars( TheFrame ); IF (TheFrame^.CurrentField > 0) AND (TheFrame^.CurrentField <= ScrnUtl1.FieldListTotal(TheFrame)) THEN IF UserOps.DoPrompting THEN GetPromptStr( TheFrame, TheFrame^.CurrentField, TmpStr ); ShowPrompt( TheFrame, TmpStr ); END; fldtype := ScrnUtl1.FieldType( TheFrame, TheFrame^.CurrentField ); IF ScrnUtl1.EntirelyVisible( TheFrame, TheFrame^.CurrentField ) THEN FramePainter.RedrawField( TheFrame, TheFrame^.CurrentField, TRUE ); IF (fldtype # ScrnTypes.GotoCode) AND (fldtype # ScrnTypes.GroupMember) AND (fldtype # ScrnTypes.DispCode) THEN VWindows.SetCursorHeight( VWindows.CurrentWindow, 2 ); END; END; END; END LookAlive; PROCEDURE ReconstructFrame( TheFrame: ScrnTypes.DisplayFrame ); VAR TmpStr: ARRAY [0..127] OF CHAR; BEGIN FramePainter.ShowDisplayFrame( TheFrame, 0, 0, 0, 0 ); LookAlive( TheFrame ); END ReconstructFrame; PROCEDURE ShowPrompt( FrameRec: ScrnTypes.DisplayFrame; str : ARRAY OF CHAR ); (*Display the prompt centered within the prompt line specified in UserOps.*) VAR tmp: ARRAY [0..127] OF CHAR; (*We use tmp because the caller may not have left enough room in str to pad it with blanks.*) BEGIN ScrnUtl1.SetPromptColors( FrameRec ); M2Strings.Assign( str, tmp ); StrEdit.Center( tmp, UserOps.PromptLength ); VWindows.DrawStr( FrameRec^.WindowHandle, UserOps.PromptCol, UserOps.PromptRow, SYSTEM.ADR(tmp), UserOps.PromptLength ); END ShowPrompt; PROCEDURE GetPromptStr( TheFrame: ScrnTypes.DisplayFrame; TheField: CARDINAL; VAR TheStr: ARRAY OF CHAR ); VAR FieldRec: ScrnTypes.InputFieldRecord; TypeCode: CARDINAL; MaxStr, MinStr: ARRAY [0..31] OF CHAR; BEGIN ScrnUtl1.GetFieldRec( TheFrame, TheField, FieldRec ); IF FieldRec.PromptNum # 0 THEN GenLists.GetElmt( TheFrame^.PromptList, FieldRec.PromptNum, TheStr, TypeCode ); ELSE FieldTypes.GetDefaultPrompt( FieldRec.typ, TheStr ); CASE FieldRec.typ OF ScrnTypes.IntCode : StrConv.LongIntegerToStr( FieldRec.iMax, 1, MaxStr ); StrConv.LongIntegerToStr( FieldRec.iMin, 1, MinStr); | ScrnTypes.RealCode : StrConv.RealToStr( FieldRec.rMax, 1, 0, MaxStr ); StrConv.RealToStr( FieldRec.rMin, 1, 0, MinStr); ELSE RETURN; END; StrEdit.ReplaceStr( 'MAX', MaxStr, TheStr ); StrEdit.ReplaceStr( 'MIN', MinStr, TheStr ); END; END GetPromptStr; PROCEDURE SlideFrame( FrameRec: ScrnTypes.DisplayFrame; OldColsScrolled, NewColsScrolled, OldRowsScrolled, NewRowsScrolled: CARDINAL ); VAR Vis: Rectangles.ARectangle; vdist, ScrollableHeight : INTEGER; BEGIN FrameRec^.ColsScrolled := NewColsScrolled; FrameRec^.RowsScrolled := NewRowsScrolled; vdist := INTEGER(NewRowsScrolled) - INTEGER(OldRowsScrolled); IF (vdist = 0) AND (NewColsScrolled = OldColsScrolled) THEN RETURN; END; ScrnUtl1.SetNormalColors( FrameRec ); GetScrollableArea( FrameRec, Vis ); WITH Vis DO IF NewColsScrolled # OldColsScrolled THEN (*We repaint the whole window if we're going to have to scroll horizontally.*) VWindows.ClearPart( FrameRec^.WindowHandle, col1, row1, col2, row2 ); FramePainter.RedrawArea( FrameRec, CARDINAL(col1), CARDINAL(row1), CARDINAL(col2), CARDINAL(row2) ); RETURN; END; ScrollableHeight := CARDINAL(row2) - CARDINAL(row1) + 1; IF ABS(vdist) > ScrollableHeight THEN IF vdist > 0 THEN vdist := ScrollableHeight; ELSE vdist := -ScrollableHeight; END; END; IF NOT VWindows.ScrollVertically(FrameRec^.WindowHandle, col1, row1, col2, row2, vdist ) THEN (*tough luck if the window manager doesn't support scrolling*) END; IF vdist > 0 THEN (*Redraw the area at the bottom because we scrolled up.*) FramePainter.RedrawArea( FrameRec, CARDINAL(col1), (CARDINAL(row2) - CARDINAL(ABS(vdist))) + 1, CARDINAL(col2), CARDINAL(row2) ); ELSE (*Redraw the area at the top because we scrolled down.*) FramePainter.RedrawArea( FrameRec, CARDINAL(col1), CARDINAL(row1),CARDINAL(col2),CARDINAL(row1+ABS(vdist)-1)); END (* if *); END (* with Vis *); END SlideFrame; PROCEDURE ControlFrame(VAR FrameRec : ScrnTypes.DisplayFrame; LandingField : CARDINAL; message : ARRAY OF CHAR; RedrawFirst : BOOLEAN; VAR NextFrame: ScrnTypes.AFrameName ); VAR MaxChoices, SavedFieldNum: CARDINAL; ReturnValue, FrameAbove, FrameBelow, FrameLeft, FrameRight : ScrnTypes.AFrameName; LastKey : CARDINAL; AbsFldCol, AbsFldRow: INTEGER; LocalMessage : ARRAY [0..79] OF CHAR; TmpScreenKeys: KbdInput.KeyNumSet; FieldRec: ScrnTypes.InputFieldRecord; PROCEDURE HitAnyKey( VAR NextFrame: ScrnTypes.AFrameName ); (* prompt for any key to be hit and exit, returning either normal next or TheKeyHandler result (keep asking for input if user asks for help or time) *) VAR key : CARDINAL; tryagain : BOOLEAN; BEGIN IF UserOps.DoPrompting THEN ShowPrompt( FrameRec, 'Press Any Key To Continue.' ); END; REPEAT key := KbdInput.KeyHit( KbdInput.AnyKeyNum ); IF BigSets.InSet( UserOps.FunctKeySet, key ) THEN (* if in special key set, execute user program *) SavedFieldNum := FrameRec^.CurrentField; UserOps.TheKeyHandler( FrameRec, key, NextFrame ); ScrnUtl1.SetCurrentField( FrameRec, SavedFieldNum ); tryagain := PosUtils.Equal( NextFrame, ScrnTypes.ContinueInput ); ELSE (* they hit a key not in the special key set, so return *) M2Strings.Assign( FrameRec^.normlnext, NextFrame ); tryagain := FALSE; END; UNTIL NOT tryagain; END HitAnyKey; PROCEDURE ShowBadType( FrameRec: ScrnTypes.DisplayFrame ); VAR ImageRec: ScrnTypes.ImageElement; dumstr: ARRAY [0..79] OF CHAR; BEGIN ScrnUtl1.GetFieldImageRec( FrameRec, FrameRec^.CurrentField, ImageRec ); M2Strings.Concat("Bad type in ControlFrame. Text = ", ImageRec.text, dumstr ); ErrorManager.WARN( dumstr ); END ShowBadType; PROCEDURE NormalKeyResponse( VAR FrameRec: ScrnTypes.DisplayFrame; VAR TheFieldRec: ScrnTypes.InputFieldRecord; VAR LastKey: CARDINAL; VAR ReturnValue: ScrnTypes.AFrameName ); VAR NewField: CARDINAL; BEGIN NewField := FrameRec^.CurrentField; (*Just in case we don't need to move it.*) IF LastKey = Key.Down THEN IF InVerticalGroup( FrameRec, FrameRec^.CurrentField ) THEN NewField := NextSelection( FrameRec, FrameRec^.CurrentField ); ELSIF NOT ScrnUtl1.InputFieldsBelow( FrameRec, FrameRec^.CurrentField ) THEN IF FrameBelow[0] # 0C THEN M2Strings.Assign( FrameBelow, ReturnValue ); ELSE NewField := FirstInputField(FrameRec); END; ELSE NewField := ClosestField( FrameRec, FrameRec^.CurrentField, 0, 0, VWindows.South ); END; MovePointerBar( FrameRec, NewField ); ELSIF LastKey = Key.Up THEN IF InVerticalGroup( FrameRec, FrameRec^.CurrentField ) THEN NewField := PrevSelection( FrameRec, FrameRec^.CurrentField ); ELSIF NOT ScrnUtl1.InputFieldsAbove( FrameRec, FrameRec^.CurrentField ) THEN IF FrameAbove[0] # 0C THEN M2Strings.Assign( FrameAbove, ReturnValue ); ELSE NewField := LastInputField( FrameRec ); END; ELSE NewField := ClosestField( FrameRec, FrameRec^.CurrentField, 0, 0, VWindows.North ); END; MovePointerBar( FrameRec, NewField ); (* RST Change *) ELSIF LastKey = Key.CtrlPgUp THEN MovePointerBar( FrameRec, FirstInputField(FrameRec)); ELSIF LastKey = Key.CtrlPgDn THEN MovePointerBar( FrameRec, LastInputField(FrameRec)); ELSIF LastKey = Key.PgUp THEN PageUp(FrameRec); ELSIF LastKey = Key.PgDn THEN PageDown(FrameRec); ELSIF LastKey = Key.Right THEN IF InHorizGroup( FrameRec, FrameRec^.CurrentField ) THEN NewField := NextSelection( FrameRec, FrameRec^.CurrentField ); ELSIF (NOT ScrnUtl1.InputFieldsToRight( FrameRec, FrameRec^.CurrentField )) AND (FrameRight[0] # 0C) THEN M2Strings.Assign( FrameRight, ReturnValue ); ELSE NewField := NextInputField( FrameRec, 0 ); END; MovePointerBar( FrameRec, NewField ); ELSIF LastKey = Key.Left THEN IF InHorizGroup( FrameRec, FrameRec^.CurrentField ) THEN NewField := PrevSelection( FrameRec, FrameRec^.CurrentField ); ELSIF (NOT ScrnUtl1.InputFieldsToLeft( FrameRec, FrameRec^.CurrentField )) AND (FrameLeft[0] # 0C) THEN M2Strings.Assign( FrameLeft, ReturnValue ); ELSE NewField := PrevInputField( FrameRec, 0 ); END; MovePointerBar( FrameRec, NewField ); ELSIF LastKey = Key.Tab THEN MovePointerBar( FrameRec, NextInputField( FrameRec, 0 )); ELSIF LastKey = Key.BackTab THEN MovePointerBar( FrameRec, PrevInputField( FrameRec, 0 )); ELSIF LastKey = Key.Return THEN IF TheFieldRec.typ = ScrnTypes.GotoCode THEN (* force jump *) M2Strings.Assign( TheFieldRec.ReturnVal, ReturnValue ); ELSIF (TheFieldRec.typ = ScrnTypes.GroupMember) THEN IF (MaxChoices = 1) THEN (* There are no other fields in the frame except this group. We know we have to leave, but first we have to choose a return value (for compatibility with 1.4.) *) IF M2Strings.Length(TheFieldRec.fnam) > 0 THEN (*This lets you store the return value in the field name of the choice. *) M2Strings.Assign( TheFieldRec.fnam, ReturnValue ); ELSE M2Strings.Assign( FrameRec^.normlnext, ReturnValue ); END; ELSE (* There are fields outside this group. Move to the first one following it.*) NewField := NextInputField( FrameRec, (TheFieldRec.GroupSize - TheFieldRec.GroupID) ); MovePointerBar( FrameRec, NewField ); END; ELSIF MaxChoices#1 THEN MovePointerBar( FrameRec, NextInputField( FrameRec, 0 ) ); ELSE M2Strings.Assign( FrameRec^.normlnext, ReturnValue); (* only one field, and it's an input field; leave.*) END; ELSIF SelectionKeyMatch( FrameRec, LastKey, NewField ) THEN MovePointerBar( FrameRec, NewField ); ScrnUtl1.GetFieldRec( FrameRec, NewField, TheFieldRec ); IF (ScrnUtl1.AllFieldsThisType(FrameRec, ScrnTypes.GotoCode)) THEN (* If the user presses the selection character of a menu item and the frame contains a mixture of field types, we move the pointer bar to the goto field, but we don't submit the frame, as we do if the frame contains only goto fields. If you want to submit the frame in that case, change this IF to something like 'IF TheFieldRec.typ = ScrnTypes.GotoCode' *) M2Strings.Assign( TheFieldRec.ReturnVal, ReturnValue ); END; IF (ScrnUtl1.AllFieldsThisType(FrameRec, ScrnTypes.GroupMember)) THEN M2Strings.Assign( TheFieldRec.fnam, ReturnValue ); END; END; END NormalKeyResponse; PROCEDURE NoFieldsKeyResponse( VAR FrameRec: ScrnTypes.DisplayFrame; VAR LastKey: CARDINAL; VAR ReturnValue: ScrnTypes.AFrameName ); VAR VisibleArea: Rectangles.ARectangle; nOutside, oldcs, oldrs, WindowHeight: CARDINAL; BEGIN ScrnUtl1.GetVisibleArea( FrameRec, VisibleArea ); WindowHeight := VisibleArea.row2 - VisibleArea.row1 + 1; oldcs := FrameRec^.ColsScrolled; oldrs := FrameRec^.RowsScrolled; StrEdit.AssignStr( ScrnTypes.ContinueInput, ReturnValue ); IF LastKey = Key.Down THEN IF ScrnUtl1.PartOutside( FrameRec, VisibleArea, VWindows.South ) > 0 THEN INC( FrameRec^.RowsScrolled ); END; ELSIF LastKey = Key.Up THEN IF ScrnUtl1.PartOutside( FrameRec, VisibleArea, VWindows.North ) > 0 THEN DEC( FrameRec^.RowsScrolled ); END; ELSIF LastKey = Key.PgUp THEN IF ScrnUtl1.PartOutside( FrameRec, VisibleArea, VWindows.North ) > WindowHeight THEN DEC( FrameRec^.RowsScrolled, WindowHeight ); ELSE FrameRec^.RowsScrolled := 0; END; ELSIF LastKey = Key.PgDn THEN IF ScrnUtl1.PartOutside( FrameRec, VisibleArea, VWindows.South ) > WindowHeight THEN INC( FrameRec^.RowsScrolled, WindowHeight ); ELSIF FrameRec^.VirtualHeight > WindowHeight THEN FrameRec^.RowsScrolled := FrameRec^.VirtualHeight - WindowHeight; ELSE FrameRec^.RowsScrolled := 0; END; ELSIF LastKey = Key.Right THEN IF ScrnUtl1.PartOutside( FrameRec, VisibleArea, VWindows.East ) > 0 THEN INC( FrameRec^.ColsScrolled ); END; ELSIF LastKey = Key.Left THEN IF ScrnUtl1.PartOutside( FrameRec, VisibleArea, VWindows.West ) > 0 THEN DEC( FrameRec^.ColsScrolled ); END; ELSIF LastKey = Key.Tab THEN nOutside := ScrnUtl1.PartOutside( FrameRec, VisibleArea, VWindows.East); IF nOutside > 8 THEN INC( FrameRec^.ColsScrolled, 8 ); ELSIF nOutside > 0 THEN INC( FrameRec^.ColsScrolled, nOutside); END; ELSIF LastKey = Key.BackTab THEN nOutside := ScrnUtl1.PartOutside( FrameRec, VisibleArea,VWindows.West); IF nOutside > 8 THEN DEC( FrameRec^.ColsScrolled, 8 ); ELSIF nOutside > 0 THEN DEC( FrameRec^.ColsScrolled, nOutside); END; ELSIF LastKey = Key.Return THEN M2Strings.Assign( FrameRec^.normlnext, ReturnValue); RETURN; END; SlideFrame( FrameRec, oldcs, FrameRec^.ColsScrolled, oldrs, FrameRec^.RowsScrolled ); END NoFieldsKeyResponse; PROCEDURE RepaintVisibleArea(); VAR FirstVisibleRow, FirstVisibleCol, LastVisibleRow, LastVisibleCol : CARDINAL; Vis : Rectangles.ARectangle; BEGIN ScrnUtl1.GetVisibleArea(FrameRec, Vis); WITH Vis DO FirstVisibleRow := CARDINAL(row1); LastVisibleRow := CARDINAL(row2); FirstVisibleCol := CARDINAL(col1); LastVisibleCol := CARDINAL(col2); (* 11 Oct 88: removed +RowsScrolled from each of these lines at suggestion of Karta Khalsa and Ulrik Schmidt. *) END; FramePainter.RedrawArea( FrameRec, FirstVisibleCol, FirstVisibleRow, LastVisibleCol, LastVisibleRow); END RepaintVisibleArea; BEGIN (*ControlFrame*) VWindows.SetCursorHeight( FrameRec^.WindowHandle, 0 ); M2Strings.Assign(message, LocalMessage); IF RedrawFirst THEN RepaintVisibleArea(); END; MaxChoices := ScrnUtl1.FieldGroupTotal( FrameRec ); (* Number of choices or fields in the frame, counting each group of choice fields as a single choice. *) M2Strings.Assign( FrameRec^.normlnext, NextFrame ); MakeLegalKeys( FrameRec, TmpScreenKeys ); StrEdit.LowerStr( FrameRec^.action ); (* Added 13 Nov 88. We lowercase the action char while the frame is active and restore it to uppercase when it is not so that we have a temporary way of determining whether the frame is active. Don't rely on this. In a future release we will add a boolean to the DisplayFrame record and quit using this kludge. *) IF CAP(FrameRec^.action) = ScrnTypes.DispCode THEN (* Do not process user input. Note that we don't call EraseFrame if the frame is both DisplayOnly and ClearAfter, since this combination really doesn't make sense -- latter is probably programmer's mistake. *) RETURN; END; IF FrameRec^.EntryBox[0] # 0C THEN (*Now we change the appearance of the border to let the user know the frame is active.*) ScrnUtl1.BoxFrame( FrameRec, TRUE ); END; IF (CAP(FrameRec^.action) = 'W') THEN (* wait for any user input, then exit *) HitAnyKey( NextFrame ); IF FrameRec^.ExitBox[0] # 0C THEN (*Now we change the appearance of the border to let the user know the frame is no longer active.*) ScrnUtl1.BoxFrame( FrameRec, FALSE ); END; IF FrameRec^.ClearAfter THEN FrameManager.EraseFrame( FrameRec ); END; RETURN; END; HiLiteSelChars( FrameRec ); StrEdit.SetLength( ReturnValue, 0 ); ScrnUtl1.GetFrameLinks( FrameRec, FrameAbove, FrameBelow, FrameLeft, FrameRight ); FrameRec^.CurrentField := 0; (*Prevent MovePointerBar from exiting if CurrentField happens to equal LandingField.*) IF (LandingField=0) AND (MaxChoices > 0) THEN MovePointerBar( FrameRec, FirstInputField(FrameRec)); (*highlights first choice*) END; REPEAT IF (LandingField # 0) AND (MaxChoices > 0) THEN (* LandingField is not 0, so highlight the specified field. We do this at the top of each loop so that ControlFrame can signal errors from within the loop. *) MovePointerBar( FrameRec, LandingField ); LandingField := 0; END; IF M2Strings.Length( LocalMessage ) > 0 THEN MsgBox2.StrMsgBox( FrameRec, VWindows.SE, LocalMessage ); StrEdit.SetLength( LocalMessage, 0 ); END; IF (MaxChoices = 0) OR (ScrnUtl1.AllFieldsThisType(FrameRec, ScrnTypes.DispCode)) THEN LastKey := KbdInput.KeyHit( TmpScreenKeys ); UserOps.TheKeyHandler( FrameRec, LastKey, ReturnValue ); IF PosUtils.Equal( ReturnValue, ScrnTypes.ContinueInput ) THEN NoFieldsKeyResponse( FrameRec, LastKey, ReturnValue ); END; ELSE ScrnUtl1.GetFieldRec( FrameRec, FrameRec^.CurrentField, FieldRec ); SavedFieldNum := FrameRec^.CurrentField; CASE FieldRec.typ OF ScrnTypes.GotoCode, ScrnTypes.GroupMember : LastKey := KbdInput.KeyHit( TmpScreenKeys ); UserOps.TheKeyHandler( FrameRec, LastKey, ReturnValue ); ELSE AbsFldRow := ScrnUtl1.AbsFieldRow(FrameRec, FrameRec^.CurrentField); AbsFldCol := ScrnUtl1.AbsFieldCol(FrameRec, FrameRec^.CurrentField); UserOps.TheFieldHandler( FrameRec, AbsFldCol, AbsFldRow, LastKey, ReturnValue ); ScrnUtl1.GetFieldRec( FrameRec, FrameRec^.CurrentField, FieldRec ); IF FieldRec.ChangeMade THEN FrameRec^.FrameChanged := TRUE; END; END; IF PosUtils.Equal( 'MovePointerBar', ReturnValue ) THEN StrEdit.AssignStr( ScrnTypes.ContinueInput, ReturnValue ); MovePointerBar( FrameRec, FrameRec^.CurrentField ); ELSE ScrnUtl1.SetCurrentField( FrameRec, SavedFieldNum ); IF PosUtils.Equal( ReturnValue, ScrnTypes.ContinueInput ) THEN (* Now, process defined action keys *) NormalKeyResponse( FrameRec, FieldRec, LastKey, ReturnValue ); END; END; IF (NOT PosUtils.Equal(ReturnValue, ScrnTypes.ContinueInput)) AND (LastKey # UserOps.BackupKey) AND (LastKey # UserOps.ExitKey) THEN (* Looks like they want to submit the screen. Let's check to see if all required fields are full *) IF PosUtils.Equal( ReturnValue, ScrnTypes.SubmitInput ) THEN ReturnValue := FrameRec^.normlnext; END; IF PosUtils.Equal( ReturnValue, ScrnTypes.CancelInput ) THEN ReturnValue := FrameRec^.parent; ELSIF (NOT RequiredFilled( FrameRec, LandingField )) THEN StrEdit.AssignStr( RequiredMessage, LocalMessage ); LastKey := 65535; StrEdit.AssignStr( ScrnTypes.ContinueInput, ReturnValue ); (*We do this to make sure we go back through the loop.*) END; END; END; UNTIL (NOT PosUtils.Equal(ReturnValue, ScrnTypes.ContinueInput)); M2Strings.Assign( ReturnValue, NextFrame ); (* IF MaxChoices > 0 THEN FramePainter.RedrawField( FrameRec, FrameRec^.CurrentField, FALSE ); END; Taken care of by RepaintVisibleArea, below. *) FrameRec^.action := CAP( FrameRec^.action ); IF FrameRec^.ExitBox[0] # 0C THEN (*Now we change the appearance of the border to let the user know the frame is no longer active.*) ScrnUtl1.BoxFrame( FrameRec, FALSE ); END; IF FrameRec^.ClearAfter THEN FrameManager.EraseFrame( FrameRec ); ELSE RepaintVisibleArea(); (* Erases pointer bar and selection characters. We do this mostly to avoid the problem of restoring things like highlighted selection characters when things pop up over inactive frames. *) END; END ControlFrame; BEGIN Initialized := FALSE; Init(); END InputManager.