TweetFollow Us on Twitter

Quadratic Plotters 2
Volume Number:5
Issue Number:9
Column Tag:MacApp Workshop

A Tale of Two Quadratic Plotters, Part II

By Carl Nelson, Chuck McMath, Hillsborough, VA

Another point of view

When I started my efforts, I had to bring the program into the MPW environment, after all I started with someone else’s code and wanted to cut and paste as much as I could. The first thing I did was run the source code through the MPW tool ‘MapObjects.’ This handy tool finds all Pascal UNITs defined in the files you give it to digest, then it goes about finding all PROCEDUREs, FUNCTIONs and Objects that are defined. As it encounters the source code it remembers where (file and offset) it saw implementations of the procedures, then it writes out a database (called an ObjectMap) which can then be used by the Browser Desk Accessory to find and view procedures, functions and objects. Essentially you get a list of all Pascal UNITS, in alphabetical order, seen by MapObjects and for every by Pascal UNIT you can see, in alphabetical order, all PROCEDURES and FUNCTIONS contained in the UNIT. You can then click on the name of a PROCEDURE and the DA fetches it for you to view. It is a read-only browser, but you can cut from the displayed text and paste it into your MPW file. (I also pass the latest MPW interfaces through MapObjects. This way I always have them online when I need to cut and paste a Toolbox call.)

Displayed below is the output from doing a ‘MapObjects -hvsm’ on the original MacTutor Code. Note that where a line has two items on it, the second item is the name of the file containing that unit:

 Program

 QuadraticPlotter plotter
 QuadraticPlotter-Private plotter
 main
 initRects
 doUpdates
 doMulti
 doMouse
 doKeyDowns
 doActivates
 crash
 MainEventLoop
 InitMyWindow
 InitMyMenus
 InitMac
 Unit

 PlotGlobals PlotGlobals 
 MyFileStuff myFileStuff
 doSaveAs
 doSave
 MyPlotStuff myPlotStuff
 doQuit
 doMenubar
 doGrow
 doDrag
 doContent
 doAbout
 Misc Misc
 doMessage
 MyPrintStuff myPrintStuff
 doPrint
 doPageSet
 MyPrintStuff-Private myPrintStuff
 PrintMe
 solve solve
 solveit
 quad
 doPlot
 PrQDStuff
 solve-Private solve
 positivecalc
 negativecalc
 doDialog
 PlotMe

The Browser turns out to be very helpful in understanding the MacTutor sources. I am not a veteran of previous MacTutor code so I did not know where Dave had decided to hide various parts of the code. I had expected that Dave’s code would have some organizing principles that he used to decide where to put PROCEDURES and FUNCTIONS. The article pointed the way but you can also see it from the MapObjects output. The main program is contained in the file ‘plotter’. Code to initialize things was found in the Init routines in the main file ‘plotter’. What struck me was the pragmatic organization of the code. The principles that organized it seemed straightforward and general enough but I would never have guessed where the functionality would actually be found. I had forgotten how much my familiarity with MacApp and its architecture caused me to make certain assumptions when looking at someone else’s code.

For example, when I first received a copy of Chuck’s code I wondered if he had taken the time to implement the full page printing option. Knowing MacApp, I knew he would have created a DoSetupMenus and a DoMenuCommand to handle the functionality. So to check his code out I used the MPW search command to find all occurrences of DoSetupMenus in the .inc1.p file he sent and sure enough, I found he had two DoSetupMenus, one in TQPlotApplication and the other in TQPlotView. Selecting the line with TQPlotView yielded exactly what I wanted to know, it used a field (fOnePage) to place a checkmark beside a couple of menu entries that had associated command names of cPrintWS and cPrintPS which I deduced were probably print window size and print page size which corresponded to the original MacTutor code. Having such strong notions of where things are (and ought to be) makes it easy to maintain and extend someone else’s source code. [Chuck’s note: the reason Carl was able to find that section of my code so easily was partially because of the ‘MacApp pact’ I signed when I converted the code to MacApp -- I agreed to place the code (actually I had very few other choices, being a good MacApp citizen and all) which deals with menu selections in the method DoMenuCommand, and Carl knows this.]

In terms of external design features, the original plot program had two things that caught my attention. First was that the PICT was always drawn to fill the window and the second was that a modal dialog was put up to get the parameters for the equation. I thought that always filling the window was a bit odd but, hey, I’m not really an engineer who plots quadratics all the time (if ever) so I felt that should be left alone. I actually had to do extra work to make the program behave this way. In the MacApp framework the simplest case would have been to setup a fixed size page or view area and then let MacApp scroll the image around for you. The modal dialog was probably an expedient design; there has to be a better user interface. I thought that it would be far better if the plot parameters could be entered in the plot window. My design was simple: put all the fields from the modal dialog into a panel to the side of the plot area, let the user click and type new parameters at any time in a modeless fashion, and then let the user choose PLOT from the menu or press the ENTER key to cause the plot to occur. This simple design change allows multiple windows with their plots and parameters that created them to be showing at the same time.

Figure 1.

The original program only allowed the choice of 8 colors for the plot. I thought as an example program that it should use the new Palette manger and let the user color as many parts of the plot with any color. Also I thought it would be nice to allow for the selection of fonts and typestyles using the hierarchical menus. Besides, I could easily cut and paste all these features from the MacApp samples.

In starting my port of the code I was going to use an external data structure to hold the pertinent data. After I started the design it became obvious that if I did a little bit of encapsulation it would be a good example of the right path to follow and clearly show the advantages of using Objects just like in Chuck’s program; I gave the original plot program’s data to the appropriate object to manage.

As Chuck pointed out, there are always three methods you will override: TApplication.DoMakeDocument, which creates the appropriate type of Document object; TDocument.DoMakeViews which creates the appropriate type of View and window objects and finally TView.Draw which Draws the contents of a view in your window or on the page.

I had to declare a Document type (TPlotDoc) that DoMakeDocument could bring into existence. This document would hold the plots we would be writing to disk. The files created by this document would be readable with MacDraw and able to be placed into PageMaker. In order to read back these files I implemented a DoRead for TPlotDoc. Granted, it is a simple minded effort but it shows where it should be done. To properly implement writing and reading the plot parameters should also be written and read back.

When a document is created its DoMakeViews method is called to create the views that will display the data in the document. In MacApp 2.0 you can create views by doing a NEW for each view component and setting up the data structures, or you can (preferably) create resources that describe your views and let MacApp read them, create the objects and fill in their data structures. These resources are best created using Apple’s ViewEdit. ViewEdit knows about MacApp view resources and lets you build and arrange on screen the view components that will make up your displays. It is indispensible in creating Applications with MacApp 2.0.

In looking at the view hierarchy, we start with a window which is handled by a standard TWindow. In the window is a dialog handled by TPlotDialog. The dialog contains two display clusters and a scroller. The two clusters contain StaticText and NumberText view items that are used for collecting the equation coefficients and the plot parameters. The scroller contains the plot view which is handled by a TPlotView. The plot view contains a subview for holding the solution text box. It is handled by a TSolutionView.

This hierarchy of views are brought into existence by TPlotDoc’s DoMakeViews call to NewTemplateWindow. As each component of the view hierarchy is brought in existence, the associated object which will handle it is found and created by DoCreateViews.

For the TStaticText and TNumberText views MacApp handles all the display and collection of keystrokes. MacApp 2.0ß8 does not have facilities for handling NumberViews with Real numbers, an oversight in the rush to get MacApp 2.0 out the door. Calvin Cock wrote an article (and contributed the code and resources) for publication in the Dec ’88 Frameworks describing the a new view called TExtendedText which handles real numbers (plug: join the MacApp Developer’s Association and receive Frameworks). Instead of reinventing the wheel, I used Calvin’s ExtendedText Views in the Clusters.

Here is a summary of the view hierarchy which produced the window in Figure 1:

In what I would call a fairly straightforward MacApp approach, TPlotDoc holds the parameters for the plot and TPlotDialog holds the PicHandle generated from the original data structure and does the display of the PICT. TPlotView and TSolutionView do all the work of actually drawing the PICT. Further work could be done on encapsulating and distributing the plotting and display. In particular, PRQDStuff from the original was a fairly large routine that did all the drawing work. I thought it might be proper to split it apart into a controlling object and objects that drew parts of plot. Not to go overboard, but to illustrate the point, I chose to have TPlotDialog create the wrapper and have it call the appropriate component parts that composed the PICT. TPlotDialog sets up the PICT and asks the other objects that it knows draw into it. It should be possible with the framework I have provided to move each AXIS and its labeling into separate views that can be setup independently.

The current design does not utilize any of the MacApp framework to do interactive graphing. If the design of the program changed not to include re-scaling the PICT to the window, it would be possible to create an interaction with the PlotView. For example, you could grab the plot and move it around to show how the coefficients vary.

Given how easy it is to create multiple windows and documents, it would be easy to create plot types and custom windows for different equations. To do this would require that you create new types of plot and view objects then override MacApp’s OpenNew method to create the desired new kind of plot document and window.

As Chuck stated MacApp provides a command mechanism for undo and redo. If you look at the menu handling code for changing the plot color and text you will see how I have implemented Undo/Redo by saving and restoring the plot characteristics. I did not go all the way by invaliding the Plot and forcing a redraw instead I, like the Daves, wait until the next plot is drawn. If you look at TPlotDialog.DoKeyCommand you will see how easy it would be to have TPlotDoc.DoMenuCommand force a redraw.

Analysis

Now that we have each discussed our programs, we need to sit back a little and see just what we got out of MacApp. While Carl’s version is obviously an improvement given the number of features he added, the benefits of Chuck’s version are not so obvious. So Chuck re-takes the floor to convince you he’s done a good job.

How much time do we spend doing things?

With all of the preceding discussion of my objects, it may seem that we are doing a lot of work in what is admittedly a simple application. Let’s see if this is the case. I have analyzed the original and my code to see what percentage of code is used for different functions. This analysis is not perfect in that the original and new versions were written by different people, and therefore it does not allow for different programming styles, but still, the end application is the same (or as similar as a MacApp and non-MacApp application can be), so we can get an idea of where we spent our time. I split the source code into five different categories:

• user interface: the Macintosh look -- windows, menu setup and enabling, the ‘generic’ Mac portion. What code was necessary to make the application look like a Macintosh application? Note that this does not include the code to actually accomplish anything; that’s in the next section.

• interaction: the portion of the code that handles any user interaction & event processing. Anything that was written to handle interaction between the user and the application was assigned here.

• input/output routines: any code involved with actually reading or writing data to the disk. This portion also includes code used to print the window, since I considered that an output operation.

• program processing: this portion of code is anything that needed to be written to calculate or determine anything. This code does not have any corresponding on-screen elements.

• initialization and other: this category was used for all pieces of code that I couldn’t assign anywhere else.

Chart 1 shows for each category: the number of lines of code written for each version, and Chart 2 the percent of the total code that each section represents (comments and blank lines were removed before the count was made, so this is only counting executable code; 1405 for the original and 705 for MacApp).

Chart 1: Lines of Code comparison: Original vs. MacApp

The first difference that should jump out at you is the number of lines of code written. The MacApp version has half the number of lines as the non-MacApp version. Not only are there fewer lines, but the MacApp version has more features than the original version -- it allows multiple windows on the screen and scrolls the window contents, to name two. In addition, the MacApp feature follows Apple’s user interface guidelines more closely in the page size/window size feature of the plot. In the original version, selecting ‘window size’ changes the printed output, but does not change the display in the window -- violating the WYSIWYG principle (What You See Is What You Get). So there’s another area in which the MacApp program outperforms the original one. Still another area in which the MacApp version improves on the original is in menu handling. The original version has the Edit menu always enabled, even though those menu items do not apply to anything displayed in the window; you can also erroneously try to save or print before you have a plot window on the screen. Again, these operations violate the user interface guidelines -- only appropriate menu items should be enabled. Yet the MacApp version does enable all of its menu items correctly. Why? Because of the design of MacApp.

