TweetFollow Us on Twitter

Quadratic Plotters
Volume Number:5
Issue Number:8
Column Tag:MacApp Workshop

A Tale of Two Quadratic Plotters

By Chuck McMath, Carl Nelson, MacApp Developer's Assoc.

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

[Author’s Note: This article is NOT about MacApp. We do not cover the basics which you can get elsewhere. For example, this article does not discuss the concepts behind Object programming and Object Pascal syntax, nor do we explain the organization of all the MacApp classes. The December 1987 MacTutor, Kurt Schmucker’s excellent book Object Oriented Programming for the Macintosh, the January 1989 APDALog, the newsletter of the MacApp Developer’s Association (Frameworks ) or the MacApp documentation itself are good reference sources. You may understand some of this article without knowing the basics behind Object Pascal or MacApp, but don’t count on it! The programs discussed in this article were written using MacApp 2.0ß8. By the time this is published, the final MacApp 2.0 should be available. As far as we know, no changes to this code should be necessary to compile, link, and run it under the final version of MacApp 2.0, but one never knows ]

Introduction

This article is about the conversion of Dave Kelly’s and Dave Smith’s Plot Program into a MacApp program. The program originally appeared as part of the Multifinder Friendly MacDraw Plotter article in the February 1988 MacTutor. Actually, we will discuss two conversions, one written by Chuck McMath (this month) which attempts to literally translate the original program into MacApp and the other a conversion (next month), by Carl Nelson, ports the intent of the original program into a MacApp program. We review the original article and program, then expose the mechanics and decisions involved in doing both conversions. Along the way, we will show you the basics of physically creating a MacApp program and give you some of our reasoning and insight as to why we did what we did. Hopefully you can use this wisdom to do the same as you start writing programs using MacApp. Most of us using MacApp have learned “the hard way” - hours of working on projects until we reach ‘enlightment’ on the techniques needed to take advantage of object programming languages.

The motive of this article is not to present the blinding vision of enlightenment on how to learn MacApp but rather a pragmatic approach, an exploration of two ways that might work. We know the starting point (the original program) and the ending point (the original program rewritten using MacApp). Let’s travel along the path from start to end with two programs, one a simple clean translation and the other a program that produces the same effect but is internally quite different -- the low road (direct translation) and the high road (conversion and expansion). Two points of view, and two results. From both of these you can gain insight into the mechanics of MacApp and a brief look at how Objects and MacApp change the way you look at writing programs.

Introduction Revisited

While Carl’s viewpoint is the elegance and power that MacApp gives you in terms of code reusability, my perspective is somewhat different. The main impression that I had when I looked at the ‘Multifinder Friendly Plotter’ was “hey -- this program is all user-interface.” Although it does spend some time solving a quadratic equation and fooling around with picture comments, most of the code is involved with the plot parameters dialog box, putting the window up, handling events correctly, etc. Of course, you might say those features are necessary in any Macintosh program, right? Absolutely! These ‘common user interface’ features are what MacApp is all about. My point of view is that MacApp provides a full-blown user interface, freeing you from having to worry about those details, and letting you concentrate on what makes your application different. You can turn your application out more quickly, and have it be of higher quality and greater reliability. The bottom line: less work!

I took the design of the plotter application and decided to implement it just as it was. I didn’t make any changes to the overall design to take advantage of MacApp, but (and this is an important but) I also did not limit the program to take away any of MacApp’s benefits. For instance, the original plotter program puts up a dialog box, waits for you to enter parameters, and then plots the quadratic equation in a new window. If you replot the equation, you get a plot in the same window -- i.e., only one window is on the screen at a time. MacApp, however, implements multiple windows as a given; instead of throwing out MacApp’s multiple window feature, I allowed the new plotter application to take advantage of that capability. The result is that the new plotter application allows you to produce as many plot windows as memory allows -- and better yet -- this was done with very little work on my part.

The Original Program

The original plotting program was written just after the new Macintosh ROMs became widely available. Since MacTutor likes to keep on the cutting edge, the two Daves decided to write a program which implements as many features as they could cram into a coherent whole. While the explicit purpose of the program is to solve quadratic equations, the real purpose was to showcase some of the new features in the Mac ][/SE ROMs. The new features being exhibited included:

- calling SysEnvirons to determine if the machine supported the required new features

- resources to specify colors in menus/windows

- hierarchical menus used to select colors for parts of the plot

- Multifinder support through calling WaitNextEvent and acting on Multifinder events

- capability to save plots as PICT files, and the use of PicComments to group logically related items

- hairlines on the LaserWriter through using PicComments.

The operation of the program is fairly simple: when Plot is selected from the File menu, a modal dialog box appears. The user types numbers in for the quadratic equation parameters and some plot parameters, then clicks the OK button (there is no Cancel button). The dialog goes away, and a plot window appears, with the solution to the quadratic equation plotted in the window. The plot is sized so as to always fill the entire window (minus allowance for the scroll bars, of course). A Graph menu lets the user change the color of the axis, the plot, and the background items. A Print Options menu allows the user to specify whether the printed output should be actual size (i.e., the window size) or a full page size. The Graph menu features three hierarchical menus displaying the colors which may be chosen for the three elements of the plot which can be colored (the axes, the plot itself, and the background). The colors available are the 8 supported in the so-called ‘Old QuickDraw model.’ The window can be resized, dragged, zoomed, and closed. The contents of the window may be saved, and if saved, the file written out is a PICT file which can be opened in MacDraw. If the file is opened in MacDraw, individual items can be manipulated, as if the plot were drawn in MacDraw itself. Selecting Plot again while a plot window is up brings up the modal dialog again, but when it is dismissed, the plot is redrawn in the existing window (only one window is allowed on the screen).

This is only an overview of the original program and this short description cannot do it justice. If you’d like to go read the original article, we won’t be offended (just come back to this one.) And now, back to Carl.

MacApp Provides Features

As Chuck said, the original article and program were written to show new features introduced into the Macintosh environment in early 1988 and not as the best or even the right way to do plotting of equations. The original article and the example program show a style for teaching and exploring programming. In order to accomplish their task, the two Daves drew source code from Professional Programmers Extender, past issues of MacTutor, Dave Wilson’s Examples and Steve Sheet’s Code, Inside Macintosh, and no less than 13 Apple Tech Notes. Several times in the article you can find a Dave saying: “It is much faster to cut and paste source code from someone else, than to reinvent the wheel yourself.” The theme of this article, and many MacTutor articles, could just as well have been learning through reuse and extension. Programming by extending and reusing code is one of premises of an application framework and a key feature of languages containing Objects. We show how reuse and extension can occur when bringing the MacTutor Plot program into the MacApp framework. Writing this a year later and having version 2.0ß8 of MacApp in hand, many of the concerns presented in the article are non-issues. To be specific:

• Update Events & Growing the Window

MacApp users in general (and specifically for a program the size and complexity of Plot) never worry about update events. The MacApp architecture nicely handles setting things up for you so that all you have to do is draw when asked to by MacApp. MacApp programmers seldom worry about events, the event loop, Desk Accessories or switching in and out under Multifinder. There is a very robust event handling architecture provided by MacApp and it has been our experience that as the MacOS changes, Apple has enhanced MacApp to match the changes.

• Multifinder

Being Multifinder friendly and having to deal with WaitNextEvent are non-issues. MacApp properly handles all of it as long as the ‘SIZE’ resource is properly set up. If background processing is needed the right objects should be overridden.

• Palette Manager

The MacApp DrawShapes Example program provides us with an example of how to setup a custom Palette color with a single call to the toolbox GetColor routine.

• Menus (Color, hierarchical or otherwise)

MacApp has a very interesting and useful scheme for handling menus and the actions to be taken when menu selections are made. MacApp uses a resource named ‘cmnu’ which is the same as a regular ‘MENU’ but adds an integer to the end. This integer serves as a unique command number for that entry. The cmnu resources are post-processed by a utility called PostRez. It splits apart cmnus and creates a regular MENU and a table that maps these command numbers to menu items for use in your program. MacApp uses these unique command numbers to inform you of menu selections as well as handling the standard kind of menu functions like New, Open and Save. Command numbers 0 through 1200 are reserved for use by MacApp; the rest are available for use in your program. The nice side effect of this is that you can rearrange menus without regard to where they reside in the MENU BAR or their item number. All you ever deal with is the unique command number. Of course there are good examples of custom Menus in both the MacApp Developer’s Association ‘Goodies Disk’ and the MacApp samples shipped by Apple.

• Saving

MacApp provides all the code surrounding New, Save and Save As. If all of your data fits into memory at once, you will have to implement only two procedures, DoNeedDiskSpace and DoWrite, to save your data. You do not have to worry about temp files, disk space and errors, as MacApp provides a powerful error handling mechanism to handle general case failures so you do not have to.

• Printing

By creating a standard print handler object and assigning it to a view (objects which display things in MacApp) a view can be made can be made to print as well as display on the screen. Because of this mechanism, you usually do not have to worry if you are drawing to the screen or a printer port.

• Machine/System Determination

MacApp provides compile time variables (qNeedsScriptManager, qNeedsROM128K, qNeedsHierarchialMenus, qNeedsStyleTextEdit, qNeedsWaitNextEvent, qNeedsColorQD, qNeedsMC68020, qNeedsMC68030, qNeedsFPU) that you can use to configure your application so that if your combination of features is not present, your application will safely exit.

With all of the above support, I will not dwell on these features of MacApp [Chuck’s note: I will dwell on them to some extent.]. We will take this support as given and refer to them as appropriate in our discussions of our conversions. Again, you can find ample documentation as to how these work by reading the MacApp 2.0 final documentation, browsing the sources which are supplied with MacApp or looking through the 1988 and 1989 issues of Frameworks which discuss the MacApp 2.0 Architecture.

With all this out of the way we can move on to discuss our conversion efforts. Chuck gets to go first and discuss his efforts then I will talk about my conversion.

Overall Program Design

The crucial point of creating a MacApp program comes before any code has been written: design is the key, for if you have a good object design the code becomes obvious (well, if not ‘obvious,’ then maybe ‘more clear’). A good design can be understood by many people. A bad design is usually not even understood by its creator after a short time passes. The major design of our objects is easy. This is because we are using MacApp. By using MacApp, you ‘sign a pact’ to become a member of the MacApp community. This agreement says that you will accept all of the wonderful features MacApp provides for your application; in exchange, you agree to be a good citizen and write your application according to a particular structure. This structure enables you to take advantage of the MacApp code, and in a sense, drop your code into MacApp and have it work. The difficult part of object design is deciding where the things you are familiar with fit in. When you start out, you will often be asking yourself which feature and parameters belong to which object. As we’ll see, determining this is usually easy, once you understand the objects MacApp provides for us, and how they relate to the pieces of your application. In this particular case, the design is made easier in that we are simply converting an existing program to MacApp, and I am following the original design as much as possible. This means that many of the decisions have been made for us.

MacApp has a number of predefined object classes which equate to the different portions of an application. These predefined objects have the ‘generic Mac thing’ behavior already implemented. For instance, there is an object which corresponds to the overall application -- TApplication (incidentally, MacApp object types all begin with a capital T. This is, I suppose, to remind you that an object is simply a declared type in Pascal). An object of type TApplication ‘knows’ how to do all of the things that a good application must -- handle desk accessories, put up an about box, work under MultiFinder, launch when double-clicked upon in the Finder, open a document when the document is double-clicked, etc. Therefore, you don’t have to do anything to your application to have it exhibit this behavior. Instead, you worry about the part of your application that is different from a standard application. One aspect of MacApp programming that you will become accustomed to is that you don’t do all of the work -- you let MacApp do it for you. This can make you somewhat confused, for in many cases, you only implement a few methods for an object -- yet it seems to be quite a sophisticated object. This is because you are taking advantage of the predefined MacApp object behavior. Don’t worry, you will quickly get used to not doing all of the work yourself -- and you might even like it.

MacApp Function Subclass

TApplication Manages Documents TQPlotApplication

launch, open, etc.

TDocument holds data TQPlotDocument

stored on disk

TView Displays data in TQPlotView

windows

Table 1: MacApp Objects and QPlot Descendents

Table 1 shows a simplified description of the predefined MacApp objects, what they are responsible for, and the descendent objects defined in the plotter application. Keep in mind that when you define an object and modify its behavior, you can be doing one of two things: adding some behavior that does not exist, or changing some existing behavior. Our TQPlotApplication is an example object which was created for both of these reasons. Behavior has to be added to it to handle the colorful hierarchical menus, for example. And some behavior also has to be changed -- and this is where experience with MacApp becomes necessary -- because the generic MacApp behavior of an application is to open a blank document when you double-click on the application in the Finder. In our case, this behavior is not what we want to happen, so, I decided to override the method which produces the blank document. This requires ‘behavior modification’ for our TApplication object.

As you can see from the table, this application requires only a few simple objects (remember, my goal was to do a quick conversion and not to make the application into the ultimate MacApp program). There is, of course, an application object, since every MacApp program has to have an application object -- TQPlotApplication. There is a document, since we are concerned with storing data on the disk -- TQPlotDocument. There is a view, since we are displaying data in a window -- TQPlotView. And, last, but not least, there is the dialog view, since we have a dialog which requests the plot parameters -- TDialogView. Note that the dialog view is not a specialized view we defined. Why is that? Well, when you look at what a typical Macintosh dialog view lets you do, you will realize that MacApp’s dialog functions are ample to do what we want, especially since our dialog is a simple one. The other objects, though, warrant some explanation to show what they provide outside of the generic MacApp structure. Which leads us to the question:

How does anything get done?

Good question, Chuck! Things get done in MacApp by having one of the conceptual‘control chains’ take over. The most prevalent ‘chain’ used in MacApp is the inheritance chain. Many parts of MacApp use this sort of chain to pass control on from child (subclass) to parent (superclass). Knowing where to hook in by OVERRIDEing is the key to using this and the other chains. The other chains are:

1) The command chain routes system generated events to objects that want to handle them.

