home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / tug__002 / field.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-08-08  |  33.7 KB  |  1,017 lines

  1. {TUG PDS CERT 1.01 (Pascal)
  2.  
  3. ==========================================================================
  4.  
  5.                   TUG PUBLIC DOMAIN SOFTWARE CERTIFICATION
  6.  
  7. The Turbo User Group (TUG) is recognized by Borland International as the
  8. official support organization for Turbo languages.  This file has been
  9. compiled and verified by the TUG library staff.  We are reasonably certain
  10. that the information contained in this file is public domain material, but
  11. it is also subject to any restrictions applied by its author.
  12.  
  13. This diskette contains PROGRAMS and/or DATA determined to be in the PUBLIC
  14. DOMAIN, provided as a service of TUG for the use of its members.  The
  15. Turbo User Group will not be liable for any damages, including any lost
  16. profits, lost savings or other incidental or consequential damages arising
  17. out of the use of or inability to use the contents, even if TUG has been
  18. advised of the possibility of such damages, or for any claim by any
  19. other party.
  20.  
  21. To the best of our knowledge, the routines in this file compile and function
  22. properly in accordance with the information described below.
  23.  
  24. If you discover an error in this file, we would appreciate it if you would
  25. report it to us.  To report bugs, or to request information on membership
  26. in TUG, please contact us at:
  27.  
  28.              Turbo User Group
  29.              PO Box 1510
  30.              Poulsbo, Washington USA  98370
  31.  
  32. --------------------------------------------------------------------------
  33.                        F i l e    I n f o r m a t i o n
  34.  
  35. * DESCRIPTION
  36. Author Frank Wood. Turbo Pascal 4.0 unit for coding input screens. The
  37. main function locates fields, allows complete editing, and returns
  38. terminating keystroke. Eight fields types with crash proof data entry and
  39. error messages. Menu pick function also included.
  40.  
  41. * ASSOCIATED FILES
  42. FIELD.PAS
  43. FLDDEMO.PAS
  44. FLDTEST.PAS
  45. OLDDEMO.PAS
  46. FIELD.TXT
  47.  
  48. * CHECKED BY
  49. DRM 08/08/88
  50.  
  51. * KEYWORDS
  52. TURBO PASCAL V4.0
  53.  
  54. ==========================================================================
  55. }
  56. Unit field;
  57.  
  58. { FIELD.PAS was developed by Frank Wood from KEYIN.INC by Michael
  59.   H. Hughes.  This material is hereby placed in the Public Domain. }
  60.  
  61. Interface
  62.  
  63. Uses Crt,Dos;
  64.  
  65. { Values returned by ReadyKey for IBM PC keys }
  66. Const backspacekey =  8;  { Cursor left and erase }
  67.       tabkey       =  9;  { Move to field on right }
  68.       shiftabkey   = 15;  { Move to field on left }
  69.       enterkey     = 13;  { Accept field }
  70.       esckey       = 27;  { Exit screen or program }
  71.       spacekey     = 32;  { Space bar }
  72.  
  73.       extendedkey  =  0;  { Nul returned to indicate an extended key }
  74.       insertkey    = 82;  { Toggle insert mode }
  75.       deletekey    = 83;  { Delete a character }
  76.       homekey      = 71;  { Cursor to first position in field }
  77.       endkey       = 79;  { Cursor to end of entry or accept screen }
  78.       uparrowkey   = 72;  { Move to field above }
  79.       dnarrowkey   = 80;  { Move to field below }
  80.       larrowkey    = 75;  { Cursor left }
  81.       rarrowkey    = 77;  { Cursor right }
  82.  
  83. { Special IBM PC characters used in menu screen. }
  84.       pickpointer = $1A;
  85.       pickmarker  = $FE;
  86.  
  87. { Constants to be used with the Boolean variable required. }
  88.       optional  = False;
  89.       manditory = True;
  90.  
  91. Type  message     = string[70];
  92.       fldtypes    = (alsymb,ascii,caplet,digits,usnint,sgnint,usndec,sgndec);
  93.       cursortypes = (hidden,underline,block);
  94.  
  95. Var firstpass: Boolean;   { Kills tabkey, shiftabkey, uparrowkey, dnarrowkey. }
  96.     reversevideo: Boolean;{ Selects reverse video or markers for field. }
  97.     zerovoid: Boolean;    { A required numerical data entry may not be zero. }
  98.     hitxtcolor: Byte;     { Highlight text color    }
  99.     lotxtcolor: Byte;     { Normal text color       }
  100.     txtbkgnd: Byte;       { Screen background color }
  101.  
  102. { "cursor" hides the cursor or switches between block and underline types. }
  103. Procedure cursor(cursortype: cursortypes);
  104.  
  105. { "note" displays an operator message on line 25 of the screen. }
  106. Procedure note(msg: message);
  107.  
  108. { "errmsg" displays an error message on line 25 of the screen. }
  109. Procedure errmsg(msg: message);
  110.  
  111. { "getkey" waits for a keystroke input and returns its numeric value. }
  112. Function getkey(var specialkey:Boolean): Byte;
  113.  
  114. { "getspecialkey" waits for a special keystroke and returns its numeric value.
  115.   An error message is generated if the operator presses an ordinary key. }
  116. Function getspecialkey: Byte;
  117.  
  118. { "editfield" is the master field input routine.  This function will display a
  119.   string, or an integer or real number at a specified position on the screen,
  120.   will allow the operator to enter or edit the data, and place the edited
  121.   result back in the string, integer or real variable.  Each character is
  122.   checked as it is entered and an error message is displayed for any
  123.   inappropriate keys.
  124.  
  125.   The parameters required are as follows:
  126.  
  127.   col,row  - The column and row position of the field.
  128.  
  129.   fldsize  - The maximum field length in character positions.
  130.  
  131.   decpla   - The number of digits allowed right of the decimal point.
  132.  
  133.   fldtype  - The type of data to be entered, specified as follows:
  134.  
  135.                alsymb - All printable symbols.
  136.                lascii - Lower (standard) ASCII characters only.
  137.                caplet - Upper case letters and other ASCII characters.
  138.                         Shifting is not required; lower case letters are
  139.                         converted to upper-case.
  140.                digits - Digits only processed as an ASCII string.
  141.                unsint - Digits only (unsigned integer).
  142.                sgnint - Digits and minus sign.
  143.                unsdec - Digits and decimal point.
  144.                sgndec - Digits, sign, and decimal point.
  145.  
  146.   required - True if data must be entered in this field.  A zero is not
  147.              accepted for a required field if zerovoid = True.
  148.  
  149.   buffer   - The string, integer or real variable that holds the initial value
  150.              and will receive the final value of the field.  If blank on entry
  151.              the routine will display markers to indicate the length of the
  152.              field, otherwise the current contents are displayed.
  153.  
  154.   editfield- This function returns the value of the keystroke that terminates
  155.              the operation. }
  156.  
  157. Function editfield(col,row,fldsize,decpla: Byte; fldtype: fldtypes;
  158.                    required: Boolean; Var buffer): Byte;
  159.  
  160. { "getpick" allows a field to be expressed as a picklist.  Given an array of
  161.   strings, it will display them as a picklist beginning at the specified column
  162.   and row position on the screen.  The operator may then move a pointer up
  163.   and down the list by pressing "spacekey" or "backspacekey".  Pressing a
  164.   letter key will cause the routine to search for a string beginning with
  165.   that letter, and position the pointer on that item.
  166.  
  167.   The parameters required are as follows:
  168.  
  169.   col,row  - The column and row position of the upper left corner of the menu
  170.              block.  This will be 2 places to the left of the leftmost
  171.              character of the first menu text line.
  172.  
  173.   maxpick  - The number of items or lines in the menu
  174.  
  175.   choice   - The number of the item where the pointer is to be positioned
  176.              when the routine is first called.  If a value of 1 is used, the
  177.              pointer will initially be on the first line of the pick list.
  178.              When the function is terminated with the enterkey, this variable
  179.              will contain the number of the item chosen.
  180.  
  181.   picklist - An array of strings, each having a maximum length of 30
  182.              characters.  The number of strings in the array must at least
  183.              as great as the value of "number".  This is an untyped parameter,
  184.              and it is up to the programmer to ensure that the array is of the
  185.              correct dimensions.
  186.  
  187.   getpick  - This function returns the value of the key stroke that terminates
  188.              the operation in the same manner as "editfield".}
  189.  
  190. { Generate A Menu Display and return the number of the choice. }
  191. Function getpick(col,row,maxpick: Byte; Var choice: Byte; Var picklist):Byte;
  192.  
  193. Implementation
  194.  
  195.  
  196. Procedure beep;
  197.  
  198. Begin
  199.   write(chr(7))
  200. End;
  201.  
  202.  
  203. Procedure cursor(cursortype: cursortypes);
  204.  
  205. Var reg: Registers;
  206.     startline: Byte;
  207.     monocrt: Boolean;
  208.  
  209. Begin
  210.   { Check to see if the CRT is monochrome. }
  211.   reg.AH:=$0F;
  212.   Intr($10,reg);           { Use interupt 10 to get display type }
  213.   If reg.AL = $07
  214.   Then monocrt:=True
  215.   Else monocrt:=False;
  216.  
  217.   { Set the startline value for the cursor type chosen. }
  218.   If cursortype = block
  219.   Then startline:=$00
  220.   Else If monocrt
  221.   Then startline:=$0C      { For monochrome cursor endline = $0D }
  222.   Else startline:=$06;     { For CGA cursor endline = $07        }
  223.   If cursortype = hidden
  224.   Then reg.CH:=$20         { This blows cursor into oblivion     }
  225.   Else reg.CH:=startline;
  226.   reg.CL:=07;
  227.   reg.AH:=1;
  228.   Intr($10,reg)            { Use interupt 10 to set startline    }
  229. End;
  230.  
  231.  
  232. Procedure blank(col,row,places: Byte);
  233.  
  234. Var start: Byte;
  235.  
  236. Begin
  237.   GotoXY(col,row);
  238.   For start:=1 To places Do Write(' ');
  239.   GotoXY(col,row)
  240. End;
  241.  
  242. Procedure note(msg: message); { Display a note at line 25 }
  243. Begin
  244.   cursor(hidden);
  245.   blank(1,25,78);
  246.   TextColor(hitxtcolor);
  247.   Write('Note');          { displayed with highlight }
  248.   TextColor(hitxtcolor+Blink);
  249.   Write(': ');            { displayed with blink and highlight }
  250.   TextColor(hitxtcolor);
  251.   Write(msg);             { displayed with highlight }
  252.   TextColor(lotxtcolor)
  253. End;
  254.  
  255. Procedure errmsg(msg: message); { Display an error message at line 25 }
  256. Begin
  257.   TextColor(hitxtcolor+Blink);
  258.   TextBackground(txtbkgnd);
  259.   blank(1,25,78);
  260.   Write(chr(7),'ERROR: ');  { sound bell, display with blink and highlight }
  261.   TextColor(hitxtcolor);
  262.   Write(msg);               { displayed with highlight }
  263.   TextColor(lotxtcolor);
  264. End;
  265.  
  266. { Waits for a key and returns its value }
  267. Function getkey(var specialkey:Boolean): Byte;
  268.  
  269. Var ch: Char;
  270.  
  271. Begin
  272.       ch:=ReadKey;
  273.       If ord(ch) = extendedkey Then
  274.         Begin
  275.           specialkey:=True;
  276.           ch:=ReadKey
  277.         End
  278.       Else If (ord(ch) = backspacekey) Or
  279.               (ord(ch) = tabkey) Or
  280.               (ord(ch) = enterkey) Or
  281.               (ord(ch) = esckey)
  282.       Then specialkey:=True
  283.       Else specialkey:=False;
  284.       getkey:=ord(ch)
  285. End;
  286.  
  287. { Waits for a special key and returns its value }
  288. Function getspecialkey: Byte;
  289.  
  290. Var
  291.   ch: Byte;
  292.   specialkey: Boolean;
  293.  
  294. Begin
  295.   Repeat
  296.     GotoXY(78,25);
  297.     TextColor(hitxtcolor);
  298.     Write(chr($FE));
  299.     GotoXY(78,25);
  300.     TextColor(lotxtcolor);
  301.     cursor(underline);
  302.     ch:=getkey(specialkey);
  303.     If Not specialkey
  304.     Then errmsg('Entry Must be a Special Key!');
  305.   Until specialkey;
  306.   getspecialkey:=ch;
  307. End;
  308.  
  309. { Allows editing of old or entry of new data and returns last keystroke }
  310. Function editfield(col,row,fldsize,decpla: Byte; fldtype: fldtypes;
  311.                    required: Boolean; Var buffer): Byte;
  312.  
  313. Type inputkeys = set of Char;
  314.      intdata = Integer;  { Identifier to typecast untyped variable }
  315.      realdata = Real;    { Identifier to typecast untyped variable }
  316.  
  317. Var field: string[80];   { Holding string for key input }
  318.  
  319.     posn: Byte;          { Current cursor position in field }
  320.     count: Byte;         { Number of characters in field }
  321.     ptr,ctr: Byte;       { Temporary pointer,counter }
  322.     code: Integer;       { Error code returned by Val procedure }
  323.     intvalue: Integer;   { Integer value returned by Val procedure }
  324.     realvalue: Real;     { Real value returned by Val procedure }
  325.  
  326.     specialkey: Boolean; { Key has an extended code }
  327.     numdata: Boolean;    { Data is not a string }
  328.     decdata: Boolean;    { Data is a decimal number }
  329.     empty: Boolean;      { Field is currently blank }
  330.     first: Boolean;      { First character is still being processed }
  331.     edit: Boolean;       { Field is in edit mode, editing key was pressed }
  332.     insert: Boolean;     { Field is in insert mode, insert key was pressed }
  333.     error: Boolean;      { Keying error has occured }
  334.     beyond: Boolean;     { Cursor is beyond last character position in field }
  335.     terminate: Boolean;  { Field entry has been terminated }
  336.     abort: Boolean;      { Field entry has been canceled }
  337.  
  338.     regkeys: Inputkeys;  { All printable keys }
  339.     asckeys: Inputkeys;  { Ordinary ASCII keys }
  340.     digkeys: Inputkeys;  { Digit keys only }
  341.  
  342.     ch: Char;            { Current key pressed }
  343.     chval: Byte;         { Ord() of current key pressed }
  344.     datablock: Byte;     { Symbol showing unused position in field }
  345.  
  346. { Changes colors and datablock character as required }
  347. Procedure inscrn(input: Boolean);
  348.  
  349. Begin
  350.   If reversevideo Then           { Reverse video display }
  351.     Begin
  352.       If input Then              { Reverse }
  353.         Begin
  354.           TextColor(txtbkgnd);
  355.           TextBackground(lotxtcolor)
  356.         End
  357.       Else                       { Normal }
  358.         Begin
  359.           TextColor(lotxtcolor);
  360.           TextBackground(txtbkgnd)
  361.         End;
  362.       datablock:=$20             { A blank space for reverse video }
  363.     End
  364.   Else                           { Regular display }
  365.     Begin
  366.       If input Then              { Highlight }
  367.         TextColor(hitxtcolor)
  368.       Else
  369.         TextColor(lotxtcolor);   { Normal }
  370.       TextBackground(txtbkgnd);
  371.       datablock:=$FE             { The regular block synbol }
  372.     End
  373. End;
  374.  
  375. Begin { editfield function }
  376.  
  377.   { Set display }
  378.   inscrn(False);
  379.  
  380.   { Determine data type }
  381.   If fldtype > digits Then numdata:=True Else numdata:=False;
  382.   If fldtype > sgnint Then decdata:=True Else decdata:=False;
  383.  
  384.   { Load data from buffer to "field" and initialize field length }
  385.   If numdata Then
  386.     If decdata Then
  387.       Begin
  388.         If (fldtype = usndec) Then
  389.           Begin
  390.             If (decpla <> 0) And (fldsize < 3) Then fldsize:=3;
  391.             If (decpla <> 0) And (decpla > fldsize-2) Then decpla:=fldsize-2
  392.           End
  393.         Else
  394.           Begin
  395.             If (decpla = 0) And (fldsize < 2) Then fldsize:=2;
  396.             If (decpla <> 0) And (fldsize < 4) Then fldsize:=4;
  397.             If (decpla <> 0) And (decpla > fldsize-3) Then decpla:=fldsize-3
  398.           End;
  399.         str(realdata(buffer):fldsize:decpla,field)
  400.       End
  401.     Else
  402.       Begin
  403.         If (fldtype = sgnint) And (fldsize < 2) Then fldsize:=2;
  404.         str(intdata(buffer):fldsize,field)
  405.       End
  406.   Else
  407.     Begin
  408.       move(buffer,ch,1);
  409.       move(buffer,field,ord(ch)+1)
  410.     End;
  411.   If length(field) > fldsize Then field[0]:=chr(fldsize);
  412.   If length(field) < fldsize Then
  413.     For posn:=length(field)+1 To fldsize Do field[posn]:=chr(datablock);
  414.   count:=length(field);
  415.   If count = 0 Then empty:=True Else empty:=False;
  416.   field[0]:=chr(fldsize);
  417.  
  418.   { Delete leading blanks }
  419.   While numdata And (field[1] = ' ') Do
  420.     If count = 1 Then
  421.       Begin
  422.         field[1]:=chr(datablock);
  423.         count:=0
  424.       End
  425.     Else
  426.       Begin
  427.         move(field[2],field[1],fldsize-1);
  428.         field[fldsize]:=chr(datablock);
  429.         count:=pred(count)
  430.       End;
  431.  
  432.   { Clear message line and display existing value }
  433.   blank(1,25,78);
  434.   cursor(hidden);
  435.   inscrn(True);
  436.   GotoXY(col,row);
  437.   Write(field);
  438.   GotoXY(col,row);
  439.  
  440.   { Initialize conditions }
  441.   regkeys:=[#1..#6,#11..#12,#14..#26,#28..#31,#32..#255];
  442.   asckeys:=[#32..#127];
  443.   digkeys:=[#48..#57];
  444.   posn:=1; insert:=False; edit:=False; first:=True;
  445.   error:=False; terminate:=False; abort:=False;
  446.   editfield:=0;
  447.  
  448.   { Get input from keyboard }
  449.   Repeat  { Until valid data or aborted }
  450.  
  451.     Repeat  { Until field entry terminated }
  452.  
  453.       { Reset cursor position and turn cursor on }
  454.       If error Then
  455.         Begin
  456.           GotoXY(col+posn-1,row);
  457.           inscrn(False)
  458.         End;
  459.       If insert Then cursor(block) Else cursor(underline);
  460.  
  461.       { Get character and turn cursor off }
  462.       chval:=getkey(specialkey);
  463.       cursor(hidden);
  464.       ch:=chr(chval);
  465.  
  466.       { Erase message line and reset cursor and attributes }
  467.       If error Then
  468.         Begin
  469.           blank(1,25,78);
  470.           GotoXY(col+posn-1,row);
  471.           inscrn(True);
  472.           error:=False
  473.         End;
  474.  
  475.       { Check if cursor is beyond end of field }
  476.       If posn <= fldsize Then beyond:=False Else beyond:=True;
  477.  
  478.       { Select proper response to the key pressed }
  479.       If specialkey Then Case chval Of
  480.  
  481.         esckey,
  482.         uparrowkey,
  483.         dnarrowkey,
  484.         tabkey,
  485.         shiftabkey:
  486.              If firstpass and Not (chval = esckey) Then
  487.                beep
  488.              Else
  489.                Begin
  490.                  { Set function return value }
  491.                  Case chval Of
  492.                    esckey:     editfield:=esckey;
  493.                    uparrowkey: editfield:=uparrowkey;
  494.                    dnarrowkey: editfield:=dnarrowkey;
  495.                    tabkey:     editfield:=tabkey;
  496.                    shiftabkey: editfield:=shiftabkey
  497.                  End;
  498.                  insert:=False;
  499.                  abort:=True;
  500.                  terminate:=True
  501.                End;
  502.  
  503.         enterkey:
  504.              Begin
  505.                { Accept data and terminate }
  506.                If empty And required Then
  507.                  Begin   { required field empty }
  508.                    errmsg('You Must Enter Data for This Item!');
  509.                    error:=True
  510.                  End;
  511.                If Not error Then
  512.                  Begin
  513.                    { accept existing data }
  514.                    If first And Not edit And Not numdata Then
  515.                      Begin
  516.                        move(buffer,field,fldsize+1);
  517.                        If length(field) > fldsize Then field[0]:=chr(fldsize)
  518.                      End;
  519.                    editfield:=enterkey;
  520.                    terminate:=True
  521.                  End;
  522.                insert:=false
  523.              End;
  524.  
  525.         rarrowkey:
  526.              Begin
  527.                { cursor right }
  528.                edit:=True;
  529.                If (posn <= count) and (posn < fldsize) Then
  530.                  Begin
  531.                    Inc(posn);
  532.                    GotoXY(col+posn-1,row)
  533.                  End
  534.                Else beep
  535.              End;
  536.  
  537.         larrowkey:
  538.              Begin
  539.                { cursor left }
  540.                edit:=True;
  541.                If posn > 1 Then
  542.                  Begin
  543.                    Dec(posn);
  544.                    GotoXY(col+posn-1,row)
  545.                  End
  546.                Else beep
  547.              End;
  548.  
  549.         homekey:
  550.              Begin
  551.                { cursor to first position in field }
  552.                edit:=True;
  553.                If posn > 1 Then
  554.                  Begin
  555.                    posn:=1;
  556.                    GotoXY(col,row)
  557.                  End
  558.                Else beep
  559.              End;
  560.  
  561.         endkey:
  562.              Begin
  563.                { cursor right }
  564.                edit:=True;
  565.                If posn <= count Then
  566.                  Begin
  567.                    posn:=succ(count);
  568.                    GotoXY(col+posn-1,row)
  569.                  End
  570.                Else beep
  571.              End;
  572.  
  573.         insertkey:
  574.              Begin
  575.                edit:=True;
  576.                insert:=not insert
  577.              End;
  578.  
  579.         backspacekey:
  580.              Begin
  581.                { Destructive backspace }
  582.                If posn > 1 Then
  583.                  Begin
  584.                    posn:=pred(posn);
  585.                    If posn < count+1 Then
  586.                      Begin
  587.                        move(field[posn+1],field[posn],fldsize-posn);
  588.                        count:=pred(count);
  589.                        If count = 0 Then empty:=True Else empty:=False;
  590.                        field[fldsize]:=chr(datablock);
  591.                        GotoXY(col,row);
  592.                        Write(field);
  593.                        GotoXY(col+posn-1,row)
  594.                      End
  595.                  End
  596.                Else beep
  597.              End;
  598.  
  599.         deletekey:
  600.              Begin
  601.                { Delete the character at the cursor position }
  602.                edit:=True;
  603.                If posn < count+1 Then
  604.                  Begin
  605.                    move(field[posn+1],field[posn],fldsize-posn);
  606.                    count:=pred(count);
  607.                    If count = 0 Then empty:=True Else empty:=False;
  608.                    field[fldsize]:=chr(datablock);
  609.                    GotoXY(col,row);
  610.                    Write(field);
  611.                    GotoXY(col+posn-1,row)
  612.                  End
  613.              End
  614.  
  615.         Else beep  { Ignore other specialkeys }
  616.       End  { specialkey case statement }
  617.  
  618.       Else If beyond Then beep
  619.  
  620.       Else If ch in regkeys Then
  621.         Begin
  622.           { Character (Printable) key }
  623.           If first And Not empty And Not edit Then
  624.             Begin
  625.               { Clear the current field if first key press is data }
  626.               fillchar(field[1],fldsize,chr(datablock));
  627.               GotoXY(col,row);
  628.               Write(field);
  629.               GotoXY(col,row);
  630.               count:=0; posn:=1; empty:=True;
  631.             End;
  632.  
  633.           { Validate key }
  634.           Case fldtype Of
  635.             alsymb:;
  636.             ascii,
  637.             caplet:
  638.                  If Not (ch in asckeys) Then
  639.                    Begin
  640.                      errmsg('Entry Must be an Ordinary ASCII Character!');
  641.                      error:=True
  642.                    End
  643.                  Else If fldtype = caplet Then
  644.                    ch:=UpCase(ch);
  645.             digits,
  646.             usnint:
  647.                  If Not (ch in digkeys) Then
  648.                    Begin
  649.                      errmsg('Entry Must be a Digit!');
  650.                      error:=True
  651.                    End;
  652.             sgnint:
  653.                  If Not (ch in digkeys)
  654.                  And Not ((ch = '-') And (posn = 1)) Then
  655.                    Begin
  656.                      errmsg('Entry Must be Digit or Initial Minus Sign!');
  657.                      error:=True
  658.                    End;
  659.             usndec:
  660.                  If Not (ch in digkeys)
  661.                  And Not ((ch = '.') And (pos('.',field) = 0))
  662.                  And Not ((ch = '.') And (pos('.',field) = posn)) Then
  663.                    Begin
  664.                      errmsg('Entry Must be Digit or Decimal Point!');
  665.                      error:=true
  666.                    End;
  667.             sgndec:
  668.                  If Not (ch in digkeys)
  669.                  And Not ((ch = '-') And (posn = 1))
  670.                  And Not ((ch = '.') And (pos('.',field) = 0))
  671.                  And Not ((ch = '.') And (pos('.',field) = posn)) Then
  672.                    Begin
  673.                      errmsg
  674.                      ('Must be Digit, Initial Minus Sign, or Declimal Point!');
  675.                      error:=True
  676.                    End
  677.                  Else
  678.             Else
  679.           End; { fldtype Case statement }
  680.  
  681.           { Display the character and update the pointers }
  682.           If not error And insert And (count = fldsize) Then
  683.             Begin
  684.               errmsg('Field is Full!');
  685.               error:=True
  686.             End
  687.           Else
  688.             If not error And insert and (field[posn] = '-') Then
  689.               Begin
  690.                 errmsg('Insertion Ahead of Minus Sign Not Allowed!');
  691.                 error:=True
  692.               End
  693.           Else
  694.             If not error Then
  695.               Begin
  696.                 { Insert a space at the cursor position }
  697.                 If insert and (posn <= count) Then
  698.                   Begin
  699.                     move(field[posn],field[posn+1],fldsize-posn);
  700.                     Inc(count);
  701.                     field[posn]:=' ';
  702.                     GotoXY(col,row);
  703.                     Write(field);
  704.                     GotoXY(col+posn-1,row)
  705.                   End;
  706.                 Write(ch);
  707.                 field[posn]:=ch;
  708.                 If posn > count Then count:=posn;
  709.                 If posn <= fldsize Then Inc(posn);
  710.                 first:=False; empty:=False
  711.               End
  712.         End    { printable character case }
  713.  
  714.       Else beep;
  715.  
  716.     Until terminate; { End of input }
  717.  
  718.     { Input Complete; Validate and Format or Abort }
  719.     field[0]:=chr(count);
  720.     If Not abort Then
  721.       Begin
  722.         If numdata Then
  723.           Begin
  724.             { Delete extra leading zeros }
  725.             While (count > 1) And (field[1] = '0')
  726.                   And (field[2] <> '.') Do
  727.               Begin
  728.                 move(field[2],field[1],fldsize-1);
  729.                 field[fldsize]:=chr(datablock);
  730.                 Dec(count);
  731.                 field[0]:=chr(count)
  732.               End;
  733.             While (count > 2) And (field[1] = '-')
  734.                   And (field[2] = '0') And (field[3] <> '.') Do
  735.               Begin
  736.                 move(field[3],field[2],fldsize-2);
  737.                 field[fldsize]:=chr(datablock);
  738.                 Dec(count);
  739.                 field[0]:=chr(count)
  740.               End;
  741.             { Place a zero in an empty field or add a zero where needed }
  742.             If count = 0 Then
  743.               Begin
  744.                 Inc(count);
  745.                 field[0]:=chr(count);
  746.                 field[1]:='0'
  747.               End
  748.             Else If field[1] = '.' Then
  749.               Begin
  750.                 Inc(count);
  751.                 field[0]:=chr(count);
  752.                 move(field[1],field[2],count-1);
  753.                 field[1]:='0'
  754.               End
  755.             Else If (field[1] = '-') And ((field[2] = '.') Or (count = 1)) Then
  756.               Begin
  757.                 Inc(count);
  758.                 field[0]:=chr(count);
  759.                 move(field[2],field[3],count-2);
  760.                 field[2]:='0'
  761.               End;
  762.             If field[count] = '.' Then
  763.               If (decpla <> 0) Then
  764.                 Begin
  765.                   Inc(count);
  766.                   field[0]:=chr(count);
  767.                   field[count]:='0'
  768.                 End
  769.               Else
  770.                 Begin
  771.                   field[count]:=chr(datablock);
  772.                   Dec(count);
  773.                   field[0]:=chr(count)
  774.                 End;
  775.             val(field,realvalue,code);
  776.             { check for zero value when entry is required }
  777.             If required And (realvalue = 0) And zerovoid Then
  778.               Begin
  779.                 errmsg('Zero is Not a Valid Entry!');
  780.                 If count > fldsize Then count:=fldsize;
  781.                 error:=True; posn:=1; edit:=True;
  782.                 terminate:=False
  783.               End
  784.             Else If decdata Then
  785.               Begin
  786.                 field[0]:=chr(fldsize);
  787.                 ptr:=pos('.',field);
  788.                 { Check for too many digits }
  789.                 If (decpla > 0) And (((ptr > 0) And (ptr+decpla > fldsize))
  790.                     Or ((ptr = 0) And (count+decpla > fldsize-1))) Then
  791.                   Begin
  792.                     errmsg('Too Many Digits before Decimal Point!');
  793.                     If count > fldsize Then count:=fldsize;
  794.                     error:=True; edit:=True; terminate:=False;
  795.                     posn:=1
  796.                   End
  797.                 Else If ((count-ptr) > decpla) And Not (ptr = 0) Then
  798.                   Begin
  799.                     errmsg('Too Many Digits after Decimal Point!');
  800.                     If count > fldsize Then count:=fldsize;
  801.                     error:=True; edit:=True; terminate:=False;
  802.                     posn:=count+1
  803.                   End
  804.                 Else
  805.                   Begin
  806.                     field[0]:=chr(count);
  807.                     realdata(buffer):=realvalue
  808.                   End
  809.               End
  810.             Else { Integer data }
  811.               Begin
  812.                 val(field,intvalue,code);
  813.                 If (code = 0) And (field[1] <> '-')
  814.                 And Not ((intvalue >= 0) And (intvalue <= 32767)) Then
  815.                   Begin
  816.                     errmsg('Invalid Entry, Maximum Integer is 32767!');
  817.                     error:=True; edit:=True; terminate:=False;
  818.                     posn:=1
  819.                   End
  820.                 Else If (code = 0) And (field[1] = '-')
  821.                 And Not ((intvalue >= -32768) And (intvalue <= 0)) Then
  822.                   Begin
  823.                     errmsg('Invalid Entry, Minimum Integer is -32768!');
  824.                     error:=True; edit:=True; terminate:=False;
  825.                     posn:=1
  826.                   End
  827.                 Else intdata(buffer):=intvalue
  828.               End
  829.           End
  830.         Else { String data }
  831.           Begin
  832.             { Set count for blank field to zero }
  833.             ptr:=1;
  834.             While (field[ptr] = ' ') And (ptr < count) Do Inc(ptr);
  835.             If (field[ptr] = ' ') And (ptr = count) Then
  836.               Begin
  837.                 If required Then
  838.                   Begin
  839.                     errmsg('You Must Enter Data Not Blanks!');
  840.                     error:=True; posn:=1; edit:=True;
  841.                     terminate:=False
  842.                   End
  843.                 Else
  844.                   Begin
  845.                     field[0]:=chr(0);
  846.                     count:=0
  847.                   End
  848.               End
  849.           End;
  850.         { Display the field and load it to the buffer }
  851.         If Not error Then
  852.           Begin
  853.             inscrn(False);
  854.             blank(col,row,fldsize);
  855.             If numdata Then
  856.               If decdata Then
  857.                 Write(realdata(buffer):fldsize:decpla)
  858.               Else { Integer data }
  859.                 Write(intdata(buffer):fldsize)
  860.             Else { String data }
  861.               Begin
  862.                 Write(field);
  863.                 move(field,buffer,length(field)+1)
  864.               End;
  865.             sound(80);  { Make a clicking sound }
  866.             delay(3);   { to confirm successful }
  867.             nosound     { entry of data!        }
  868.           End
  869.         Else { Error }
  870.           If numdata Then
  871.             Begin
  872.               field[0]:=chr(fldsize);
  873.               inscrn(True);
  874.               blank(col,row,fldsize);
  875.               Write(field)
  876.             End
  877.       End
  878.     Else { Abort }
  879.       { Restore original data and exit without change }
  880.       Begin
  881.         inscrn(False);
  882.         blank(col,row,fldsize); { Erase field }
  883.         If numdata Then
  884.           If decdata Then
  885.             Write(realdata(buffer):fldsize:decpla)
  886.           Else { Integer data }
  887.             Write(intdata(buffer):fldsize)
  888.         Else { String data }
  889.           Begin
  890.             move(buffer,ch,1);
  891.             move(buffer,field,ord(ch)+1);
  892.             If length(field) > fldsize Then
  893.               field[0]:=chr(fldsize);
  894.             Write(field)
  895.           End
  896.       End;
  897.  
  898.   Until terminate
  899. End;  { editfield }
  900.  
  901. Function getpick(col,row,maxpick: Byte; Var choice: Byte; Var picklist):Byte;
  902.  
  903.   Const maxnumber=20; { maximum size of list array }
  904.  
  905.   Type listtype=Array[1..maxnumber] Of String[30];
  906.  
  907.   Var list: listtype Absolute picklist;
  908.       picknum, count, chval, initial: Byte;
  909.       pointer, marker: String[3];
  910.       firstletter: String[1];
  911.       ch: Char;
  912.       specialkey: Boolean;
  913.  
  914.   Begin
  915.     pointer:='   ';
  916.     pointer[2]:=chr(pickpointer);
  917.     marker:='   ';
  918.     marker[2]:=chr(pickmarker);
  919.     cursor(hidden);
  920.     TextColor(lotxtcolor);
  921.  
  922.     { Display list }
  923.     For picknum:=1 To maxpick Do
  924.       Begin
  925.         GotoXY(col,picknum+row-1);
  926.         Write(marker,list[picknum])
  927.       End;
  928.     note('SPACE, BACKSPACE or First Letter to Move; ENTER to Select!');
  929.  
  930.     { Pick menu }
  931.     picknum:=choice;
  932.     initial:=choice;
  933.     getpick:=0;
  934.     Repeat
  935.       { Display current pick }
  936.       GotoXY(col,row+picknum-1);
  937.       TextColor(hitxtcolor+Blink);
  938.       Write(pointer);
  939.       TextColor(hitxtcolor);
  940.       Write(list[picknum]);
  941.       { Get Keyboard and clear current pick }
  942.       chval:=getkey(specialkey);
  943.       GotoXY(col,row+picknum-1);
  944.       TextColor(hitxtcolor);
  945.       Write(pointer); { Kill blink on pointer }
  946.       GotoXY(col,row+picknum-1);
  947.       TextColor(lotxtcolor);
  948.       If (chval <> enterkey) Then
  949.         Write(marker,list[picknum]);
  950.       { If abort, reset initial pick }
  951.       If (chval = uparrowkey) Or
  952.          (chval = dnarrowkey) Or
  953.          (chval = tabkey) Or
  954.          (chval = shiftabkey) Or
  955.          (chval = esckey) Then
  956.         Begin
  957.           GotoXY(col,row+initial-1);
  958.           TextColor(hitxtcolor);
  959.           Write(pointer,list[initial])
  960.         End;
  961.  
  962.       { Determine new Pick }
  963.       Case chval Of
  964.         enterkey:
  965.             Begin
  966.               getpick:=enterkey;
  967.               choice:=picknum
  968.             End;
  969.         endkey:
  970.             picknum:=maxpick;
  971.         homekey:
  972.             picknum:=1;
  973.         esckey:
  974.             getpick:=esckey;
  975.         uparrowkey:
  976.             If firstpass Then beep
  977.             Else getpick:=uparrowkey;
  978.         dnarrowkey:
  979.             If firstpass Then beep
  980.             Else getpick:=dnarrowkey;
  981.         tabkey:
  982.             If firstpass Then beep
  983.             Else getpick:=tabkey;
  984.         shiftabkey:
  985.             If firstpass Then beep
  986.             Else getpick:=shiftabkey;
  987.         backspacekey:
  988.             If picknum > 1 Then Dec(picknum)
  989.             Else picknum:=maxpick;
  990.         spacekey:
  991.             If picknum < (maxpick) Then Inc(picknum)
  992.             Else picknum:=1
  993.         Else { default case }
  994.           Begin
  995.             { Check for first character of line }
  996.             count:=picknum;
  997.             ch:=UpCase(chr(chval));
  998.             Repeat
  999.               Inc(count);
  1000.               If count > maxpick Then count:=1;
  1001.               firstletter:=copy(list[count],1,1);
  1002.             Until (count = picknum)
  1003.                Or (ch = UpCase(firstletter[1]));
  1004.             picknum:=count
  1005.           End
  1006.       End;   { chval Case statement }
  1007.  
  1008.     Until (chval = enterkey) Or
  1009.           (chval = esckey) Or
  1010.           (chval = uparrowkey) Or
  1011.           (chval = dnarrowkey) Or
  1012.           (chval = tabkey) Or
  1013.           (chval = shiftabkey)
  1014.   End;
  1015.  
  1016. End.
  1017.