TweetFollow Us on Twitter

Plotter
Volume Number:4
Issue Number:2
Column Tag:Pascal Procedures

MultiFinder Friendly MacDraw Plotter

By Dave Kelly, MacTutor Editorial Board & David Smith, Editor & Publisher

For the past few months, MacTutor has been running a series of editorials on the importance of developers getting with the new way of doing things. In the last six months, Apple has introduced a number of product enhancements that directly affect commercial software development. These include:

• MultiFinder Quasi-Multitasking Finder

• AppleShare File Server

• New Menu Manager with nested menus

• New Color PICT format

• New Color Quickdraw Capability

• New Style-enhanced Text Edit & Clipboard type

• Multiple screen capability

• Universal Hyper-Text type data base

• Faster number crunching with 68881 chip

• New ROM interface files, MPW 2.0

• Lots of new Technical notes fixing old bugs

• New compatibility headaches

As usually happens when new goodies come on the market, everyone looks at their old software and says “how come my version of MS____ doesn’t support this?” As programmers and developers, we have a responsibility to bring our software up to speed as quickly as possible with the new way of doing things. For example, the time-consuming dialog box to change text font and style is no longer good enough when nested menus can do the same job so much faster. Black and white windows, menus and documents get old after using color for a few weeks. Big screen monitors make old style paint programs frustrating when you can’t grow the window, or have to turn off color to keep the program from crashing. And program development environments that once were speedy now send the Mac into the bit-bucket because the developer can’t figure out how to handle the switching context with a color video card installed. Even lowly debuggers have problems trying to cope with all the system enhancements. So while Apple has indeed given us lots of new toys, they have also given us lots of new headaches trying to understand and upgrade our products to work with everything. If you thought it was hard to program the Mac two years ago, pity the programmer just getting started today. And the fact that Apple has just now managed to cleaned up the documentation in Inside Macintosh Volume 5, doesn’t help much.

Fig. 1 Plotter Program generates hairline plots

Put Up or Shut Up

After hi-lighting commercial products which have made the transition to the new rules of the game, we have decided to put our money where our editorial mouth is, and attempt to publish a program that illustrates how to incorporate many of the new system features Apple has introduced in the last six months.

Problem Solving

Since one of the hottest markets for Macintosh now is in engineering environments, we will discuss a typical engineering approach to computer use. In aerospace and the defense industry, the name of the game is problem solving. You use the computer to solve a problem. It may be physics, engineering or math, but the computer is the tool for investigating the problem and finding a solution. Let’s suppose our problem is to build a space shuttle that flies rather than blows up. And let’s suppose a key part of the problem is the equation for modeling the burn rate of the solid rocket fuel in the boosters. To make things simple, we will assume the modeling equation is quadratic in form. We want to use the computer to model this quadratic equation and all others like it so we can determine the best model for the rocket’s design. The problem most engineers have when trying to use the Macintosh for problem solving, is they spend so much time figuring out how the Mac works, they never get around to the problem! So here is a shell program for modeling and simulation programs that follows the new Macintosh way of doing things. Our “Plotter” program analyzes the quadratic equation and plots it with the following Mac features:

• Dialog box for user-friendly input of parameters

• Equation plotted as a Quickdraw picture

• Plot can be saved to disk as a PICT file

• Program supports printing:

• hairline line width for graph

• Choice of window size or paper size

• Plot Window is growable, zoomable, moveable

• Plot can be opened and edited in MacDraw

• Plot can be placed in Pagemaker

• Uses Quickdraw and Postscript comments

• Supports WaitNextEvent for MultiFinder use

• Quickdraw colors for menus, graph, axis

• Nested menus allow color changes

Mac Modeling Requires Quickdraw

One of the big problems in trying to model equations on the Macintosh is how to create a Quickdraw Picture. Naturally you could just draw it on the screen as a paint-type bit-map, but then you couldn’t take advantage of the higher resolution of the LaserWriter to show the details of the plot. Once a plot is created, you want to be able to save and edit it to add notes, or even move the graph around the axis. To do this, the parts of the plot have to be created as MacDraw type objects. Yet they also have to be grouped or else you end up with 200 date points being re-positioned on the page by a careless mouse. When the plot is finished you have to be able to print or import it into a program like Pagemaker to show it to someone. So how to you create a program that does all this?

Check Your Library!

First, you make sure your supply to Technical Notes is up to date. Many of these features are documented and supported by the just released Volume Five of Inside Macintosh, and by a rash of new Technical Notes released since the last Boston Expo. Here are some of the notes that deal with the problems of pictures from the point of view of modeling equations.

• 21 Internal Picture format 11/86

• 27 MacDraw Picture Format 9/86

• 59 Pictures and Clip Regions 1/86

• 72 Optimizing for the Laser 3/86

• 91 Picture Comments 3/87

• 152 Using Laser Prep routines 7/87

• 154 Displaying large PICT files 7/87

• 155 Handles & Pointers 9/87

• 181 Picture Comments 11/87

• 183 Position Independent PS 11/87

In addition, there is the LaserWriter Technical manual, a new PICT File Format Notes, and Mac Example Applications, ver. 1.0. These three publications, available from APDA, include a wealth of information on how to create and print Quickdraw pictures and pic comments, both MacDraw and Postscript comments.

The problem of making an application MultiFinder friendly is partly addressed in the following technical notes as well as the recently released MultiFinder Development Package, ver. 1.0, from APDA:

• 158 Asked MultiFinder Questions 9/87

• 177 Sleep Parameter problem 11/87

• 180 MultiFinder Miscellanea 11/87

One of the best “overview” publications of how to implement all of the new goodies, especially color, is Dave Wilson’s new note collection, Programming the Macintosh II. This is available from MacTutor’s mail order store, in this issue. Dave has collected the slides from his Mac II seminar at last year’s Boston Expo and published his color paint program source code to provide a nice one-stop shopping center for all of the features in our program this month. Finally, you should plan on getting the Professional Programmer’s Extender from Invention Software. This contains all of the source code for volumes 1 and 2 of their extender products. This is also available from the MacTutor mail order store, in this issue. It is much faster to cut and paste source code from someone else, then re-invent the wheel yourself.

For those who like books (and have the time to read them), your in luck, if you use Borland’s Turbo Pascal for the Mac. A rash of new books have been released including Macintosh Turbo Pascal by Tom Swan [Wiley & Sons] and Turbo Pascal for the Mac by Leon Wortman [Tab Books]. Borland has also released a bunch of goodies including Turbo Pascal Tutor, and Numerical Methods Toolbox. I make it a habit to just visit my local computer bookstore regularly and buy anything with Mac on it. Call it a business expense!

How to Use the New Goodies

Our program this month features the full Macintosh User Interface, as documented in the recently released Human Interface Guidelines: The Apple Desktop Interface, published Addison-Wesley, for Apple. It would be a great challenge to take this book as a program definition and attempt to write a demo program that included full support for every feature in this book, showing how the full User Interface is implemented. The main program, and a unit called MyPlotStuff, implement the standard event loop for a single window application. Much of this was cut from the Multi-Window Text Editor MacTutor published last year. As I said, its always faster to cut and paste than re-invent. To support color, a color array is set up in the InitMac routine to define the eight Quickdraw colors. This way the program can run on all Macs without a lot of special programming. (Apple really needs to put color quickdraw into the SE so that all machines have the same version of Quickdraw, even if they can’t show color.)

MultiFinder Friendly

To be considered MultiFinder friendly, an application has to call WaitNextEvent and support suspend and resume events correctly. Our program works under MultiFinder and is especially useful with MacDraw, saving and opening our graphs between the two programs. But it wasn’t easy figuring out how to do it. The first problem we had was that neither Think’s Lightspeed Pascal nor Borland’s Turbo Pascal support the final MPW 2.0 interfaces. The latest versions, (LS Pascal 1.11 and Turbo Pascal 1.1) both use MPW 2.0 beta interfaces and so do not include either the SysEnvirons glue, nor the WaitNextEvent interface. To get around this, I added the WaitNextEvent definition to the ROM85 library for LS Pascal. Since SysEnvirons is an OS trap, I suspect you can’t call it without assembly glue to manage the register set-up so it is commented out in the listing. I just assumed the Mac was a Plus, SE or II with the latest system.

Where is WaitNextEvent

The MultiFinder documentation says you should call WaitNextEvent if it is present. Otherwise, call GetNextEvent and SystemTask. So you have to check the unimplemented trap call to find out and set a flag so you will know which event trap to use. I did this and after a while I noticed the program always said the WaitNextEvent trap was unimplemented. What? I have a Mac II with the latest system. How can it be unimplemented? Where is it? I called several people, both at Borland and Think, but no one knew the answer. Finally, after studying two sample programs from the MultiFinder Developer’s package previously mentioned, I noticed their programs didn’t seem to have any problem. It finally dawned on me. WaitNextEvent is inside MultiFinder! Thus it only exists when your application is running under MultiFinder, when I suppose it gets patched into the system. Under the Finder, it’s not there so you have to check for it. You would think this little gem would have been included in the documentation somewhere. Alas, I don’t have either the final Volume 5 of IM, nor the final MultiFinder Developer’s package!

Our plot is stored as a picture in a data structure called PlotDocHandle. We set up the document in our InitMyWindow routine in the normal manner. Note that all the rectangles we will need are set here, relative to the window’s portRect. We also do a ClipRect to set the clipping region of the window’s grafport so we don’t have any Quickdraw problems a la tech note 59.

Fig. 2 Our menus include a nested color menu

Color Menus

Our InitMyMenus routine includes an apple, file and edit menu as well as a nested menu for color and a menu for some printing options. The data structures are designed to make it easy to check the nested menu items and this code depends heavily on both Dave Wilson’s programming examples, and other code segments I’ve seen.

The Mighty Update Event

Our doMouse, Keydowns, and activate routines are pretty standard user interface stuff so no need to go over those here. The Update routine, is critical. The ideal for all Macintosh programs is to never draw anything! The application creates a Quickdraw picture or pictures and then invalidates some portion of the screen, causing an update event. Then, in the Update Event routine, you call DrawPicture to display the results of all the other application code that has been maintaining and modifying those pictures. It has always been a mystery to me how you create the perfect Update Event routine. Here is how ours works:

• Save and set the current grafport

• Begin Update to restrict the visRgn to the collection of invalid rgns that need updating.

• Erase the window’s portRect.

• Set the clip rgn to the window’s portRect.

• Draw the picture.

• Draw the grow icon.

• End the update, restoring the VisRgn.

Exactly why all of these steps are needed, in that order is a mystery to me, but it works. The window’s portRect encloses the content region of the window, which includes everything but the title bar. In particular, it includes the scroller and grow icon regions. So when you erase that, you have to re-draw the grow icon. The picture is drawn in what I call the PicRect, or the application area of the content region, not including the scroller areas. When a grow window event takes place, these rectangles have to be carefully updated so that the next update event will work properly.

MultiFinder Support

Our doMulti routine implements the suspend and resume events from MultiFinder. Basically, it is a carbon copy of our activate / deactivate event routine. Since it is not really an event, we have to do a lot of processing to check for suspend or resume, and for a mouse moved event, if we are supporting that feature of MultiFinder. Our program is set up for it, but we don’t support it, since, for multiple monitors, you have to do a lot of region arithmetic I don’t fully understand. The beta documentation also says we have to call SystemEvent and post an activate event if a DA is the front window when we are suspended or resumed. I have included this code in our doMulti routine, but it may not be necessary. I’m looking forward to checking the final documentation to see about this.

Grow Window