It’s interesting to compare how time was spent in creating the two versions (assuming that the code was written at a constant rate. I know this is not an entirely rational assumption, but it’s all we have to go on). I’ve been talking about how MacApp helps you by implementing the standard user interface elements, but looking at the chart you see that the MacApp program has four times as much user interface code (relatively speaking). Does this mean that I was lying? I sure hope not! The reason for so much user interface code in the MacApp version is that there is a fixed amount of overhead associated with handling menu, mouse, and key events. This overhead is in the form of procedures which must be overridden to provide for the user interface processing. In addition, each object which handles these events must override the appropriate methods to provide the processing. Writing the code for all of these overrides adds up. However, once the procedures are overridden, adding more functionality to the processing is simple and does not require much more code. On the other hand, look at the amount of code we wrote to deal with interaction -- the MacApp implement spent only half as much time implementing its interaction code. This is because we build upon the foundation that MacApp provides, and only have to add code to support the extra functionality we wish to provide. MacApp takes care of the normal interaction.

Chart 2: Percent of Code: Original vs. MacApp

This application is somewhat unusual in that the amount of ‘pure’ processing code is rather small, although it’s interesting that the relative amount of processing code is constant. One last thing to note is the amount of code in the ‘Other’ category. As I categorized the source code for the MacApp version, I realized that much of the code fell into this category. That’s because MacApp programs spend a lot of time initializing objects, creating windows and views and documents, and doing a lot of things that are difficult to categorize.

Chart 3 shows the amount of code that came directly from the original version to the MacApp version. The first column is the number of lines of code that was directly cut and pasted from the old version to the new. The second column is the total number of lines in the new category. The third column shows the percentage of each category that the old code makes up. This chart is instructive in that it shows how much of your non MacApp program you will be able to reuse. It shouldn’t be surprising that none of the interaction or user interface code was transferable; it’s a little more surprising that none of the ‘other’ code was applicable. If you think about it, however, the MacApp ‘other’ category is made up of code which is pretty specific to MacApp -- object creation and initialization, and the object definitions. This code could not have come from the original program.

# Lines Taken Total in New % of New

Input/Output 181 211 86

Interaction 0 108 0

Other 0 221 0

Processing 48 48 100

User Interface 0 117 0

Totals 229 705 N/A

Chart 3: Code requiring no conversion

As you can see, all of the processing code used in the MacApp program came directly from the original version. This should give some weight to my assertion that in a MacApp program you need to concentrate on the unique portion of your application -- for indeed, in the plotter application, the processing is the unique portion. And note also that most of the input/output routines came directly from the original version. Most of this code is related to creating and printing the PICT, and of course remains the same no matter whether you’re using MacApp or not.

The bottom line here, though, is that the MacApp version only required 50% as much code as the original version; and fully one-third of that code was lifted directly from the original, which means that the MacApp version only had around 500 new lines of code -- one third as much as the original. And this does not yield a program that is crippled or partially functional, it yields a program that conforms to the user interface guidelines, is fully functional (within its design), and is a good bet to run on future Macintosh architectures (not to mention A/UX). This is the big win we get from MacApp: not something for nothing, but more results for less work. Sure, you have to change your thinking, but all I can say is this: look at the bottom line.

Conclusion

So there you have it -- two views of a MacApp conversion effort, from two slightly different viewpoints. Although the two MacApp programs may seem quite different, they are much more similar to each other than either is to the original effort. If Carl and I swapped our two MacApp programs and each had to add a feature to them, we would be able to much more easily than if we were to try the same on the original program. All MacApp programs share a structure, an organization; different programs do similar things in the same place. Reusing code from one MacApp program to another is increased. You don’t have to spend time searching for the procedure or function you want -- you will know where to find it.

We hope you have some idea of the benefits of MacApp and that you’ll not only get more done, but you’ll get it done more quickly (once you become a MacApp citizen), and your final product will be a real professional job. MacApp is the wave of the future -- catch it today! [Aw Come-on Chuck, knock it off.]

