Category : Files from Magazines
Archive   : DDJ0292.ZIP
Filename : HCALC.ASC

 
Output of file : HCALC.ASC contained in archive : DDJ0292.ZIP
PROGRAM HCalc; { By Jeff Duntemann; Update of 10/31/91 }
{ Requires Turbo Pascal 6.0! }

USES App,Dialogs,Objects,Views,Menus,Drivers,
FInput, { By Allen Bauer; on CompuServe BPROGA }
Mortgage; { By Jeff Duntemann; from DDJ 10/91 }

CONST
cmNewMortgage = 199;
cmExtraPrin = 198;
cmCloseAll = 197;
cmCloseBC = 196;
cmPrintSummary = 195;
WindowCount : Integer = 0;

TYPE
MortgageDialogData =
RECORD
PrincipalData : Real;
InterestData : Real;
PeriodsData : Integer;
END;

ExtraPrincipalDialogData =
RECORD
PaymentNumber : Integer;
ExtraDollars : Real;
END;

THouseCalcApp =
OBJECT(TApplication)
InitDialog : PDialog; { Dialog for initializing a mortgage }
ExtraDialog : PDialog; { Dialog for entering extra principal }
CONSTRUCTOR Init;
PROCEDURE InitMenuBar; VIRTUAL;
PROCEDURE CloseAll;
PROCEDURE HandleEvent(VAR Event : TEvent); VIRTUAL;
PROCEDURE NewMortgage;
END;

PMortgageTopInterior = ^TMortgageTopInterior;
TMortgageTopInterior =
OBJECT(TView)
Mortgage : PMortgage;
CONSTRUCTOR Init(VAR Bounds : TRect);
PROCEDURE Draw; VIRTUAL;
END;


PMortgageBottomInterior = ^TMortgageBottomInterior;
TMortgageBottomInterior =
OBJECT(TScroller)
{ Points to Mortgage object owned by TMortgageView }
Mortgage : PMortgage;
CONSTRUCTOR Init(VAR Bounds : TRect;
AHScrollBar, AVScrollbar : PScrollBar);
PROCEDURE Draw; VIRTUAL;
END;

PMortgageView = ^TMortgageView;
TMortgageView =
OBJECT(TWindow)
Mortgage : TMortgage;
CONSTRUCTOR Init(VAR Bounds : TRect;
ATitle : TTitleStr;
ANumber : Integer;
InitMortgageData :
MortgageDialogData);
PROCEDURE HandleEvent(Var Event : TEvent); VIRTUAL;
PROCEDURE ExtraPrincipal;
PROCEDURE PrintSummary;
DESTRUCTOR Done; VIRTUAL;
END;


CONST
DefaultMortgageData : MortgageDialogData =
(PrincipalData : 100000;
InterestData : 10.0;
PeriodsData : 360);


VAR
HouseCalc : THouseCalcApp; { This is the application object itself }



{------------------------------}
{ METHODS: THouseCalcApp }
{------------------------------}


CONSTRUCTOR THouseCalcApp.Init;

VAR
R : TRect;
aView : PView;