2) The idle chain is traversed during idle to give selected objects periodic chances to execute.

3) The choice chain informs a view object’s parent views that its state has changed.

Knowing these chains exist help you to determine where as well as who does the work and gives you conceptual frameworks around which to build your application. Now what were you going to say about the plotter application, Chuck?

In the plotter application, nothing happens unless the user selects something using the mouse, so we will only consider mouse down events, which are part of the command chain (incidentally, you don’t need to know much about these ‘chains’ in order to program in MacApp, although knowing what is going on under the hood helps you to understand when things turn out differently from what you expect. But back to mouse downs ) In addition, I’ll classify the mouse downs into either menu bar hits or ‘other.’ Initially I will discuss menu bar hits and how you translate from a menu selection to some activity.

In a non-MacApp program menu enabling and disabling is tied quite closely in with activate and deactivate events. Of course, this makes perfect sense, because when you activate a window you want that window’s menu items enabled, and vice versa when the window is being deactivated. There are a few inherent problems with this approach, however. First, you need to have special code in your activate or deactivate event handling procedure to eat up successive activate/deactivate events (the way Chernikoff’s MiniEdit does it) or else you will end up in the wrong state -- with the wrong items enabled. Second, this technique is not easy to extend or modify, and if you end up adding a new window type, then you add volumes to the code.

MacApp and Menus

In MacApp, menus are handled quite differently, as Carl has described above. MacApp tries to ‘unhook’ the connection between an item in a menu and an object which handles that item. Instead of hard-coding menu processing in a gigantic procedure, MacApp introduces the concept of commands and command numbers. Think of each menu item as representing a different command, and each command having its unique number. Some commands will best be handled by the application -- New, Open, and Quit for example. Other command are the domain of the document -- Save, SaveAs and Close. Still other commands should be handled by the object which draws the data -- turning grids on and off, aligning objects, perhaps cutting and pasting. So you can see that instead of a central processing repository for all ‘menu actions,’ MacApp farms the commands out the different objects. In fact, this is a crucial tenet of object programming: an object will only deal with information it knows how to process. Therefore, in MacApp, each object is given a stab at a menu selection. If the object ‘knows’ how to handle that command, it does whatever it is supposed to. If, however, the object doesn’t recognize that command as something it knows about, the object just passes the request along. Eventually either some object somewhere handled the menu choice, or MacApp senses that no object handled the menu choice, and that choice is simply thrown away.

Menu enabling is handled in the same distributed way as menu selection: there is a special method defined for objects in MacApp where they enable or disable the menu items they are concerned with. This ensures your program will never see a menu item enabled if it shouldn’t be, because the only way that item is enabled is if its corresponding object exists. In fact, whenever MacApp determines that the menu bar could have changed, it disables every item in all of the menus. Only after all items have been disabled do the individual existing objects get a chance to enable their functions.

Using a Command to Do Work

When a selection is made from a menu, the object that chooses to handle the menu selection can do one of two things: go ahead and perform whatever action was called for (in easy or trivial cases), or create a command object to perform the command and pass it back to MacApp to be executed (more difficult cases). Command objects are the technique MacApp uses to implement an action and its associated Undo and Redo. Since all of the actions in the plotting program were simple and could be undone easily, my version of the plotter application does not have any command objects. [Carl’s Note: My version does]

What about mouse downs that aren’t in the menu bar? They are normally handled by a method called DoMouseCommand (pretty obvious name, eh? Most MacApp methods attempt to be as obvious) but since the plotter application is a simple one, we don’t have anything to do in this method. All of the normal Macintosh behavior is already provided for us by MacApp: dragging the window around; clicking and dragging in the grow box, and resizing the window when we release the button; clicking in the close box to indicate that we want to put the window away; clicking in the zoom box to zoom or unzoom the window -- all of these normal, everyday Macintosh features are there -- yet we didn’t do a thing about them. This is the power of MacApp.

The Application Object

The application object, as we have mentioned before, is responsible for the things a good application does -- handling chores at startup and quitting time, creating and opening documents, handling desk accessories, and of course handling and sending events to the appropriate object. What does the object we created for this program do? Remember, that we can either add functionality to our object, or override existing functionality to change the behavior of our customized application object. Outside of initialization code, my application does one thing: handle choices from the Graph menu, which allows the user to choose the color of the axis, plot, and background. Since we want to be able to set a default for the next plot, the application object has three variables which will correspond to those colors. Selecting from these menus only changes the application’s variable. When a plot is created it uses the current set of default colors. Once a plot is created, its colors cannot be changed.

The Document Object

The document object is principally responsible for only one thing: saving and restoring its data. While there are certainly other things the document must be concerned with, most of the document’s methods will involve either saving and restoring, or manipulating its data structure -- the document is the object which is responsible for maintaining the data that our application requires. In addition, each document will usually have a window associated with it, and it will be used to display data from the document.

The standard document knows that it must be able to save and retrieve itself from disk, however, there’s no way the generic document can know how you want to store your data. So, if you were to look in the MacApp source code, in the section that dealt with saving the document, you would find that the DoWrite method is called. However, looking at the DoWrite methods would not help you, since the TDocument.DoWrite method is empty. So what’s going on here? Well, this design takes advantage of the inheritance chain Carl spoke of earlier. When you define your document class, you will implement your save routine for the DoWrite method that OVERRIDEs (replaces) TDocument’s DoWrite (this is where you need to understand the concept of OVERRIDE). When Save is selected from the File menu, DoWrite is called for the document (your document) and its DoWrite method gets called -- all because of the hook put in by MacApp. You don’t have to write any code to handle disk errors, not enough space, etc., because MacApp does it for you by calling DoWrite at the right time and under the right conditions. MacApp is full of these hooks -- calling a placeholder procedure that serves only to occupy space until you OVERRIDE it to provide the needed functionality. In many cases you are only defining these needed override procedures. Sometimes it is frustrating and confusing or seems quite magical as to where to find these magic place holders that you can override to get the work done. The only advice we offer here is patience. Reading the documentation sometimes helps, looking at source code of sample programs that behave the way you want is also a good way to discover these placeholders and of course reading articles like this one.

So what does the plotter document do? It has its own initialization code where it clears its copy of the quadratic equation parameters, and creates the window and view. Since the document does this work in my application, it has a method which will present the dialog box to the user and allow the user to type in parameters for the quadratic equation. Solving the equation is another function the document performs (note: the application object could have been chosen to solve the equation; I chose the document object since each document carries its own set of equation variables). And of course we need methods to write the plot out to disk. Since my plotter application does not read its data back in, there are no methods to read the PICT file, only ones to write it.

The View Object

The view exists to display the data in a window. Since the application draws quadratic equations, this is the main function of the view. However, there are some other functions our view must perform. Since good object design says data should be encapsulated, the view is the only object which knows its size, it is responsible for calculating how large it is. In the plotter application, the view can be one of two sizes: either the view is the entire size of the window or it is the size of a full page. When the window changes size, MacApp sends a message to the view, telling it to recalculate its size. Our view must know whether it is full page size or not, and depending on that status, must calculate its size. Since the view size can be changed by a menu choice, the view must have the necessary code to handle that menu choice. And of course, there must be code to enable the menu choices that the view can handle.

One big difference between the MacApp and the original version of the plotter program is that the original plotter explicitly passed which device was being drawn on -- the screen or the LaserWriter -- while the MacApp program doesn’t know. The original program did this to optimize operations for the LaserWriter (as all good Macintosh programmers do): for instance, when drawing on the LaserWriter, the original program did not fill rectangles with white (since on the LaserWriter this operation is just a waste of time). My MacApp version did not follow this approach because in the MacApp structure, printing is just the same as drawing on the screen -- the view doesn’t know and shouldn’t care which is being done. Although, I could have queried the global variable gPrinting to find out if the view was printing. MacApp takes care of all the device-specific setup, and our view just draws.

The Dialog Object

The dialog which initially appears is a simple one, but it serves to illustrate just how much MacApp does for us, and how much we don’t have to worry about. Think about all the steps required to put up a good-looking dialog that simply requests some values: after the resources have been created we need to get the dialog (it’s invisible), install a procedure for the UserItem (to outline the default button), stuff initial values, make the dialog visible, drop into a ModalDialog loop, if the default button was pressed then grab values from the dialog items and convert them back into numbers. The design of dialogs in MacApp incorporates much of this tedious process into a complete package that again gets done for us. Sure, MacApp dialogs aren’t free, but as they get more complex, MacApp’s contribution becomes more and more significant.

