{ FIELDS.PAS: Fields Routines }

{==========================================================================}
{ (c) Copyright Waterline Software Developent V.O.F. 1990-1994             }
{                                                                          }
{    Waterline Software Development V.O.F.                                 }
{    Wouter Sluislaan 12                                                   }
{    1461 AC  Zuidoostbeemster                                             }
{    The Netherlands                                                       }
{                                                                          }
{ It not allowed to use this user interface in any program not owned by    }
{ the Waterline Software Development V.O.F.                                }
{ Special conditions apply to programs distributed by the Waterline        }
{ Software Development V.O.F. If the source code of any of these programs  }
{ is distributed as well, it is NOT allowed to use the user interface in   }
{ your own programs. Violators may be prosecuted!                          }
{                                                                          }
{ Please contact the Waterline Software Development V.O.F. at the above    }
{ address for your licence to use the "Ramon" user interface. You will get }
{ the most recent copy of the "Ramon" user interface and the "Ramon" user  }
{ interface expert for free. This program helps you design your user       }
{ interfaces at an instance.                                               }
{                                                                          }
{ This copyright notice should remain in this file and all files that are  }
{ part of the user interface "Ramon".                                      }
{==========================================================================}

{ History:

17-10-93 FieldSetHelp toegevoegd om per veld een help toe te kunnen kennen.

         FieldSelectKeysLine en FieldEditKeysLine voor de toetsen die tijdens
         de veld-select en edit fases in beeld komen. Deze kunnen eenvoudig
         vervangen worden (ivm een andere taal etc).

22-08-94 FieldDefineToggles en FieldDefineTogglesCall toegevoegd.

961213   Added new keys for toggles fields.
         Now allowing empty option in toggles fields ("opt1||opt3").
}


CONST FLAGS_NONE     = $00;
      FLAGS_USED     = $01;
      FLAGS_DISABLED = $02;
      FLAGS_PASSWORD = $04;
      FLAGS_ALL      = $FF;     { for disabling: all-specific }

TYPE FieldType = RECORD
                       Flags       : BYTE;
                       StartX,
                       StartY,                         { start coordinaten }
                       Offset,
                       ScreenMax,       { max. aantal tekens op het scherm }
                       Len         : XYType;            { schermdeel lengte }
                       PrevLink,                              { vorige veld }
                       SuccLink    : FieldNrType;           { volgende veld }
                       BufferPtr   : StringPtr;            { opslag pointer }
                       Allowed     : STRING;                { invoer opties }
                       ListProc    : ProcedureType;      { voor List fields }
                       CheckFunc   : FieldCheckFunc;    { voor Check fields }
                       HelpHandle  : HelpHandleType;
                       TogglePtr   : ^BYTE;
                       Toggle1St   : BYTE;            { value of first item }
                       FileMgr     : FileMgrProc;
                       EditProc    : FieldEditProc;
                 END;

     FieldsArrayType = ARRAY[1..MaxFields] OF FieldType;

     FieldStackRecordPtr = ^FieldStackRecord;

     FieldStackRecord = RECORD
                              PrevPtr : FieldStackRecordPtr;
                              FArray  : FieldsArrayType;
                              LastNr  : FieldNrType;
                        END;

VAR Fields      : FieldsArrayType;
    FieldStkPtr : FieldStackRecordPtr;
    NewFieldNr  : FieldNrType;

{--------------------------------------------------------------------------}
{ FieldInit                                                                }
{                                                                          }
{ Deze routine moet aangeroepen voordat een van de andere routines aange-  }
{ roepen mag worden. Hier worden alle Field definities gewist en met een   }
{ schone lei gestart.                                                      }
{                                                                          }
PROCEDURE FieldInit;

VAR Lp : BYTE;

BEGIN
     LastFieldNr:=1;
     NewFieldNr:=0;

     FOR Lp:=1 TO MaxFields DO
         WITH Fields[Lp] DO
         BEGIN
              Flags:=FLAGS_NONE;
              StartX:=0;
              StartY:=0;
              Offset:=0;
              ScreenMax:=0;
              Len:=0;
              PrevLink:=0;
              SuccLink:=0;
              BufferPtr:=NIL;
              Allowed:='';
              ListProc:=NIL;
              CheckFunc:=NIL;
              HelpHandle:=0;
              TogglePtr:=NIL;
              Toggle1St:=0;
              FileMgr:=NIL;
              EditProc:=NIL;
         END; { with, for }
END;


{--------------------------------------------------------------------------}
{ GetNewFieldNr                                                            }
{                                                                          }
{ Deze routine bepaald het nieuwe veld nummer. NewFieldNr wordt simpel met }
{ een verhoogd. Als er een vorig veld was, dan wordt dat veld gechained    }
{ aan dit nieuwe veld.                                                     }
{                                                                          }
PROCEDURE GetNewFieldNr;
BEGIN
     Inc (NewFieldNr);

     IF (NewFieldNr > 1) THEN
        Fields[NewFieldNr-1].SuccLink:=NewFieldNr;

     Fields[1].PrevLink:=NewFieldNr;
END;


