|
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.0ß8 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 Taken Total in New % of New
Input/Output 181 211 86
Interaction 0 108 0
Other 0 221 0
Processing 48 48 100
User Interface 0 117 0
Totals 229 705 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 kPlotView1010 #define kViewRsrcID1005 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”}} };
- SPREAD THE WORD:
- Slashdot
- Digg
- Del.icio.us
- Newsvine