Plotter
Volume Number: | | 4
|
Issue Number: | | 2
|
Column Tag: | | Pascal Procedures
|
MultiFinder Friendly MacDraw Plotter ![](img001.gif)
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____ doesnt 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 cant 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 cant 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, doesnt help much.
![](img002.gif)
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. Lets suppose our problem is to build a space shuttle that flies rather than blows up. And lets 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 rockets 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 couldnt 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 Wilsons new note collection, Programming the Macintosh II. This is available from MacTutors mail order store, in this issue. Dave has collected the slides from his Mac II seminar at last years 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 Programmers 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 Borlands 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 cant 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 wasnt easy figuring out how to do it. The first problem we had was that neither Thinks Lightspeed Pascal nor Borlands 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 cant 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 Developers package previously mentioned, I noticed their programs didnt 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, its 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 dont have either the final Volume 5 of IM, nor the final MultiFinder Developers 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 windows portRect. We also do a ClipRect to set the clipping region of the windows grafport so we dont have any Quickdraw problems a la tech note 59.
![](img003.gif)
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 Wilsons programming examples, and other code segments Ive 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 windows portRect.
Set the clip rgn to the windows 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 windows 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 dont support it, since, for multiple monitors, you have to do a lot of region arithmetic I dont 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. Im 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 Ive 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, Id like to see it.
![](img004.gif)
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 its 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.
![](img005.gif)
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 weve 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 users 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
![](img006.gif)
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 doesnt 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 doesnt 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 windows 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 windows 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 functions 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 rectangles 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 Pascals 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 equations 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 applications 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 QuickDraws 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 dont know. If I did know, Id 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 cant 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). Apples 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 developers 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.]
![](img007.gif)
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 numberunimplemented 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 ids}
AppleMenu = 256;
FileMenu = 257;
EditMenu = 258;
ColorMenu = 259;
OptionMenu = 260;
{submenus ids}
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