UPlot.p  Plot UNIT FILE
{[a-,body+,h,o=100,r+,rec+, t=4,u+,#+,j=20/57/1$,n+]}
{ The above is the official MacApp PasMat Style statement.What you don’t 
use pasmat to make all your source code conform to your company’s (or 
personal) standard for source code style? }

{Copyright © 1986-1988 Apple Computer, Inc.
  All rights reserved.}
{Copyright © 1989 by Software Architects, Inc.
  All rights reserved.}
{Portions Copyright © 1988 MacTutor
    All rights reserved.}

{[f-]}
(*
 This is a very small sample application which uses concepts and program 
fragments presented in the February 1988 MacTutor Plot Article. 
By looking at this program you may be able to gain a better understanding 
of how to cast a conventional program into the MacApp “Application Framework” 
or (Class structure depending upon whose jargon you wish to use).
In the tradition of MacApp it defines the basic three Class (object) 
overrides:
TPlotApplication.DoMakeDocument  -- Launches appropriate type of Document 
object.
TPlotDoc.DoMakeViews -- Launches appropriate type View and window objects.
TPlotDialog.Draw --  Calls it sub components to draw the contents of 
a view.
 TPlotView--  To actually plot the thing
 TSolveView --  To draw the solution text box
In addition it defines commands unique to the plot program. See the text 
of the accompaning article for detials.
*)
{[f+]}

UNIT UPlot;
INTERFACE
 USES
 { • MacApp - this includes all of the things
 necessary from the MacApp Library }
 UMacApp, 

 { • Building Blocks }
 UDialog, UPrinting, UExtendedText,

 { • Implementation Use }
 SANE, ToolUtils, Fonts, Resources,
  Script, PickerIntf, Packages;

 CONST
 kSignature = ‘Plot’;
 { Application signature}
 kFileType= ‘PICT’;
 { File-type code used for document files
 created by this application}
 kPlotDialog= 1010;
  
{  MacApp uses a very useful technique for seperating menu item numbering 
from what you want done by chosing a menu item.  See MacApp manual pggs 
xxx-xx  for full details.  Work is done in MacApp with commands.  Each 
command is assigned a unique number.  For example Save is 30 and SaveAs 
is 32.  Numbers below 1200 are reserved for MacApp.  In this Application 
we have chosen a command numbering scheme that makes life easy:
 Application Commands= 1400
 Font styles     = 2000
 Font sizes      = 2100
 Font just       = 2200
 Font fonts      = 2300
 Hierarchical Menus= 2400
 Plot colors= 2500
 }
 
{ the command to cause a plot to happen }
 cPlotIt= 1401;
 
{ Command numbers for typestyle attributes }
 cPlainText = 2001;
 cBold  = 2002;
 cItalic  = 2003;
 cUnderline = 2004;
 cOutline = 2005;
 cShadow  = 2006;
 cCondense= 2007;
 cExtend  = 2008;
 
{ Command numbers for font-size commands }
 cSizeChange   = 2100;
 cSizeBase= 2100;
 cSizeMin = 2109;
 cSizeMax = 2124;
 
{ 2101-2197 reserved for font sizes 1-97 pts. }
 cSizeGrow= 2198;
 cSizeShrink   = 2199;
 
{ Command numbers cover other stylistic changes }
 cJustChange   = 2200;
 cJustLeft= 2201;
 cJustCenter   = 2202;
 cJustRight = 2203;
 cFontChange   = 2300;
 
{ Command numbers for the hierarchial menu }
   cStyle = 2401;
 cSize  = 2402;
 cFont  = 2403;
 cColor = 2404;
 
{ Command numbers for changing colors }
 cColorChange  = 2500;
 cColorText = 2501;
 cColorBackground= 2502;
 cColorGraph= 2503;
 cColorAxis = 2504;
 
{ Constant for amount to relative
  size text selection }
 kRelSizeAmount  = 4;

{ Constants for the prompts string list }
 kPromptsRsrcID  = 1001;
 kColTextPrompt  = 1;
 kColBackPrompt  = 2;
 kColGraphPrompt = 3;
 kColAxisPrompt  = 4;
 
{ Menu numbers }
 mFont  = 10;  
 
{ Menus displayed on hier. menu system }
 kHierDisplayedMBar= 131;

{ Menus displayed on non-hier. system }
 kNonHierDisplayedMBar = 128;

{ Offset added to non-hier menu cmds to get }
 kHierMenuOffset = 1000;
 { ‘view’ resource for default values }
 kViewRsrcID     = 1005;
 
{ PICT comments for our plot and text box }
 {selected MacDraw comments}
 picDwgBeg  = 130;
 picDwgEnd= 131;
 picGrpBeg  = 140;
 picGrpEnd  = 141;
 TextBegin  = 150;
 TextEnd  = 151;
 StringBegin= 151;
 StringEnd  = 153;
 TextCenter = 154;

 {postscript comments}
 SetLineWidth    = 182;
 PostScriptBegin = 190;
 TextIsPostscript  = 194;
 PostScriptEnd   = 191;
 
 { The size of a MacDraw Header }
 kHeaderSize   = 512;
 
 TYPE
 QuadraticType = (NotSolved, RealRoots,
 SingleSolution, ComplexRoot);

 {specifications of text display}
 PlotSpecs= RECORD
 theTextFont:    Str255;
 theFontNum:INTEGER;
 theTextFace:    Style;
 theTextSize:    INTEGER;
 theJustification:INTEGER; { text }
 theTextColor:   RGBColor; { label color }
 theGraphColor:  RGBColor;
 theAxisColor:   RGBColor;
 theBackColor:   RGBColor;
 END;

 PlotSpecsPtr    = ^PlotSpecs;
 PlotSpecsHdl    = ^PlotSpecsPtr;

{ Object Definitions }
{------------------------------------}
 TPlotApplication = OBJECT (TApplication)

 { Initialize application and globals. }
 PROCEDURE TPlotApplication.IPlotApplication(
 itsMainFileType: OSType);

 { Launches a TPlotDocument }
 FUNCTION TPlotApplication.DoMakeDocument(
 itsCmdNumber: cmdNumber): TDocument;
 OVERRIDE;
 
 PROCEDURE TPlotApplication.IdentifySoftware;
 OVERRIDE;
 PROCEDURE TPlotApplication.Fields(
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType:INTEGER));
 OVERRIDE;
 END; { TPlotApplication }
 
 {------------------------------------}
 TPlotDoc = OBJECT (TDocument)
 fPlotDialog: TPlotDialog;
 fPlotSpecs : PlotSpecs;
 fOldPlot : PicHandle;
 
 { coefficients to our quadratic equation }
 faParam: Real;
 fbParam  : Real;
 fcParam: Real;

 { plot display parameters }
 fstepParam : Real;
 fxParam: INTEGER;
 fyParam  : INTEGER;
 
 { the solutions to our quadratic }
 f1stRoot : Real;
 f2ndRoot : Real;
 
 fRootType: QuadraticType;
 
 { setup for the document to hold the plot }
 PROCEDURE TPlotDoc.IPlotDocument;
 
 { For new doc or revert  initial state }
 PROCEDURE TPlotDoc.DoInitialState; OVERRIDE;

 { Generate command to change Look of a plot }
 FUNCTION TPlotDoc.DoMakePStyleCmd( itsStyle:PlotSpecsPtr; itsCmdNumber:CmdNumber): 
TPStyleCmd;
 
 { create all the views needed for document }
 PROCEDURE TPlotDoc.DoMakeViews(forPrinting: BOOLEAN); OVERRIDE;
 
 { calculater how much disk space this
  document will need }
 PROCEDURE TPlotDoc.DoNeedDiskSpace(
  VAR dataForkBytes, rsrcForkBytes: LONGINT);
 OVERRIDE;
 
 { read the data for this document }
 PROCEDURE TPlotDoc.DoRead(
 aRefNum: INTEGER; rsrcExists,
 forPrinting: BOOLEAN); OVERRIDE;
 
 { write the data for this document }
 PROCEDURE TPlotDoc.DoWrite(aRefNum: INTEGER;
  makingCopy: BOOLEAN); OVERRIDE;
 
 { given a Menu choice handle or pass it on }
 FUNCTION TPlotDoc.DoMenuCommand(
 aCmdNumber: cmdNumber): TCommand;
 OVERRIDE;

 { setup the menus for the document }
 PROCEDURE TPlotDoc.DoSetupMenus; OVERRIDE;
 
 { given the parameters of our
 document calculate a solution }
 PROCEDURE TPlotDoc.SolveQuadratic;

 PROCEDURE TPlotDoc.ChangeBackColor(
 newColor: RGBColor);

 {$IFC qDebug}
 PROCEDURE TPlotDoc.Fields(
 PROCEDURE DoToField(
 fieldName: Str255;
 fieldAddr: Ptr;
   fieldType: INTEGER));
 OVERRIDE;
 {$ENDC}
 
 END; { TPlotDoc }
 
 TPlotView= OBJECT (TView)
 fPlotDoc : TPlotDoc;
 
 { Add to the pict we will draw on
          the screen or printed page }
 PROCEDURE TPlotView.AddToPict(picRect:Rect);
 
 { A convenience routine }
 PROCEDURE TPlotView.GetQDFrame(
 VAR frameRect:Rect);
 
 { The design says the plot fills the
   window, therefore when we are
   resized we must invalidate ourselves}
 PROCEDURE TPlotView.Resize(width,
  height: VCoordinate; invalidate: BOOLEAN);
 OVERRIDE;
 END;
 
 TSolutionView = OBJECT (TView)
 fPlotDoc : TPlotDoc;
 fSolveRect : Rect;
 
 { Add to pict we will draw on the screen or printed page }
 PROCEDURE TSolutionView.AddToPict(picRect:Rect);
 END;
 
 TPlotDialog= OBJECT (TDialogView)
 fPlotSize: VPoint;
 fPlotView: TPlotView;
 fSolutionView : TSolutionView;
 fPlotDoc : TPlotDoc;
 fPlotPICT  : PicHandle;

 FUNCTION  TPlotDialog.DoKeyCommand(
 ch: CHAR; aKeyCode: INTEGER;
 VAR info: EventInfo): TCommand;
 OVERRIDE;
 FUNCTION  TPlotDialog.DoMenuCommand(
 aCmdNumber: CmdNumber):TCommand;
 OVERRIDE;

 PROCEDURE TPlotDialog.DismissDialog(
 dismisser: IDType; flashDismisser: BOOLEAN);
 OVERRIDE;

 PROCEDURE TPlotDialog.Draw(area: Rect);
 OVERRIDE;

 PROCEDURE TPlotDialog.EachSubView(
 PROCEDURE DoToSubView(
 theSubView: TView));
 OVERRIDE;
 
 PROCEDURE TPlotDialog.PlotNDrawPICT;
 
 PROCEDURE TPlotDialog.GetPlotValues;

 PROCEDURE TPlotDialog.DoSetupMenus; OVERRIDE;
 
 END;

 TPStyleCmd = OBJECT (TCommand)
 fPlotDialog: TPlotDialog;
 fOldPlotSpecs   : PlotSpecs;
 fNewPlotSpecs   : PlotSpecs;
 
 { Initialize the command; if unsuccessful,
 signalled by Failure mechanism }
 PROCEDURE TPStyleCmd.IPStyleCmd(
 itsPlotDialog:TPlotDialog; 
 itsNewStyle:PlotSpecsPtr;
 itsCmdNumber: CmdNumber);

 PROCEDURE TPStyleCmd.DoIt; OVERRIDE;
 PROCEDURE TPStyleCmd.RedoIt; OVERRIDE;
 PROCEDURE TPStyleCmd.UndoIt; OVERRIDE;
 END;

 VAR
 gDefaultSpecs:  PlotSpecs;
 { a Menu Management Global }
 gMenuOfs:INTEGER;
 { Convenience, fetching string from resource }
 gPromptString:  Str255;

IMPLEMENTATION
{ I M P L E M E N T A T I O N }
{--------------------------------}
{$S ARes}
{ Generallly useful routines }
FUNCTION GetPrompt(index: INTEGER): StringPtr;
 BEGIN
 GetIndString(gPromptString,
  kPromptsRsrcID, index);
 GetPrompt := @gPromptString;
 END;

FUNCTION Real2Str(aReal: Real; theDigits: INTEGER): Str255;
 VAR  aStr: DecStr;
 form : DecForm; 
 BEGIN
 form.style  := FixedDecimal;
 form.digits := theDigits;
 Num2Str(form,aReal,aStr);
 
 Real2Str := aStr;
 END;

{$IFC qDebug}
{$IFC qTrace} {$D+} {$ENDC}
{ In the final version of MacApp 2.0 there will some kind of support 
for REAL numbers in text entry fields, for now we use Calvins Cock’s 
code from the Dec ’88 Frameworks }
 
PROCEDURE MyFieldToString(theData: Ptr;
      fieldType: integer; VAR theString: str255);
 CONST
 DecPrec = 2;
   { Change if you want more decimal precision }
   TYPE
      TAlias              = RECORD
         CASE integer OF
            bReal, bSingle: (asReal : Real);
            bDouble: (asDouble : Double);
            bExtended: (asExtended : Extended);
         END;
   VAR
      alias              : ^TAlias;
      aDecForm           : DecForm;
      x                  : Extended;
      NumStr             : DecStr;
   BEGIN
      alias := Pointer(theData);
      WITH alias^ DO
         CASE fieldType OF
            bReal, bSingle:
               BEGIN
                  aDecForm.style := FixedDecimal;
                  aDecForm.digits := DecPrec;
                  x := asReal;
                  Num2Str(aDecForm, x, NumStr);
                  theString := str255(NumStr);
               END;
            bDouble:
               BEGIN
                  aDecForm.style := FixedDecimal;
                  aDecForm.digits := DecPrec;
                  x := asDouble;
                  Num2Str(aDecForm, x, NumStr);
                  theString := str255(NumStr);
               END;
            bExtended:
               BEGIN
                  aDecForm.style := FixedDecimal;
                  aDecForm.digits := DecPrec;
                  x := asExtended;
                  Num2Str(aDecForm, x, NumStr);
                  theString := str255(NumStr);
               END;
            OTHERWISE StdFieldToString(theData,
  fieldType, theString);
         END;
   END;

{$IFC qTrace} {$D++} {$ENDC}
{$ENDC qDebug}

{--------------------------------}
{$S AReadFile}
PROCEDURE ReadBytes(theRefNum: INTEGER;
   size:LONGINT; buffer: Ptr);
{ Utility for reading data from a file }

 BEGIN
 FailOSErr(FSRead(theRefNum, size, buffer));
 END;


{--------------------------------}
{$S AWriteFile}
PROCEDURE WriteBytes(theRefNum: INTEGER;
  size: LONGINT; buffer: Ptr);
{ Utility for writing data to a file. }
 BEGIN
 FailOSErr(FSWrite(theRefNum, size, buffer));
 END;

{------------------------------------------}
{$S AInit}

PROCEDURE TPlotApplication.IPlotApplication(
 itsMainFileType: OSType);
 VAR
 fontName:Str255;
 aTEView: TTEView;

 BEGIN
 
 { qNeedsHierarchialMenus is a MacApp compile time flag you can set which 
will require the use of Heirarchical Menus }
 
 {$IFC NOT qNeedsHierarchialMenus}
 IF NOT gConfiguration.hasHierarchicalMenus THEN
 BEGIN
 gMBarDisplayed := kNonHierDisplayedMBar;
 gMenuOfs := 0;
 END
 ELSE
 {$ENDC}
 BEGIN
 gMBarDisplayed := kHierDisplayedMBar;
 gMenuOfs := kHierMenuOffset;
 END;
 
 IApplication(itsMainFileType);
 
 { Do not setup the menus if we were started up with the request to print 
}
 IF NOT gFinderPrinting THEN
 BEGIN
 AddResMenu(GetMHandle(mFont), ‘FONT’);

 SetStyle(cBold, [bold]);
 SetStyle(cUnderline, [underline]);
 SetStyle(cItalic, [italic]);
 SetStyle(cOutline, [outline]);
 SetStyle(cShadow, [shadow]);
 SetStyle(cCondense, [condense]);
 SetStyle(cExtend, [extend]);
 END;

{ This is an example of questional code reuse. We know that TTEVIEWS 
holds lots of info about fonts, sizes and color and we have the Viewedit 
tool at our disposal, so why not use it to create a useful resource to 
get our initial values from instead of hard-wiring the defaults. The 
technique here is to define a TTEView resource and use all those great 
fields that you can setup with viewEdit as the defaults, then steal the 
values from the TTEVIEW object and trash the TTEView once all the work 
is done. }
 
 {fetch the resource}
 aTEView := TTEView(DoCreateViews(NIL, NIL,
  kViewRsrcID, gZeroVPt));
 FailNIL(aTEView);
 
 { Set up initial text specs }
 GetFontName(aTEView.fTextStyle.tsFont, fontName);
 WITH gDefaultSpecs, aTEView DO
 BEGIN
 theTextFont := fontName;
 theTextFace := fTextStyle.tsFace;
 theTextSize := fTextStyle.tsSize;
 theTextColor := fTextStyle.tsColor;
 theJustification := fJustification;
 theBackColor := gRGBWhite;
 END;
 aTEView.Free;

 { Until MacApp 2.0 debug and ViewTemplates support REALs this is our 
work around from Calvin Cock’s January ’89 MapApp Frameworks article. 
}
 gFieldToStrRtn := @MyFieldToString;

 END;

{------------------------------------------}
{$IFC qDebug}
{$S ADebug}
PROCEDURE TPlotApplication.IdentifySoftware;

 BEGIN
 WriteLn(‘Plot Source date: 31 Jan 89;Compiled:’,
  COMPDATE, ‘ @ ‘, COMPTIME);
 INHERITED IdentifySoftware;
 END;

PROCEDURE TPlotApplication.Fields(
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType:INTEGER));
 OVERRIDE;
 BEGIN
 WITH gDefaultSpecs DO
 BEGIN
 DoToField(‘  Font’, @theTextFont, bFontName);
 DoToField(‘  Face’, @theTextFace, bStyle);
 DoToField(‘  Size’, @theTextSize, bInteger);
 END;
 END;
{$ENDC}

{************************************************}
{  T P l o t D o c u m e n t   }
{***** ******************************************}
{------------------------------------------}
{$S AOpen}

PROCEDURE TPlotDoc.IPlotDocument;
 VAR
 aRect: Rect;
 BEGIN
 IDocument(kFileType, kSignature,
  kUsesDataFork, NOT kUsesRsrcFork,
  NOT kDataOpen, NOT kRsrcOpen);
 fOldPlot := NIL;
 END;

{------------------------------------------}
{$S AOpen}
FUNCTION TPlotApplication.DoMakeDocument(itsCmdNumber: cmdNumber): TDocument;
 VAR
 aPlotDocument:  TPlotDoc;
 dimensions:     Rect;
 BEGIN
 { Allocate and initialize the document}
 NEW(aPlotDocument);
 FailNIL(aPlotDocument);
 aPlotDocument.IPlotDocument;
 DoMakeDocument := aPlotDocument;
 END;

{----------------------------------------------}
{$S AOpen}
PROCEDURE TPlotDoc.DoInitialState; OVERRIDE;
 BEGIN
 { when reverting to an old copy of a document we
    need to reset to some reasonable values }
 fPlotSpecs  := gDefaultSpecs;
 fOldPlot := NIL;
 END;

{------------------------------------------}
FUNCTION  TPlotDoc.DoMakePStyleCmd(itsStyle:PlotSpecsPtr;
  itsCmdNumber:CmdNumber): TPStyleCmd ;
 VAR
 aPStyleCmd:TPStyleCmd;
 aPlotDialog: TPlotDialog;
 BEGIN
 New(aPStyleCmd);
 FailNIL(aPStyleCmd);
 aPlotDialog := fPlotDialog;
 aPStyleCmd.IPStyleCmd(aPlotDialog, itsStyle, itsCmdNumber);
 DoMakePStyleCmd := aPStyleCmd;
 END;
 