Just what is a MacApp dialog?

While in the ‘normal’ Macintosh environment a dialog is a special item, in MacApp, a dialog is simply a view (i.e., a place where data gets drawn) with a bunch of views within it. Every item in the DITL that can handle some interaction is a view, and these view types correspond pretty intuitively to the DITL types: TCheckBox, TRadioButton, TButton, TEditText, and TNumberText are the major types. As you may by now assume, these classes respond to mouse clicks in the way we’d want them to: for instance, when the check box is clicked on, the TCheckBox class flips an internal variable and checks the control. So we don’t have to do anything special in this dialog to get the kind of interaction we want (in fact, MacApp also does the little things like highlighting the default button, so we have even less work to do).

Our dialog box is pretty simple, since the only items in it that can respond to events are the six parameter EditText items. Each of these items is represented as a TEditText object in MacApp. By now you should realize that each of these ‘dialog object types’ has default behavior that corresponds to what we expect when we are in a dialog -- in our case, the TEditText objects respond to clicks and keystrokes. Hitting a tab while in a field causes the succeeding field (in DITL order) to be highlighted. This behavior is what we want, for the most part.

One important sidelight is that MacApp 2.0 does not use the Dialog Manager for its dialogs. This has a number of implications: dialogs are handled like other windows -- in fact, you may have noticed that when a modal dialog comes up, the menus all get disabled except for the Edit menu. With MacApp, you can use the Edit menu while your modal dialog is up. Another interesting feature is that since these modal dialogs are not real dialogs, your application can be switched out under MultiFinder while a modal dialog is on top. But back to our description

You may have noted that there is a TNumberText object, yet we used TEditText objects for numeric fields. Why? Well, TNumberText is only used for LongInts, and we want real numbers, so we will just take the strings and convert them to real numbers ourselves (Unlike Carl, I wasn’t aware of Calvin Cock’s TExtendedText unit that handles Reals, which he discusses later, so I (ugh) reinvented the wheel. Talk about an advertisement for being in touch.).

What goes where?

One of the decisions you must make when writing a MacApp program is which object a method belongs to. In many cases, it’s just not clear which object should have the responsibility. Take cut and paste for example. On the one hand, you could consider that cut and paste change the data structure associated with the document, so they should be document-level methods. On the other hand, you could say that cutting and pasting change the appearance of the items on the screen, so they should be view-level methods. One way to tell that a method is in the wrong place is that you are constantly (i.e., more than two or three times) having to refer to another objects’s fields to accomplish even a simple task. You probably have the method in the wrong class. Putting a method in the wrong class makes the method look messier or more complicated than it is. You will usually find yourself doing something like:

 a := TMyDoc.fMyView.fMyViewData.fGetaValue;

Another way to tell if a method is “misassigned” is to see if you rely on information that isn’t plainly available to your object to enable or disable the menu item associated with that command. If, for instance, you have cut and paste associated with the document, and you need to ask the view if any items are highlighted so you can tell if you should enable the menu items, then you either have a bad design or you have the method in the wrong class.

Discussion of the program

At this point, I’d like to move through the source files and point out where you will find the pieces I have described. The source files consist of three types of files: Pascal (MacApp) source, resources, and the makefile. The source files will merit most of the discussion, so let’s start with them.

Main program file (MQPlot.p)

All MacApp main programs look pretty much alike. After the necessary junk at the beginning at the file, the main program starts. Main programs are boring, because so much of the Macintosh functionality is rolled up into the application object. A MacApp main program does the following: initialize the Toolbox Managers and other needed functions, create the application object, call its initializing method, then call its Run method. That’s it, and that’s usually always it; when Run returns the program execution ends.

Unit file (UQPlot.p and UQPlot.inc1.p)

MacApp source files have a strange arrangement forced upon them by MacApp. The .inc1 source file is organized by object hierarchy: first the application, then the document, and last the view (remember, the dialog view does not have a customized object because the standard dialog handling was sufficient for our purposes).

As we mentioned before, the application object is a simple one, since there is not too much to do. In order to handle the menu choices relating to the color selections, we need to override DoSetupMenus and DoMenuCommand, and both of those methods are pretty easy to understand. Remember, the DoSetupMenus method is called by MacApp frequently (you won’t believe just how frequently) so there shouldn’t be any lengthy calculations here. If you need to do some complicated calculations to determine if some menu item should be enabled, you should do it somewhere else (like in the idle chain) and set a flag or value in your object; that flag can then be used for the menu enabling. The only other method of interest is a real short one: HandleFinderRequest. MacApp’s default behavior for applications is that when an application is launched from the Finder by double clicking on the application icon, a blank document opens. Well, we don’t want that to happen, since our document is the plot, and we wouldn’t want a blank plot window on the screen. So, to modify this behavior, we just override HandleFinderRequest and do nothing. Now when the application is launched, our HandleFinderRequest is called instead of the default one, and we don’t get a empty document. This method is a demonstration of the small things you sometimes have to do to make your application ‘perfect’ -- and note that it’s not difficult, it just requires knowing what’s going on and where to look. [Carl’s Note: In many ways this typifies the MacApp design - the methods are there to do the kind of things you will need to do - you just have to look for them.]

The document methods can be characterized into three categories: initialization, solving the quadratic equation, and saving the PICT data. Initialization methods are not very interesting, except to note that the DoMakeViews and DoMakeWindows methods are some more of the methods which you are required to OVERRIDE or else your program will not work (Actually that’s not really the truth -- with MacApp 2.0 you can omit these overrides and your program will work, it’s just that you’ll get the default view and window size/location). The method titles are fairly self explanatory. Solving the quadratic equation involves a few methods which contain a lot of code lifted directly from the original plotter application. All I did for these methods was put the method syntax before and after them, and change the variable references to refer to the document object’s variables instead of some global variables. The last few methods deal with saving the data to disk. As mentioned before, there are really two methods necessary to save data on disk: DoNeedDiskSpace -- which calculates if the file will fit on the disk, and DoWrite -- which actually writes out the data. If there seems to be a lot missing from the implementation of the disk handling, remember that MacApp does most of the work for us -- opening the file and checking for errors. Again, all we have to do is handle our application’s specific needs, which in this case is saving the PICT.

The view object contains some initialization methods (which should be quite familiar by now). After that is a method called CalcMinSize. This method is called (by MacApp of course) when the size of the view needs to be determined. Remember, the view can be either the size of the window or the size of an entire page. So we need to have a flag (fOnePage) which tells us which is the case. If we are an entire page, we tell MacApp that our size is the size of our print handler’s page (since we want the printout to be one page). If we are not the size of a page, we tell MacApp our size is the size of our superview (our superview is the view which we are inside. In the case of a simple view, our superview is the window itself). After the menu handling routines (DoSetupMenus and DoMenuCommand) we have a large method which prints the plot on the LaserWriter (again, this method was stolen directly from the original plotter application and had some method syntax wrapped around it). The next two methods were written to handle the case where the window is resized. In SuperViewChangedSize, we check to see if we are displaying the plot in full page mode. If not, when the window changes size we need to change the size of the view (since the view mirrors the window size). The next method, Resize, has been overridden because when the view size changes we want to force the view to be redrawn (i.e., when switching between full page and window size display modes). The last view method just draws the view, and it is also pretty simple.

Resource file (QPlot.r)

Resources for a MacApp program are almost identical to those for a non-MacApp program. There are only two differences (and they are big differences): ‘cmnu’ instead of ‘MENU’ and ‘view’ resources. ‘cmnu’ resources (probably stands for ‘Command Menu’) are used to associate menu items with command numbers. Carl and I have both spoken of the usefulness of command numbers, and I don’t need to reiterate it here. The view resource is different, and is a crucial resource in your MacApp program. Carl will speak about view resources in greater detail, but let me say that the view resource allows you to specify the contents of your windows (in functional areas). You can (and will) use views to specify your dialogs in MacApp, because these dialogs are build out of views, as we mentioned earlier. The benefit of using a view resource is the same as you get anywhere else in using resources: you can change the resource without having to recompile the source code. While it may seem that this benefit is limited with regard to views, I’m sure you can attest to the value of resources in other areas, and isn’t it nice to be able to ‘tweak’ a resource quickly?

One other thing you should know about MacApp resource files is that MacApp has a default number for the about box. If you can live with a boring about box (i.e., an ALRT) then you should create it with id 201. That’s because as part of the generic Macintosh application that MacApp implements, when you select the About Application from the Apple menu, you get ALRT 201 displayed. If you like that, it’s great, and as always, if you don’t like it, you can easily override it. In fact, I override it in my program because I want to calculate some system parameters. I’m sure that you realize the proper method is in the Application level object (since of course the application handles requests to display the about box).

Makefile (QPlot.MAmake)

The makefile is something many Lightspeed users are unfamiliar with. MacApp 2.0’s MABuild process eliminates the need for a makefile in simple cases. I have provided a simple make file, it’s not much, as you can see from the listing. When your program becomes more complicated the makefile usually grows proportionally in complexity. For small projects made up of two or three files, the example makefiles in the MacApp samples folder can be used as guides (and of course, you can consult the manual for more explanation).

Trouble In Paradise

One last parenthetical note before we move over to Carl’s description of his program. When we both did the conversions, we independently had problems printing the plots on the LaserWriter -- PostScript errors. I tore my hair out about it for a few weeks, then decided to really dig down and see what was happening. By strategically inserting debugging statements into my code I finally isolated my bug to a PicComment call. The PicComment in question sets the linewidth, and looks like this:

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

However, the real call should look like this:

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

The problem was that the second parameter to the PicComment is supposed to be the size (in bytes) of the data. The original specification was wrong, yet it worked (we assume) because Lightspeed Pascal must be more forgiving than MPW. Not only was this line a bug, but the Daves even featured the bug in their article (top of page 21)!! Let this be a lesson that just because someone gives you code that works you can’t assume that it is completely bug-free.

That just about covers my program; Next month, we’ll hear about Carl’s.

Continued in next frame
Volume Number:5
Issue Number:8
Column Tag:MacApp Workshop

A Tale of Two Quadratic Plotters (code)

{--------------------------------------------}
{------------ File MQPlot.p ----------------}
{--------------------------------------------}
{$P}
{MQPlot.p}
{Copyright © 1989 by Charles F. McMath  All rights reserved.}

{This is the main program for the MacApp
 plotter application.  The original plotter was
 written by Dave Smith and Dave Kelly for MacTutor
 Magazine.  This coversion was done by Chuck
 McMath to demonstrate the same program done using
 MacApp.  It also hopefully demonstrates some of
 the strengths of MacApp!
)
PROGRAM QPlot;

USES
 { • MacApp }
 UMacApp, 
 { • Building Blocks }
 UDialog, UPrinting,
 { • Implementation Use }
 SANE, ToolUtils, Fonts, Resources, Script,
 PickerIntf, Packages,
 { • the PlotUNIT }
 UQPlot;

VAR
 gQPlotApplication:   TQPlotApplication;