{--------------------------------------------------------------------------}
{ FieldDefineOne                                                           }
{                                                                          }
{ Met deze routine kan een veld op het scherm gedefinieerd worden.         }
{                                                                          }
PROCEDURE FieldDefineOne (Nr : FieldNrType; X,Y,LX : XYType; U,D : FieldNrType; Buffer : StringPtr; Template : STRING);
BEGIN
     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=LX;
          Offset:=1;
          Len:=LX;
          PrevLink:=U;
          SuccLink:=D;
          BufferPtr:=Buffer;
          Allowed:=Template;

          IF (Length (BufferPtr^) <> Len) THEN
             Error ('Error (FieldDefineOne): String has incorrect length in field '+Byte2String (Nr));
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldDefineLongOne                                                       }
{                                                                          }
{ Zelfde als de vorige routine, alleen moetnu in SX ook opgegeven worden   }
{ hoeveel tekens er op het scherm maximaal mogen staan.                    }
{                                                                          }
PROCEDURE FieldDefineLongOne (Nr : FieldNrType; X,Y,LX,SX : XYType; U,D : FieldNrType; Buffer : StringPtr; Template : STRING);
BEGIN
     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=SX;
          Len:=LX;
          PrevLink:=U;
          SuccLink:=D;
          BufferPtr:=Buffer;
          Allowed:=Template;

          IF (Length (BufferPtr^) <> Len) THEN
             Error ('Error (FieldDefineLongOne): String has incorrect length in field '+Byte2String (Nr));
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldDefineList                                                          }
{                                                                          }
{ Met deze routine kan een veld gedefinieerd worden waarbij een custom     }
{ edit routine opgegeven kan worden. Daar wordt dan naartoe gesprongen als }
{ op dit veld op Enter wordt gedrukt om te editten.                        }
{                                                                          }
PROCEDURE FieldDefineList (Nr : FieldNrType; X,Y,LX : XYType; U,D : FieldNrType; Buffer : StringPtr; ProcAd : ProcedureType);
BEGIN
     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=0; { ScreenMax = 0 -> List Field; BufferPtr = Message }
          Len:=LX;
          PrevLink:=U;
          SuccLink:=D;
          BufferPtr:=Buffer;
          ListProc:=ProcAd;

          IF (Length (BufferPtr^) <> Len) THEN
             Error ('Error (FieldDefineList): String has incorrect length in field '+Byte2String (Nr));
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldDefineEdit                                                          }
{                                                                          }
{ Met deze routine kan een veld gedefinieerd worden waarbij een custom     }
{ edit routine opgegeven kan worden. Daar wordt dan naartoe gesprongen als }
{ op dit veld op Enter wordt gedrukt om te editten.                        }
{                                                                          }
PROCEDURE FieldDefineEdit (Nr : FieldNrType; X,Y,LX : XYType; U,D : FieldNrType; Buffer : StringPtr; ProcAd : FieldEditProc);
BEGIN
     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=0; { ScreenMax = 0 -> List Field; BufferPtr = Message }
          Len:=LX;
          PrevLink:=U;
          SuccLink:=D;
          BufferPtr:=Buffer;
          EditProc:=ProcAd;

          IF (Length (BufferPtr^) <> Len) THEN
             Error ('Error (FieldDefineList): String has incorrect length in field '+Byte2String (Nr));
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldDefineCheckOne                                                      }
{                                                                          }
{ Met deze routine kan een gewoon veld gedefinieerd worden, met de optie   }
{ om de ingevoerde inhoud te checken. Als deze routine meld dat wat        }
{ ingevoerd is niet aan de eisen voldoet (de functie geeft FALSE terug),   }
{ dan wordt de oude inhoud hersteld. Anders kan de check routine de invoer }
{ formatteren, bijvoorbeeld bij getallen.                                  }
{                                                                          }
PROCEDURE FieldDefineCheckOne (Nr : FieldNrType; X,Y,LX : XYType; U,D : FieldNrType; Buffer : StringPtr; Template : STRING;
                               FuncAd : FieldCheckFunc);
BEGIN
     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=LX;
          Offset:=1;
          Len:=LX;
          PrevLink:=U;
          SuccLink:=D;
          BufferPtr:=Buffer;
          Allowed:=Template;
          CheckFunc:=FuncAd;

          IF (Length (BufferPtr^) <> Len) THEN
             Error ('Error (FieldDefineCheckOne): String has incorrect length in field '+Byte2String (Nr));
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldDefineCheckLongOne                                                  }
{                                                                          }
{ Zelfde als de vorige routine, alleen moetnu in SX ook opgegeven worden   }
{ hoeveel tekens er op het scherm maximaal mogen staan.                    }
{                                                                          }
PROCEDURE FieldDefineCheckLongOne (Nr : FieldNrType; X,Y,LX,SX : XYType; U,D : FieldNrType; Buffer : StringPtr;
                                   Template : STRING; FuncAd : FieldCheckFunc);
BEGIN
     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=SX;
          Len:=LX;
          PrevLink:=U;
          SuccLink:=D;
          BufferPtr:=Buffer;
          Allowed:=Template;
          CheckFunc:=FuncAd;

          IF (Length (BufferPtr^) <> Len) THEN
             Error ('Error (FieldDefineLongOne): String has incorrect length in field '+Byte2String (Nr));
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldDefineToggles                                                       }
{                                                                          }
{ Met deze routine kan een toggles field gedefinieerd worden. De VAR geeft }
{ de huidige keuze aan (0..n) en kan worden gewijzigd.                     }
{                                                                          }
PROCEDURE FieldDefineToggles (Nr : FieldNrType; X,Y : XYType; U,D : FieldNrType;
                              VAR Keuze; Opties : STRING; FirstValue : BYTE);

VAR Count : BYTE;
    Lp    : BYTE;

BEGIN
     Count:=0;
     FOR Lp:=1 TO Length (Opties) DO
         IF (Opties[Lp] = '|') THEN
            Inc (Count);

     IF (Byte (Keuze) > FirstValue+Count) OR (Byte (Keuze) < FirstValue) THEN
     BEGIN
          Error2Lines ('FieldDefineToggles current value ('+Byte2String (Byte (Keuze))+') is invalid for field '+
                       Byte2String (Nr)+'.',
                       'Selection has been reset to the first option ('+Byte2String (FirstValue)+').');
          Byte (Keuze):=FirstValue;
     END;

     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=1; { moet <> 0 }
          Offset:=1;    { cursorpos. Invul door FieldsUpdateOneField }
          Len:=Count;   { aantal toggle opties }
          PrevLink:=U;
          SuccLink:=D;
          Allowed:=Opties;
          TogglePtr:=@Keuze;
          Toggle1St:=FirstValue;
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldDefineTogglesCall                                                   }
{                                                                          }
{ Met deze routine kan een toggles field gedefinieerd worden. De VAR geeft }
{ de huidige keuze aan (0..n) en kan worden gewijzigd.                     }
{                                                                          }
PROCEDURE FieldDefineTogglesCall (Nr : FieldNrType; X,Y : XYType; U,D : FieldNrType; VAR Keuze; Opties : STRING;
                                  FirstValue : BYTE; ProcAd : ProcedureType);

VAR Count : BYTE;
    Lp    : BYTE;

BEGIN
     Count:=0;
     FOR Lp:=1 TO Length (Opties) DO
         IF (Opties[Lp] = '|') THEN
            Inc (Count);

     IF ((Byte (Keuze)-FirstValue) > Count) THEN
     BEGIN
          Error2Lines ('FieldDefineToggles current value ('+Byte2String (Byte (Keuze))+') is invalid for field '+
                       Byte2String (Nr)+'.',
                       'Selection has been reset to the first option ('+Byte2String (FirstValue)+').');
          Byte (Keuze):=FirstValue;
     END;

     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=1; { moet <> 0 }
          Offset:=1;    { cursorpos. Invul door FieldsUpdateOneField }
          Len:=Count;   { aantal toggle opties }
          PrevLink:=U;
          SuccLink:=D;
          Allowed:=Opties;
          ListProc:=ProcAd;
          TogglePtr:=@Keuze;
          Toggle1St:=FirstValue;
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldDefineFileMgr                                                       }
{                                                                          }
{ Als FieldDefineLongOne, maar je kan op F10 drukken om de file manager    }
{ functie aan te roepen. Die bepaald daarna of het een pad of een file     }
{ selectie is en roept de juiste file manager aan.                         }
{                                                                          }
PROCEDURE FieldDefineFileMgr (Nr : FieldNrType; X,Y,LX,SX : XYType; U,D : FieldNrType;
                              Buffer : StringPtr; ProcAd : FileMgrProc; AllowSearchChars : BOOLEAN);