Our MyPlotStuff unit implements the remainder of the usual user interface. We have an about box dialog that reads the ID string like the new Finder does and displays it. We also find out how much memory we have left from whatever MultiFinder has allocated to us by calling MaxMem. Our doMenuBar routine does the usual menu bar processing, including checking the nested color menu items when the user selects a new color. The menus also are displayed in the color of the selection thanks to the color menu resources Steve Sheets taught us about in past issues of MacTutor.

Our grow routine is the most important one in this unit. Grow works with the update event to change the window properly when it is resized. It is another Macintosh mystery I’ve never fully understood. As I understand it, you have a pre-grow period and a post-grow period, determined by when you call SizeWindow. I use the routine for both a grow window event and a zoom window event. In the case of a zoom, you get the new window size from the portRect, which is already set for you by the zoom. In the case of a grow, you call GrowWindow to return the new window size. I re-calculate the important window rectangles both before a SizeWindow and after. SizeWindow changes the portRect of the window to the new size. So, first you invalidate the scroller, grow and pic rectangles with the old portRect, then you SizeWindow to change the portRect, and invalidate the scroller, grow and pic rectangles for the new window size. This seems to correctly get all the window areas properly drawn during the update event. I suspect we may be invalidating to many areas and that this can be re-fined so that you only invalidate certain rectangles depending on whether the window is getting smaller or larger. Also, if you have controls, you can move and re-size controls separately, so they can be removed from the invalidation by calling the validate trap. If anyone has a more efficient grow / update routine for the general case, I’d like to see it.

Fig. 3 MultiFinder support: Plotter works with MacDraw

Saving Our Graph

Once we have played around with various graphs, it would be nice to save them. Our myFileStuff unit does the SaveAs and Save functions. To save a picture, you call the standard file dialog and if the reply is good, you create the file, open the file, set the file position to the start of the file and write something into the file. Then you close the file and flush the toilet, er, volume. This is the order of calls in our doSaveAs routine, the majority of which is error checking if anything goes wrong, goes wrong, goes wrong

To write our graph out to disk, we simply have to write out our quickdraw picture. But first we write a 512 byte blank header. This will cause MacDraw to open the PICT file and use it’s default settings. Our plotter program has no open function so we save our document as a MacDraw document so it can be viewed later and edited. The picture handle is stored in DrawingPic so we do a GetHandleSize and write out that number of bytes to the file, passing a pointer to the dereferenced picture handle. After saving the picture, we set the window title to the file name and store the file name, and volume reference number in our document data structure and enable the Save menu item for future use. For the Save function, we do the same thing as the SaveAs (they could be combined at the expense of clarity) except that we get the file name and volume reference number from our document datastructure rather than from a standard file dialog.

Fig. 4 Dialog Box gets our parameters

But Where Do We Actually Model It?

I told you it was tempting to get lost in the Macintosh interface and forget all about the modeling task our Boss assigned us to! We are supposed to be modeling a quadratic equation and coming up with some numbers for that next moon shot, not sitting around reading Inside Macintosh for the 100th time. Our Solve Unit implements the routines to analyze our equation and plot it by actually creating the quickdraw picture we’ve been spending all this time talking about. We also put up a dialog box to get all of the equation parameters and plot characteristics we need. We can set the step size, and the scale of both the x axis and the y axis. And of course, we can input the three parameters that define the general quadratic equation. In our doDialog routine, we get these parameters from the user, and remember them so they appear the next time the plot function is selected. SetIText is used to set the dialog items with the values of the global variables that hold the equation parameters. A flag is used to by-pass SetIText if this is the first time we have been called, in which case the default values from the dialog item resources will be used. This allows the user to modify the default values in the resource file with ResEdit if he wishes.

The hard part about the dialog box is converting the user’s response into real numbers. LS Pascal has a routine called ReadString that takes the string variables from the GetDItem trap and converts them into integer and real numbers for our equation parameters. However, this routine crashes mightily if the user types a non-numeric entry in the dialog! So the first improvement would be to protect yourself by checking the dialog input somehow.

The Quadratic Solution

The example problem is to find the roots of a quadratic equation. The problem in itself is not difficult (this time), but the solution technique will be similar for other problems.

First we should consider what the input specifications will be. Among the questions we should ask ourselves about the problem are:

1) What values will be provided as input to the program?

2) What range will these values be in?

3) What format will the values be in?

4) In what ways can these input values be used? Can the inputs be modified?

5) How will the input values be provided to the program?

6) What values will be returned by the program?

7) What format will the return values be in?

8) What kind of output will be produced?

Any quadratic equation may be reduced to the form, --

ax2 + bx + c = 0

then

If a, b, and c are real then:

If b2-4ac is positive, the roots are real and unequal;

If b2-4ac is zero, the roots are real and equal;

If b2-4ac is negative, the roots are imaginary and unequal.

The inputs required in this problem are a, b, and c. These values will be in the set of real numbers. Our dialog box allows us to input these values. On our plot, we print the results in a box indicating if the analysis yields real, or complex results. We can also solve the first derivative problem and determine where the graph has a local minimum or a maximum. Our program doesn’t do it, but we could also indicate the second derivative to show if the curve is concave upward or downward. Keep in mind that in a “real life” problem the algorithm is not always given as in this example. The user normally doesn’t care how the program arrives at the result as long as the result is correct. If too many details are specified early in the defining the problem, the programmer may get “locked in” to a particular solution too early. The programmer then lacks the flexibility needed to choose the best technique to solve the problem.

Our SolveIt and Quad routines implement the analysis portion of our modeling program by solving the quadratic equation and checking for the type of result. When the user selects Plot from the file menu, our doPlot routine will call SolveIt, which in turn calls Quad to get the “answers”. With answers in hand, we call PlotMe to create a quickdraw picture and display it in our window. After creating the picture with OpenPicture and ClosePicture, we get the picture displayed by simply invalidating the window’s portRect. This forces an update event, when will draw the graph by calling DrawPicture in our update event routine. Thus the whole plotter program really boils down to the magical routine which creates this quickdraw picture. This routine is called PrQDPicStuff in our Solve unit and is the most important of the whole program.

Creating the Quickdraw Picture

When we call OpenPicture, the characteristics of the current grafport will be used to determine how the picture will be stored. In our PrQDPicStuff routine, we want to allow for drawing either the picture on the screen or on the printer. We do this by passing to the routine, the display rectangle for the picture and a parameter indicating if we have been called from the Plot function or from the Print function. This was done to allow the added printer option of printing the graph using the full printer page, rather than the window’s portRect. While printing to full page size is not WYSIWYG, it is useful to get the biggest plot possible when you are trying to analyze a function’s behavior. In addition, if we are printing on the laserwriter, we set the font to times instead of geneva.

Constructing the picture definition routine is important. In our program we have grouped all the tasks together. First we calculate all the program variables, from the picture rectangle’s width and height. We get the font information from GetFontInfo so our paragraph can be constructed properly. The initial x and y values are calculated. These real values are converted into integer coordinates for plotting in such a way that the plot axis will extend the full length and height of the picture rectangle.

Next all the text is constructed with LS Pascal’s StringOf command and stored in Macintosh strings. For our paragraph, we use an array of strings which will be used to display the analysis results: the roots of the equation, the local min/max point, and the equation’s defining parameters. Once all the initial calculations and strings are set up, we are ready to ‘draw’ into our picture.

We set the background, axis and graph colors as set by the color menu items checked. We draw a box around the graph boundary (the display rectangle). We draw the axis, the plot itself, and a box for our paragraph. Finally we draw the paragraph and dispose of our temporary handles and clip regions.

Pic Comments

In order to get MacDraw to display our graph, the objects we draw must be grouped together. In particular, the graph itself must be grouped so all those little line segments stick together. A Pic Comment is used to do this. Pic Comments allow commands to be imbedded within the picture definition. There are two published lists of Pic Comments in the technical notes. One is the Pic Comments that MacDraw recognizes. The other are the Pic Comments that Postscript recognizes. Using these two sets of Pic Comments will enhance an application’s ability to create pictures that can be imported into other applications or that can take advantage of new capabilities. Apple is supposed to be keeping a list of registered Pic Comments, but little has come from it. The power of QuickDraw’s Pic Comments has really not been exploited or pushed by Apple in comparison to postscript.

PostScript Pic Comments

Since Quickdraw cannot do hairlines, we need to use some postscript Pic Comments the LaserWriter understands to set the line width thinner than that possible by Quickdraw. To get a hairline, define:

Type
 widhdl = ^widptr;
 widptr=^widpt;
 widpt=Point;
Var
 Width:Widhdl;

Then set up Width as follows:

Width^^.h:=10;
Width^^.v:=1;

Then use a Pic Comment:

PicComment(SetLineWidth,2,Handle(Width));

We can also draw our text so that it will be grouped as a paragraph by using the TextBegin and TextEnd comments. With the PicGrpEnd and PicGrpBegin comments we can group objects so that they stay together when moved around in MacDraw.

Printing Our Graph

Once our picture is defined, we can print it when the user selects print from the file menu. To print, we call our PrQDStuff routine above with the printing rectangle obtained from the Print Setup dialog and the display device set to LaserWriter. PrQDStuff will re-create the picture to the page rectangle, if the print option is selected, and a simple DrawPicture command during an open printing grafport will send the picture to the printer. The print traps are now in the system file, so we no longer link to the printing glue. In our doPrint routine, we get our print handle, saved in our document definition, save the current grafport and call PrOpen. Then we validate our print record and call PrJobDialog to put up the printing dialog box. If the user selects print, then we open the printing grafport by calling PrOpenDoc followed by PrOpenPage. From the printing info record (prInfo.rPage) we get the PageRect to pass to our picture creation routine. The PrintMe routine opens the picture and re-creates it using the PageRect, just as our PlotMe routine set up the picture for drawing to the screen. After drawing the picture into the printing grafPort, we close the page, close the document and close the printing manager by calling PrClosePage, PrCloseDoc and PrClose respectfully. When the printing grafPort is opened, the low level Quickdraw primitives are replaced with pointers into the printing manager, where the printer equivalent of the Quickdraw primitives translate the quickdraw picture definition into LaserPrep commands, which in turn are defined by the LaserPrep file into Postscript, and then interpreted by the Postscript interpreter in the LaserWriter into an image on the page. How does Postscript image the page? I don’t know. If I did know, I’d build a Postscript photo-typesetter, buy an Adobe Atlas board and have myself a 2700 dot per inch typesetting machine without paying Allied Linotype $50,000.

New Goodies Not Addressed

The key to this program is the fact that it produces a document that can be read, edited and placed by two other popular programs. In this way, the Plotter Program illustrates an important rule in the MultiFinder world: applications should work together to produce a library of compatible tools. The best way this can happen is by formatting the output of similar tools to read and write compatible documents. The MacDraw PICT file, the MacPaint bit-map file and the MacWrite formatted text file are important document standards that many similar tools support, besides the nearly universal unformatted text file. Even though Apple has defined a standard style definition for Text Edit that allows for font changes, we have yet to see a widely used formatted text item type that is a standard across many applications.

Apple Share is another new goodie that affects developers. How do we make Apple Share compatible programs? Consider this: To be MultiFinder friendly, Apple says you should keep track of where your windows were moved last. That means you have to write something to disk to save this information, but where? If you write it in the resource fork, the most logical place, then your program can’t be Apple Share compatible since the resource fork is not sharable. Two users cannot write to the same resource fork without destroying the integrity of the file. So Apple has created a catch-22 situation; supporting one new goodie (MultiFinder) makes it impossible to support another (Apple Share). Apple’s recommended solution is to write a “configuration file” into the system folder. Great. Now our hard disks will have hundreds of little configuration files to keep track of! Since the resource manager is Apple Share brain damaged, it hardly seems realistic for Apple to expect developer’s to rush madly to embrace this goodie. We encourage Apple to continue to define and support compatible data formats so tools can be used together. [Complete listing starts on the next page.]