BEGIN
 InitUMacApp(5); 
 InitUDialog;
 InitPrinting;

 New(gQPlotApplication);
 gQPlotApplication.
 IQPlotApplication(kFileType);
 gQPlotApplication.Run;
END.

{--------------------------------------------}
{------------ File UQPlot.p ----------------}
{--------------------------------------------}
{Copyright © 1989 by Charles F. McMath.
 All rights reserved.}

UNIT UQPlot;

INTERFACE

USES
 { • MacApp - this includes all of the
 things necessary from the MacApp  Library }
 UMacApp, 
 { • Building Blocks }
 UDialog, UPrinting,
 { • Implementation Use }
 SANE, ToolUtils, Fonts, Resources, Script,
 PickerIntf, Packages;

CONST
 kSignature = ‘FGT3’; {Appl. signature}
 kFileType  = ‘PICT’;{our filetype }
 kQPlotWindowID    = 1001;

TYPE
 TQPlotApplication = OBJECT(TApplication)
   fDefGraph:    INTEGER; { Graph color index }
   fDefAxis:INTEGER; { Axis color index }
   fDefBack:INTEGER; { Back color index }
   fPrintOpt:    INTEGER; { Page/Window size }
 
 PROCEDURE TQPlotApplication.
 IQPlotApplication
 (itsMainFileType:OSType);
 FUNCTION  TQPlotApplication.DoMakeDocument
 (itsCmdNumber:CmdNumber): TDocument;
 OVERRIDE;
 PROCEDURE TQPlotApplication.
 HandleFinderRequest; OVERRIDE;
 PROCEDURE TQPlotApplication.DoSetupMenus;
 OVERRIDE;
 FUNCTION TQPlotApplication.DoMenuCommand
 (aCmdNumber: CmdNumber): TCommand;
 OVERRIDE;
 PROCEDURE TQPlotApplication.ShowAboutApp;
 END;

 TQPlotDocument = OBJECT(TDocument)
   fAParam: Real;{ these parameters }
   fBParam: Real;{  correspond }
 {  to those }
   fCParam: Real;{  in the quadratic }
   fStep: Real;  {  equation. }
   fXScale: INTEGER; { X axis scale }
   fYScale: INTEGER; { Y axis scale }
 
   fResult: INTEGER; { real results? }
   fRoot1:REAL;  { first root }
   fRoot2:REAL;  { second root }

   fPlotView:  TQPlotView;

 PROCEDURE TQPlotDocument.IQPlotDocument
 (itsFileType, itsCreator: OSType;
 usesDataFork, usesRsrcFork: BOOLEAN;
 keepsDataOpen, keepsRsrcOpen:
 BOOLEAN);
 PROCEDURE TQPlotDocument.DoMakeWindows;
 OVERRIDE;
 PROCEDURE TQPlotDocument.DoMakeViews
 (forPrinting: BOOLEAN); OVERRIDE;

 PROCEDURE TQPlotDocument.PosePlotDialog;
 PROCEDURE TQPlotDocument.Quad
 (a, b, c : REAL;VAR x1, x2 : REAL;
 VAR result : INTEGER);
 FUNCTION TQPlotDocument.SolveIt
 (a, b, c: REAL; VAR x1, x2: REAL):
 INTEGER;

 PROCEDURE TQPlotDocument.DoNeedDiskSpace
 (VAR dataForkBytes,
 rsrcForkBytes: LONGINT); OVERRIDE;
 PROCEDURE TQPlotDocument.DoWrite
 (aRefNum: INTEGER;
 makingCopy: BOOLEAN); OVERRIDE;
 END;

 TQPlotView = OBJECT(TView)
   fPlotDoc:TQPlotDocument; { link to doc }
   fOnePage:BOOLEAN; { if TRUE, page size }
   fDrawing:PicHandle;  { our picture! }

 PROCEDURE TQPlotView.IQPlotView
 (theDoc: TQPlotDocument;
 theGrafColor, theAxisColor,
 theBackColor: INTEGER);
 PROCEDURE TQPlotView.Free; OVERRIDE;

 PROCEDURE TQPlotView.CalcMinSize
 (VAR minSize: VPoint); OVERRIDE;
 PROCEDURE TQPlotView.DoSetupMenus;
 OVERRIDE;
 FUNCTION TQPlotView.DoMenuCommand
 (aCmdNumber: CmdNumber): TCommand;
 OVERRIDE;
 
 PROCEDURE TQPlotView.PrQDStuff
 (pRect : rect; QDdevice : integer);
 PROCEDURE TQPlotView.SuperViewChangedSize
 (delta: VPoint;
 invalidate: BOOLEAN); OVERRIDE;
 PROCEDURE TQPlotView.Resize
 (width, height: VCoordinate;
 invalidate: BOOLEAN); OVERRIDE;
 PROCEDURE TQPlotView.Draw(area: Rect); OVERRIDE;
 END;

IMPLEMENTATION
{$I UQPlot.inc1.p}

END.

{--------------------------------------------}
{---------- File UQPlot.inc1.p --------------}
{--------------------------------------------}
{Copyright © 1989 by Charles F. McMath.
 All rights reserved.}
CONST
 kPlotWindowID   = 1001;
 kPlotDLOG= 2000;
 kPlotID= ‘PPRM’;
 
 kStaggerAmt=  16;
 
 { these are command numbers } 
 cGraphColor=  1201;
 cAxisColor =  1202;
 cBackColor =  1203;
 
 cGrafBlack =  10001;
 cGrafWhite =  10002;
 cGrafRed = 10003;
 cGrafGreen =  10004;
 cGrafBlue= 10005;
 cGrafCyan= 10006;
 cGrafMagenta    = 10007;
 cGrafYellow=  10008;
 
 cAxisBlack =  11001;
 cAxisWhite =  11002;
 cAxisRed = 11003;
 cAxisGreen =  11004;
 cAxisBlue= 11005;
 cAxisCyan= 11006;
 cAxisMagenta    = 11007;
 cAxisYellow=  11008;

 cBackBlack =  12001;
 cBackWhite =  12002;
 cBackRed = 12003;
 cBackGreen =  12004;
 cBackBlue= 12005;
 cBackCyan= 12006;
 cBackMagenta    = 12007;
 cBackYellow=  12008;
 
 cPrintWS = 1301;
 cPrintPS = 1302;
 
(*
 * The following constants relate to DLOG
 * and ALRT numbers.
 *)
 kAboutDLOG = 1024; { our about box }
VAR
 gStaggerCount:  INTEGER;
 colors:ARRAY [1..8] OF INTEGER;
 crString:Str255;
{------------------------------------------------}
FUNCTION Int2Str(theInt: INTEGER): Str255;
(*
 * This utility function takes an integer and
 * converts it into a string.
 *)
VAR
 tempLong:LongInt;
 tempStr: Str255;
BEGIN
 tempLong := theInt;
 NumToString(tempLong, tempStr);
 Int2Str := tempStr;
END;    { Int2Str }
{------------------------------------------------}
FUNCTION Real2String(theReal: REAL;
 numDigits: INTEGER): Str255;
(*
 * This function takes a real number,
 * and converts it to a string with
 * the specified number of digits PAST the
 * decimal point.
 *)
VAR
 theForm: DecForm;
 xTemp: Extended;
 tempStr: DecStr;
BEGIN
 theForm.style := FixedDecimal;
 theForm.digits := numDigits;
 
 xTemp := theReal;
 Num2Str(theForm, xTemp, tempStr);
 Real2String := tempStr;
END;    { Real2String }
{------------------------------------------------}
FUNCTION String2Real(theString: Str255): REAL;
(*
 * This function takes a string form of a real
 * number, and converts it into the real number.
 *)
VAR
 xTemp: Extended;
BEGIN
 xTemp := Str2Num(theString);
 String2Real := Num2Real(xTemp);
END;    { String2Real }
{------------------------------------------------}
{------  QPlot Application Methods  ------------}
{------------------------------------------------}
PROCEDURE TQPlotApplication.IQPlotApplication
 (itsMainFileType: OSType);
(*
 * This procedure initializes the application.
 * It sets up all of our global variables and
 * fills the color index array.
 *)
VAR
 aQPlotView:TQPlotView;
BEGIN
 IApplication(itsMainFileType);
 
 crString[0] := CHR(1);
 crString[1] := CHR(13);
 
 colors[1] :=  33; { black }
 colors[2] :=  30; { white }
 colors[3] :=  205;{ red }
 colors[4] :=  341;{ green }
 colors[5] :=  409;{ blue }
 colors[6] :=  273;{ cyan }
 colors[7] :=  137;{ magenta }
 colors[8] :=  69; { yellow }
 
 fDefGraph := colors[3];
 fDefAxis := colors[1];
 fDefBack := colors[2];
 fPrintOpt := 1;
 
 gStaggerCount := 0;
END;  { TQPlotApplication.IQPlotApplication }
{------------------------------------------------}
FUNCTION  TQPlotApplication.DoMakeDocument
 (itsCmdNumber: CmdNumber): TDocument;
 OVERRIDE;
(*
 * This function is called whenever we’re
 * creating a new document.  It creates the
 * document object and returns it (properly
 * initialized, of course).
 *)
VAR
 aQPlotDocument: TQPlotDocument;
BEGIN
 New(aQPlotDocument);
 FailNil(aQPlotDocument);
 aQPlotDocument.IQPlotDocument
 (kFileType, kSignature,
 kUsesDataFork, NOT kUsesRsrcFork,
 NOT kDataOpen, NOT kRsrcOpen);

 aQPlotDocument.fSavePrintInfo := FALSE;
 DoMakeDocument := aQPlotDocument;
END;    { TQPlotApplication.DoMakeDocument }
{------------------------------------------------}
PROCEDURE TQPlotApplication.HandleFinderRequest;
 OVERRIDE;
BEGIN
 { just override this so we don’t put up a
   blank document }
END;  { TQPlotApplication.HandleFinderRequest }
{------------------------------------------------}
PROCEDURE TQPlotApplication.DoSetupMenus;
 OVERRIDE;
(*
 * This procedure enables the appropriate menu
 * items for the application.
 *)
BEGIN
 INHERITED DoSetupMenus;
 
 Enable(cGraphColor, TRUE);
 Enable(cAxisColor, TRUE);
 Enable(cBackColor, TRUE);