{------------------------------------------}
{$S AOpen}
PROCEDURE TPlotDoc.DoMakeViews(forPrinting: BOOLEAN);
 VAR
 aWindow: TWindow;
 aPlotDialog:    TPlotDialog;
 aPlotView: TPlotView;
 aTEView: TTEView;
 aSolutionView:  TSolutionView;
 aCluster:TCluster;
 aPrintHandler:  TStdPrintHandler;
 anExtendedText: TExtendedText;
 aRect: Rect;

 BEGIN
 { We want to  dynamically call these in
    exisitance.  Do a New() call for each object
    type, so the linker doesn’t strip them out. }
 IF gCreateWithTemplates THEN 
 BEGIN  
 New(aPlotDialog);
 New(aPlotView);
 New(aTEView);   
 New(aSolutionView);
 New(aCluster);
 New(anExtendedText);
 END;

 { we will now ceate and connect up all the view
    and document variables }

 aWindow := NewTemplateWindow(kPlotDialog, SELF);
 { bring our plot window into exisitance }
 
 aPlotDialog := TPlotDialog(aWindow.FindSubView(‘DLOG’));
 FailNIL(aPlotDialog);
 {find dialog portions & make certian we have it }

 fPlotDialog := aPlotDialog;
 { save this away for late when we need
      to easily find the dialog }
 
 aPlotDialog.fPlotDoc := SELF;
 { and of course we need to cross refer so
      tell the plotdialog who its doc is }
 
 IF (fOldPlot <> NIL)
     | (GetHandleSize(Handle(fOldPlot)) > 0 ) THEN
 aPlotDialog.fPlotPICT := fOldPlot
 { If the document has an old plot PICT display it }
 ELSE
 aPlotDialog.GetPlotValues;
 { Use the values from the resource to
      generate the first plot }

 { Find the PlotView and make some
      connections to our PlotDocument }
 aPlotView := TPlotView(aWindow.FindSubView(‘plot’));
 FailNIL(aPlotView);
 aPlotView.fPlotDoc := SELF;
 aPlotDialog.fPlotView := aPlotView;
 aPlotDialog.fPlotPICT := NIL;
 aPlotDialog.fPlotSize := aPlotView.fSize;

 { Find the SolutionView and make some
     connections to our PlotDocument }
 aSolutionView := TSolutionView(aWindow.FindSubView(‘qslv’));
 FailNIL(aSolutionView);
 aSolutionView.fPlotDoc := SELF;
 aPlotDialog.fSolutionView := aSolutionView;
 
 { while we are at it, retrieve the rectangle
      size we will use to display in }
 SetRect(aRect,0,0,aSolutionView.fSize.h,
        aSolutionView.fSize.v);
 aSolutionView.fSolveRect := aRect;
 
 { we want to limit the minimum size this
     window can be so  use the size of our
    clusters to determine the minimum}
 aCluster:=TCluster(aWindow.FindSubView(‘Ccof’));
 aWindow.fResizeLimits.top:= aCluster.fSize.v*2;
 aWindow.fResizeLimits.left:=aCluster.fSize.h*3;
 aCluster:= TCluster(aWindow.FindSubView(‘Cdsp’));
 aWindow.fResizeLimits.top := aWindow.fResizeLimits.top
           + aCluster.fSize.v;

 NEW(aPrintHandler);
 FailNIL(aPrintHandler);
 aPrintHandler.IStdPrintHandler(SELF, { its document }
    aPlotDialog, { its view }
   { does not have square dots }
    FALSE,{ horzontal page size is fixed }
    TRUE,{ vertical page size is variable
                    (could be set to true on
                     non-style TE systems) }
    FALSE);
 aPrintHandler.fMinimalMargins := FALSE;
 END;

{------------------------------------------}
{$S ASelCommand}
FUNCTION TPlotDoc.DoMenuCommand(
       aCmdNumber: CmdNumber): TCommand; OVERRIDE;
 VAR
 aName: Str255;
 menu:  INTEGER;
 item:  INTEGER;
 newStyle:PlotSpecs;

 {------------------------------------------}
 PROCEDURE DoSizeChange(base: CmdNumber);
 BEGIN
 newStyle.theTextSize := aCmdNumber - base;
 DoMenuCommand := DoMakePStyleCmd(
                          @newStyle, cSizeChange);
 END;

 {----------------------------------------------}
 PROCEDURE DoRelSizeChange(amount: INTEGER);
 BEGIN
 WITH newStyle DO
 theTextSize := theTextSize + amount;
 DoMenuCommand := DoMakePStyleCmd(@newStyle, cSizeChange);
 END;

 {------------------------------------------}
 PROCEDURE DoFontChange;
 BEGIN
 GetItem(GetMHandle(menu), item,newStyle.theTextFont);
 GetFNum(aName, newStyle.theFontNum);
 DoMenuCommand := DoMakePStyleCmd(@newStyle, cFontChange);
 END;

 {--------------------------------------------}
 PROCEDURE DoColTextChange;
 VAR
 aColor:  RGBColor;
 BEGIN
 aColor := fPlotSpecs.theTextColor;
 IF GetColor(Point($00400040),
       GetPrompt(kColTextPrompt)^,
       aColor, newStyle.theTextColor) THEN
    DoMenuCommand := DoMakePStyleCmd(
                           @newStyle, cColorText);
 END;

 {------------------------------------------}
 PROCEDURE DoColGraphChange;
 VAR
 aColor:  RGBColor;
 BEGIN
 aColor := fPlotSpecs.theGraphColor;
 IF GetColor(Point($00400040),
      GetPrompt(kColGraphPrompt)^, aColor,
      newStyle.theGraphColor) THEN
 DoMenuCommand := DoMakePStyleCmd(@newStyle, cColorGraph);
 END;

 {--------------------------------------------}
 PROCEDURE DoColAxisChange;
 VAR
 aColor:  RGBColor;
 BEGIN
 aColor := fPlotSpecs.theAxisColor;
 IF GetColor(Point($00400040),
       GetPrompt(kColAxisPrompt)^, aColor,
       newStyle.theAxisColor) THEN
 DoMenuCommand := DoMakePStyleCmd(
   @newStyle, cColorAxis);
 END;

 {----------------------------------------}
 PROCEDURE DoColBackChange;
 VAR
 aColor:  RGBColor;
 BEGIN
 aColor := fPlotSpecs.theBackColor;
 IF GetColor(Point($00400040),
       GetPrompt(kColBackPrompt)^, aColor,
       newStyle.theBackColor) THEN
 BEGIN
 DoMenuCommand := DoMakePStyleCmd(
                   @newStyle, cColorBackGround);
 END;
 END;

 {----------------------------------------}
 PROCEDURE DoJustChange;
 VAR
 newJust: INTEGER;
 BEGIN
 CASE aCmdNumber OF
 cJustLeft:
 newJust := teJustLeft;
 cJustCenter:
 newJust := teJustCenter;
 cJustRight:
 newJust := teJustRight;
 END;
 newStyle.theJustification := newJust;
 DoMenuCommand := DoMakePStyleCmd(@newStyle, aCmdNumber);
 END;

 {----------------------------------------}
 PROCEDURE DoPlainChange;
 BEGIN
 newStyle.theTextFace := [];
 DoMenuCommand := DoMakePStyleCmd(@newStyle, cStyleChange);
 END;

 {------------------------------------------}
 PROCEDURE DoStyleChange;
 VAR
 newFace : Style;
 BEGIN
 WITH newStyle DO
 BEGIN
 CASE aCmdNumber OF
 cBold:
 newFace := [bold];
 cItalic:
 newFace := [italic];
 cUnderline:
 newFace := [underline];
 cOutline:
 newFace := [outline];
 cShadow:
 newFace := [shadow];
 cCondense:
 newFace := [condense];
 cExtend:
 newFace := [extend];
 END;
 IF newFace * theTextFace = newFace THEN
 theTextFace := theTextFace - newFace
 ELSE
 theTextFace := theTextFace + newFace;
 END;
 DoMenuCommand := DoMakePStyleCmd(
                         @newStyle, cStyleChange);
 END;

 {----------------------------------------}
 BEGIN  { DoMenuCommand }
 DoMenuCommand := gNoChanges;

 newStyle := fPlotSPecs;
 
 CmdToMenuItem(aCmdNumber, menu, item);

 IF menu = mFont THEN
 DoFontChange
 ELSE
 CASE aCmdNumber OF
 cSizeMin..cSizeMax:
 DoSizeChange(cSizeBase);
 cSizeGrow:
 DoRelSizeChange(kRelSizeAmount);
 cSizeShrink:
 DoRelSizeChange( - kRelSizeAmount);
 cJustLeft..cJustRight:
 DoJustChange;
 cPlainText:
 DoPlainChange;
 cBold..cExtend:
 DoStyleChange;
 cColorText:
 DoColTextChange;
 cColorGraph:
 DoColGraphChange;
 cColorAxis:
 DoColAxisChange;
 cColorBackground:
 DoColBackChange;

 OTHERWISE
 DoMenuCommand := INHERITED
  DoMenuCommand(aCmdNumber);
 END;
 END;

{------------------------------------------}
{$S ARes}
PROCEDURE TPlotDoc.DoSetupMenus; OVERRIDE;
 VAR
 hasColor:BOOLEAN;
 hasStyle:BOOLEAN;
 checkPlain:     BOOLEAN;
 checkSize: BOOLEAN;
 checkFont: BOOLEAN;
 specChange:     BOOLEAN;
 just:  INTEGER;
 item:  INTEGER;
 fnt:   INTEGER;
 c:INTEGER;
 aMode: INTEGER;
 aFace: Style;
 aMenuHandle:    MenuHandle;
 aName: Str255;
 aStyle:  TextStyle;
 theFont: INTEGER;
 aStr255: Str255;
 BEGIN
 INHERITED DoSetupMenus;

 hasColor := gConfiguration.hasColorQD;
 hasStyle := gConfiguration.hasStyleTextEdit;

 aStr255 := fPlotSpecs.theTextFont;
 GetFNum(aStr255, aStyle.tsFont);
 WITH aStyle, fPlotSpecs DO
 BEGIN
 tsFace := theTextFace;
 tsSize := theTextSize;
 tsColor := theTextColor;
 END;
 checkPlain := aStyle.tsFace = [];
 checkFont := TRUE;

 aMenuHandle := GetMHandle(mFont);

 GetFontName(aStyle.tsFont, aName);
 { Get real font number in case tsFont is }
 GetFNum(aName, theFont);
 {  the system or application font. }
 FOR item := 1 TO CountMItems(aMenuHandle) DO
 BEGIN
  { There can be more than 31 menu entries
    with scrolling menus, but trying to enable
    an item with number > 31 is bad news.
    If the menu itself is enabled (which it
    will be in MacApp if any of the first 31
    items is enabled), then the extras
    will always be enabled. }
 IF item <= 31 THEN
 EnableItem(aMenuHandle, item);
 IF checkFont THEN
 BEGIN
 GetItem(aMenuHandle, item, aName);
 GetFNum(aName, fnt);
 CheckItem(aMenuHandle, item, fnt = theFont);
 END;
 END;

 just := fPlotSpecs.theJustification;
 { Enable justification related menu items }
 EnableCheck(cJustLeft, TRUE, (just = teJustLeft));
 EnableCheck(cJustCenter, TRUE, (just = teJustCenter));
 EnableCheck(cJustRight, TRUE, (just = teJustRight));

 {$IFC NOT qNeedsHierarchialMenus}
 IF gConfiguration.hasHierarchicalMenus THEN
 {$ENDC}
 BEGIN
 Enable(cStyle, TRUE);    { Enable sub-menus }
 Enable(cSize,  TRUE);
 Enable(cFont,  TRUE);
 Enable(cColor, hasColor);
 END;

 aFace := aStyle.tsFace;
 EnableCheck(cPlainText, TRUE, checkPlain);
          { Enable normal Style menu items }
 EnableCheck(cBold, TRUE, bold IN aFace);
 EnableCheck(cItalic, TRUE, italic IN aFace);
 EnableCheck(cUnderline, TRUE, underline     IN aFace);
 EnableCheck(cOutline, TRUE,  outline  IN aFace);
 EnableCheck(cShadow, TRUE,    shadow  IN aFace);
 EnableCheck(cCondense, TRUE,condense  IN aFace);
 EnableCheck(cExtend, TRUE,    extend  IN aFace);

 FOR c := cSizeMin TO cSizeMax DO
 BEGIN
 IF hasStyle THEN
 checkSize := FALSE
 ELSE
 checkSize := (c - cSizeBase) = aStyle.tsSize;
 EnableCheck(c, TRUE, checkSize);
 
 IF ((NOT hasStyle) |
 { If the record isn’t styled, or }
    RealFont(aStyle.tsFont,c-cSizeBase))
        { the size is a real one }
 THEN aFace := [outline]      {  then we outline it }
 ELSE
 aFace := [];
 SetStyle(c, aFace);
 END;

 Enable(cSizeGrow, TRUE);
 Enable(cSizeShrink, TRUE);

 Enable(cColorText, hasColor);
 Enable(cColorBackground, hasColor);
 Enable(cColorGraph, hasColor);
 Enable(cColorAxis, hasColor);

 END;

