|
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 don’t 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 don’t 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 don’t 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 Chernicoff’s 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, let’s 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 it’s 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.
Let’s 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 let’s 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 don’t 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 Smith’s screen. Since then the Mac has changed the way people are using computers. Having covered already menus, let’s 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 window’s 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 window’s 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 don’t want to use Assembler, still nothing can beat Fortran! Absoft’s 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 Joe’s “Golden Ratio of Scrolling”, therefore I will mainly cover here the differences to other people’s 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 let’s 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 window’s 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} {****************************************}
- SPREAD THE WORD:
- Slashdot
- Digg
- Del.icio.us
- Newsvine