BEGIN
TApplication.Init; { Always call the parent's constructor first! }

{ Create the dialog for initializing a mortgage: }
R.Assign(20,5,60,16);
InitDialog := New(PDialog,Init(R,'Define Mortgage Parameters'));
WITH InitDialog^ DO
BEGIN
{ First item in the dialog box is input line for principal: }
R.Assign(3,3,13,4);
aView := New(PFInputLine,Init(R,8,DRealSet,DReal,0));
Insert(aView);
R.Assign(2,2,12,3);
Insert(New(PLabel,Init(R,'Principal',aView)));

{ Next is the input line for interest rate: }
R.Assign(17,3,26,4);
aView := New(PFInputLine,Init(R,6,DRealSet,DReal,3));
Insert(aView);
R.Assign(16,2,25,3);
Insert(New(PLabel,Init(R,'Interest',aView)));
R.Assign(26,3,27,4); { Add a static text "%" sign }
Insert(New(PStaticText,Init(R,'%')));

{ Up next is the input line for number of periods: }
R.Assign(31,3,36,4);
aView := New(PFInputLine,Init(R,3,DUnsignedSet,DInteger,0));
Insert(aView);
R.Assign(29,2,37,3);
Insert(New(PLabel,Init(R,'Periods',aView)));

{ These are standard buttons for the OK and Cancel commands: }
R.Assign(8,8,16,10);
Insert(New(PButton,Init(R,'~O~K',cmOK,bfDefault)));
R.Assign(22,8,32,10);
Insert(New(PButton,Init(R,'Cancel',cmCancel,bfNormal)));
END;

{ Create the dialog for adding additional principal to a payment: }
R.Assign(20,5,60,16);
ExtraDialog := New(PDialog,Init(R,'Apply Extra Principal to Mortgage'));
WITH ExtraDialog^ DO
BEGIN
{ First item in the dialog is the payment number to which }
{ we're going to apply the extra principal: }
R.Assign(9,3,18,4);
aView := New(PFInputLine,Init(R,6,DUnsignedSet,DInteger,0));
Insert(aView);
R.Assign(3,2,12,3);
Insert(New(PLabel,Init(R,'Payment #',aView)));

{ Next item in the dialog box is input line for extra principal: }
R.Assign(23,3,33,4);
aView := New(PFInputLine,Init(R,8,DRealSet,DReal,2));
Insert(aView);
R.Assign(20,2,35,3);
Insert(New(PLabel,Init(R,'Extra Principal',aView)));

{ These are standard buttons for the OK and Cancel commands: }
R.Assign(8,8,16,10);
Insert(New(PButton,Init(R,'~O~K',cmOK,bfDefault)));
R.Assign(22,8,32,10);
Insert(New(PButton,Init(R,'Cancel',cmCancel,bfNormal)));
END;

END;


{ This method sends out a broadcast message to all views. Only the
{ mortgage windows know how to respond to it, so when cmCloseBC is
{ issued, only the mortgage windows react--by closing. }

PROCEDURE THouseCalcApp.CloseAll;

VAR
Who : Pointer;

BEGIN
Who := Message(Desktop,evBroadcast,cmCloseBC,@Self);
END;


PROCEDURE THouseCalcApp.HandleEvent(VAR Event : TEvent);

BEGIN
TApplication.HandleEvent(Event);
IF Event.What = evCommand THEN
BEGIN
CASE Event.Command OF
cmNewMortgage : NewMortgage;
cmCloseAll : CloseAll;
ELSE
Exit;
END; { CASE }
ClearEvent(Event);
END;
END;


PROCEDURE THouseCalcApp.NewMortgage;

VAR
Code : Integer;
R : TRect;
Control : Word;
ThisMortgage : PMortgageView;
InitMortgageData : MortgageDialogData;

BEGIN
{ First we need a dialog to get the intial mortgage values from }
{ the user. The dialog appears *before* the mortgage window! }
WITH InitMortgageData DO
BEGIN
PrincipalData := 100000;

InterestData := 10.0;
PeriodsData := 360;
END;
InitDialog^.SetData(InitMortgageData);
Control := Desktop^.ExecView(InitDialog);
IF Control <> cmCancel THEN { Create a new mortgage object: }
BEGIN
R.Assign(5,5,45,20);
Inc(WindowCount);
{ Get data from the initial mortgage dialog: }
InitDialog^.GetData(InitMortgageData);
{ Call the constructor for the mortgage window: }
ThisMortgage :=
New(PMortgageView,Init(R,'Mortgage',WindowCount,
InitMortgageData));

{ Insert the mortgage window into the desktop: }
Desktop^.Insert(ThisMortgage);
END;
END;


PROCEDURE THouseCalcApp.InitMenuBar;

VAR
R : TRect;

BEGIN
GetExtent(R);
R.B.Y := R.A.Y + 1; { Define 1-line menu bar }

MenuBar := New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~M~ortgage',hcNoContext,NewMenu(
NewItem('~N~ew','F6',kbF6,cmNewMortgage,hcNoContext,
NewItem('~E~xtra Principal ','',0,cmExtraPrin,hcNoContext,
NewItem('~C~lose all','F7',kbF7,cmCloseAll,hcNoContext,
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,hcNoContext,
NIL))))),
NIL)
)));
END;


{---------------------------------}
{ METHODS: TMortgageTopInterior }
{---------------------------------}

