home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0000 - 0009 / ibm0000-0009 / ibm0003.tar / ibm0003 / TPOWER54.ZIP / DEMOSRC.ARC / ENTRY.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-07-10  |  31.7 KB  |  1,061 lines

  1. {$S-,I-}
  2. {$V-}                        {<- required for TPENTRY}
  3. {$M 16384,16384,600000}
  4.  
  5. {$I TPDEFINE.INC}
  6.  
  7. {*********************************************************}
  8. {*                   ENTRY.PAS 5.07                      *}
  9. {*     An example program for Turbo Professional 5.0     *}
  10. {*        Copyright (c) TurboPower Software 1988.        *}
  11. {* Portions copyright (c) Sunny Hill Software 1985, 1986 *}
  12. {*     and used under license to TurboPower Software     *}
  13. {*                 All rights reserved.                  *}
  14. {*********************************************************}
  15.  
  16. program TpEntryDemo;
  17.   {-Demonstrates use of TPENTRY unit}
  18.  
  19. uses
  20.   TpString,                  {string handling}
  21.   TpCrt,                     {basic screen handling}
  22.   {$IFDEF UseMouse}
  23.   TpMouse,                   {mouse routines}
  24.   {$ENDIF}
  25.   TpDate,                    {date and time variables}
  26.   TpEntry,                   {data entry}
  27.   TpMemo,                    {memo field editor}
  28.   TpWindow,                  {window management}
  29.   TpPick,                    {pick lists}
  30.   TpHelp;                    {popup help}
  31.  
  32. const
  33.   TitleLine = 02;
  34.   StatusLine = 04;
  35.   HelpLine = 22;
  36.   KeyInfoLine = 24;
  37.   Title : string[38] = 'Demonstration Program for TPENTRY 5.07';
  38.   KeyInfoText : string[78] =
  39.   ' <F1> Help '^G' '^[^X^Y^Z' move cursor '^G' <Enter> Accept '^G' <Esc> Cancel '^G' <^Enter> Quit ';
  40. type
  41.   GenderType = (Unknown, Male, Female);
  42.   MemoField = array[1..2048] of Char;
  43.   Info =
  44.     record
  45.       Name : string[30];     {string field}
  46.       Address : string[30];  {string field}
  47.       City : string[25];     {string field}
  48.       State : string[02];    {string field w/ special validation}
  49.       Zip : string[10];      {string field w/ special validation}
  50.       WPhone : string[14];   {string field w/ special validation}
  51.       HPhone : string[14];   {string field w/ special validation}
  52.       Gender : GenderType;   {multiple choice field}
  53.       Married : Boolean;     {yes/no field}
  54.       Born : Date;           {date field}
  55.       Age : Byte;            {calculated field, based on Born}
  56.       Wage : Real;           {numeric field w/ range checking}
  57.       Weekly : Real;         {calculated field (= Wage * Hours)}
  58.       Hours : Byte;          {multiple choice field, incremental}
  59.       Yearly : Real;         {calculated field (= Weekly * 52)}
  60.       Notes : MemoField;     {a memo field}
  61.     end;
  62. const
  63.   MaxRec = 20;
  64.   PhoneMask : string[14] = '(999) 999-9999';
  65.   ValidPhone : string[14] = '(ppp) uuu-uuuu';
  66.   ZipMask : string[10] = '99999-9999';
  67.   ValidZip : string[10] = 'uuuuu-pppp';
  68.   Genders : array[GenderType] of string[7] = (
  69.     'Unknown', 'Male   ', 'Female ');
  70.   EmptyString : string[1] = '';
  71.   OurHelpColorAttr : HelpColorArray = ($1D, $1B, $5F, $5F, $3F, $1E, $1F, $1B);
  72.   OurHelpMonocAttr : HelpColorArray = ($0F, $07, $70, $70, $09, $0F, $0F, $0F);
  73. var
  74.   InfoRecs : array[1..MaxRec] of Info; {the "database"}
  75.   Scrap : Info;              {blank record used for editing}
  76.   CurrentRec : Byte;         {current index into InfoRecs}
  77.   ExitCommand : EStype;      {exit command returned by editor}
  78.   ESR1 : ESrecord;            {our main edit screen}
  79.   ESR2 : ESrecord;           {our nested edit screen}
  80.   BoxAttr : Byte;            {color of boxes}
  81.   BoxTextAttr : Byte;        {color of text in boxes}
  82.   ProtectAttr : Byte;        {attribute used for protected fields}
  83.   BlankWageAttr : Byte;      {special attribute used for Wage field}
  84.   PickColors : PickColorArray; {colors for TPPICK}
  85.   HelpColors : HelpColorArray; {colors for TPHELP}
  86.   AllDone : Boolean;         {done with demo program}
  87.   HelpP : HelpPtr;           {pointer to help system}
  88.   WP1 : WindowPtr;           {points to window for second entry screen}
  89.   WP2 : WindowPtr;           {points to window for memo field editor}
  90.   DateMask : string[10];     {picture mask for date strings}
  91.   TimeMask : string[11];     {picture mask for time strings}
  92.   WageMask : string[10];     {picture mask for wage field}
  93.   CurrMask : string[15];     {picture mask for totals based on wages}
  94.  
  95. const
  96.   StateStrings : array[1..51] of string[19] = (
  97.     {01} 'AK Alaska',
  98.     {02} 'AL Alabama',
  99.     {03} 'AR Arkansas',
  100.     {04} 'AZ Arizona',
  101.     {05} 'CA California',
  102.     {06} 'CO Colorado',
  103.     {07} 'CT Connecticut',
  104.     {08} 'DC Dist of Columbia',
  105.     {09} 'DE Delaware',
  106.     {10} 'FL Florida',
  107.     {11} 'GA Georgia',
  108.     {12} 'HI Hawaii',
  109.     {13} 'IA Iowa',
  110.     {14} 'ID Idaho',
  111.     {15} 'IL Illinois',
  112.     {16} 'IN Indiana',
  113.     {17} 'KS Kansas',
  114.     {18} 'KY Kentucky',
  115.     {19} 'LA Louisana',
  116.     {20} 'MA Massachusetts',
  117.     {21} 'MD Maryland',
  118.     {22} 'ME Maine',
  119.     {23} 'MI Michigan',
  120.     {24} 'MN Minnesota',
  121.     {25} 'MO Missouri',
  122.     {26} 'MS Mississippi',
  123.     {27} 'MT Montana',
  124.     {28} 'NC North Carolina',
  125.     {29} 'ND North Dakota',
  126.     {30} 'NE Nebraska',
  127.     {31} 'NH New Hampshire',
  128.     {32} 'NJ New Jersey',
  129.     {33} 'NM New Mexico',
  130.     {34} 'NV Nevada',
  131.     {35} 'NY New York',
  132.     {36} 'OH Ohio',
  133.     {37} 'OK Oklahoma',
  134.     {38} 'OR Oregon',
  135.     {39} 'PA Pennsylvania',
  136.     {40} 'RI Rhode Island',
  137.     {41} 'SC South Carolina',
  138.     {42} 'SD South Dakota',
  139.     {43} 'TN Tennessee',
  140.     {44} 'TX Texas',
  141.     {45} 'UT Utah',
  142.     {46} 'VA Virginia',
  143.     {47} 'VT Vermont',
  144.     {48} 'WA Washington',
  145.     {49} 'WI Wisconsin',
  146.     {50} 'WV West Virginia',
  147.     {51} 'WY Wyoming');
  148.  
  149.   {$F+}
  150.   function ValidatePhone(var FR : FieldRec;
  151.                          var ErrCode : Byte;
  152.                          var ErrorSt : StringPtr) : Boolean;
  153.     {-Validate a phone number}
  154.   begin
  155.     ValidatePhone := ValidateSubfields(ValidPhone, FR, ErrCode, ErrorSt);
  156.   end;
  157.  
  158.   function ValidateZip(var FR : FieldRec;
  159.                        var ErrCode : Byte;
  160.                        var ErrorSt : StringPtr) : Boolean;
  161.     {-Validate a zip code}
  162.   begin
  163.     ValidateZip := ValidateSubfields(ValidZip, FR, ErrCode, ErrorSt);
  164.   end;
  165.  
  166.   function ValidateState(var FR : FieldRec;
  167.                          var ErrCode : Byte;
  168.                          var ErrorSt : StringPtr) : Boolean;
  169.     {-Validate a state abbreviation}
  170.   const
  171.     BadState : String[37] = 'Not a valid abbreviation for a state.';
  172.   var
  173.     I : Word;
  174.     S : String[2];
  175.   begin
  176.     {don't validate if user pressed <F2> or clicked on the field}
  177.     if (LastEntryCommand = ESuser1) or (LastEntryCommand = ESclickExit) then
  178.       ValidateState := True
  179.     {check for partial entry}
  180.     else if ValidateNotPartial(FR, ErrCode, ErrorSt) then begin
  181.       {not partial--is it empty?}
  182.       ValidateState := True;
  183.       S := Trim(FR.EditSt^);
  184.       if Length(S) = 0 then
  185.         Exit;
  186.  
  187.       {check list of valid abbreviations}
  188.       for I := 1 to 51 do
  189.         {exit if it's a match}
  190.         if (S[1] = StateStrings[I][1]) and (S[2] = StateStrings[I][2]) then
  191.           Exit;
  192.  
  193.       {not a valid abbreviation}
  194.       ErrCode := 10; {arbitrary}
  195.       ErrorSt := @BadState;
  196.       ValidateState := False;
  197.     end
  198.     else
  199.       ValidateState := False;
  200.   end;
  201.  
  202.   function StateChoice(I : Word) : string;
  203.     {-Return a state string given an index}
  204.   begin
  205.     StateChoice := StateStrings[I];
  206.   end;
  207.   {$F-}
  208.  
  209.   procedure DisplayCentered(S : string; Row : Byte);
  210.     {-Display S centered on the specified Row}
  211.   begin
  212.     FastWrite(Center(S, 78), Row, 2, BoxTextAttr);
  213.   end;
  214.  
  215.   procedure ClearHelpLine;
  216.     {-Clear the help line}
  217.   begin
  218.     DisplayCentered(EmptyString, HelpLine);
  219.   end;
  220.  
  221.   {$F+}
  222.   function GetKey : Word;
  223.     {-Display current date and time while waiting for keypress}
  224.   begin
  225.     {$IFDEF UseMouse}
  226.     while not(KeyPressed or MousePressed) do begin
  227.     {$ELSE}
  228.     while not KeyPressed do begin
  229.     {$ENDIF}
  230.       {make sure TSR's can pop up}
  231.       inline($CD/$28);
  232.  
  233.       {display the current date and time}
  234.       FastWrite(TodayString(DateMask), StatusLine, 38, ESfieldAttr);
  235.       FastWrite(CurrentTimeString(TimeMask), StatusLine, 57, ESfieldAttr);
  236.     end;
  237.  
  238.     {$IFDEF UseMouse}
  239.     if KeyPressed then
  240.       GetKey := ReadKeyWord
  241.     else
  242.       GetKey := MouseKeyWord;
  243.     {$ELSE}
  244.       GetKey := ReadKeyWord
  245.     {$ENDIF}
  246.   end;
  247.  
  248.   procedure IncChoice(var Value; FieldID : Word; Factor : Integer; var St : string);
  249.     {-Increment a multiple choice field value and convert it to a string}
  250.   var
  251.     Gender : GenderType absolute Value;
  252.     Hours : Byte absolute Value;
  253.   begin
  254.     if FieldID = 7 then begin
  255.       {Gender}
  256.       case Factor of
  257.         01 :                 {increment}
  258.           if Gender = Female then
  259.             Gender := Unknown
  260.           else
  261.             Inc(Gender);
  262.         -1 :                 {decrement}
  263.           if Gender = Unknown then
  264.             Gender := Female
  265.           else
  266.             Dec(Gender);
  267.       end;
  268.       St := Genders[Gender];
  269.     end
  270.     else if FieldID = 13 then begin
  271.       {Hours}
  272.       case Factor of
  273.         01 :                 {increment}
  274.           if Hours < 99 then
  275.             Inc(Hours);
  276.         -1 :                 {decrement}
  277.           if Hours > 0 then
  278.             Dec(Hours);
  279.       end;
  280.       Str(Hours:2, St);
  281.     end;
  282.   end;
  283.  
  284.   procedure DisplayErrorMessage(Msg : string);
  285.     {-Display an error message}
  286.   var
  287.     W, CursorSL, CursorXY : Word;
  288.   begin
  289.     {Store cursor position and shape, then make it a fat cursor}
  290.     GetCursorState(CursorXY, CursorSL);
  291.     FatCursor;
  292.  
  293.     {add to default message, if possible}
  294.     if Length(Msg) < 60 then
  295.       Msg := Msg+' Press any key...';
  296.  
  297.     {display error message and ring bell}
  298.     DisplayCentered(Msg, HelpLine);
  299.     RingBell;
  300.  
  301.     {flush keyboard buffer}
  302.     while KeyPressed do
  303.       W := GetKey;
  304.  
  305.     {wait for keypress, then clear the help line}
  306.     W := GetKey;
  307.     ClearHelpLine;
  308.  
  309.     {Restore cursor position and shape}
  310.     RestoreCursorState(CursorXY, CursorSL);
  311.   end;
  312.  
  313.   procedure ErrorHandler(var ESR : ESrecord; Code : Byte; Msg : string);
  314.     {-Display messages for errors reported by TPENTRY}
  315.   begin
  316.     DisplayErrorMessage(Msg);
  317.     case Code of
  318.       InitError, OverflowError, MemoryError, ParamError :
  319.         begin
  320.           {a fatal error: set normal cursor and clear the screen}
  321.           NormalCursor;
  322.           ClrScr;
  323.         end;
  324.     end;
  325.   end;
  326.  
  327.   procedure SetAgeFieldAttribute(var ESR : ESrecord);
  328.     {-Set the attributes for the Age field such that the field is hidden if
  329.       Age = 0}
  330.   begin
  331.     if Scrap.Age = 0 then begin
  332.       {hide the entire field}
  333.       ChangePromptAttr(ESR, 10, 0);
  334.       ChangeFieldAttr(ESR, 10, 0);
  335.     end
  336.     else begin
  337.       {unhide the field}
  338.       ChangePromptAttr(ESR, 10, ESpromptAttr);
  339.       ChangeFieldAttr(ESR, 10, ProtectAttr);
  340.     end;
  341.   end;
  342.  
  343.   procedure SetWageFieldAttribute(var ESR : ESrecord);
  344.     {-Set the attributes for the Wage field such that the field is blanked out
  345.       if Wage = 0}
  346.   begin
  347.     if Scrap.Wage = 0 then
  348.       ChangeFieldAttr(ESR, 11, BlankWageAttr)
  349.     else
  350.       ChangeFieldAttr(ESR, 11, ESfieldAttr);
  351.   end;
  352.  
  353.   procedure UpdateHandler(var ESR : ESrecord);
  354.     {-Called after a field has been edited}
  355.   var
  356.     Days, Months, Years : Integer;
  357.     ThisDate : Date;         {today's date in julian format}
  358.   begin
  359.     ThisDate := Today;
  360.     with Scrap do
  361.       case ESR.CurrentID of
  362.         09 :                 {Born}
  363.           begin
  364.             {calculate Age field}
  365.             if (Born = BadDate) or (Born > ThisDate) then
  366.               Age := 0
  367.             else begin
  368.               DateDiff(Born, ThisDate, Days, Months, Years);
  369.               Age := Years;
  370.             end;
  371.  
  372.             {redraw the Age and field}
  373.             SetAgeFieldAttribute(ESR);
  374.             DrawField(ESR, 10);
  375.           end;
  376.         11,                  {Wage}
  377.         13 :                 {Hours}
  378.           begin
  379.             {calculate weekly and yearly earnings}
  380.             Weekly := Wage*Hours;
  381.             Yearly := Weekly*52;
  382.  
  383.             {redraw Wage field if appropriate}
  384.             if ESR.CurrentID = 11 then begin
  385.               SetWageFieldAttribute(ESR);
  386.               DrawField(ESR, 11);
  387.             end;
  388.  
  389.             {redraw Weekly}
  390.             DrawField(ESR, 12);
  391.  
  392.             {redraw Yearly}
  393.             DrawField(ESR, 14);
  394.           end;
  395.       end;
  396.   end;
  397.  
  398.   procedure DisplayHelpPrompt(var ESR : ESrecord);
  399.     {-Display a help prompt for the current field}
  400.   var
  401.     S : string[80];
  402.   begin
  403.     case ESR.CurrentID of
  404.       {--Field 0 is the record number (protected)--}
  405.       01 : S := 'Enter first name, middle initial, last name';
  406.       02 : S := 'Enter street address or post office box';
  407.       03 : S := 'Enter city of residence';
  408.       04 : S := 'Enter state of residence or press <F2> to select from list';
  409.       05 : S := 'Enter a five- or nine-digit zip code';
  410.       06 : S := 'Press <Enter> to edit work and home phone numbers';
  411.       07 : S := 'Press space bar, "+" or "-" to select gender';
  412.       08 : S := 'Enter "N" if marital status is unknown, else "N" or "Y"';
  413.       09 : S := 'Enter date of birth';
  414.       {--Field 10 is Age (protected, calculated)--}
  415.       11 : S := 'Enter hourly wage ($0-$99.99)';
  416.       {--Field 12 is Weekly (protected, calculated)--}
  417.       13 : S := 'Press "+" or "-" to adjust hours worked per week';
  418.       {--Field 14 is Yearly (protected, calculated)--}
  419.       15 : S := 'Press <Enter> to edit notes field';
  420.     end;
  421.     DisplayCentered(S, HelpLine);
  422.   end;
  423.  
  424.   procedure DisplayHelpPrompt2(var ESR : ESrecord);
  425.     {-Display a help prompt for the current field}
  426.   var
  427.     S : string[80];
  428.   begin
  429.     case ESR.CurrentID of
  430.       00 : S := 'Enter work phone number (area code is optional)';
  431.       01 : S := 'Enter home phone number (area code is optional)';
  432.     end;
  433.     DisplayCentered(S, HelpLine);
  434.   end;
  435.  
  436.   procedure DisplayHelp(UnitCode : Byte; IdPtr : Pointer; HelpIndex : Word);
  437.     {-Display context sensitive help}
  438.   begin
  439.     {do nothing if help index is illegal}
  440.     if HelpIndex <> 0 then begin
  441.       {ignore the help index passed by TPPICK}
  442.       if UnitCode = HelpForPick then
  443.         if IdPtr = @StateChoice then
  444.           HelpIndex := 4
  445.         else
  446.           {in help system displaying topic index--do nothing}
  447.           Exit;
  448.  
  449.       {display the help screen}
  450.       if not ShowHelp(HelpP, HelpIndex) then
  451.         RingBell;
  452.     end;
  453.   end;
  454.  
  455.   procedure MemoFieldStatus(var EMCB : EMcontrolBlock);
  456.     {-Display status line for memo field}
  457.                               {         1         2         }
  458.   const                       {12345678901234567890123456789}
  459.     StatusLine : string[29] = ' Line: xxx Column: xxx 100% ';
  460.   var
  461.     S : string[5];
  462.   begin
  463.     with EMCB do begin
  464.       {insert line number}
  465.       S := Long2Str(CurLine);
  466.       S := Pad(S, 3);
  467.       Move(S[1], StatusLine[8], 3);
  468.  
  469.       {insert column number}
  470.       S := Long2Str(CurCol);
  471.       S := Pad(S, 3);
  472.       Move(S[1], StatusLine[20], 3);
  473.  
  474.       {insert percentage of buffer used}
  475.       S := Real2Str(Trunc((TotalBytes*100.0)/(BufSize-2)), 3, 0);
  476.       Move(S[1], StatusLine[24], 3);
  477.  
  478.       {$IFDEF UseMouse}
  479.       HideMouse;
  480.       {$ENDIF}
  481.  
  482.       {display status line}
  483.       FastWrite(StatusLine, 19, 27, BoxTextAttr);
  484.  
  485.       {$IFDEF UseMouse}
  486.       ShowMouse;
  487.       {$ENDIF}
  488.     end;
  489.   end;
  490.  
  491.   procedure MemoPrompt;
  492.     {-Display the prompt for the memo editor}
  493.   begin
  494.     DisplayCentered('Press <Esc> when finished entering notes', HelpLine);
  495.   end;
  496.  
  497.   procedure MemoErrorHandler(var EMCB : EMcontrolBlock; ErrorCode : Word);
  498.     {-Display error message and wait for key press}
  499.   begin
  500.     case ErrorCode of
  501.       tmBufferFull :
  502.         DisplayErrorMessage('Edit buffer is full.');
  503.       tmLineTooLong :
  504.         DisplayErrorMessage('Line too long, carriage return inserted.');
  505.       tmTooManyLines :
  506.         DisplayErrorMessage('Limit on number of lines has been reached.');
  507.       tmOverLineLimit :
  508.         DisplayErrorMessage('Limit on number of lines has been exceeded');
  509.       else
  510.         DisplayErrorMessage('Unknown error.');
  511.     end;
  512.  
  513.     {redisplay our prompt}
  514.     MemoPrompt;
  515.   end;
  516.   {$F-}
  517.  
  518.   procedure EditMemoField;
  519.     {-Edit a memo field}
  520.   const
  521.     NullCmdList : EMtype = EMnone;
  522.   var
  523.     ExitCommand : EMtype;
  524.     EMCB : EMcontrolBlock;
  525.   begin
  526.     {$IFDEF UseMouse}
  527.     {hide the mouse cursor}
  528.     HideMouse;
  529.     {$ENDIF}
  530.  
  531.     {display the window}
  532.     if not DisplayWindow(WP2) then {} ;
  533.  
  534.     {$IFDEF UseMouse}
  535.     {reveal the mouse cursor}
  536.     ShowMouse;
  537.     {$ENDIF}
  538.  
  539.     {initialize the edit control block}
  540.     InitControlBlock(
  541.       EMCB,                  {control block}
  542.       9,                     {left column of edit window}
  543.       8,                     {top row of edit window}
  544.       72,                    {right column of edit window}
  545.       18,                    {bottom row of edit window}
  546.       BoxTextAttr,           {attribute for normal text}
  547.       BoxTextAttr,           {attribute for control characters}
  548.       True,                  {insert mode on?}
  549.       True,                  {auto-indent on?}
  550.       True,                  {word wrap on?}
  551.       8,                     {distance between tab stops}
  552.       15,                    {help index}
  553.       63,                    {right margin}
  554.       999,                   {maximum number of lines}
  555.       SizeOf(MemoField),     {size of edit buffer}
  556.       Scrap.Notes);          {edit buffer}
  557.  
  558.     {start editing}
  559.     MemoPrompt;
  560.     ExitCommand := EditMemo(EMCB, False, NullCmdList);
  561.     ClearHelpLine;
  562.  
  563.     {$IFDEF UseMouse}
  564.     {hide the mouse cursor}
  565.     HideMouse;
  566.     {$ENDIF}
  567.  
  568.     {erase the window}
  569.     WP2 := EraseTopWindow;
  570.  
  571.     {$IFDEF UseMouse}
  572.     {reveal the mouse cursor}
  573.     ShowMouse;
  574.     {$ENDIF}
  575.   end;
  576.  
  577.   function ConfirmQuitting : Boolean;
  578.     {-Confirm that the user wants to quit}
  579.   var
  580.     ChWord : Word;
  581.     Ch : Char absolute ChWord;
  582.   begin
  583.     while KeyPressed do
  584.       ChWord := ReadKeyWord;
  585.  
  586.     {$IFDEF UseMouse}
  587.     while MousePressed do
  588.       ChWord := MouseKeyWord;
  589.     {$ENDIF}
  590.  
  591.     HiddenCursor;
  592.     DisplayCentered(
  593.       'Are you sure you want to quit? (Press "Y" or <Esc> to confirm.)', HelpLine);
  594.     ChWord := GetKey;
  595.  
  596.     {$IFDEF UseMouse}
  597.       ConfirmQuitting := (Upcase(Ch) = 'Y') or (Ch = #27) or (ChWord = MouseRt);
  598.     {$ELSE}
  599.       ConfirmQuitting := (Upcase(Ch) = 'Y') or (Ch = #27);
  600.     {$ENDIF}
  601.  
  602.     ClearHelpLine;
  603.     NormalCursor;
  604.   end;
  605.  
  606.   procedure PickAState;
  607.     {-Pick a state name from a pick list}
  608.   const
  609.     Choice : Word = 1;
  610.   var
  611.     B : Boolean;
  612.   begin
  613.     {uncomment the following line to home the cursor each time}
  614.     {Choice := 1;}
  615.  
  616.     PickMatrix := 3;
  617.     PickSrch := CharPickSrch;
  618.     PickHelpPtr := @DisplayHelp;
  619.  
  620.     {choose a state from the list}
  621.     B := PickWindow(@StateChoice, 51, 8, 7, 73, 19, True, PickColors,
  622.       ' Abbreviated State Names ', Choice);
  623.  
  624.     {do nothing if ESC was pressed}
  625.     if PickCmdNum = PKSSelect then
  626.       {put the name in the actual variable, not Scrap}
  627.       InfoRecs[CurrentRec].State := StateChoice(Choice);
  628.   end;
  629.  
  630.   procedure DrawMainScreen;
  631.     {-Draw the outline of the screen. Fields filled in later}
  632.  
  633.     procedure DrawBox(Row : Byte);
  634.       {-Draw a divided box starting at the specified Row}
  635.     var
  636.       I : Word;
  637.     begin
  638.       {draw the main box}
  639.       for I := Row to Row+4 do
  640.         FastFill(80, ' ', I, 1, BoxAttr);
  641.       FrameWindow(1, Row, 80, Row+4, BoxAttr, BoxAttr, EmptyString);
  642.       FastWrite('├'+CharStr('─', 78)+'┤', Row+2, 1, BoxAttr);
  643.     end;
  644.  
  645.   begin
  646.     ClrScr;
  647.     FrameChars := '╒╘╕╛═│';
  648.  
  649.     {draw the box at the top of the screen}
  650.     DrawBox(TitleLine-1);
  651.     DisplayCentered(Title, TitleLine);
  652.     FastWrite('Date', StatusLine, 32, BoxTextAttr);
  653.     FastWrite('Time', StatusLine, 51, BoxTextAttr);
  654.  
  655.     {draw the box at the bottom of the screen}
  656.     DrawBox(HelpLine-1);
  657.     DisplayCentered(KeyInfoText, KeyInfoLine);
  658.   end;
  659.  
  660.   procedure OpenHelp;
  661.     {-Open ENTRY.HLP}
  662.   var
  663.     Status : Word;
  664.   begin
  665.     {open the help file}
  666.     Status := OpenHelpFile('ENTRY.HLP', 8, 7, 19, 2, HelpColors, HelpP);
  667.     if Status <> 0 then begin
  668.       case Status of
  669.         002 : WriteLn('Help file ENTRY.HLP not found');
  670.         100 : WriteLn('Unexpected end of file reading ENTRY.HLP');
  671.         106 : WriteLn('Help file has invalid format');
  672.         203 : WriteLn('Insufficient heap space available');
  673.         else WriteLn('Help initialization error ', Status);
  674.       end;
  675.       Halt(1);
  676.     end;
  677.   end;
  678.  
  679.   function SecondaryEditScreen : Boolean;
  680.     {-Display secondary edit screen in a popup window. Returns True to advance
  681.       cursor for main edit screen forward, False for backward.}
  682.   var
  683.     ExitCommand : EStype;
  684.     Done : Boolean;
  685.   begin
  686.     {$IFDEF UseMouse}
  687.     {hide the mouse cursor}
  688.     HideMouse;
  689.     {$ENDIF}
  690.  
  691.     {display the window}
  692.     if not DisplayWindow(WP1) then {} ;
  693.  
  694.     {$IFDEF UseMouse}
  695.     {reveal the mouse cursor}
  696.     ShowMouse;
  697.     {$ENDIF}
  698.  
  699.     Done := False;
  700.     repeat
  701.       {start editing}
  702.       ExitCommand := EditScreen(ESR2, ESR2.CurrentID, False);
  703.  
  704.       {copy the edited data back if ESC wasn't pressed}
  705.       if ExitCommand <> ESquit then begin
  706.         InfoRecs[CurrentRec].WPhone := Scrap.WPhone;
  707.         InfoRecs[CurrentRec].HPhone := Scrap.HPhone;
  708.       end;
  709.  
  710.       {see if we need to edit another record}
  711.       case ExitCommand of
  712.         ESuser0 :            {toggle Bell on/off}
  713.           begin
  714.             SetBeepOnError(ESR1, not ESR1.BeepOnError);
  715.             SetBeepOnError(ESR2, not ESR2.BeepOnError);
  716.           end;
  717.         ESnextRec,
  718.         ESprevRec,
  719.         ESquit, ESdone :
  720.           begin
  721.             Done := True;
  722.             SecondaryEditScreen := ExitCommand <> ESprevRec;
  723.           end;
  724.       end;
  725.     until Done;
  726.  
  727.     {$IFDEF UseMouse}
  728.     {hide the mouse cursor}
  729.     HideMouse;
  730.     {$ENDIF}
  731.  
  732.     {erase the window}
  733.     WP1 := EraseTopWindow;
  734.  
  735.     {$IFDEF UseMouse}
  736.     {reveal the mouse cursor}
  737.     ShowMouse;
  738.     {$ENDIF}
  739.   end;
  740.  
  741. begin
  742.   {initialize the database}
  743.   FillChar(Scrap, SizeOf(Scrap), 0);
  744.   FillChar(InfoRecs, SizeOf(InfoRecs), 0);
  745.   for CurrentRec := 1 to MaxRec do begin
  746.     InfoRecs[CurrentRec].Born := BadDate;
  747.     InfoRecs[CurrentRec].Hours := 40;
  748.     InfoRecs[CurrentRec].Notes[1] := ^Z;
  749.   end;
  750.  
  751.   {get international picture mask formats}
  752.   DateMask := InternationalDate(False, False);
  753.   TimeMask := InternationalTime(True, False, True, True);
  754.   WageMask := InternationalCurrency('9', 2, True, False);
  755.   CurrMask := InternationalCurrency('#', 6, True, True);
  756.  
  757.   {handle color mapping manually}
  758.   MapColors := False;
  759.  
  760.   {break checking off}
  761.   CheckBreak := False;
  762.  
  763.   {make sure we're in 80*25 mode}
  764.   case CurrentMode of
  765.     0..1 : TextMode(CurrentMode+2);
  766.     else
  767.      if Hi(LastMode) <> 0 then
  768.        SelectFont8x8(False);
  769.   end;
  770.  
  771.   {set colors based on video mode}
  772.   if WhichHerc = HercInColor then
  773.     CurrentMode := 3;
  774.   case CurrentMode of
  775.     2 : begin
  776.           BoxAttr := $0F;
  777.           BoxTextAttr := $07;
  778.           SetPromptAttr($0F);
  779.           SetFieldAttr($70);
  780.           SetStringAttr($70);
  781.           SetCtrlAttr($70);
  782.           ProtectAttr := $07;
  783.           BlankWageAttr := $77;
  784.           HelpColors := OurHelpMonocAttr;
  785.         end;
  786.     3 : begin
  787.           BoxAttr := $1D;
  788.           BoxTextAttr := $1B;
  789.           SetPromptAttr($0B);
  790.           SetFieldAttr($1F);
  791.           SetStringAttr($5F);
  792.           SetCtrlAttr($5F);
  793.           ProtectAttr := $0F;
  794.           BlankWageAttr := $11;
  795.           HelpColors := OurHelpColorAttr;
  796.         end;
  797.     7 : begin
  798.           BoxAttr := $0F;
  799.           BoxTextAttr := $07;
  800.           SetPromptAttr($0F);
  801.           SetFieldAttr($70);
  802.           SetStringAttr($70);
  803.           SetCtrlAttr($70);
  804.           ProtectAttr := $07;
  805.           BlankWageAttr := $77;
  806.           HelpColors := OurHelpMonocAttr;
  807.         end;
  808.   end;
  809.   if WhichHerc = HercInColor then
  810.     CurrentMode := GetCrtMode;
  811.   TextAttr := ESpromptAttr;
  812.   SetProtectAttrs(ESpromptAttr, ProtectAttr);
  813.   PickColors[WindowAttr] := BoxTextAttr;
  814.   PickColors[FrameAttr] := BoxAttr;
  815.   PickColors[HeaderAttr] := ESstringAttr;
  816.   PickColors[SelectAttr] := ESstringAttr;
  817.   PickColors[AltNormal] := BoxTextAttr;
  818.   PickColors[AltHigh] := ESstringAttr;
  819.   {$IFDEF PickItemDisable}
  820.   PickColors[UnpickableAttr] := BoxTextAttr;
  821.   {$ENDIF}
  822.  
  823.   {make a window for the secondary edit screen}
  824.   if not MakeWindow(WP1, 17, 12, 63, 15, True, True, True, BoxTextAttr,
  825.     BoxAttr, ESstringAttr, ' Phone Numbers ') then
  826.     Halt(1);
  827.  
  828.   {make a window for the memo editor}
  829.   if not MakeWindow(WP2, 8, 7, 73, 19, True, True, True, BoxTextAttr,
  830.     BoxAttr, ESstringAttr, ' Notes ') then
  831.     Halt(1);
  832.  
  833.   {open the help file}
  834.   OpenHelp;
  835.  
  836.   {draw basic outline of the screen}
  837.   DrawMainScreen;
  838.  
  839.   {$IFDEF UseMouse}
  840.   if MouseInstalled then begin
  841.     {use a diamond of the same color as field prompts for our mouse cursor}
  842.     SoftMouseCursor($0000, (ESpromptAttr shl 8)+$04);
  843.     ShowMouse;
  844.  
  845.     {enable mouse support}
  846.     EnableEntryMouse;
  847.     EnablePickMouse;
  848.     EnableHelpMouse;
  849.     EnableMemoMouse
  850.   end;
  851.   {$ENDIF}
  852.  
  853.   {$IFDEF EnablePickOrientations}
  854.   {initialize the pick orientation}
  855.   SetSnakingPick;
  856.   {$ENDIF}
  857.  
  858.   {initialize the edit screen record}
  859.   InitESrecord(ESR1);
  860.  
  861.   {install user-written event handlers}
  862.   SetPreEditPtr(ESR1, @DisplayHelpPrompt);
  863.   SetPostEditPtr(ESR1, @UpdateHandler);
  864.   SetErrorPtr(ESR1, @ErrorHandler);
  865.   EntryKeyPtr := @GetKey;
  866.   HelpKeyPtr := @GetKey;
  867.   PickKeyPtr := @GetKey;
  868.   MemoKeyPtr := @GetKey;
  869.   EntryHelpPtr := @DisplayHelp;
  870.   MemoHelpPtr := @DisplayHelp;
  871.   MemoStatusPtr := @MemoFieldStatus;
  872.   MemoErrorPtr := @MemoErrorHandler;
  873.  
  874.   {set up user exit keys}
  875.   {<AltB> turns bell on/off}
  876.   if not AddEntryCommand(ESuser0, 1, $3000, 0) then ;
  877.   {<F2> pops up pick list for State field}
  878.   if not AddEntryCommand(ESuser1, 1, $3C00, 0) then ;
  879.  
  880.   {set edit screen options}
  881.   SetWrapMode(ESR1, WrapAtEdges);
  882.   SetBeepOnError(ESR1, On);
  883.  
  884.   {set field editing options}
  885.   SetClearFirstChar(On);
  886.  
  887.   {add each of the edit fields in order: left to right, top to bottom}
  888.   {                              Prompt                     Field   Fld Hlp Val}
  889.   {Range     Range     Prompt    Row Col Picture            Row Col Len Ndx Ptr}
  890.   {Low       High      Decimals  Field                                         }
  891.  
  892.   SetProtectAttrs(BoxTextAttr, ESfieldAttr);
  893.   SetProtection(On);
  894.   AddByteField(ESR1,   'Record', 04, 17, '99',              04, 25,     0,
  895.    0,        0,                  CurrentRec);  {** <-- not part of Scrap! **}
  896.   SetProtection(Off);
  897.   SetProtectAttrs(ESpromptAttr, ProtectAttr);
  898.   AddStringField(ESR1, 'Name',   07, 19, '',                07, 25, 30, 1,  nil,
  899.                                  Scrap.Name);
  900.  
  901.   SetRequired(On);
  902.   AddStringField(ESR1, 'Address',08, 16, '',                08, 25, 30, 2,  nil,
  903.                                  Scrap.Address);
  904.   SetRequired(Off);
  905.  
  906.   SetInsertPushes(Off);
  907.   AddStringField(ESR1, 'City',   09, 19, '',                09, 25, 25, 3,  nil,
  908.                                  Scrap.City);
  909.   SetInsertPushes(On);
  910.  
  911.   {$IFDEF UseMouse}
  912.   SetExitOnSecondClick(On);
  913.   {$ENDIF}
  914.   AddStringField(ESR1, 'State',  10, 18, 'AA',              10, 25, 02, 4, @ValidateState,
  915.                                  Scrap.State);
  916.   {$IFDEF UseMouse}
  917.   SetExitOnSecondClick(Off);
  918.   {$ENDIF}
  919.  
  920.   AddStringField(ESR1, 'Zip',    10, 52, ZipMask,           10, 57, 10, 5, @ValidateZip,
  921.                                  Scrap.Zip);
  922.  
  923.   AddNestedField(ESR1, 'Phones', 11, 17, '',                11, 25,  2, 6);
  924.  
  925.   {multiple-choice field}
  926.   AddChoiceField(ESR1, 'Gender', 13, 17, 'XXXXXXX',         13, 25,     7,
  927.    1,        @IncChoice,         Scrap.Gender);
  928.  
  929.   AddYesNoField(ESR1, 'Married', 13, 48, '',                13, 57,     8,
  930.                                  Scrap.Married);
  931.   AddDateField(ESR1, 'Born',     14, 19, DateMask,          14, 25,     9,
  932.    0,        0,                  Scrap.Born);
  933.  
  934.   {a calculated field}
  935.   SetProtection(On);
  936.   AddByteField(ESR1, 'Age',      14, 52, '999',             14, 57,     10,
  937.    0,        0,                  Scrap.Age);
  938.   SetProtection(Off);
  939.  
  940.   {a numeric field}
  941.   SetNumeric(On);
  942.   AddRealField(ESR1, 'Hourly wage',16,12,WageMask,          16, 25,     11,
  943.    0,        999.99,   0,        Scrap.Wage);
  944.   SetNumeric(Off);
  945.  
  946.   {a calculated field}
  947.   SetProtection(On);
  948.   SetPadChar('*');
  949.   AddRealField(ESR1, 'Weekly',   16, 49, CurrMask,          16, 57,     12,
  950.    0,        0,        0,        Scrap.Weekly);
  951.   SetPadChar(' ');
  952.   SetProtection(Off);
  953.  
  954.   {multiple-choice field}
  955.   AddChoiceField(ESR1, 'Hours/week',17,13,'99',             17, 25,     13,
  956.    1,        @IncChoice,         Scrap.Hours);
  957.  
  958.   {a calculated field}
  959.   SetProtection(On);
  960.   SetPadChar('*');
  961.   AddRealField(ESR1, 'Yearly',   17, 49, CurrMask,          17, 57,     14,
  962.    0,        0,        0,        Scrap.Yearly);
  963.   SetPadChar(' ');
  964.   SetProtection(Off);
  965.  
  966.   AddNestedField(ESR1, 'Notes',  19, 18, '',                19, 25, 2,  15);
  967.  
  968.   {now set up the secondary edit screen}
  969.   InitESrecord(ESR2);
  970.   SetPreEditPtr(ESR2, @DisplayHelpPrompt2);
  971.   SetErrorPtr(ESR2, @ErrorHandler);
  972.   SetWrapMode(ESR2, ExitAtEdges);
  973.   SetAutoAdvance(On);
  974.   SetBeepOnError(ESR2, On);
  975.   SetPadChar('_');
  976.   SetPromptAttr(BoxTextAttr);
  977.   AddStringField(ESR2, 'Work phone number', 13, 25, PhoneMask, 13, 43, 14, 16,
  978.     @ValidatePhone, Scrap.WPhone);
  979.   AddStringField(ESR2, 'Home phone number', 14, 25, PhoneMask, 14, 43, 14, 17,
  980.     @ValidatePhone, Scrap.HPhone);
  981.   SetPromptAttr(TextAttr);
  982.   SetPadChar(' ');
  983.  
  984.   CurrentRec := 1;
  985.   AllDone := False;
  986.   repeat
  987.     {copy the current record into the scrap record used for editing}
  988.     Scrap := InfoRecs[CurrentRec];
  989.  
  990.     {reset the attributes for the Age and Wage fields}
  991.     SetAgeFieldAttribute(ESR1);
  992.     SetWageFieldAttribute(ESR1);
  993.  
  994.     {start editing}
  995.     ExitCommand := EditScreen(ESR1, ESR1.CurrentID, False);
  996.  
  997.     if ExitCommand = ESquit then
  998.       {confirm that the user wants to quit}
  999.       if not ConfirmQuitting then
  1000.         ExitCommand := ESnone;
  1001.  
  1002.     {copy the edited record back if ESC wasn't pressed}
  1003.     if ExitCommand <> ESquit then
  1004.       InfoRecs[CurrentRec] := Scrap;
  1005.  
  1006.     {see if we need to edit another record}
  1007.     case ExitCommand of
  1008.       ESdone,                {^Enter, ^KD, or ^KQ}
  1009.       ESquit :               {ESC}
  1010.         AllDone := True;
  1011.       ESnextRec :            {next record}
  1012.         if CurrentRec < MaxRec then
  1013.           Inc(CurrentRec);
  1014.       ESprevRec :            {previous record}
  1015.         if CurrentRec > 1 then
  1016.           Dec(CurrentRec);
  1017.       ESuser0 :              {toggle Bell on/off}
  1018.         begin
  1019.           SetBeepOnError(ESR1, not ESR1.BeepOnError);
  1020.           SetBeepOnError(ESR2, not ESR2.BeepOnError);
  1021.         end;
  1022.       {$IFDEF UseMouse}
  1023.       ESclickExit,
  1024.       {$ENDIF}
  1025.       ESuser1 :              {pick a state}
  1026.         if ESR1.CurrentID = 4 then
  1027.           PickAState;
  1028.       ESnested :             {handle nested form}
  1029.         if ESR1.CurrentID = 15 then begin
  1030.           {edit the notes field}
  1031.           EditMemoField;
  1032.  
  1033.           {copy the notes field}
  1034.           InfoRecs[CurrentRec].Notes := Scrap.Notes;
  1035.         end
  1036.         {switch to secondary edit screen}
  1037.         else if SecondaryEditScreen then
  1038.           {advance to next field in main screen (Gender)}
  1039.           Inc(ESR1.CurrentID)
  1040.         else
  1041.           {back up to State field}
  1042.           Dec(ESR1.CurrentID, 2);
  1043.     end;
  1044.   until AllDone;
  1045.  
  1046.   {$IFDEF UseMouse}
  1047.   {hide the mouse cursor}
  1048.   HideMouse;
  1049.   {$ENDIF}
  1050.  
  1051.   {these calls are unnecessary in this case}
  1052.   DisposeEditScreen(ESR1);
  1053.   DisposeEditScreen(ESR2);
  1054.   DisposeWindow(WP1);
  1055.   DisposeWindow(WP2);
  1056.  
  1057.   {clean up display}
  1058.   NormVideo;
  1059.   ClrScr;
  1060. end.
  1061.