(*
 * Enable all of these, and put a check by
 * the current one.
 *)
 EnableCheck(cGrafBlack, TRUE, 
 fDefGraph=colors[1]);
 EnableCheck(cGrafWhite, TRUE,
 fDefGraph=colors[2]);
 EnableCheck(cGrafRed, TRUE,
 fDefGraph=colors[3]);
 EnableCheck(cGrafGreen, TRUE,
 fDefGraph=colors[4]);
 EnableCheck(cGrafBlue, TRUE,
 fDefGraph=colors[5]);
 EnableCheck(cGrafCyan, TRUE,
 fDefGraph=colors[6]);
 EnableCheck(cGrafMagenta, TRUE,
 fDefGraph=colors[7]);
 EnableCheck(cGrafYellow, TRUE,
 fDefGraph=colors[8]);
 
 EnableCheck(cAxisBlack, TRUE,
 fDefAxis=colors[1]);
 EnableCheck(cAxisWhite, TRUE,
 fDefAxis=colors[2]);
 EnableCheck(cAxisRed, TRUE,
 fDefAxis=colors[3]);
 EnableCheck(cAxisGreen, TRUE,
 fDefAxis=colors[4]);
 EnableCheck(cAxisBlue, TRUE,
 fDefAxis=colors[5]);
 EnableCheck(cAxisCyan, TRUE,
 fDefAxis=colors[6]);
 EnableCheck(cAxisMagenta, TRUE,
 fDefAxis=colors[7]);
 EnableCheck(cAxisYellow, TRUE,
 fDefAxis=colors[8]);
 
 EnableCheck(cBackBlack, TRUE,
 fDefBack=colors[1]);
 EnableCheck(cBackWhite, TRUE,
 fDefBack=colors[2]);
 EnableCheck(cBackRed, TRUE,
 fDefBack=colors[3]);
 EnableCheck(cBackGreen, TRUE,
 fDefBack=colors[4]);
 EnableCheck(cBackBlue, TRUE,
 fDefBack=colors[5]);
 EnableCheck(cBackCyan, TRUE,
 fDefBack=colors[6]);
 EnableCheck(cBackMagenta, TRUE,
 fDefBack=colors[7]);
 EnableCheck(cBackYellow, TRUE,
 fDefBack=colors[8]);
 
END;    { TQPlotApplication.DoSetupMenus }
{------------------------------------------------}
FUNCTION TQPlotApplication.DoMenuCommand
 (aCmdNumber: CmdNumber): TCommand;
 OVERRIDE;
(*
 * This function handles menu requests that
 * pertain to the application.  It ensures that
 * choices that change colors work correctly.
 *)
BEGIN
 DoMenuCommand := gNoChanges;
 CASE aCmdNumber OF
 cAboutApp: ShowAboutApp;
 cGrafBlack,
  cGrafWhite,
  cGrafRed,
  cGrafGreen,
  cGrafBlue,
  cGrafCyan,
  cGrafMagenta,
  cGrafYellow:
 fDefGraph := colors[aCmdNumber -
 cGrafBlack + 1];
 cAxisBlack,
  cAxisWhite,
  cAxisRed,
  cAxisGreen,
  cAxisBlue,
  cAxisCyan,
  cAxisMagenta,
  cAxisYellow:
   fDefAxis := colors[aCmdNumber -
 cAxisBlack + 1];
 cBackBlack,
  cBackWhite,
  cBackRed,
  cBackGreen,
  cBackBlue,
  cBackCyan,
  cBackMagenta,
  cBackYellow:
   fDefBack := colors[aCmdNumber -
 cBackBlack + 1];
 cPrintWS,
  cPrintPS:
   fPrintOpt := aCmdNumber -
 cPrintWS + 1;
 OTHERWISE
 DoMenuCommand := INHERITED
 DoMenuCommand(aCmdNumber);
 END;   { case }
END;    { TQPlotApplication.DoMenuCommand }
{------------------------------------------------}
PROCEDURE DrawBox(wPtr: WindowPtr; itemNum: INTEGER);
(*
 * This procedure is the UserItem proc that
 * gets called for the about box.
 *)
VAR
 ityp:  INTEGER;
 itemHdl: Handle;
 tRect: Rect;
BEGIN
 GetDItem(DialogPtr(wPtr), 5, ityp, itemHdl, tRect);
 FrameRect(tRect);
END;    { DrawBox }
{------------------------------------------------}
PROCEDURE TQPlotApplication.ShowAboutApp;
(*
 * Show our about box.  This version is almost
 * identical to the original, except for the
 * addition of some stuff about MacApp
 * (incidentally, this is required by the license
 * agreement for programs developed with MacApp!)
 *)
VAR
 idStrHandle:    StringHandle;
 freeSpace: Size;
 myHeapSpace:    LongInt;
 tempStr1:Str255;
 tempStr2:Str255;
 tempStr3:Str255;
 diaPtr:DialogPtr;
 itemHit: INTEGER;
 
 ityp:  INTEGER;
 itemHdl: Handle;
 tRect: Rect;
BEGIN
 idStrHandle :=
     StringHandle(GetResource(kSignature, 0));
 FailNIL(idStrHandle);

 MoveHHi(Handle(idStrHandle));
 HLock(Handle(idStrHandle));
 
 freeSpace := FreeMem;
 myHeapSpace := MaxMem(freeSpace);
 NumToString(myHeapSpace, tempStr2);
 tempStr2 := concat(‘Memory = ‘, tempStr2);
 tempStr3 := ‘’;
 tempStr1 := ‘’;
 ParamText(idStrHandle^^, tempStr1, tempStr2, tempStr3);
 diaPtr := GetNewDialog(kAboutDLOG, NIL, Pointer(-1));
 FailNIL(diaPtr);
 GetDItem(diaPtr, 5, ityp, itemHdl, tRect);
 SetDItem(diaPtr, 5, ityp, Handle(@DrawBox), tRect);

 InitCursor;
 ModalDialog(NIL, itemHit);
 DisposDialog(diaPtr);

 HUnlock(Handle(idStrHandle));
END;    { TQPlotApplication.ShowAboutApp }
{------------------------------------------------}
{--------  QPlot Document Methods  ------------}
{------------------------------------------------}
PROCEDURE TQPlotDocument.IQPlotDocument
 (itsFileType, itsCreator: OSType;
 usesDataFork, usesRsrcFork: BOOLEAN;
 keepsDataOpen, keepsRsrcOpen:
 BOOLEAN);
(*
 * Initialize the QPlot document.  For our
 * document, this means that we will present the
 * dialog box that asks for the quadratic
 * parameters, and we’ll solve the equation while
 * we’re here.
 *)
VAR
 x1, x2:REAL;
BEGIN
 IDocument(itsFileType, itsCreator, usesDataFork, usesRsrcFork, keepsDataOpen, 
keepsRsrcOpen);
 
 PosePlotDialog;
 fResult := SolveIt(fAParam, fBParam,
 fCParam, x1, x2);
 IF (fResult<>-1) THEN
 BEGIN
 fRoot1 := x1;
 fRoot2 := x2;
 END
 ELSE
 BEGIN
 fRoot1 := -999;
 fRoot2 := -999
 END;
 fPlotView := NIL;
END;    { TQPlotDocument.IQPlotDocument }
{------------------------------------------------}
PROCEDURE TQPlotDocument.DoMakeWindows; OVERRIDE;
(*
 * This procedure is called when we have to
 * make a new document (and its associated
 * window).  We just get a simple window and shove
 * it on the screen.
 *)
VAR
 aWindow: TWindow;
BEGIN
 aWindow := NewSimpleWindow(kPlotWindowID,
 kWantHScrollBar, kWantVScrollBar, SELF, fPlotView);
 aWindow.SimpleStagger(kStaggerAmt,
 kStaggerAmt, gStaggerCount);
END;    { TQPlotDocument.DoMakeWindows }
{------------------------------------------------}
PROCEDURE TQPlotDocument.DoMakeViews
 (forPrinting: BOOLEAN); OVERRIDE;
(*
 * This procedure is called when we are making
 * a new document.  It creates all views that are
 * needed.  In our case, it’s only one.  We then
 * initialize the view.
 *)
VAR
 plotApp: TQPlotApplication;
 aQPlotView:TQPlotView;
 aHandler:TStdPrintHandler;
 tRect: Rect;
BEGIN
 plotApp := TQPlotApplication(gApplication);
 
 NEW(aQPlotView);
 FailNIL(aQPlotView);
 aQPlotView.IQPlotView(SELF,
 plotApp.fDefGraph, plotApp.fDefAxis,
 plotApp.fDefBack);
 
 fPlotView := aQPlotView;