Fig. 6 Pic Comments group objects for editing in MacDraw. Note that MacDraw ignores hairline Pic Comment!


{ Quadratic Equation Example program }
{ By Dave Kelly & Dave Smith     }
{ ©MacTutor, 1988}

PROGRAM QuadraticPlotter;

 USES
 ROM85, PrintTraps, PlotGlobals, Misc, myPlotStuff;

 PROCEDURE crash;
 BEGIN
 ExitToShell;
 END;

 PROCEDURE InitMac;
 VAR
 err : OSErr;
 BEGIN
 MaxApplZone;
 MoreMasters;
 MoreMasters;
 MoreMasters;
 MoreMasters;
 MoreMasters;
 InitGraf(@thePort);
 InitFonts;
 InitWindows;
 InitMenus;
 TEInit;
 InitDialogs(@crash);
 InitCursor;
 FlushEvents(everyEvent, 0);
 Finished := false;
 dialogflg := false;

 color[1] := 33; {black}
 color[2] := 30; {white}
 color[3] := 205;{red}
 color[4] := 341;{green}
 color[5] := 409;{blue}
 color[6] := 273;{cyan}
 color[7] := 137;{magenta}
 color[8] := 69; {yellow}

 theWorld.machineType := 4; {Mac II}
 {err := SysEnvirons(1, theWorld);  not in LSP 1.11}
 typeOfMac := theWorld.machineType;

 IF (typeOfMac >= 0) AND (NGetTrapAddress(WNETrapNum, ToolTrap) = NGetTrapAddress(UnImplTrapNum, 
ToolTrap)) THEN
 BEGIN
 WNE := FALSE;
 doMessage(‘WaitNextEvent not implemented’, ‘’, ‘’, ‘’); {Only true under 
Multifinder}
 END
 ELSE
 WNE := TRUE;
 mouseRgn := NewRgn;
 END;

 PROCEDURE initRects;
 VAR
 MemoryPtr : ^Integer;
 BEGIN
 MemoryPtr := pointer(mBarHeightGlobal); 
 mBarHeight := MemoryPtr^;
 screen := ScreenBits.Bounds; {current screen device}
 SetRect(DragArea, Screen.left + 4, Screen.top + mBarHeight + 4, Screen.right 
- 4, Screen.bottom - 4);
 SetRect(GrowArea, Screen.left + MinWidth, Screen.top + MinHeight, Screen.right 
- 8, Screen.bottom - 8);
 SetRect(PlotWindowRect, Screen.left + 15, Screen.top + 45, Screen.right 
- 75, Screen.bottom - 50);
 SetRect(ZoomRect, Screen.left + 4, Screen.top + mBarHeight + 4, Screen.right 
- 4, Screen.bottom - 4);
 END;

 PROCEDURE InitMyWindow;
 VAR
 windtype : integer;
 Visible : boolean;
 GoAway : boolean;
 RefVal : LongInt;
 title : str255;
 myPrint : THPrint;
 BEGIN
 Visible := false;
 windtype := documentProc + ZoomBox;
 GoAway := true;
 RefVal := 0;
 title := ‘Quadratic Plotter’;
 PlotWindow := NewWindow(NIL, PlotWindowRect, title, Visible, windtype, 
pointer(-1), GoAway, RefVal);
 PlotWindowPeek := WindowPeek(PlotWindow);
 SetPort(PlotWindow);
 TextFont(Geneva);
 TextSize(10);
 TextFace([]); {plain}
 TextMode(1);  {Or}
 PenNormal;
 ForeColor(blackColor);
 BackColor(whiteColor);
 PlotDocHandle := DocHandle(NewHandle(sizeof(Document)));
 PlotWindowPeek^.refCon := LongInt(PlotDocHandle);
 PlotWindowPeek^.windowKind := userKind;
 PlotDocHandle^^.drawing := NIL;
 WITH PlotWindow^.portRect DO
 BEGIN
 SetRect(VCRect, right - (SBarWidth - 1), top - 1, right + 1, bottom 
- (SBarWidth - 2));
 SetRect(HCRect, left - 1, bottom - (SBarWidth - 1), right - (SBarWidth 
- 2), bottom + 1);
 SetRect(GrowRect, HCRect.right, HCRect.top, VCRect.right, HCRect.bottom);
 SetRect(PicRect, left, top, right - (SBarWidth - 1), bottom - (SBarWidth 
- 1));
 SetRect(PageRect, left, top, right - (SBarWidth - 1), bottom - (SBarWidth 
- 1));
 END;  {of with }
 ClipRect(PlotWindow^.portRect);
 myPrint := THPrint(NewHandle(SIZEOF(TPrint)));
 PlotDocHandle^^.Print := myPrint;
 END;

 PROCEDURE InitMyMenus;
 VAR
 i : integer;
 BEGIN
 myMenus[AppleM] := GetMenu(AppleMenu);
 AddResMenu(myMenus[AppleM], ‘DRVR’);
 myMenus[FileM] := GetMenu(FileMenu);
 myMenus[EditM] := GetMenu(EditMenu);
 myMenus[ColorM] := GetMenu(ColorMenu);
 myMenus[OptionM] := GetMenu(OptionMenu);
 myMenus[GraphM] := GetMenu(GraphMenu);
 myMenus[AxisM] := GetMenu(AxisMenu);
 myMenus[BackgroundM] := GetMenu(BackgroundMenu);

 FOR i := 1 TO MenuCount DO
 InsertMenu(myMenus[i], 0);
 FOR i := SubMenuStart TO TotalMenuCount DO
 InsertMenu(myMenus[i], -1);

 GraphColor := 3;
 CheckItem(myMenus[GraphM], GraphColor, true);
 AxisColor := 1;
 CheckItem(myMenus[AxisM], AxisColor, true);
 BackgroundColor := 2;
 CheckItem(myMenus[BackgroundM], BackgroundColor, true);

 CheckItem(myMenus[OptionM], 1, true);
 Option := 1;  {window rect printing}

 DrawMenuBar;
 END; {of proc}

 PROCEDURE doMouse (myEvent : EventRecord);
 VAR
 whereIsIt : integer;
 whichWindow : WindowPtr;
 localPt, globalPt : Point;
 oldPort : GrafPtr;
 BEGIN
 globalPt := myEvent.where;
 localPt := globalPt;{global coord of mouse}
 GlobalToLocal(localPt);  {local coord of mouse}
 whereIsIt := FindWindow(globalPt, whichWindow);
 CASE whereIsIt OF
 inDesk : {0}
 doMessage(‘Mouse Click on Desktop.’, ‘(Not handled in this program.)’, 
‘’, ‘’);
 inMenuBar :    {1}
 doMenuBar(MenuSelect(globalPt));
 inSysWindow :   {2}
 SystemClick(myEvent, whichWindow);
 inContent :     {3}
 doContent(myEvent, whichWindow);
 inDrag : {4}
 doDrag(whichWindow, globalPt);
 inGrow : {5}
 doGrow(whichWindow, globalPt, False);
 inGoAway : {6}
 IF TrackGoAway(whichWindow, globalPt) THEN
 HideWindow(whichWindow);
 inZoomIn, InZoomOut :    {7, 8}
 BEGIN
 IF TrackBox(whichWindow, globalPt, whereIsIt) THEN
 BEGIN
 GetPort(OldPort);
 SetPort(whichWindow); {safety device}
 EraseRect(whichWindow^.portRect);
 ZoomWindow(whichWindow, whereIsIt, True);
 doGrow(whichWindow, globalPt, True);
 SetPort(OldPort);
 END;
 END;
 OTHERWISE
 BEGIN
 END;
 END; {of whereIsIt}
 END;

 PROCEDURE doKeyDowns (myEvent : EventRecord);
 VAR
 ch : char;
 charCode : longInt;
 keyCode : longInt;
 BEGIN
 charCode := BitAnd(myEvent.Message, charCodeMask);  
keyCode := BitShift(BitAnd(myEvent.Message, keyCodeMask), -8); 
 ch := Chr(charCode);  {get keyboard char}
 IF BitAnd(myEvent.Modifiers, CmdKey) = CmdKey THEN
 doMenuBar(MenuKey(ch))  { do menu command key}
 ELSE
 BEGIN  { do keystroke }
 ParamText(‘No typing supported ’, ‘’, ‘’, ‘’);
 itemhit := CautionAlert(AlertDialog, NIL);
 END;  { of do key stroke }
 END;  { of proc}

 PROCEDURE doUpdates (myEvent : EventRecord);
 VAR
 UpdateWindow : WindowPtr;
 TempPort : GrafPtr;
 BEGIN
 UpdateWindow := WindowPtr(myEvent.message);
 IF UpdateWindow = PlotWindow THEN
 BEGIN
 GetPort(TempPort); {save port}
 SetPort(UpdateWindow);
 BeginUpDate(UpdateWindow);
 BackColor(whiteColor);
 EraseRect(UpdateWindow^.portRect);
 ClipRect(UpdateWindow^.portRect);
 DrawPicture(DrawingPic, PicRect);
 DrawGrowIcon(UpdateWindow);
 EndUpDate(UpdateWindow);
 SetPort(TempPort);{restore port}
 END;
 END; {of proc}

 PROCEDURE doActivates (myEvent : EventRecord);
 VAR
 TargetWindow : WindowPtr;
 TargetPeek : WindowPeek;
 BEGIN
 TargetWindow := WindowPtr(myEvent.message);
 TargetPeek := windowPeek(TargetWindow);
 SetPort(TargetWindow);
 IF Odd(myEvent.modifiers) THEN
 BEGIN {activate}
 IF TargetWindow = PlotWindow THEN
 BEGIN
 DisableItem(myMenus[EditM], eUndo);
 DisableItem(myMenus[EditM], eCut);
 DisableItem(myMenus[EditM], eCopy);
 DisableItem(myMenus[EditM], ePaste);
 DisableItem(myMenus[EditM], eClear);
 DrawGrowIcon(TargetWindow);
 END
 END  { of activate loop}
 ELSE
 BEGIN {deactivate}
 IF TargetWindow = PlotWindow THEN
 BEGIN
 EnableItem(myMenus[EditM], eUndo);
 EnableItem(myMenus[EditM], eCut);
 EnableItem(myMenus[EditM], eCopy);
 EnableItem(myMenus[EditM], ePaste);
 EnableItem(myMenus[EditM], eClear);
 DrawGrowIcon(TargetWindow);
 END; { of my window activation}
 END; {of deactivate loop}
 END; {of proc}

 PROCEDURE doMulti (myEvent : EventRecord);

 CONST
 MouseMovedEvt = $FA;
 VAR
 HiByte : byte;
 bit0 : LongInt;
 sysresult : boolean;
 ResumeWindow : WindowPtr;
 ResumePeek : WindowPeek;
 SuspendWindow : WindowPtr;
 SuspendPeek : WindowPeek;
 MouseMove : LongAndByte;
 BEGIN
 bit0 := 31; {convert 68000 to toolbox}
 MouseMove.longView := myEvent.message;
 HiByte := Byte(MouseMove.byteView.byte0);
 IF HiByte = MouseMovedEvt THEN
 BEGIN {Handle mouse moved event}
 END;
 {check for resume event }
 IF Odd(myEvent.message) THEN
 BEGIN  {resume}
 {activate Event}
 ResumeWindow := FrontWindow;
 IF ResumeWindow = PlotWindow THEN
 BEGIN
 SetPort(ResumeWindow);
 InvalRect(ResumeWindow^.portRect); 
 DisableItem(myMenus[EditM], eUndo);
 DisableItem(myMenus[EditM], eCut);
 DisableItem(myMenus[EditM], eCopy);
 DisableItem(myMenus[EditM], ePaste);
 DisableItem(myMenus[EditM], eClear);
 DrawGrowIcon(ResumeWindow);
 END;
 IF FrontWindow <> NIL THEN
 BEGIN {DA check}
 ResumePeek := WindowPeek(FrontWindow);
 IF ResumePeek^.windowKind < 0 THEN {DA}
 BEGIN
 myEvent.what := activateEvt;
 BitSet(@myEvent.modifiers, bit0);
 sysresult := SystemEvent(myEvent);
 END; {da}
 END; {DA check}
 { end of activate Event}
 END {of resume}
 ELSE
 BEGIN  {suspend}
 {de-activate Event}
 SuspendWindow := FrontWindow;
 IF SuspendWindow = PlotWindow THEN
 BEGIN {plotwindow}
 SetPort(SuspendWindow);
 InvalRect(SuspendWindow^.portRect); 
 EnableItem(myMenus[EditM], eUndo);
 EnableItem(myMenus[EditM], eCut);
 EnableItem(myMenus[EditM], eCopy);
 EnableItem(myMenus[EditM], ePaste);
 EnableItem(myMenus[EditM], eClear);
 DrawGrowIcon(SuspendWindow);
 END; {plotwindow}
 IF FrontWindow <> NIL THEN
 BEGIN {DA check}
 SuspendPeek := WindowPeek(FrontWindow);
 IF SuspendPeek^.windowKind < 0 THEN
 BEGIN {da}
 myEvent.what := activateEvt;
 BitClr(@myEvent.modifiers, bit0);
 sysresult := SystemEvent(myEvent);
 END; {da}
 END; {DA check}
 { end of de-activate Event}
 END; {suspend}
 END; {of proc}

 PROCEDURE MainEventLoop;
 CONST
 MultiFinderEvt = 15;
 VAR
 sleep : LongInt;
 Event : EventRecord;
 DoIt : Boolean;
 BEGIN
 sleep := 10;
 REPEAT
 IF WNE THEN
 DoIt := WaitNextEvent(EveryEvent, Event, sleep, NIL) 
 ELSE
 BEGIN
 SystemTask;
 DoIt := GetNextEvent(EveryEvent, Event);
 END;
 IF DoIt THEN
 CASE Event.what OF
 mouseDown : 
 doMouse(Event);
 KeyDown, Autokey : 
 doKeyDowns(Event);
 updateEvt : 
 doUpdates(Event);
 activateEvt : 
 doActivates(Event);
 MultiFinderEvt : 
 doMulti(Event);
 OTHERWISE
 BEGIN
 END;
 END; {of event case}
 UNTIL Finished; {end program}
 END;

