Quadratic Plotters 2
Volume Number: 5
Issue Number: 9
Column Tag: MacApp Workshop
A Tale of Two Quadratic Plotters, Part II
By Carl Nelson, Chuck McMath, Hillsborough, VA
Another point of view
When I started my efforts, I had to bring the program into the MPW
environment, after all I started with someone else’s code and wanted to cut and paste as
much as I could. The first thing I did was run the source code through the MPW tool
‘MapObjects.’ This handy tool finds all Pascal UNITs defined in the files you give it to
digest, then it goes about finding all PROCEDUREs, FUNCTIONs and Objects that are
defined. As it encounters the source code it remembers where (file and offset) it saw
implementations of the procedures, then it writes out a database (called an ObjectMap)
which can then be used by the Browser Desk Accessory to find and view procedures,
functions and objects. Essentially you get a list of all Pascal UNITS, in alphabetical
order, seen by MapObjects and for every by Pascal UNIT you can see, in alphabetical
order, all PROCEDURES and FUNCTIONS contained in the UNIT. You can then click on the
name of a PROCEDURE and the DA fetches it for you to view. It is a read-only browser,
but you can cut from the displayed text and paste it into your MPW file. (I also pass
the latest MPW interfaces through MapObjects. This way I always have them online
when I need to cut and paste a Toolbox call.)
Displayed below is the output from doing a ‘MapObjects -hvsm’ on the original
MacTutor Code. Note that where a line has two items on it, the second item is the name
of the file containing that unit:
Program
QuadraticPlotter plotter
QuadraticPlotter-Private plotter
main
initRects
doUpdates
doMulti
doMouse
doKeyDowns
doActivates
crash
MainEventLoop
InitMyWindow
InitMyMenus
InitMac
Unit
PlotGlobals PlotGlobals
MyFileStuff myFileStuff
doSaveAs
doSave
MyPlotStuff myPlotStuff
doQuit
doMenubar
doGrow
doDrag
doContent
doAbout
Misc Misc
doMessage
MyPrintStuff myPrintStuff
doPrint
doPageSet
MyPrintStuff-Private myPrintStuff
PrintMe
solve solve
solveit
quad
doPlot
PrQDStuff
solve-Private solve
positivecalc
negativecalc
doDialog
PlotMe
The Browser turns out to be very helpful in understanding the MacTutor sources.
I am not a veteran of previous MacTutor code so I did not know where Dave had decided
to hide various parts of the code. I had expected that Dave’s code would have some
organizing principles that he used to decide where to put PROCEDURES and FUNCTIONS.
The article pointed the way but you can also see it from the MapObjects output. The
main program is contained in the file ‘plotter’. Code to initialize things was found in
the Init routines in the main file ‘plotter’. What struck me was the pragmatic
organization of the code. The principles that organized it seemed straightforward and
general enough but I would never have guessed where the functionality would actually
be found. I had forgotten how much my familiarity with MacApp and its architecture
caused me to make certain assumptions when looking at someone else’s code.
For example, when I first received a copy of Chuck’s code I wondered if he had
taken the time to implement the full page printing option. Knowing MacApp, I knew he
would have created a DoSetupMenus and a DoMenuCommand to handle the functionality.
So to check his code out I used the MPW search command to find all occurrences of
DoSetupMenus in the .inc1.p file he sent and sure enough, I found he had two
DoSetupMenus, one in TQPlotApplication and the other in TQPlotView. Selecting the
line with TQPlotView yielded exactly what I wanted to know, it used a field (fOnePage)
to place a checkmark beside a couple of menu entries that had associated command
names of cPrintWS and cPrintPS which I deduced were probably print window size and
print page size which corresponded to the original MacTutor code. Having such strong
notions of where things are (and ought to be) makes it easy to maintain and extend
someone else’s source code. [Chuck’s note: the reason Carl was able to find that section
of my code so easily was partially because of the ‘MacApp pact’ I signed when I
converted the code to MacApp -- I agreed to place the code (actually I had very few
other choices, being a good MacApp citizen and all) which deals with menu selections in
the method DoMenuCommand, and Carl knows this.]
In terms of external design features, the original plot program had two things
that caught my attention. First was that the PICT was always drawn to fill the window
and the second was that a modal dialog was put up to get the parameters for the
equation. I thought that always filling the window was a bit odd but, hey, I’m not
really an engineer who plots quadratics all the time (if ever) so I felt that should be
left alone. I actually had to do extra work to make the program behave this way. In the
MacApp framework the simplest case would have been to setup a fixed size page or view
area and then let MacApp scroll the image around for you. The modal dialog was
probably an expedient design; there has to be a better user interface. I thought that it
would be far better if the plot parameters could be entered in the plot window. My
design was simple: put all the fields from the modal dialog into a panel to the side of the
plot area, let the user click and type new parameters at any time in a modeless fashion,
and then let the user choose PLOT from the menu or press the ENTER key to cause the
plot to occur. This simple design change allows multiple windows with their plots and
parameters that created them to be showing at the same time.
Figure 1.
The original program only allowed the choice of 8 colors for the plot. I thought as
an example program that it should use the new Palette manger and let the user color as
many parts of the plot with any color. Also I thought it would be nice to allow for the
selection of fonts and typestyles using the hierarchical menus. Besides, I could easily
cut and paste all these features from the MacApp samples.
In starting my port of the code I was going to use an external data structure to
hold the pertinent data. After I started the design it became obvious that if I did a little
bit of encapsulation it would be a good example of the right path to follow and clearly
show the advantages of using Objects just like in Chuck’s program; I gave the original
plot program’s data to the appropriate object to manage.
As Chuck pointed out, there are always three methods you will override:
TApplication.DoMakeDocument, which creates the appropriate type of Document
object; TDocument.DoMakeViews which creates the appropriate type of View and
window objects and finally TView.Draw which Draws the contents of a view in your
window or on the page.
I had to declare a Document type (TPlotDoc) that DoMakeDocument could bring
into existence. This document would hold the plots we would be writing to disk. The
files created by this document would be readable with MacDraw and able to be placed
into PageMaker. In order to read back these files I implemented a DoRead for TPlotDoc.
Granted, it is a simple minded effort but it shows where it should be done. To properly
implement writing and reading the plot parameters should also be written and read
back.
When a document is created its DoMakeViews method is called to create the views
that will display the data in the document. In MacApp 2.0 you can create views by
doing a NEW for each view component and setting up the data structures, or you can
(preferably) create resources that describe your views and let MacApp read them,
create the objects and fill in their data structures. These resources are best created
using Apple’s ViewEdit. ViewEdit knows about MacApp view resources and lets you
build and arrange on screen the view components that will make up your displays. It is
indispensible in creating Applications with MacApp 2.0.
In looking at the view hierarchy, we start with a window which is handled by a
standard TWindow. In the window is a dialog handled by TPlotDialog. The dialog
contains two display clusters and a scroller. The two clusters contain StaticText and
NumberText view items that are used for collecting the equation coefficients and the
plot parameters. The scroller contains the plot view which is handled by a TPlotView.
The plot view contains a subview for holding the solution text box. It is handled by a
TSolutionView.
This hierarchy of views are brought into existence by TPlotDoc’s DoMakeViews
call to NewTemplateWindow. As each component of the view hierarchy is brought in
existence, the associated object which will handle it is found and created by
DoCreateViews.
For the TStaticText and TNumberText views MacApp handles all the display and
collection of keystrokes. MacApp 2.0B8 does not have facilities for handling
NumberViews with Real numbers, an oversight in the rush to get MacApp 2.0 out the
door. Calvin Cock wrote an article (and contributed the code and resources) for
publication in the Dec ’88 Frameworks describing the a new view called TExtendedText
which handles real numbers (plug: join the MacApp Developer’s Association and
receive Frameworks). Instead of reinventing the wheel, I used Calvin’s ExtendedText
Views in the Clusters.
Here is a summary of the view hierarchy which produced the window in Figure 1:
In what I would call a fairly straightforward MacApp approach, TPlotDoc holds
the parameters for the plot and TPlotDialog holds the PicHandle generated from the
original data structure and does the display of the PICT. TPlotView and TSolutionView
do all the work of actually drawing the PICT. Further work could be done on
encapsulating and distributing the plotting and display. In particular, PRQDStuff from
the original was a fairly large routine that did all the drawing work. I thought it might
be proper to split it apart into a controlling object and objects that drew parts of plot.
Not to go overboard, but to illustrate the point, I chose to have TPlotDialog create the
wrapper and have it call the appropriate component parts that composed the PICT.
TPlotDialog sets up the PICT and asks the other objects that it knows draw into it. It
should be possible with the framework I have provided to move each AXIS and its
labeling into separate views that can be setup independently.
The current design does not utilize any of the MacApp framework to do interactive
graphing. If the design of the program changed not to include re-scaling the PICT to
the window, it would be possible to create an interaction with the PlotView. For
example, you could grab the plot and move it around to show how the coefficients vary.
Given how easy it is to create multiple windows and documents, it would be easy
to create plot types and custom windows for different equations. To do this would
require that you create new types of plot and view objects then override MacApp’s
OpenNew method to create the desired new kind of plot document and window.
As Chuck stated MacApp provides a command mechanism for undo and redo. If you
look at the menu handling code for changing the plot color and text you will see how I
have implemented Undo/Redo by saving and restoring the plot characteristics. I did not
go all the way by invaliding the Plot and forcing a redraw instead I, like the Daves,
wait until the next plot is drawn. If you look at TPlotDialog.DoKeyCommand you will
see how easy it would be to have TPlotDoc.DoMenuCommand force a redraw.
Analysis
Now that we have each discussed our programs, we need to sit back a little and
see just what we got out of MacApp. While Carl’s version is obviously an improvement
given the number of features he added, the benefits of Chuck’s version are not so
obvious. So Chuck re-takes the floor to convince you he’s done a good job.
How much time do we spend doing things?
With all of the preceding discussion of my objects, it may seem that we are doing
a lot of work in what is admittedly a simple application. Let’s see if this is the case. I
have analyzed the original and my code to see what percentage of code is used for
different functions. This analysis is not perfect in that the original and new versions
were written by different people, and therefore it does not allow for different
programming styles, but still, the end application is the same (or as similar as a
MacApp and non-MacApp application can be), so we can get an idea of where we spent
our time. I split the source code into five different categories:
• user interface: the Macintosh look -- windows, menu setup and enabling, the
‘generic’ Mac portion. What code was necessary to make the application look like
a Macintosh application? Note that this does not include the code to actually
accomplish anything; that’s in the next section.
• interaction: the portion of the code that handles any user interaction & event
processing. Anything that was written to handle interaction between the user and
the application was assigned here.
• input/output routines: any code involved with actually reading or writing data to
the disk. This portion also includes code used to print the window, since I
considered that an output operation.
• program processing: this portion of code is anything that needed to be written to
calculate or determine anything. This code does not have any corresponding
on-screen elements.
• initialization and other: this category was used for all pieces of code that I
couldn’t assign anywhere else.
Chart 1 shows for each category: the number of lines of code written for each
version, and Chart 2 the percent of the total code that each section represents
(comments and blank lines were removed before the count was made, so this is only
counting executable code; 1405 for the original and 705 for MacApp).
Chart 1: Lines of Code comparison: Original vs. MacApp
The first difference that should jump out at you is the number of lines of code
written. The MacApp version has half the number of lines as the non-MacApp version.
Not only are there fewer lines, but the MacApp version has more features than the
original version -- it allows multiple windows on the screen and scrolls the window
contents, to name two. In addition, the MacApp feature follows Apple’s user interface
guidelines more closely in the page size/window size feature of the plot. In the
original version, selecting ‘window size’ changes the printed output, but does not
change the display in the window -- violating the WYSIWYG principle (What You See
Is What You Get). So there’s another area in which the MacApp program outperforms
the original one. Still another area in which the MacApp version improves on the
original is in menu handling. The original version has the Edit menu always enabled,
even though those menu items do not apply to anything displayed in the window; you can
also erroneously try to save or print before you have a plot window on the screen.
Again, these operations violate the user interface guidelines -- only appropriate menu
items should be enabled. Yet the MacApp version does enable all of its menu items
correctly. Why? Because of the design of MacApp.
It’s interesting to compare how time was spent in creating the two versions
(assuming that the code was written at a constant rate. I know this is not an entirely
rational assumption, but it’s all we have to go on). I’ve been talking about how MacApp
helps you by implementing the standard user interface elements, but looking at the
chart you see that the MacApp program has four times as much user interface code
(relatively speaking). Does this mean that I was lying? I sure hope not! The reason
for so much user interface code in the MacApp version is that there is a fixed amount of
overhead associated with handling menu, mouse, and key events. This overhead is in
the form of procedures which must be overridden to provide for the user interface
processing. In addition, each object which handles these events must override the
appropriate methods to provide the processing. Writing the code for all of these
overrides adds up. However, once the procedures are overridden, adding more
functionality to the processing is simple and does not require much more code. On the
other hand, look at the amount of code we wrote to deal with interaction -- the MacApp
implement spent only half as much time implementing its interaction code. This is
because we build upon the foundation that MacApp provides, and only have to add code to
support the extra functionality we wish to provide. MacApp takes care of the normal
interaction.
Chart 2: Percent of Code: Original vs. MacApp
This application is somewhat unusual in that the amount of ‘pure’ processing code
is rather small, although it’s interesting that the relative amount of processing code is
constant. One last thing to note is the amount of code in the ‘Other’ category. As I
categorized the source code for the MacApp version, I realized that much of the code fell
into this category. That’s because MacApp programs spend a lot of time initializing
objects, creating windows and views and documents, and doing a lot of things that are
difficult to categorize.
Chart 3 shows the amount of code that came directly from the original version to
the MacApp version. The first column is the number of lines of code that was directly
cut and pasted from the old version to the new. The second column is the total number
of lines in the new category. The third column shows the percentage of each category
that the old code makes up. This chart is instructive in that it shows how much of your
non MacApp program you will be able to reuse. It shouldn’t be surprising that none of
the interaction or user interface code was transferable; it’s a little more surprising
that none of the ‘other’ code was applicable. If you think about it, however, the
MacApp ‘other’ category is made up of code which is pretty specific to MacApp --
object creation and initialization, and the object definitions. This code could not have
come from the original program.
# Lines TakenTotal in New % of New
Input/Output 181 [TOKEN:12849]1 86
Interaction 0 [TOKEN:12592]8 0
Other 0 [TOKEN:12850]1 0
Processing 48 48 100
User Interface 0 [TOKEN:12593]7 0
Totals 229 [TOKEN:14128]5 N/A
Chart 3: Code requiring no conversion
As you can see, all of the processing code used in the MacApp program came
directly from the original version. This should give some weight to my assertion that
in a MacApp program you need to concentrate on the unique portion of your application
-- for indeed, in the plotter application, the processing is the unique portion. And
note also that most of the input/output routines came directly from the original
version. Most of this code is related to creating and printing the PICT, and of course
remains the same no matter whether you’re using MacApp or not.
The bottom line here, though, is that the MacApp version only required 50% as
much code as the original version; and fully one-third of that code was lifted directly
from the original, which means that the MacApp version only had around 500 new
lines of code -- one third as much as the original. And this does not yield a program
that is crippled or partially functional, it yields a program that conforms to the user
interface guidelines, is fully functional (within its design), and is a good bet to run on
future Macintosh architectures (not to mention A/UX). This is the big win we get from
MacApp: not something for nothing, but more results for less work. Sure, you have to
change your thinking, but all I can say is this: look at the bottom line.
Conclusion
So there you have it -- two views of a MacApp conversion effort, from two
slightly different viewpoints. Although the two MacApp programs may seem quite
different, they are much more similar to each other than either is to the original
effort. If Carl and I swapped our two MacApp programs and each had to add a feature to
them, we would be able to much more easily than if we were to try the same on the
original program. All MacApp programs share a structure, an organization; different
programs do similar things in the same place. Reusing code from one MacApp program
to another is increased. You don’t have to spend time searching for the procedure or
function you want -- you will know where to find it.
We hope you have some idea of the benefits of MacApp and that you’ll not only get
more done, but you’ll get it done more quickly (once you become a MacApp citizen),
and your final product will be a real professional job. MacApp is the wave of the
future -- catch it today! [Aw Come-on Chuck, knock it off.]
UPlot.p Plot UNIT FILE
{[a-,body+,h,o=100,r+,rec+, t=4,u+,#+,j=20/57/1$,n+]}
{ The above is the official MacApp PasMat Style statement.What you
don’t use pasmat to make all your source code conform to your
company’s (or personal) standard for source code style? }
{Copyright © 1986-1988 Apple Computer, Inc.
All rights reserved.}
{Copyright © 1989 by Software Architects, Inc.
All rights reserved.}
{Portions Copyright © 1988 MacTutor
All rights reserved.}
{[f-]}
(*
This is a very small sample application which uses concepts and
program fragments presented in the February 1988 MacTutor Plot
Article.
By looking at this program you may be able to gain a better
understanding of how to cast a conventional program into the MacApp
“Application Framework” or (Class structure depending upon whose
jargon you wish to use).
In the tradition of MacApp it defines the basic three Class (object)
overrides:
TPlotApplication.DoMakeDocument -- Launches appropriate type of
Document object.
TPlotDoc.DoMakeViews -- Launches appropriate type View and window
objects.
TPlotDialog.Draw -- Calls it sub components to draw the contents of
a view.
TPlotView -- To actually plot the thing
TSolveView -- To draw the solution text box
In addition it defines commands unique to the plot program. See the
text of the accompaning article for detials.
*)
{[f+]}
UNIT UPlot;
INTERFACE
USES
{ • MacApp - this includes all of the things
necessary from the MacApp Library }
UMacApp,
{ • Building Blocks }
UDialog, UPrinting, UExtendedText,
{ • Implementation Use }
SANE, ToolUtils, Fonts, Resources,
Script, PickerIntf, Packages;
CONST
kSignature = ‘Plot’;
{ Application signature}
kFileType = ‘PICT’;
{ File-type code used for document files
created by this application}
kPlotDialog = 1010;
{ MacApp uses a very useful technique for seperating menu item
numbering from what you want done by chosing a menu item. See MacApp
manual pggs xxx-xx for full details. Work is done in MacApp with
commands. Each command is assigned a unique number. For example
Save is 30 and SaveAs is 32. Numbers below 1200 are reserved for
MacApp. In this Application we have chosen a command numbering
scheme that makes life easy:
Application Commands= 1400
Font styles = 2000
Font sizes = 2100
Font just = 2200
Font fonts = 2300
Hierarchical Menus = 2400
Plot colors = 2500
}
{ the command to cause a plot to happen }
cPlotIt = 1401;
{ Command numbers for typestyle attributes }
cPlainText = 2001;
cBold = 2002;
cItalic = 2003;
cUnderline = 2004;
cOutline = 2005;
cShadow = 2006;
cCondense = 2007;
cExtend = 2008;
{ Command numbers for font-size commands }
cSizeChange = 2100;
cSizeBase = 2100;
cSizeMin = 2109;
cSizeMax = 2124;
{ 2101-2197 reserved for font sizes 1-97 pts. }
cSizeGrow = 2198;
cSizeShrink = 2199;
{ Command numbers cover other stylistic changes }
cJustChange = 2200;
cJustLeft = 2201;
cJustCenter = 2202;
cJustRight = 2203;
cFontChange = 2300;
{ Command numbers for the hierarchial menu }
cStyle = 2401;
cSize = 2402;
cFont = 2403;
cColor = 2404;
{ Command numbers for changing colors }
cColorChange = 2500;
cColorText = 2501;
cColorBackground = 2502;
cColorGraph = 2503;
cColorAxis = 2504;
{ Constant for amount to relative
size text selection }
kRelSizeAmount = 4;
{ Constants for the prompts string list }
kPromptsRsrcID = 1001;
kColTextPrompt = 1;
kColBackPrompt = 2;
kColGraphPrompt = 3;
kColAxisPrompt = 4;
{ Menu numbers }
mFont = 10;
{ Menus displayed on hier. menu system }
kHierDisplayedMBar= 131;
{ Menus displayed on non-hier. system }
kNonHierDisplayedMBar = 128;
{ Offset added to non-hier menu cmds to get }
kHierMenuOffset = 1000;
{ ‘view’ resource for default values }
kViewRsrcID = 1005;
{ PICT comments for our plot and text box }
{selected MacDraw comments}
picDwgBeg = 130;
picDwgEnd = 131;
picGrpBeg = 140;
picGrpEnd = 141;
TextBegin = 150;
TextEnd = 151;
StringBegin = 151;
StringEnd = 153;
TextCenter = 154;
{postscript comments}
SetLineWidth = 182;
PostScriptBegin = 190;
TextIsPostscript = 194;
PostScriptEnd = 191;
{ The size of a MacDraw Header }
kHeaderSize = 512;
TYPE
QuadraticType = (NotSolved, RealRoots,
SingleSolution, ComplexRoot);
{specifications of text display}
PlotSpecs = RECORD
theTextFont: Str255;
theFontNum: INTEGER;
theTextFace: Style;
theTextSize: INTEGER;
theJustification:INTEGER; { text }
theTextColor: RGBColor; { label color }
theGraphColor: RGBColor;
theAxisColor: RGBColor;
theBackColor: RGBColor;
END;
PlotSpecsPtr = ^PlotSpecs;
PlotSpecsHdl = ^PlotSpecsPtr;
{ Object Definitions }
{------------------------------------}
TPlotApplication = OBJECT (TApplication)
{ Initialize application and globals. }
PROCEDURE TPlotApplication.IPlotApplication(
itsMainFileType: OSType);
{ Launches a TPlotDocument }
FUNCTION TPlotApplication.DoMakeDocument(
itsCmdNumber: cmdNumber): TDocument;
OVERRIDE;
PROCEDURE TPlotApplication.IdentifySoftware;
OVERRIDE;
PROCEDURE TPlotApplication.Fields(
PROCEDURE DoToField(fieldName: Str255;
fieldAddr: Ptr;
fieldType:INTEGER));
OVERRIDE;
END; { TPlotApplication }
{------------------------------------}
TPlotDoc = OBJECT (TDocument)
fPlotDialog : TPlotDialog;
fPlotSpecs : PlotSpecs;
fOldPlot : PicHandle;
{ coefficients to our quadratic equation }
faParam : Real;
fbParam : Real;
fcParam : Real;
{ plot display parameters }
fstepParam : Real;
fxParam : INTEGER;
fyParam : INTEGER;
{ the solutions to our quadratic }
f1stRoot : Real;
f2ndRoot : Real;
fRootType : QuadraticType;
{ setup for the document to hold the plot }
PROCEDURE TPlotDoc.IPlotDocument;
{ For new doc or revert initial state }
PROCEDURE TPlotDoc.DoInitialState; OVERRIDE;
{ Generate command to change Look of a plot }
FUNCTION TPlotDoc.DoMakePStyleCmd( itsStyle:PlotSpecsPtr;
itsCmdNumber:CmdNumber): TPStyleCmd;
{ create all the views needed for document }
PROCEDURE TPlotDoc.DoMakeViews(forPrinting: BOOLEAN); OVERRIDE;
{ calculater how much disk space this
document will need }
PROCEDURE TPlotDoc.DoNeedDiskSpace(
VAR dataForkBytes, rsrcForkBytes: LONGINT);
OVERRIDE;
{ read the data for this document }
PROCEDURE TPlotDoc.DoRead(
aRefNum: INTEGER; rsrcExists,
forPrinting: BOOLEAN); OVERRIDE;
{ write the data for this document }
PROCEDURE TPlotDoc.DoWrite(aRefNum: INTEGER;
makingCopy: BOOLEAN); OVERRIDE;
{ given a Menu choice handle or pass it on }
FUNCTION TPlotDoc.DoMenuCommand(
aCmdNumber: cmdNumber): TCommand;
OVERRIDE;
{ setup the menus for the document }
PROCEDURE TPlotDoc.DoSetupMenus; OVERRIDE;
{ given the parameters of our
document calculate a solution }
PROCEDURE TPlotDoc.SolveQuadratic;
PROCEDURE TPlotDoc.ChangeBackColor(
newColor: RGBColor);
{$IFC qDebug}
PROCEDURE TPlotDoc.Fields(
PROCEDURE DoToField(
fieldName: Str255;
fieldAddr: Ptr;
fieldType: INTEGER));
OVERRIDE;
{$ENDC}
END; { TPlotDoc }
TPlotView = OBJECT (TView)
fPlotDoc : TPlotDoc;
{ Add to the pict we will draw on
the screen or printed page }
PROCEDURE TPlotView.AddToPict(picRect:Rect);
{ A convenience routine }
PROCEDURE TPlotView.GetQDFrame(
VAR frameRect:Rect);
{ The design says the plot fills the
window, therefore when we are
resized we must invalidate ourselves}
PROCEDURE TPlotView.Resize(width,
height: VCoordinate; invalidate: BOOLEAN);
OVERRIDE;
END;
TSolutionView = OBJECT (TView)
fPlotDoc : TPlotDoc;
fSolveRect : Rect;
{ Add to pict we will draw on the screen or printed page }
PROCEDURE TSolutionView.AddToPict(picRect:Rect);
END;
TPlotDialog = OBJECT (TDialogView)
fPlotSize : VPoint;
fPlotView : TPlotView;
fSolutionView : TSolutionView;
fPlotDoc : TPlotDoc;
fPlotPICT : PicHandle;
FUNCTION TPlotDialog.DoKeyCommand(
ch: CHAR; aKeyCode: INTEGER;
VAR info: EventInfo): TCommand;
OVERRIDE;
FUNCTION TPlotDialog.DoMenuCommand(
aCmdNumber: CmdNumber):TCommand;
OVERRIDE;
PROCEDURE TPlotDialog.DismissDialog(
dismisser: IDType; flashDismisser: BOOLEAN);
OVERRIDE;
PROCEDURE TPlotDialog.Draw(area: Rect);
OVERRIDE;
PROCEDURE TPlotDialog.EachSubView(
PROCEDURE DoToSubView(
theSubView: TView));
OVERRIDE;
PROCEDURE TPlotDialog.PlotNDrawPICT;
PROCEDURE TPlotDialog.GetPlotValues;
PROCEDURE TPlotDialog.DoSetupMenus; OVERRIDE;
END;
TPStyleCmd = OBJECT (TCommand)
fPlotDialog : TPlotDialog;
fOldPlotSpecs : PlotSpecs;
fNewPlotSpecs : PlotSpecs;
{ Initialize the command; if unsuccessful,
signalled by Failure mechanism }
PROCEDURE TPStyleCmd.IPStyleCmd(
itsPlotDialog:TPlotDialog;
itsNewStyle:PlotSpecsPtr;
itsCmdNumber: CmdNumber);
PROCEDURE TPStyleCmd.DoIt; OVERRIDE;
PROCEDURE TPStyleCmd.RedoIt; OVERRIDE;
PROCEDURE TPStyleCmd.UndoIt; OVERRIDE;
END;
VAR
gDefaultSpecs: PlotSpecs;
{ a Menu Management Global }
gMenuOfs: INTEGER;
{ Convenience, fetching string from resource }
gPromptString: Str255;
IMPLEMENTATION
{ I M P L E M E N T A T I O N }
{--------------------------------}
{$S ARes}
{ Generallly useful routines }
FUNCTION GetPrompt(index: INTEGER): StringPtr;
BEGIN
GetIndString(gPromptString,
kPromptsRsrcID, index);
GetPrompt := @gPromptString;
END;
FUNCTION Real2Str(aReal: Real; theDigits: INTEGER): Str255;
VAR aStr : DecStr;
form : DecForm;
BEGIN
form.style := FixedDecimal;
form.digits := theDigits;
Num2Str(form,aReal,aStr);
Real2Str := aStr;
END;
{$IFC qDebug}
{$IFC qTrace} {$D+} {$ENDC}
{ In the final version of MacApp 2.0 there will some kind of support
for REAL numbers in text entry fields, for now we use Calvins Cock’s
code from the Dec ’88 Frameworks }
PROCEDURE MyFieldToString(theData: Ptr;
fieldType: integer; VAR theString: str255);
CONST
DecPrec = 2;
{ Change if you want more decimal precision }
TYPE
TAlias = RECORD
CASE integer OF
bReal, bSingle: (asReal : Real);
bDouble: (asDouble : Double);
bExtended: (asExtended : Extended);
END;
VAR
alias : ^TAlias;
aDecForm : DecForm;
x : Extended;
NumStr : DecStr;
BEGIN
alias := Pointer(theData);
WITH alias^ DO
CASE fieldType OF
bReal, bSingle:
BEGIN
aDecForm.style := FixedDecimal;
aDecForm.digits := DecPrec;
x := asReal;
Num2Str(aDecForm, x, NumStr);
theString := str255(NumStr);
END;
bDouble:
BEGIN
aDecForm.style := FixedDecimal;
aDecForm.digits := DecPrec;
x := asDouble;
Num2Str(aDecForm, x, NumStr);
theString := str255(NumStr);
END;
bExtended:
BEGIN
aDecForm.style := FixedDecimal;
aDecForm.digits := DecPrec;
x := asExtended;
Num2Str(aDecForm, x, NumStr);
theString := str255(NumStr);
END;
OTHERWISE StdFieldToString(theData,
fieldType, theString);
END;
END;
{$IFC qTrace} {$D++} {$ENDC}
{$ENDC qDebug}
{--------------------------------}
{$S AReadFile}
PROCEDURE ReadBytes(theRefNum: INTEGER;
size:LONGINT; buffer: Ptr);
{ Utility for reading data from a file }
BEGIN
FailOSErr(FSRead(theRefNum, size, buffer));
END;
{--------------------------------}
{$S AWriteFile}
PROCEDURE WriteBytes(theRefNum: INTEGER;
size: LONGINT; buffer: Ptr);
{ Utility for writing data to a file. }
BEGIN
FailOSErr(FSWrite(theRefNum, size, buffer));
END;
{------------------------------------------}
{$S AInit}
PROCEDURE TPlotApplication.IPlotApplication(
itsMainFileType: OSType);
VAR
fontName: Str255;
aTEView: TTEView;
BEGIN
{ qNeedsHierarchialMenus is a MacApp compile time flag you can set
which will require the use of Heirarchical Menus }
{$IFC NOT qNeedsHierarchialMenus}
IF NOT gConfiguration.hasHierarchicalMenus THEN
BEGIN
gMBarDisplayed := kNonHierDisplayedMBar;
gMenuOfs := 0;
END
ELSE
{$ENDC}
BEGIN
gMBarDisplayed := kHierDisplayedMBar;
gMenuOfs := kHierMenuOffset;
END;
IApplication(itsMainFileType);
{ Do not setup the menus if we were started up with the request to
print }
IF NOT gFinderPrinting THEN
BEGIN
AddResMenu(GetMHandle(mFont), ‘FONT’);
SetStyle(cBold, [bold]);
SetStyle(cUnderline, [underline]);
SetStyle(cItalic, [italic]);
SetStyle(cOutline, [outline]);
SetStyle(cShadow, [shadow]);
SetStyle(cCondense, [condense]);
SetStyle(cExtend, [extend]);
END;
{ This is an example of questional code reuse. We know that TTEVIEWS
holds lots of info about fonts, sizes and color and we have the
Viewedit tool at our disposal, so why not use it to create a useful
resource to get our initial values from instead of hard-wiring the
defaults. The technique here is to define a TTEView resource and use
all those great fields that you can setup with viewEdit as the
defaults, then steal the values from the TTEVIEW object and trash the
TTEView once all the work is done. }
{fetch the resource}
aTEView := TTEView(DoCreateViews(NIL, NIL,
kViewRsrcID, gZeroVPt));
FailNIL(aTEView);
{ Set up initial text specs }
GetFontName(aTEView.fTextStyle.tsFont, fontName);
WITH gDefaultSpecs, aTEView DO
BEGIN
theTextFont := fontName;
theTextFace := fTextStyle.tsFace;
theTextSize := fTextStyle.tsSize;
theTextColor := fTextStyle.tsColor;
theJustification := fJustification;
theBackColor := gRGBWhite;
END;
aTEView.Free;
{ Until MacApp 2.0 debug and ViewTemplates support REALs this is
our work around from Calvin Cock’s January ’89 MapApp Frameworks
article. }
gFieldToStrRtn := @MyFieldToString;
END;
{------------------------------------------}
{$IFC qDebug}
{$S ADebug}
PROCEDURE TPlotApplication.IdentifySoftware;
BEGIN
WriteLn(‘Plot Source date: 31 Jan 89;Compiled:’,
COMPDATE, ‘ @ ‘, COMPTIME);
INHERITED IdentifySoftware;
END;
PROCEDURE TPlotApplication.Fields(
PROCEDURE DoToField(fieldName: Str255;
fieldAddr: Ptr;
fieldType:INTEGER));
OVERRIDE;
BEGIN
WITH gDefaultSpecs DO
BEGIN
DoToField(‘ Font’, @theTextFont, bFontName);
DoToField(‘ Face’, @theTextFace, bStyle);
DoToField(‘ Size’, @theTextSize, bInteger);
END;
END;
{$ENDC}
{************************************************}
{ T P l o t D o c u m e n t }
{***** ******************************************}
{------------------------------------------}
{$S AOpen}
PROCEDURE TPlotDoc.IPlotDocument;
VAR
aRect: Rect;
BEGIN
IDocument(kFileType, kSignature,
kUsesDataFork, NOT kUsesRsrcFork,
NOT kDataOpen, NOT kRsrcOpen);
fOldPlot := NIL;
END;
{------------------------------------------}
{$S AOpen}
FUNCTION TPlotApplication.DoMakeDocument(itsCmdNumber: cmdNumber):
TDocument;
VAR
aPlotDocument: TPlotDoc;
dimensions: Rect;
BEGIN
{ Allocate and initialize the document}
NEW(aPlotDocument);
FailNIL(aPlotDocument);
aPlotDocument.IPlotDocument;
DoMakeDocument := aPlotDocument;
END;
{----------------------------------------------}
{$S AOpen}
PROCEDURE TPlotDoc.DoInitialState; OVERRIDE;
BEGIN
{ when reverting to an old copy of a document we
need to reset to some reasonable values }
fPlotSpecs := gDefaultSpecs;
fOldPlot := NIL;
END;
{------------------------------------------}
FUNCTION TPlotDoc.DoMakePStyleCmd(itsStyle:PlotSpecsPtr;
itsCmdNumber:CmdNumber): TPStyleCmd ;
VAR
aPStyleCmd: TPStyleCmd;
aPlotDialog: TPlotDialog;
BEGIN
New(aPStyleCmd);
FailNIL(aPStyleCmd);
aPlotDialog := fPlotDialog;
aPStyleCmd.IPStyleCmd(aPlotDialog, itsStyle, itsCmdNumber);
DoMakePStyleCmd := aPStyleCmd;
END;
{------------------------------------------}
{$S AOpen}
PROCEDURE TPlotDoc.DoMakeViews(forPrinting: BOOLEAN);
VAR
aWindow: TWindow;
aPlotDialog: TPlotDialog;
aPlotView: TPlotView;
aTEView: TTEView;
aSolutionView: TSolutionView;
aCluster: TCluster;
aPrintHandler: TStdPrintHandler;
anExtendedText: TExtendedText;
aRect: Rect;
BEGIN
{ We want to dynamically call these in
exisitance. Do a New() call for each object
type, so the linker doesn’t strip them out. }
IF gCreateWithTemplates THEN
BEGIN
New(aPlotDialog);
New(aPlotView);
New(aTEView);
New(aSolutionView);
New(aCluster);
New(anExtendedText);
END;
{ we will now ceate and connect up all the view
and document variables }
aWindow := NewTemplateWindow(kPlotDialog, SELF);
{ bring our plot window into exisitance }
aPlotDialog := TPlotDialog(aWindow.FindSubView(‘DLOG’));
FailNIL(aPlotDialog);
{find dialog portions & make certian we have it }
fPlotDialog := aPlotDialog;
{ save this away for late when we need
to easily find the dialog }
aPlotDialog.fPlotDoc := SELF;
{ and of course we need to cross refer so
tell the plotdialog who its doc is }
IF (fOldPlot <> NIL)
| (GetHandleSize(Handle(fOldPlot)) > 0 ) THEN
aPlotDialog.fPlotPICT := fOldPlot
{ If the document has an old plot PICT display it }
ELSE
aPlotDialog.GetPlotValues;
{ Use the values from the resource to
generate the first plot }
{ Find the PlotView and make some
connections to our PlotDocument }
aPlotView := TPlotView(aWindow.FindSubView(‘plot’));
FailNIL(aPlotView);
aPlotView.fPlotDoc := SELF;
aPlotDialog.fPlotView := aPlotView;
aPlotDialog.fPlotPICT := NIL;
aPlotDialog.fPlotSize := aPlotView.fSize;
{ Find the SolutionView and make some
connections to our PlotDocument }
aSolutionView := TSolutionView(aWindow.FindSubView(‘qslv’));
FailNIL(aSolutionView);
aSolutionView.fPlotDoc := SELF;
aPlotDialog.fSolutionView := aSolutionView;
{ while we are at it, retrieve the rectangle
size we will use to display in }
SetRect(aRect,0,0,aSolutionView.fSize.h,
aSolutionView.fSize.v);
aSolutionView.fSolveRect := aRect;
{ we want to limit the minimum size this
window can be so use the size of our
clusters to determine the minimum}
aCluster:=TCluster(aWindow.FindSubView(‘Ccof’));
aWindow.fResizeLimits.top:= aCluster.fSize.v*2;
aWindow.fResizeLimits.left:=aCluster.fSize.h*3;
aCluster:= TCluster(aWindow.FindSubView(‘Cdsp’));
aWindow.fResizeLimits.top := aWindow.fResizeLimits.top
+ aCluster.fSize.v;
NEW(aPrintHandler);
FailNIL(aPrintHandler);
aPrintHandler.IStdPrintHandler(SELF, { its document }
aPlotDialog, { its view }
{ does not have square dots }
FALSE,{ horzontal page size is fixed }
TRUE,{ vertical page size is variable
(could be set to true on
non-style TE systems) }
FALSE);
aPrintHandler.fMinimalMargins := FALSE;
END;
{------------------------------------------}
{$S ASelCommand}
FUNCTION TPlotDoc.DoMenuCommand(
aCmdNumber: CmdNumber): TCommand; OVERRIDE;
VAR
aName: Str255;
menu: INTEGER;
item: INTEGER;
newStyle: PlotSpecs;
{------------------------------------------}
PROCEDURE DoSizeChange(base: CmdNumber);
BEGIN
newStyle.theTextSize := aCmdNumber - base;
DoMenuCommand := DoMakePStyleCmd(
@newStyle, cSizeChange);
END;
{----------------------------------------------}
PROCEDURE DoRelSizeChange(amount: INTEGER);
BEGIN
WITH newStyle DO
theTextSize := theTextSize + amount;
DoMenuCommand := DoMakePStyleCmd(@newStyle, cSizeChange);
END;
{------------------------------------------}
PROCEDURE DoFontChange;
BEGIN
GetItem(GetMHandle(menu), item,newStyle.theTextFont);
GetFNum(aName, newStyle.theFontNum);
DoMenuCommand := DoMakePStyleCmd(@newStyle, cFontChange);
END;
{--------------------------------------------}
PROCEDURE DoColTextChange;
VAR
aColor: RGBColor;
BEGIN
aColor := fPlotSpecs.theTextColor;
IF GetColor(Point($00400040),
GetPrompt(kColTextPrompt)^,
aColor, newStyle.theTextColor) THEN
DoMenuCommand := DoMakePStyleCmd(
@newStyle, cColorText);
END;
{------------------------------------------}
PROCEDURE DoColGraphChange;
VAR
aColor: RGBColor;
BEGIN
aColor := fPlotSpecs.theGraphColor;
IF GetColor(Point($00400040),
GetPrompt(kColGraphPrompt)^, aColor,
newStyle.theGraphColor) THEN
DoMenuCommand := DoMakePStyleCmd(@newStyle, cColorGraph);
END;
{--------------------------------------------}
PROCEDURE DoColAxisChange;
VAR
aColor: RGBColor;
BEGIN
aColor := fPlotSpecs.theAxisColor;
IF GetColor(Point($00400040),
GetPrompt(kColAxisPrompt)^, aColor,
newStyle.theAxisColor) THEN
DoMenuCommand := DoMakePStyleCmd(
@newStyle, cColorAxis);
END;
{----------------------------------------}
PROCEDURE DoColBackChange;
VAR
aColor: RGBColor;
BEGIN
aColor := fPlotSpecs.theBackColor;
IF GetColor(Point($00400040),
GetPrompt(kColBackPrompt)^, aColor,
newStyle.theBackColor) THEN
BEGIN
DoMenuCommand := DoMakePStyleCmd(
@newStyle, cColorBackGround);
END;
END;
{----------------------------------------}
PROCEDURE DoJustChange;
VAR
newJust: INTEGER;
BEGIN
CASE aCmdNumber OF
cJustLeft:
newJust := teJustLeft;
cJustCenter:
newJust := teJustCenter;
cJustRight:
newJust := teJustRight;
END;
newStyle.theJustification := newJust;
DoMenuCommand := DoMakePStyleCmd(@newStyle, aCmdNumber);
END;
{----------------------------------------}
PROCEDURE DoPlainChange;
BEGIN
newStyle.theTextFace := [];
DoMenuCommand := DoMakePStyleCmd(@newStyle, cStyleChange);
END;
{------------------------------------------}
PROCEDURE DoStyleChange;
VAR
newFace : Style;
BEGIN
WITH newStyle DO
BEGIN
CASE aCmdNumber OF
cBold:
newFace := [bold];
cItalic:
newFace := [italic];
cUnderline:
newFace := [underline];
cOutline:
newFace := [outline];
cShadow:
newFace := [shadow];
cCondense:
newFace := [condense];
cExtend:
newFace := [extend];
END;
IF newFace * theTextFace = newFace THEN
theTextFace := theTextFace - newFace
ELSE
theTextFace := theTextFace + newFace;
END;
DoMenuCommand := DoMakePStyleCmd(
@newStyle, cStyleChange);
END;
{----------------------------------------}
BEGIN { DoMenuCommand }
DoMenuCommand := gNoChanges;
newStyle := fPlotSPecs;
CmdToMenuItem(aCmdNumber, menu, item);
IF menu = mFont THEN
DoFontChange
ELSE
CASE aCmdNumber OF
cSizeMin..cSizeMax:
DoSizeChange(cSizeBase);
cSizeGrow:
DoRelSizeChange(kRelSizeAmount);
cSizeShrink:
DoRelSizeChange( - kRelSizeAmount);
cJustLeft..cJustRight:
DoJustChange;
cPlainText:
DoPlainChange;
cBold..cExtend:
DoStyleChange;
cColorText:
DoColTextChange;
cColorGraph:
DoColGraphChange;
cColorAxis:
DoColAxisChange;
cColorBackground:
DoColBackChange;
OTHERWISE
DoMenuCommand := INHERITED
DoMenuCommand(aCmdNumber);
END;
END;
{------------------------------------------}
{$S ARes}
PROCEDURE TPlotDoc.DoSetupMenus; OVERRIDE;
VAR
hasColor: BOOLEAN;
hasStyle: BOOLEAN;
checkPlain: BOOLEAN;
checkSize: BOOLEAN;
checkFont: BOOLEAN;
specChange: BOOLEAN;
just: INTEGER;
item: INTEGER;
fnt: INTEGER;
c: INTEGER;
aMode: INTEGER;
aFace: Style;
aMenuHandle: MenuHandle;
aName: Str255;
aStyle: TextStyle;
theFont: INTEGER;
aStr255: Str255;
BEGIN
INHERITED DoSetupMenus;
hasColor := gConfiguration.hasColorQD;
hasStyle := gConfiguration.hasStyleTextEdit;
aStr255 := fPlotSpecs.theTextFont;
GetFNum(aStr255, aStyle.tsFont);
WITH aStyle, fPlotSpecs DO
BEGIN
tsFace := theTextFace;
tsSize := theTextSize;
tsColor := theTextColor;
END;
checkPlain := aStyle.tsFace = [];
checkFont := TRUE;
aMenuHandle := GetMHandle(mFont);
GetFontName(aStyle.tsFont, aName);
{ Get real font number in case tsFont is }
GetFNum(aName, theFont);
{ the system or application font. }
FOR item := 1 TO CountMItems(aMenuHandle) DO
BEGIN
{ There can be more than 31 menu entries
with scrolling menus, but trying to enable
an item with number > 31 is bad news.
If the menu itself is enabled (which it
will be in MacApp if any of the first 31
items is enabled), then the extras
will always be enabled. }
IF item <= 31 THEN
EnableItem(aMenuHandle, item);
IF checkFont THEN
BEGIN
GetItem(aMenuHandle, item, aName);
GetFNum(aName, fnt);
CheckItem(aMenuHandle, item, fnt = theFont);
END;
END;
just := fPlotSpecs.theJustification;
{ Enable justification related menu items }
EnableCheck(cJustLeft, TRUE, (just = teJustLeft));
EnableCheck(cJustCenter, TRUE, (just = teJustCenter));
EnableCheck(cJustRight, TRUE, (just = teJustRight));
{$IFC NOT qNeedsHierarchialMenus}
IF gConfiguration.hasHierarchicalMenus THEN
{$ENDC}
BEGIN
Enable(cStyle, TRUE); { Enable sub-menus }
Enable(cSize, TRUE);
Enable(cFont, TRUE);
Enable(cColor, hasColor);
END;
aFace := aStyle.tsFace;
EnableCheck(cPlainText, TRUE, checkPlain);
{ Enable normal Style menu items }
EnableCheck(cBold, TRUE, bold IN aFace);
EnableCheck(cItalic, TRUE, italic IN aFace);
EnableCheck(cUnderline, TRUE, underline IN aFace);
EnableCheck(cOutline, TRUE, outline IN aFace);
EnableCheck(cShadow, TRUE, shadow IN aFace);
EnableCheck(cCondense, TRUE,condense IN aFace);
EnableCheck(cExtend, TRUE, extend IN aFace);
FOR c := cSizeMin TO cSizeMax DO
BEGIN
IF hasStyle THEN
checkSize := FALSE
ELSE
checkSize := (c - cSizeBase) = aStyle.tsSize;
EnableCheck(c, TRUE, checkSize);
IF ((NOT hasStyle) |
{ If the record isn’t styled, or }
RealFont(aStyle.tsFont,c-cSizeBase))
{ the size is a real one }
THEN aFace := [outline]
{ then we outline it }
ELSE
aFace := [];
SetStyle(c, aFace);
END;
Enable(cSizeGrow, TRUE);
Enable(cSizeShrink, TRUE);
Enable(cColorText, hasColor);
Enable(cColorBackground, hasColor);
Enable(cColorGraph, hasColor);
Enable(cColorAxis, hasColor);
END;
{------------------------------------------}
{$S AWriteFile}
PROCEDURE TPlotDoc.DoNeedDiskSpace(
VAR dataForkBytes, rsrcForkBytes: LONGINT);
VAR
r: Rect;
BEGIN
{ In other MacApp Samples we would normally get
the Print record space requirements by doing:

INHERITED DoNeedDiskSpace(dataForkBytes, rsrcForkBytes);
BUT seeing as we are trying to imitate a
MacDraw File we will just do our size
calculation
}
dataForkBytes := kHeaderSize { for std MacDraw Header }
+ GetHandleSize(Handle(fPlotDialog.fPlotPICT));
{ For now we will write only the PICT Handle in
the future we might want to write the
PlotSpecs and other parameters to the resource
fork of the file }
rsrcForkBytes := 0;
END;
{------------------------------------------}
{$S AReadFile}
PROCEDURE TPlotDoc.DoRead(aRefNum: INTEGER; rsrcExists, forPrinting:
BOOLEAN);
VAR
fi: FailInfo;
aPICTSize: LONGINT;
aPICTHandle:Handle;
PROCEDURE SkipDocHeaderInfo;
BEGIN
{ skip the dummy header }
FailOSErr( SetFPos(aRefNum,fsFromStart,kHeaderSize));
END;
PROCEDURE HdlReadFailure(error: OSErr; message: LONGINT);
BEGIN
{ We ran into trouble reading the data for
now do nothing}
END;
BEGIN
CatchFailures(fi, HdlReadFailure);
{ Normally, we would ask our ancestors to read
in their data by:
INHERITED DoRead(aRefNum, rsrcExists, forPrinting);
but we are imitating a MacDraw Doc and have
to behave like one
}
SkipDocHeaderInfo;
IF fOldPlot <> NIL THEN
DisposHandle(Handle(fOldPlot));
FailOSErr(GetEOF(aRefNum,aPICTSize));
aPICTSize := aPICTSize - kHeaderSize;
aPICTHandle := NewHandle(aPICTSize);
HLock(aPICTHandle);
ReadBytes(aRefNum, aPICTSize, aPICTHandle^);
HUnLock(aPICTHandle);
fOldPlot := PicHandle(aPICTHandle);
Success(fi);
END;
{------------------------------------------}
{$S AWriteFile}
PROCEDURE TPlotDoc.DoWrite(aRefNum: INTEGER; makingCopy: BOOLEAN);
PROCEDURE WriteHeaderInfo;
VAR
aPtr: Ptr;
BEGIN
aPtr := NewPtrClear(kHeaderSize);
FailNil(aPtr);
WriteBytes(aRefNum, kHeaderSize, aPtr);
DisposPtr(aPtr);
END;
PROCEDURE WritePlotInfo;
VAR
aPICTHandle : Handle;
aPICTSize : LONGINT;
BEGIN
aPICTHandle := Handle(fPlotDialog.fPlotPICT);
aPICTSize := GetHandleSize(aPICTHandle);
HLock(aPICTHandle);
WriteBytes(aRefNum, aPICTSize, aPICTHandle^);
HUnLock(aPICTHandle);
END;
BEGIN
WriteHeaderInfo;
WritePlotInfo
END;
{------------------------------------------}
{$S ARes}
PROCEDURE TPlotDoc.SolveQuadratic;
VAR
a,b,c,check : real;
FUNCTION PositiveCalc(a, b, check:real):real;
BEGIN
PositiveCalc := (-b + sqrt(check)) / (2 * a);
END;
FUNCTION NegativeCalc(a, b, check:real):real;
BEGIN
NegativeCalc := (-b - sqrt(check)) / (2 * a);
END;
BEGIN
a := faParam;
b := fbParam;
c := fcParam;
check := (b * b) - (4 * a * c);
IF check = 0 THEN
{ we have a double root (same place twice) }
BEGIN
fRootType := SingleSolution;
f1stRoot := PositiveCalc(a, b, check);
f2ndRoot := f1stRoot;
END
ELSE IF check > 0 THEN
{ we have a pair of “real” x axis crossings }
BEGIN
fRootType := RealRoots;
f1stRoot := PositiveCalc(a, b, check);
f2ndRoot := NegativeCalc(a, b, check);
END
ELSE IF check < 0 THEN
{ roots are represented by complex number }
BEGIN
fRootType := ComplexRoot;
check := -check;
f1stRoot := PositiveCalc(a, b, check);
f2ndRoot := NegativeCalc(a, b, check);
END;
END;
{------------------------------------------}
{$S ANonRes}
PROCEDURE TPlotDoc.ChangeBackColor(newColor: RGBColor);
VAR
oldPort: GrafPtr;
itsWindow: TWindow;
BEGIN
itsWindow := TView(fPlotDialog).GetWindow;
IF itsWindow <> NIL THEN
BEGIN
GetPort(oldPort);
SetPort(itsWindow.fWMgrWindow);
RGBBackColor(newColor);
itsWindow.ForceRedraw;
SetPort(oldPort);
END;
END;
{------------------------------------------}
{$IFC qDebug}
{$S AFields}
PROCEDURE TPlotDoc.Fields(PROCEDURE DoToField(fieldName: Str255;
fieldAddr: Ptr; fieldType: INTEGER)); OVERRIDE;
VAR
aStr : DecStr;
form : DecForm;
aReal: Real;
BEGIN
form.style := FloatDecimal;
form.digits := 6;
DoToField(‘TPlotDoc’, NIL, bClass);
aReal := faParam;
Num2Str(form,aReal,aStr);
DoToField(‘faParam’, @aStr, bString);
aReal := fbParam;
Num2Str(form,aReal,aStr);
DoToField(‘fbParam’, @aStr, bString);
aReal := fcParam;
Num2Str(form,aReal,aStr);
DoToField(‘fcParam’, @aStr, bString);
aReal := fstepParam;
Num2Str(form,aReal,aStr);
DoToField(‘fstepParam’, @aStr, bString);
DoToField(‘fxParam’, @fxParam, bInteger);
DoToField(‘fyParam’, @fyParam, bInteger);
DoToField(‘ Font’, @fPlotSpecs.theTextFont, bFontName);
DoToField(‘ Face’, @fPlotSpecs.theTextFace, bStyle);
DoToField(‘ Size’, @fPlotSpecs.theTextSize, bInteger);
INHERITED Fields(DoToField);
END;
{$ENDC}
{**********************************************}
{ T P l o t D i a l o g }
{**********************************************}
{$S }
PROCEDURE TPlotDialog.DismissDialog(
dismisser: IDType; flashDismisser: BOOLEAN);
OVERRIDE;
BEGIN
INHERITED DismissDialog(dismisser, flashDismisser);
END;
{------------------------------------------}
FUNCTION TPlotDialog.DoKeyCommand(ch: CHAR;
aKeyCode: INTEGER; VAR info: EventInfo): TCommand;
OVERRIDE;
BEGIN
{ If Enter is pressed, assume we have new
parameters and a new plot to create. }
IF (ch = chEnter) THEN
BEGIN
{we have everything we need, lets DOIT!}
PlotNDrawPICT;
{We did all the work no reason to
generate a command}
DoKeyCommand := gNoChanges; END
ELSE
DoKeyCommand := INHERITED
DoKeyCommand(ch, aKeyCode, info);
END;
{------------------------------------------}
FUNCTION TPlotDialog.DoMenuCommand(
aCmdNumber: CmdNumber): TCommand; OVERRIDE;
BEGIN
{ Plot Menu Command was chosen so create plot. }
IF (aCmdNumber = cPlotIt) THEN
BEGIN
PlotNDrawPICT; { we have everything, lets DOIT! }
DoMenuCommand := gNoChanges;
{ We did all the work no reason to generate a command}
END
ELSE
DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
END;
{------------------------------------------}
PROCEDURE TPlotDialog.DoSetupMenus; OVERRIDE;
BEGIN
Enable(cPlotIt, TRUE);
INHERITED DoSetupMenus;
END;
{------------------------------------------}
PROCEDURE TPlotDialog.Draw(area: Rect); OVERRIDE;
VAR
plotRect : Rect;
dontCare : BOOLEAN;
BEGIN
dontCare := fPlotView.Focus;
{ set the world up to focus all drawing
in the PlotView }
fPlotView.GetQDFrame(plotRect);
{ the design says we draw into the
available frame }
DrawPicture(fPlotPICT, plotRect);
{ Draw the PICT in the PlotView }
dontCare := SELF.Focus;
{ shift the focus back to us }
END;
{------------------------------------------}
PROCEDURE TPlotDialog.EachSubView(PROCEDURE DoToSubView(theSubView:
TView));
BEGIN
{ We do not want all of our clever
dialog elements printing so lets
skip them when printing }
IF NOT gPrinting THEN
INHERITED EachSubView(DoToSubView);
END;
{------------------------------------------}
PROCEDURE TPlotDialog.PlotNDrawPICT;
VAR
plotRect : Rect;
solveRect : Rect;
saveClip : RgnHandle;
pstate : PenState;
dontCare : BOOLEAN;
aFontNum : INTEGER;
BEGIN
GetPlotValues;
{ get current values from the view }
fPlotDoc.SolveQuadratic;
{ for the parameters retrieved, setup
the solution values }
IF fPlotPICT <> NIL THEN
KillPicture(fPlotPICT);
dontCare := fPlotView.Focus;
fPlotView.GetQDExtent(plotRect);
{ change MacApp’s focus to the plotview
to properly get our plot rect}
dontCare := SELF.Focus;
{ and of course lets set FOCUS back to us.
The above process of setting up plotRect
might have been better handleed by
declaring an fRect in plotview
and having the resize method of plotview
keep it up to date}

fPlotPICT := OpenPicture(plotRect);
saveClip := NewRgn;
FailNIL(SaveClip);
GetClip(SaveClip);
GetPenState(pstate);
{ setup the font info for our plot }
{$Push} {$H-}
GetFNum(fPlotDoc.fPlotSpecs.theTextFont, aFontNum);
{$H+}
TextFont(aFontNum);
TextSize(fPlotDoc.fPlotSpecs.theTextSize);
TextFace(fPlotDoc.fPlotSpecs.theTextFace);
{ we also have: theTextColor,
theJustification, theBackColor
that we might want to do something with
in the future }
TextMode(srcOr);
{Begin MacDraw Document PICT}
PicComment(picDwgBeg, 0, NIL);
PicComment(picGrpBeg, 0, NIL);
fPlotView.AddToPict(plotRect);
solveRect := fSolutionView.fSolveRect;
{ get our plot rect, we know that this
is a fixed rect}
offsetRect(solveRect,4{border},
plotRect.Bottom-(solveRect.Bottom+4{border}));
{ slide the textbox on down to the
bottom of the view area this assumes
that the solution textbox is smaller
than the plotRect}
fSolutionView.AddToPict(solveRect);
PicComment(PicGrpEnd, 0, NIL);
PicComment(picDwgEnd, 0, NIL);
ClosePicture;
SetPenState(pstate);
SetClip(saveClip);
DisposeRgn(saveClip);
ForceRedraw;
{ make the dialog rect invalid }
END;
{------------------------------------------}
PROCEDURE TPlotDialog.GetPlotValues;
BEGIN
fPlotDoc.faParam :=
TExtendedText(FindSubView(‘cofA’)).GetValue;
fPlotDoc.fbParam :=
TExtendedText(FindSubView(‘cofB’)).GetValue;
fPlotDoc.fcParam :=
TExtendedText(FindSubView(‘cofC’)).GetValue;
fPlotDoc.fstepParam :=
TExtendedText(FindSubView(‘step’)).GetValue;
fPlotDoc.fxParam :=
TNumberText(FindSubView(‘xAxs’)).GetValue;
fPlotDoc.fyParam :=
TNumberText(FindSubView(‘yAxs’)).GetValue;
END;
{------------------------------------------}
PROCEDURE TPlotView.GetQDFrame(VAR frameRect:Rect);
VAR
extent: VRect;
BEGIN
GetFrame(extent);
ViewToQDRect(extent, frameRect);
END;
{------------------------------------------}
PROCEDURE TPlotView.AddToPict(picRect:Rect);
CONST
AxisLabelIndent = 4;
TYPE
Widpt = Point;
WidPtr = ^WidPt;
WidHdl = ^WidPtr;
VAR
x, y : Real;
a,b,c : Real;
step : Real;
halfXScale : Real;
xPictScale : Real;
yPictScale : Real;
lastPt : Point;
thisPt : Point;
xScale : INTEGER;
yScale : INTEGER;
CenterHorz : INTEGER;
CenterVert : INTEGER;
PictHorz : INTEGER;
PictVert : INTEGER;
leading : INTEGER;
fInfo : FontInfo;
Width : Widhdl;
axisLabel : str255;
newColor : RGBColor;
oldBack : RGBColor;
oldFore : RGBColor;
drawLine : BOOLEAN;
BEGIN
Width := Widhdl(NewHandle(sizeof(widpt)));
Width^^.h := 10;
Width^^.v := 1;
GetFontInfo(fInfo);
leading := fInfo.descent
+ fInfo.ascent + fInfo.leading;
WITH fPlotDoc DO
BEGIN
{ retrieve the length of our Axis }
xScale := fxParam;
yScale := fyParam;
{ retrieve the coeficients }
a := faParam;
b := fbParam;
c := fcParam;
step := fStepParam;
END;
ClipRect(picRect);
GetForeColor(oldFore);
GetBackColor(oldBack);
PenNormal;
{Draw Graph Boundry}
PicComment(picGrpBeg, 0, NIL);
newColor := fPlotDoc.fPlotSpecs.theBackColor;
RGBBackColor(newColor);
PicComment(SetLineWidth,
GetHandleSize(Handle(Width)), Handle(Width));
FillRect(picRect, white);
FrameRect(picRect);
{Two Axis}
newColor := fPlotDoc.fPlotSpecs.theAxisColor;
RGBForeColor(newColor);
{ find height of our View we will draw into }
PictHorz := picRect.right - picRect.left;
PictVert := picRect.bottom - picRect.top;
{ find the center coordinates of the view }
CenterHorz := PictHorz DIV 2;
CenterVert := PictVert DIV 2;
PicComment(picGrpBeg, 0, NIL);
moveto(0, CenterVert);
line( PictHorz, 0);
moveto(CenterHorz, 0);
line(0, PictVert);
PicComment(picGrpEnd, 0, NIL);
newColor := fPlotDoc.fPlotSpecs.theGraphColor;
RGBForeColor(newColor);
{Axis Text}
{ Place -X axis label to the lowerleft of
the axis line }
moveto(AxisLabelIndent, CenterVert + leading);
NumToString(-xScale,axisLabel);
DrawString(axisLabel);
{ Place +Y axis label to the topleft of the
axis line }
NumToString(yScale,axisLabel);
moveto(CenterHorz - (StringWidth(axisLabel)
+ AxisLabelIndent), leading);
DrawString(axisLabel);
{ Place +X axis label to the lowerright
of the axis line }
NumToString(xScale,axisLabel);
moveto(PictHorz - (StringWidth(axisLabel)
+ AxisLabelIndent), CenterVert + leading);
DrawString(axisLabel);
{ Place -Y axis label to the lowerleft
of the axis line }
NumToString(-yScale,axisLabel);
moveto(CenterHorz - (StringWidth(axisLabel)
+ AxisLabelIndent), PictVert - leading);
DrawString(axisLabel);
{The Plot}
{ calculate a scale factor for the
PICT’s axis in the view }
xPictScale := PictHorz / xScale;
yPictScale := PictVert / yScale;
{ calculate our starting x,y point }
halfXScale := xScale / 2;
x := -halfXScale;
y := a * x * x + (b * x) + c;
{ Scale it into the PICT’s
(and PostScript’s) view space}
thisPt.h :=
integer(round(x * xPictScale))+CenterHorz;
thisPt.v :=
integer(round(-y * yPictScale))+CenterVert;
{ Find where to stop and start drawing.
LOOP until we reach all x values:
1. Find our first visible line segment
2. Plot until it disappears
3. Find a suitable end point
}
WHILE (NOT PtInRect(thisPt,picRect))
& (x <= halfXscale) DO
BEGIN
x := x + step;
y := a * x * x + (b * x) + c;
thisPt.h :=
integer(round(x * xPictScale))+CenterHorz;
thisPt.v :=
integer(round(-y * yPictScale))+CenterVert;
END;
moveTo(thisPt.h,thisPt.v);
drawLine := TRUE;
PicComment(picGrpBeg, 0, NIL);
REPEAT
x := x + step;
y := (a * x * x) + (b * x) + c;
thisPt.h :=
integer(round(x*xPictScale))+CenterHorz;
thisPt.v :=
integer(round(-y*yPictScale))+CenterVert;
IF NOT PtInRect(thisPt,picRect) THEN
drawLine := FALSE
ELSE
BEGIN
IF drawLine THEN
LineTo(thisPt.h,thisPt.v)
ELSE
BEGIN
drawLine := TRUE;
moveTo(thisPt.h,thisPt.v)
END
END;
UNTIL x >= halfXScale;
PicComment(picGrpEnd, 0, NIL);
RGBForeColor(oldFore);
RGBBackColor(oldBack);
PicComment(PicGrpEnd, 0, NIL); {of select all objects}
END;
{------------------------------------------}
PROCEDURE TPlotView.Resize(width,
height: VCoordinate; invalidate: BOOLEAN);
OVERRIDE;
BEGIN
invalidate := TRUE;
INHERITED Resize(width, height, invalidate);
ForceRedraw;
END;
{------------------------------------------}
{ Adds the text box containing the Quadratic equation solution to our
PICT. }
PROCEDURE TSolutionView.AddToPict(picRect: Rect);
CONST
k1stLine = 1; k2ndLine = 2; k3rdLine = 3;
k4thLine = 4; k5thLine = 5;
kLeftJust = 1;
kIndent = 2;
TYPE
Widpt = Point;
WidPtr = ^WidPt;
WidHdl = ^WidPtr;
TTxtPicRec = PACKED RECORD
tJus : Byte;
tFlip : Byte;
tRot : Integer;
tLine : Byte;
tCmnt : Byte;
END;
VAR
TextClipRgn : RgnHandle;
TxtPicRec : TTxtPicRec;
TxtPicPtr : QDPtr;
TxtPicHdl : QDHandle;
Width : WidHdl;
clipBox : Rect;
boxTop : INTEGER;
boxLeft : INTEGER;
leading : INTEGER;
fInfo : FontInfo;
LineNo : INTEGER;
a,b,c : Real;
x1,x2 : Real;
z1,z2 : Real;
newColor : RGBColor;
BEGIN
WITH fPlotDoc DO
BEGIN
{ retrieve the Solution }
x1 := f1stRoot;
x2 := f2ndRoot;
{ retrieve the coeficients }
a := faParam;
b := fbParam;
c := fcParam;
END;
Width := Widhdl(NewHandle(sizeof(widpt)));
Width^^.h := 10;
Width^^.v := 1;
GetFontInfo(fInfo);
leading := fInfo.descent + fInfo.ascent + fInfo.leading;
PicComment(picGrpBeg, 0, NIL);
{Box }
PicComment(picGrpBeg, 0, NIL);
PicComment(SetLineWidth,
GetHandleSize(Handle(Width)),
Handle(Width));
fillRect(picRect, white);
frameRect(picRect);
PicComment(picGrpEnd, 0, NIL); {of box}
TextClipRgn := NewRgn;
FailNil(TextClipRgn);
GetClip(TextClipRgn);
clipBox := picRect;
ClipRect(clipBox);
newColor := fPlotDoc.fPlotSpecs.theTextColor;
RGBForeColor(newColor);
{Box Text}
{ setup our Text Comment Handle }
TxtPicPtr := @TxtPicRec;
TxtPicHdl := @TxtPicPtr;
TxtPicRec.tJus := kLeftJust;
TxtPicRec.tFlip := 0; {no flip}
TxtPicRec.tRot := 0; {no rotation}
TxtPicRec.tLine := 2; {1 1/2 spacing}
{put the Comment into our PICT}
PicComment(TextBegin, sizeof(TTxtPicRec), Handle(TxtPicHdl));
{ Add the BOX text to the PICT }
boxTop := picRect.top;
boxLeft:= picRect.Left;
MoveTo(boxLeft + kIndent,
boxTop + (k1stLine * leading));
DrawString(CONCAT(‘y=ax^2 + bx + c’, chr(13)));
MoveTo(boxLeft + kIndent,
boxTop + (k2ndLine * leading));
DrawString(CONCAT( ‘a=’, Real2Str(a,1), ‘, b=’,
Real2Str(b,1), ‘, c=’, Real2Str(c,1), chr(13)));

{ The solution text is next }
MoveTo(boxLeft + kIndent,
boxTop + (k3rdLine * leading));
DrawString(CONCAT( ‘x1=’, Real2Str(x1,3),
‘, x2=’, Real2Str(x2,3), chr(13)));
{ Display kind of Quadratic we have }
MoveTo(boxLeft + kIndent,
boxTop + (k4thLine * leading));
CASE fPlotDoc.fRootType OF
RealRoots :
DrawString(CONCAT(‘Two Real Roots, x1, x2’,
chr(13)));
SingleSolution :
DrawString(CONCAT(‘Double Root’, chr(13)));
ComplexRoot :
DrawString(CONCAT(‘Two Complex Roots ‘,chr(13)));
OTHERWISE
;
END;
{ Calculate the slope and add the
string it to the PICT}
WITH fPlotDoc DO
BEGIN
z1 := -b / (2 * a);
z2 := (4 * a * c - (b * b)) / (4 * b);
END;
MoveTo(boxLeft + kIndent,
boxTop + (k5thLine * leading));
DrawString(CONCAT(‘Slope 0 is (‘,
Real2Str(z1,1),’,’, Real2Str(z2,1),’)’,
chr(13)));
{ All done with our text }
PicComment(TextEnd, 0, NIL);
PicComment(PicGrpEnd, 0, NIL); {of Box & text}
DisposHandle(Handle(width));
DisposeRgn(TextClipRgn);
END;
{------------------------------------------}
PROCEDURE TPStyleCmd.DoIt;
BEGIN
fPlotDialog.fPlotDoc.fPlotSpecs := fNewPlotSPecs;
END;
{------------------------------------------}
PROCEDURE TPStyleCmd.ReDoIt;
BEGIN
fPlotDialog.fPlotDoc.fPlotSpecs := fNewPlotSPecs;
END;
{------------------------------------------}
PROCEDURE TPStyleCmd.UnDoIt;
BEGIN
fPlotDialog.fPlotDoc.fPlotSpecs := fOldPlotSPecs;
END;
{------------------------------------------}
PROCEDURE TPStyleCmd.IPStyleCmd(itsPlotDialog: TPlotDialog;
itsNewStyle: PlotSpecsPtr; itsCmdNumber: CmdNumber);
BEGIN
ICommand(itsCmdNumber, itsPlotDialog.fPlotDoc,
itsPlotDialog, NIL);
fPlotDialog := itsPlotDialog;
fOldPlotSPecs:=fPlotDialog.fPlotDoc.fPlotSpecs;
fNewPlotSPecs:=itsNewStyle^;
END;
END.
MPlot.p Main Program FILE
{•••••••••••••••••••••••••••••••••••••••••••••••}
Program Plot;
USES
{ • MacApp }
UMacApp,
{ • Building Blocks }
UDialog, UPrinting,
{ • Implementation Use }
SANE, ToolUtils, Fonts, Resources,
Script, PickerIntf, Packages,
{ • the PlotUNIT }
UPlot;
VAR
gPlotApplication: TPlotApplication;
{The application object:}
{----------------------------------------------}
{ T H E M A I N P R O G R A M }
BEGIN
InitUMacApp(8);
{Initialize the Toolbox,
making 8 calls to MoreMasters:}
InitPrinting;
{Initialize the UPrinting unit:}
NEW(gPlotApplication);
{Allocate a new TPlotApplication object:}
FailNIL(gPlotApplication);
gPlotApplication.IPlotApplication(kFileType);
{Initialize that new object:}
gPlotApplication.Run;
{Run the application.
When it’s done, exit.}
END.
PLOT.r-Plot resource FILE
/* Copyright © 1988-1989 Apple Computer, Inc.
All rights reserved. */
/* Copyright © 1989 Software Architects, Inc.
All rights reserved. */
#if qDebug
include “Debug.rsrc”;
#endif
include “MacApp.rsrc”;
include “Dialog.rsrc”;
include “Printing.rsrc”;
include “Plot” ‘CODE’;
#define kPlotView 1010
#define kViewRsrcID 1005
resource ‘seg!’ (256, purgeable) {
{
“GOpen”;
“GClose”;
“GNonRes”;
“GSelCommand”
}
};
resource ‘SIZE’ (-1) {
dontSaveScreen,
acceptSuspendResumeEvents,
enableOptionSwitch,
canBackground,
MultiFinderAware,
backgroundAndForeground,
dontGetFrontClicks,
ignoreChildDiedEvents,
is32BitCompatible,
reserved,
reserved,
reserved,
reserved,
reserved,
reserved,
reserved,
#if qDebug
368 * 1024, /* ??? BALLPARK GUESSES ????? */
320 * 1024
#else
(300-32) * 1024, /* ??? BALLPARK GUESSES ?? */
(200-32) * 1024
#endif
};
resource ‘DITL’ (201, purgeable) {
{
/* [1] */
{160, 182, 180, 262}, Button { enabled, “OK” };
/* [2] */
{10, 75, 150, 316}, StaticText { disabled,
“This is an implementation of the MacTutor Plotter Program.”
“\n\n written “
“with MacApp® © 1985-1989 Apple Computer, Inc.”};
/* [3] */ {10, 20, 42, 52}, Icon { disabled, 1 }
}
};
resource ‘ALRT’ (1000, purgeable) {
{44, 48, 130, 358},
1000,
{
OK, visible, sound1,
OK, visible, sound1,
OK, visible, sound1,
OK, visible, sound1
}
};
resource ‘ALRT’ (201, purgeable) {
{90, 100, 280, 412},
201,
{
OK, visible, silent;
OK, visible, silent;
OK, visible, silent;
OK, visible, silent
}
};
resource ‘cmnu’ (1) {
1,
textMenuProc,
0x7FFFFFFD,
enabled,
apple,
{
/* [1] */
“About Plotter”, noIcon, noKey, noMark, plain, cAboutApp;
/* [2] */
“-”, noIcon, noKey, noMark, plain, nocommand
}
};
resource ‘cmnu’ (2) {
2,
textMenuProc,
0x7FFFEEFB,
enabled,
“File”,
{
“New”, noIcon, “N”, noMark, plain, cNew;
“Open”, noIcon, “O”, noMark, plain, cOpen;
“-”, noIcon, noKey, noMark, plain, nocommand;
“Close”, noIcon, noKey, noMark, plain,cClose;
“Save”, noIcon, “S”, noMark, plain, cSave;
“Save As”, noIcon,noKey,noMark,plain, cSaveAs;
“Save a Copy In”,
noIcon,noKey,noMark,plain, cSaveCopy;
“Revert”,noIcon,noKey,noMark,plain, cRevert;
“-”, noIcon, noKey, noMark, plain,
nocommand;
“Page Setup”,
noIcon,noKey,noMark,plain,cPageSetup;
“Print”,noIcon,noKey,noMark,plain, cPrint;
“-”, noIcon, noKey, noMark, plain, nocommand;
“Quit”, noIcon, “Q”, noMark, plain, cQuit
}
};
resource ‘cmnu’ (3) {
3,
textMenuProc,
0x7FFFFFBD,
enabled,
“Edit”,
{
“Undo”, noIcon, “Z”, noMark, plain, cUndo;
“-”, noIcon, noKey, noMark, plain, nocommand;
“Cut”, noIcon, “X”, noMark, plain, cCut;
“Copy”,noIcon, “C”, noMark, plain, cCopy;
“Paste”,
noIcon, “V”, noMark, plain, cPaste;
“Clear”,
noIcon, noKey, noMark, plain, cClear;
“-”, noIcon, noKey, noMark, plain, nocommand;
“Show Clipboard”,
noIcon, noKey, noMark, plain, cShowClipboard
}
};
/* Hierarchical menu with Style, Size & Font submenus */
resource ‘cmnu’ (7) {
7,
textMenuProc,
allEnabled,
enabled,
“MacAppPlot”,
{
“Plot”, noIcon, noKey, noMark, plain, 1401;
“-”, noIcon, noKey, noMark, plain, nocommand;
“Style”, noIcon, “\0x1B”, “\0x08”, plain, 2401;
“Size”, noIcon, “\0x1B”, “\0x09”, plain, 2402;
“Font”, noIcon, “\0x1B”, “\0x0A”, plain, 2403;
“Color”, noIcon, “\0x1B”, “\0x0B”, plain, 2404
}
};
/* Hierarchical Style Sub-menu */
resource ‘cmnu’ (8) {
8,
textMenuProc,
allEnabled,
enabled,
“Style”,
{
“Plain Text”, noIcon, “P”, noMark, plain, 2001;
“Bold”, noIcon, “B”, noMark, bold, 2002;
“Italic”, noIcon, “I”, noMark, italic, 2003;
“Underline”, noIcon, “U”, noMark, underline, 2004;
“Outline”, noIcon, “O”, noMark, outline, 2005;
“Shadow”, noIcon, “S”, noMark, shadow, 2006;
“Condensed”, noIcon, noKey, noMark, condense, 2007;
“Extended”, noIcon, noKey, noMark, extend, 2008;
“-”, noIcon, noKey, noMark, plain, nocommand;
“Left justified”,noIcon, noKey,noMark,plain,2201;
“Center justified”,noIcon,noKey,noMark,plain,2202;
“Right justified”,noIcon, noKey,noMark,plain,2203
}
};
/* Hierarchical Size Sub-menu */
resource ‘cmnu’ (9) {
9,
textMenuProc,
AllEnabled,
enabled,
“Size”,
{
“ 9 Point”, noIcon, noKey, noMark, plain, 2109;
“10 Point”, noIcon, noKey, noMark, plain, 2110;
“12 Point”, noIcon, noKey, noMark, plain, 2112;
“14 Point”, noIcon, noKey, noMark, plain, 1114;
“18 Point”, noIcon, noKey, noMark, plain, 1118;
“24 Point”, noIcon, noKey, noMark, plain, 1124;
“-”, noIcon, noKey, noMark, plain, nocommand;
“Grow selection”, noIcon, “]”, noMark, plain, 1198;
“Shrink selection”, noIcon, “[“,noMark,plain, 1199
}
};
/* Font menu for hierarchical or non-hierarchical system */
resource ‘MENU’ (10) {
10,
textMenuProc,
allEnabled,
enabled,
“Font”,
{ }
};
resource ‘cmnu’ (11) {
11,
textMenuProc,
allEnabled,
enabled,
“Color”,
{
“Set Graph Color”, noIcon, noKey, noMark, plain, 2503;
“Set Axis Color”, noIcon, noKey, noMark, plain, 2504;
“Set Text Color”, noIcon, noKey, noMark, plain, 2501;
“Set Background Color”, noIcon, noKey, noMark, plain, 2502
}
};
resource ‘cmnu’ (128) {
128,
textMenuProc,
allEnabled,
enabled,
“Buzzwords”,
{
“Style Change”,
noIcon, noKey, noMark, plain, cStyleChange;
“Size Change”,
noIcon, noKey, noMark, plain, 2100;
“Justification Change”,
noIcon, noKey, noMark, plain, 2200;
“Font Change”,
noIcon, noKey, noMark, plain, 2300;
“Color Change”,
noIcon, noKey, noMark, plain, 2500;
“Page Setup Change”,
noIcon, noKey, noMark, plain,
cChangePrinterStyle
}
};
/* Displayed menus on a non-hierarchical system */
resource ‘MBAR’ (128) {
{1; 2; 3 ; 8; 9; 10; 11}
};
/* Displayed menus on an hierarchical system */
resource ‘MBAR’ (131) {
{1; 2; 3; 7}
};
/* Hierarchial Sub-Menus */
resource ‘MBAR’ (130) {
{8; 9; 10; 11}
};
resource ‘STR#’ (1001, purgeable) {
{
“Select a new text color”,
“Select background color
“Select graph line color
“Select axis color
}
};
/* a resource for picking up default text,
graph and color info */
resource ‘view’ (kViewRsrcID, purgeable) {{
root, ‘TEVW’, { 0, 0 }, { 116, 1020 },
sizeVariable, sizePage, shown, enabled,
TEView { “TTEView”,
withStyle, autoWrap, acceptChanges,
dontFreeText, cTyping, unlimited,
{ 8, 10, 0, 10 },
justLeft, plain, 9, {0, 0, 0}, “Geneva” }
} };
PLOT.VE.r-Plot View resource FILE
resource ‘view’ (1010, purgeable) {
{
root, ‘WIND’,
{50, 40},
{310, 380}, sizeVariable, sizeVariable,
notShown, enabled,
Window {
“TWindow”,
zoomDocProc,goAwayBox,resizable,
modeless,ignoreFirstClick,
dontFreeOnClosing,disposeOnFree,
closesDocument,OpenWithDocument,
AdaptToScreen,Stagger,ForceOnScreen,
dontCenter,’cofA’,
“Plot <<<>>>”
},
‘WIND’, ‘DLOG’,
{0, 0},{240, 294},
sizeSuperView, sizeSuperView, shown, disabled,
DialogView {
“TPlotDialog”,
noID,
noID
},
‘DLOG’, ‘Ccof’,
{2, 5},{90, 96}, sizeFixed, sizeFixed, shown, disabled,
Cluster {
“TCluster”,
0b0,{1, 1},sizeable,notDimmed,notHilited,
doesntDismiss,{0, 0, 0, 0},
plain,12,{0x0,0x0,0x0},
“Helvetica”,
“Coefficients”
},
‘Ccof’, ‘cofA’,
{15, 36},{20, 44}, sizeFixed, sizeFixed, shown, enabled,
ExtendedText {
“TExtendedText”,
0b1101,{1, 1},sizeable,notDimmed,notHilited,
doesntDismiss,{2, 2, 2, 2},
plain,0,{0x0,0x0,0x0},
“”,
justLeft,”1",unlimited,
0b11111000000000000000000100000000,
-10000,10000,2,”1.0
},
‘Ccof’, ‘cofB’,
{38, 36}, {20, 44}, sizeFixed, sizeFixed, shown, enabled,
ExtendedText {
“TExtendedText”,
0b1101,{1, 1},sizeable,notDimmed,notHilited,
doesntDismiss,{2, 2, 2, 2},
plain,0,{0x0,0x0,0x0},
“”,
justLeft,”5",unlimited,
0b11110000000000000000000100000000,
-10000,10000,2,”5.0
},
‘Ccof’, ‘cofC’,
{62, 36},
{20, 44}, sizeFixed, sizeFixed, shown, enabled,
ExtendedText {
“TExtendedText”,
0b1101,{1, 1},sizeable,notDimmed,notHilited,
doesntDismiss,{2, 2, 2, 2},
plain,0,{0x0,0x0,0x0},
“”,
justLeft,”2",unlimited,
0b11110000000000000000000100000000,
-10000,10000,2,”2.0
},
‘Ccof’, ‘VW13’,
{15, 10},
{20, 26}, sizeFixed, sizeFixed, shown, disabled,
StaticText {
“TStaticText”,
0b111,{1, 1},notSizeable,notDimmed,
notHilited,doesntDismiss,{0, 0, 0, 0},
plain,0,{0x0,0x0,0x0},
“”,
justRight,
“a = “
},
‘Ccof’, ‘VW14’,
{38, 10},
{20, 26}, sizeFixed, sizeFixed, shown, disabled,
StaticText {
“TStaticText”,
0b111,{1, 1},notSizeable,notDimmed,
notHilited,doesntDismiss,{0, 0, 0, 0},
plain,0,{0x0,0x0,0x0},
“”,
justRight,
“b =”
},
‘Ccof’, ‘VW15’,
{62, 10},
{20, 26}, sizeFixed, sizeFixed, shown, disabled,
StaticText {
“TStaticText”,
0b111,{1, 1},notSizeable,notDimmed,
notHilited,doesntDismiss,{0, 0, 0, 0},
plain,0,{0x0,0x0,0x0},
“”,
justRight,
“c =”
},
‘DLOG’, ‘Cdsp’,
{95, 5},
{139, 96}, sizeFixed, sizeFixed, shown, disabled,
Cluster {
“TCluster”,
0b0,{1, 1},sizeable,notDimmed,
notHilited, doesntDismiss,{0, 0, 0, 0},
plain,12,{0x0,0x0,0x0},
“Helvetica”,
“Display”
},
‘Cdsp’, ‘step’,
{26, 36},
{20, 40}, sizeFixed, sizeFixed,shown, enabled,
ExtendedText {
“TExtendedText”,
0b1111,{1, 1},sizeable,notDimmed,
notHilited, doesntDismiss,{2, 2, 2, 2},
plain,0,{0x0,0x0,0x0},
“”,
justRight,”1",unlimited,
0b11110000000000000000000100000000, 0, 10, 2, “0.25”
},
‘Cdsp’, ‘xAxs’,
{66, 17},
{20, 60}, sizeFixed, sizeFixed,
shown, enabled,
NumberText {
“TNumberText”,
0b1111,{1, 1},sizeable,notDimmed,
notHilited, doesntDismiss,{2, 2, 2, 2},
plain,0,{0x0,0x0,0x0},
“”,
justRight,”10",unlimited,
0b11110000000000000000000100000000,10, 1, 1000
},
‘Cdsp’, ‘yAxs’,
{106, 17},
{20, 60}, sizeFixed, sizeFixed, shown, enabled,
NumberText {
“TNumberText”,
0b1111,{1, 1},sizeable,notDimmed,
notHilited, doesntDismiss,{2, 2, 2, 2},
plain,0,{0x0,0x0,0x0},
“”,
justRight,”20",unlimited,
0b11110000000000000000000100000000,20, 1, 1000
},
‘Cdsp’, ‘VW17’,
{13, 31},
{12, 40}, sizeFixed, sizeFixed, shown, disabled,
StaticText {
“TStaticText”,
0b0,{1, 1},notSizeable,notDimmed,
notHilited, doesntDismiss,{0, 0, 0, 0},
plain,9,{0x0,0x0,0x0},
“Helvetica”,
justCenter,
“step”
},
‘Cdsp’, ‘VW18’,
{54, 17},
{12, 60}, sizeFixed, sizeFixed, shown, disabled,
StaticText {
“TStaticText”,
0b0,{1, 1},notSizeable,notDimmed,
notHilited, doesntDismiss,{0, 0, 0, 0},
plain,9,{0x0,0x0,0x0},
“Helvetica”,
justCenter,
“X AXIS”
},
‘Cdsp’, ‘VW19’,
{93, 17},
{12, 60}, sizeFixed, sizeFixed, shown, disabled,
StaticText {
“TStaticText”,
0b0,{1, 1},notSizeable,notDimmed,
notHilited,doesntDismiss,{0, 0, 0, 0},
plain,9,{0x0,0x0,0x0},
“Helvetica”,
justCenter,
“Y AXIS”
},
‘DLOG’, ‘sclr’,
{0, 104}, {225, 175},
sizeRelSuperView, sizeRelSuperView, shown, enabled,
Scroller {
“TScroller”,
VertScrollBar,HorzScrollBar,
0,0,16,16,
noVertConstrain,noHorzConstrain,{0, 0, 0, 0}
},
‘sclr’, ‘plot’,
{0, 0}, {400, 400}, sizeSuperView, sizeSuperView,
shown, enabled,
View {“TPlotView”},
‘plot’, ‘qslv’,
{325, 0}, {75, 160},sizeFixed,sizeFixed, shown, enabled,
View {“TSolutionView”}}
};