{------------------------------------------}
{$S AWriteFile}
PROCEDURE TPlotDoc.DoNeedDiskSpace(
      VAR dataForkBytes, rsrcForkBytes: LONGINT);
 VAR
 r:Rect;
 BEGIN
 { In other MacApp Samples we would normally get
    the Print record space requirements  by doing:
   
 INHERITED DoNeedDiskSpace(dataForkBytes, rsrcForkBytes);
 
   BUT seeing as we are trying to imitate a
        MacDraw File we will just do our size
        calculation
 }

 dataForkBytes := kHeaderSize { for std MacDraw Header }
  + GetHandleSize(Handle(fPlotDialog.fPlotPICT));
  
 { For now we will write only the PICT Handle in
    the future we might want to write the
    PlotSpecs and other parameters to the resource
    fork of the file }
 rsrcForkBytes := 0;
 END;

{------------------------------------------}
{$S AReadFile}

PROCEDURE TPlotDoc.DoRead(aRefNum: INTEGER; rsrcExists, forPrinting: 
BOOLEAN);
 VAR
 fi:    FailInfo;
 aPICTSize: LONGINT;
 aPICTHandle:Handle;
 
 PROCEDURE SkipDocHeaderInfo;
 BEGIN
 { skip the dummy header }
 FailOSErr( SetFPos(aRefNum,fsFromStart,kHeaderSize));         END;

 PROCEDURE HdlReadFailure(error: OSErr; message: LONGINT);
 BEGIN
 { We ran into trouble reading the data for
      now do nothing}
 END;

 BEGIN
 CatchFailures(fi, HdlReadFailure);
 
 { Normally, we would ask our ancestors to read
    in their data by:
 INHERITED DoRead(aRefNum, rsrcExists, forPrinting);
   but we are imitating a MacDraw Doc and have
    to behave like one
 }

 SkipDocHeaderInfo;
 
 IF fOldPlot <> NIL THEN
 DisposHandle(Handle(fOldPlot));
 
 FailOSErr(GetEOF(aRefNum,aPICTSize));
 aPICTSize := aPICTSize - kHeaderSize;
 aPICTHandle := NewHandle(aPICTSize);
 
 HLock(aPICTHandle);
 ReadBytes(aRefNum, aPICTSize, aPICTHandle^);
 HUnLock(aPICTHandle);

 fOldPlot := PicHandle(aPICTHandle);
 
 Success(fi);
 END;

{------------------------------------------}
{$S AWriteFile}
PROCEDURE TPlotDoc.DoWrite(aRefNum: INTEGER; makingCopy: BOOLEAN);

 PROCEDURE WriteHeaderInfo;
 VAR
 aPtr:  Ptr;
 BEGIN
 aPtr := NewPtrClear(kHeaderSize);
 FailNil(aPtr);
 WriteBytes(aRefNum, kHeaderSize, aPtr);
 DisposPtr(aPtr);
 END;

 PROCEDURE WritePlotInfo;
 VAR
 aPICTHandle : Handle;
 aPICTSize: LONGINT;
 BEGIN
 aPICTHandle := Handle(fPlotDialog.fPlotPICT);
 aPICTSize := GetHandleSize(aPICTHandle);
 
 HLock(aPICTHandle);
 WriteBytes(aRefNum, aPICTSize, aPICTHandle^);
 HUnLock(aPICTHandle);
 END;

 BEGIN
 WriteHeaderInfo;
 WritePlotInfo
 END;

{------------------------------------------}
{$S ARes}
 PROCEDURE TPlotDoc.SolveQuadratic;
 VAR
 a,b,c,check : real;
 
 FUNCTION PositiveCalc(a, b, check:real):real;
 BEGIN
 PositiveCalc := (-b + sqrt(check)) / (2 * a);
 END;
 
 FUNCTION NegativeCalc(a, b, check:real):real;
 BEGIN
 NegativeCalc := (-b - sqrt(check)) / (2 * a);
 END;
 
 BEGIN
 a := faParam;
 b := fbParam;
 c := fcParam;
 
 check := (b * b) - (4 * a * c);
 
 IF check = 0 THEN
   { we have a double root (same place twice) }
 BEGIN
 fRootType := SingleSolution;
 f1stRoot := PositiveCalc(a, b, check);
 f2ndRoot := f1stRoot;
 END
 
 ELSE IF check > 0 THEN
   { we have a pair of “real” x axis crossings }
 BEGIN
 fRootType := RealRoots;
 f1stRoot := PositiveCalc(a, b, check);
 f2ndRoot := NegativeCalc(a, b, check);
 END
 
 ELSE IF check < 0 THEN
  { roots are represented by complex number }
 BEGIN
 fRootType := ComplexRoot;
 check := -check;
 f1stRoot := PositiveCalc(a, b, check);
 f2ndRoot := NegativeCalc(a, b, check);
 END;
 END;

{------------------------------------------}
{$S ANonRes}
PROCEDURE TPlotDoc.ChangeBackColor(newColor: RGBColor);
 VAR
 oldPort: GrafPtr;
 itsWindow: TWindow;
 BEGIN
 itsWindow := TView(fPlotDialog).GetWindow;
 IF itsWindow <> NIL THEN
 BEGIN
 GetPort(oldPort);
 SetPort(itsWindow.fWMgrWindow);
 RGBBackColor(newColor);
 itsWindow.ForceRedraw;
 SetPort(oldPort);
 END;
 END;

{------------------------------------------}
{$IFC qDebug}
{$S AFields}
PROCEDURE TPlotDoc.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: 
Ptr; fieldType: INTEGER)); OVERRIDE;
 VAR
 aStr : DecStr;
 form : DecForm;
 aReal: Real;
 BEGIN
 form.style := FloatDecimal;
 form.digits := 6;
 
 DoToField(‘TPlotDoc’, NIL, bClass);
 aReal := faParam;
 Num2Str(form,aReal,aStr);
 DoToField(‘faParam’, @aStr, bString);

 aReal := fbParam;
 Num2Str(form,aReal,aStr);
 DoToField(‘fbParam’, @aStr, bString);

 aReal := fcParam;
 Num2Str(form,aReal,aStr);
 DoToField(‘fcParam’, @aStr, bString);

 aReal := fstepParam;
 Num2Str(form,aReal,aStr);
 DoToField(‘fstepParam’, @aStr, bString);
 DoToField(‘fxParam’, @fxParam, bInteger);
 DoToField(‘fyParam’, @fyParam, bInteger);
 
 DoToField(‘  Font’, @fPlotSpecs.theTextFont, bFontName);
 DoToField(‘  Face’, @fPlotSpecs.theTextFace, bStyle);
 DoToField(‘  Size’, @fPlotSpecs.theTextSize, bInteger);
 
 INHERITED Fields(DoToField);
 END;
{$ENDC}

{**********************************************}
{  T P l o t D i a l o g   }
{**********************************************}
{$S }
PROCEDURE TPlotDialog.DismissDialog(
 dismisser: IDType; flashDismisser: BOOLEAN);
 OVERRIDE;
 BEGIN
 INHERITED DismissDialog(dismisser, flashDismisser);
 END;

{------------------------------------------}
FUNCTION TPlotDialog.DoKeyCommand(ch: CHAR;
 aKeyCode: INTEGER; VAR info: EventInfo): TCommand;
  OVERRIDE;
 BEGIN
 { If Enter is pressed, assume we have new
 parameters and a new plot to create. }
 IF (ch = chEnter) THEN
 BEGIN
    {we have everything we need, lets DOIT!}
 PlotNDrawPICT;
 {We did all the work no reason to 
       generate a command}
 DoKeyCommand := gNoChanges;END
 ELSE
 DoKeyCommand := INHERITED
  DoKeyCommand(ch, aKeyCode, info);
END;

{------------------------------------------}
FUNCTION TPlotDialog.DoMenuCommand(
 aCmdNumber: CmdNumber): TCommand; OVERRIDE;
 BEGIN
 { Plot Menu Command was chosen so create plot. }
 IF (aCmdNumber = cPlotIt) THEN
 BEGIN
 PlotNDrawPICT; { we have everything, lets DOIT! }
 DoMenuCommand := gNoChanges;
{ We did all the work no reason to generate a command}
 END
 ELSE
 DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
END;

{------------------------------------------}
PROCEDURE TPlotDialog.DoSetupMenus; OVERRIDE;
BEGIN
 Enable(cPlotIt, TRUE);
 INHERITED DoSetupMenus;
END;

{------------------------------------------}
PROCEDURE TPlotDialog.Draw(area: Rect); OVERRIDE;
 VAR
 plotRect : Rect;
 dontCare : BOOLEAN;
 BEGIN
 dontCare := fPlotView.Focus;
 { set the world up to focus all drawing
   in the PlotView }
 
 fPlotView.GetQDFrame(plotRect);
 { the design says we draw into the
  available frame }

 DrawPicture(fPlotPICT, plotRect);
 { Draw the PICT in the PlotView }
 
 dontCare := SELF.Focus;
 { shift the focus back to us }
 END;

{------------------------------------------}
PROCEDURE TPlotDialog.EachSubView(PROCEDURE DoToSubView(theSubView: TView));
BEGIN
 { We do not want all of our clever
  dialog elements printing so lets
   skip them when printing }
 IF NOT gPrinting THEN
 INHERITED EachSubView(DoToSubView);
END;

{------------------------------------------}
PROCEDURE TPlotDialog.PlotNDrawPICT;
 VAR
 plotRect : Rect;
 solveRect: Rect;
 saveClip : RgnHandle;
 pstate : PenState;
 dontCare : BOOLEAN;
 aFontNum : INTEGER;
 
 BEGIN
 GetPlotValues;
 { get current values from the view }
 fPlotDoc.SolveQuadratic;
 { for the parameters retrieved, setup
  the solution values }
 
 IF fPlotPICT <> NIL THEN
 KillPicture(fPlotPICT);
 
 dontCare := fPlotView.Focus;
 fPlotView.GetQDExtent(plotRect);
 { change MacApp’s focus to the plotview
   to properly get our plot rect}
 dontCare := SELF.Focus;
 { and of course lets set FOCUS back to us.
   The above process of setting up plotRect
 might have been better handleed by
 declaring an fRect in plotview
   and having the resize method of plotview
 keep it up to date}
   
 fPlotPICT := OpenPicture(plotRect);

 saveClip := NewRgn;
 FailNIL(SaveClip);
 GetClip(SaveClip);

 GetPenState(pstate);
 
 { setup the font info for our plot }
 {$Push} {$H-}
 GetFNum(fPlotDoc.fPlotSpecs.theTextFont, aFontNum);
 {$H+}
 TextFont(aFontNum);
 TextSize(fPlotDoc.fPlotSpecs.theTextSize);
 TextFace(fPlotDoc.fPlotSpecs.theTextFace);
 { we also have: theTextColor,
       theJustification, theBackColor
   that we might want to do something with
       in the future }
 TextMode(srcOr);
 
 {Begin MacDraw Document PICT}
 PicComment(picDwgBeg, 0, NIL);    
 PicComment(picGrpBeg, 0, NIL);

 fPlotView.AddToPict(plotRect);

 solveRect := fSolutionView.fSolveRect;
 { get our plot rect, we know that this
         is a fixed rect}
 
 offsetRect(solveRect,4{border},
 plotRect.Bottom-(solveRect.Bottom+4{border}));
 { slide the textbox on down to the
  bottom of the view area this assumes
  that the solution textbox is smaller
  than the plotRect}

 fSolutionView.AddToPict(solveRect);

 PicComment(PicGrpEnd, 0, NIL);
 PicComment(picDwgEnd, 0, NIL);    

 ClosePicture;

 SetPenState(pstate);
 SetClip(saveClip);

 DisposeRgn(saveClip);

 ForceRedraw;
 { make the dialog rect invalid }
 END;
 