{ Main Program}
BEGIN
 InitMac;
 InitRects;
 InitMyWindow;
 InitMyMenus;
 MainEventLoop;
END.


UNIT MyPlotStuff;

INTERFACE

 USES
 ROM85, PrintTraps, PlotGlobals, Misc, solve, MyFileStuff, MyPrintStuff;

 PROCEDURE doAbout;
 PROCEDURE doQuit;
 PROCEDURE doMenubar (menuResult : LongInt);
 PROCEDURE doContent (ConEvent : EventRecord;
 contentWindow : windowPtr);
 PROCEDURE doDrag (GrabWindow : WindowPtr;
 GlobalMouse : point);
 PROCEDURE doGrow (ResizeWindow : WindowPtr;
 Globalmouse : point;
 Zoomflg : Boolean);
IMPLEMENTATION

 PROCEDURE doAbout;
 VAR
 IDStrHandle : StringHandle;
 dialogP : DialogPtr;
 item : integer;
 Str1, Str2, Str3 : str255;
 myHeapSpace : LongInt;
 FreeSpace : Size;
 BEGIN
 IDStrHandle := StringHandle(GetResource(rsrc, 0));
 IF IDStrHandle = NIL THEN
 BEGIN
 doMessage(‘Get About box crash!’, ‘’, ‘’, ‘’);
 ExitToShell;
 END;
 MoveHHi(Handle(IDStrHandle));
 HLock(Handle(IDStrHandle));
 FreeSpace := FreeMem;
 myHeapSpace := MaxMem(FreeSpace);
 NumToString(myHeapSpace, Str2);
 Str2 := concat(‘Memory = ‘, Str2);
 Str3 := ‘’;
 Str1 := ‘’;
 ParamText(IDStrHandle^^, Str1, Str2, Str3);
 dialogP := GetNewDialog(AboutDialog, NIL, pointer(-1));
 IF dialogP = NIL THEN
 BEGIN
 doMessage(‘Dialog crash!’, ‘We are dead...’, ‘’, ‘’);
 ExitToShell;
 END;
 initCursor;
 ModalDialog(NIL, item);
 DisposDialog(dialogP);
 HUnlock(Handle(IDStrHandle));
 END;

 PROCEDURE doQuit;
 BEGIN
 BackColor(whiteColor);
 ForeColor(blackColor);
 PenNormal;
 DisposeWindow(PlotWindow);
 DisposeRgn(mouseRgn);
 DisposHandle(Handle(PlotDocHandle));
 Finished := true;
 END; {of proc}

 PROCEDURE doMenubar; {(menuResult : LongInt)}
 VAR
 theMenu : integer;
 theItem : integer;
 daName : STR255;
 accItem : integer;
 temp : GrafPtr;
BEGIN
 theMenu := HiWord(menuResult); {menu}
 theItem := LoWord(menuResult); {item}
 CASE theMenu OF
 AppleMenu : 
 BEGIN
 IF theItem = aAbout THEN
 doAbout
 ELSE
 BEGIN  {must be DA}
 GetItem(myMenus[AppleM], theItem, daName);
 GetPort(temp);  {protect against flacky DA}
 accItem := OpenDeskAcc(daName);
 SetPort(temp);
 END; {else}
 END; {of AppleMenu}
 FileMenu : 
 BEGIN
 CASE theItem OF
 fPlot : 
 BEGIN
 doPlot;
 END;
 fSave : 
 BEGIN
 doSave;
 END;
 fSaveAs : 
 BEGIN
 doSaveAs;
 END;
 fPageSet : 
 BEGIN
 doPageSet;
 END;
 fPrint : 
 BEGIN
 doPrint;
 END;
 fQuit : 
 BEGIN
 doQuit;
 END;
 OTHERWISE
 BEGIN
 END;
 END; {of theitem}
 END; {of FileMenu}
 EditMenu : 
 BEGIN
 IF NOT SystemEdit(theitem - 1) THEN
 BEGIN
 CASE theItem OF
 eUndo : 
 BEGIN
 END;
 eCut : 
 BEGIN
 END;
 eCopy : 
 BEGIN
 END;
 ePaste : 
 BEGIN
 END;
 eClear : 
 BEGIN
 END;
 OTHERWISE
 BEGIN
 END;
 END; {of case}
 END; {of system edit}
 END; {of EditMenu}
 ColorMenu : 
 BEGIN {just a dummy for submenus}
 END; {of color menu}
 GraphMenu : 
 BEGIN
 CheckItem(myMenus[GraphM], GraphColor, false);
 GraphColor := theitem;
 CheckItem(myMenus[GraphM], GraphColor, true);
 END; {of graph menu}
 AxisMenu : 
 BEGIN
 CheckItem(myMenus[AxisM], AxisColor, false);
 AxisColor := theitem;
 CheckItem(myMenus[AxisM], AxisColor, true);
 END; {of axis menu}
 BackgroundMenu : 
 BEGIN
 CheckItem(myMenus[BackgroundM], BackgroundColor, false);
 BackgroundColor := theitem;
 CheckItem(myMenus[BackgroundM], BackgroundColor, true);
 END; {of background menu}
 OptionMenu : 
 BEGIN
 CheckItem(myMenus[OptionM], Option, false);
 Option := theitem;
 CheckItem(myMenus[OptionM], Option, true);
 END;
 OTHERWISE
 BEGIN
 END;
 END; {of theMenu}
 HiliteMenu(0);  {un-hilite selected menu}
 END;

 PROCEDURE doContent; {(ConEvent : EventRecord}
 {contentWindow : windowPtr);}
 VAR
 localPt, globalPt : Point;
 part : integer;
 myRect : Rect;
 control : ControlHandle;
 BEGIN
 IF contentWindow <> FrontWindow THEN
 SelectWindow(contentWindow);
 globalPt := ConEvent.where;
 localPt := globalPt;{global coord of mouse}
 GlobalToLocal(localPt);  {local coord of mouse}
 part := FindControl(localPt, contentWindow, control);

 IF contentWindow = PlotWindow THEN
 BEGIN
 SetPort(PlotWindow);
 IF part <> 0 THEN
 BEGIN {in control}
 END;
 IF part = 0 THEN
 BEGIN  {content region}
 myRect := PlotWindow^.portRect;
 IF PtInRect(localPt, myRect) THEN
 BEGIN
 END;  {of ptInRect}
 END; { of part=0 }
 END; {of contentwindow}
 END;  {of proc}

 PROCEDURE doDrag; {(GrabWindow : WindowPtr}
 {GlobalMouse : point);}
 BEGIN
 DragWindow(GrabWindow, GlobalMouse, DragArea);
 END;

 PROCEDURE doGrow; {(ResizeWindow : WindowPtr;}
 {Globalmouse : point;}
 {ZoomFlg:Boolean);}
 VAR
 newSize : LongInt;
 hsize : integer;
 vsize : integer;
 oldPort : GrafPtr;
 myRect : rect;
 tempLong : LongInt;
 BEGIN
 IF (ResizeWindow <> FrontWindow) THEN
 SelectWindow(ResizeWindow)
 ELSE
 BEGIN
 IF (ZoomFlg) THEN
 BEGIN
 WITH ResizeWindow^.portRect DO
 BEGIN
 tempLong := bottom - top;
 newSize := BitShift(tempLong, 16);
 newSize := newSize + (right - left);
 END;
 END
 ELSE
 newSize := GrowWindow(ResizeWindow, Globalmouse, GrowArea);
 IF newSize <> 0 THEN
 BEGIN  {grow the window}
 hsize := LoWord(newSize);
 vsize := HiWord(newSize);
 IF ResizeWindow = PlotWindow THEN
 BEGIN
 WITH ResizeWindow^.portRect DO {Pre-Grow}
 BEGIN
SetRect(VCRect, right - (SBarWidth - 1), top - 1, right + 1, bottom - 
(SBarWidth - 2));
SetRect(HCRect, left - 1, bottom - (SBarWidth - 1), right - (SBarWidth 
- 2), bottom + 1);
SetRect(GrowRect, HCRect.right, HCRect.top, VCRect.right, HCRect.bottom);
SetRect(PicRect, left, top, right - (SBarWidth - 1), bottom - (SBarWidth 
- 1));
 END;  {of with }
 InvalRect(VCRect);
 InvalRect(HCRect);
 InvalRect(GrowRect);
SizeWindow(ResizeWindow, hsize, vsize, TRUE); {new portRect}
 WITH ResizeWindow^.portRect DO {Post Grow}
 BEGIN
