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

Dropbox 193.4.5594 - Cloud backup and sy...
Dropbox is a file hosting service that provides cloud storage, file synchronization, personal cloud, and client software. It is a modern workspace that allows you to get to all of your files, manage... Read more
Google Chrome 122.0.6261.57 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
Skype 8.113.0.210 - Voice-over-internet...
Skype is a telecommunications app that provides HD video calls, instant messaging, calling to any phone number or landline, and Skype for Business for productive cooperation on the projects. This... Read more
Tor Browser 13.0.10 - Anonymize Web brow...
Using Tor Browser you can protect yourself against tracking, surveillance, and censorship. Tor was originally designed, implemented, and deployed as a third-generation onion-routing project of the U.... Read more
Deeper 3.0.4 - Enable hidden features in...
Deeper is a personalization utility for macOS which allows you to enable and disable the hidden functions of the Finder, Dock, QuickTime, Safari, iTunes, login window, Spotlight, and many of Apple's... Read more
OnyX 4.5.5 - Maintenance and optimizatio...
OnyX is a multifunction utility that you can use to verify the startup disk and the structure of its system files, to run miscellaneous maintenance and cleaning tasks, to configure parameters in the... Read more
Hopper Disassembler 5.14.1 - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more

Latest Forum Discussions

See All

Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »
Live, Playdate, Live! – The TouchArcade...
In this week’s episode of The TouchArcade Show we kick things off by talking about all the games I splurged on during the recent Playdate Catalog one-year anniversary sale, including the new Lucas Pope jam Mars After Midnight. We haven’t played any... | Read more »
TouchArcade Game of the Week: ‘Vroomies’
So here’s a thing: Vroomies from developer Alex Taber aka Unordered Games is the Game of the Week! Except… Vroomies came out an entire month ago. It wasn’t on my radar until this week, which is why I included it in our weekly new games round-up, but... | Read more »
SwitchArcade Round-Up: ‘MLB The Show 24’...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for March 15th, 2024. We’re closing out the week with a bunch of new games, with Sony’s baseball franchise MLB The Show up to bat yet again. There are several other interesting games to... | Read more »
Steam Deck Weekly: WWE 2K24 and Summerho...
Welcome to this week’s edition of the Steam Deck Weekly. The busy season has begun with games we’ve been looking forward to playing including Dragon’s Dogma 2, Horizon Forbidden West Complete Edition, and also console exclusives like Rise of the... | Read more »
Steam Spring Sale 2024 – The 10 Best Ste...
The Steam Spring Sale 2024 began last night, and while it isn’t as big of a deal as say the Steam Winter Sale, you may as well take advantage of it to save money on some games you were planning to buy. I obviously recommend checking out your own... | Read more »
New ‘SaGa Emerald Beyond’ Gameplay Showc...
Last month, Square Enix posted a Let’s Play video featuring SaGa Localization Director Neil Broadley who showcased the worlds, companions, and more from the upcoming and highly-anticipated RPG SaGa Emerald Beyond. | Read more »
Choose Your Side in the Latest ‘Marvel S...
Last month, Marvel Snap (Free) held its very first “imbalance" event in honor of Valentine’s Day. For a limited time, certain well-known couples were given special boosts when conditions were right. It must have gone over well, because we’ve got a... | Read more »
Warframe welcomes the arrival of a new s...
As a Warframe player one of the best things about it launching on iOS, despite it being arguably the best way to play the game if you have a controller, is that I can now be paid to talk about it. To whit, we are gearing up to receive the first... | Read more »
Apple Arcade Weekly Round-Up: Updates an...
Following the new releases earlier in the month and April 2024’s games being revealed by Apple, this week has seen some notable game updates and events go live for Apple Arcade. What The Golf? has an April Fool’s Day celebration event going live “... | Read more »

Price Scanner via MacPrices.net

Apple Education is offering $100 discounts on...
If you’re a student, teacher, or staff member at any educational institution, you can use your .edu email address when ordering at Apple Education to take $100 off the price of a new M3 MacBook Air.... Read more
Apple Watch Ultra 2 with Blood Oxygen feature...
Best Buy is offering Apple Watch Ultra 2 models for $50 off MSRP on their online store this week. Sale prices available for online orders only, in-store prices may vary. Order online, and choose... Read more
New promo at Sams Club: Apple HomePods for $2...
Sams Club has Apple HomePods on sale for $259 through March 31, 2024. Their price is $40 off Apple’s MSRP, and both Space Gray and White colors are available. Sale price is for online orders only, in... Read more
Get Apple’s 2nd generation Apple Pencil for $...
Apple’s Pencil (2nd generation) works with the 12″ iPad Pro (3rd, 4th, 5th, and 6th generation), 11″ iPad Pro (1st, 2nd, 3rd, and 4th generation), iPad Air (4th and 5th generation), and iPad mini (... Read more
10th generation Apple iPads on sale for $100...
Best Buy has Apple’s 10th-generation WiFi iPads back on sale for $100 off MSRP on their online store, starting at only $349. With the discount, Best Buy’s prices are the lowest currently available... Read more
iPad Airs on sale again starting at $449 on B...
Best Buy has 10.9″ M1 WiFi iPad Airs on record-low sale prices again for $150 off Apple’s MSRP, starting at $449. Sale prices for online orders only, in-store price may vary. Order online, and choose... Read more
Best Buy is blowing out clearance 13-inch M1...
Best Buy is blowing out clearance Apple 13″ M1 MacBook Airs this weekend for only $649.99, or $350 off Apple’s original MSRP. Sale prices for online orders only, in-store prices may vary. Order... Read more
Low price alert! You can now get a 13-inch M1...
Walmart has, for the first time, begun offering new Apple MacBooks for sale on their online store, albeit clearance previous-generation models. They now have the 13″ M1 MacBook Air (8GB RAM, 256GB... Read more
Best Apple MacBook deal this weekend: Get the...
Apple has 13″ M2 MacBook Airs available for only $849 today in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty is included,... Read more
New 15-inch M3 MacBook Air (Midnight) on sale...
Amazon has the new 15″ M3 MacBook Air (8GB RAM/256GB SSD/Midnight) in stock and on sale today for $1249.99 including free shipping. Their price is $50 off MSRP, and it’s the lowest price currently... Read more

Jobs Board

Early Preschool Teacher - Glenda Drive/ *Appl...
Early Preschool Teacher - Glenda Drive/ Apple ValleyTeacher Share by Email Share on LinkedIn Share on Twitter Read more
Senior Software Engineer - *Apple* Fundamen...
…center of Microsoft's efforts to empower our users to do more. The Apple Fundamentals team focused on defining and improving the end-to-end developer experience in Read more
Relationship Banker *Apple* Valley Main - W...
…Alcohol Policy to learn more. **Company:** WELLS FARGO BANK **Req Number:** R-350696 **Updated:** Mon Mar 11 00:00:00 UTC 2024 **Location:** APPLE VALLEY,California Read more
Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill WellSpan Medical Group, York, PA | Nursing | Nursing Support | FTE: 1 | Regular | Tracking Code: 200555 Apply Now Read more
Early Preschool Teacher - Glenda Drive/ *Appl...
Early Preschool Teacher - Glenda Drive/ Apple ValleyTeacher Share by Email Share on LinkedIn Share on Twitter Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.