home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1989 / 11 / dunteman.lst < prev    next >
File List  |  1989-10-04  |  13KB  |  544 lines

  1. _STRUCTURED PROGRAMMING_
  2. by Jeff Duntemann
  3.  
  4. [LISTING ONE]
  5.  
  6. Unit Fields;
  7.  
  8. INTERFACE
  9.  
  10.  
  11. USES Crt;
  12.  
  13. CONST
  14.   IntChars  = ['0'..'9','-'];
  15.   TextChars = [#0..#255];
  16.   Visible   = True;
  17.   Invisible = False;
  18.  
  19. TYPE
  20.   String10 = String[10];
  21.   String80 = String[80];
  22.   CharSet  = SET OF Char;
  23.  
  24.   PositionPtr = ^TextPosition;
  25.   TextPosition =               { ABSTRACT! }
  26.     OBJECT
  27.       X,Y     : Integer;       { Coordinates of location on the screen }
  28.       CONSTRUCTOR Init(InitX,InitY : Integer);
  29.       FUNCTION    XPos : Integer;
  30.       FUNCTION    YPos : Integer;
  31.     END;
  32.  
  33.   FieldPtr = ^Field;
  34.   Field =                      { ABSTRACT! }
  35.     OBJECT(TextPosition)
  36.       VisibleState : Boolean;  { True = Field is displayed }
  37.       CONSTRUCTOR Init(InitX,InitY : Integer;
  38.                        InitVisible : Boolean);
  39.       FUNCTION    IsVisible : Boolean;
  40.       PROCEDURE   MoveTo(NewX,NewY : Integer);
  41.       PROCEDURE   Show; VIRTUAL;
  42.       PROCEDURE   Hide; VIRTUAL;
  43.       PROCEDURE   Edit; VIRTUAL;
  44.     END;
  45.  
  46.   TextFieldPtr = ^TextField;
  47.   TextField =                  { For ordinary text strings }
  48.     OBJECT(Field)
  49.       StringData  : String80;
  50.       FieldLength : Integer;
  51.       CONSTRUCTOR Init(InitX,InitY : Integer;
  52.                        InitVisible : Boolean;
  53.                        InitText    : String80;
  54.                        InitLength  : Integer);
  55.       FUNCTION    GetData : String80;
  56.       PROCEDURE   Show; VIRTUAL;
  57.       PROCEDURE   Hide; VIRTUAL;
  58.       PROCEDURE   Edit; VIRTUAL;
  59.     END;
  60.  
  61.   BooleanFieldPtr = ^BooleanField;
  62.   BooleanField =
  63.     OBJECT(Field)
  64.       Toggle : Boolean;
  65.       TrueString,FalseString : String80;
  66.       CONSTRUCTOR Init(InitX,InitY : Integer;
  67.                        InitVisible : Boolean;
  68.                        InitToggle  : Boolean;
  69.                        InitTrueStr,
  70.                        InitFalseStr : String80);
  71.       FUNCTION    Getdata : Boolean;
  72.       PROCEDURE   Show; VIRTUAL;
  73.       PROCEDURE   Hide; VIRTUAL;
  74.       PROCEDURE   Edit; VIRTUAL;
  75.     END;
  76.  
  77.   IntFieldPtr = ^IntField;
  78.   IntField =
  79.     OBJECT(TextField)
  80.       IntVal : Integer;
  81.       CONSTRUCTOR Init(InitX,InitY : Integer;
  82.                        InitVisible : Boolean;
  83.                        InitIntVal : Integer);
  84.       FUNCTION    GetData : Integer;
  85.       PROCEDURE   Show; VIRTUAL;
  86.       PROCEDURE   Edit; VIRTUAL;
  87.     END;
  88.  
  89.  
  90. IMPLEMENTATION
  91.  
  92.  
  93. VAR
  94.   Blanker   : String80;
  95.  
  96.  
  97.  
  98. FUNCTION MaxLength(String1,String2 : String) : Integer;
  99.  
  100. BEGIN
  101.   IF Length(String1) > Length(String2) THEN
  102.     MaxLength := Length(String1)
  103.   ELSE
  104.     MaxLength := Length(String2);
  105. END;
  106.  
  107.  
  108. PROCEDURE ShowBlanks(NumberOfBlanks : Integer);
  109.  
  110. BEGIN
  111.   Write(Copy(Blanker,1,NumberOfBlanks));
  112. END;
  113.  
  114.  
  115. PROCEDURE HighLight(X,Y,TargetLength : Integer; TargetText : String);
  116.  
  117. BEGIN
  118.   GotoXY(X,Y); ShowBlanks(TargetLength);
  119.   GotoXY(X,Y); Write(TargetText);
  120. END;
  121.  
  122.  
  123. PROCEDURE UhUh;
  124.  
  125. BEGIN
  126.   Sound(35);    { Make first grunt }
  127.   Delay(100);
  128.   NoSound;
  129.   Delay(50);    { Delay between grunts }
  130.   Sound(35);    { Make second grunt }
  131.   Delay(100);
  132.   NoSound;
  133.   Delay(50);    { Delay after second grunt }
  134. END;
  135.  
  136.  
  137.  
  138.  
  139. PROCEDURE GetLine(X,Y : Integer;
  140.                   VAR MyLine : String80;
  141.                   MaxWidth   : Integer;
  142.                   LegalChars : CharSet);
  143.  
  144. VAR
  145.   Ch        : Char;
  146.   Quit,Done : Boolean;
  147.   TempLine  : String;
  148.   WorkPoint : Integer;
  149.  
  150.  
  151.   PROCEDURE DisplayLine;
  152.  
  153.   BEGIN
  154.     GotoXY(X,Y);
  155.     Write(TempLine);
  156.   END;
  157.  
  158.  
  159. BEGIN
  160.   Quit := False; Done := False;
  161.   TempLine := MyLine;
  162.   DisplayLine;
  163.   REPEAT
  164.     IF KeyPressed THEN
  165.       BEGIN
  166.         WorkPoint := (WhereX-X) + 1;
  167.         Ch := ReadKey;
  168.         CASE Ord(Ch) OF
  169.          0  : BEGIN             { If the first char is 0, there's more... }
  170.                 Ch := ReadKey;  { Get the second portion }
  171.                 CASE Ord(Ch) OF
  172.                  71 : GotoXY(X,Y);  { Home }
  173.                  79 : GotoXY(X + Length(TempLine),Y);
  174.  
  175.                  75 : IF WorkPoint <= 1 THEN Uhuh   { Left Arrow }
  176.                       ELSE
  177.                         BEGIN
  178.                           Dec(WorkPoint);
  179.                           GotoXY(X+WorkPoint-1,Y);
  180.                         END;
  181.  
  182.                  83 : BEGIN    { Del }
  183.                         Delete(TempLine,WorkPoint,1);
  184.                         DisplayLine;
  185.                         Write(' ');
  186.                         GotoXY(X+WorkPoint-1,Y);
  187.                       END;
  188.  
  189.                 END { case }
  190.               END;
  191.           8 : IF WorkPoint <= 1 THEN Uhuh
  192.                 ELSE
  193.                   BEGIN
  194.                     Dec(WorkPoint);               { Move left one position }
  195.                     Delete(TempLine,WorkPoint,1); { Delete a char in string }
  196.                     DisplayLine;                  { Re-display the string }
  197.                     Write(' ');                   { Erase the last char }
  198.                     GotoXY(X+WorkPoint-1,Y);      { And put the cursor back }
  199.                   END;                            { to the correct position }
  200.          13 : Done := True;    { Enter }
  201.          27 : Quit := True;    { Esc }
  202.  
  203.          32..254 : IF Ch IN LegalChars THEN
  204.                      IF Length(TempLine) >= MaxWidth THEN UhUh
  205.                        ELSE
  206.                          BEGIN
  207.                            Insert(Ch,TempLine,WorkPoint);
  208.                            DisplayLine;
  209.                            GotoXY(X+WorkPoint,Y);
  210.                          END
  211.                    ELSE Uhuh;
  212.          END { case }
  213.       END;
  214.   UNTIL Done OR Quit;
  215.   IF Done THEN MyLine := TempLine;
  216. END;
  217.  
  218.  
  219.  
  220.  
  221. {------------------------------------------------------------------}
  222. {  All of the following routines are method implementations        }
  223. {------------------------------------------------------------------}
  224.  
  225.  
  226. CONSTRUCTOR TextPosition.Init(InitX,InitY : Integer);
  227.  
  228. BEGIN
  229.   X := InitX; Y := InitY;
  230. END;
  231.  
  232.  
  233. FUNCTION TextPosition.XPos : Integer;
  234.  
  235. BEGIN
  236.   XPos := X;
  237. END;
  238.  
  239.  
  240. FUNCTION TextPosition.YPos : Integer;
  241.  
  242. BEGIN
  243.   YPos := Y;
  244. END;
  245.  
  246.  
  247. CONSTRUCTOR Field.Init(InitX,InitY : Integer;
  248.                        InitVisible : Boolean);
  249.  
  250. BEGIN
  251.   TextPosition.Init(InitX,InitY);
  252.   VisibleState := InitVisible;
  253. END;
  254.  
  255.  
  256. FUNCTION Field.IsVisible : Boolean;
  257.  
  258. BEGIN
  259.   IsVisible := VisibleState;
  260. END;
  261.  
  262.  
  263. PROCEDURE Field.MoveTo(NewX,NewY : Integer);
  264.  
  265. BEGIN
  266.   IF IsVisible THEN Hide;
  267.   X := NewX;
  268.   Y := NewY;
  269.   IF IsVisible THEN Show;
  270. END;
  271.  
  272.  
  273. PROCEDURE Field.Show;
  274.  
  275. BEGIN
  276. END;
  277.  
  278.  
  279. PROCEDURE Field.Hide;
  280.  
  281. BEGIN
  282. END;
  283.  
  284.  
  285. PROCEDURE Field.Edit;
  286.  
  287. BEGIN
  288. END;
  289.  
  290.  
  291. CONSTRUCTOR TextField.Init(InitX,InitY : Integer;
  292.                            InitVisible : Boolean;
  293.                            InitText    : String80;
  294.                            InitLength  : Integer);
  295.  
  296. BEGIN
  297.   Field.Init(InitX,InitY,InitVisible);
  298.   StringData := InitText;
  299.   FieldLength := InitLength;
  300.   IF InitVisible THEN Show;
  301. END;
  302.  
  303.  
  304. FUNCTION TextField.Getdata : String80;
  305.  
  306. BEGIN
  307.   Getdata := StringData;
  308. END;
  309.  
  310.  
  311. PROCEDURE TextField.Show;
  312.  
  313. BEGIN
  314.   GotoXY(XPos,YPos);
  315.   Write(StringData);
  316.   VisibleState := True;
  317. END;
  318.  
  319.  
  320. PROCEDURE TextField.Hide;
  321.  
  322. BEGIN
  323.   GotoXY(XPos,YPos);
  324.   ShowBlanks(FieldLength);
  325.   VisibleState := False;
  326. END;
  327.  
  328.  
  329. PROCEDURE TextField.Edit;
  330.  
  331. VAR
  332.   AttributeStash : Byte;
  333.  
  334. BEGIN
  335.   IF IsVisible THEN
  336.     BEGIN
  337.       AttributeStash := TextAttr;
  338.       TextAttr := $70;
  339.       HighLight(XPos,YPos,FieldLength,StringData);
  340.       GetLine(XPos,YPos,StringData,FieldLength,TextChars);
  341.       TextAttr := AttributeStash;
  342.       HighLight(XPos,YPos,FieldLength,StringData);
  343.     END;
  344. END;
  345.  
  346.  
  347. CONSTRUCTOR BooleanField.Init(InitX,InitY : Integer;
  348.                               InitVisible : Boolean;
  349.                               InitToggle  : Boolean;
  350.                               InitTrueStr,
  351.                               InitFalseStr : String80);
  352.  
  353. BEGIN
  354.   Field.Init(InitX,InitY,InitVisible);
  355.   Toggle := InitToggle;
  356.   TrueString := InitTrueStr;
  357.   FalseString := InitFalseStr;
  358.   IF InitVisible THEN Show;
  359. END;
  360.  
  361.  
  362. FUNCTION BooleanField.Getdata : Boolean;
  363.  
  364. BEGIN
  365.   Getdata := Toggle;
  366. END;
  367.  
  368.  
  369. PROCEDURE BooleanField.Show;
  370.  
  371. BEGIN
  372.   GotoXY(XPos,YPos);
  373.   IF Toggle THEN Write(TrueString)
  374.     ELSE Write(FalseString);
  375.   VisibleState := True;
  376. END;
  377.  
  378.  
  379. PROCEDURE BooleanField.Hide;
  380.  
  381. BEGIN
  382.   GotoXY(XPos,YPos);
  383.   IF Toggle THEN ShowBlanks(Length(TrueString))
  384.     ELSE ShowBlanks(Length(FalseString));
  385.   VisibleState := False;
  386. END;
  387.  
  388.  
  389. PROCEDURE BooleanField.Edit;
  390.  
  391. VAR
  392.   Ch             : Char;
  393.   Done,Quit      : Boolean;
  394.   SaveState      : Boolean;
  395.   AttributeStash : Byte;
  396.  
  397. BEGIN
  398.   IF IsVisible THEN  { Only edit if it's visible... }
  399.   BEGIN
  400.     SaveState := Toggle; Done := False; Quit := False;
  401.     AttributeStash := TextAttr; TextAttr := $70;
  402.     HighLight(XPos,YPos,MaxLength(TrueString,FalseString),'');
  403.     Show;
  404.     REPEAT
  405.       IF KeyPressed THEN         { If there's a keystroke waiting }
  406.         BEGIN
  407.           Ch := ReadKey;         { go get it... }
  408.           CASE Ord(Ch) OF        { and parse it. }
  409.              0 : Ch := ReadKey;  { Get second half of extended char; ignore it }
  410.             13 : Done := True;   { Enter means accept current state of Toggle  }
  411.             27 : Quit := True;   { Esc means restore Toggle as it was on entry }
  412.             ELSE BEGIN           { Another other ASCII key: Flip Toggle }
  413.                    Hide;         { Erase the current state string }
  414.                    Toggle := NOT Toggle;   { Flip Toggle to its opposite state }
  415.                    Show;         { Display the alternate state string }
  416.                  END;
  417.           END; { CASE }
  418.         END;
  419.     UNTIL Done OR Quit;
  420.     IF Quit THEN
  421.       BEGIN
  422.         Hide;                    { Erase current display of state string }
  423.         Toggle := SaveState;     { Restore original state of Toggle }
  424.         Show;                    { And re-display it }
  425.       END;
  426.     TextAttr := AttributeStash;
  427.     HighLight(XPos,YPos,MaxLength(TrueString,FalseString),'');
  428.     Show;
  429.   END;
  430. END;
  431.  
  432.  
  433.  
  434. CONSTRUCTOR IntField.Init(InitX,InitY : Integer;
  435.                           InitVisible : Boolean;
  436.                           InitIntVal : Integer);
  437.  
  438. VAR
  439.   WorkString : String10;
  440.  
  441. BEGIN
  442.   Str(InitIntVal : 6,WorkString);
  443.   TextField.Init(InitX,InitY,InitVisible,WorkString,6);
  444.   IntVal := InitIntVal;
  445.   IF InitVisible THEN Show;
  446. END;
  447.  
  448.  
  449. FUNCTION IntField.Getdata : Integer;
  450.  
  451. BEGIN
  452.   Getdata := IntVal;
  453. END;
  454.  
  455.  
  456. PROCEDURE IntField.Show;
  457.  
  458. BEGIN
  459.   Str(IntVal : 6,Stringdata);
  460.   TextField.Show;
  461. END;
  462.  
  463. {-------------------------------------------------------------------}
  464. { Notice that there is NO IntField.Hide!  The mechanism for erasing }
  465. { an integer field is no different from erasing any string field,   }
  466. { so objects of type IntField use the Hide method inherited from    }
  467. { TextField.                                                        }
  468. {-------------------------------------------------------------------}
  469.  
  470.  
  471. PROCEDURE IntField.Edit;
  472.  
  473. VAR
  474.   WorkValue,ErrorPos : Integer;
  475.   AttributeStash : Byte;
  476.  
  477. BEGIN
  478.   IF IsVisible THEN   { Only edit an object if it's visible... }
  479.     BEGIN
  480.       AttributeStash := TextAttr;
  481.       TextAttr := $70;
  482.       Str(IntVal : 6,StringData); { Convert the integer value to a string }
  483.       HighLight(XPos,YPos,Length(StringData),Stringdata);
  484.       REPEAT                      { And edit the string until it's right  }
  485.         GetLine(XPos,YPos,StringData,FieldLength,IntChars);
  486.         Val(Stringdata,WorkValue,ErrorPos);
  487.         IF ErrorPos <> 0 THEN Uhuh;
  488.       UNTIL ErrorPos = 0;
  489.       IntVal := WorkValue;
  490.       TextAttr := AttributeStash;
  491.       HighLight(XPos,YPos,Length(StringData),StringData);
  492.     END;
  493. END;
  494.  
  495.  
  496.  
  497. BEGIN
  498.   FillChar(Blanker,SizeOf(Blanker),' ');
  499.   Blanker[0] := Chr(80);
  500. END.
  501.  
  502.  
  503. [LISTING TWO]
  504.  
  505. PROGRAM FieldTest;
  506.  
  507. USES Crt,
  508.      Fields;  { Published in DDJ November 1989 }
  509.  
  510. CONST
  511.   Female = True;
  512.   Male   = NOT Female;
  513.  
  514. VAR
  515.   FieldArray : ARRAY[1..4] OF FieldPtr;
  516.   I : Integer;
  517.  
  518. BEGIN
  519.   ClrScr;
  520.   Writeln('Patient name: ');
  521.   Writeln('         sex: ');
  522.   Writeln('         age: ');
  523.   Writeln('   Physician: ');
  524.  
  525.   { Initialize the objects on the heap & provide initial values: }
  526.   FieldArray[1] := New(TextFieldPtr,Init(15,1,Invisible,'Jones,Tom',40));
  527.   FieldArray[2] := New(BooleanFieldPtr,Init(15,2,Invisible,
  528.                                             Female,'Female','Male'));
  529.   FieldArray[3] := New(IntFieldPtr,Init(15,3,Invisible,42));
  530.   FieldArray[4] := New(TextFieldPtr,Init(15,4,Invisible,'Dr. Asimov',40));
  531.  
  532.   { First display initial values through polymorphic calls to Show: }
  533.   FOR I := 1 TO 4 DO FieldArray[I]^.Show;
  534.  
  535.   { Now edit each one through a polymorphic call to the Edit method: }
  536.   FOR I := 1 TO 4 DO FieldArray[I]^.Edit;
  537. END.
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.