|
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
- SPREAD THE WORD:
- Slashdot
- Digg
- Del.icio.us
- Newsvine