{------------------------------------------}
PROCEDURE TPlotDialog.GetPlotValues;
 BEGIN
 
 fPlotDoc.faParam :=
  TExtendedText(FindSubView(‘cofA’)).GetValue;
 fPlotDoc.fbParam :=
  TExtendedText(FindSubView(‘cofB’)).GetValue;
 fPlotDoc.fcParam :=
  TExtendedText(FindSubView(‘cofC’)).GetValue;
 
 fPlotDoc.fstepParam :=
  TExtendedText(FindSubView(‘step’)).GetValue;
 fPlotDoc.fxParam :=
  TNumberText(FindSubView(‘xAxs’)).GetValue;
 fPlotDoc.fyParam :=
  TNumberText(FindSubView(‘yAxs’)).GetValue;
 END;

{------------------------------------------}
PROCEDURE TPlotView.GetQDFrame(VAR frameRect:Rect);
 VAR
 extent:  VRect;
BEGIN
 GetFrame(extent);
 ViewToQDRect(extent, frameRect);
END;

{------------------------------------------}
PROCEDURE TPlotView.AddToPict(picRect:Rect);
 CONST
 AxisLabelIndent = 4;
 TYPE
 Widpt  = Point;
 WidPtr = ^WidPt;
 WidHdl = ^WidPtr;
 VAR
 x, y   : Real;
 a,b,c  : Real;
 step   : Real;
 halfXScale : Real;
 xPictScale : Real;
 yPictScale : Real;

 lastPt : Point;
 thisPt : Point;
 xScale : INTEGER;
 yScale : INTEGER;
 CenterHorz : INTEGER;
 CenterVert : INTEGER;
 PictHorz : INTEGER;
 PictVert : INTEGER;
 
 leading: INTEGER;
 fInfo  : FontInfo;
 Width  : Widhdl;
 axisLabel: str255;
 
 newColor : RGBColor;
 oldBack: RGBColor;
 oldFore: RGBColor;
 
 drawLine : BOOLEAN;
 
 BEGIN
 Width := Widhdl(NewHandle(sizeof(widpt)));
 Width^^.h := 10;
 Width^^.v := 1;

 GetFontInfo(fInfo);
 leading := fInfo.descent
  + fInfo.ascent + fInfo.leading;
 
 WITH fPlotDoc DO 
 BEGIN
 { retrieve the length of our Axis }
 xScale := fxParam;
 yScale := fyParam;
 
 { retrieve the coeficients }
 a := faParam;
 b := fbParam;
 c := fcParam;
 step := fStepParam;
 END;
 
 ClipRect(picRect);

 GetForeColor(oldFore);
 GetBackColor(oldBack);

 PenNormal; 

{Draw Graph Boundry}
 PicComment(picGrpBeg, 0, NIL);

 newColor := fPlotDoc.fPlotSpecs.theBackColor;
 RGBBackColor(newColor);
 
 PicComment(SetLineWidth,
 GetHandleSize(Handle(Width)), Handle(Width));
 FillRect(picRect, white);
 FrameRect(picRect);

{Two Axis}
 newColor := fPlotDoc.fPlotSpecs.theAxisColor;
 RGBForeColor(newColor);

 { find height of our View we will draw into }
 PictHorz := picRect.right  - picRect.left;
 PictVert := picRect.bottom - picRect.top;
 
 { find the center coordinates of the view }
 CenterHorz := PictHorz DIV 2;
 CenterVert := PictVert DIV 2;
 
 PicComment(picGrpBeg, 0, NIL);
 moveto(0, CenterVert);
 line( PictHorz, 0);
 moveto(CenterHorz, 0);
 line(0, PictVert);
 PicComment(picGrpEnd, 0, NIL);

 newColor := fPlotDoc.fPlotSpecs.theGraphColor;
 RGBForeColor(newColor);
 
{Axis Text}
 { Place -X axis label to the lowerleft of
      the axis line }
 moveto(AxisLabelIndent, CenterVert + leading);
 NumToString(-xScale,axisLabel);
 DrawString(axisLabel);

 { Place +Y axis label to the topleft of the
      axis line }
 NumToString(yScale,axisLabel);
 moveto(CenterHorz - (StringWidth(axisLabel)
 + AxisLabelIndent), leading);
 DrawString(axisLabel);

 { Place +X axis label to the lowerright
  of the axis line }
 NumToString(xScale,axisLabel);
 moveto(PictHorz - (StringWidth(axisLabel)
 + AxisLabelIndent), CenterVert + leading);
 DrawString(axisLabel);

 { Place -Y axis label to the lowerleft
  of the axis line }
 NumToString(-yScale,axisLabel);
 moveto(CenterHorz - (StringWidth(axisLabel)
 + AxisLabelIndent), PictVert - leading);
 DrawString(axisLabel);

{The Plot}
 { calculate a scale factor for the
  PICT’s axis in the view }
 xPictScale := PictHorz / xScale;
 yPictScale := PictVert / yScale;
 
 
 { calculate our starting x,y point }
 halfXScale := xScale / 2;
 x := -halfXScale;
 y := a * x * x + (b * x) + c;
 
 { Scale it into the PICT’s
  (and PostScript’s) view space} 
 thisPt.h :=
 integer(round(x * xPictScale))+CenterHorz;
 thisPt.v :=
 integer(round(-y * yPictScale))+CenterVert;

 { Find where to stop and start drawing.
  LOOP until we reach all x values:
   1. Find our first visible line segment
 2. Plot until it disappears
 3. Find a suitable end point
  }
  
 WHILE (NOT PtInRect(thisPt,picRect))
  &  (x <= halfXscale) DO
 BEGIN
 x := x + step;
 y := a * x * x + (b * x) + c;
 thisPt.h :=
 integer(round(x * xPictScale))+CenterHorz;
 thisPt.v :=
 integer(round(-y * yPictScale))+CenterVert;
 END;
 
 moveTo(thisPt.h,thisPt.v);
 drawLine := TRUE;
 
 PicComment(picGrpBeg, 0, NIL);

 REPEAT
 x := x + step;
 y := (a * x * x) + (b * x) + c;
 thisPt.h :=
 integer(round(x*xPictScale))+CenterHorz;
 thisPt.v :=
 integer(round(-y*yPictScale))+CenterVert;
 IF NOT PtInRect(thisPt,picRect) THEN
 drawLine := FALSE
 ELSE
 BEGIN
 IF drawLine THEN
 LineTo(thisPt.h,thisPt.v)
 ELSE
 BEGIN
 drawLine := TRUE;
 moveTo(thisPt.h,thisPt.v)
 END
 END;
  UNTIL x >= halfXScale;
 
 PicComment(picGrpEnd, 0, NIL);

 RGBForeColor(oldFore);
 RGBBackColor(oldBack);
 
 PicComment(PicGrpEnd, 0, NIL); {of select all objects}

 END;

{------------------------------------------}
PROCEDURE TPlotView.Resize(width,
 height: VCoordinate; invalidate: BOOLEAN);
  OVERRIDE;
BEGIN
invalidate := TRUE;
INHERITED Resize(width, height, invalidate);
ForceRedraw;
END;

{------------------------------------------}
{ Adds the text box containing the Quadratic equation solution to our 
PICT. }
PROCEDURE TSolutionView.AddToPict(picRect: Rect);
 CONST
 k1stLine = 1; k2ndLine = 2; k3rdLine = 3;
 k4thLine = 4; k5thLine = 5;
 
 kLeftJust = 1;
 kIndent = 2;
 TYPE
 Widpt  = Point;
 WidPtr = ^WidPt;
 WidHdl = ^WidPtr;

 TTxtPicRec = PACKED RECORD
 tJus : Byte;
 tFlip : Byte;
 tRot : Integer;
 tLine : Byte;
 tCmnt : Byte;
 END;
 VAR
 TextClipRgn : RgnHandle;
 TxtPicRec  : TTxtPicRec;
 TxtPicPtr  : QDPtr;
 TxtPicHdl  : QDHandle;
 Width  : WidHdl;
 
 clipBox: Rect;
 boxTop : INTEGER;
 boxLeft: INTEGER;
 leading: INTEGER;
 fInfo  : FontInfo;
 LineNo : INTEGER;

 a,b,c  : Real;
 x1,x2  : Real;
 z1,z2  : Real;
 
 newColor : RGBColor;
 
BEGIN
 WITH fPlotDoc DO 
 BEGIN
 { retrieve the Solution }
 x1 := f1stRoot;
 x2 := f2ndRoot;
 
 { retrieve the coeficients }
 a := faParam;
 b := fbParam;
 c := fcParam;
 END;
 
 Width := Widhdl(NewHandle(sizeof(widpt)));
 Width^^.h := 10;
 Width^^.v := 1;
 
 GetFontInfo(fInfo);
 leading := fInfo.descent + fInfo.ascent + fInfo.leading;

 PicComment(picGrpBeg, 0, NIL);
 
 {Box }
 PicComment(picGrpBeg, 0, NIL);
 PicComment(SetLineWidth,
  GetHandleSize(Handle(Width)),
  Handle(Width));
 fillRect(picRect, white); 
 frameRect(picRect);
 PicComment(picGrpEnd, 0, NIL); {of box}

 TextClipRgn := NewRgn;
 FailNil(TextClipRgn);
 
 GetClip(TextClipRgn);
 clipBox := picRect;
 ClipRect(clipBox);
 
 newColor := fPlotDoc.fPlotSpecs.theTextColor;
 RGBForeColor(newColor);

 {Box Text}
 { setup our Text Comment Handle }
 TxtPicPtr := @TxtPicRec;
 TxtPicHdl := @TxtPicPtr;
 TxtPicRec.tJus  := kLeftJust;
 TxtPicRec.tFlip := 0;  {no flip}
 TxtPicRec.tRot  := 0;  {no rotation}
 TxtPicRec.tLine := 2;  {1 1/2 spacing}
 
 {put the Comment into our PICT}
 PicComment(TextBegin, sizeof(TTxtPicRec), Handle(TxtPicHdl));

 { Add the BOX text to the PICT }
 boxTop :=  picRect.top;
 boxLeft:=  picRect.Left;
 
 MoveTo(boxLeft + kIndent,
   boxTop + (k1stLine * leading));
 DrawString(CONCAT(‘y=ax^2 + bx + c’, chr(13)));
 
 MoveTo(boxLeft + kIndent,
  boxTop + (k2ndLine * leading));
 DrawString(CONCAT(  ‘a=’, Real2Str(a,1), ‘, b=’, Real2Str(b,1), ‘, c=’, 
Real2Str(c,1), chr(13)));
   
 { The solution text is next }
 MoveTo(boxLeft + kIndent,
  boxTop + (k3rdLine * leading));
 DrawString(CONCAT(  ‘x1=’, Real2Str(x1,3),
 ‘, x2=’, Real2Str(x2,3), chr(13)));

 { Display kind of Quadratic we have }
 MoveTo(boxLeft + kIndent,
   boxTop + (k4thLine * leading));
 CASE fPlotDoc.fRootType OF
 RealRoots : 
 DrawString(CONCAT(‘Two Real Roots, x1, x2’,
  chr(13)));
 SingleSolution : 
 DrawString(CONCAT(‘Double Root’, chr(13)));
 ComplexRoot : 
 DrawString(CONCAT(‘Two Complex Roots ‘,chr(13)));
 OTHERWISE
 ;
 END;
 
 { Calculate the slope and add the
  string it to the PICT}
 WITH fPlotDoc DO
 BEGIN
 z1 := -b / (2 * a);
 z2 := (4 * a * c - (b * b)) / (4 * b);
 END;
 
 MoveTo(boxLeft + kIndent,
   boxTop + (k5thLine * leading));
 DrawString(CONCAT(‘Slope 0 is (‘,
 Real2Str(z1,1),’,’, Real2Str(z2,1),’)’,
  chr(13)));
 
 { All done with our text } 
 PicComment(TextEnd, 0, NIL);
 
 PicComment(PicGrpEnd, 0, NIL); {of Box & text}
 
 DisposHandle(Handle(width));
 DisposeRgn(TextClipRgn);