(*
 * Now make the view printable by creating a
 * print handler.
 *)
 IF NOT(forPrinting) THEN
 BEGIN
 New(aHandler);
 FailNIL(aHandler);
 aHandler.IStdPrintHandler(SELF,
 aQPlotView, FALSE, TRUE, TRUE);
 { set up for 1/2" margins }
 SetRect(tRect,35,35,-35,-35);
 aHandler.InstallMargins(tRect, FALSE);
 END;
END;    { TQPlotDocument.DoMakeViews }
{------------------------------------------------}
PROCEDURE TQPlotDocument.PosePlotDialog;
(*
 * This procedure puts up the dialog that
 * requests the quadratic parameters.
 *)
 
 FUNCTION CvtEditReal(aText: TEditText):
 Real;
 VAR
 tempStr: Str255;
 BEGIN
 aText.GetText(tempStr);
 CvtEditReal := String2Real(tempStr);
 END;   { CvtEditReal }
 
 FUNCTION CvtEditInt(aText: TEditText):
 INTEGER;
 VAR
 tempStr: Str255;
 tempLong:LongInt;
 BEGIN
 aText.GetText(tempStr);
 StringToNum(tempStr, tempLong);
 CvtEditInt := tempLong;
 END;   { CvtEditInt }
VAR
 aWindow: TWindow;
 dismisser: IDType;
 
 aQPlotView:TQPlotView;
 dView: TDialogView;
 anEditText:TEditText;
 aVal:  TEditText;
 bVal:  TEditText;
 cVal:  TEditText;
 stepVal: TEditText;
 xVal:  TEditText;
 yVal:  TEditText;
 
 tempStr: Str255;
BEGIN
(*
 * First make our calls (which never get
 * executed) to tell the linker we want to create
 * these types of objects.
 *)
 IF gCreateWithTemplates THEN 
 BEGIN  
 NEW(aQPlotView);
 NEW(dView);
 NEW(anEditText);
 END;
(*
 * Get the dialog window and find the dialog subview.
 *)
 aWindow := NewTemplateWindow(kPlotDLOG, NIL);
 dView := TDialogView(aWindow.
 FindSubView(kPlotID));
(*
 * Retrieve references to each of the edit
 * text items.  We will need to reference them
 * later to get their values.
 *)
 aVal := TEditText(dView.FindSubView(‘a   ‘));
 bVal := TEditText(dView.FindSubView(‘b   ‘));
 cVal := TEditText(dView.FindSubView(‘c   ‘));
 stepVal := TEditText(dView.FindSubView(‘step’));
 xVal := TEditText(dView.FindSubView(‘xscl’));
 yVal := TEditText(dView.FindSubView(‘yscl’));

 dView.SelectEditText(‘a   ‘, kRedraw);
 
 dismisser := dView.PoseModally;
(*
 * Now that we have the values, convert them
 * to numbers and plug them into the quadratic
 * equation solver.  Note that we don’t test to
 * see if the OK button was pressed, because in
 * this dialog, you can’t exit except by saying
 * OK.
 *)
 fAParam := CvtEditReal(aVal);
 fBParam := CvtEditReal(bVal);
 fCParam := CvtEditReal(cVal);
 fStep := CvtEditReal(stepVal);
 fXScale := CvtEditInt(xVal);
 fYScale := CvtEditInt(yVal);

 aWindow.Close;
END;    { TQPlotDocument.PosePlotDialog }
{------------------------------------------------}
PROCEDURE TQPlotDocument.Quad(a, b, c : REAL;
 VAR x1, x2 : REAL;
 VAR result : INTEGER);
(*
 * This procedure is identical to the one
 * written in ‘vanilla’ Pascal
 *)
 VAR  check :  real;
 
 FUNCTION PositiveCalc
 (a, b, check : real) : real;
 BEGIN
 PositiveCalc := (-b + sqrt(check)) /
 (2 * a);
 END;   { PositiveCalc ---------- }
 
 FUNCTION NegativeCalc
 (a, b, check : real) : real;
 BEGIN
 NegativeCalc := (-b - sqrt(check)) /
 (2 * a);
 END;   { NegativeCalc ---------- }

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;    { TQPlotDocument.Quad }
{------------------------------------------------}
FUNCTION TQPlotDocument.SolveIt(a, b, c: REAL;
 VAR x1, x2: REAL): INTEGER;
(*
 * This function is identical to the one
 * written for the original program.
 *)
VAR
 result:INTEGER;
BEGIN
 IF (a <> 0) THEN
 quad(a, b, c, x1, x2, result)
 ELSE
 result := -1;
 SolveIt := result;
END;    { TQPlotDocument.SolveIt }
{------------------------------------------------}
PROCEDURE TQPlotDocument.DoNeedDiskSpace
 (VAR dataForkBytes,
 rsrcForkBytes: LONGINT); OVERRIDE;
(*
 * This procedure calculates the amount of
 * disk space we need to store our document on
 * disk.  In our case, it’s just the size of the
 * drawing since no additional information is
 * stored in our file.
 *)
BEGIN
 INHERITED DoNeedDiskSpace(dataForkBytes, rsrcForkBytes);
 
 dataForkBytes := dataForkBytes +
 512 { header } +
 GetHandleSize(Handle(fPlotView.fDrawing));
END;    { TQPlotDocument.DoNeedDiskSpace }
{------------------------------------------------}
PROCEDURE TQPlotDocument.DoWrite(aRefNum: INTEGER;
 makingCopy: BOOLEAN); OVERRIDE;
(*
 * This procedure is called to write the data
 * onto the disk.
 *)
VAR
 count: LongInt;
 buffer:ARRAY [1..256] OF INTEGER;
 pHdl:  PicHandle;
 i:INTEGER;
 err:   OSErr;
BEGIN
 INHERITED DoWrite(aRefNum, makingCopy);
(*
 * Now write the blank 512 byte header needed
 * for PICT files.
 *)
 FOR i:= 1 TO 256 DO
 buffer[i] := 0;
 
 count := 512;
 err := FSWrite(aRefNum, count, @buffer);
 IF ((err<>noErr) OR (count<>512)) THEN
 SysBeep(10);  { @@@ error alert }
 
 pHdl := fPlotView.fDrawing;
 HLock(Handle(pHdl));
 count := GetHandleSize(Handle(pHdl));
 err := FSWrite(aRefNum, count, Ptr(pHdl^));
 HUnlock(Handle(pHdl));
 IF ((err<>noErr) OR
     (count <> GetHandleSize(Handle(pHdl)))) THEN
 SysBeep(10);  { @@@ error alert }
END;    { TQPlotDocument.DoWrite }
{------------------------------------------------}
{----------  QPlot View Methods  ----------------}
{------------------------------------------------}
PROCEDURE TQPlotView.IQPlotView(theDoc:
 TQPlotDocument; theGrafColor,
 theAxisColor, theBackColor: INTEGER);
(*
 * This procedure is called to initialize a
 * QPlot view.  It sets the view’s variables to
 * good initial values.
 *)
VAR
 vOrigin: VPoint;
 vSize: VPoint;
 tempPort:GrafPtr;
BEGIN
 SetVPt(vOrigin, 0, 0);
 SetVPt(vSize, 600, 400);

 IView(theDoc, NIL, vOrigin, vSize, sizeVariable, sizeVariable);
 fPlotDoc := theDoc;

 fDrawing := NIL;
 fOnePage := FALSE;
 END;   { TQPlotView.IQPlotView }
{------------------------------------------------}
PROCEDURE TQPlotView.Free; OVERRIDE;
(*
 * This procedure is called when the view is
 * finished, and we are cleaning up any space we
 * have allocated.  We just dispose of the picture
 * handle.
 *)
BEGIN
 KillPicture(fDrawing);
 INHERITED Free;
END;    { TQPlotView.Free }
{------------------------------------------------}
PROCEDURE TQPlotView.CalcMinSize
 (VAR minSize: VPoint); OVERRIDE;
(*
 * This procedure is called to calculate the
 * minimum size of the view.  It is called
 * initially when the view is being created, and
 * later on when we tell the view to recalculate
 * its view size.
 *)
VAR
 vSize: Point;
 tWind: TWindow;
 tRect: Rect;
BEGIN
 INHERITED CalcMinSize(minSize);
 IF fOnePage THEN
 BEGIN
 minSize := fPrintHandler.fViewPerPage;
 END
 ELSE
 BEGIN
 IF (fSuperView<>NIL) THEN
 minSize := fSuperView.fSize
 ELSE
 BEGIN
 vSize := Point(0);
 IF SELF.Focus THEN ;
 QDToViewPt(vSize, minSize);
 END;
 END;
END;    { TQPlotView.CalcMinSize }
{------------------------------------------------}
PROCEDURE TQPlotView.DoSetupMenus; OVERRIDE;
(*
 * This procedure is called to enable menu
 * items that pertain to the view.
 *)
BEGIN
 INHERITED DoSetupMenus;

 EnableCheck(cPrintWS, TRUE, NOT fOnePage);
 EnableCheck(cPrintPS, TRUE, fOnePage);
END;    { TQPlotView.DoSetupMenus }
{------------------------------------------------}
FUNCTION TQPlotView.DoMenuCommand
 (aCmdNumber: CmdNumber): TCommand;
 OVERRIDE;
(*
 * This function is called to handle menu
 * commands that pertain to the view.
 *)
VAR
 tempVPt: VPoint;
 tRect: Rect;
BEGIN
 DoMenuCommand := gNoChanges;
 IF (aCmdNumber = cPrintWS) OR
    (aCmdNumber = cPrintPS) THEN
 BEGIN
 fOnePage := (aCmdNumber=cPrintPS);
 AdjustSize;
 END
 ELSE
 DoMenuCommand :=
   INHERITED DoMenuCommand(aCmdNumber);
END;    { TQPlotView.DoMenuCommand }
{------------------------------------------------}
PROCEDURE TQPlotView.PrQDStuff(pRect : rect;
 QDdevice : integer);
(*
 * This is the main drawing procedure for the
 * view.  It is (almost) unchanged from the
 * original version.  Since in MacApp you don’t
 * know who you’re drawing for (Display vs.
 * LaserWriter) most of the display-specific code
 * has been deleted.  Drawing still works
 * correctly, since we erase the invalid
 * areas before we draw it.
 *)
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;
 
 TextFont(geneva);
 TextSize(10);
 TextFace([]);
 
 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;
 WITH fPlotDoc DO
 BEGIN
 x := -fXScale / 2;
 y := fAParam * x * x + (fBParam * x)
 + fCParam;
 hPos := INTEGER(ROUND(x * hor * 2 / fXScale + hor));
 vPos := INTEGER(round(-y * ver * 2 / fYScale + ver));
 z1 := -fBParam / (2 * fAParam);
 z2 := (4 * fAParam * fCParam -
 (fBParam * fBParam)) / (4 * fAParam);
 END;
 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}
 WITH fPlotDoc DO
 BEGIN
 str1 := Int2Str(-fXScale DIV 2);
 str2 := Int2Str(fYScale DIV 2);
 str3 := Int2Str(fXScale DIV 2);
 str4 := Int2Str(-fYScale DIV 2);
 
 Paragraph[1] := CONCAT(
 ‘y=ax^2 + bx + c’, crString);
 Paragraph[2] := CONCAT(‘a=’,
 Real2String(fAParam,1),
 ‘, b=’,
 Real2String(fBParam,1),
 ‘, c=’,
 Real2String(fCParam,1),
 crString);
 Paragraph[3] := CONCAT(‘x1=’,
 Real2String(fRoot1,2),
 ‘, x2=’,
 Real2String(fRoot2,2),
 crString);
 END;
 
 CASE fPlotDoc.fResult OF
 1 : 
 Paragraph[4] :=
 CONCAT(
   ‘Two Real Roots, x1, x2’, 
 crString);
 2 : 
 Paragraph[4] :=
 CONCAT(‘Double Root’,
 crString);
 3 : 
 Paragraph[4] :=
 CONCAT(‘Two Complex Roots ‘,
 crString);
 OTHERWISE
 ;
 END;
 Paragraph[5] := CONCAT(‘Slope 0 = (‘,
 Real2String(z1, 1),
 ‘,’,Real2String(z2,1), ‘)’,
 crString);

 PenNormal;
 BackColor(TQPlotApplication(gApplication).
 fDefBack);
 ForeColor(TQPlotApplication(gApplication).
 fDefAxis);