CONSTRUCTOR TMortgageTopInterior.Init(VAR Bounds : TRect);

BEGIN
TView.Init(Bounds); { Call ancestor's constructor }
GrowMode := gfGrowHiX; { Permits pane to grow in X but not Y }
END;


PROCEDURE TMortgageTopInterior.Draw;

VAR
YRun : Integer;
Color : Byte;
B : TDrawBuffer;
STemp : String[20];

BEGIN
Color := GetColor(1);
MoveChar(B,' ',Color,Size.X); { Clear the buffer to spaces }
MoveStr(B,' Principal Interest Periods',Color);
WriteLine(0,0,Size.X,1,B);

MoveChar(B,' ',Color,Size.X); { Clear the buffer to spaces }
{ Here we convert payment data to strings for display: }
Str(Mortgage^.Principal:7:2,STemp);
MoveStr(B[2],STemp,Color); { At beginning of buffer B }
Str(Mortgage^.Interest*100:7:2,STemp);
MoveStr(B[14],STemp,Color); { At position 14 of buffer B }
Str(Mortgage^.Periods:4,STemp);
MoveStr(B[27],STemp,Color); { At position 27 of buffer B }
WriteLine(0,1,Size.X,1,B);

MoveChar(B,' ',Color,Size.X); { Clear the buffer to spaces }
MoveStr(B,
' Extra Principal Interest',
Color);
WriteLine(0,2,Size.X,1,B);

MoveChar(B,' ',Color,Size.X); { Clear the buffer to spaces }
MoveStr(B,
'Paymt # Prin. Int. Balance Principal So far So far ',
Color);
WriteLine(0,3,Size.X,1,B);

END;


{------------------------------------}
{ METHODS: TMortgageBottomInterior }
{------------------------------------}

CONSTRUCTOR TMortgageBottomInterior.Init(VAR Bounds : TRect;
AHScrollBar, AVScrollBar :
PScrollBar);


BEGIN
{ Call ancestor's constructor: }
TScroller.Init(Bounds,AHScrollBar,AVScrollBar);
GrowMode := gfGrowHiX + gfGrowHiY;
Options := Options OR ofFramed;
END;


PROCEDURE TMortgageBottomInterior.Draw;

VAR
Color : Byte;
B : TDrawBuffer;
YRun : Integer;
STemp : String[20];

BEGIN
Color := GetColor(1);
FOR YRun := 0 TO Size.Y-1 DO
BEGIN
MoveChar(B,' ',Color,80); { Clear the buffer to spaces }
Str(Delta.Y+YRun+1:4,STemp);
MoveStr(B,STemp+':',Color); { At beginning of buffer B }
{ Here we convert payment data to strings for display: }
Str(Mortgage^.Payments^[Delta.Y+YRun+1].PayPrincipal:7:2,STemp);
MoveStr(B[6],STemp,Color); { At beginning of buffer B }
Str(Mortgage^.Payments^[Delta.Y+YRun+1].PayInterest:7:2,STemp);
MoveStr(B[15],STemp,Color); { At position 15 of buffer B }
Str(Mortgage^.Payments^[Delta.Y+YRun+1].Balance:10:2,STemp);
MoveStr(B[24],STemp,Color); { At position 24 of buffer B }
{ There isn't an extra principal value for every payment, so }
{ display the value only if it is nonzero: }
STemp := '';
IF Mortgage^.Payments^[Delta.Y+YRun+1].ExtraPrincipal > 0
THEN
Str(Mortgage^.Payments^[Delta.Y+YRun+1].ExtraPrincipal:10:2,STemp);
MoveStr(B[37],STemp,Color); { At position 37 of buffer B }
Str(Mortgage^.Payments^[Delta.Y+YRun+1].PrincipalSoFar:10:2,STemp);
MoveStr(B[50],STemp,Color); { At position 50 of buffer B }
Str(Mortgage^.Payments^[Delta.Y+YRun+1].InterestSoFar:10:2,STemp);
MoveStr(B[64],STemp,Color); { At position 64 of buffer B }
{ Here we write the line to the window, taking into account the }
{ state of the X scroll bar: }
WriteLine(0,YRun,Size.X,1,B[Delta.X]);
END;
END;


{------------------------------}
{ METHODS: TMortgageView }
{------------------------------}

CONSTRUCTOR TMortgageView.Init(VAR Bounds : TRect;
ATitle : TTitleStr;
ANumber : Integer;
InitMortgageData :
MortgageDialogData);
VAR
TopInterior : PMortgageTopInterior;
BottomInterior : PMortgageBottomInterior;
HScrollBar,VScrollBar : PScrollBar;
R,S : TRect;

BEGIN
TWindow.Init(Bounds,ATitle,ANumber); { Call ancestor's constructor }
{ Call the Mortgage object's constructor using dialog data: }
WITH InitMortgageData DO
Mortgage.Init(PrincipalData,
InterestData / 100,
PeriodsData,
12);

{ Here we set up a window with *two* interiors, one scrollable, one }
{ static. It's all in the way that you define the bounds, mostly: }
GetClipRect(Bounds); { Get bounds for interior of view }
Bounds.Grow(-1,-1); { Shrink those bounds by 1 for both X & Y }

{ Define a rectangle to embrace the upper of the two interiors: }
R.Assign(Bounds.A.X,Bounds.A.Y,Bounds.B.X,Bounds.A.Y+4);
TopInterior := New(PMortgageTopInterior,Init(R));
TopInterior^.Mortgage := @Mortgage;
Insert(TopInterior);

{ Define a rectangle to embrace the lower of two interiors: }
R.Assign(Bounds.A.X,Bounds.A.Y+5,Bounds.B.X,Bounds.B.Y);

{ Create scroll bars for both mouse & keyboard input: }
VScrollBar := StandardScrollBar(sbVertical + sbHandleKeyboard);
{ We have to adjust vertical bar to fit bottom interior: }
VScrollBar^.Origin.Y := R.A.Y; { Adjust top Y value }
VScrollBar^.Size.Y := R.B.Y - R.A.Y; { Adjust size }
{ The horizontal scroll bar, on the other hand, is standard: }
HScrollBar := StandardScrollBar(sbHorizontal + sbHandleKeyboard);

{ Create bottom interior object with scroll bars: }
BottomInterior :=
New(PMortgageBottomInterior,Init(R,HScrollBar,VScrollBar));
{ Make copy of pointer to mortgage object: }
BottomInterior^.Mortgage := @Mortgage;
{ Set the limits for the scroll bars: }
BottomInterior^.SetLimit(80,InitMortgageData.PeriodsData);
{ Insert the interior into the window: }
Insert(BottomInterior);
END;


PROCEDURE TMortgageView.HandleEvent(Var Event : TEvent);

BEGIN
TWindow.HandleEvent(Event);
IF Event.What = evCommand THEN
BEGIN
CASE Event.Command OF
cmExtraPrin : ExtraPrincipal;
cmPrintSummary : PrintSummary;
ELSE
Exit;
END; { CASE }
ClearEvent(Event);
END
ELSE
IF Event.What = evBroadcast THEN
CASE Event.Command OF
cmCloseBC : Done
END; { CASE }
END;


PROCEDURE TMortgageView.ExtraPrincipal;

VAR
Control : Word;
ExtraPrincipalData : ExtraPrincipalDialogData;

BEGIN
{ Execute the "extra principal" dialog box: }
Control := Desktop^.ExecView(HouseCalc.ExtraDialog);
IF Control <> cmCancel THEN { Update the active mortgage window: }
BEGIN
{ Get data from the extra principal dialog: }
HouseCalc.ExtraDialog^.GetData(ExtraPrincipalData);
Mortgage.Payments^[ExtraPrincipalData.PaymentNumber].ExtraPrincipal :=
ExtraPrincipalData.ExtraDollars;
Mortgage.Recalc; { Recalculate the amortization table... }
Redraw; { ...and redraw the mortgage window }
END;
END;


PROCEDURE TMortgageView.PrintSummary;

BEGIN
END;


DESTRUCTOR TMortgageView.Done;

BEGIN
Mortgage.Done; { Dispose of the mortgage object's memory }
TWindow.Done; { Call parent's destructor to dispose of window }
END;



BEGIN
HouseCalc.Init;
HouseCalc.Run;
HouseCalc.Done;
END.

  3 Responses to “Category : Files from Magazines
Archive   : DDJ0292.ZIP
Filename : HCALC.ASC

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/