SetRect(VCRect, right - (SBarWidth - 1), top - 1, right + 1, bottom - 
(SBarWidth - 2));
SetRect(HCRect, left - 1, bottom - (SBarWidth - 1), right - (SBarWidth 
- 2), bottom + 1);
SetRect(GrowRect, HCRect.right, HCRect.top, VCRect.right, HCRect.bottom);
SetRect(PicRect, left, top, right - (SBarWidth - 1), bottom - (SBarWidth 
- 1));
SetRect(PageRect, left, top, right - (SBarWidth - 1), bottom - (SBarWidth 
- 1));
 END;  {of with }
 InvalRect(VCRect);
 InvalRect(HCRect);
 InvalRect(GrowRect);
 InvalRect(PicRect);
 END; {of if ResizeWindow}
 END; {of grow window stuff}
 END; {of if then newsize}
 END;  { of proc }

END. {of unit}


UNIT MyFileStuff;

INTERFACE

 USES
 ROM85, PrintTraps, PlotGlobals, Misc;

 PROCEDURE doSaveAs;
 PROCEDURE doSave;

IMPLEMENTATION

 PROCEDURE doSaveAs;
 LABEL
 1, 2;
 CONST
 SFPutLeft = 82;
 SFPutTop = 50;
 headerBytes = 512;
 TYPE
 DrawHeader = RECORD
 fill : ARRAY[1..256] OF integer;
 END;
 VAR
 SFPutPt : Point;
 theReply : SFReply;
 err : OSErr;
 refNum : Integer;
 bytes : LongInt;
 myWindow : WindowPtr;
 title : str255;
 myType : OSType;
 myCreator : OSType;
 str1, str2 : str255;
 header : DrawHeader;
 i : integer;
 myPicture : PicHandle;
 PicLength : LongInt;
 BEGIN
 myPicture := PlotDocHandle^^.Drawing;
 IF myPicture = NIL THEN
 doMessage(‘No picture to save yet!’, ‘’, ‘’, ‘’)
 ELSE
 BEGIN
 SetPt(SFPutPt, SFPutLeft, SFPutTop);
 WITH header DO
 BEGIN
 FOR i := 1 TO headerBytes DIV 2 DO
 fill[i] := 0;
 END;
 bytes := headerBytes;
 myWindow := PlotWindow;
 GetWTitle(myWindow, title);
 SFPutFile(SFPutPt, ‘Save Plot as ’, title, NIL, theReply);
 IF theReply.good THEN
 BEGIN {theReply.good}
 myType := ‘PICT’;
 myCreator := ‘MDRW’; {MacDraw doc}
 err := Create(theReply.fname, theReply.vRefNum, myCreator, myType);
 IF err <> noErr THEN
 BEGIN {err<>noErr}
 IF err = dupFNErr THEN
 BEGIN {err=dupFNerr}
 err := FSDelete(theReply.fname, theReply.vRefNum);
 IF err <> noErr THEN
 BEGIN {err<>noErr}
 doMessage(‘Cannot delete duplicate file.’, ‘’, ‘’, ‘’);
 GOTO 1;
 END; {err<>noErr}
 err := Create(theReply.fname, theReply.vRefNum, myCreator, myType);
 IF err <> noErr THEN
 BEGIN {err<>noErr}
 doMessage(‘Cannot create file...’, ‘’, ‘’, ‘’);
 GOTO 1;
 END; {err<>noErr}
 END {err=dupFNerr}
 ELSE {create file error}
 BEGIN {create file error}
 doMessage(‘Cannot create new file...’, ‘’, ‘’, ‘’);
 GOTO 1;
 END; {create file error}
 END; {err<>noErr}
 err := FSOpen(theReply.fname, theReply.vRefNum, refNum);
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot open file...’, ‘’, ‘’, ‘’);
 GOTO 1;
 END;
 err := SetFPos(refNum, FSFromStart, 0);
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot set start of file...’, ‘’, ‘’, ‘’);
 GOTO 2;
 END;

 err := FSWrite(refNum, bytes, @header);
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot write header to file...’, ‘’, ‘’, ‘’);
 GOTO 2;
 END;
 IF bytes <> 512 THEN
 BEGIN
 NumToString(bytes, str1);
 str1 := concat(str1, ‘ bytes’);
 str2 := concat(‘out of ‘, ‘512’);
 doMessage(‘Only able to write ‘, str1, str2, ‘to file.’);
 GOTO 2;
 END;
 PicLength := GetHandleSize(Handle(DrawingPic));
 bytes := PicLength;
 err := FSWrite(refNum, bytes, pointer(DrawingPic^));
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot write picture to file...’, ‘’, ‘’, ‘’);
 GOTO 2;
 END;
 IF bytes <> PicLength THEN
 BEGIN
 NumToString(bytes, str1);
 str1 := concat(str1, ‘ bytes’);
 NumToString(PicLength, str2);
 str2 := concat(‘out of ‘, str2);
 doMessage(‘Only able to write ‘, str1, str2, ‘to file.’);
 GOTO 2;
 END;
 SetWTitle(myWindow, theReply.fname);
 PlotDocHandle^^.FileName := theReply.fname;
 PlotDocHandle^^.VolRefNum := theReply.vRefNum;
 EnableItem(myMenus[FileM], fSave);
2 :
 err := FSClose(refNum);
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot close file...’, ‘’, ‘’, ‘’);
 ExitToShell;
 END;
 err := FlushVol(NIL, theReply.vRefNum);
 IF err <> NoErr THEN
 BEGIN
 doMessage(‘Cannot flush volume...’, ‘’, ‘’, ‘’);
 ExitToShell;
 END;
1 :
 SetCursor(arrow);
 END; {if good}
 END; {else pic exits}
 END;{ of proc}

 PROCEDURE doSave;
 LABEL
 1, 2;
 CONST
 headerBytes = 512;
 TYPE
 DrawHeader = RECORD
 fill : ARRAY[1..256] OF integer;
 END;
 VAR
 err : OSErr;
 refNum : Integer;
 bytes : LongInt;
 myWindow : WindowPtr;
 title : str255;
 str1, str2 : str255;
 header : DrawHeader;
 i : integer;
 myPicture : PicHandle;
 PicLength : LongInt;
 myRefNum : integer;
 myFname : str255;
 BEGIN
 myPicture := PlotDocHandle^^.Drawing;
 IF myPicture = NIL THEN
 doMessage(‘No picture to save yet!’, ‘’, ‘’, ‘’)
 ELSE
 BEGIN
 myRefNum := PlotDocHandle^^.VolRefNum;
 myFname := PlotDocHandle^^.FileName;
 IF myRefNum = 0 THEN
 BEGIN
 doMessage(‘Cannot save file’, ‘Use SaveAs...’, ‘’, ‘’);
 GOTO 1;
 END;

 WITH header DO
 BEGIN
 FOR i := 1 TO headerBytes DIV 2 DO
 fill[i] := 0;
 END;
 bytes := headerBytes;

 err := FSOpen(myFname, myRefNum, refNum);
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot open file...’, ‘’, ‘’, ‘’);
 GOTO 1;
 END;
 err := SetFPos(refNum, FSFromStart, 0);
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot set start of file...’, ‘’, ‘’, ‘’);
 GOTO 2;
 END;

 err := FSWrite(refNum, bytes, @header);
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot write header to file...’, ‘’, ‘’, ‘’);
 GOTO 2;
 END;
 IF bytes <> 512 THEN
 BEGIN
 NumToString(bytes, str1);
 str1 := concat(str1, ‘ bytes’);
 str2 := concat(‘out of ‘, ‘512’);
 doMessage(‘Only able to write ‘, str1, str2, ‘to file.’);
 GOTO 2;
 END;
 PicLength := GetHandleSize(Handle(DrawingPic));
 bytes := PicLength;
 err := FSWrite(refNum, bytes, pointer(DrawingPic^));
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot write picture to file...’, ‘’, ‘’, ‘’);
 GOTO 2;
 END;
 IF bytes <> PicLength THEN
 BEGIN
 NumToString(bytes, str1);
 str1 := concat(str1, ‘ bytes’);
 NumToString(PicLength, str2);
 str2 := concat(‘out of ‘, str2);
 doMessage(‘Only able to write ‘, str1, str2, ‘to file.’);
 GOTO 2;
 END;
2 :
 err := FSClose(refNum);
 IF err <> noErr THEN
 BEGIN
 doMessage(‘Cannot close file...’, ‘’, ‘’, ‘’);
 ExitToShell;
 END;
 err := FlushVol(NIL, myRefNum);
 IF err <> NoErr THEN
 BEGIN
 doMessage(‘Cannot flush volume...’, ‘’, ‘’, ‘’);
 ExitToShell;
 END;
1 :
 SetCursor(arrow);
 END; {if good}
 END;{ of proc}

END.


UNIT solve;

INTERFACE

 USES
 ROM85, PrintTraps, PlotGlobals, Misc;

 PROCEDURE quad (a, b, c : real;
 VAR x1, x2 : real;
 VAR result : integer);

 FUNCTION solveit : integer;
 PROCEDURE doPlot;
 PROCEDURE PrQDStuff (pRect : rect;
 QDdevice : integer);