{Drawing Boundary}
{Begin MacDraw Document}
 PicComment(picDwgBeg, 0, NIL);

 PicComment(picGrpBeg, 0, NIL);
 PicComment(SetLineWidth,
 GetHandleSize(Handle(Width)),
 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(TQPlotApplication(gApplication).
 fDefGraph);

{Plot Itsef}
 PicComment(picGrpBeg, 0, NIL);
 moveto(hPos, vPos);
 WITH fPlotDoc DO
 REPEAT
 x := x + fStep;
 y := fAParam * x * x + (fBParam * x) + fCParam;
 hPos := integer(round(x * hor * 2 / fXScale + hor));
 vPos := integer(round(-y * ver *  2 / fYScale + 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 >= fXScale / 2;
 PicComment(picGrpEnd, 0, NIL);

 ForeColor(Colors[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,
 GetHandleSize(Handle(Width)),
 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 sel. all}
 picComment(picDwgEnd, 0, NIL); {of drawing}

 SetClip(SaveClip);
 disposHandle(handle(width));
 DisposeRgn(TextClipRgn);
 DisposeRgn(SaveClip);
END;    { TQPlotView.PrQDStuff }
{------------------------------------------------}
PROCEDURE TQPlotView.SuperViewChangedSize
 (delta: VPoint; invalidate: BOOLEAN);
 OVERRIDE;
(*
 * This procedure changes the view size when
 * the window is resized.
 *)
BEGIN
(*
 * We only need to go through these
 * shenanigans if we are NOT displaying a page-
 * sized picture.  This resizes the view’s extent
 * rectangle and invalidates the area, forcing the
 * view to redraw the picture in the new size.
 *)
 IF NOT(fOnePage) THEN
 BEGIN
 AdjustSize;
 ForceRedraw;
 END;
END;    { TQPlotView.SuperViewChangedSize }
{------------------------------------------------}
PROCEDURE TQPlotView.Resize (width,
 height: VCoordinate; invalidate:
 BOOLEAN); OVERRIDE;
(*
 * This procedure is called from AdjustSize.
 * It is here because when we toggle between Page
 * Size and Window Size plots, we need to tell the
 * view to redraw itself (because it changed size,
 * even though the window didn’t).
 *)
BEGIN
 ForceRedraw;
 INHERITED Resize(width, height, FALSE);
 ForceRedraw;
END;    { TQPlotView.Resize }
{------------------------------------------------}
PROCEDURE TQPlotView.Draw(area: Rect); OVERRIDE;
(*
 * This procedure is called to draw the view
 * when it needs to be drawn.  The picture we
 * created before is ALWAYS drawn to take 
 * up the entire window.
 *)
VAR
 tRect: Rect;
BEGIN

 GetQDExtent(tRect); { always draw pict to
 fill entire extent of the view }
 EraseRect(tRect);
 IF (fDrawing=NIL) THEN
 BEGIN
 fDrawing := OpenPicture(tRect);
 PrQDStuff(tRect, 1);
 ClosePicture;
 PenNormal;
 END;
 DrawPicture(fDrawing, tRect);
END;    { TQPlotView.Draw }

{--------------------------------------------}
{------------ File UQPlot.r ----------------}
{--------------------------------------------}
/* Copyright © 1989 by Charles F. McMath.
 All rights reserved. */

#ifdef Debugging
include “Debug.rsrc”;
#endif
include “MacApp.rsrc”;
include “Printing.rsrc”;
include “Dialog.rsrc”;

include “QPlot” ‘CODE’;

resource ‘BNDL’ (128) {
 ‘FGT3’,
 0,
 { ‘ICN#’,
 { 0, 128, 1, 129 },
 ‘FREF’,
 {0, 128, 1, 129 }
 }
};

resource ‘FREF’ (128) {
 ‘APPL’, 0, “”
};

resource ‘FREF’ (129) {
 ‘PICT’, 1, “”
};

type ‘FGT3’ as ‘STR ‘;

resource ‘FGT3’ (0) {
 “© by Dave Kelly & Dave Smith \nver”
 “4 JAN 1988;”
 “ MacApp version by Chuck McMath”
};

resource ‘WIND’ (1001, purgeable) {
 {45, 15, 445, 615},
 zoomDocProc,
 invisible,
 goAway,
 0x0,
 “<<<>>>”
};

resource ‘view’ (1001, purgeable) {
 {
 root, ‘WIND’, { 50, 20 }, { 260, 430 },
 sizeVariable, sizeVariable, shown,
 enabled,
 Window { “TWindow”, zoomDocProc,
 goAwayBox, resizable,
 modeless,
 ignoreFirstClick,
 freeOnClosing,
 disposeOnFree,
 closesDocument,
 openWithDocument,
 dontAdaptToScreen,
 stagger, forceOnScreen,
 dontCenter, ‘QPLT’, “” };
 ‘WIND’, ‘SCLR’, { 0, 0 },
 { 260-kSBarSizeMinus1,
   430-kSBarSizeMinus1 },
 sizeRelSuperView,
 sizeRelSuperView,
 shown, enabled,
 Scroller { “TScroller”,
 vertScrollBar,
 horzScrollBar,
 0, 0, 16, 16,
 vertConstrain,
 horzConstrain,
 { 0, 0, 0, 0 } };
 ‘SCLR’,IncludeViews { 1002 }
 }
};

resource ‘view’ (1002, purgeable) {
 {
 root, ‘QPLT’,
 { 0, 0 }, { 134, 414 },
 sizeFixed, sizeFixed,
 shown, enabled,
 View { “TQPlotView”}
 }
};

resource ‘view’ (2000, purgeable) {
 { /* array viewArray: 15 elements */
 root, noID,
 { 100, 105 }, { 150, 300 },
 sizeVariable, sizeVariable,
 notShown, enabled,
 Window {
 “TWindow”,
 documentProc,
 noGoAwayBox,
 notResizable,
 modal,
 ignoreFirstClick,
 freeOnClosing,
 disposeOnFree,
 doesntCloseDocument,
 dontOpenWithDocument,
 dontAdaptToScreen,
 dontStagger,
 dontForceOnScreen,
 center,
 noID,
 “Plot Parameters”
 },
 /* [2] */
 root, ‘PPRM’,
 {0, 0},{150, 300}, sizeVariable,
 sizeVariable, shown, disabled,
 DialogView { “TDialogView”, ‘ok  ‘,
 noID },
 /* [3] */
 ‘PPRM’, ‘ok  ‘,
 {110, 230}, {26, 45}, sizeFixed,
 sizeFixed, shown, enabled,
 Button {
 “TButton”,
 0b0,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 dismisses,
 {0, 0, 0, 0},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 “OK”
 },
 /* [4] */
 ‘PPRM’, ‘a   ‘,
 {30, 15},{20, 45},
 sizeFixed, sizeFixed, 
 shown, enabled,
 EditText {
 “TEditText”,
 0b1111,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {2, 2, 2, 2},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “1”,
 unlimited,
 0b1111000000000
0000000000100000000
 },
 /* [5] */
 ‘PPRM’, ‘b   ‘,
 {30, 100},{20, 45}, sizeFixed,
 sizeFixed, shown, enabled,
 EditText {
 “TEditText”,
 0b1111,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {2, 2, 2, 2},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “-1”,
 unlimited,
 0b111100000000000
00000000100000000
 },
 /* [6] */
 ‘PPRM’, ‘c   ‘,
 {30, 180},{20, 45}, sizeFixed,
 sizeFixed, shown, enabled,
 EditText {
 “TEditText”,
 0b1111,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {2, 2, 2, 2},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “-6”,
 unlimited,
 0b1111000000000000000
0000100000000
 },
 /* [7] */
 ‘PPRM’, ‘step’,
 {80, 10},{20, 55}, sizeFixed,
 sizeFixed, shown, enabled,
 EditText {
 “TEditText”,
 0b1111,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {2, 2, 2, 2},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “.05”,
 unlimited,
 0b11110000000000000000
000100000000
 },
 /* [8] */
 ‘PPRM’, ‘xscl’,
 {80, 100},{20, 50}, sizeFixed,
 sizeFixed, shown, enabled,
 EditText {
 “TEditText”,
 0b1111,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {2, 2, 2, 2},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “10”,
 unlimited,
 0b1111000000000000000
0000100000000
 },
 /* [9] */
 ‘PPRM’, ‘yscl’,
 {80, 185},{20, 50}, sizeFixed,
 sizeFixed, shown, enabled,
 EditText {
 “TEditText”,
 0b1111,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {2, 2, 2, 2},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “20”,
 unlimited,
 0b111100000000000000000
00100000000
 },
 /* [10] */
 ‘PPRM’, ‘alab’,
 {10, 35},{16, 20},
 sizeFixed, sizeFixed, 
 shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {0, 0, 0, 0},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “a”
 },
 /* [11] */
 ‘PPRM’, ‘blab’,
 {10, 120},{16, 20}, sizeFixed,
 sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {0, 0, 0, 0},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “b”
 },
 /* [12] */
 ‘PPRM’, ‘clab’,
 {10, 200},{16, 20}, sizeFixed,
 sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {0, 0, 0, 0},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “c”
 },
 /* [13] */
 ‘PPRM’, ‘slab’,
 {60, 10},{16, 55},
 sizeFixed, sizeFixed, 
 shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {0, 0, 0, 0},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “step size”
 },
 /* [14] */
 ‘PPRM’, ‘xlab’,
 {60, 95},{16, 55},
 sizeFixed, sizeFixed, 
 shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {0, 0, 0, 0},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “x scale”
 },
 /* [15] */
 ‘PPRM’, ‘ylab’,
 {60, 180},{16, 70}, sizeFixed,
 sizeFixed, shown, disabled,
 StaticText {
 “TStaticText”,
 0b0,
 {1, 1},
 sizeable,
 notDimmed,
 notHilited,
 doesntDismiss,
 {0, 0, 0, 0},
 plain,
 0,
 {0x0,0x0,0x0},
 “”,
 justLeft,
 “y scale”
 }
 }
};

resource ‘SIZE’ (-1) {
 dontSaveScreen,
 acceptSuspendResumeEvents,
 enableOptionSwitch,
 canBackground,
 MultiFinderAware,
 backgroundAndForeground,
 dontGetFrontClicks,
 ignoreChildDiedEvents,
 is32BitCompatible,
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
#if qDebug
 275 * 1024,
 200 * 1024
#else
 (250-32) * 1024,
 (175-32) * 1024
#endif
};

resource ‘DLOG’ (1024) {
 {100, 100, 318, 416},
 dBoxProc,
 -1,
 noGoAway,
 0x0,
 1024,
 “About Plotter ”
};

resource ‘DITL’ (1024, purgeable) {
 { /* array DITLarray: 5 elements */
 /* [1] */
 {112, 235, 141, 284},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {10, 88, 141, 289},
 StaticText {
 disabled,
 “Plot Demo\n\nGraphs “
 “Quadratic Equations\n^0”
 “\n^1\n^2\n^3”
 },
 /* [3] */
 {10, 10, 96, 81},
 Picture {
 disabled,
 128
 },
 /* [4] */
 {154, 22, 208, 283},
 StaticText {
 disabled,
 “This application brought”
 “ to you courtesy”
 “ of MacApp® 2.0.”
 “ Copyright “1985-1988”
 “ Apple Computer, Inc.”
 },
 /* [5] */
 {149, 17, 211, 290},
 UserItem {
 disabled
 }
 }
};

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

resource ‘cmnu’ (2) {
 2,
 textMenuProc,
 allEnabled,
 enabled,
 “File”,
  {/* array: 8 elements */
 /* [1] */
 “Plot ”, noIcon, “P”, noMark, plain, cNew;
 /* [2] */
 “-”, noIcon, noKey, noMark, plain, nocommand;
 /* [3] */
 “Save”, noIcon, “S”, noMark, plain, cSave;
 /* [4] */
 “Save As ”, noIcon, noKey, noMark, plain,
 cSaveAs;
 /* [5] */
 “Page Setup ”, noIcon, “U”, noMark, plain,
 cPageSetup;
 /* [6] */
 “Print ”, noIcon, “O”, noMark, plain, cPrint;
 /* [7] */
 “-”, noIcon, noKey, noMark, plain, nocommand;
 /* [8] */
 “Quit”, noIcon, “Q”, noMark, plain, cQuit
 }
};

resource ‘cmnu’ (3) {
 3,
 textMenuProc,
 allEnabled,
 enabled,
 “Edit”,
  {/* array: 6 elements */
 /* [1] */
 “Undo”, noIcon, “Z”, noMark, plain, cUndo;
 /* [2] */
 “-”, noIcon, noKey, noMark, plain, nocommand;
 /* [3] */
 “Cut”, noIcon, “X”, noMark, plain, cCut;
 /* [4] */
 “Copy”, noIcon, “C”, noMark, plain, cCopy;
 /* [5] */
 “Paste”, noIcon, “V”, noMark, plain, cPaste;
 /* [6] */
 “Clear”, noIcon, noKey, noMark, plain, cClear
 }
};

