Object Shell 1
Volume Number: | | 6
|
Issue Number: | | 8
|
Column Tag: | | MacOOPs!
|
Object Shell, Part I
By Dr. Christian Stratowa, Vienna, Austria
Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.
[C. S. started his scientific career as a nuclear physicist (where he has made his Ph.D.), which involved a lot of programming on mainframes. Later on his interests changed, and he moved to Germany to start a career in molecular biology. Beginning 1984, he spent two years at UCSF in San Francisco, where he bought his first Macintosh and became a Mac-addict. Back in Austria he is currently working in the gene technology department of an international pharmaceutical company.]
Part1: Objects, Objects Everywhere!
If you dont learn object-oriented programming now, you will not be able to program the Macintosh later. I think this statement from the technical editor of Apple Direct, a monthly newsletter from Apple Developer Services, is a good way to start my article. It is also supposed to answer your obvious question why present here another shell program although MacTutor has already published so many shells. But this is only part of the story.
I really enjoy reading MacTutor, although as someone who does not have so much time to program the Mac, I find it often hard to follow all the exciting advanced stuff. Maybe others feel like me. Therefore I decided to write a program for a bimp (advanced beginner in Mac programming) which should be useful as a basis to build more advanced applications. However, when I started to write my own shell I found none of the published code really satisfiable, including the one I had put (i.e. stolen) together from different articles and books. Therefore I decided to restart from the very beginning. Besides that, I may be a little old fashioned but as someone who has started programming back in the bad old days on an IBM 1130 mainframe with 16 k(!)byte core memory (do you remember this word?), I prefer to understand every bit of code, and the best way is still to write your own. So here it is. Using OOPS (object oriented programming style) it is a fairly complete shell program written in Object Pascal (not MacApp, which I dont have, but using mainly LS-Pascal 2.0 and sometimes TML Pascal II running under MPW), which contains the following features:
All menus, windows, scrollbars, documents and dialogs are defined as objects which are kept in separate units (e.g. StdMenus, MyMenus, StdWindows, MyDocuments). These units are put together as building blocks to make the final program. Therefore to develop your own application you only need to exchange or modify the units of interest or add your own units (e.g. MyWindows), without changing any code in other units or in the main program.
The program contains a texteditor with Font, Size, Style and Justification submenus (using old Textedit) and a graphics demo program (drawing ovals, spirals). For both text and graphics fore- and background color can be selected from submenus (using old style QuickDraw).
An unlimited number of windows can be opened. Text and graphics windows can be open at the same time with the menubar changing dependent on the type of Frontwindow.
In a submenu you can decide if the window should contain only a grow box or also horizontal and/or vertical scrollbars. To be able to scroll one line a time, an initial scroll delay is established.
Cut, Copy and Paste is established between different text windows and different graphics windows (but not between text and graphics windows, which would probably be an article by itself).
The program can save and open TEXT and PICT documents, whereby PICT documents are saved with a 512 byte header so that MacDraw can open them too. (The program can even open and save MacDraw documents which were saved as PICT files.)
Both TEXT and PICT documents can be printed on an ImageWriter or LaserWriter using the standard PageSetup and Print dialog boxes.
All Dialog and Alert boxes are automatically centered for every screen size used.
Documents can be opened from the Finder by double-clicking.
Multifinder is supported.
Program, Text and Pict documents have their own icons.
Although ObjectShell should even run on an old 64k ROM Mac when you dont use hierarchical menus in unit MyMenus, I have only tested it on a Mac SE or II using System 6.02, and printing on an ImageWriter (I and LQ) or a LaserWriter (Plus and II NTX).
I hope this ObjectShell program, shown in Fig.1, will be a good starting point for the beginning Mac programmer, which s/he could easily modify to write her/his own applications. However, it should be clear by now, that there is no way to write a program for the Mac without having at least the five volume set of Inside Macintosh (IM). It would also be a good idea to have some of the books covering programming on the Mac. A good starting point is to buy Steven Chernicoffs Macintosh Revealed (MR), which does at the moment (June 1989) consist of three volumes. Last but not least, subscribing to MacTutor (MT) is a must! Supposing, that you have now everything you need, lets begin to cover the most important features of ObjectShell.
The World of Objects
Almost everything in the world is an object, a house, a door, windows, even more abstract things like documents or menus. Our brain does even treat the stuff it sees on our Macscreen like menus, windows or scrollbars as different objects. So it seems quite naturally to handle these things already during program development as objects, which can communicate together. This is the philosophy behind object oriented programming. Each object does have its own kind of behavior, which can be inherited by sub-objects, and can send messages to other objects.
In Object Pascal you define an object of type window the following way:
{1}
type
TWindow = object(TObject)
fWPtr: WindowPtr;
procedure DoOpen;
end;
var
oWindow: TWindow;
Here fWPtr is a field variable like the ones in a Pascal record, and DoOpen is a method. As you can see, in Pascal an object is simply the natural extension of a record. The actual variable you use is called oWindow. Let me state here the first important point: Never forget, that oWindow is not the object itself but a handle to object TWindow! (Actually its called object reference variable.) Therefore you have first to create an object before you can use its fields and methods:
{2}
New(oWindow);
oWindow.fWPtr:= ....;
oWindow.DoNew;
Actually, to be able to use variable oWindow throughout my code, regardless of the type of window I want to use, i.e. class TWindow or any of its subclasses (descendants) TGrowWindow, TScrollWindow, etc. I create most of the objects the following way:
{3}
var
oWindow: TWindow;
begin
New(TScrollWindow(oWindow));
...
oWindow.DoOpen;
...
end;
This sets oWindow to the window type I want and has the advantage, that further code can use variable oWindow without a need to know which subclass of type TWindow (e.g. TScrollWindow) we are definitively using. (Sorrowly, this elegant way can not be used in TML-Pascal II. You have first to create a temporary variable for each subclass and then set oWindow equal to this variable.)
After we have called a method from outside, that method begins to execute, and we are inside the object. From within a method it is not only possible to call other methods of that object (self.Do...) but we can also take advantage of a feature called inheritance. This has the advantage that you often need only add the code specific to the subclass that overrides a method of its ancestor. In our example:
{4}
procedure TScrollWindow.DoOpen;
begin
self.DoNew;
inherited DoOpen;
{code specific to subclass}
end;
Before a scrollwindow can be opened, it has to be created with method self.DoNew. To open it, first the method of its immediate ancestor is executed and then the subclass specific code.
Once you have understood the concept of objects you may find it much easier to write your own code that way. At least this was true for me. For a deeper coverage of objects see earlier issues of MacTutor (MT 12/86, 2/87, 8/87).
Globals and the Main Program
As I have already said earlier ObjectShell is made of self-contained units, which serve as building blocks to put together the final application, as shown in Fig.2 and 3. At the top is unit GlobalStuff which does not only contain all global constants and variables but also some procedures, which can be used throughout the program. The main unit, program ObjectShell, is located at the bottom level.
The constants at the beginning of unit GlobalStuff are diverse program parameters and can be changed by the programmer to fit her/his own needs. As an example it is possible to limit the number of windows the application can open at once to four by setting kMaxWindows=4. With kWindowKind you can determine if your window should only have a growbox or also horizontal and/or vertical scroll bars. (In our demonstration shell this choice is left to the user.) Similarly, kMaxEditItems is the maximum number of editable text fields in any of the dialog boxes we are using.
By the way, for better readability of my code I use following conventions for constants and variables:
kName ... global constant
cName ... local constant
gName ... global variable
vName ... local variable
uName ... variable global within unit
oName ... object type variable
fName ... field variable of object or record
The main unit, program ObjectShell itself is designed as general as possible. More specific code is handled in units StdMenus and StdWindows, and application-specific code in units MyMenus, MyDocuments (and if you design your own windows, in unit MyWindows). Therefore, under normal circumstances there should not be any need to change this code when you adopt ObjectShell to your own needs.
The main program does first call routines to initialize the Mac, different globals, printing, and menus, and does then call CheckFinder in case ObjectShell has been launched by double-clicking a document or by selecting a number of documents and choosing Open from the Finder. When you select more than one document to open from the Finder, procedure CheckFinder has to take care that the previously opened window will be deactivated properly before creating a new window for the next document. We have therefore to force a deactivation event to make sure the scrollbars are unhighlited. Try to open some MacDraw documents together from the Finder to see that this is not an obvious feature.
The heart of every Mac program is the main event loop, which repeats until gDone returns TRUE, at which time procedure ShutDown is called to dispose of all handles and regions still in use. The main event loop keeps track, if we press a key or the mouse button, if a window needs to be activated or updated, or if other events have occurred. For example, procedure DoDiskEvent makes sure that our program is able to initialize new disks.
Lets suppose we have clicked in the menubar. Procedure DoMouseDown does then call DoMenuClick, which checks if we have clicked in one of the standard menus (Apple, File, Edit) every application should support (ClickInStdMenus), or in one of the menus specific to our application (ClickInMyMenus). At this point you can see, that both the routines for setting up menus (InitStdMenus, InitMyMenus) and for selecting a menu (ClickInStdMenus, ClickInMyMenus) are implemented in the appropriate units StdMenus and MyMenus, respectively. So lets first talk about menus.
Attaching Menus
Menus are implemented as objects in unit StdMenus. Class TMenu does contain a menuhandle fMenuHdl as field variable and two self-explanatory methods Create and Choose. Subclass TAppleMenu does contain an additional variable and method for the About...box (see MT 6/88 p.85).
In addition to InitStdMenus and ClickInStdMenus three other global procedures do exist. SetStdMenuItems keeps track of the state of the menus, e.g. vMaxWFlag will disable New in the File menu if the number of windows open equals kMaxWindows. It is called immediately before calling MenuSelect or MenuKey, since these are the only times the user can see the menu items. DisposeStdMenus is called at ShutDown, although I dont know if it is really necessary. However, it is always a good programming habit to dispose of all handles yourself. Finally, procedure DoNew, which is normally called from TFileMenu.Choose, must also be made accessible to procedure CheckFinder to be able to supply a window when the user opens a document directly from the Finder.
Windows to the World
Most computers have only one window to display information to the user, the whole screen. This has also been true for the Mac when it became alive the first time by displaying the words Hello World on Burell Smiths screen. Since then the Mac has changed the way people are using computers. Having covered already menus, lets now see how to handle windows. (Always refer to Inside Macintosh or Macintosh Revealed for additional information!)
Analogous to menus we are defining windows as objects in unit StdWindows. A window consists of the window frame containing title bar, drag region and close region, and the content region, the area our application draws in. When defining object TWindow we divide this content region into a control region (fControlRgn), where growbox, scroll bars and maybe other controls can be placed, and a display region (fDisplayRgn), where the contents of field oDocument are drawn. Placing object oDocument as field variable in TWindow has the advantage that each document is automatically attached to the window it belongs to. In the same way we attach scroll bars oHBar and oVBar to TScrollWindow. (This is a good example of the power and elegance of object oriented programming.)
Once handle oWindow is created in DoNew in unit StdMenus, procedure TWindow.DoNew will create the actual window with Toolbox function NewWindow. Most of the window parameters are set in method Initialze, only its port rectangle is calculated in function NewRect, which takes care that further windows will be offset by kWOffset (see Fig.1). After having created the windowpointer fWPtr, we set the window reference constant to self, which is the reference value of the object calling the method. This will enable us later to find the window connected with windowpointer vWPtr by calling:
{5}
oWindow:= TWindow(GetWRefCon(vWPtr));
This statement will be used by us whenever we need to know which window to work with. After defining windows control and display region, we finally create the document oDocument attached to the window. Let me state here again, that once created in this way, further coding can be done without knowing the type of document that has to be handled.
When you click the mouse in a window method ClickInWindow will determine in which part of the window the mouse button was pressed, in grow box, scroll bars, drag region, zoom box or within the document. But before the desired action will be executed the window has to be activated.
Activate and Update Events
Activate events take priority over all others. Procedure DoActivate in the main program extracts the window pointer from gEvent.message and calls oWindow.Activate, which sets the new GrafPort. The current port will be changed permanently only here! Depending on the window subclass method Activate will also redraw the Growbox icon and take care, that the scroll bars are highlighted properly.
In contrast to activate events update events have the lowest priority. After extracting the window pointer in DoUpdate, TWindow.Update makes the window the current port, calls BeginUpdate, redraws the window contents and finally calls EndUpdate [see IM I-279]. BeginUpdate temporarily restricts the visible region to the portion of the window that needs redrawing. First we clip to fControlRgn and call DrawGrowIcon and DrawControls. Then we clip to and erase fDisplayRgn and do the actual updating before resetting to the port rectangle. (We will treat updating pictures in more detail in the second part of our article.) Finally, EndUpdate restores the normal visRgn.
The Secret of Resizing Windows
I have played around a lot to find out the best code to resize windows. Although the simplest way would be to resize the window and to invalidate its portRect afterwards therefore updating the whole window, this would mean that e.g. a picture would always be redrawn completely, which could take quite a time in the case of complex pictures. Furthermore, in case you enlarge the window, you would see the scroll bars for a moment within the window. Many of you have probable experienced just this behavior when using MacDraw. To avoid this I have coded method Grow the following way:
After calling GrowWindow to get the new window size I check if the window will be enlarged or made smaller by setting a horizontal and vertical flag. In case the window is enlarged I erase first fControlRgn to prevent scroll bars from cluttering the window and invalidate then fControlRgn before calling SizeWindow; in case it was made smaller I erase and invalidate fControlRgn afterwards only (see Fig.4). That this is the best way to do is also clearly stated in [IM I-292, Figure 10]. Procedure self.ReDrawContent called immediately after ResizeWindow calculates the new sizes of fControlRgn and fDisplayRgn before calling oDocument.ReDraw to redraw the actual document. In this way only the newly exposed part of the window will be updated. That this cannot always be done, is also shown in our application: Because we can change Font, Size etc. of TEXT documents, we have to call TECalText and invalidate fViewRgn afterwards. The same holds true for our PICT documents, where we are able to change fore- and background colors. Try to delete InvalRgn(fViewRgn) at end of TPictDocument.ReDraw and look what happens when you change colors first and enlarge the window afterwards.
For TScrollWindow method ReDrawContent does also calculate the new scrollbar sizes using variable uRect. However, in TScrollBar.ReDraw, uRect is used differently. TopLeft is used to move scroll bars to their new positions, BottomRight to resize them.
Sorrowly, zooming cannot be handled the same way as growing because Toolbox procedure ZoomWindow seems to invalidate always windows complete portRect. Therefore I erase the portRect only before calling ZoomWindow. No invalidating would be needed to be done by us.
A Problem called Scrolling
To supply scrolling for a window has always been the hardest part to program. Recently, two very good articles about scrolling have appeared in MacTutor (MT 3/89 p.62 and MT 4/89 p.11). Especially nice seems to be the Scrolling Manager, which probably could be used with small changes instead of my unit StdScroll. The only problem is that for someone who has never programmed in C it is not easy to follow. (Who needs cryptic C or C++? The Mac is a Pascal (!) machine (for how long?), and when you need to speed up part of your code, e.g. to establish Bezier curves, and dont want to use Assembler, still nothing can beat Fortran! Absofts RAT MacFortran compiler and TML Pascal II, both running under MPW, would probably be a combination hard to beat. If Apple would develop ObjectPascal further by e.g. establishing multiple inheritance and adding a Smalltalk like Class Browser, instead of becoming a me too C++ user, Pascal could become an even more powerful and elegant development system, much better than for example C-Talk, which looks already a lot like Smalltalk.)
My scroll code is fairly conventional, e.g. not following Joes Golden Ratio of Scrolling, therefore I will mainly cover here the differences to other peoples code. Besides defining TScrollBar as object, probably the most important difference is the following:
There is really no need to implement scrolling differently for text or graphics! The sole exception is adjusting scroll bars during typing (method Adjust). To understand this lets see how scrolling is done principally. Every document, be it text or graphics, is drawn on a sheet of paper we name fDocRect (also called destination rectangle). We look at this paper through the peephole fViewRect (view rectangle) of our window. Scrolling now means displacing the paper containing our document with respect to our window so that another part of the document comes to view. This is exactly what our core-procedure ScrollContent does:
{6}
OffsetRect(oDocument.fDocRect, dH, dV);
ScrollRect(oDocument.fViewRect, dH, dV);
oDocument.Update;
For text all this is normally done by Toolbox procedure TEScroll (see MR 2-246), but since we have to implement this sequence of commands for graphics anyhow, so why not use this code also for text. The problem of scrolling text one line a time is taken care of by simply setting vAmount to fTextHdl^^.lineHeight in procedure DoScroll. This is our action procedure, which is called every time the user presses the mouse button in one of the scroll bars, or when s/he scrolls with the mouse to the window edge to select text beyond the window boundary (DoAutoScroll).
Autoscrolling is supported both horizontally and vertically for text only. If you find procedure SetupAutoScroll, which is called every time the mouse is clicked in a document (see TScrollWindow.ClickInContent) a little strange, then you are right. The reason for this is that DoAutoScroll is a glue routine called from within procedure SetClikLoop, and DoScroll is an action procedure called from within TrackControl when the mouse button was pressed in the up or down arrow of a scrollbar. Therefore we cannot define DoAutoScroll and DoScroll as methods in TScrollBar. The only way to make the field variables fCtlHdl and oDocument accessible to these procedures is by setting both fields equal to temporary variables in the implementation part of unit StdScroll, and this is done in SetupAutoScroll.
As stated earlier method Adjust is set up for text only. It allows automatic scrolling of text during typing so that the text remains visible and the user can not blame us when s/he types junk. While looking for an easy way to scroll text horizontally when typing past the right end of the window I discovered, that textedit record field selRect does return the caret position in pixels. Therefore I have only to check if the coordinates of the caret are still within the limit of windows fViewRect otherwise the document has to be scrolled. (selRect.left is limited to -20000 to prevent integer overflow.) When calculating the maximum vertical scroll value function AdjustToCR does correct a bug in Text Edit, where the number of lines is not correct if carriage return is the last character.
On a Mac II text is often scrolled so fast that it is hard to scroll one line a time. Therefore DoScroll implements an initial scroll delay the duration of which in number of ticks is set in global constant kScrollDelay.
On the Mac SE I have made a strange observation, the reason of which I would like to know. When I change e.g. ForeColor to white and BackColor to black, and scroll afterwards, I get a striped pattern as if some region is not updated properly. On a Mac II everything works as it is supposed to. By the way, I have realized that it was always a good idea to change background color to e.g. yellow when testing my program. Doing this I could eliminate some strange bugs I have found when resizing a window, which I would not have detected if the background would have remained white.
A Short Preview
So much for now. Next time we will talk about the units specific to our application. We will cover TEXT and PICT documents, dialog boxes, saving and printing, and Multifinder support.
Meanwhile I hope after studying the code you will be able to enjoy the elegance of using objects as much as I do.
Listing: GlobalStuff.p
UNIT GlobalStuff;
{***********************************}
INTERFACE
USES
MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, MacPrint, ObjIntf;
CONST
{Constants allowed to change}
kMasters = 12; {# MoreMasters}
kMaxWindows = 0;{# windows: 0 = unlimited}
kScreenMargin = 2;{screen margin}
kTextMargin = 10; {text margin}
kPrintMargin = 0.5;{margin around printed page}
kHBarMargin = 40; {left margin of horiz.
scroll bar, usually 0}
kWOffset = 18; {# pixels to offset windows}
kWindowKind = 8;{# see Window constants}
kScrollDelay = 15;{# ticks for initial scroll delay}
kMaxEditItems = 6;{max # of editable text in dialogboxes}
kCreator = 'CSOS';{Christian Stratowa Object Shell}
{Document constants}
kPictDoc = 'PICT';{First document in typelist}
kTextDoc = 'TEXT';{Second document in typelist}
kDocKind = 'TEXT';{Document type in File menu}
kPictHeader = 512;{#bytes for header}
{Window constants}
kNoGrow = 1;
kGrow = 2;
kHScroll = 3;
kVScroll = 4;
kScroll = 5;
kHScrollZoom = 6;
kVScrollZoom = 7;
kScrollZoom = 8;
{Scroll bar constants}
kHBar = 1;
kVBar = 2;
kSBarWidth = 15;
{ASCII constants}
kCR = 13;
kBS = 8;
kEnter = 3;
{Apple Menu}
kAppleID = 1;
kAbout = 1;
{File Menu}
kFileID = 2;
kNew = 1;
kOpen = 2;
kClose = 3;
{----}
kSave = 5;
kSaveAs = 6;
{----}
kPageSetUp = 8;
kPrint = 9;
{----}
kQuit = 11;
{Edit Menu}
kEditID = 3;
kUndo = 1;
{----}
kCut = 3;
kCopy = 4;
kPaste = 5;
kClear = 6;
{*begin MyMenus*}
{New Menu}
kNewID = 21;
{New Picture Menu}
kNewPictID = 211;
{New Text Menu}
kNewTextID = 212;
{Graphics Menu}
kGraphID = 4;
kOvals = 1;
kSpirals = 2;
{Color Menu}
kColorID = 5;
kBlack = 1;
kWhite = 2;
kRed = 3;
kGreen = 4;
kBlue = 5;
kCyan = 6;
kMagenta = 7;
kYellow = 8;
{ForeColor Menu}
kForeCID = 51;
{BackColor Menu}
kBackCID = 52;
{Text Menu}
kTextID = 6;
{Font Menu}
kFontID = 61;
{Size Menu}
kSizeID = 62;
{Style Menu}
kStyleID = 63;
kPlain = 1;
kBold = 2;
kItalic = 3;
kUnderline = 4;
kOutline = 5;
kShadow = 6;
kCondense = 7;
kExtend = 8;
{Align Menu}
kJustID = 64;
kLeft = 1;
kCenter = 2;
kRight = 3;
{PopUp Menus}
kPopUpID1 = 10;
kFrameOval = 1;
kInvertOval = 2;
kFrameRect = 3;
kInvertRect = 4;
{*end MyMenus*}
{Alert constants}
kAboutID = 1000;
kErrID = 1001;
kSizeErrID = 1002;
kSaveID = 1003;
{Dialog constants}
kPrintID = 2000;
{Str# constants}
kStrListID = 1000;
kOSErrID = 1001;
{low memory constants}
ROM85 = $28E;
MBarHeight = $BAA;
VAR
{Rectangle variables}
gDeskTopRect: Rect;
gDragRect: Rect;
gGrowRect: Rect;
{Window variables}
gMinWidth: Integer;
gMinHeight: Integer;
gWCount: Integer;
gCloseFlag: BOOLEAN;
{menu variables}
gMBarHeight: Integer;
{Cursor variables}
gWatch: Cursor;
gCross: Cursor;
gIBeam: Cursor;
{Print variables}
gPrintHdl: THPrint;
{Event variables}
gQuitting: BOOLEAN;
gDone: BOOLEAN;
gMFEvent: BOOLEAN;
gNextEvent: BOOLEAN;
gEvent: EventRecord;
gSleep: LongInt;
gMouseRgn: RgnHandle;
{----------------------------------------}
PROCEDURE SetEnable(vRsrcID, vItem: Integer;
vFlag: BOOLEAN);
PROCEDURE CenterDialogBox(vWidth,vHeight: Integer;
VAR vPt: Point);
PROCEDURE CenterMyDialog(vType: OSType; vResID: Integer);
FUNCTION IsAppWindow(vWPtr: WindowPtr): BOOLEAN;
FUNCTION OSError(vErr: OSErr): BOOLEAN;
{****************************************}
IMPLEMENTATION
PROCEDURE SetEnable(vRsrcID, vItem: Integer; vFlag: BOOLEAN);
BEGIN
IF vFlag THEN
EnableItem(GetMHandle(vRsrcID), vItem)
ELSE
DisableItem(GetMHandle(vRsrcID), vItem)
END; {SetEnable}
{========================================}
PROCEDURE CenterDialogBox(vWidth,vHeight: Integer;
VAR vPt: Point);
BEGIN
WITH screenBits.bounds DO
BEGIN
vPt.h:= (right - left - vWidth) DIV 2;
vPt.v:= (bottom - top - vHeight) DIV 3;
END;
END; {CenterDialogBox}
{========================================}
PROCEDURE CenterMyDialog(vType: OSType; vResID: Integer);
VAR
vHdl: Handle;
vRect: Rect;
vWidth, vHeight: Integer;
vPt: Point;
BEGIN
vHdl:= GetResource(vType, vResID);
HNoPurge(vHdl);
IF (vType = 'DLOG') THEN
vRect:= DialogTHndl(vHdl)^^.boundsRect
ELSE IF (vType = 'ALRT') THEN
vRect:= AlertTHndl(vHdl)^^.boundsRect;
WITH vRect DO
BEGIN
vWidth:= (right - left);
vHeight:= (bottom - top);
CenterDialogBox(vWidth, vHeight, vPt);
left:= vPt.h;
right:= vPt.h + vWidth;
top:= vPt.v;
bottom:= vPt.v + vHeight;
END;
IF (vType = 'DLOG') THEN
DialogTHndl(vHdl)^^.boundsRect:= vRect
ELSE IF (vType = 'ALRT') THEN
AlertTHndl(vHdl)^^.boundsRect:= vRect;
SetResPurge(TRUE);
HPurge(vHdl);
InitCursor;
END; {CenterMyDialog}
{========================================}
FUNCTION IsAppWindow(vWPtr: WindowPtr):BOOLEAN;
BEGIN
IF vWPtr = NIL THEN
IsAppWindow:= FALSE
ELSE
WITH WindowPeek(vWPtr)^ DO
IsAppWindow:= (windowkind = userkind);
END; {IsAppWindow}
{========================================}
FUNCTION OSError(vErr: OSErr): BOOLEAN;
VAR
vErrNr: Str255;
vErrMess: Str255;
vItem: Integer;
BEGIN
OSError:= (vErr <> noErr);
CASE vErr OF
DupFNErr:
GetIndString(vErrMess, kOSErrID, 1);
OpWrErr:
GetIndString(vErrMess, kOSErrID, 2);
IPrAbort:
Exit(OSError);
OTHERWISE
vErrMess:= '';
END;
NumToString(vErr, vErrNr);
ParamText(vErrNr, vErrMess, '', '');
IF vErr <> noErr THEN
BEGIN
CenterMyDialog('ALRT', kErrID);
IF StopAlert(kErrID, NIL) = OK THEN
END;
END; {OSError}
END. {unit GlobalStuff}
{****************************************}
Listing: StdMenus.p
UNIT StdMenus;
{****************************************}
INTERFACE
USES
MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, MacPrint, ObjIntf,
GlobalStuff, AboutBox, StdWindows;
TYPE
TMenu = OBJECT(TObject)
fMenuHdl: MenuHandle;
PROCEDURE Create(vRsrcID: Integer);
PROCEDURE Choose(vItem: Integer);
END;
TAppleMenu = OBJECT(TMenu)
fAboutID: Integer;
PROCEDURE Setup(vAlertID: Integer);
PROCEDURE Create(vRsrcID: Integer);
override;
PROCEDURE Choose(vItem: Integer);
override;
END;
TFileMenu = OBJECT(TMenu)
PROCEDURE Choose(vItem: Integer);
override;
END;
TEditMenu = OBJECT(TMenu)
PROCEDURE Choose(vItem: Integer);
override;
END;
VAR
oAppleMenu: TAppleMenu;
oFileMenu: TFileMenu;
oEditMenu: TEditMenu;
PROCEDURE InitStdMenus;
PROCEDURE ClickInStdMenus(vMenu,vItem: Integer);
PROCEDURE SetStdMenuItems;
PROCEDURE DisposeStdMenus;
PROCEDURE DoNew(vWindowKind: Integer; vDocType: OSType);
{****************************************}
IMPLEMENTATION
PROCEDURE InitStdMenus;
BEGIN
New(oAppleMenu);
oAppleMenu.Setup(kAboutID);
oAppleMenu.Create(kAppleID);
New(oFileMenu);
oFileMenu.Create(kFileID);
New(oEditMenu);
oEditMenu.Create(kEditID);
END; {InitStdMenus}
{========================================}
PROCEDURE ClickInStdMenus(vMenu, vItem: Integer);
BEGIN
CASE vMenu OF
kAppleID:
oAppleMenu.Choose(vItem);
kFileID:
oFileMenu.Choose(vItem);
kEditID:
oEditMenu.Choose(vItem);
OTHERWISE
END;
END; {ClickInStdMenus}
{========================================}
PROCEDURE SetStdMenuItems;
VAR
vFrontWFlag: BOOLEAN;
vUserWFlag: BOOLEAN;
vMaxWFlag: BOOLEAN;
BEGIN
vFrontWFlag:= (FrontWindow <> NIL);
vUserWFlag := IsAppWindow(FrontWindow);
vMaxWFlag:= NOT ((kMaxWindows <> 0) AND
(gWCount = kMaxWindows));
SetEnable(kFileID, kNew, vMaxWFlag);
SetEnable(kFileID, kClose, vFrontWFlag);
SetEnable(kFileID, kSave, vUserWFlag);
SetEnable(kFileID, kSaveAs, vUserWFlag);
SetEnable(kFileID, kPrint, vUserWFlag);
SetEnable(kEditID, 0, vFrontWFlag);
IF vFrontWFlag AND NOT vUserWFlag THEN
BEGIN
SetEnable(kEditID, kCut, TRUE);
SetEnable(kEditID, kCopy, TRUE);
SetEnable(kEditID, kPaste, TRUE);
END;
END; {SetStdMenuItems}
{========================================}
PROCEDURE DisposeStdMenus;
BEGIN
oAppleMenu.Free;
oFileMenu.Free;
oEditMenu.Free;
END; {DisposeStdMenus}
{========================================}
PROCEDURE TMenu.Create(vRsrcID: Integer);
BEGIN
HLock(Handle(Self));
fMenuHdl:= GetMenu(vRsrcID);
InsertMenu(fMenuHdl, 0);
HUnlock(Handle(Self));
END; {Create}
{----------------------------------------}
PROCEDURE TMenu.Choose(vItem: Integer);
BEGIN
END; {Choose}
{========================================}
PROCEDURE TAppleMenu.Setup(vAlertID: Integer);
BEGIN
fAboutID:= vAlertID
END; {Setup}
{----------------------------------------}
PROCEDURE TAppleMenu.Create(vRsrcID: Integer);
BEGIN
HLock(Handle(Self));
fMenuHdl:= GetMenu(vRsrcID);
AddResMenu(fMenuHdl, 'DRVR');
InsertMenu(fMenuHdl, 0);
HUnlock(Handle(Self));
END; {Create}
{----------------------------------------}
PROCEDURE TAppleMenu.Choose(vItem: Integer);
VAR
vDAName: Str255;
vDANumber: Integer;
vSavePort: GrafPtr;
BEGIN
IF vItem = kAbout THEN
DoAbout(fAboutID)
ELSE
BEGIN
GetPort(vSavePort);
GetItem(fMenuHdl, vItem, vDAName);
vDANumber:= OpenDeskAcc(vDAName);
SetPort(vSavePort);
END;
END; {Choose}
{========================================}
PROCEDURE DoNew(vWindowKind: Integer; vDocType: OSType);
BEGIN
{for TML create tempvariables!}
CASE vWindowKind OF
kNoGrow:
New(TWindow(oWindow));
kGrow:
New(TGrowWindow(oWindow));
kHScroll..kScroll:
New(TScrollWindow(oWindow));
kHScrollZoom..kScrollZoom:
IF BitTst(Ptr(ROM85), 0) THEN
New(TScrollWindow(oWindow))
ELSE
New(TScrollZoomWindow(oWindow));
OTHERWISE
END;
oWindow.fWKind:= vWindowKind;
oWindow.DoNew(vDocType);
ShowWindow(oWindow.fWPtr);
END; {DoNew}
{----------------------------------------}
PROCEDURE DoOpen;
VAR
vPt: Point;
vNumTypes: Integer;
vTypeList: SFTypeList;
vReply: SFReply;
vWPeek: WindowPeek;
BEGIN
CenterDialogBox(348, 200, vPt);
vNumTypes:= 2;
vTypeList[0]:= kPictDoc;
vTypeList[1]:= kTextDoc;
SFGetFile(vPt, '', NIL, vNumTypes, vTypeList, NIL, vReply);
WITH vReply DO
IF good THEN
BEGIN
IF IsAppWindow(FrontWindow) THEN
IF DuplicateFileName(FrontWindow, fName, vFrontW) THEN
IF OSError(opWRErr) THEN
Exit(DoOpen);
DoNew(kWindowKind, fType);
oWindow.DoOpen(fName, vRefNum);
END;
END; {DoOpen}
{----------------------------------------}
PROCEDURE DoClose;
VAR
vDANumber: Integer;
BEGIN
IF IsAppWindow(FrontWindow) THEN
BEGIN
oWindow:= TWindow(GetWRefCon(FrontWindow));
oWindow.DoClose;
END
ELSE
BEGIN
vDANumber:= WindowPeek(FrontWindow)^.windowkind;
CloseDeskAcc(vDANumber);
END;
END; {DoClose}
{----------------------------------------}
PROCEDURE DoSave(vSaveAs: BOOLEAN);
BEGIN
oWindow:= TWindow(GetWRefCon(FrontWindow));
IF oWindow.Saved(vSaveAs) THEN
END; {DoSave}
{----------------------------------------}
PROCEDURE DoPageSetup;
VAR
vFlag: BOOLEAN;
BEGIN
PrOpen;
IF OSError(PrError) THEN
Exit(DoPageSetup);
SetCursor(arrow);
vFlag:= PrValidate(gPrintHdl);
vFlag:= PrStlDialog(gPrintHdl);
vFlag:= OSError(PrError);
PrClose;
IF OSError(PrError) THEN
END; {DoPageSetup}
{----------------------------------------}
PROCEDURE DoPrint;
VAR
vFlag: BOOLEAN;
BEGIN
oWindow:= TWindow(GetWRefCon(FrontWindow));
PrOpen;
IF OSError(PrError) THEN
Exit(DoPrint);
SetCursor(arrow);
vFlag:= PrValidate(gPrintHdl);
IF PrJobDialog(gPrintHdl) THEN
oWindow.DoPrint;
PrClose;
IF OSError(PrError) THEN
END; {DoPrint}
{----------------------------------------}
PROCEDURE DoQuit;
BEGIN
gQuitting:= TRUE;
WHILE (FrontWindow <> NIL) AND gQuitting DO
DoClose;
IF gQuitting THEN
gDone:= TRUE;
END; {DoQuit}
{----------------------------------------}
PROCEDURE TFileMenu.Choose(vItem: Integer);
BEGIN
CASE vItem OF
kNew:
DoNew(kWindowKind, kDocKind);
kOpen:
DoOpen;
kClose:
DoClose;
kSave:
DoSave(FALSE);
kSaveAs:
DoSave(TRUE);
kPageSetUp:
DoPageSetup;
kPrint:
DoPrint;
kQuit:
DoQuit;
END;
END; {Choose}
{========================================}
PROCEDURE TEditMenu.Choose(vItem: Integer);
BEGIN
IF NOT SystemEdit(vItem - 1) THEN
IF FrontWindow <> NIL THEN
BEGIN
oWindow:= TWindow(GetWRefCon(FrontWindow));
oWindow.Edit(vItem);
END;
END; {Choose}
END. {unit StdMenus}
{****************************************}
Listings: StdWindows.p
UNIT StdWindows;
{****************************************}
INTERFACE
USES
MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, MacPrint, ObjIntf,
GlobalStuff, StdScroll, MyDocuments;
TYPE
TWindow = OBJECT(TObject)
fWKind: Integer;
fWPtr: WindowPtr;
fControlRgn: RgnHandle;
fDisplayRgn: RgnHandle;
oDocument: TDocument;
FUNCTION ControlRgn: RgnHandle;
FUNCTION DisplayRgn(vCtlRgn:RgnHandle): RgnHandle;
PROCEDURE Initialize;
PROCEDURE DoNew(vDocType: OSType);
PROCEDURE DoOpen(vFileName: Str255;
vVolNum: Integer);
FUNCTION Saved(vSaveAs: BOOLEAN): BOOLEAN;
PROCEDURE DoClose;
PROCEDURE DoPrint;
PROCEDURE ApplTask;
PROCEDURE ReDrawContent;
PROCEDURE Grow;
PROCEDURE Zoom(vPart: Integer);
PROCEDURE ClickInContent(vPt: Point);
PROCEDURE ClickInWindow(vPart: Integer);
PROCEDURE KeyPress(vChar: CHAR);
PROCEDURE Update;
PROCEDURE Activate;
PROCEDURE Edit(vItem: Integer);
PROCEDURE Free;
override;
END;
TGrowWindow = OBJECT(TWindow)
FUNCTION ControlRgn: RgnHandle;
override;
PROCEDURE Initialize;
override;
PROCEDURE Grow;
override;
PROCEDURE Activate;
override;
END;
TScrollWindow = OBJECT(TGrowWindow)
oVBar: TScrollBar;
oHBar: TScrollBar;
FUNCTION ControlRgn: RgnHandle;
override;
PROCEDURE DoNew(vDocType: OSType);
override;
PROCEDURE DoOpen(vFileName: Str255;
vVolNum: Integer);
override;
PROCEDURE ReDrawContent;
override;
PROCEDURE ClickInContent(vPt: Point);
override;
PROCEDURE KeyPress(vChar: CHAR);
override;
PROCEDURE Activate;
override;
PROCEDURE Edit(vItem: Integer);
override;
PROCEDURE Free;
override;
END;
TScrollZoomWindow = OBJECT(TScrollWindow)
PROCEDURE Initialize;
override;
PROCEDURE Zoom(vPart: Integer);
override;
END;
VAR
oWindow: TWindow;
FUNCTION DuplicateFileName(vWPtr: WindowPtr;
vFileName: Str255;
VAR vNextWindow: WindowPeek): BOOLEAN;
{****************************************}
IMPLEMENTATION
VAR
uNr: Str255;
uRect: Rect;
uTitle: Str255;
uVisible: BOOLEAN;
uWindID: Integer;
uGoAway: BOOLEAN;
uRefVal: longint;
{========================================}
FUNCTION DuplicateFileName(vWPtr: WindowPtr;
vFileName: Str255;
VAR vNextWindow: WindowPeek): BOOLEAN;
BEGIN
DuplicateFileName:= FALSE;
vNextWindow:= WindowPeek(vWPtr);
REPEAT
uTitle:= vNextWindow^.titleHandle^^;
IF vFileName = uTitle THEN
BEGIN
DuplicateFileName := TRUE;
leave;
END;
vNextWindow:= vNextWindow^.nextWindow;
UNTIL (vNextWindow = NIL);
END; {DuplicateFileName}
{========================================}
FUNCTION TWindow.ControlRgn: RgnHandle;
VAR
vRgn: RgnHandle;
BEGIN
vRgn:= NewRgn;
SetEmptyRgn(vRgn);
ControlRgn:= vRgn;
END; {ControlRgn}
{- - - - - - - - - - - - - -}
FUNCTION TWindow.DisplayRgn(vCtlRgn: RgnHandle): RgnHandle;
VAR
vRgn: RgnHandle;
BEGIN
uRect:= fWPtr^.portRect;
vRgn:= NewRgn;
RectRgn(vRgn, uRect);
DiffRgn(vRgn, vCtlRgn, vRgn);
DisplayRgn:= vRgn;
END; {DisplayRgn}
{----------------------------------------}
PROCEDURE TWindow.Initialize;
BEGIN
GetIndString(uTitle, kStrListID, 1);
uTitle:= Concat(uTitle, uNr);
uVisible:= FALSE;
uWindID:= noGrowDocProc;
uGoAway:= TRUE;
uRefVal:= 0;
END; {Initialize}
{- - - - - - - - - - - - - -}
FUNCTION NewRect(vCount: Integer): Rect;
VAR
vOffset: Integer;
BEGIN
vOffset:= (vCount - 1) * kWOffset;
IF gMinWidth > gMinHeight THEN
vOffset:= vOffset MOD (gMinWidth -kWOffset)
ELSE
vOffset:= vOffset MOD (gMinHeight -2*kWOffset);
WITH ScreenBits.Bounds DO
BEGIN
NewRect.left:= kScreenMargin + vOffset;
NewRect.top:= 2 * gMBarHeight + vOffset;
NewRect.right:= right - kScreenMargin - gMinWidth + vOffset;
NewRect.bottom:= bottom - kScreenMargin - gMinHeight + vOffset;
END;
END; {NewRect}
{- - - - - - - - - - - - - -}
PROCEDURE TWindow.DoNew(vDocType: OSType);
BEGIN
gWCount:= gWCount + 1;
uRect:= NewRect(gWCount);
NumToString(gWCount, uNr);
self.Initialize;
fWPtr:= NewWindow(NIL, uRect, uTitle, uVisible, uWindID, POINTER(-1),
uGoAway, uRefVal);
IF (fWPtr = NIL) THEN
Exit(DoNew);
SetWRefCon(fWPtr, Ord4(self));
SetPort(fWPtr);
fControlRgn:= self.ControlRgn;
fDisplayRgn:= self.DisplayRgn(fControlRgn);
{for TML define tempvariables!}
IF vDocType = kTextDoc THEN
New(TTextDocument(oDocument))
ELSE IF vDocType = kPictDoc THEN
New(TPictDocument(oDocument))
ELSE
; {Initialize your own type of document}
WITH oDocument DO
BEGIN
fViewRgn := self.fDisplayRgn;
fViewRect := self.fDisplayRgn^^.rgnBBox;
fDocType := vDocType;
DoNew;
END;
END; {DoNew}
{----------------------------------------}
PROCEDURE TWindow.DoOpen(vFileName: Str255;
vVolNum: Integer);
VAR
vFileNum: Integer;
BEGIN
IF OSError(FSOpen(vFileName,vVolNum,vFileNum)) THEN
Exit(DoOpen);
SetCursor(gWatch);
oDocument.DoOpen(vVolNum, vFileNum);
SetCursor(arrow);
IF oDocument.fFileNum <> 0 THEN
BEGIN
SetWTitle(fWPtr, vFileName);
InvalRgn(fDisplayRgn);
END;
IF OSError(FSClose(vFileNum)) THEN
END; {DoOpen}
{----------------------------------------}
FUNCTION TWindow.Saved(vSaveAs:BOOLEAN): BOOLEAN;
VAR
vNewFile: BOOLEAN;
vPt: Point;
vText: Str255;
vReply: SFReply;
vErr: OSErr;
vFInfo: FInfo;
vFileNum: Integer;
vVolNum: Integer;
vType: OSType;
vWPeek: WindowPeek;
vOldWPtr: WindowPtr;
oOldDoc: TDocument;
BEGIN
Saved:= FALSE;
GetWTitle(fWPtr, uTitle);
vNewFile:= (oDocument.fFileNum = 0);
IF vSaveAs OR vNewFile THEN
BEGIN
CenterDialogBox(304, 184, vPt);
GetIndString(vText, kStrListID, 2);
SFPutFile(vPt, vText, uTitle, NIL, vReply);
WITH vReply DO
IF good THEN
BEGIN
vErr:= GetFInfo(fName, vRefNum, vFInfo);
IF DuplicateFileName(fWPtr, fName, vWPeek) THEN
BEGIN
self.Initialize;
vOldWPtr:= WindowPtr(vWPeek);
SetWTitle(vOldWPtr, uTitle);
oOldDoc:= TWindow(GetWRefCon(vOldWPtr)).oDocument;
vVolNum:= oOldDoc.fVolNum;
IF oOldDoc.fFileNum <> 0 THEN
IF OSError(FSDelete(fName, vVolNum)) THEN
Exit(Saved);
oOldDoc.fFileNum:= 0;
oOldDoc.fChanged:= TRUE;
vErr:= GetFInfo(fName, vRefNum, vFInfo);
END;
CASE vErr OF
noErr:
;
fnfErr:
BEGIN
vType:= oDocument.fDocType;
IF OSError(Create(fName, vRefNum, kCreator, vType)) THEN
Exit(Saved);
END;
OTHERWISE
IF OSError(vErr) THEN
Exit(Saved);
END;
uTitle:= fName;
SetWTitle(fWPtr, uTitle);
oDocument.fVolNum:= vRefNum;
END
ELSE
Exit(Saved);
END;
IF OSError(FSOpen(uTitle, oDocument.fVolNum, vFileNum)) THEN
Exit(Saved);
SetCursor(gWatch);
oDocument.DoSave(vFileNum);
SetCursor(arrow);
IF OSError(FSClose(vFileNum)) THEN
Exit(Saved);
IF OSError(FlushVol(NIL, oDocument.fVolNum)) THEN
Exit(Saved);
Saved:= TRUE;
END; {Saved}
{----------------------------------------}
PROCEDURE TWindow.DoClose;
VAR
vNextWindow: WindowPeek;
BEGIN
IF oDocument.fChanged THEN
BEGIN
GetWTitle(fWPtr, uTitle);
ParamText(uTitle, '', '', '');
CenterMyDialog('ALRT', kSaveID);
CASE Alert(kSaveID, NIL) OF
OK:
IF NOT self.Saved(FALSE) THEN
Exit(DoClose);
cancel:
BEGIN
gQuitting:= FALSE;
Exit(DoClose);
END;
OTHERWISE
END;
END;
vNextWindow:= WindowPeek(FrontWindow)^.nextWindow;
IF (gWCount = 1) OR (vNextWindow^.windowkind <> userkind) THEN
gCloseFlag:= TRUE;
gWCount:= gWCount - 1;
self.Free;
END; {DoClose}
{----------------------------------------}
PROCEDURE DisplayPrintDialog(VAR vDPtr: DialogPtr);
VAR
vFlag: BOOLEAN;
vDEvent: EventRecord;
vDItem: Integer;
BEGIN
CenterMyDialog('DLOG', kPrintID);
vDPtr:= GetNewDialog(kPrintID, NIL, POINTER(-1));
vFlag:= GetNextEvent(updateMask, vDEvent);
vFlag:= DialogSelect(vDEvent, vDPtr, vDItem);
END; {DisplayPrintDialog}
{- - - - - - - - - - - - - -}
PROCEDURE TWindow.DoPrint;
VAR
vSavePort: GrafPtr;
vPrPort: TPPrPort;
vFlag: BOOLEAN;
vPrStatus: TPrStatus;
vDPtr: DialogPtr;
BEGIN
GetPort(vSavePort);
SetCursor(gWatch);
vPrPort:= PrOpenDoc(gPrintHdl, NIL, NIL);
IF OSError(PrError) THEN
Exit(DoPrint);
DisplayPrintDialog(vDPtr);
oDocument.DoPrint(vPrPort);
PrCloseDoc(vPrPort);
vFlag:= NOT OSError(PrError);
vFlag:= (gPrintHdl^^.prJob.bJDocLoop = bSpoolLoop) AND vFlag;
IF vFlag THEN
BEGIN
SetCursor(gWatch);
PrPicFile(gPrintHdl, NIL, NIL, NIL, vPrStatus);
END;
vFlag:= OSError(PrError);
DisposDialog(vDPtr);
SetPort(vSavePort);
END; {DoPrint}
{----------------------------------------}
PROCEDURE TWindow.ApplTask;
BEGIN
oDocument.ApplTask;
END; {ApplTask}
{----------------------------------------}
PROCEDURE TWindow.ReDrawContent;
BEGIN
DisposeRgn(fControlRgn);
DisposeRgn(fDisplayRgn);
fControlRgn:= self.ControlRgn;
fDisplayRgn:= self.DisplayRgn(fControlRgn);
WITH oDocument DO
BEGIN
fViewRgn := self.fDisplayRgn;
fViewRect := self.fDisplayRgn^^.rgnBBox;
ReDraw;
END;
END; {ReDrawContent}
{----------------------------------------}
PROCEDURE TWindow.Grow;
BEGIN
END; {Grow}
{- - - - - - - - - - - - - -}
PROCEDURE TWindow.Zoom;
BEGIN
END; {Zoom}
{- - - - - - - - - - - - - -}
PROCEDURE TWindow.ClickInContent(vPt: Point);
BEGIN
GlobalToLocal(vPt);
IF PtInRgn(vPt, fDisplayRgn) THEN
oDocument.ClickInDoc(vPt);
END; {ClickInContent}
{- - - - - - - - - - - - - -}
PROCEDURE TWindow.ClickInWindow (vPart: Integer);
VAR
vSavePort: GrafPtr;
BEGIN
GetPort(vSavePort);
SetPort(fWPtr);
WITH gEvent DO
CASE vPart OF
inDrag:
IF fWPtr <> FrontWindow THEN
SelectWindow(fWPtr)
ELSE
DragWindow(fWPtr, where, gDragRect);
inGoAway:
IF TrackGoAway(fWPtr, where) THEN
self.DoClose;
inGrow:
self.Grow;
inZoomIn, inZoomOut:
IF TrackBox(fWPtr, where, vPart) THEN
self.Zoom(vPart);
inContent:
IF fWPtr <> FrontWindow THEN
SelectWindow(fWPtr)
ELSE
self.ClickInContent(where);
OTHERWISE
END;
SetPort(vSavePort);
END; {ClickInWindow}
{----------------------------------------}
PROCEDURE TWindow.KeyPress(vChar: CHAR);
BEGIN
oDocument.KeyPress(vChar);
END; {KeyPress}
{----------------------------------------}
PROCEDURE TWindow.Update;
VAR
vSavePort: GrafPtr;
BEGIN
GetPort(vSavePort);
SetPort(fWPtr);
BeginUpdate(fWPtr);
SetClip(fControlRgn);
IF fWKind <> kNoGrow THEN
DrawGrowIcon(fWPtr);
DrawControls(fWPtr);
SetClip(fDisplayRgn);
EraseRgn(fDisplayRgn);
oDocument.Update;
ClipRect(fWPtr^.portRect);
EndUpdate(fWPtr);
SetPort(vSavePort);
END; {Update}
{----------------------------------------}
PROCEDURE TWindow.Activate;
BEGIN
SetPort(fWPtr);
oDocument.Activate;
END; {Activate}
{----------------------------------------}
PROCEDURE TWindow.Edit(vItem: Integer);
BEGIN
oDocument.Edit(vItem);
END; {Edit}
{----------------------------------------}
PROCEDURE TWindow.Free;
BEGIN
oDocument.Free;
DisposeRgn(fControlRgn);
DisposeRgn(fDisplayRgn);
DisposeWindow(fWPtr);
INHERITED Free;
END; {Free}
{========================================}
FUNCTION TGrowWindow.ControlRgn: RgnHandle;
VAR
vRgn: RgnHandle;
BEGIN
vRgn:= NewRgn;
uRect:= fWPtr^.portRect;
WITH uRect DO
BEGIN
left:= right - kSBarWidth;
top:= bottom - kSBarWidth;
END;
RectRgn(vRgn, uRect);
ControlRgn:= vRgn;
END; {ControlRgn}
{----------------------------------------}
PROCEDURE TGrowWindow.Initialize;
BEGIN
GetIndString(uTitle, kStrListID, 1);
uTitle:= Concat(uTitle, uNr);
uVisible:= FALSE;
uWindID:= documentProc;
uGoAway:= TRUE;
uRefVal:= 0;
END; {Initialize}
{----------------------------------------}
PROCEDURE TGrowWindow.Grow;
VAR
vNewSize: LongInt;
vWidth: Integer;
vHeight: Integer;
vHFlag, vVFlag: BOOLEAN;
BEGIN
vNewSize:= GrowWindow(fWPtr, gEvent.where, gGrowRect);
IF vNewSize <> 0 THEN
BEGIN
vWidth:= LoWord(vNewSize);
vHeight:= HiWord(vNewSize);
WITH fWPtr^.portRect DO
BEGIN
vHFlag:= (vWidth > (right - left));
vVFlag:= (vHeight > (bottom - top));
END;
IF vHFlag OR vVFlag THEN
BEGIN
EraseRgn(fControlRgn);
InvalRgn(fControlRgn);
END;
SizeWindow(fWPtr, vWidth, vHeight, TRUE);
self.ReDrawContent;
IF NOT vHFlag OR NOT vVFlag THEN
BEGIN
EraseRgn(fControlRgn);
InvalRgn(fControlRgn);
END;
END;
END; {Grow}
{----------------------------------------}
PROCEDURE TGrowWindow.Activate;
BEGIN
INHERITED Activate;
SetClip(fControlRgn);
DrawGrowIcon(fWPtr);
ClipRect(fWPtr^.portRect);
END; {Activate}
{========================================}
FUNCTION TScrollWindow.ControlRgn: RgnHandle;
VAR
vRgn1, vRgn2: RgnHandle;
BEGIN
vRgn1:= INHERITED ControlRgn;
IF fWKind IN [kHScroll, kScroll, kHScrollZoom, kScrollZoom] THEN
BEGIN
vRgn2:= NewRgn;
WITH fWPtr^.portRect DO
SetRect(uRect, left, bottom - kSBarWidth, right - kSBarWidth, bottom);
RectRgn(vRgn2, uRect);
UnionRgn(vRgn1, vRgn2, vRgn1);
DisposeRgn(vRgn2);
END;
IF fWKind IN [kVScroll, kScroll, kVScrollZoom, kScrollZoom] THEN
BEGIN
vRgn2:= NewRgn;
WITH fWPtr^.portRect DO
SetRect(uRect, right - kSBarWidth, top, right, bottom - kSBarWidth);
RectRgn(vRgn2, uRect);
UnionRgn(vRgn1, vRgn2, vRgn1);
DisposeRgn(vRgn2);
END;
ControlRgn:= vRgn1;
END; {ControlRgn}
{----------------------------------------}
PROCEDURE TScrollWindow.DoNew(vDocType: OSType);
BEGIN
INHERITED DoNew(vDocType);
oHBar:= NIL;
oVBar:= NIL;
IF fWKind IN [kHScroll, kScroll, kHScrollZoom, kScrollZoom] THEN
BEGIN
New(oHBar);
oHBar.oDocument:= self.oDocument;
WITH fWPtr^.portRect DO
SetRect(uRect, -1 + kHBarMargin, bottom - kSBarWidth, right - kSBarWidth
+ 1, bottom + 1);
oHBar.DoNew(kHBar, fWPtr, uRect);
END;
IF fWKind IN [kVScroll, kScroll, kVScrollZoom, kScrollZoom] THEN
BEGIN
New(oVBar);
oVBar.oDocument:= self.oDocument;
WITH fWPtr^.portRect DO
SetRect(uRect, right - kSBarWidth, -1, right + 1, bottom - kSBarWidth
+ 1);
oVBar.DoNew(kVBar, fWPtr, uRect);
END;
InitAutoScroll(oDocument);
END; {DoNew}
{----------------------------------------}
PROCEDURE TScrollWindow.DoOpen(vFileName:Str255;
vVolNum: Integer);
BEGIN
INHERITED DoOpen(vFileName, vVolNum);
IF oHBar <> NIL THEN
oHBar.Adjust;
IF oVBar <> NIL THEN
oVBar.Adjust;
END; {DoOpen}
{----------------------------------------}
PROCEDURE TScrollWindow.ReDrawContent;
BEGIN
INHERITED ReDrawContent;
IF oHBar <> NIL THEN
BEGIN
WITH fWPtr^.portRect DO
SetRect(uRect, -1 + kHBarMargin, bottom - kSBarWidth, right - kSBarWidth
+ 2 - kHBarMargin, kSBarWidth + 1);
oHBar.ReDraw(uRect);
END;
IF oVBar <> NIL THEN
BEGIN
WITH fWPtr^.portRect DO
SetRect(uRect, right - kSBarWidth, -1, kSBarWidth + 1, bottom - kSBarWidth
+ 2);
oVBar.ReDraw(uRect);
END;
END; {ReDrawContent}
{----------------------------------------}
PROCEDURE TScrollWindow.ClickInContent(vPt: Point);
VAR
vPart: Integer;
vCtlHdl: ControlHandle;
BEGIN
GlobalToLocal(vPt);
vPart:= FindControl(vPt, fWPtr, vCtlHdl);
CASE vPart OF
inUpButton..inPageDown, inThumb:
CASE GetCRefCon(vCtlHdl) OF
kHBar:
oHBar.ClickInSBar(vPart, vPt);
kVBar:
oVBar.ClickInSBar(vPart, vPt);
END;
inButton:
;
inCheckBox:
;
OTHERWISE
BEGIN
IF oHBar <> NIL THEN
oHBar.SetupAutoScroll(fWKind);
IF oVBar <> NIL THEN
oVBar.SetupAutoScroll(fWKind);
LocalToGlobal(vPt);
INHERITED ClickInContent(vPt);
END;
END;
END; {ClickInContent}
{----------------------------------------}
PROCEDURE TScrollWindow.KeyPress(vChar: CHAR);
BEGIN
INHERITED KeyPress(vChar);
IF oHBar <> NIL THEN
oHBar.Adjust;
IF oVBar <> NIL THEN
oVBar.Adjust;
END; {KeyPress}
{----------------------------------------}
PROCEDURE TScrollWindow.Activate;
BEGIN
INHERITED Activate;
IF oHBar <> NIL THEN
oHBar.Activate;
IF oVBar <> NIL THEN
oVBar.Activate;
END; {Activate}
{----------------------------------------}
PROCEDURE TScrollWindow.Edit(vItem: Integer);
BEGIN
INHERITED Edit(vItem);
IF oHBar <> NIL THEN
oHBar.Adjust;
IF oVBar <> NIL THEN
oVBar.Adjust;
END; {Edit}
{----------------------------------------}
PROCEDURE TScrollWindow.Free;
BEGIN
KillControls(fWPtr);
IF oHBar <> NIL THEN
oHBar.Free;
IF oVBar <> NIL THEN
oVBar.Free;
INHERITED Free;
END; {Free}
{========================================}
PROCEDURE TScrollZoomWindow.Initialize;
BEGIN
GetIndString(uTitle, kStrListID, 1);
uTitle:= Concat(uTitle, uNr);
uVisible:= FALSE;
uWindID:= documentProc + kScrollZoom;
uGoAway:= TRUE;
uRefVal:= 0;
END; {Initialize}
{----------------------------------------}
PROCEDURE TScrollZoomWindow.Zoom(vPart: Integer);
BEGIN
EraseRect(fWPtr^.portRect);
ZoomWindow(fWPtr, vPart, TRUE);
self.ReDrawContent;
END; {Zoom}
END. {unit StdWindows}
{****************************************}
Listing: StdScroll.p
UNIT StdScroll;
{****************************************}
INTERFACE
USES
MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, MacPrint, ObjIntf,
GlobalStuff, MyDocuments;
TYPE
TScrollBar = OBJECT(TObject)
fCtlHdl: ControlHandle;
oDocument: TDocument;
FUNCTION ScrollMax(vBar,vMargin: Integer): Integer;
PROCEDURE DoNew(vBar: Integer;
vWPtr: WindowPtr;
vRect: Rect);
PROCEDURE ClickInSBar(vCtlItem: Integer;
vPt: Point);
PROCEDURE SetupAutoScroll(vSBars: Integer);
PROCEDURE Adjust;
PROCEDURE ReDraw(vRect: Rect);
PROCEDURE Activate;
END;
PROCEDURE InitAutoScroll(oDoc: TDocument);
{****************************************}
IMPLEMENTATION
VAR
uHHdl: ControlHandle;
uVHdl: ControlHandle;
uSBars: Integer;
oDoc: TDocument;
uScrollDelay, uDelay: LongInt;
{========================================}
FUNCTION TScrollBar.ScrollMax(vBar, vMargin: Integer): Integer;
VAR
vDocWidth: Integer;
vDocHeight: Integer;
vMax: Integer;
BEGIN
WITH oDocument.fDocRect DO
BEGIN
vDocWidth:= right - left;
vDocHeight:= bottom - top;
END;
vMax:= 0;
WITH oDocument.fViewRect DO
CASE vBar OF
kHBar:
vMax:= vDocWidth - (right-left) + vMargin;
kVBar:
vMax:= vDocHeight - (bottom-top) + vMargin;
END;
IF vMax < 0 THEN
vMax:= 0;
ScrollMax:= vMax;
END; {ScrollMax}
{----------------------------------------}
PROCEDURE TScrollBar.DoNew (vBar: Integer;
vWPtr: WindowPtr;
vRect: Rect);
VAR
vTitle: Str255;
vVisible: BOOLEAN;
vCtlValue: Integer;
vCtlMin: Integer;
vCtlMax: Integer;
vProcID: Integer;
vRefVal: longint;
BEGIN
vTitle:= '';
vVisible:= TRUE;
vCtlValue:= 0;
vCtlMin:= 0;
vCtlMax:= ScrollMax(vBar, 0);
vProcID:= scrollBarProc;
vRefVal:= vBar;
fCtlHdl:= NewControl(vWPtr, vRect, vTitle, vVisible, vCtlValue, vCtlMin,
vCtlMax, vProcID, vRefVal);
END; {DoNew}
{----------------------------------------}
PROCEDURE ScrollContent(vCtlHdl: ControlHandle);
VAR
vCtlValue: Integer;
vDocRect: Rect;
vDeltaH, vDeltaV: Integer;
vUpdateRgn: RgnHandle;
BEGIN
HLock(Handle(oDoc));
WITH oDoc DO
BEGIN
vCtlValue:= GetCtlValue(vCtlHdl);
SetClip(fViewRgn);
vDeltaH:= 0;
vDeltaV:= 0;
vUpdateRgn:= NewRgn;
CASE GetCRefCon(vCtlHdl) OF
kHBar:
vDeltaH:= fViewRect.left - fDocRect.left - vCtlValue;
kVBar:
vDeltaV:= fViewRect.top - fDocRect.top - vCtlValue;
END;
vDocRect := fDocRect;
OffsetRect(vDocRect, vDeltaH, vDeltaV);
fDocRect := vDocRect;
ScrollRect(fViewRect, vDeltaH, vDeltaV, vUpdateRgn);
SetClip(vUpdateRgn);
Update;
ClipRect(thePort^.portRect);
DisposeRgn(vUpdateRgn);
END;
HUnlock(Handle(oDoc));
END; {ScrollContent}
{- - - - - - - - - - - - - -}
PROCEDURE DoScroll (vCtlHdl: ControlHandle;
vPart: Integer);
VAR
vCtlValue: Integer;
vCtlMax: Integer;
vCtlMin: Integer;
vSize: Integer;
vPageSize: Integer;
vAmount: Integer;
BEGIN
vCtlValue:= GetCtlValue(vCtlHdl);
vCtlMax:= GetCtlMax(vCtlHdl);
vCtlMin:= GetCtlMin(vCtlHdl);
vAmount:= 0;
IF oDoc.fDocType = kTextDoc THEN
vSize:= oDoc.fTextHdl^^.lineHeight
ELSE
vSize:= 5;
WITH oDoc.fViewRect DO
CASE GetCRefCon(vCtlHdl) OF
kHBar:
vPageSize:= (right-left) DIV 2;
kVBar:
vPageSize:= ((bottom-top) DIV vSize -1)* vSize
END;
CASE vPart OF
inUpButton:
IF vCtlValue > vCtlMin THEN
vAmount:= -vSize;
inDownButton:
IF vCtlValue < vCtlMax THEN
vAmount:= +vSize;
inPageUp:
IF vCtlValue > vCtlMin THEN
vAmount:= -vPageSize;
inPageDown:
IF vCtlValue < vCtlMax THEN
vAmount:= +vPageSize;
OTHERWISE
END;
IF vAmount <> 0 THEN
BEGIN
SetCtlValue(vCtlHdl, vCtlValue + vAmount);
ScrollContent(vCtlHdl);
IF uScrollDelay > 0 THEN
uScrollDelay:= uScrollDelay - 5
ELSE
uScrollDelay:= 0;
Delay(uScrollDelay, uDelay);
END;
END; {DoScroll}
{- - - - - - - - - - - - - -}
PROCEDURE TScrollBar.ClickInSBar(vCtlItem: Integer;
vPt: Point);
BEGIN
oDoc:= self.oDocument;
CASE vCtlItem OF
inUpButton..inPageDown:
BEGIN
uScrollDelay:= kScrollDelay;
vCtlItem:= TrackControl(fCtlHdl, vPt, @DoScroll);
END;
inThumb:
BEGIN
vCtlItem:= TrackControl(fCtlHdl, vPt, NIL);
ScrollContent(fCtlHdl);
END;
END;
END; {ClickInSBar}
{----------------------------------------}
FUNCTION DoAutoScroll: BOOLEAN;
VAR
vOldClip: RgnHandle;
vPt: Point;
vViewRect: Rect;
BEGIN
vOldClip:= NewRgn;
GetClip(vOldClip);
ClipRect(thePort^.portRect);
GetMouse(vPt);
vViewRect:= oDoc.fViewRgn^^.rgnBBox;
IF uSBars IN [kHScroll, kScroll,
kHScrollZoom, kScrollZoom] THEN
IF vPt.h < vViewRect.left THEN
DoScroll(uHHdl, InUpButton)
ELSE IF vPt.h > vViewRect.right THEN
DoScroll(uHHdl, InDownButton);
IF uSBars IN [kVScroll, kScroll,
kVScrollZoom, kScrollZoom] THEN
IF vPt.v < vViewRect.top THEN
DoScroll(uVHdl, InUpButton)
ELSE IF vPt.v > vViewRect.bottom THEN
DoScroll(uVHdl, InDownButton);
SetClip(vOldClip);
DisposeRgn(vOldClip);
DoAutoScroll:= TRUE;
END; {DoAutoScroll}
{----------------------------------------}
PROCEDURE InitAutoScroll (oDoc: TDocument);
BEGIN
IF oDoc.fDocType = kTextDoc THEN
SetClikLoop(@DoAutoScroll, oDoc.fTextHdl)
ELSE IF oDoc.fDocType = kPictDoc THEN
; {Install Autoscroll for graphics}
END; {InitAutoScroll}
{----------------------------------------}
PROCEDURE TScrollBar.SetupAutoScroll(vSBars: Integer);
BEGIN
oDoc:= self.oDocument;
uSBars:= vSBars;
uScrollDelay:= 0;
CASE GetCRefCon(fCtlHdl) OF
kHBar:
uHHdl:= fCtlHdl;
kVBar:
uVHdl:= fCtlHdl;
END;
IF vSBars IN [kHScroll, kHScrollZoom] THEN
uVHdl:= NIL;
IF vSBars IN [kVScroll, kVScrollZoom] THEN
uHHdl:= NIL;
END; {SetupAutoScroll}
{----------------------------------------}
FUNCTION AdjustToCR(vTextHdl: TEHandle): Integer;
VAR
vCharHdl: CharsHandle;
BEGIN
WITH vTextHdl^^ DO
BEGIN
AdjustToCR:= 0;
vCharHdl:= CharsHandle(hText);
IF teLength > 0 THEN
IF vCharHdl^^[teLength - 1] = Chr(kCR) THEN
AdjustToCR:= lineHeight;
END;
END; {AdjustToCR}
{- - - - - - - - - - - - - -}
PROCEDURE TScrollBar.Adjust;
VAR
vViewWidth: Integer;
vViewHeight: Integer;
vCtlValue: Integer;
vCtlMax: Integer;
vScrollFlag: BOOLEAN;
BEGIN
oDoc:= self.oDocument;
WITH oDocument DO
IF fDocType = kTextDoc THEN
BEGIN
WITH fViewRect DO
BEGIN
vViewWidth:= (right-left) - kTextMargin;
vViewHeight:= (bottom-top);
END;
WITH fTextHdl^^.selRect DO
CASE GetCRefCon(fCtlHdl) OF
kHBar:
BEGIN
vCtlMax:= self.ScrollMax(kHBar, 0);
SetCtlMax(fCtlHdl, vCtlMax);
vScrollFlag:=(left < fViewRect.left)
OR (right > fViewRect.right);
IF vScrollFlag THEN
BEGIN
IF left < -20000 THEN
left:= -20000;
vCtlValue:= left - fDocRect.left - vViewWidth;
SetCtlValue(fCtlHdl, vCtlValue);
ScrollContent(fCtlHdl);
END;
END;
kVBar:
BEGIN
vCtlMax:= self.ScrollMax(kVBar, AdjustToCR(fTextHdl));
SetCtlMax(fCtlHdl, vCtlMax);
vScrollFlag:= (top < fViewRect.top) OR (bottom > fViewRect.bottom);
vScrollFlag:= vScrollFlag OR (fDocRect.bottom < fViewRect.bottom);
IF vScrollFlag THEN
BEGIN
vCtlValue:= bottom - fDocRect.top - vViewHeight;
SetCtlValue(fCtlHdl, vCtlValue);
ScrollContent(fCtlHdl);
END;
END;
END;
END
ELSE IF fDocType = kPictDoc THEN
; {Code for graphics}
END; {Adjust}
{----------------------------------------}
PROCEDURE TScrollBar.ReDraw (vRect: Rect);
VAR
vDelta: Integer;
vDocRect: Rect;
BEGIN
HideControl(fCtlHdl);
WITH vRect, oDocument DO
CASE GetCRefCon(fCtlHdl) OF
kHBar:
BEGIN
MoveControl(fCtlHdl, left, top);
SizeControl(fCtlHdl, right, bottom);
SetCtlMax(fCtlHdl, ScrollMax(kHBar, 0));
vDelta:= GetCtlMax(fCtlHdl) + fDocRect.left - fViewRect.left;
IF vDelta < 0 THEN
BEGIN
vDocRect:= fDocRect;
OffsetRect(vDocRect, -vDelta, 0);
fDocRect:= vDocRect;
END;
END;
kVBar:
BEGIN
MoveControl(fCtlHdl, left, top);
SizeControl(fCtlHdl, right, bottom);
SetCtlMax(fCtlHdl, ScrollMax(kVBar, 0));
vDelta:= GetCtlMax(fCtlHdl) + fDocRect.top - fViewRect.top;
IF vDelta < 0 THEN
BEGIN
vDocRect:= fDocRect;
OffsetRect(vDocRect, 0, -vDelta);
fDocRect:= vDocRect;
END;
END;
END;
ShowControl(fCtlHdl);
END; {ReDraw}
{----------------------------------------}
PROCEDURE TScrollBar.Activate;
BEGIN
IF BitAnd(gEvent.modifiers, activeFlag) <> 0 THEN
HiliteControl(fCtlHdl, 0)
ELSE
HiliteControl(fCtlHdl, 255);
END; {Activate}
END. {unit StdScroll}
{****************************************}
Listing: AboutBox.p
UNIT AboutBox;
{****************************************}
INTERFACE
USES
MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, MacPrint, GlobalStuff;
PROCEDURE DoAbout(vAboutID: Integer);
{****************************************}
IMPLEMENTATION
PROCEDURE DoAbout(vAboutID: Integer);
BEGIN
ParamText('Christian Stratowa', '', '', '');
CenterMyDialog('ALRT', vAboutID);
IF Alert(vAboutID, NIL) = OK THEN
END; {DoAbout}
END. {unit AboutBox}
{****************************************}
Listing: ObjectShell.p
PROGRAM ObjectShell;
{****************************************}
USES
MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, MacPrint, ObjIntf,
GlobalStuff, StdWindows, StdMenus, MyMenus;
{========================================}
PROCEDURE Escape;
BEGIN
ExitToShell
END; {Escape}
{========================================}
PROCEDURE InitToolbox (vMasters: Integer);
VAR
i: Integer;
BEGIN
MaxApplZone;
FOR i:= 1 TO vMasters DO
MoreMasters;
InitGraf(@thePort);
InitFonts;
InitWindows;
InitMenus;
TEInit;
InitDialogs(@Escape);
InitCursor;
FlushEvents(everyEvent, 0);
END; {InitToolbox}
{----------------------------------------}
PROCEDURE InitGlobals;
TYPE
tShortPointer = ^Integer;
VAR
vShortPtr: tShortPointer;
BEGIN
IF BitTst(Ptr(ROM85), 0) THEN
gMBarHeight:= 20
ELSE
BEGIN
vShortPtr:= tShortPointer(MBarHeight);
gMBarHeight:= vShortPtr^;
END;
IF BitTst(Ptr(ROM85), 0) THEN
gMFEvent:= FALSE
ELSE
gMFEvent:= (NGetTrapAddress($60, ToolTrap) <>
NGetTrapAddress($9F, ToolTrap));
gSleep:= 10;
gMouseRgn:= NewRgn;
gMouseRgn:= NIL;
gWatch:= GetCursor(watchCursor)^^;
gCross:= GetCursor(crossCursor)^^;
gIBeam:= GetCursor(iBeamCursor)^^;
gWCount:= 0;
gCloseFlag:= FALSE;
gDone:= FALSE;
END; {InitGlobals}
{----------------------------------------}
PROCEDURE InitRects;
BEGIN
gMinWidth:= 108;
gMinHeight:= 72;
WITH ScreenBits.Bounds DO
BEGIN
SetRect(gDeskTopRect, left, top+gMBarHeight, right, bottom);
gDragRect:= gDeskTopRect;
InsetRect(gDragRect, kScreenMargin, kScreenMargin);
SetRect(gGrowRect, gMinWidth, gMinHeight, right-kScreenMargin, bottom-kScreenMargin);
END;
END; {InitRects}
{----------------------------------------}
PROCEDURE InitPrint;
BEGIN
gPrintHdl:= THPrint(NewHandle(SizeOf(TPrint)));
PrOpen;
IF OSError(PrError) THEN
gPrintHdl:= NIL;
PrintDefault(gPrintHdl);
IF OSError(PrError) THEN
gPrintHdl:= NIL;
PrClose;
IF OSError(PrError) THEN
gPrintHdl:= NIL;
END; {InitPrint}
{----------------------------------------}
PROCEDURE CheckFinder;
VAR
vMessage: Integer;
vDocMax: Integer;
vIndex: Integer;
vInfo: AppFile;
BEGIN
CountAppFiles(vMessage, vDocMax);
IF vDocMax > 0 THEN
IF vMessage = appOpen THEN
FOR vIndex:= 1 TO vDocMax DO
BEGIN
IF FrontWindow <> NIL THEN
BEGIN
gEvent.message:= GetWRefCon(oWindow.fWPtr);
BitClr(@gEvent.modifiers, 15);
oWindow.Activate;
END;
GetAppFiles(vIndex, vInfo);
WITH vInfo DO
BEGIN
DoNew(kWindowKind, fType);
oWindow.DoOpen(fName, vRefNum);
END;
ClrAppFiles(vIndex);
END;
END; {CheckFinder}
{========================================}
PROCEDURE DoApplTasks;
BEGIN
IF IsAppWindow(FrontWindow) THEN
BEGIN
oWindow:= TWindow(GetWRefCon(FrontWindow));
oWindow.ApplTask;
END;
IF gCloseFlag THEN
BEGIN
SetMyMenuBar;
gCloseFlag:= FALSE;
END;
END; {DoApplTasks}
{========================================}
PROCEDURE DoMenuClick(vMenuCode: LongInt);
VAR
vMenu: Integer;
vItem: Integer;
BEGIN
vMenu:= HiWord(vMenuCode);
vItem:= LoWord(vMenuCode);
CASE vMenu OF
kAppleID..kEditID:
ClickInStdMenus(vMenu, vItem);
OTHERWISE
ClickInMyMenus(vMenu, vItem);
END;
HiliteMenu(0);
END; {DoMenuClick}
{----------------------------------------}
PROCEDURE DoWindowClick(vPart: Integer;
vWPtr: WindowPtr);
BEGIN
oWindow:= TWindow(GetWRefCon(vWPtr));
oWindow.ClickInWindow(vPart);
END; {DoWindowClick}
{----------------------------------------}
PROCEDURE DoMouseDown;
VAR
vPart: Integer;
vWhichWindow: WindowPtr;
BEGIN
WITH gEvent DO
BEGIN
vPart:= FindWindow(where, vWhichWindow);
CASE vPart OF
inDesk:
SysBeep(1);
inMenuBar:
BEGIN
SetStdMenuItems;
SetMyMenuItems;
DoMenuClick(MenuSelect(where));
END;
inSysWindow:
SystemClick(gEvent, vWhichWindow);
OTHERWISE
DoWindowClick(vPart, vWhichWindow);
END;
END;
END; {DoMouseDown}
{========================================}
PROCEDURE DoKeyPress (vChar: CHAR);
BEGIN
oWindow.KeyPress(vChar);
END; {DoKeyPress}
{----------------------------------------}
PROCEDURE DoKeyDown;
VAR
vCharCode: CHAR;
BEGIN
WITH gEvent DO
BEGIN
vCharCode:= CHR(BitAnd(message,charCodeMask));
IF BitAnd(modifiers, CmdKey) = CmdKey THEN
BEGIN
SetStdMenuItems;
SetMyMenuItems;
DoMenuClick(MenuKey(vCharCode));
END
ELSE
DoKeyPress(vCharCode);
END;
END; {DoKeyDown}
{========================================}
PROCEDURE DoUpdate;
VAR
vWhichWindow: WindowPtr;
BEGIN
vWhichWindow:= WindowPtr(gEvent.message);
oWindow:= TWindow(GetWRefCon(vWhichWindow));
oWindow.Update;
END; {DoUpdate}
{========================================}
PROCEDURE DoActivate;
VAR
vWhichWindow: WindowPtr;
BEGIN
vWhichWindow:= WindowPtr(gEvent.message);
oWindow:= TWindow(GetWRefCon(vWhichWindow));
oWindow.fWPtr:= vWhichWindow;
oWindow.Activate;
SetMyMenuBar;
END; {DoActivate}
{========================================}
PROCEDURE DoDiskEvent;
VAR
vPt: Point;
vErr: OSErr;
BEGIN
IF HiWrd(gEvent.message) <> noErr THEN
BEGIN
CenterDialogBox(290, 100, vPt);
vErr:= DIBadMount(vPt, gEvent.message);
IF vErr IN [1, 2, noErr, ioErr, badMDBErr, noMacDskErr] THEN
ELSE IF OSError(vErr) THEN
END;
END; {DoDiskEvent}
{========================================}
PROCEDURE DoMFEvent;
VAR
vWhichWindow: WindowPtr;
BEGIN
IF Odd(gEvent.message) THEN
BitSet(@gEvent.modifiers, 15)
ELSE
BitClr(@gEvent.modifiers, 15);
IF IsAppWindow(FrontWindow) THEN
BEGIN
oWindow:= TWindow(GetWRefCon(FrontWindow));
oWindow.fWPtr:= FrontWindow;
oWindow.Activate;
END;
END; {DoMFEvent}
{========================================}
PROCEDURE ShutDown;
BEGIN
DisposHandle(Handle(gPrintHdl));
DisposeRgn(gMouseRgn);
DisposeStdMenus;
DisposeMyMenus;
END; {ShutDown}
{========================================}
{$I-}
BEGIN {main}
InitToolbox(kMasters);
InitGlobals;
InitRects;
InitPrint;
InitStdMenus;
InitMyMenus;
DrawMenuBar;
CheckFinder;
REPEAT
DoApplTasks;
IF gMFEvent THEN
gNextEvent:= WaitNextEvent(everyEvent, gEvent, gSleep, gMouseRgn)
ELSE
BEGIN
SystemTask;
gNextEvent:= GetNextEvent(everyEvent, gEvent);
END;
IF gNextEvent THEN
CASE gEvent.what OF
NullEvent:
;
MouseDown:
DoMouseDown;
KeyDown:
DoKeyDown;
AutoKey:
DoKeyDown;
UpdateEvt:
DoUpdate;
ActivateEvt:
DoActivate;
DiskEvt:
DoDiskEvent;
NetworkEvt:
;
DriverEvt:
;
App1Evt:
;
App2Evt:
;
App3Evt:
;
App4Evt:
DoMFEvent;
OTHERWISE
END;
UNTIL gDone;
ShutDown;
END. {main}
{****************************************}