BEGIN
     WITH Fields[Nr] DO
     BEGIN
          Flags:=Flags OR FLAGS_USED;
          StartX:=X;
          StartY:=Y;
          ScreenMax:=SX;
          Len:=LX;
          PrevLink:=U;
          SuccLink:=D;
          BufferPtr:=Buffer;
          IF AllowSearchChars THEN
             Allowed:=RepChar (Len,'*')
          ELSE
              Allowed:=RepChar (Len,'!');
          FileMgr:=ProcAd;

          IF (Length (BufferPtr^) <> Len) THEN
             Error ('Error (FieldDefineFileMgr): String has incorrect length in field '+Byte2String (Nr));
     END; { with }
END;


{--------------------------------------------------------------------------}
{ FieldAutoDefineXXX                                                       }
{                                                                          }
{ Deze auto routines bepalen zelf het veld nummer dat het veld krijgt en   }
{ koppelen ook automatisch alle velden aan elkaar. Hierdoor zijn flink wat }
{ minder argumenten nodig en wordt het voor de programmeur makkelijker     }
{ even een veld tussen te voegen EN de source wordt leesbaarder (meestal). }
{                                                                          }
PROCEDURE FieldAutoDefineOne (X,Y : XYType; Buffer : StringPtr; Template : STRING);
BEGIN
     GetNewFieldNr; { linkt ook automatisch de vorige door }
     FieldDefineOne (NewFieldNr,X,Y,Length (Template),NewFieldNr-1,1,Buffer,Template);
END;

PROCEDURE FieldAutoDefineLongOne (X,Y,SX{on screen} : XYType; Buffer : StringPtr; Template : STRING);
BEGIN
     GetNewFieldNr;
     FieldDefineLongOne (NewFieldNr,X,Y,Length (Template),SX,NewFieldNr-1,1,Buffer,Template);
END;

PROCEDURE FieldAutoDefineEdit (X,Y : XYType; Buffer : StringPtr; ProcAd : FieldEditProc);
BEGIN
     GetNewFieldNr;
     FieldDefineEdit (NewFieldNr,X,Y,Length (Buffer^),NewFieldNr-1,1,Buffer,ProcAd);
END;

PROCEDURE FieldAutoDefineList (X,Y : XYType; Buffer : StringPtr; ProcAd : ProcedureType);
BEGIN
     GetNewFieldNr;
     FieldDefineList (NewFieldNr,X,Y,Length (Buffer^),NewFieldNr-1,1,Buffer,ProcAd);
END;

PROCEDURE FieldAutoDefineCheckOne (X,Y : XYType; Buffer : StringPtr; Template : STRING; FuncAd : FieldCheckFunc);
BEGIN
     GetNewFieldNr;
     FieldDefineCheckOne (NewFieldNr,X,Y,Length (Template),NewFieldNr-1,1,Buffer,Template,FuncAd);
END;

PROCEDURE FieldAutoDefineCheckLongOne (X,Y,SX{on screen} : XYType; Buffer : StringPtr; Template : STRING;
                                       FuncAd : FieldCheckFunc);
BEGIN
     GetNewFieldNr;
     FieldDefineCheckLongOne (NewFieldNr,X,Y,Length (Template),SX,NewFieldNr-1,1,Buffer,Template,FuncAd);
END;

PROCEDURE FieldAutoDefineToggles (X,Y : XYType; VAR Keuze; Opties : STRING; FirstValue : BYTE);
BEGIN
     GetNewFieldNr;
     FieldDefineToggles (NewFieldNr,X,Y,NewFieldNr-1,1,Keuze,Opties,FirstValue);
END;

PROCEDURE FieldAutoDefineTogglesCall (X,Y : XYType; VAR Keuze; Opties : STRING; FirstValue : BYTE; ProcAd : ProcedureType);
BEGIN
     GetNewFieldNr;
     FieldDefineTogglesCall (NewFieldNr,X,Y,NewFieldNr-1,1,Keuze,Opties,FirstValue,ProcAd);
END;

PROCEDURE FieldAutoDefineFileMgr (X,Y,SX : XYType; Buffer : StringPtr; ProcAd : FileMgrProc; AllowSearchChars : BOOLEAN);
BEGIN
     GetNewFieldNr;
     FieldDefineFileMgr (NewFieldNr,X,Y,Length (Buffer^),SX,NewFieldNr-1,1,Buffer,ProcAd,AllowSearchChars);
END;


{--------------------------------------------------------------------------}
{ FieldGetLastAutoFieldNr                                                  }
{                                                                          }
{ This routine returns the field number that was last used by the          }
{ FieldAutoDefine* routines.                                               }
{                                                                          }
FUNCTION FieldGetLastAutoFieldNr : FieldNrType;
BEGIN
     FieldGetLastAutoFieldNr:=NewFieldNr;
END;


{--------------------------------------------------------------------------}
{ FieldDisableField                                                        }
{                                                                          }
{ Met deze routine kan een veld 'Disabled' gezet worden. De routine tekent }
{ NIET het veld op het scherm opnieuw. Dit moet door de applicatie zelf    }
{ gedaan worden, omdat op het moment van toggelen een select lijst of menu }
{ nog over de schermen heen kan staan. Gebruik voor het updaten de routine }
{ FieldUpdateOneField.                                                     }
{                                                                          }
PROCEDURE FieldDisableField (FieldNr : FieldNrType);
BEGIN
     IF (FieldNr = 0) OR ((Fields[FieldNr].Flags AND FLAGS_USED) = 0) THEN
        FieldNr:=NewFieldNr;

     Fields[FieldNr].Flags:=Fields[FieldNr].Flags OR FLAGS_DISABLED;
END;


{--------------------------------------------------------------------------}
{ FieldEnableField                                                         }
{                                                                          }
{ Met deze routine herstelt een veld van de 'Disabled' status. Voor meer   }
{ info zie FieldDisabledField.                                             }
{                                                                          }
PROCEDURE FieldEnableField (FieldNr : FieldNrType);
BEGIN
     IF (FieldNr = 0) OR ((Fields[FieldNr].Flags AND FLAGS_USED) = 0) THEN
        FieldNr:=NewFieldNr;

     Fields[FieldNr].Flags:=Fields[FieldNr].Flags AND (FLAGS_ALL-FLAGS_DISABLED);
END;