resource ‘cmnu’ (4) {
 4,
 textMenuProc,
 allEnabled,
 enabled,
 “Graph”,
  {/* array: 3 elements */
 /* [1] */
 “Graph”, noIcon, “\0x1B”, “\0x0A”, plain,
 1201;
 /* [2] */
 “Axis”, noIcon, “\0x1B”, “\0x0B”, plain, 1202;
 /* [3] */
 “Background”, noIcon, “\0x1B”, “\0x0C”, plain,
 1203
 }
};

resource ‘cmnu’ (5) {
 5,
 textMenuProc,
 allEnabled,
 enabled,
 “Print Options”,
  {/* array: 2 elements */
 /* [1] */
 “Window Size”, noIcon, “[“, noMark, plain,
 1301;
 /* [2] */
 “Page Size”, noIcon, “]”, noMark, plain, 1302
 }
};

resource ‘cmnu’ (10) {
 10,
 textMenuProc,
 allEnabled,
 enabled,
 “Graph Colors”,
  {/* array: 8 elements */
 /* [1] */
 “Black”, noIcon, noKey, noMark, plain, 10001;
 /* [2] */
 “White”, noIcon, noKey, noMark, plain, 10002;
 /* [3] */
 “Red”, noIcon, noKey, noMark, plain, 10003;
 /* [4] */
 “Green”, noIcon, noKey, noMark, plain, 10004;
 /* [5] */
 “Blue”, noIcon, noKey, noMark, plain, 10005;
 /* [6] */
 “Cyan”, noIcon, noKey, noMark, plain, 10006;
 /* [7] */
 “Magenta”, noIcon, noKey, noMark, plain,
 10007;
 /* [8] */
 “Yellow”, noIcon, noKey, noMark, plain, 10008
 }
};

resource ‘cmnu’ (11) {
 11,
 textMenuProc,
 allEnabled,
 enabled,
 “Axis Colors”,
  {/* array: 8 elements */
 /* [1] */
 “Black”, noIcon, noKey, noMark, plain, 11001;
 /* [2] */
 “White”, noIcon, noKey, noMark, plain, 11002;
 /* [3] */
 “Red”, noIcon, noKey, noMark, plain, 11003;
 /* [4] */
 “Green”, noIcon, noKey, noMark, plain, 11004;
 /* [5] */
 “Blue”, noIcon, noKey, noMark, plain, 11005;
 /* [6] */
 “Cyan”, noIcon, noKey, noMark, plain, 11006;
 /* [7] */
 “Magenta”, noIcon, noKey, noMark, plain,
 11007;
 /* [8] */
 “Yellow”, noIcon, noKey, noMark, plain, 11008
 }
};

resource ‘cmnu’ (12) {
 12,
 textMenuProc,
 allEnabled,
 enabled,
 “Background Colors”,
  {/* array: 8 elements */
 /* [1] */
 “Black”, noIcon, noKey, noMark, plain, 12001;
 /* [2] */
 “White”, noIcon, noKey, noMark, plain, 12002;
 /* [3] */
 “Red”, noIcon, noKey, noMark, plain, 12003;
 /* [4] */
 “Green”, noIcon, noKey, noMark, plain, 12004;
 /* [5] */
 “Blue”, noIcon, noKey, noMark, plain, 12005;
 /* [6] */
 “Cyan”, noIcon, noKey, noMark, plain, 12006;
 /* [7] */
 “Magenta”, noIcon, noKey, noMark, plain,
 12007;
 /* [8] */
 “Yellow”, noIcon, noKey, noMark, plain, 12008
 }
};

resource ‘cmnu’ (128) {
 128,
 textMenuProc,
 allEnabled,
 enabled,
 “Buzzwords”,
  {/* array: 1 elements */
 /* [1] */
 “Page Setup Change”, noIcon, noKey, noMark,
 plain, cChangePrinterStyle
 }
};

resource ‘MBAR’ (128) {
 {1; 2; 3; 4; 5}
};

resource ‘MBAR’ (130) {
 {10; 11; 12}
};

resource ‘mctb’ (0) {
 {0, 0,
 { /* array: 4 elements */
 0, 0, 0,
 65535, 65535, 65535,
 65535, 0, 65535,
 65535, 65535, 65535
 }
 }
};

resource ‘mctb’ (1) {
 {1, 0,
 /* [1] */
 { /* array: 4 elements */
 0, 65535, 65535,
 65535, 65535, 65535,
 65535, 0, 0,
 65535, 65535, 65535
 },
 /* [2] */
 1, 1,
 { /* array: 4 elements */
 0, 0, 65535,
 0, 0, 65535,
 0, 0, 65535,
 65535, 65535, 65535
 },
 /* [3] */
 1, 2,
 { /* array: 4 elements */
 0, 0, 65535,
 0, 0, 65535,
 0, 0, 65535,
 65535, 65535, 65535
 }
 }
};

resource ‘mctb’ (10) {
 {10, 1,
 { /* array: 4 elements */
 0, 0, 0,
 0, 0, 0,
 0, 0, 0,
 65535, 65535, 65535
 },
 /* [2] */
 10, 2,
 { /* array: 4 elements */
 0, 0, 0,
 0, 0, 0,
 0, 0, 0,
 65535, 65535, 65535
 },
 /* [3] */
 10, 3,
 { /* array: 4 elements */
 65535, 0, 0,
 65535, 0, 0,
 65535, 0, 0,
 65535, 65535, 65535
 },
 /* [4] */
 10, 4,
 { /* array: 4 elements */
 0, 65535, 0,
 0, 65535, 0,
 0, 65535, 0,
 65535, 65535, 65535
 },
 /* [5] */
 10, 5,
 { /* array: 4 elements */
 0, 0, 65535,
 0, 0, 65535,
 0, 0, 65535,
 65535, 65535, 65535
 },
 /* [6] */
 10, 6,
 { /* array: 4 elements */
 0, 65535, 65535,
 0, 65535, 65535,
 0, 65535, 65535,
 65535, 65535, 65535
 },
 /* [7] */
 10, 7,
 { /* array: 4 elements */
 65535, 0, 65535,
 65535, 0, 65535,
 65535, 0, 65535,
 65535, 65535, 65535
 },
 /* [8] */
 10, 8,
 { /* array: 4 elements */
 65535, 65535, 0,
 65535, 65535, 0,
 65535, 65535, 0,
 65535, 65535, 65535
 }
 }
};

resource ‘mctb’ (11) {
 { /* array MCTBArray: 8 elements */
 /* [1] */
 11, 1,
 { /* array: 4 elements */
 0, 0, 0,
 0, 0, 0,
 0, 0, 0,
 65535, 65535, 65535
 },
 /* [2] */
 11, 2,
 { /* array: 4 elements */
 0, 0, 0,
 0, 0, 0,
 0, 0, 0,
 65535, 65535, 65535
 },
 /* [3] */
 11, 3,
 { /* array: 4 elements */
 65535, 0, 0,
 65535, 0, 0,
 65535, 0, 0,
 65535, 65535, 65535
 },
 /* [4] */
 11, 4,
 { /* array: 4 elements */
 0, 65535, 0,
 0, 65535, 0,
 0, 65535, 0,
 65535, 65535, 65535
 },
 /* [5] */
 11, 5,
 { /* array: 4 elements */
 0, 0, 65535,
 0, 0, 65535,
 0, 0, 65535,
 65535, 65535, 65535
 },
 /* [6] */
 11, 6,
 { /* array: 4 elements */
 0, 65535, 65535,
 0, 65535, 65535,
 0, 65535, 65535,
 65535, 65535, 65535
 },
 /* [7] */
 11, 7,
 { /* array: 4 elements */
 65535, 0, 65535,
 65535, 0, 65535,
 65535, 0, 65535,
 65535, 65535, 65535
 },
 /* [8] */
 11, 8,
 { /* array: 4 elements */
 65535, 65535, 0,
 65535, 65535, 0,
 65535, 65535, 0,
 65535, 65535, 65535
 }
 }
};

resource ‘mctb’ (12) {
 { /* array MCTBArray: 8 elements */
 /* [1] */
 12, 1,
 { /* array: 4 elements */
 0, 0, 0,
 0, 0, 0,
 0, 0, 0,
 65535, 65535, 65535
 },
 /* [2] */
 12, 2,
 { /* array: 4 elements */
 0, 0, 0,
 0, 0, 0,
 0, 0, 0,
 65535, 65535, 65535
 },
 /* [3] */
 12, 3,
 { /* array: 4 elements */
 65535, 0, 0,
 65535, 0, 0,
 65535, 0, 0,
 65535, 65535, 65535
 },
 /* [4] */
 12, 4,
 { /* array: 4 elements */
 0, 65535, 0,
 0, 65535, 0,
 0, 65535, 0,
 65535, 65535, 65535
 },
 /* [5] */
 12, 5,
 { /* array: 4 elements */
 0, 0, 65535,
 0, 0, 65535,
 0, 0, 65535,
 65535, 65535, 65535
 },
 /* [6] */
 12, 6,
 { /* array: 4 elements */
 0, 65535, 65535,
 0, 65535, 65535,
 0, 65535, 65535,
 65535, 65535, 65535
 },
 /* [7] */
 12, 7,
 { /* array: 4 elements */
 65535, 0, 65535,
 65535, 0, 65535,
 65535, 0, 65535,
 65535, 65535, 65535
 },
 /* [8] */
 12, 8,
 { /* array: 4 elements */
 65535, 65535, 0,
 65535, 65535, 0,
 65535, 65535, 0,
 65535, 65535, 65535
 }
 }
};

resource ‘PICT’ (128) {
 891,
 {195, 254, 281, 325},
 $”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”
};

resource ‘ICN#’ (128) {
 { /* array: 2 elements */
 /* [1] */
 $”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 80",
 /* [2] */
 $”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 80"
 }
};

resource ‘ICN#’ (129) {
 { /* array: 2 elements */
 /* [1] */
 $”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",
 /* [2] */
 $”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"
 }
};

{--------------------------------------------}
{---------- File UQPlot.MAmake --------------}
{--------------------------------------------}
# Copyright © 1989 Charles F. McMath.
# All rights reserved.
#
#This is the makefile.  As you can see,
# there’s not much to it.  Because the application
# files are the ‘standard’ ones, MABuild will
# figure out (correctly) what needs to be done.

AppName = QPlot
Creator = ‘FGT3’

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more
New promo at Visible: Buy a new iPhone, get $...
Switch to Visible, and buy a new iPhone, and Visible will take $10 off their monthly Visible+ service for 24 months. Visible+ is normally $45 per month. With this promotion, the cost of Visible+ is... Read more
B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for $100 off Apple’s new MSRP, only $899. Free 1-2 day delivery is available to most US addresses. Their... Read more
Take advantage of Apple’s steep discounts on...
Apple has a full line of 16″ M3 Pro and M3 Max MacBook Pros available, Certified Refurbished, starting at $2119 and ranging up to $600 off MSRP. Each model features a new outer case, shipping is free... Read more

Jobs Board

Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Business Analyst | *Apple* Pay - Banco Popu...
Business Analyst | Apple PayApply now " Apply now + Apply Now + Start applying with LinkedIn Start + Please wait Date:Mar 19, 2024 Location: San Juan-Cupey, PR Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.