home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / ddjmag / ddj9209.zip / HCALC.ASC < prev    next >
Text File  |  1992-08-10  |  20KB  |  588 lines

  1. _STRUCTURED PROGRAMMING COLUMN_
  2. by Jeff Duntemann
  3.  
  4. [LISTING ONE]
  5.  
  6. PROGRAM HCalc;   { By Jeff Duntemann; Update of 5/2/92 }
  7.                  { Requires Turbo Pascal 6.0! }
  8. USES App,Dialogs,Objects,Views,Menus,StdDlg,Drivers,
  9.      FInput,    { By Allen Bauer; on CompuServe BPROGA }
  10.      Mortgage;  { By Jeff Duntemann; from DDJ 10/91 }
  11. CONST
  12.   cmNewMortgage  = 199;
  13.   cmExtraPrin    = 198;
  14.   cmCloseAll     = 197;
  15.   cmCloseBC      = 196;
  16.   cmPrintSummary = 195;
  17.   cmLoadMortgage = 194;
  18.   cmSaveMortgage = 193;
  19.  
  20.   WindowCount : Integer = 0;
  21.  
  22. TYPE
  23.   MortgageDialogData =
  24.     RECORD
  25.       PrincipalData : Real;
  26.       InterestData  : Real;
  27.       PeriodsData   : Integer;
  28.     END;
  29.   ExtraPrincipalDialogData =
  30.     RECORD
  31.       PaymentNumber : Integer;
  32.       ExtraDollars  : Real;
  33.     END;
  34.   THouseCalcApp =
  35.     OBJECT(TApplication)
  36.       InitDialog  : PDialog;  { Dialog for initializing a mortgage }
  37.       ExtraDialog : PDialog;  { Dialog for entering extra principal }
  38.       CONSTRUCTOR Init;
  39.       PROCEDURE   InitMenuBar; VIRTUAL;
  40.       PROCEDURE   CloseAll;
  41.       PROCEDURE   HandleEvent(VAR Event : TEvent); VIRTUAL;
  42.       PROCEDURE   NewMortgage;
  43.       PROCEDURE   LoadMortgage;
  44.       PROCEDURE   SaveMortgage;
  45.     END;
  46.   PMortgageTopInterior = ^TMortgageTopInterior;
  47.   TMortgageTopInterior =
  48.     OBJECT(TView)
  49.       Mortgage       : PMortgage;
  50.       CONSTRUCTOR Init(VAR Bounds : TRect);
  51.       CONSTRUCTOR Load(VAR S : TStream);
  52.       PROCEDURE   Store(VAR S : TStream);
  53.       PROCEDURE   Draw; VIRTUAL;
  54.     END;
  55.   PMortgageBottomInterior = ^TMortgageBottomInterior;
  56.   TMortgageBottomInterior =
  57.     OBJECT(TScroller)
  58.       { Points to Mortgage object owned by TMortgageView }
  59.       Mortgage    : PMortgage;
  60.       CONSTRUCTOR Init(VAR Bounds : TRect;
  61.                        AHScrollBar, AVScrollbar : PScrollBar);
  62.       CONSTRUCTOR Load(VAR S : TStream);
  63.       PROCEDURE   Store(VAR S : TStream);
  64.       PROCEDURE   Draw; VIRTUAL;
  65.     END;
  66.  
  67.   PMortgageView = ^TMortgageView;
  68.   TMortgageView =
  69.     OBJECT(TWindow)
  70.       Mortgage    : TMortgage;
  71.       TopInterior    : PMortgageTopInterior;
  72.       BottomInterior : PMortgageBottomInterior;
  73.       CONSTRUCTOR Init(VAR Bounds  : TRect;
  74.                        ATitle  : TTitleStr;
  75.                        ANumber : Integer;
  76.                        InitMortgageData :
  77.                        MortgageDialogData);
  78.       CONSTRUCTOR Load(VAR S : TStream);
  79.       PROCEDURE   Store(VAR S : TStream);
  80.       PROCEDURE   HandleEvent(Var Event : TEvent); VIRTUAL;
  81.       PROCEDURE   ExtraPrincipal;
  82.       PROCEDURE   PrintSummary;
  83.       DESTRUCTOR  Done; VIRTUAL;
  84.     END;
  85. VAR
  86.   HouseCalc : THouseCalcApp;  { This is the application object itself  }
  87.   TempMtg   : PMortgageView;  { Temporary pointer for mortgage windows }
  88. CONST
  89.   DefaultMortgageData : MortgageDialogData =
  90.     (PrincipalData : 100000;
  91.      InterestData  : 10.0;
  92.      PeriodsData   : 360);
  93.   RMortgageView : TStreamRec =
  94.     (ObjType : 1101;
  95.      VMTLink : Ofs(TypeOf(TMortgageView)^);
  96.      Load    : @TMortgageView.Load;
  97.      Store   : @TMortgageView.Store);
  98.   RMortgageTopInterior : TStreamRec =
  99.     (ObjType : 1102;
  100.      VMTLink : Ofs(TypeOf(TMortgageTopInterior)^);
  101.      Load    : @TMortgageTopInterior.Load;
  102.      Store   : @TMortgageTopInterior.Store);
  103.   RMortgageBottomInterior: TStreamRec =
  104.     (ObjType : 1103;
  105.      VMTLink : Ofs(TypeOf(TMortgageBottomInterior)^);
  106.      Load    : @TMortgageBottomInterior.Load;
  107.      Store   : @TMortgageBottomInterior.Store);
  108.  
  109. PROCEDURE RegisterAllTypes;
  110. BEGIN
  111.   RegisterType(RScrollBar);
  112.   RegisterType(RFrame);
  113.   RegisterFInputLine;
  114.   RegisterType(RMortgage);    { RMortgage defined in unit MORTGAGE.PAS }
  115.   RegisterType(RMortgageView);
  116.   RegisterType(RMortgageTopInterior);
  117.   RegisterType(RMortgageBottomInterior);
  118. END;
  119.  
  120. FUNCTION ExecDialog(P: PDialog; Data: Pointer): Word;
  121. VAR
  122.   Result: Word;
  123. BEGIN
  124.   Result := cmCancel;
  125.   P := PDialog(Application^.ValidView(P));
  126.   IF P <> NIL THEN
  127.   BEGIN
  128.     IF Data <> NIL THEN P^.SetData(Data^);
  129.     Result := DeskTop^.ExecView(P);
  130.     IF (Result <> cmCancel) AND (Data <> NIL) THEN P^.GetData(Data^);
  131.     Dispose(P, Done);
  132.   END;
  133.   ExecDialog := Result;
  134. END;
  135.  
  136. {------------------------------}
  137. {   METHODS: THouseCalcApp     }
  138. {------------------------------}
  139. CONSTRUCTOR THouseCalcApp.Init;
  140. VAR
  141.   R : TRect;
  142.   aView      : PView;
  143. BEGIN
  144.   TApplication.Init;  { Always call the parent's constructor first! }
  145.   { Create the dialog for initializing a mortgage: }
  146.   R.Assign(20,5,60,16);
  147.   InitDialog := New(PDialog,Init(R,'Define Mortgage Parameters'));
  148.   WITH InitDialog^ DO
  149.     BEGIN
  150.       { First item in the dialog box is input line for principal: }
  151.       R.Assign(3,3,13,4);
  152.       aView := New(PFInputLine,Init(R,8,DRealSet,DReal,0));
  153.       Insert(aView);
  154.       R.Assign(2,2,12,3);
  155.       Insert(New(PLabel,Init(R,'Principal',aView)));
  156.  
  157.       { Next is the input line for interest rate: }
  158.       R.Assign(17,3,26,4);
  159.       aView := New(PFInputLine,Init(R,6,DRealSet,DReal,3));
  160.       Insert(aView);
  161.       R.Assign(16,2,25,3);
  162.       Insert(New(PLabel,Init(R,'Interest',aView)));
  163.       R.Assign(26,3,27,4);   { Add a static text "%" sign }
  164.       Insert(New(PStaticText,Init(R,'%')));
  165.  
  166.       { Up next is the input line for number of periods: }
  167.       R.Assign(31,3,36,4);
  168.       aView := New(PFInputLine,Init(R,3,DUnsignedSet,DInteger,0));
  169.       Insert(aView);
  170.       R.Assign(29,2,37,3);
  171.       Insert(New(PLabel,Init(R,'Periods',aView)));
  172.  
  173.       { These are standard buttons for the OK and Cancel commands: }
  174.       R.Assign(8,8,16,10);
  175.       Insert(New(PButton,Init(R,'~O~K',cmOK,bfDefault)));
  176.       R.Assign(22,8,32,10);
  177.       Insert(New(PButton,Init(R,'Cancel',cmCancel,bfNormal)));
  178.     END;
  179.  
  180.   { Create the dialog for adding additional principal to a payment: }
  181.   R.Assign(20,5,60,16);
  182.   ExtraDialog := New(PDialog,Init(R,'Apply Extra Principal to Mortgage'));
  183.   WITH ExtraDialog^ DO
  184.     BEGIN
  185.       { First item in the dialog is the payment number to which }
  186.       { we're going to apply the extra principal:               }
  187.       R.Assign(9,3,18,4);
  188.       aView := New(PFInputLine,Init(R,6,DUnsignedSet,DInteger,0));
  189.       Insert(aView);
  190.       R.Assign(3,2,12,3);
  191.       Insert(New(PLabel,Init(R,'Payment #',aView)));
  192.  
  193.       { Next item in the dialog box is input line for extra principal: }
  194.       R.Assign(23,3,33,4);
  195.       aView := New(PFInputLine,Init(R,8,DRealSet,DReal,2));
  196.       Insert(aView);
  197.       R.Assign(20,2,35,3);
  198.       Insert(New(PLabel,Init(R,'Extra Principal',aView)));
  199.  
  200.       { These are standard buttons for the OK and Cancel commands: }
  201.       R.Assign(8,8,16,10);
  202.       Insert(New(PButton,Init(R,'~O~K',cmOK,bfDefault)));
  203.       R.Assign(22,8,32,10);
  204.       Insert(New(PButton,Init(R,'Cancel',cmCancel,bfNormal)));
  205.     END;
  206. END;
  207.  
  208. { This method sends out a broadcast message to all views.  Only the
  209. { mortgage windows know how to respond to it, so when cmCloseBC is
  210. { issued, only the mortgage windows react--by closing. }
  211.  
  212. PROCEDURE THouseCalcApp.CloseAll;
  213. VAR
  214.   Who : Pointer;
  215. BEGIN
  216.   Who := Message(Desktop,evBroadcast,cmCloseBC,@Self);
  217. END;
  218.  
  219. PROCEDURE THouseCalcApp.LoadMortgage;
  220. VAR
  221.   FileName : FNameStr;
  222.   FetchMtg : PBufStream;
  223. BEGIN
  224.   FileName := '*.MTG';
  225.   IF ExecDialog(New(PFileDialog, Init('*.*', 'Load Mortgage File',
  226.     '~N~ame', fdOpenButton, 100)), @FileName) <> cmCancel
  227.   THEN
  228.     BEGIN
  229.       FetchMtg := New(PBufStream,Init(FileName,stOpenRead,1024));
  230.       IF FetchMtg^.Status <> 0 THEN Halt(1);
  231.       TempMtg := PMortgageView(FetchMtg^.Get);
  232.       IF FetchMtg^.Status <> 0 THEN
  233.         BEGIN
  234.           Writeln('Status code =',FetchMtg^.Status);
  235.           Halt(1);
  236.         END;
  237.       Dispose(FetchMtg,Done);
  238.       DisableCommands([cmSaveMortgage]);
  239.       IF TempMtg <> NIL THEN
  240.         Desktop^.Insert(TempMtg);
  241.       EnableCommands([cmSaveMortgage]);
  242.     END;
  243. END;
  244.  
  245. PROCEDURE THouseCalcApp.SaveMortgage;
  246. VAR
  247.   FileName : FNameStr;
  248.   SaveMtg  : PBufStream;
  249. BEGIN
  250.   FileName := '*.MTG';
  251.   IF ExecDialog(New(PFileDialog, Init('*.*', 'Save Mortgage File',
  252.     '~N~ame', fdOpenButton, 100)), @FileName) <> cmCancel
  253.   THEN
  254.     BEGIN
  255.       SaveMtg := New(PBufStream,Init(FileName,stCreate,1024));
  256.       IF SaveMtg^.Status <> 0 THEN Halt(1);
  257.       IF DeskTop^.Current <> NIL THEN
  258.         BEGIN
  259.           SaveMtg^.Put(DeskTop^.Current);
  260.           IF SaveMtg^.Status <> 0 THEN
  261.             BEGIN
  262.               Writeln('Status value =',SaveMtg^.Status);
  263.               Halt(1);
  264.             END;
  265.         END;
  266.       Dispose(SaveMtg,Done);
  267.     END;
  268. END;
  269.  
  270. PROCEDURE THouseCalcApp.HandleEvent(VAR Event : TEvent);
  271. BEGIN
  272.   TApplication.HandleEvent(Event);
  273.   IF Event.What = evCommand THEN
  274.     BEGIN
  275.       CASE Event.Command OF
  276.         cmNewMortgage  : NewMortgage;
  277.         cmLoadMortgage : LoadMortgage;
  278.         cmSaveMortgage : SaveMortgage;
  279.         cmCloseAll     : CloseAll;
  280.       ELSE
  281.         Exit;
  282.       END; { CASE }
  283.       ClearEvent(Event);
  284.     END;
  285. END;
  286.  
  287. PROCEDURE THouseCalcApp.NewMortgage;
  288. VAR
  289.   Code       : Integer;
  290.   R          : TRect;
  291.   Control    : Word;
  292.   ThisMortgage     : PMortgageView;
  293.   InitMortgageData : MortgageDialogData;
  294. BEGIN
  295.   { First we need a dialog to get the intial mortgage values from }
  296.   { the user.  The dialog appears *before* the mortgage window!   }
  297.   WITH InitMortgageData DO
  298.     BEGIN
  299.       PrincipalData := 100000;
  300.       InterestData  := 10.0;
  301.       PeriodsData   := 360;
  302.     END;
  303.   InitDialog^.SetData(InitMortgageData);
  304.   Control := Desktop^.ExecView(InitDialog);
  305.    IF Control <> cmCancel THEN  { Create a new mortgage object: }
  306.      BEGIN
  307.        R.Assign(5,5,45,20);
  308.        Inc(WindowCount);
  309.        { Get data from the initial mortgage dialog: }
  310.        InitDialog^.GetData(InitMortgageData);
  311.        { Call the constructor for the mortgage window: }
  312.        ThisMortgage :=
  313.          New(PMortgageView,Init(R,'Mortgage',WindowCount,InitMortgageData));
  314.        { Insert the mortgage window into the desktop: }
  315.        Desktop^.Insert(ThisMortgage);
  316.      END;
  317. END;
  318.  
  319. PROCEDURE THouseCalcApp.InitMenuBar;
  320. VAR
  321.   R : TRect;
  322. BEGIN
  323.   GetExtent(R);
  324.   R.B.Y := R.A.Y + 1;  { Define 1-line menu bar }
  325.  
  326.   MenuBar := New(PMenuBar,Init(R,NewMenu(
  327.     NewSubMenu('~M~ortgage',hcNoContext,NewMenu(
  328.       NewItem('~N~ew','F6',kbF6,cmNewMortgage,hcNoContext,
  329.       NewItem('~O~pen','F3',kbF3,cmLoadMortgage,hcNoContext,
  330.       NewItem('~S~ave Top','F2',kbF2,cmSaveMortgage,hcNoContext,
  331.       NewItem('~E~xtra Principal    ','',0,cmExtraPrin,hcNoContext,
  332.       NewItem('~C~lose all','F7',kbF7,cmCloseAll,hcNoContext,
  333.       NewItem('E~x~it','Alt-X',kbAltX,cmQuit,hcNoContext,
  334.       NIL))))))),
  335.     NIL)
  336.   )));
  337. END;
  338.  
  339. {---------------------------------}
  340. {   METHODS: TMortgageTopInterior }
  341. {---------------------------------}
  342. CONSTRUCTOR TMortgageTopInterior.Init(VAR Bounds : TRect);
  343. BEGIN
  344.   TView.Init(Bounds);     { Call ancestor's constructor }
  345.   GrowMode := gfGrowHiX;  { Permits pane to grow in X but not Y }
  346. END;
  347.  
  348. CONSTRUCTOR TMortgageTopInterior.Load(VAR S : TStream);
  349. BEGIN
  350.   TView.Load(S);
  351. END;
  352.  
  353. PROCEDURE TMortgageTopInterior.Store(Var S : TStream);
  354. BEGIN
  355.   TView.Store(S)
  356. END;
  357.  
  358. PROCEDURE TMortgageTopInterior.Draw;
  359. VAR
  360.   YRun  : Integer;
  361.   Color : Byte;
  362.   B     : TDrawBuffer;
  363.   STemp : String[20];
  364. BEGIN
  365.   Color := GetColor(1);
  366.   MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  367.   MoveStr(B,' Principal   Int.  Periods  Payment',Color);
  368.   WriteLine(0,0,Size.X,1,B);
  369.  
  370.   MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  371.   { Here we convert payment data to strings for display: }
  372.   Str(Mortgage^.Principal:7:2,STemp);
  373.   MoveStr(B[1],STemp,Color);         { At beginning of buffer B }
  374.   Str(Mortgage^.Interest*100:7:2,STemp);
  375.   MoveStr(B[10],STemp,Color);      { At position 14 of buffer B }
  376.   Str(Mortgage^.Periods:4,STemp);
  377.   MoveStr(B[20],STemp,Color);      { At position 25 of buffer B }
  378.   WriteLine(0,1,Size.X,1,B);
  379.   Str(Mortgage^.MonthlyPI:7:2,STemp);
  380.   MoveStr(B[27],STemp,Color);      { At position 29 of buffer B }
  381.   WriteLine(0,1,Size.X,1,B);
  382.  
  383.   MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  384.   MoveStr(B,
  385.   '                                      Extra        Principal      Interest',
  386.   Color);
  387.   WriteLine(0,2,Size.X,1,B);
  388.  
  389.   MoveChar(B,' ',Color,Size.X);    { Clear the buffer to spaces }
  390.   MoveStr(B,
  391.   'Paymt #  Prin.   Int.     Balance     Principal    So far         So far ',
  392.   Color);
  393.   WriteLine(0,3,Size.X,1,B);
  394. END;
  395.  
  396. {------------------------------------}
  397. {   METHODS: TMortgageBottomInterior }
  398. {------------------------------------}
  399. CONSTRUCTOR TMortgageBottomInterior.Init(VAR Bounds : TRect;
  400.                                        AHScrollBar, AVScrollBar : PScrollBar);
  401.  
  402. BEGIN
  403.   { Call ancestor's constructor: }
  404.   TScroller.Init(Bounds,AHScrollBar,AVScrollBar);
  405.   GrowMode := gfGrowHiX + gfGrowHiY;
  406.   Options := Options OR ofFramed;
  407. END;
  408.  
  409. CONSTRUCTOR TMortgageBottomInterior.Load(VAR S : TStream);
  410. BEGIN
  411.   TScroller.Load(S);
  412. END;
  413.  
  414. PROCEDURE TMortgageBottomInterior.Store(Var S : TStream);
  415. BEGIN
  416.   TScroller.Store(S)
  417. END;
  418.  
  419. PROCEDURE TMortgageBottomInterior.Draw;
  420. VAR
  421.   Color : Byte;
  422.   B     : TDrawBuffer;
  423.   YRun  : Integer;
  424.   STemp : String[20];
  425. BEGIN
  426.   Color := GetColor(1);
  427.   FOR YRun := 0 TO Size.Y-1 DO
  428.     BEGIN
  429.       MoveChar(B,' ',Color,80);    { Clear the buffer to spaces }
  430.       Str(Delta.Y+YRun+1:4,STemp);
  431.       MoveStr(B,STemp+':',Color);        { At beginning of buffer B }
  432.       { Here we convert payment data to strings for display: }
  433.       Str(Mortgage^.Payments^[Delta.Y+YRun+1].PayPrincipal:7:2,STemp);
  434.       MoveStr(B[6],STemp,Color);         { At beginning of buffer B }
  435.       Str(Mortgage^.Payments^[Delta.Y+YRun+1].PayInterest:7:2,STemp);
  436.       MoveStr(B[15],STemp,Color);      { At position 15 of buffer B }
  437.       Str(Mortgage^.Payments^[Delta.Y+YRun+1].Balance:10:2,STemp);
  438.       MoveStr(B[24],STemp,Color);      { At position 24 of buffer B }
  439.       { There isn't an extra principal value for every payment, so }
  440.       { display the value only if it is nonzero:                   }
  441.       STemp := '';
  442.       IF  Mortgage^.Payments^[Delta.Y+YRun+1].ExtraPrincipal > 0
  443.       THEN
  444.         Str(Mortgage^.Payments^[Delta.Y+YRun+1].ExtraPrincipal:10:2,STemp);
  445.       MoveStr(B[37],STemp,Color);      { At position 37 of buffer B }
  446.       Str(Mortgage^.Payments^[Delta.Y+YRun+1].PrincipalSoFar:10:2,STemp);
  447.       MoveStr(B[50],STemp,Color);      { At position 50 of buffer B }
  448.       Str(Mortgage^.Payments^[Delta.Y+YRun+1].InterestSoFar:10:2,STemp);
  449.       MoveStr(B[64],STemp,Color);      { At position 64 of buffer B }
  450.       { Here we write the line to the window, taking into account the }
  451.       { state of the X scroll bar: }
  452.       WriteLine(0,YRun,Size.X,1,B[Delta.X]);
  453.     END;
  454. END;
  455.  
  456. {------------------------------}
  457. {   METHODS: TMortgageView     }
  458. {------------------------------}
  459. CONSTRUCTOR TMortgageView.Init(VAR Bounds  : TRect;
  460.                                    ATitle  : TTitleStr;
  461.                                    ANumber : Integer;
  462.                                    InitMortgageData :
  463.                                    MortgageDialogData);
  464. VAR
  465.   HScrollBar,VScrollBar : PScrollBar;
  466.   R,S  : TRect;
  467. BEGIN
  468.   TWindow.Init(Bounds,ATitle,ANumber); { Call ancestor's constructor }
  469.   { Call the Mortgage object's constructor using dialog data: }
  470.   WITH InitMortgageData DO
  471.     Mortgage.Init(PrincipalData,
  472.                   InterestData / 100,
  473.                   PeriodsData,
  474.                   12);
  475.   { Here we set up a window with *two* interiors, one scrollable, one }
  476.   { static.  It's all in the way that you define the bounds, mostly:  }
  477.   GetClipRect(Bounds);             { Get bounds for interior of view  }
  478.   Bounds.Grow(-1,-1);      { Shrink those bounds by 1 for both X & Y  }
  479.  
  480.   { Define a rectangle to embrace the upper of the two interiors:     }
  481.   R.Assign(Bounds.A.X,Bounds.A.Y,Bounds.B.X,Bounds.A.Y+4);
  482.   TopInterior := New(PMortgageTopInterior,Init(R));
  483.   TopInterior^.Mortgage := @Mortgage;
  484.   Insert(TopInterior);
  485.  
  486.   { Define a rectangle to embrace the lower of two interiors: }
  487.   R.Assign(Bounds.A.X,Bounds.A.Y+5,Bounds.B.X,Bounds.B.Y);
  488.  
  489.   { Create scroll bars for both mouse & keyboard input: }
  490.   VScrollBar := StandardScrollBar(sbVertical + sbHandleKeyboard);
  491.   { We have to adjust vertical bar to fit bottom interior: }
  492.   VScrollBar^.Origin.Y := R.A.Y;       { Adjust top Y value }
  493.   VScrollBar^.Size.Y := R.B.Y - R.A.Y; { Adjust size }
  494.   { The horizontal scroll bar, on the other hand, is standard: }
  495.   HScrollBar := StandardScrollBar(sbHorizontal + sbHandleKeyboard);
  496.  
  497.   { Create bottom interior object with scroll bars: }
  498.   BottomInterior :=
  499.     New(PMortgageBottomInterior,Init(R,HScrollBar,VScrollBar));
  500.   { Make copy of pointer to mortgage object: }
  501.   BottomInterior^.Mortgage := @Mortgage;
  502.   { Set the limits for the scroll bars: }
  503.   BottomInterior^.SetLimit(80,InitMortgageData.PeriodsData);
  504.   { Insert the interior into the window: }
  505.   Insert(BottomInterior);
  506. END;
  507.  
  508. CONSTRUCTOR TMortgageView.Load(VAR S : TStream);
  509. VAR
  510.   MortgageTemp : PObject;
  511. BEGIN
  512.   TWindow.Load(S);       { Load what you've inherited from parent type}
  513.  
  514.   MortgageTemp := S.Get; { Load the contained TMortgage object }
  515.   { Now we have to copy the heap-based copy of TMortgage to the copy }
  516.   { embedded in the TMortgageView object we're in the process of loading: }
  517.   Move(MortgageTemp^,Mortgage,Sizeof(TMortgage));
  518.  
  519.   GetSubViewPtr(S,BottomInterior);
  520.   GetSubViewPtr(S,TopInterior);
  521.   TopInterior^.Mortgage := @Mortgage;
  522.   BottomInterior^.Mortgage := @Mortgage;
  523. END;
  524.  
  525. PROCEDURE TMortgageView.Store(VAR S : TStream);
  526. BEGIN
  527.   TWindow.Store(S);   { Store what you've inherited from parent type}
  528.   S.Put(@Mortgage);   { Store the contained TMortgage object }
  529.   PutSubViewPtr(S,BottomInterior);
  530.   PutSubViewPtr(S,TopInterior);
  531. END;
  532.  
  533. PROCEDURE TMortgageView.HandleEvent(Var Event : TEvent);
  534. BEGIN
  535.   TWindow.HandleEvent(Event);
  536.   IF Event.What = evCommand THEN
  537.     BEGIN
  538.       CASE Event.Command OF
  539.         cmExtraPrin    : ExtraPrincipal;
  540.         cmPrintSummary : PrintSummary;
  541.       ELSE
  542.         Exit;
  543.       END; { CASE }
  544.       ClearEvent(Event);
  545.     END
  546.   ELSE
  547.     IF Event.What = evBroadcast THEN
  548.       CASE Event.Command OF
  549.         cmCloseBC : Done
  550.       END; { CASE }
  551. END;
  552.  
  553. PROCEDURE TMortgageView.ExtraPrincipal;
  554. VAR
  555.   Control : Word;
  556.   ExtraPrincipalData : ExtraPrincipalDialogData;
  557. BEGIN
  558.   { Execute the "extra principal" dialog box: }
  559.   Control := Desktop^.ExecView(HouseCalc.ExtraDialog);
  560.    IF Control <> cmCancel THEN  { Update the active mortgage window: }
  561.      BEGIN
  562.        { Get data from the extra principal dialog: }
  563.        HouseCalc.ExtraDialog^.GetData(ExtraPrincipalData);
  564.        Mortgage.Payments^[ExtraPrincipalData.PaymentNumber].ExtraPrincipal :=
  565.          ExtraPrincipalData.ExtraDollars;
  566.        Mortgage.Recalc;   { Recalculate the amortization table... }
  567.        Redraw;            { ...and redraw the mortgage window     }
  568.      END;
  569. END;
  570.  
  571. PROCEDURE TMortgageView.PrintSummary;
  572. BEGIN
  573. END;
  574.  
  575. DESTRUCTOR TMortgageView.Done;
  576. BEGIN
  577.   Mortgage.Done;  { Dispose of the mortgage object's memory }
  578.   TWindow.Done;   { Call parent's destructor to dispose of window }
  579. END;
  580.  
  581. BEGIN
  582.   RegisterAllTypes;
  583.   HouseCalc.Init;
  584.   HouseCalc.Run;
  585.   HouseCalc.Done;
  586. END.
  587.  
  588.