{--------------------------------------------------------------------------}
{ FieldSetPassword                                                         }
{                                                                          }
{ This routine can be used to change a field definition into a password    }
{ field, meaning it only shows *** until Enter is pressed to edit the      }
{ field.                                                                   }
{                                                                          }
PROCEDURE FieldSetPassword (FieldNr : FieldNrType);
BEGIN
     IF (FieldNr = 0) OR ((Fields[FieldNr].Flags AND FLAGS_USED) = 0) THEN
        FieldNr:=NewFieldNr;

     Fields[FieldNr].Flags:=Fields[FieldNr].Flags OR FLAGS_PASSWORD;
END;


{--------------------------------------------------------------------------}
{ FieldSetFirst                                                            }
{                                                                          }
{ Deze routine stelt het veldnummer in waarop de cursor komt te staan bij  }
{ de eerste volgende FieldEdit aanroep. Na de aanroep van FieldInit staat  }
{ deze op 1. Na het verlaten van FieldEdit staat deze op het laatste veld  }
{ waar de cursor op stond.                                                 }
{                                                                          }
PROCEDURE FieldSetFirst (Nr : FieldNrType);
BEGIN
     IF (Nr = 0) THEN
        Nr:=NewFieldNr;

     LastFieldNr:=Nr;
END;


{--------------------------------------------------------------------------}
{ DrawOneField                                                             }
{                                                                          }
{ Deze routine tekent het opgegeven veld in de actieve kleur. Hierdoor is  }
{ het mogelijk andere veld types straks eenvoudig in te voegen.            }
{                                                                          }
PROCEDURE DrawOneField (FieldNr : FieldNrType; PasswordVisible : BOOLEAN);

VAR Part   : STRING[132];
    P      : BYTE;
    Toggle : BYTE;

BEGIN
     WITH Fields[FieldNr] DO
     BEGIN
          IF (TogglePtr <> NIL) THEN
          BEGIN
               Part:=Allowed;
               RGotoXY (StartX,StartY);
               Toggle:=TogglePtr^-Toggle1St;

               REPEAT
                     P:=Pos ('|',Part);
                     IF (P = 0) THEN
                     BEGIN
                          { laatste optie }
                          IF (Toggle = 0) THEN
                          BEGIN
                               { actieve optie }
                               Offset:=RWhereX-StartX;
                               RWrite (UpCaseString (Part))
                          END ELSE
                              RWrite (LoCaseString (Part));
                     END ELSE
                         IF (P = 1) THEN
                         BEGIN
                              { lege optie; sla deze over }
                              Dec (Toggle);
                              Delete (Part,1,1);
                         END ELSE
                         BEGIN
                              { komt nog een optie hierna }
                              IF (Toggle = 0) THEN
                              BEGIN
                                   { actieve optie }
                                   Offset:=RWhereX-StartX;
                                   RWrite (UpCaseString (Copy (Part,1,P-1)))
                              END ELSE
                                  RWrite (LoCaseString (Copy (Part,1,P-1)));

                              RWrite (' ');
                              Dec (Toggle);
                              Delete (Part,1,P);
                         END;
               UNTIL (P = 0);
          END ELSE
          BEGIN
               IF (ScreenMax = 0) OR (ScreenMax = Len) THEN
               BEGIN
                    IF (NOT PasswordVisible) AND ((Flags AND FLAGS_PASSWORD) <> 0) THEN
                       WriteXY (StartX,StartY,RepChar (Length (BufferPtr^),'*'))
                    ELSE
                        WriteXY (StartX,StartY,BufferPtr^);
               END ELSE
               BEGIN
                    Part:=Copy (BufferPtr^,Offset,ScreenMax);

                    { add the arrows }
                    IF (Offset > 1) THEN Part[1]:=#17;
                    IF (Offset < Len-ScreenMax+1) THEN Part[ScreenMax]:=#16;

                    WriteXY (StartX,StartY,Part);
               END;
          END;
     END;
END;


{--------------------------------------------------------------------------}
{ FieldUpdateOneField                                                      }
{                                                                          }
{ Deze routine kan eenvoudig van buitenaf aangeroepen in een Check routine }
{ om een veranderd veld af te drukken. Als dit via FieldUpdateScreen       }
{ gebeurd gaan er allerlei dingen fout met de kleur van het cursorveld en  }
{ worden de muis velden nog eens gedefinieerd. En de te updaten fields     }
{ zijn toch altijd andere velden dan het cursor veld.                      }
{                                                                          }
PROCEDURE FieldUpdateOneField (FieldNr : FieldNrType);

VAR OldColor    : ColorSet;

BEGIN
     IF (FieldNr = 0) OR ((Fields[FieldNr].Flags AND FLAGS_USED) = 0) THEN
        Exit;

     OldColor:=GetColor;
     IF ((Fields[FieldNr].Flags AND FLAGS_DISABLED) <> 0) THEN
        SetColor (cFieldDisabled)
     ELSE
         SetColor (cFieldData);

     DrawOneField (FieldNr,{PasswordVisible:}FALSE);

     SetColor (OldColor);
END;


{--------------------------------------------------------------------------}
{ FieldUpdateScreen                                                        }
{                                                                          }
{ Deze routine tekent de velden op het scherm. Alleen de gedefinieerde     }
{ velden komen op het scherm. Ze komen allemaal in de cFieldData kleuren   }
{ te staan.                                                                }
{                                                                          }
PROCEDURE FieldUpdateScreen;

VAR Lp : BYTE;

BEGIN
     FOR Lp:=1 TO MaxFields DO
         IF ((Fields[Lp].Flags AND FLAGS_USED) <> 0) THEN
         BEGIN
              IF ((Fields[Lp].Flags AND FLAGS_DISABLED) <> 0) THEN
                 SetColor (cFieldDisabled)
              ELSE
                  SetColor (cFieldData);

              DrawOneField (Lp,{PasswordVisible:}FALSE);
         END;
END;