IMPLEMENTATION

 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;

 PROCEDURE doDialog;
 VAR
 dialogP : DialogPtr;
 item : integer;
 dtype : integer;
 ditem : handle;
 drect : rect;
 dtext : Str255;
 BEGIN
 dialogP := GetNewDialog(ParamDialog, NIL, pointer(-1));
 IF dialogP = NIL THEN
 BEGIN
 doMessage(‘Dialog crash!’, ‘We are dead...’, ‘’, ‘’);
 ExitToShell;
 END;
 initCursor;
 IF dialogflg THEN
 BEGIN
 dtext := StringOf(a : 4 : 1);
 GetDItem(dialogP, dA, dtype, ditem, drect);
 SetIText(ditem, dtext);
 dtext := StringOf(b : 4 : 1);
 GetDItem(dialogP, dB, dtype, ditem, drect);
 SetIText(ditem, dtext);
 dtext := StringOf(c : 4 : 1);
 GetDItem(dialogP, dC, dtype, ditem, drect);
 SetIText(ditem, dtext);
 dtext := StringOf(step : 5 : 3);
 GetDItem(dialogP, dSTEP, dtype, ditem, drect);
 SetIText(ditem, dtext);
 dtext := StringOf(xscale);
 GetDItem(dialogP, dXSCALE, dtype, ditem, drect);
 SetIText(ditem, dtext);
 dtext := StringOf(yscale);
 GetDItem(dialogP, dYSCALE, dtype, ditem, drect);
 SetIText(ditem, dtext);
 END;
 REPEAT
 ModalDialog(NIL, item);
 UNTIL item = dOK;
 GetDItem(dialogP, dA, dtype, ditem, drect);
 GetIText(ditem, dtext);
 ReadString(dtext, a);
 GetDItem(dialogP, dB, dtype, ditem, drect);
 GetIText(ditem, dtext);
 ReadString(dtext, b);
 GetDItem(dialogP, dC, dtype, ditem, drect);
 GetIText(ditem, dtext);
 ReadString(dtext, c);
 GetDItem(dialogP, dSTEP, dtype, ditem, drect);
 GetIText(ditem, dtext);
 ReadString(dtext, step);
 GetDItem(dialogP, dXSCALE, dtype, ditem, drect);
 GetIText(ditem, dtext);
 ReadString(dtext, xscale);
 GetDItem(dialogP, dYSCALE, dtype, ditem, drect);
 GetIText(ditem, dtext);
 ReadString(dtext, yscale);
 PlotDocHandle^^.aParam := a;
 PlotDocHandle^^.bParam := b;
 PlotDocHandle^^.cParam := c;
 PlotDocHandle^^.stepParam := step;
 PlotDocHandle^^.xParam := xscale;
 PlotDocHandle^^.yParam := yscale;
 dialogflg := true;
 DisposDialog(dialogP);
 END;

 PROCEDURE quad; {(a, b, c : real;var x1, x2 : real;var result : integer);}
 VAR
 check : real;
 BEGIN
 result := 0;
 check := (b * b) - (4 * a * c);
 IF result = 0 THEN
 BEGIN
   { Check if double root exists }
 IF check = 0 THEN
 BEGIN
 result := 2;
 x1 := positivecalc(a, b, check);
 x2 := x1;
 END;
 { Check if real result}
 IF check > 0 THEN
 BEGIN
 result := 1;
 x1 := positivecalc(a, b, check);
 x2 := negativecalc(a, b, check);
 END;
 { Check if root is complex }
 IF check < 0 THEN
 BEGIN
 result := 3;
 check := -check;
 x1 := positivecalc(a, b, check);
 x2 := negativecalc(a, b, check);
 END;
 END;
 END;

 PROCEDURE PrQDStuff; {(pRect : rect; QDdevice : integer);}
 CONST
 Display = 1;
 LaserWriter = 2;
 ImageWriter = 3;
 NoJust = 0;
 LeftJust = 1;
 CenterJust = 2;
 RightJust = 3;
 FullJust = 4;
 LinesInParagraph = 5;
 {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;
 TYPE
 widhdl = ^widptr;
 widptr = ^widpt;
 widpt = Point;

 TTxtPicRec = PACKED RECORD
 tJus : Byte;
 tFlip : Byte;
 tRot : Integer;
 tLine : Byte;
 tCmnt : Byte;
 END;

 VAR
 le, tp, ri, bo : integer;
 str1, str2, str3, str4, str5 : str255;
 str6, str7, str8, str9 : str255;
 hPos, vPos, hor, ver : integer;
 x, y, z1, z2 : real;
 rBox, ClipBox : rect;
 Width : Widhdl;
 leading : integer;
 LineNo : integer;
 ParagraphBegin : Point;
 Indent : integer;
 Paragraph : ARRAY[1..LinesInParagraph] OF str255;
 TxtPicRec : TTxtPicRec;
 TxtPicPtr : QDPtr;
 TxtPicHdl : QDHandle;
 TextClipRgn : RgnHandle;
 SaveClip : RgnHandle;
 fInfo : FontInfo;
 BEGIN
 SaveClip := NewRgn;
 GetClip(SaveClip);
 ClipRect(pRect);
 TextClipRgn := NewRgn;
 penNormal;
 IF QDdevice = LaserWriter THEN
 BEGIN
 TextFont(times);
 TextSize(10);
 TextFace([]);
 TextMode(srcOr);
 END;
 hor := (pRect.right - pRect.left) DIV 2;
 ver := (pRect.bottom - pRect.top) DIV 2;
 Width := Widhdl(NewHandle(sizeof(widpt)));
 Width^^.h := 10;
 Width^^.v := 1;
 TxtPicPtr := @TxtPicRec;
 TxtPicHdl := @TxtPicPtr;
 TxtPicRec.tJus := LeftJust;
 TxtPicRec.tFlip := 0; {no flip}
 TxtPicRec.tRot := 0; {no rotation}
 TxtPicRec.tLine := 2; {1 1/2 spacing}
 GetFontInfo(fInfo);
 leading := fInfo.descent + fInfo.ascent + fInfo.leading;
 Indent := 2;
 x := -xscale / 2;
 y := a * x * x + (b * x) + c;
 hPos := integer(round(x * hor * 2 / xscale + hor));
 vPos := integer(round(-y * ver * 2 / yscale + ver));
 z1 := -b / (2 * a);
 z2 := (4 * a * c - (b * b)) / (4 * a);
 le := 2;
 tp := ver + (ver DIV 3);
 ri := 140;
 IF ri >= (hor + hor DIV 3) THEN
 ri := hor + hor DIV 3;
 bo := ver + ver - 2;
 setRect(rBox, le, tp - 14, ri, bo);
 ParagraphBegin.h := 4;
 ParagraphBegin.v := tp;

 {Graph Text}
 str1 := stringOf(-xscale DIV 2);
 str2 := stringOf(yscale DIV 2);
 str3 := stringOf(xscale DIV 2);
 str4 := stringOf(-yscale DIV 2);

 Paragraph[1] := StringOf(‘y=ax^2 + bx + c’, chr(13));
 Paragraph[2] := StringOf(‘a=’, a : 3 : 1, ‘, b=’, b : 3 : 1, ‘, c=’, 
c : 3 : 1, chr(13));
 Paragraph[3] := StringOf(‘x1=’, x1 : 5 : 3, ‘, x2=’, x2 : 5 : 3, chr(13));
 CASE result OF
 1 : 
Paragraph[4] := StringOf(‘Two Real Roots, x1, x2’, chr(13));
 2 : 
Paragraph[4] := StringOf(‘Double Root’, chr(13));
 3 : 
Paragraph[4] := StringOf(‘Two Complex Roots ‘, chr(13));
 OTHERWISE
 ;
 END;
Paragraph[5] := StringOf(‘Slope 0 = (‘, z1 : 2 : 1, ‘,’, z2 : 2 : 1, 
‘)’, chr(13));

 PenNormal;
 BackColor(Color[BackgroundColor]);
 ForeColor(Color[AxisColor]);

 {Drawing Boundry}
 PicComment(picDwgBeg, 0, NIL); {Begin MacDraw Document}
 PicComment(picGrpBeg, 0, NIL);
 PicComment(SetLineWidth, 2, Handle(Width));
 IF QDdevice = Display THEN
 FillRect(pRect, white);
 FrameRect(pRect);

 {Two Axis}
 PicComment(picGrpBeg, 0, NIL);
 moveto(0, ver);
 line(hor + hor, 0);
 moveto(hor, 0);
 line(0, ver + ver);
 PicComment(picGrpEnd, 0, NIL);

 ForeColor(Color[GraphColor]);

 {Plot Itsef}
 PicComment(picGrpBeg, 0, NIL);
 moveto(hPos, vPos);
 REPEAT
 x := x + step;
 y := a * x * x + (b * x) + c;
 hPos := integer(round(x * hor * 2 / xscale + hor));
 vPos := integer(round(-y * ver * 2 / yscale + ver));
 WITH pRect DO
 IF (hPos < right) AND (hPos > left) AND (vPos < bottom) AND (vPos > 
top) THEN
 LineTo(hPos, vPos)
 ELSE
 moveto(hPos, vPos);
 UNTIL x >= xscale / 2;
 PicComment(picGrpEnd, 0, NIL);
 ForeColor(Color[1]);
 {Axis Text}
 moveto(4, ver + 14);
 DrawString(str1);
 moveto(hor - 40, 14);
 DrawString(str2);
 moveto(hor + hor - 50, ver + 14);
 DrawString(str3);
 moveto(hor - 40, ver + ver - 14);
 DrawString(str4);
 {Box }
 PicComment(picGrpBeg, 0, NIL);
 PicComment(picGrpBeg, 0, NIL);
 PicComment(SetLineWidth, 2, Handle(Width));
 IF QDdevice = Display THEN
 fillRect(rBox, white);
 frameRect(rBox);
 PicComment(picGrpEnd, 0, NIL); {of box}

 GetClip(TextClipRgn);
 ClipBox := rBox;
 ClipRect(ClipBox);
 {Box Text}
PicComment(TextBegin, sizeof(TTxtPicRec), Handle(TxtPicHdl));
 FOR LineNo := 1 TO LinesInParagraph DO
 BEGIN
 moveto(ParagraphBegin.h, ParagraphBegin.v);
 move(Indent, (LineNo - 1) * leading);
 DrawString(Paragraph[LineNo]);
 END;
 PicComment(TextEnd, 0, NIL);
 PicComment(PicGrpEnd, 0, NIL); {of Box & text}
 PicComment(PicGrpEnd, 0, NIL); {of select all objects}
 picComment(picDwgEnd, 0, NIL); {of drawing}
 SetClip(SaveClip);
 disposHandle(handle(width));
 DisposeRgn(TextClipRgn);
 DisposeRgn(SaveClip);
 END;

 PROCEDURE PlotMe;
 CONST
 Display = 1;
 VAR
 Displayrect : rect;
 pstate : PenState;
 BEGIN
 Displayrect := PicRect;
 IF PlotDocHandle^^.drawing <> NIL THEN
 BEGIN
 KillPicture(DrawingPic);
 PlotDocHandle^^.drawing := NIL;
 END;
 GetPenState(pstate);
 DrawingPic := OpenPicture(Displayrect);
 PrQDStuff(Displayrect, Display);
 ClosePicture;
 SetPenState(pstate);
 InvalRect(Displayrect); {draw picture}
 PlotDocHandle^^.drawing := DrawingPic; {save it}
 END;

 FUNCTION solveit; { : integer;}
 BEGIN
 doDialog;
 IF a <> 0 THEN
 quad(a, b, c, x1, x2, result)
 ELSE
 result := -1;
 solveit := result;
 END;

 PROCEDURE doPlot;
 BEGIN
 result := solveit;
 showWindow(PlotWindow);
 IF PlotWindow <> FrontWindow THEN
 SelectWindow(PlotWindow);
 IF result <> -1 THEN
 BEGIN
 PlotMe;
 EnableItem(myMenus[FileM], fPrint);
 END;
 END;
END.

UNIT MyPrintStuff;

INTERFACE

 USES
 ROM85, PrintTraps, PlotGlobals, Misc, myFileStuff, Solve;
 PROCEDURE doPageSet;
 PROCEDURE doPrint;
IMPLEMENTATION

 PROCEDURE PrintMe;
 CONST
 LaserWriter = 2;
 VAR
 theWorld : rect;
 pstate : penstate;
 BEGIN
 theWorld := PicRect;
 IF Option = 1 THEN
 theWorld := PicRect
 ELSE IF Option = 2 THEN
 theWorld := PageRect
 ELSE
 doMessage(‘Printing Rectangle Problem’, ‘’, ‘’, ‘’);
 GetPenState(pstate);
 PrintingPic := OpenPicture(theWorld);
 PrQDStuff(theWorld, LaserWriter);
 ClosePicture;
 SetPenState(pstate);
 DrawPicture(PrintingPic, theWorld);
 KillPicture(PrintingPic);
 END;

 PROCEDURE doPrint;
 VAR
 DoIt : boolean;
 myPrint : THPrint;
 myPrStatus : TPrStatus;
 myPrPort : TPPrPort;
 PrRect : rect;
 str1 : str255;
 temp : GrafPtr;
 numCopies : integer;
 count : integer;
 prStatus : TPrStatus;
 BEGIN {1}
 IF DrawingPic <> NIL THEN
 BEGIN {2}
 myPrint := PlotDocHandle^^.print;
 getport(temp);
 PrOpen;
 IF PrError = noErr THEN
 BEGIN {3}
 DoIt := PrValidate(myPrint);
 DoIt := PrJobDialog(myPrint);
 IF PrError <> noErr THEN
 doMessage(‘Printer error in job dialog’, ‘’, ‘’, ‘’);
 IF DoIt THEN
 BEGIN {4}
 myPrPort := PrOpenDoc(myPrint, NIL, NIL);
 IF PrError = noErr THEN
 BEGIN {5}
 numCopies := myPrint^^.prJob.iCopies;
 FOR count := 1 TO numCopies DO
 BEGIN {6}
 PrOpenPage(myPrPort, NIL);
 IF PrError = noErr THEN
 BEGIN {7}
 { print something dummy!}
 PageRect := myPrint^^.prInfo.rPage;
 PrintMe;
 END { 7}
 ELSE
doMessage(‘OpenPage error’, ‘cannot print this page’, ‘’, ‘’);
 PrClosePage(myPrPort);
 IF PrError <> noErr THEN
doMessage(‘ClosePage error’, ‘cannot close this page’, ‘’, ‘’);
 END; {6}
 END { 5}
 ELSE
 doMessage(‘OpenDoc error’, ‘cannot print’, ‘’, ‘’);
 PrCloseDoc(myPrPort);
 IF PrError <> noErr THEN
 doMessage(‘CloseDoc error’, ‘’, ‘’, ‘’);
 IF (myPrint^^.prJob.bJDocLoop = bSpoolLoop) AND (PrError = noerr) THEN
 PrPicFile(myPrint, NIL, NIL, NIL, prStatus);
 END; {4}
 END; {3}
 PrClose;
 setport(temp);
 END;{2}
 END; {of proc 1}


 PROCEDURE doPageSet;
 VAR
 DoIt : boolean;
 myPrint : THPrint;
 BEGIN
 myPrint := PlotDocHandle^^.print;
 PrOpen;
 IF PrError = noErr THEN
 BEGIN
 DoIt := PrValidate(myPrint);
 DoIt := PrStlDialog(myPrint);
 IF PrError <> noErr THEN
 doMessage(‘Printer error in style dialog’, ‘’, ‘’, ‘’)
 ELSE
 PageRect := myPrint^^.prInfo.rpage;
 END
 ELSE
 doMessage(‘Cannot perform PrOpen!’, ‘’, ‘’, ‘’);
 PrClose;
 END;
END. {of unit}

UNIT PlotGlobals;
INTERFACE
 USES
 ROM85, PrintTraps;
{ Global Constants }
 CONST

 {multifinder stuff}
 SysEnvTrap = $90;
 WNETrapNum = $60;    {trap number of WaitNextEvent}
 UnImplTrapNum = $9F;{trap number”unimplemented trap”}
 {window constants}
 ZoomBox = 8;  {window type}
 MinWidth = 80;
 MinHeight = 80;
 mBarHeightGlobal = $BAA;
 GrayRgnLowMemGlobal = $9EE;
 sBarWidth = 16;
 rsrc = ‘PLTR’;  {creator bytes restype}
 {dialog stuff}
 AboutDialog = 256;
 ParamDialog = 257;
 MessageDialog = 258;
 AlertDialog = 260;
 { menu res id’s}
 AppleMenu = 256;
 FileMenu = 257;
 EditMenu = 258;
 ColorMenu = 259;
 OptionMenu = 260;
 {submenus id’s}
 GraphMenu = 44;
 AxisMenu = 45;
 BackgroundMenu = 46;
 MenuCount = 5;
 SubMenuStart = 6;
 TotalMenuCount = 8;
 AppleM = 1;
 FileM = 2;
 EditM = 3;
 ColorM = 4;
 OptionM = 5;
 GraphM = 6;
 AxisM = 7;
 BackGroundM = 8;
 {menu items}
 aAbout = 1;
 fPlot = 1;
 fSave = 3;
 fSaveAs = 4;
 fPageSet = 5;
 fPrint = 6;
 fQuit = 8;
 eUndo = 1;
 eCut = 3;
 eCopy = 4;
 ePaste = 5;
 eClear = 6;
 oWindowRect = 1;
 oPageRect = 2;
 {Dialog Items}
 dOK = 1;
 dA = 2;
 dB = 3;
 dC = 4;
 dSTEP = 5;
 dXSCALE = 6;
 dYSCALE = 7;
 TYPE
 Document = RECORD
 aParam : real;
 bParam : real;
 cParam : real;
 stepParam : real;
 xParam : integer;
 yParam : integer;
 drawing : PicHandle;
 print : THPrint;
 FileName : str255;
 volRefNum : integer;
 END;
 DocPtr = ^Document;
 DocHandle = ^DocPtr;
 LongAndByte = RECORD
 CASE integer OF
 1 : (
 longView : LongInt
 );
 2 : (
 byteView : RECORD
 byte0 : SignedByte;
 byte1 : Signedbyte;
 byte2 : Signedbyte;
 byte3 : Signedbyte;
 END;
 );
 END;
{ Global Variables }
 VAR
 {my misc stuff}
 Finished : boolean;
 mBarHeight : Integer;
 {Multifinder stuff}
 WNE : boolean; {Multifinder friendly}
 SysEnv : boolean; {Multifinder friendly}
 theWorld : SysEnvRec;  {not in LSP 1.11 }
 typeOfMac : integer;
 mouseRgn : RgnHandle; {cursor region to pass to WNE}
 {menu stuff}
 myMenus : ARRAY[1..TotalMenuCount] OF MenuHandle;
 GraphColor : integer;
 AxisColor : integer;
 BackgroundColor : integer;
 color : ARRAY[1..8] OF LongInt;
 Option : integer; {1 = windowrect, 2=pagerect}
 {rectangles}
 DragArea : Rect;  {window drag area}
 GrowArea : Rect;{window grow area}
 Screen : Rect;  {physical screen area}
 PlotWindowRect : Rect; {beginning window size}
 ZoomRect : Rect;{zoomed window size}
 HCRect, VCRect, GrowRect : Rect; {scroller rects}
 PicRect : Rect; {content region of less scrollers}
 PageRect : rect;
 {dialogs stuff}
 ItemHit : integer;
 dialogflg : boolean;
 {plot stuff}
 a, b, c, x1, x2, check, step : real;
 result, xscale, yscale : integer;
 PlotWindow : WindowPtr;
 PlotWindowPeek : WindowPeek;
 PlotDocHandle : DocHandle;
 DrawingPic : PicHandle;
 PrintingPic : PicHandle;

IMPLEMENTATION

END.

*Plotter.R
*

Plotter.RSRC
????????

Type PLTR = STR 
 ,0
© by Dave Kelly & Dave Smith \0Dver 4 JAN 1988

Type FREF
,128
APPL 0
,129
PICT 1

Type BNDL
,128
PLTR 0
ICN#
0 128 1 129
FREF 
0 128 1 129

* ------ Multifinder events --------

* bit 15 = switcher save screen
* bit 14 = accept suspend resume events
* bit 13 = switcher enable option switch
* bit 12 = can do background on null events
* bit 11 = multifinder aware 
*         (activates & deactivates topmost 
*           window at resume, suspend events)

Type SIZE = GNRL
 ,-1
.H
4800    ;; $4800 = bits 14,11 set
.L
128000  ;; (for 150K recomended)
.L
80000 ;; (for 80K minimum)
.I
* ------------ menus ------------

Type MENU
* the desk acc menu
 ,256
\14;;apple menu
 About Plotter 
 (-

* the file menu
 ,257
File
 Plot /P
 (-
 (Save /S
 Save as 
 Page Setup  /U
 (Print  /O
 (-
   Quit /Q

* the edit menu
 ,258
Edit
 (Undo /Z
 (-
 Cut /X
 Copy /C
 Paste /V
 Clear

* the color menu
 ,259
Color
 Graph /\1B!\2C
 Axis /\1B!\2D
 Background /\1B!\2E

* the Option menu
 ,260
Print Options
 Window Size /[
 Page Size /]

* submenus
 ,44
Graph
 Black
 White
 Red
 Green
 Blue
 Cyan
 Magenta
 Yellow

 ,45
Axis
 Black
 White
 Red
 Green
 Blue
 Cyan
 Magenta
 Yellow

 ,46
Background
 Black
 White
 Red
 Green
 Blue
 Cyan
 Magenta
 Yellow


* ------ Dialogs --------
* About Box dialog...
type DLOG
 ,256
About Plotter 
100 100 250 400 
visible NoGoAway 
1
0
256

type DITL
 ,256
3
BtnItem Enabled
112 235 141 284 
OK

StatText Disabled
10 88 141 289 
Plot Demo\0D\0D++
Graphs Quadratic Equations\0D^0\0D^1\0D^2\0D^3

PicItem Disabled
10 10 96 81 
128

* Plot box dialog...
type DLOG
 ,257
Plot Parameters
100 105 250 405 
Visible NoGoAway 
4
0
257

type DITL
 ,257
13
* ok button (default)
BtnItem Enabled
110 230 136 275 
OK

* a parameter
EditText Enabled
30 15 46 60 
1

* b parameter
EditText Enabled
30 100 46 145 
-1

*c parameter
EditText Enabled
30 180 46 225 
-6

* step parameter
EditText Enabled
80 10 96 65 
.05

* xscale parameter
EditText Enabled
80 100 96 150
10

* yscale parameter
EditText Enabled
80 185 96 235 
20

StatText Disabled
10 35 26 55 
a

StatText Disabled
10 120 26 140 
b

StatText Disabled
10 200 26 220 
c

StatText Disabled
60 10 76 65 
step size

StatText Disabled
60 95 76 150 
x scale

StatText Disabled
60 180 76 250 
y scale

* Program Messages Dialog box...
type DLOG
 ,258
Program Messages
100 100 200 400
Visible NoGoAway
1
0
258

type DITL
 ,258
3
BtnItem Enabled
65 230 95 285
OK

StatText Disabled
15 60 85 222 
^0\0D^1\0D^2\0D^3

IconItem Disabled
10 10 42 42
1

* ------ Alerts ------------

* Program error alerts...
type ALRT
 ,260
100 100 200 400
260
5555

type DITL
 ,260
2

BtnItem
65 230 95 285
OK

StatText Disabled
15 60 60 275 
Program Problem Alert:\0D^0^1^2^3

* misc resources

Type ICN# = GNRL
  ,128 (0)
.H
0001 0000 0002 8000 0004 4000 0008 2000 
0010 1000 0020 0800 0050 0400 0088 0200 
0100 0100 0284 0080 0440 0240 0822 0420 
1410 0810 220A 1008 4084 3F04 802A 4082 
4001 8041 2003 3022 1005 C814 080E 7F8F 
0412 3005 0221 0007 0140 8005 0080 6007 
0040 1FE5 0020 021F 0010 0407 0008 0800 
0004 1000 0002 2000 0001 4000 0000 8000
*
0001 0000 0003 8000 0007 C000 000F E000 
001F F000 003F F800 007F FC00 00FF FE00 
01FF FF00 03FF FF80 07FF FFC0 0FFF FFE0 
1FFF FFF0 3FFF FFF8 7FFF FFFC FFFF FFFE 
7FFF FFFF 3FFF FFFE 1FFF FFFC 0FFF FFFF 
07FF FFFF 03FF FFFF 01FF FFFF 00FF FFFF 
007F FFFF 003F FE1F 001F FC07 000F F800 
0007 F000 0003 E000 0001 C000 0000 8000 

Type ICN# = GNRL
  ,129 (0)
.H
0FFF FE00 0800 0300 0800 0280 0800 0240 
0800 0220 0800 0210 0800 03F8 0801 0008 
0880 0008 0801 0208 0840 0008 0801 0408 
0820 0008 0801 0808 0810 0008 0801 1008 
0AAB AAA8 0809 2008 0804 4008 0803 8008 
0800 0008 0801 0008 0800 0008 0801 0008 
0800 0008 0801 0008 0800 0008 0801 0008 
0800 0008 0800 0008 0800 0008 0FFF FFF8
*
0FFF FE00 0FFF FF00 0FFF FF80 0FFF FFC0 
0FFF FFE0 0FFF FFF0 0FFF FFF8 0FFE FFF8 
0F7F FFF8 0FFE FDF8 0FBF FFF8 0FFF FBF8 
0FDD 7FF8 0FFA B7F8 0FE7 DFF8 0FEF FFF8 
0D74 5D58 0FB7 DBF8 0F7B BDF8 0EFD 7EF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 

 
TYPE PICT = GNRL
 ,128
.I
891
195 254 281 325
.H
1101 A000 82A0 008E 0100 0A00 0000 0002
D002 4098 000A 00C3 00F8 00FF 0148 00C3
00FE 00FF 0145 00C3 00FE 00FF 0145 0000
02F7 0002 F700 02F7 0002 F700 02F7 0002
F700 02F7 0002 F700 02F7 0002 F700 02F7
0006 FD00 000E FC00 07FD 0001 1F80 FD00
07FD 0001 7FC0 FD00 07FD 0001 FFF0 FD00
08FE 0002 03FF FCFD 0008 FE00 0207 FFFE
FD00 09FE 0003 1FFF FF80 FE00 09FE 0003
3FFF FFE0 FE00 09FE 0003 7FFF FFF8 FE00
0A02 0000 01FE FF00 FCFE 0008 0200 0003
FDFF FE00 0A02 0000 0FFD FF00 C0FF 000B
0700 001F FFFF 3FFF E0FF 000B 0700 007F
FFFE 1FFF F8FF 000B 0700 00FF FFFE 1FFF
FCFF 000B 0100 01FE FF02 27FF FCFF 000B
0100 01FE FF02 F9FF F8FF 000B 0100 00FE
FF02 FE7F F0FF 000B 0200 003F FEFF 019F
E0FF 000B 0200 001F FEFF 01E7 C0FF 000B
0200 003F FEFF 01F9 80FF 000B 0200 0033
FEFF 01FE 80FF 000A 0200 0060 FDFF 00C0
FF00 0B07 0000 607F FFFF FCC0 FF00 0B07
0000 601F FFFF F870 FF00 0B07 0000 6007
FFFF F0F8 FF00 0B07 0000 6001 FFFF F0F8
FF00 0B07 0000 6000 FFFF F0F8 FF00 0B07
0000 6038 3FFF B050 FF00 0A06 0000 607C
0FFF 30FE 000B 0700 0060 F603 FE30 A8FF
000B 0700 0060 E301 FC30 50FF 000B 0700
0060 C000 7830 20FF 000B 0700 0060 0000
1030 88FF 000B 0200 0060 FE00 0130 50FF
000A 0200 0060 FE00 0030 FE00 0B02 0000
60FE 0001 30A8 FF00 0B07 0000 6807 0700
B050 FF00 0A06 0000 681F 8FC0 B0FE 000B
0700 006C 7FDF F1B0 A8FF 000A 0200 0067
FEFF 0030 FE00 0B09 0000 63FF FFFE 31F4
1000 0B09 0000 307F DFF0 6046 3000 0B09
0000 381F 8FC0 E045 5000 0B09 0000 1C00
0001 C044 9000 0B09 0000 0E00 0003 8044
1000 0802 0000 07FE FFFD 0009 0500 0001
FFFF FCFD 0008 FE00 0280 0004 FD00 9800
0A00 FF00 F801 1901 4800 FF00 FE01 1901
4500 FF00 FE01 1901 4500 0008 FE00 0280
0004 FD00 08FE 0002 FFFF FCFD 0008 0200
0001 FEAA FD00 0802 0000 03FE 55FD 000A
0600 0006 FEAF EA80 FE00 0A06 0000 0D83
5835 40FE 000A 0600 001B 01B0 1AA0 FE00
0A06 0000 3501 5015 50FE 000A 0600 006A
82A8 2AA8 FE00 0A06 0000 D57D 57D7 F4FE
000A 0600 01AF AAFA AC1A FE00 0A06 0003
5055 0558 0DFE 000B 0700 06A0 2A02 A80A
80FF 000B 0700 0D60 3603 5415 40FF 000B
0700 0AB0 6B06 ABEA C0FF 000B 0700 0D5F
D5FD 5555 40FF 0009 0100 0AFC AA00 C0FF
0009 0100 0DFC 5500 40FF 0009 0100 0FFC
FF00 C0FF 0002 F700 02F7 0002 F700 02F7
0002 F700 02F7 0002 F700 A000 8FA0 0083
FF

* Menu color Definitions
*
* TYPE mctb followed by ID#,
* followed by number of entries.
* (ID 0 is menu bar entry.)
* Other ID# are menu ID#.
*
* For each entry:
* 1. Menu ID number
* 2. Menu item number
* 3. RGB color 1 (3 INTEGERS)
* 4. RGB color 2 (3 INTEGERS)
* 5. RGB color 3 (3 INTEGERS)
* 6. RGB color 4 (3 INTEGERS)
* 7. filler integer


* menu bar
Type mctb = GNRL
 ,0
* number of entries
.I
1
.I
* Menu ID number & the Menu item number
* 0 & 0 for menu bar entry.
* Default title & title background =
* black on white
* Default item & item background = 
* magenta on white
0 0
.H
0000 0000 0000
FFFF FFFF FFFF 
FFFF 0000 FFFF 
FFFF FFFF FFFF 
0000

* apple menu
 ,256
.I
3
.I
* title & title background =
* Cyan on white
* default item & background=
* red on white
256 0
.H
0000 FFFF FFFF 
FFFF FFFF FFFF 
FFFF 0000 0000 
FFFF FFFF FFFF 
0000
.I
* ITEM ONE
* Mark, command, name
* and background =
* blue on white
256 1
.H
0000 0000 FFFF
0000 0000 FFFF
0000 0000 FFFF
FFFF FFFF FFFF 
0000
.I
* ITEM TWO
* Mark, command, name
* and background =
* blue on white
256 2
.H
0000 0000 FFFF
0000 0000 FFFF
0000 0000 FFFF
FFFF FFFF FFFF 
0000

* Graph menu
 ,44
.I
8
.I
* black on white
44 1
.H
0000 0000 0000
0000 0000 0000
0000 0000 0000
FFFF FFFF FFFF
0000
.I
* black on white
44 2
.H
0000 0000 0000
0000 0000 0000
0000 0000 0000
FFFF FFFF FFFF
0000
.I
* red on white
44 3
.H
FFFF 0000 0000
FFFF 0000 0000
FFFF 0000 0000
FFFF FFFF FFFF
0000
.I
* green on white
44 4
.H
0000 FFFF 0000
0000 FFFF 0000
0000 FFFF 0000
FFFF FFFF FFFF
0000
.I
* blue on white
44 5
.H
0000 0000 FFFF
0000 0000 FFFF
0000 0000 FFFF
FFFF FFFF FFFF
0000
.I
* cyan on white
44 6
.H
0000 FFFF FFFF
0000 FFFF FFFF
0000 FFFF FFFF
FFFF FFFF FFFF
0000
.I
* magenta on white
44 7
.H
FFFF 0000 FFFF
FFFF 0000 FFFF
FFFF 0000 FFFF
FFFF FFFF FFFF
0000
.I
* yellow on white
44 8
.H
FFFF FFFF 0000
FFFF FFFF 0000
FFFF FFFF 0000
FFFF FFFF FFFF
0000

* Axis menu
 ,45
.I
8
.I
45 1
.H
0000 0000 0000
0000 0000 0000
0000 0000 0000
FFFF FFFF FFFF
0000
.I
45 2
.H
0000 0000 0000
0000 0000 0000
0000 0000 0000
FFFF FFFF FFFF
0000
.I
45 3
.H
FFFF 0000 0000
FFFF 0000 0000
FFFF 0000 0000
FFFF FFFF FFFF
0000
.I
45 4
.H
0000 FFFF 0000
0000 FFFF 0000
0000 FFFF 0000
FFFF FFFF FFFF
0000
.I
45 5
.H
0000 0000 FFFF
0000 0000 FFFF
0000 0000 FFFF
FFFF FFFF FFFF
0000
.I
45 6
.H
0000 FFFF FFFF
0000 FFFF FFFF
0000 FFFF FFFF
FFFF FFFF FFFF
0000
.I
45 7
.H
FFFF 0000 FFFF
FFFF 0000 FFFF
FFFF 0000 FFFF
FFFF FFFF FFFF
0000
.I
45  8
.H
FFFF FFFF 0000
FFFF FFFF 0000
FFFF FFFF 0000
FFFF FFFF FFFF
0000

* Background menu
 ,46
.I
8
.I
46 1
.H
0000 0000 0000
0000 0000 0000
0000 0000 0000
FFFF FFFF FFFF
0000
.I
46 2
.H
0000 0000 0000
0000 0000 0000
0000 0000 0000
FFFF FFFF FFFF
0000
.I
46 3
.H
FFFF 0000 0000
FFFF 0000 0000
FFFF 0000 0000
FFFF FFFF FFFF
0000
.I
46 4
.H
0000 FFFF 0000
0000 FFFF 0000
0000 FFFF 0000
FFFF FFFF FFFF
0000
.I
46 5
.H
0000 0000 FFFF
0000 0000 FFFF
0000 0000 FFFF
FFFF FFFF FFFF
0000
.I
46 6
.H
0000 FFFF FFFF
0000 FFFF FFFF
0000 FFFF FFFF
FFFF FFFF FFFF
0000
.I
46 7
.H
FFFF 0000 FFFF
FFFF 0000 FFFF
FFFF 0000 FFFF
FFFF FFFF FFFF
0000
.I
46 8
.H
FFFF FFFF 0000
FFFF FFFF 0000
FFFF FFFF 0000
FFFF FFFF FFFF
0000
.I

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Aether Gazer unveils Chapter 16 of its m...
After a bit of maintenance, Aether Gazer has released Chapter 16 of its main storyline, titled Night Parade of the Beasts. This big update brings a new character, a special outfit, some special limited-time events, and, of course, an engaging... | Read more »
Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »

Price Scanner via MacPrices.net

Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobile’s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Apple’s one-year warranty is... Read more
Updated Apple MacBook Price Trackers
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16″ and 14″ MacBook Pros along with 13″ and 15″ MacBook... Read more
Every model of Apple’s 13-inch M3 MacBook Air...
Best Buy has Apple 13″ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices are the lowest currently available for new 13″ M3 MacBook Airs among... Read more
Sunday Sale: Apple iPad Magic Keyboards for 1...
Walmart has Apple Magic Keyboards for 12.9″ iPad Pros, in Black, on sale for $150 off MSRP on their online store. Sale price for online orders only, in-store price may vary. Order online and choose... Read more
Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more
AT&T has the iPhone 14 on sale for only $...
AT&T has the 128GB Apple iPhone 14 available for only $5.99 per month for new and existing customers when you activate unlimited service and use AT&T’s 36 month installment plan. The fine... Read more
Amazon is offering a $100 discount on every M...
Amazon is offering a $100 instant discount on each configuration of Apple’s new 13″ M3 MacBook Air, in Midnight, this weekend. These are the lowest prices currently available for new 13″ M3 MacBook... Read more
You can save $300-$480 on a 14-inch M3 Pro/Ma...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more

Jobs Board

Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple 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
IT Systems Engineer ( *Apple* Platforms) - S...
IT Systems Engineer ( Apple Platforms) at SpaceX Hawthorne, CA SpaceX was founded under the belief that a future where humanity is out exploring the stars is Read more
*Apple* Systems Administrator - JAMF - Activ...
…**Public Trust/Other Required:** None **Job Family:** Systems Administration **Skills:** Apple Platforms,Computer Servers,Jamf Pro **Experience:** 3 + years of Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.