END;

{------------------------------------------}
PROCEDURE TPStyleCmd.DoIt;
 BEGIN
 fPlotDialog.fPlotDoc.fPlotSpecs := fNewPlotSPecs;
 END;

{------------------------------------------}
PROCEDURE TPStyleCmd.ReDoIt;
 BEGIN
 fPlotDialog.fPlotDoc.fPlotSpecs := fNewPlotSPecs;
 END;

{------------------------------------------}
PROCEDURE TPStyleCmd.UnDoIt;
 BEGIN
 fPlotDialog.fPlotDoc.fPlotSpecs := fOldPlotSPecs;
 END;

{------------------------------------------}
PROCEDURE TPStyleCmd.IPStyleCmd(itsPlotDialog: TPlotDialog;
 itsNewStyle: PlotSpecsPtr; itsCmdNumber: CmdNumber);
 BEGIN
 ICommand(itsCmdNumber, itsPlotDialog.fPlotDoc,
 itsPlotDialog, NIL);

 fPlotDialog  := itsPlotDialog;
 fOldPlotSPecs:=fPlotDialog.fPlotDoc.fPlotSpecs;
 fNewPlotSPecs:=itsNewStyle^;
 END;
 
END.  

MPlot.p  Main Program FILE
{•••••••••••••••••••••••••••••••••••••••••••••••}
Program Plot;
USES
 { • MacApp }
 UMacApp, 

 { • Building Blocks }
 UDialog, UPrinting,

 { • Implementation Use }
 SANE, ToolUtils, Fonts, Resources,
  Script, PickerIntf, Packages,
 
 { • the PlotUNIT }
 UPlot;

VAR
 gPlotApplication: TPlotApplication;
 {The application object:}

{----------------------------------------------}
 { T H E   M A I N   P R O G R A M }
 BEGIN

 InitUMacApp(8);
 {Initialize the Toolbox,
 making 8 calls to MoreMasters:}
 InitPrinting;
 {Initialize the UPrinting unit:}

 NEW(gPlotApplication);
 {Allocate a new TPlotApplication object:}

 FailNIL(gPlotApplication);
 gPlotApplication.IPlotApplication(kFileType);                 
 {Initialize that new object:}

 gPlotApplication.Run;
 {Run the application.
   When it’s done, exit.}
 END.

PLOT.r-Plot resource FILE

/* Copyright © 1988-1989 Apple Computer, Inc.
    All rights reserved. */
/* Copyright © 1989 Software Architects, Inc.
    All rights reserved. */

#if qDebug
include “Debug.rsrc”;
#endif
include “MacApp.rsrc”;
include “Dialog.rsrc”;
include “Printing.rsrc”;

include “Plot” ‘CODE’;

#define kPlotView1010
#define kViewRsrcID1005

resource ‘seg!’ (256, purgeable) {
 {
 “GOpen”;
 “GClose”;
 “GNonRes”;
 “GSelCommand”
 }
};

resource ‘SIZE’ (-1) {
 dontSaveScreen,
 acceptSuspendResumeEvents,
 enableOptionSwitch,
 canBackground,
 MultiFinderAware,
 backgroundAndForeground,
 dontGetFrontClicks,
 ignoreChildDiedEvents,
 is32BitCompatible,
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
#if qDebug
 368 * 1024,/* ??? BALLPARK GUESSES ?????    */
 320 * 1024
#else
 (300-32) * 1024,/* ??? BALLPARK GUESSES ??  */
 (200-32) * 1024
#endif
};

resource ‘DITL’ (201, purgeable) {
  {
/* [1] */
 {160, 182, 180, 262}, Button { enabled, “OK” };
/* [2] */
 {10, 75, 150, 316}, StaticText { disabled, 
 “This is an implementation of the MacTutor Plotter Program.” 
 “\n\n written “
 “with MacApp® © 1985-1989 Apple Computer, Inc.”};
/* [3] */ {10, 20, 42, 52}, Icon { disabled, 1 }
 }
};

resource ‘ALRT’ (1000, purgeable) {
 {44, 48, 130, 358},
 1000,
 {
 OK, visible, sound1,
 OK, visible, sound1,
 OK, visible, sound1,
 OK, visible, sound1
 }
};

resource ‘ALRT’ (201, purgeable) {
 {90, 100, 280, 412},
 201,
 {
 OK, visible, silent;
 OK, visible, silent;
 OK, visible, silent;
 OK, visible, silent
 }
};

resource ‘cmnu’ (1) {
 1,
 textMenuProc,
 0x7FFFFFFD,
 enabled,
 apple,
  {
/* [1] */
 “About Plotter ”, noIcon, noKey, noMark, plain, cAboutApp;
/* [2] */
 “-”, noIcon, noKey, noMark, plain, nocommand
 }
};

resource ‘cmnu’ (2) {
 2,
 textMenuProc,
 0x7FFFEEFB,
 enabled,
 “File”,
 {
 “New”, noIcon, “N”, noMark, plain,  cNew;
 “Open ”, noIcon, “O”, noMark, plain,cOpen;
 “-”,   noIcon, noKey, noMark, plain, nocommand;
 “Close”, noIcon, noKey, noMark, plain,cClose;
 “Save”,  noIcon, “S”, noMark, plain,  cSave;
 “Save As ”, noIcon,noKey,noMark,plain, cSaveAs;
 “Save a Copy In ”,
 noIcon,noKey,noMark,plain, cSaveCopy;
 “Revert”,noIcon,noKey,noMark,plain, cRevert;
 “-”,   noIcon, noKey, noMark, plain,
   nocommand;
 “Page Setup ”,
 noIcon,noKey,noMark,plain,cPageSetup;
 “Print ”,noIcon,noKey,noMark,plain, cPrint;
 “-”,   noIcon, noKey, noMark, plain,  nocommand;
 “Quit”,noIcon, “Q”, noMark, plain, cQuit
 }
};

resource ‘cmnu’ (3) {
 3,
 textMenuProc,
 0x7FFFFFBD,
 enabled,
 “Edit”,
  {
 “Undo”, noIcon, “Z”,   noMark, plain, cUndo;
 “-”,   noIcon, noKey, noMark, plain, nocommand;
 “Cut”, noIcon, “X”, noMark, plain,  cCut;
 “Copy”,noIcon, “C”, noMark, plain,  cCopy;
 “Paste”,
 noIcon, “V”, noMark, plain,  cPaste;
 “Clear”,
 noIcon, noKey, noMark, plain,   cClear;
 “-”,   noIcon, noKey, noMark, plain, nocommand;
 “Show Clipboard”,
 noIcon, noKey, noMark, plain, cShowClipboard
 }
};

/* Hierarchical menu with Style, Size & Font submenus */
resource ‘cmnu’ (7) {
 7,
 textMenuProc,
 allEnabled,
 enabled,
 “MacAppPlot”,
  {
 “Plot”,noIcon, noKey, noMark, plain, 1401;
 “-”,   noIcon,  noKey, noMark,  plain,nocommand;
 “Style”, noIcon, “\0x1B”, “\0x08”, plain, 2401;
 “Size”,noIcon, “\0x1B”, “\0x09”, plain, 2402;
 “Font”,noIcon, “\0x1B”, “\0x0A”, plain, 2403;
 “Color”, noIcon, “\0x1B”, “\0x0B”, plain, 2404
 }
};

/* Hierarchical Style Sub-menu */
resource ‘cmnu’ (8) {
 8,
 textMenuProc,
 allEnabled,
 enabled,
 “Style”,
  {
“Plain Text”,  noIcon,  “P”,noMark,plain,          2001;
“Bold”, noIcon,  “B”,noMark,bold,  2002;
“Italic”, noIcon,“I”,noMark,italic,2003;
“Underline”,noIcon,“U”, noMark,  underline,  2004;
“Outline”,noIcon,“O”,noMark,outline, 2005;
“Shadow”, noIcon,“S”,noMark,shadow,2006;
“Condensed”,noIcon,noKey, noMark, condense,  2007;
“Extended”, noIcon,noKey, noMark, extend,          2008;
“-”,    noIcon,  noKey, noMark,  plain,nocommand;
“Left justified”,noIcon,  noKey,noMark,plain,2201;
“Center justified”,noIcon,noKey,noMark,plain,2202;
“Right justified”,noIcon, noKey,noMark,plain,2203
}
};

/* Hierarchical Size Sub-menu */
resource ‘cmnu’ (9) {
 9,
 textMenuProc,
 AllEnabled,
 enabled,
 “Size”,
  {
“ 9 Point”, noIcon,noKey, noMark,  plain,    2109;
“10 Point”, noIcon,noKey, noMark,  plain,    2110;
“12 Point”, noIcon,noKey, noMark,  plain,    2112;
“14 Point”, noIcon,noKey, noMark,  plain,    1114;
“18 Point”, noIcon,noKey, noMark,  plain,    1118;
“24 Point”, noIcon,noKey, noMark,  plain,    1124;
“-”,    noIcon,  noKey, noMark,  plain,nocommand;
“Grow selection”,noIcon,  “]”,noMark,plain, 1198;
“Shrink selection”,noIcon,“[“,noMark,plain, 1199

  }
};

/* Font menu for hierarchical or non-hierarchical system */
resource ‘MENU’ (10) {
 10,
 textMenuProc,
 allEnabled,
 enabled,
 “Font”,
 { }
};

resource ‘cmnu’ (11) {
 11,
 textMenuProc,
 allEnabled,
 enabled,
 “Color”,
 {
“Set Graph Color ”, noIcon, noKey, noMark, plain, 2503;
“Set Axis Color ”, noIcon,noKey, noMark,     plain, 2504;
“Set Text Color ”, noIcon,noKey, noMark,     plain, 2501;
“Set Background Color ”, noIcon, noKey,noMark, plain, 2502
 }
};

resource ‘cmnu’ (128) {
 128,
 textMenuProc,
 allEnabled,
 enabled,
 “Buzzwords”,
 {
 “Style Change”,
 noIcon,noKey, noMark,  plain,cStyleChange;
 “Size Change”,
 noIcon,noKey, noMark,  plain,2100;
 “Justification Change”,
 noIcon,noKey, noMark,  plain,2200;
 “Font Change”,
 noIcon,noKey, noMark,  plain,2300;
 “Color Change”,
 noIcon,noKey, noMark,  plain,2500;
 “Page Setup Change”,
 noIcon,noKey, noMark,  plain,
 cChangePrinterStyle
 }
};

/* Displayed menus on a non-hierarchical system */
resource ‘MBAR’ (128) {
 {1; 2; 3 ; 8; 9; 10; 11}
};

/* Displayed menus on an hierarchical system */
resource ‘MBAR’ (131) {
 {1; 2; 3; 7}
};

/* Hierarchial Sub-Menus */
resource ‘MBAR’ (130) {
 {8; 9; 10; 11}
};

resource ‘STR#’ (1001, purgeable) {
 {
 “Select a new text color ”,
 “Select background color ”
 “Select graph line color ”
 “Select axis color ”
 }
};

/* a resource for picking up default text,
   graph and color info */