{--------------------------------------------------------------------------}
{ FieldEditContents                                                        }
{                                                                          }
{ Met deze routine wordt de inhoud van het opgegeven veld aangepast.       }
{                                                                          }
{ StuffKey definitie:                                                      }
{ ' '..'~'        : Invoer van die AsciiKey                                }
{ kleiner dan ' ' : KeyType (AsciiKey) (kRet etc.)                         }
{ groter dan #200 : AsciiKey-#200 (CtrlY etc.)                             }
{                                                                          }
PROCEDURE FieldEditContents (FieldNr : FieldNrType; StuffKey : CHAR; SpecialKeys : KeysSet);

VAR X : WORD;

    PROCEDURE MoveCursorToEnd;
    BEGIN
         WITH Fields[FieldNr] DO
         BEGIN
              { start at end }
              X:=StartX+Len-1;

              { while not on a space, keep moving left }
              WHILE (X > StartX) AND (BufferPtr^[X-StartX+1] = ' ') DO
                    Dec (X);

              { if not at start and not on space, then one to right }
              IF (BufferPtr^[X-StartX+1] <> ' ') AND (X <> StartX+Len-1) THEN
                 Inc (X);
         END; { with }
    END;

CONST AllowChars = ['@','#','%','$','<','>','!','*'];

VAR Quit    : BOOLEAN;
    PrevX,
    SaveX   : WORD;
    OldData : STRING;
    Lp,
    SameCnt,
    SM2,
    StrOfs  : BYTE;

BEGIN
     WITH Fields[FieldNr] DO
     BEGIN
          IF (TogglePtr <> NIL) THEN
             Exit;

          IF (ScreenMax = 0) THEN
          BEGIN
               { cursor verwijderen }
               SetColor (cBoxBack);
               DrawOneField (LastFieldNr,{PasswordVisible:}TRUE);

               IF (@ListProc <> NIL) THEN
                  ListProc;

               IF (@EditProc <> NIL) THEN
                  EditProc (BufferPtr);

               { cursor terug }
               SetColor (cFieldCursor);
               DrawOneField (LastFieldNr,{PasswordVisible:}FALSE);
               Exit;
          END;

          PushKeysLine;
          WriteKeysLine (FieldEditKeysLine);

          OldData:=BufferPtr^;

          IF (StuffKey IN [' '..'~',#128..#254]) THEN
          BEGIN
               FOR Lp:=1 TO Length (OldData) DO
                   IF (Allowed[Lp] IN AllowChars) THEN
                      BufferPtr^[Lp]:=' ';
               SetColor (cFieldCursor);
               DrawOneField (FieldNr,{PasswordVisible:}TRUE);
          END ELSE
              IF ((Flags AND FLAGS_PASSWORD) <> 0) THEN
              BEGIN
                   SetColor (cFieldCursor);
                   DrawOneField (FieldNr,{PasswordVisible:}TRUE);
              END;

          {RAWI 980106: now putting cursor at end of text
          X:=StartX;
          }
          MoveCursorToEnd;
          PrevX:=0;
          CursorOn;

          Quit:=FALSE;
          REPEAT
                { cursor positioneren }
                IF (PrevX <> X) THEN
                BEGIN
                     IF (ScreenMax <> Len) THEN
                     BEGIN
                          SM2:=ScreenMax DIV 2;

                          IF (X-StartX < SM2) THEN
                          BEGIN
                               { vooraan }
                               Offset:=1;
                               CursorGotoXY (X,StartY);
                          END ELSE
                              IF (X-StartX > Len-SM2) THEN
                              BEGIN
                                   { achteraan }
                                   Offset:=Len-ScreenMax+1;
                                   CursorGotoXY (X-Len+ScreenMax,StartY);
                              END ELSE
                              BEGIN
                                   { midden }
                                   Offset:=(X-StartX)-SM2+1;
                                   CursorGotoXY (X-(X-StartX-SM2),StartY);
                              END;

                          SetColor (cFieldCursor);
                          DrawOneField (FieldNr,{PasswordVisible:}TRUE);
                     END ELSE
                         CursorGotoXY (X,StartY);

                     PrevX:=X;
                END;

                { op invoer wachten }
                IF (StuffKey <> #0) THEN
                BEGIN
                     IF (StuffKey < ' ') THEN
                     BEGIN
                          {$IFDEF FPC}
                          Key:=KeyType (BYTE (StuffKey));
                          {$ELSE}
                          Key:=KeyType (StuffKey);
                          {$ENDIF}

                          AsciiKey:=#0;
                     END ELSE
                         IF (StuffKey > #200) THEN
                         BEGIN
                              Key:=kUnknown;
                              AsciiKey:=Chr (Ord (StuffKey)-200);
                         END ELSE
                         BEGIN
                              Key:=kUnknown;
                              AsciiKey:=StuffKey;
                         END;

                     StuffKey:=#0;
                END ELSE
                    Key:=ReadKey;

                StrOfs:=X-StartX+1;
                { tekst invoer }
                IF ((Key = kUnknown) AND
{ strings }         (((Allowed[StrOfs] IN ['$','@']) AND (AsciiKey IN [' '..'~',#128..#254])) OR
{ numbers }          ((Allowed[StrOfs] IN ['#','%']) AND (AsciiKey IN ['0'..'9',' ','-'])) OR
{ dec. numbers }     ((Allowed[StrOfs] = '%') AND (AsciiKey = '.')) OR
{ plain strings }    ((Allowed[StrOfs] IN ['<','>']) AND (AsciiKey IN [' '..'~'])) OR
{ paths }            ((Allowed[StrOfs] = '!') AND
                              (AsciiKey IN ['!'..'~']) AND (NOT (AsciiKey IN ['?','*','/','"','<','>','|']))) OR
{ search paths }     ((Allowed[StrOfs] = '*') AND (AsciiKey IN ['!'..'~']) AND (NOT (AsciiKey IN ['/','"','<','>','|']))) OR
                     (NOT (Allowed[StrOfs] IN AllowChars) AND (Allowed[StrOfs] = AsciiKey)))
                    ) THEN
                BEGIN
                     IF (Allowed[StrOfs] IN ['@','>']) THEN
                        AsciiKey:=UpCase (AsciiKey);

                     IF (Allowed[StrOfs] = '<') THEN
                        AsciiKey:=LoCase (AsciiKey);

                     IF (Length (BufferPtr^) = 1) THEN
                        BufferPtr^:=AsciiKey
                     ELSE BEGIN
                          SameCnt:=1;
                          WHILE (X-StartX+SameCnt < Len) AND (Allowed[X-StartX+1+SameCnt] = Allowed[X-StartX+1]) DO
                                Inc (SameCnt);

                          BufferPtr^:=Copy (BufferPtr^,1,X-StartX)+ { tot cursor }
                                      AsciiKey+ { nieuwe teken }
                                      Copy (BufferPtr^,X-StartX+1,SameCnt-1)+ { rest same deel }
                                      Copy (BufferPtr^,X-StartX+1+SameCnt,Len-(X-StartX)-SameCnt); { rest na same }
                     END;

                     { oude methode, lette niet op Allowed }
                     {
                     BufferPtr^:=Copy (BufferPtr^,1,X-StartX)+
                                 AsciiKey +
                                 Copy (BufferPtr^,X-StartX+1,Len-(X-StartX+1));
                     }

                     SetColor (cFieldCursor);
                     DrawOneField (LastFieldNr,{PasswordVisible:}TRUE);

                     IF (ScreenMax <> Len) THEN
                        PrevX:=0
                     ELSE
                         WriteXYC (X,StartY,cFieldCursor,BufferPtr^[StrOfs]);

                     Key:=kRight;
                END;

                CASE Key OF
                     kPressedRButton,
                     kEsc : BEGIN
                                 Quit:=TRUE;
                                 BufferPtr^:=OldData;
                                 SetColor (cFieldCursor);
                                 DrawOneField (LastFieldNr,{PasswordVisible:}FALSE);
                            END;

                     kRet : BEGIN
                                 IF (@FileMgr <> NIL) THEN
                                 BEGIN
                                      CursorOff;
                                      FileMgr (BufferPtr,TRUE{check});
                                      SetColor (cFieldCursor);
                                      DrawOneField (FieldNr,{PasswordVisible:}FALSE);
                                      Quit:=TRUE;
                                 END ELSE
                                     IF (@CheckFunc = NIL) THEN
                                        Quit:=TRUE
                                     ELSE BEGIN
                                          { RW961208: added CursorOff/On }
                                          CursorOff;
                                          Quit:=CheckFunc (BufferPtr);
                                          CursorOn;
                                          SetColor (cFieldCursor);
                                          DrawOneField (FieldNr,{PasswordVisible}NOT Quit);
                                     END;
                            END;

                     kLeft :
                         REPEAT
                               IF (X > StartX) THEN
                                  Dec (X);
                         UNTIL (Allowed[X-StartX+1] IN AllowChars) OR
                               (X = StartX);

                     kRight :
                         REPEAT
                               IF (X < StartX+Len-1) THEN
                                  Inc (X);
                         UNTIL (Allowed[X-StartX+1] IN AllowChars) OR
                               (X = StartX+Len-1);

                     kHome :
                         X:=StartX;

                     kEnd :
                         MoveCursorToEnd;

                     kCtrlLeft :
                         BEGIN
                              { een terug gaan. Het kan zijn dat we }
                              { dan precies van het woord afstappen }
                              IF (X > StartX) THEN
                                 Dec (X);

                              { als we nu van het woord zijn afgestapt }
                              { dan gaan we nu op zoek naar het einde  }
                              { van het vorige woord.                  }
                              WHILE (X > StartX) AND
                                    ((BufferPtr^[X-StartX+1] = ' ') OR
                                     NOT (Allowed[X-StartX+1] IN AllowChars))
                                    DO Dec (X);

                              IF (X <> StartX) THEN
                              BEGIN
                                   { we staan nu op een woord; zoek  }
                                   { het begin van het woord op door }
                                   { van het woord af te stappen.    }
                                   WHILE (X > StartX) AND
                                         (BufferPtr^[X-StartX+1] <> ' ') AND
                                         (Allowed[X-StartX+1] IN AllowChars)
                                         DO Dec (X);

                                   { als we er nu afgestapt zij, dan }
                                   { terug naar het eerste teken van }
                                   { het woord.                      }
                                   IF ((BufferPtr^[X-StartX+1] = ' ') OR
                                       NOT (Allowed[X-StartX+1] IN AllowChars)) AND
                                      (X < StartX+Len-1)
                                      THEN Inc (X);
                              END;
                         END;

                     kCtrlRight :
                         BEGIN
                              { zolang je nog op een woord staat }
                              { naar de volgende positie van het }
                              { woord tot je eraf valt.          }
                              WHILE (X < StartX+Len-1) AND
                                    (BufferPtr^[X-StartX+1] <> ' ') AND
                                    (Allowed[X-StartX+1] IN AllowChars)
                                    DO Inc (X);

                              { nu staan we achter het woord. Zoek }
                              { het begin van het volgende woord   }
                              { op.                                }
                              WHILE (X < StartX+Len-1) AND
                                    ((BufferPtr^[X-StartX+1] = ' ') OR
                                    NOT (Allowed[X-StartX+1] IN AllowChars))
                                    DO Inc (X);
                         END;

                     kCtrlEnd :
                         BEGIN
                              SaveX:=X;

                              REPEAT
                                    BufferPtr^[SaveX-StartX+1]:=' ';
                                    Inc (SaveX);
                              UNTIL (SaveX > StartX+Len-1);

                              SetColor (cFieldCursor);
                              DrawOneField (LastFieldNr,TRUE);
                         END;

                     kBs :
                         IF (X > StartX) THEN
                         BEGIN
                              { eerste terug gaan tot op een teken dat }
                              { verwijderd mag worden met een kDel.    }
                              { een kLeft actie dus.                   }
                              REPEAT
                                    IF (X > StartX) THEN
                                       Dec (X);
                              UNTIL (Allowed[X-StartX+1] IN AllowChars)
                                    OR (X = StartX);

                              IF (Allowed[X-StartX+1] IN AllowChars) THEN
                              BEGIN
                                   IF (Length (BufferPtr^) = 1) THEN
                                      BufferPtr^:=' '
                                   ELSE BEGIN
                                        { alleen het deel met een aaneengesloten }
                                        { zelfde teken in de template opschuiven }
                                        { en daarachter een spatie plaatsen.     }
                                        SameCnt:=1;
                                        WHILE (X-StartX+SameCnt < Len) AND
                                              (Allowed[X-StartX+1+SameCnt] = Allowed[X-StartX+1])
                                        DO
                                          Inc (SameCnt);

                                        BufferPtr^:=Copy (BufferPtr^,1,X-StartX)+   { tot de cursor }
                                                    Copy (BufferPtr^,X-StartX+2,SameCnt-1)+ { same gedeelte }
                                                    ' '+ { achter same gedeelte de spatie }
                                                    Copy (BufferPtr^,X-StartX+SameCnt+1,Len-(X-StartX)-SameCnt); { de rest }
                                   END;

                                   SetColor (cFieldCursor);
                                   DrawOneField (LastFieldNr,TRUE);
                              END;
                         END; { kBs }

                     kDel : IF (Allowed[X-StartX+1] IN AllowChars) THEN
                            BEGIN
                                 IF (Length (BufferPtr^) = 1) THEN
                                    BufferPtr^:=' '
                                 ELSE BEGIN
                                      { alleen het deel met een aaneengesloten }
                                      { zelfde teken in de template opschuiven }
                                      { en daarachter een spatie plaatsen.     }
                                      SameCnt:=1;
                                      WHILE (X-StartX+SameCnt < Len) AND
                                            (Allowed[X-StartX+1+SameCnt] = Allowed[X-StartX+1])
                                      DO
                                        Inc (SameCnt);

                                      BufferPtr^:=Copy (BufferPtr^,1,X-StartX)+   { tot de cursor }
                                                  Copy (BufferPtr^,X-StartX+2,SameCnt-1)+ { same gedeelte }
                                                  ' '+ { achter same gedeelte de spatie }
                                                  Copy (BufferPtr^,X-StartX+SameCnt+1,Len-(X-StartX)-SameCnt); { de rest }
                                 END;

                                 SetColor (cFieldCursor);
                                 DrawOneField (LastFieldNr,TRUE);
                            END;

                     kIns : IF (Allowed[X-StartX+1] IN AllowChars) THEN
                            BEGIN
                                 IF (Length (BufferPtr^) = 1) THEN
                                    BufferPtr^:=' '
                                 ELSE BEGIN
                                      SameCnt:=1;
                                      WHILE (X-StartX+SameCnt < Len) AND
                                            (Allowed[X-StartX+1+SameCnt] = Allowed[X-StartX+1])
                                      DO
                                        Inc (SameCnt);

                                      BufferPtr^:=Copy (BufferPtr^,1,X-StartX)+ { tot cursor }
                                                  ' '+ { spatie in same deel }
                                                  Copy (BufferPtr^,X-StartX+1,SameCnt-1)+ { rest same deel }
                                                  Copy (BufferPtr^,X-StartX+1+SameCnt,Len-(X-StartX)-SameCnt); { rest na same }
                                 END;

                                 SetColor (cFieldCursor);
                                 DrawOneField (LastFieldNr,TRUE);
                            END;

                     kF1 : IF (HelpHandle <> 0) THEN
                              RequestHelp (HelpHandle);

                     kF3 : IF (@FileMgr <> NIL) THEN
                           BEGIN
                                CursorOff;
                                FileMgr (BufferPtr,FALSE{edit});
                                MoveCursorToEnd;
                                PrevX:=0;
                                CursorOn; { was uitgezet }
                           END;

                     kUnknown : IF (AsciiKey = #25{CtrlY}) THEN
                                BEGIN
                                     FOR Lp:=1 TO Length (OldData) DO
                                         IF (Allowed[Lp] IN AllowChars) THEN
                                            BufferPtr^[Lp]:=' ';
                                     X:=StartX;
                                     SetColor (cFieldCursor);
                                     DrawOneField (FieldNr,TRUE);
                                END;

                     ELSE
                         IF (Key IN SpecialKeys) THEN
                            IF (@CheckFunc = NIL) THEN
                               Quit:=TRUE
                            ELSE BEGIN
                                 { RW961208: added CursorOff/On }
                                 CursorOff;
                                 Quit:=CheckFunc (BufferPtr);
                                 CursorOn;
                                 SetColor (cFieldCursor);
                                 DrawOneField (FieldNr,NOT Quit);
                            END;
                END; { case }

          UNTIL Quit;

          IF (Offset <> 1) OR ((Flags AND FLAGS_PASSWORD) <> 0) THEN
          BEGIN
               Offset:=1;
               SetColor (cFieldCursor);
               DrawOneField (FieldNr,{PasswordVisible:}FALSE);
          END;
     END; { with }

     CursorOff;
     PopKeysLine;
END;


{--------------------------------------------------------------------------}
{ FieldEditDirectSpecial                                                   }
{                                                                          }
{ Zelfde als FieldEditDirect, maar nu mag een keysset opgeven.             }
{                                                                          }
PROCEDURE FieldEditDirectSpecial (SpecialKeys : KeysSet);
BEGIN
     SetColor (cFieldCursor);
     DrawOneField (LastFieldNr,{PasswordVisible:}TRUE);
     FieldEditContents (LastFieldNr,#0,SpecialKeys);
END;


{--------------------------------------------------------------------------}
{ FieldEditDirect                                                          }
{                                                                          }
{ Edit het huidige veld direct. Deze routine moet aangeroepen worden omdat }
{ het veld waarschijnlijk nog niet in de goede kleur staat. Ook het veld   }
{ nummer hoeft nu niet van buitenaf opgegeven te worden.                   }
{                                                                          }
PROCEDURE FieldEditDirect;
BEGIN
     FieldEditDirectSpecial ([]);
END;


{--------------------------------------------------------------------------}
{ FieldEditDirectWithStuffKey                                              }
{                                                                          }
{ Zelfde als FieldEditDirect, maar dan wordt de cursor meteen aan het eind }
{ van de regel gezet.                                                      }
{                                                                          }
PROCEDURE FieldEditDirectWithStuffKey (Key : KeyType);
BEGIN
     SetColor (cFieldCursor);
     DrawOneField (LastFieldNr,{PasswordVisible:}TRUE);
     FieldEditContents (LastFieldNr,Char (Key),[]);
END;


{--------------------------------------------------------------------------}
{ MoveToggle                                                               }
{                                                                          }
{ 1=Forward, 2=Backwords, (future?: 3=Home, 4=End)                         }
{                                                                          }
PROCEDURE MoveToggle (Direction : BYTE);

VAR N  : BYTE;
    S  : STRING;

BEGIN
     { wijzig toggle }
     WITH Fields[LastFieldNr] DO
     BEGIN
          REPEAT
                { move the toggle }
                CASE Direction OF
                     1: IF ((TogglePtr^-Toggle1St) = Len) THEN
                           TogglePtr^:=Toggle1St
                        ELSE
                            Inc (TogglePtr^);

                     2: IF (TogglePtr^ = Toggle1St) THEN
                           TogglePtr^:=Toggle1St+Len
                        ELSE
                            Dec (TogglePtr^);
                END; { case }

                { controleer of we nu op een lege optie staan ("||") }
                { zoja, ga dan nog een stap verder.                  }

                { verwijder de opties voor alle voorgangers }
                S:=Allowed;
                N:=TogglePtr^-Toggle1St;
                WHILE (N > 0) DO
                BEGIN
                     Dec (N);
                     Delete (S,1,Pos ('|',S));
                END; { while }

          UNTIL (S[1] <> '|');  { not on empty spot }

          { screen update }
          SetColor (cFieldCursor);
          DrawOneField (LastFieldNr,{PasswordVisible:}FALSE);

          { procedure aanroep bij TogglesCall }
          IF (@ListProc <> NIL) THEN
             ListProc;
     END; { width }
END;


{--------------------------------------------------------------------------}
{ FieldEdit                                                                }
{                                                                          }
{ Met deze routine kan het editten in de velden gestart worden. Aan de     }
{ hand van het veld dat het laatste gebruikt is wordt begonnen. Als er nog }
{ geen veld gebruikt is, dan is dat het veld met nummer 1.                 }
{ Met de cursor toetsen omhoog en omlaag kan door de velden gebladerd      }
{ worden. Na een druk op de Enter toets kan het veld gewijzigd worden.     }
{                                                                          }
PROCEDURE FieldEdit;

VAR Lp,
    PrevLastFieldNr : FieldNrType;
    GoEdit,
    Quit            : BOOLEAN;
    StuffKey        : CHAR;

BEGIN
     IF ((Fields[1].Flags AND FLAGS_USED) = 0) THEN
     BEGIN
          Error ('No fields defined');
          Exit;
     END;

     PushKeysLine;
     WriteKeysLine (FieldSelectKeysLine);

     FieldUpdateScreen;

     PrevLastFieldNr:=0;

     Quit:=FALSE;
     REPEAT
           { cursor beweging laten zien }
           IF (PrevLastFieldNr <> LastFieldNr) THEN
           BEGIN
                IF (PrevLastFieldNr <> 0) THEN
                BEGIN
                     SetColor (cFieldData);
                     DrawOneField (PrevLastFieldNr,{PasswordVisible:}FALSE);
                END;

                SetColor (cFieldCursor);
                DrawOneField (LastFieldNr,{PasswordVisible:}TRUE);

                PrevLastFieldNr:=LastFieldNr;
           END;

           { toets afhandelen }
           GoEdit:=FALSE;
           StuffKey:=#0;
           CASE ReadKey OF
                kEsc,
                kF10 : Quit:=TRUE;

                kRight,
                kDown  : REPEAT
                               LastFieldNr:=Fields[LastFieldNr].SuccLink;
                         UNTIL (LastFieldNr = 0) OR ((Fields[LastFieldNr].Flags AND FLAGS_DISABLED) = 0);

                kLeft,
                kUp   : REPEAT
                              LastFieldNr:=Fields[LastFieldNr].PrevLink;
                        UNTIL (LastFieldNr = 0) OR ((Fields[LastFieldNr].Flags AND FLAGS_DISABLED) = 0);

                kF1 : IF (Fields[LastFieldNr].HelpHandle <> 0) THEN
                         RequestHelp (Fields[LastFieldNr].HelpHandle);

               {kSpace,   }                  { osiris freaking }
                kRet : IF (Fields[LastFieldNr].TogglePtr <> NIL) THEN
                          MoveToggle (1{forward})
                       ELSE
                           GoEdit:=TRUE;

                kAltRet,
                kShTab,
                kAltLeft :
                    IF (Fields[LastFieldNr].TogglePtr <> NIL) THEN
                       MoveToggle (2{backwards});

                kTab,
                kAltRight :
                    IF (Fields[LastFieldNr].TogglePtr <> NIL) THEN
                       MoveToggle (1{forward});

                kF3 :
                    IF (@Fields[LastFieldNr].FileMgr <> NIL) THEN
                    BEGIN
                         Fields[LastFieldNr].FileMgr (Fields[LastFieldNr].BufferPtr,FALSE{edit});
                         PrevLastFieldNr:=0; { force redraw }
                         { put the cursor at the end again }

                    END;

                { start met doorgave toets }
                ELSE
                    IF (Fields[LastFieldNr].TogglePtr = NIL) AND
                       (AsciiKey IN [#25{CtrlY},' '..'~']) THEN
                    BEGIN
                         GoEdit:=TRUE;

                         { change CtrlY into CtrlEnd (?) }
                         IF (AsciiKey = #25) THEN
                            AsciiKey:=#225;

                         StuffKey:=AsciiKey;
                    END;
           END; { case }

           IF (LastFieldNr = 0) THEN
              LastFieldNr:=PrevLastFieldNr;

           { veld inhoud wijzigen }
           IF GoEdit THEN
              FieldEditContents (LastFieldNr,StuffKey,[]);

     UNTIL Quit;

     { cursor verwijderen }
     SetColor (cFieldData);
     DrawOneField (LastFieldNr,{PasswordVisible:}FALSE);

     PopKeysLine;
END;


{--------------------------------------------------------------------------}
{ FieldSetHelp                                                             }
{                                                                          }
{ Met deze routine kan een help veld worden toegekend aan een van de Field }
{ velden. Hierdoor kan voor ieder veld een aparte help geinstalleerd       }
{ worden.                                                                  }
{                                                                          }
PROCEDURE FieldSetHelp (FieldNr : FieldNrType; HelpHandle : HelpHandleType);
BEGIN
     IF (FieldNr = 0) THEN
        FieldNr:=NewFieldNr; { laatste automatisch aangemaakte veld nr }

     Fields[FieldNr].HelpHandle:=HelpHandle;
END;


{---------------------------------------------------------------------------}
{ FieldPushAll                                                              }
{                                                                           }
{ Deze routine slaat de huidige veld definities op de stack op. De fields   }
{ zelf worden niet gewijzigd en kunnen dus zo uitgebreid worden.            }
{                                                                           }
PROCEDURE FieldPushAll;

VAR NewFieldStkPtr : FieldStackRecordPtr;

BEGIN
     GetMem (NewFieldStkPtr,SizeOf (FieldStackRecord));

     WITH NewFieldStkPtr^ DO
     BEGIN
          PrevPtr:=FieldStkPtr;
          FArray:=Fields;
          LastNr:=LastFieldNr;
     END;

     FieldStkPtr:=NewFieldStkPtr;
END;


{---------------------------------------------------------------------------}
{ FieldPopAll                                                               }
{                                                                           }
{ Deze routine haalt de op de stack opgeslagen velden definities terug.     }
{                                                                           }
PROCEDURE FieldPopAll;

VAR EraseFieldStkPtr : FieldStackRecordPtr;

BEGIN
     EraseFieldStkPtr:=FieldStkPtr;
     LastFieldNr:=FieldStkPtr^.LastNr;
     FieldStkPtr:=FieldStkPtr^.PrevPtr;
     Fields:=EraseFieldStkPtr^.FArray;
     FreeMem (EraseFieldStkPtr,SizeOf (FieldStackRecord));
END;


{--------------------------------------------------------------------------}
{ FieldCheckByteFunc                                                       }
{                                                                          }
{ Deze routine controleert of het ingevoerde getal voor wel een byte is en }
{ formatteerd deze meteen.                                                 }
{                                                                          }
FUNCTION FieldCheckByteFunc (BufferPtr : StringPtr) : BOOLEAN;

VAR Getal : BYTE;
    Nop   : ValErrType;

BEGIN
     Val (DeleteFrontAndBackSpaces (BufferPtr^),Getal,Nop);
     BufferPtr^:=AddUpWithSpaces (3,Byte2String (Getal));
     FieldCheckByteFunc:=(Nop = 0);
END;


{--------------------------------------------------------------------------}
{ FieldCheckWordFunc                                                       }
{                                                                          }
{ Deze routine controleert of het ingevoerde getal voor wel een word is en }
{ formatteerd deze meteen.                                                 }
{                                                                          }
FUNCTION FieldCheckWordFunc (BufferPtr : StringPtr) : BOOLEAN;

VAR Getal : WORD;
    Nop   : ValErrType;

BEGIN
     Val (DeleteFrontAndBackSpaces (BufferPtr^),Getal,Nop);
     BufferPtr^:=AddUpWithSpaces (5,Word2String (Getal));
     FieldCheckWordFunc:=(Nop = 0);
END;

{ end of file fields.inc }