resource ‘view’ (kViewRsrcID, purgeable) {{
 root, ‘TEVW’, { 0, 0 }, { 116, 1020 },
 sizeVariable, sizePage, shown, enabled,
 TEView { “TTEView”,
 withStyle, autoWrap, acceptChanges,
 dontFreeText, cTyping, unlimited,
 { 8, 10, 0, 10 },
 justLeft, plain, 9, {0, 0, 0}, “Geneva” }
} };
PLOT.VE.r-Plot View resource FILE
resource ‘view’ (1010, purgeable) {
 { 
 root, ‘WIND’,
 {50, 40},
 {310, 380}, sizeVariable, sizeVariable,
  notShown, enabled,
 Window {
 “TWindow”,
 zoomDocProc,goAwayBox,resizable,
 modeless,ignoreFirstClick,
 dontFreeOnClosing,disposeOnFree,
 closesDocument,OpenWithDocument,
 AdaptToScreen,Stagger,ForceOnScreen,
 dontCenter,’cofA’,
 “Plot <<<>>>”
 },

 ‘WIND’, ‘DLOG’,
 {0, 0},{240, 294},
 sizeSuperView, sizeSuperView, shown, disabled,
 DialogView {
 “TPlotDialog”,
 noID,
 noID
 },
 
 ‘DLOG’, ‘Ccof’,
 {2, 5},{90, 96}, sizeFixed, sizeFixed, shown, disabled,
 Cluster {
 “TCluster”,
 0b0,{1, 1},sizeable,notDimmed,notHilited,
 doesntDismiss,{0, 0, 0, 0},
 plain,12,{0x0,0x0,0x0},
 “Helvetica”,
 “Coefficients”
 },
 
 ‘Ccof’, ‘cofA’,
 {15, 36},{20, 44}, sizeFixed, sizeFixed, shown, enabled,
 ExtendedText {
 “TExtendedText”,
 0b1101,{1, 1},sizeable,notDimmed,notHilited,
 doesntDismiss,{2, 2, 2, 2},
 plain,0,{0x0,0x0,0x0},
 “”,
 justLeft,”1",unlimited,
 0b11111000000000000000000100000000,
 -10000,10000,2,”1.0"
 },
 
 ‘Ccof’, ‘cofB’,
 {38, 36}, {20, 44}, sizeFixed, sizeFixed, shown, enabled,
 ExtendedText {
 “TExtendedText”,
 0b1101,{1, 1},sizeable,notDimmed,notHilited,
 doesntDismiss,{2, 2, 2, 2},
 plain,0,{0x0,0x0,0x0},
 “”,
 justLeft,”5",unlimited,
 0b11110000000000000000000100000000,
 -10000,10000,2,”5.0"
 },
 
 ‘Ccof’, ‘cofC’,
 {62, 36},
 {20, 44}, sizeFixed, sizeFixed, shown, enabled,
 ExtendedText {
 “TExtendedText”,
 0b1101,{1, 1},sizeable,notDimmed,notHilited,
 doesntDismiss,{2, 2, 2, 2},
 plain,0,{0x0,0x0,0x0},
 “”,
 justLeft,”2",unlimited,
 0b11110000000000000000000100000000,
 -10000,10000,2,”2.0"
 },
 
 ‘Ccof’, ‘VW13’,
 {15, 10},
 {20, 26}, sizeFixed, sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b111,{1, 1},notSizeable,notDimmed,
 notHilited,doesntDismiss,{0, 0, 0, 0},
 plain,0,{0x0,0x0,0x0},
 “”,
 justRight,
 “a = “
 },
 
 ‘Ccof’, ‘VW14’,
 {38, 10},
 {20, 26}, sizeFixed, sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b111,{1, 1},notSizeable,notDimmed,
 notHilited,doesntDismiss,{0, 0, 0, 0},
 plain,0,{0x0,0x0,0x0},
 “”,
 justRight,
 “b =”
 },
 
 ‘Ccof’, ‘VW15’,
 {62, 10},
 {20, 26}, sizeFixed, sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b111,{1, 1},notSizeable,notDimmed,
 notHilited,doesntDismiss,{0, 0, 0, 0},
 plain,0,{0x0,0x0,0x0},
 “”,
 justRight,
 “c =”
 },
 
 ‘DLOG’, ‘Cdsp’,
 {95, 5},
 {139, 96}, sizeFixed, sizeFixed, shown, disabled,
 Cluster {
 “TCluster”,
 0b0,{1, 1},sizeable,notDimmed,
 notHilited, doesntDismiss,{0, 0, 0, 0},
 plain,12,{0x0,0x0,0x0},
 “Helvetica”,
 “Display”
 },

 ‘Cdsp’, ‘step’,
 {26, 36},
 {20, 40}, sizeFixed, sizeFixed,shown, enabled,
 ExtendedText {
 “TExtendedText”,
 0b1111,{1, 1},sizeable,notDimmed,
 notHilited,doesntDismiss,{2, 2, 2, 2},
 plain,0,{0x0,0x0,0x0},
 “”,
 justRight,”1",unlimited,
 0b11110000000000000000000100000000, 0, 10, 2, “0.25”
 },

 ‘Cdsp’, ‘xAxs’,
 {66, 17},
 {20, 60}, sizeFixed, sizeFixed,
  shown, enabled,
 NumberText {
 “TNumberText”,
 0b1111,{1, 1},sizeable,notDimmed,
 notHilited, doesntDismiss,{2, 2, 2, 2},
 plain,0,{0x0,0x0,0x0},
 “”,
 justRight,”10",unlimited,
 0b11110000000000000000000100000000,10, 1, 1000
 },
 
 ‘Cdsp’, ‘yAxs’,
 {106, 17},
 {20, 60}, sizeFixed, sizeFixed, shown, enabled,
 NumberText {
 “TNumberText”,
 0b1111,{1, 1},sizeable,notDimmed,
 notHilited,doesntDismiss,{2, 2, 2, 2},
 plain,0,{0x0,0x0,0x0},
 “”,
 justRight,”20",unlimited,
 0b11110000000000000000000100000000,20, 1, 1000
 },
 
 ‘Cdsp’, ‘VW17’,
 {13, 31},
 {12, 40}, sizeFixed, sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,{1, 1},notSizeable,notDimmed,
 notHilited, doesntDismiss,{0, 0, 0, 0},
 plain,9,{0x0,0x0,0x0},
 “Helvetica”,
 justCenter,
 “step”
 },
 
 ‘Cdsp’, ‘VW18’,
 {54, 17},
 {12, 60}, sizeFixed, sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,{1, 1},notSizeable,notDimmed,
 notHilited,doesntDismiss,{0, 0, 0, 0},
 plain,9,{0x0,0x0,0x0},
 “Helvetica”,
 justCenter,
 “X AXIS”
 },
 
 ‘Cdsp’, ‘VW19’,
 {93, 17},
 {12, 60}, sizeFixed, sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,{1, 1},notSizeable,notDimmed,
 notHilited,doesntDismiss,{0, 0, 0, 0},
 plain,9,{0x0,0x0,0x0},
 “Helvetica”,
 justCenter,
 “Y AXIS”
 },
 
 ‘DLOG’, ‘sclr’,
 {0, 104}, {225, 175},
 sizeRelSuperView, sizeRelSuperView, shown, enabled,
 Scroller {
 “TScroller”,
 VertScrollBar,HorzScrollBar,
 0,0,16,16,
 noVertConstrain,noHorzConstrain,{0, 0, 0, 0}
 },
 
 ‘sclr’, ‘plot’,
 {0, 0},  {400, 400}, sizeSuperView, sizeSuperView,
  shown, enabled,
 View {“TPlotView”},
 ‘plot’, ‘qslv’,
 {325, 0},  {75, 160},sizeFixed,sizeFixed, shown, enabled,
 View {“TSolutionView”}}
};

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Tokkun Studio unveils alpha trailer for...
We are back on the MMORPG news train, and this time it comes from the sort of international developers Tokkun Studio. They are based in France and Japan, so it counts. Anyway, semantics aside, they have released an alpha trailer for the upcoming... | Read more »
Win a host of exclusive in-game Honor of...
To celebrate its latest Jujutsu Kaisen crossover event, Honor of Kings is offering a bounty of login and achievement rewards kicking off the holiday season early. [Read more] | Read more »
Miraibo GO comes out swinging hard as it...
Having just launched what feels like yesterday, Dreamcube Studio is wasting no time adding events to their open-world survival Miraibo GO. Abyssal Souls arrives relatively in time for the spooky season and brings with it horrifying new partners to... | Read more »
Ditch the heavy binders and high price t...
As fun as the real-world equivalent and the very old Game Boy version are, the Pokemon Trading Card games have historically been received poorly on mobile. It is a very strange and confusing trend, but one that The Pokemon Company is determined to... | Read more »
Peace amongst mobile gamers is now shatt...
Some of the crazy folk tales from gaming have undoubtedly come from the EVE universe. Stories of spying, betrayal, and epic battles have entered history, and now the franchise expands as CCP Games launches EVE Galaxy Conquest, a free-to-play 4x... | Read more »
Lord of Nazarick, the turn-based RPG bas...
Crunchyroll and A PLUS JAPAN have just confirmed that Lord of Nazarick, their turn-based RPG based on the popular OVERLORD anime, is now available for iOS and Android. Starting today at 2PM CET, fans can download the game from Google Play and the... | Read more »
Digital Extremes' recent Devstream...
If you are anything like me you are impatiently waiting for Warframe: 1999 whilst simultaneously cursing the fact Excalibur Prime is permanently Vault locked. To keep us fed during our wait, Digital Extremes hosted a Double Devstream to dish out a... | Read more »
The Frozen Canvas adds a splash of colou...
It is time to grab your gloves and layer up, as Torchlight: Infinite is diving into the frozen tundra in its sixth season. The Frozen Canvas is a colourful new update that brings a stylish flair to the Netherrealm and puts creativity in the... | Read more »
Back When AOL WAS the Internet – The Tou...
In Episode 606 of The TouchArcade Show we kick things off talking about my plans for this weekend, which has resulted in this week’s show being a bit shorter than normal. We also go over some more updates on our Patreon situation, which has been... | Read more »
Creative Assembly's latest mobile p...
The Total War series has been slowly trickling onto mobile, which is a fantastic thing because most, if not all, of them are incredibly great fun. Creative Assembly's latest to get the Feral Interactive treatment into portable form is Total War:... | Read more »

Price Scanner via MacPrices.net

Early Black Friday Deal: Apple’s newly upgrad...
Amazon has Apple 13″ MacBook Airs with M2 CPUs and 16GB of RAM on early Black Friday sale for $200 off MSRP, only $799. Their prices are the lowest currently available for these newly upgraded 13″ M2... Read more
13-inch 8GB M2 MacBook Airs for $749, $250 of...
Best Buy has Apple 13″ MacBook Airs with M2 CPUs and 8GB of RAM in stock and on sale on their online store for $250 off MSRP. Prices start at $749. Their prices are the lowest currently available for... Read more
Amazon is offering an early Black Friday $100...
Amazon is offering early Black Friday discounts on Apple’s new 2024 WiFi iPad minis ranging up to $100 off MSRP, each with free shipping. These are the lowest prices available for new minis anywhere... Read more
Price Drop! Clearance 14-inch M3 MacBook Pros...
Best Buy is offering a $500 discount on clearance 14″ M3 MacBook Pros on their online store this week with prices available starting at only $1099. Prices valid for online orders only, in-store... Read more
Apple AirPods Pro with USB-C on early Black F...
A couple of Apple retailers are offering $70 (28%) discounts on Apple’s AirPods Pro with USB-C (and hearing aid capabilities) this weekend. These are early AirPods Black Friday discounts if you’re... Read more
Price drop! 13-inch M3 MacBook Airs now avail...
With yesterday’s across-the-board MacBook Air upgrade to 16GB of RAM standard, Apple has dropped prices on clearance 13″ 8GB M3 MacBook Airs, Certified Refurbished, to a new low starting at only $829... Read more
Price drop! Apple 15-inch M3 MacBook Airs now...
With yesterday’s release of 15-inch M3 MacBook Airs with 16GB of RAM standard, Apple has dropped prices on clearance Certified Refurbished 15″ 8GB M3 MacBook Airs to a new low starting at only $999.... Read more
Apple has clearance 15-inch M2 MacBook Airs a...
Apple has clearance, Certified Refurbished, 15″ M2 MacBook Airs now available starting at $929 and ranging up to $410 off original MSRP. These are the cheapest 15″ MacBook Airs for sale today at... Read more
Apple drops prices on 13-inch M2 MacBook Airs...
Apple has dropped prices on 13″ M2 MacBook Airs to a new low of only $749 in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, now available for $679 for 8-Core CPU/7-Core GPU/256GB models. Apple’s one-year warranty is included, shipping is free, and each... Read more

Jobs Board

Seasonal Cashier - *Apple* Blossom Mall - J...
Seasonal Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Seasonal Fine Jewelry Commission Associate -...
…Fine Jewelry Commission Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) Read more
Seasonal Operations Associate - *Apple* Blo...
Seasonal Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Read more
Hair Stylist - *Apple* Blossom Mall - JCPen...
Hair Stylist - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.