TweetFollow Us on Twitter

Tear-Off
Volume Number:3
Issue Number:12
Column Tag:Pascal Procedures

Tear-Off Menus Explained

By Darryl Lovato, TML Systems, MacTutor Contributing Editor

Hello once again, this month I would like to show how to implement tear-off menus. What is a tear-off menu? It is a menu which can be removed from the menu bar and used as a window. I first saw a tear off menu in a pre-release version of Hypercard by Bill Atkinson. Since I have had a lot of experience creating and using Menu and Window Definition routines, I thought I would try to duplicate his implementation of tear-offs so that MacTutor readers can see how it is done and use them in their own programs.

I assume that you know how menu and window definition routines work. If you are not familiar with them read my articles in the July, August, and October 1986 issues of MacTutor.

The Window Definition routine used in the example is fairly straight forward, and, in fact, really isn’t needed. It’s sole purpose is to NOT look like a regular window. To do this I made the window’s title bar small and solid black. The pattern drawing is not a part of the definition routine. It is handled in a update event as any other window’s contents. The window looks like the one in figure 1.

Figure 1

The Menu Definition routine used in the example is where the special tear-menu code is. The tear-off menu in figure 2 looks very similar to the tear-off window. The size and draw messages are just as you would expect. The choose message, however, has some special coding to implement the tear-off. When we get the choose message, and the mouse is outside of the menu rectangle we check to see how far outside it is. If it is more than 10 pixels outide of the menu rectange, then we do not return from the choose message routine. Instead, we drag a outline of the menu on the desktop region until the mouse comes up, the user moves the mouse over another menu, or the mouse is moved back onto the original menu. If the mouse comes up while we are tracking it, we send a message back to the program telling it to move and re-display the torn window at that point. We communicate this information by posting an event which is unused by the application. I picked event #12, but you could choose any of the application event numbers. We pass the top left coordinate of where to display the pallete window in the Event.message paramter.

When the main event loop gets event 12, it must move the menu to the location passed in the message and display the window.

Figure #2

There are a couple of things that need to be pointed out. First, drawing all the patterns is real slow (even on a MacII!!!). This could be improved a great deal by keeping a offscreen bitmap of the patterns and use copybits instead of drawing them. Second. I know I have done a big no-no by not making the menu and window defs code resources. Third, you should be able to edit the patterns by double clicking on them to bring up a pattern editor window. Fourth, it would be great if the patterns could be in color on a Mac II. I leave the above enhancements to you as an exersize.

The program I used to create the tear-off windows is given below. It was written is TML Pascal, but the techniques shown should be usefull no matter what language your using. Have fun!

Pascal Code Optimizations

I would like to share some secrets with MacTutor readers out there who strive for the fastest, smallest Pascal code. My tricks will not improve your code 500%, as re-designing a algorithm could, but they can help you get the most out of the code generated by your compiler. These tricks are for TML Pascal, but should help you generate better code in any Pascal.

1. Always use Inc(x) and Dec(x) procedures instead of x := x + 1 or x := x - 1. The inc and dec procedures generate one assembler instruction as opposed to 3 for x := x + 1. This saves 6 bytes each time you use it. When inc and dec are used in loops, this can save a lot of execution time. [Unfortuanately, these are not available in other implementations. -Ed]

2. If you pass a structure larger than 4 bytes to a procedure or function, pass it as a static paramter. When you use a static, instead of regular parameters, you save 18 bytes per paramter in code size. This saves a lot of execution time, too. The reason for this is that when you pass a large structure as a static parameter, it is not copied local to the procedure. This is especially usefull if you pass a lot of strings to procedures and functions.

3. In certain if..then..else statements, you can save code by restructuring the statement to eliminate the else, and 4 bytes!

4. For loops are code hogs! Because Pascal compilers check the bounds of ‘for’ loops before entering them, they generate a lot of error checking. By recoding a ‘for’ loop as a repeat loop you can save 16 bytes. Here is an example:

Instead of this:

 for x := 1 to 100 do
   begin
   end;

Do this:

 x := 1;
 repeat
   inc(x);
 until x = 100;

There are a lot of other optimizations that can be done to make faster, smaller Pascal code, but these are the ones that can be used the most. Of course, re-writting the code in assembler would make the biggest diffrence in code size and speed, but that can take a long time and there are a lot of people who do not understand 680x0 assembler.

[The following code has been sanitized to work in both TML Pascal and LS Pascal and has been tested in both. However, one of the functions that returns a rect as an argument tripped up the Turbo Pascal syntax checker, so some modification may be necessary to get the program compiled in Turbo. We are at a loss as to why Turbo should be more picky than LS Pascal, which I thought was the most fussy of all! The code should also work fine in MPW, but we didn’t take the time to actually try it. -Ed]

We welcome Darryl back to MacTutor and present him with our Program of the Month award for this important and timely example of tear-off menus. One reader wanted it so bad, he made me send an advance copy of the article next day air so his department could get to work on it. Thanks Darryl!

{1}
Listing 1 TML & LS Pascal Source Code
PROGRAM TearMenu;

{ Example of tear-off menus}
{ by Darryl Lovato of TML for MacTutor}
{ Inspired by HyperCard}
{ TML Pascal / LS Pascal Version }
{ Some modifications may be required for Turbo Pascal }
{ Turbo Pascal does not seem to like a rect as }
{ a return variable from a function. }

uses MacIntf;    { remove for LS Pascal }

{$T APPL TEAR}   { remove for LS Pascal }
{$B+}   { remove for LS Pascal }
{$L TearMenuRes} { remove for LS Pascal }

{global constants}
CONST
 AppleMenuID = 1;
 FileMenuID = 2;
 EditMenuID = 3;
 graphicalMenu = 4;
 WindResID = 1;
 AboutID = 3000;

{global variables}
VAR
 myMenus : ARRAY[AppleMenuID..EditMenuID] OF MenuHandle;
 Done : Boolean;
 RegWDEFWindow : WindowPtr;
 GrowArea : rect;
 DragArea : rect;
 myWindowPeek : WindowPeek;
 MyGraphicsMenu : menuhandle;
 currentPatWind : WindowPtr;

{ My Window Definition Function }

 FUNCTION MyWindowDef (varCode : Integer;
 theWindow : WindowPtr;
 message : Integer;
 param : LongInt) : LongInt;
 TYPE
 RectPtr = ^Rect;

 VAR
 aRectPtr : RectPtr;
 myWindowPeek : WindowPeek;

{ Nested procedures follow }
 PROCEDURE DoDrawMessage (WindToDraw : WindowPtr;
 DrawParam : LongInt);
 VAR
 TitleBarRect : Rect;
 CurrentY : Integer;
 index : Integer;
 GoAwayBox : Rect;
 Show : boolean;
 WindowRec : WindowPeek;
 BEGIN
 WindowRec := WindowPeek(WindToDraw);
 Show := WindowRec^.visible;
 IF Show THEN
 BEGIN
 TitleBarRect := WindowRec^.strucRgn^^.rgnBBox;
 IF DrawParam <> 0 THEN {just toggle goAway box}
 BEGIN
 WITH TitleBarRect DO
 BEGIN
 top := top + 3;
 left := left + 5;
 bottom := top + 8;
 right := left + 8;
 END;
 InsetRect(TitleBarRect, 1, 1);
 InvertRect(TitleBarRect);
 END
 ELSE {we need to draw the window frame}
 BEGIN
 PenNormal;
 FrameRect(TitleBarRect);
 TitleBarRect.bottom := TitleBarRect.top + 13;

 FrameRect(TitleBarRect);
 InsetRect(TitleBarRect, 1, 1); {shrink by 1}
 EraseRect(TitleBarRect);

 IF WindowRec^.hilited THEN
 BEGIN { add hiliting }
 FillRect(TitleBarRect, black);
 WITH TitleBarRect DO
 BEGIN
 top := top + 2;
 left := left + 4;
 bottom := top + 8;
 right := left + 8;
 END;
 PenMode(patXor);
 FrameRect(TitleBarRect);
 PenNormal;
 END;
 END;
 END;
 END;

 FUNCTION DoHitMessage (WindToTest : WindowPtr;
 theParam : LongInt) : LongInt;
 VAR
 globalPt : Point;
 aRect : Rect;
 GoAwayBox : Rect;
 tempRect : Rect;
 WindowRec : WindowPeek;
 BEGIN
 globalPt.h := LoWord(theParam);
 globalPt.v := HiWord(theParam);
 WindowRec := WindowPeek(WindToTest);
 aRect := WindowRec^.strucRgn^^.rgnBBox;
 aRect.bottom := aRect.top + 12; {create tBar Rect}
 tempRect := WindowRec^.strucRgn^^.rgnBBox;
 IF PtInRect(globalPt, tempRect) THEN {in structure rgn?}
 BEGIN
 tempRect := WindowRec^.contRgn^^.rgnBBox;
 IF PtInRect(globalPt,tempRect) THEN {if content rgn}
 DoHitMessage := wInContent
 ELSE IF PtInRect(globalPt, aRect) THEN {drag}
 BEGIN
 IF WindowRec^.hilited THEN
 BEGIN {we need to check go-away box}
 WITH aRect DO
 BEGIN
 top := top + 2;
 left := left + 4;
 bottom := top + 8;
 right := left + 8;
 END;
 IF PtInRect(globalPt, aRect) THEN
 DoHitMessage := wInGoAway
 ELSE
 DoHitMessage := wInDrag;
 END
 ELSE
 DoHitMessage := wInDrag;
 END
 ELSE {it was in our window frame}
 DoHitMessage := wNoHit;
 END
 ELSE {it wasn’t in our window at all}
 DoHitMessage := wNoHit;
END;

PROCEDURE DoCalcRgnsMessage (WindToCalc : WindowPtr);
 VAR
 tempRect : Rect;
 aWindowPeek : WindowPeek;
 aRgn : RgnHandle;
 WindowRec : WindowPeek;
BEGIN
 tempRect := WindToCalc^.PortRect;
 OffsetRect(tempRect, -WindToCalc^.PortBits.Bounds.Left, -WindToCalc^.PortBits.Bounds.Top);

 TempRect.top := TempRect.top - 1;
 WindowRec := WindowPeek(WindToCalc);
 RectRgn(WindowRec^.contRgn, tempRect);

 InsetRect(tempRect, -1, -1);
 tempRect.top := tempRect.top - 12;
 RectRgn(WindowRec^.strucRgn, tempRect);
END;

{ End of nested procedures }
BEGIN
 MyWindowDef := 0;
 CASE message OF
 wDraw : 
 DoDrawMessage(theWindow, param);
 wHit : 
 MyWindowDef := DoHitMessage(theWindow, param);
 wCalcRgns : 
 DoCalcRgnsMessage(theWindow);
 wNew : 
 ;
 wDispose : 
 ;
 wGrow : 
 ;
 END; {of case}
END;

{ -------------------------------------------- }
{function GetItemRect(item : integer) : rect; }

FUNCTION GetItemRect (item : integer) : rect;
VAR
 tempRect : Rect;
BEGIN
 WITH tempRect DO
 BEGIN
 top := (((item - 1) DIV 8) * 16) - 1;
 bottom := top + 17;
 left := (((item - 1) MOD 8) * 16) - 1;
 right := left + 17;
 END;
 GetItemRect := tempRect;
END;

{procedure DrawPatWindow;   }

PROCEDURE DrawPatWindow;
 VAR
 i : integer;
 currentPat : Pattern;
 currRect : Rect;
BEGIN
 FOR i := 1 TO 96 DO
 BEGIN
 currRect := GetItemRect(i);
 FrameRect(currRect);
 GetIndPattern(currentPat, 100, i);
 FillRect(currRect, currentPat);
 FrameRect(currRect);
 END;
END;

{function GetMItemRect(whichRect:Integer;myRect:Rect):Rect;}

FUNCTION GetMItemRect (whichRect : Integer;
 myRect : Rect) : Rect;
 VAR
 ItemRect : Rect;
BEGIN
 ItemRect := GetItemRect(whichRect);
 OffSetRect(itemRect, myRect.left, myRect.top);
 GetMItemRect := ItemRect;
END;

{procedure drawItem(myRect : rect; myItem : integer); }

PROCEDURE drawItem (myRect : rect;
 myItem : integer);
 VAR
 currentPat : pattern;
BEGIN
 IF (myItem > 0) AND (myItem < 97) THEN
 BEGIN
 myRect := GetMItemRect(myItem, myRect);
 GetIndPattern(currentPat, 100, myItem);
 FillRect(myRect, currentPat);
 FrameRect(myRect);
 END;
END;

{procedure clearitem(myRect : Rect; lastCell : integer); }

PROCEDURE clearitem (myRect : Rect;
 lastCell : integer);
BEGIN
 DrawItem(myRect, lastCell - 9);
 DrawItem(myRect, lastCell - 8);
 DrawItem(myRect, lastCell - 7);
 DrawItem(myRect, lastCell - 1);
 DrawItem(myRect, lastCell);
 DrawItem(myRect, lastCell + 1);
 DrawItem(myRect, lastCell + 7);
 DrawItem(myRect, lastCell + 8);
 DrawItem(myRect, lastCell + 9);
END;

{Menu Definition Routine   }

PROCEDURE MyMenuDef (message : Integer;
 theMenu : MenuHandle;
 VAR menuRect : Rect;
 hitPt : Point;
 VAR whichItem : Integer);

{ Begin nested procedrues }
 PROCEDURE DoDrawMessage (myMenu : MenuHandle;
 myRect : Rect);
 CONST
 MBarHeight = 20;
 VAR
 whichRect : Integer;
 currentPat : Pattern;
 currRect : Rect;
 BEGIN
 FOR whichRect := 1 TO 96 DO
 Drawitem(myRect, whichRect);
 END;

 FUNCTION DoChooseMessage (myMenu : MenuHandle;
 myRect : Rect;
 myPoint : Point;
 oldItem : Integer) : Integer;
 VAR
 currRect : Rect;
 alldone : boolean;
 whichRect : Integer;
 oldRect : Rect;
 mPt : Point;
 lastPt : Point;
 lastRect : Rect;
 menuPt : Point;
 tempRect : Rect;
 exitrect : rect;
 saveClip : RgnHandle;
 io : integer;
 BEGIN
 ClipRect(myRect);
 whichRect := 1;
 alldone := false;
 REPEAT
 currRect := GetMItemRect(whichRect, myRect);
 IF PtInRect(myPoint, currRect) THEN
 alldone := true
 ELSE
 whichRect := whichRect + 1;
 UNTIL ((AllDone) OR (whichRect > 96));
 IF AllDone THEN { if we are in a item}
 BEGIN
 IF (whichRect <> oldItem) THEN
 BEGIN
 IF (oldItem <> 0) THEN
 ClearItem(myRect, oldItem);
 InsetRect(currRect, -6, -6);
 PenSize(6, 6);
 PenPat(white);
 FrameRect(currRect);
 PenNormal;
 InsetRect(currRect, -1, -1);
 FrameRect(currRect);
 END;
 DoChooseMessage := whichRect;
 END
 ELSE { we are not in a item}
 BEGIN
 IF oldItem <> 0 THEN { invert the old item}
 clearitem(myRect, oldItem);
 DoChooseMessage := 0;

 PenMode(notPatXOR);
 penpat(gray);
 exitrect := myrect;
 InsetRect(ExitRect, -10, -10);
 ExitRect.top := 20;
 menuPt.h := myRect.left + ((myRect.right - myRect.left) DIV 2);
 menuPt.v := myRect.top + ((myRect.bottom - myRect.top) DIV 2);
 SetRect(tempRect, 0, 0, 0, 0);
 lastRect := tempRect;
 ClipRect(screenbits.bounds);
 REPEAT
 GetMouse(mPt);
 LocalToGlobal(mPt);
 IF ((Longint(mpt) <> Longint(lastPt)) AND (NOT PtInRect(mpt, ExitRect)) 
AND (mPt.v > 20)) THEN
 BEGIN
 lastPt := mPt;
 tempRect := myRect;
 OffSetRect(tempRect, mPt.h - menuPt.h, mPt.v - menuPt.v);
 IF tempRect.top < 20 THEN
 BEGIN
 tempRect.top := 20;
 tempRect.bottom := 20 + 202;
 END;
 FrameRect(lastRect);
 FrameRect(tempRect);
 lastRect := tempRect;
 END;
 UNTIL (NOT button) OR ptInRect(mPt, exitrect) OR (mPt.v < 21);
 FrameRect(lastRect);
 PenNormal;
 IF (NOT PtInRect(mpt, ExitRect)) AND (mPt.v > 20) THEN
 BEGIN
 lastrect.top := lastrect.top + 12;
 io := PostEvent(12,Longint(lastRect.topleft));
        { this communicates back to the main event}
        { loop that a window was just torn from the}
        { menu.  We pass the new topLeft in the message}
 END;
 END;
 END;

 PROCEDURE DoSizeMessage (VAR myMenu : MenuHandle);
 BEGIN
 WITH myMenu^^ DO
 BEGIN
 menuWidth := 127;
 menuHeight := 191;
 END;
 END;

{ End of nested procedures }
BEGIN
 CASE message OF
 mSizeMsg : 
 DoSizeMessage(theMenu);
 mDrawMsg : 
 DoDrawMessage(theMenu, menuRect);
 mChooseMsg : 
 whichItem := DoChooseMessage(theMenu, menuRect, hitPt, whichItem);
 END;
END;

{ ---------------------------------- }
{ShowAbout procedure  }

PROCEDURE ShowAbout;
 VAR
 theDlog : DialogPtr;
 theItem : Integer;
BEGIN
 theDlog := GetNewDialog(AboutID, NIL, Pointer(-1));
 ModalDialog(NIL, theItem);
 DisposDialog(theDlog);
END;

{  ProcessMenu procedure   }

PROCEDURE ProcessMenu (codeWord : Longint);
 TYPE
 PatPtr = ^Pattern;
 VAR
 menuNum : Integer;
 itemNum : Integer;
 NameHolder : str255;
 dummy : Integer;
 yuck : boolean;
 myPattern : Pattern;
 DeskPatternPtr : PatPtr;
 savePort, aPort : grafPtr;
 theRgn1, theRgn2 : RgnHandle;
BEGIN
IF codeWord <> 0 THEN
 BEGIN
 menuNum := HiWord(codeWord);
 itemNum := LoWord(codeWord);
 CASE menuNum OF { the different menus}
 AppleMenuID : 
 IF itemNum < 3 THEN
 ShowAbout
 ELSE
 BEGIN
 GetItem(myMenus[AppleMenuID], itemNum, NameHolder);
 dummy := OpenDeskAcc(NameHolder);
 END;
 FileMenuID : 
 Done := true;
 EditMenuID : 
 yuck := SystemEdit(itemNum - 1);
 GraphicalMenu : 
 IF ItemNum <> 0 THEN
 BEGIN
 GetIndPattern(myPattern, 100, ItemNum);
 SetPort(currentPatWind);
 BackPat(myPattern);
 EraseRect(currentPatWind^.portRect);
 END;
 END;
 HiliteMenu(0);
 END;
END;

{Deal With Mouse Downs procedure }

 PROCEDURE DealWithMouseDowns (theEvent : EventRecord);
 VAR
 location : Integer;
 windowPointedTo : WindowPtr;
 mouseLoc : point;
 windowLoc : integer;
 VandH : Longint;
 Height : Integer;
 Width : Integer;
 currRect, myRect : Rect;
 newcell, LastCell : integer;
 thePt, LastPt : Point;
 i : integer;
 myPattern : Pattern;
 BEGIN
 mouseLoc := theEvent.where;
 windowLoc := FindWindow(mouseLoc, windowPointedTo);
 CASE windowLoc OF
 inMenuBar : 
 ProcessMenu(MenuSelect(mouseLoc));
 inSysWindow : 
 SystemClick(theEvent, windowPointedTo);
 inContent : 
 IF windowPointedTo <> FrontWindow THEN
 SelectWindow(windowPointedTo)
 ELSE
 BEGIN
 IF RegWDEFWindow = windowPointedTo THEN
 BEGIN
 SetPort(RegWDEFWindow);
 GetMouse(lastPt);
 newCell := 0;
 lastCell := 0;
 myRect := RegWDEFWindow^.portRect;
 WHILE waitmouseup DO {track in pattern wind}
 BEGIN
 GetMouse(thePt);
 IF NOT PtInRect(thePt, myRect) THEN
 BEGIN {we moved outside the window}
 IF lastCell <> 0 THEN
 clearItem(myRect, lastCell);
 lastCell := 0;
 END
 ELSE
 BEGIN
 FOR i := 1 TO 96 DO
 IF PtInRect(thePt, GetItemRect(i)) THEN
 newCell := i;
 IF newCell <> lastCell THEN
 BEGIN
 IF (lastCell <> 0) THEN
 Clearitem(myRect, lastCell);
 currRect := GetItemRect(newCell);
 InsetRect(currRect, -6, -6);
 PenSize(6, 6);
 PenPat(white);
 FrameRect(currRect);
 PenNormal;
 InsetRect(currRect, -1, -1);
 FrameRect(currRect);
 lastCell := newCell;
 END;
 END;
 END;
 Clearitem(myRect, lastCell);
 GetIndPattern(myPattern, 100, newCell);
 SetPort(currentPatWind);
 BackPat(myPattern);
 EraseRect(currentPatWind^.portRect);
 END;
 END;
 inDrag : 
 BEGIN
 DragWindow(windowPointedTo, mouseLoc, DragArea);
 SelectWindow(windowPointedTo);
 END;
 inGoAway : 
 IF TrackGoAway(windowPointedTo, mouseLoc) THEN
 HideWindow(windowPointedTo);
 END;
END;

{Deal With Key Downs procedure}

 PROCEDURE DealWithKeyDowns (theEvent : EventRecord);
 TYPE
 Trick = PACKED RECORD
 CASE boolean OF
 true:(
 long : Longint
 );
 false : (
 chr3, chr2, chr1, chr0 : char
 )
 END;
 VAR
 CharCode : char;
 TrickVar : Trick;
 BEGIN
 TrickVar.long := theEvent.message;
 CharCode := TrickVar.chr0;
 IF BitAnd(theEvent.modifiers, CmdKey) = CmdKey THEN           
 {check for a menu selection}
 ProcessMenu(MenuKey(CharCode))
 END;

{Deal With Updates procedure}

 PROCEDURE DealWithUpdates (theEvent : EventRecord);
 VAR
 UpDateWindow : WindowPtr;
 tempPort : WindowPtr;

 BEGIN
 UpDateWindow := WindowPtr(theEvent.message);
 GetPort(tempPort);
 SetPort(UpDateWindow);
 BeginUpDate(UpDateWindow);
 EraseRect(UpDateWindow^.portRect);
 IF UpdateWindow <> currentPatWind THEN
 DrawPatWindow;
 EndUpDate(UpDateWindow);
 SetPort(tempPort);
 END;

{MainEventLoop procedure  }

 PROCEDURE MainEventLoop;
 VAR
 Event : EventRecord;
 ProcessIt : boolean;
 where : Point;
 BEGIN
 REPEAT
 SystemTask;
 IF GetNextEvent(everyEvent, Event) THEN
 CASE Event.what OF
 mouseDown : 
 DealWithMouseDowns(Event);
 AutoKey : 
 DealWithKeyDowns(Event);
 KeyDown : 
 DealWithKeyDowns(Event);
 UpdateEvt : 
 DealWithUpdates(Event);
 12 : 
 BEGIN { we return this when a window torn}
 where := Point(Event.message);
 HideWindow(RegWDefWindow);
 MoveWindow(RegWDefWindow, where.h, where.v, true);
 ShowWindow(RegWDEFWindow);
 END;
 OTHERWISE
 BEGIN
 END;
 END; {of case}
 UNTIL Done;
 END;

{SetupMemory procedure      }

 PROCEDURE SetupMemory;
 VAR
 x : Longint;
 BEGIN
{x := ORD4(ApplicZone) + 128000;}
{SetApplLimit(Pointer(x));}
 MaxApplZone;
 MoreMasters;
 MoreMasters;
 MoreMasters;
 END;

{ SetupLimits    }

 PROCEDURE SetupLimits;
 VAR
 Screen : Rect;
 BEGIN
 Screen := ScreenBits.bounds;
 WITH Screen DO
 BEGIN
 SetRect(DragArea, left+4, top+24, right-4, bottom-4);
 SetRect(GrowArea, left, top + 24, right, bottom);
 END;
 END;

{MakeMenus procedure   }

 PROCEDURE MakeMenus;
 VAR
 index : Integer;
 BEGIN
 FOR index := AppleMenuID TO EditMenuID DO
 BEGIN
 myMenus[index] := GetMenu(index);
 InsertMenu(myMenus[index], 0);
 END;
 AddResMenu(myMenus[AppleMenuID], ‘DRVR’);
 MyGraphicsMenu := NewMenu(4, ‘Graphics’);
 MyGraphicsMenu^^.menuProc := NewHandle(0);
 MyGraphicsMenu^^.menuProc^ := Ptr(@MyMenuDef);
 CalcMenuSize(MyGraphicsMenu);
 Insertmenu(MyGraphicsMenu, 0);
 DrawMenuBar;
 END;

 PROCEDURE crash;
 BEGIN
 ExitToShell;
 END;

{ ---------------------------------- }
{Main Program Excecution Starts Here }

BEGIN
 InitGraf(@thePort);
 InitFonts;
 InitWindows;
 InitMenus;
 TEInit;
 InitDialogs(@crash);
 InitCursor;
 Done := false;
 FlushEvents(everyEvent, 0);

 SetupLimits;
 SetupMemory;
 MakeMenus;

 RegWDEFWindow := GetNewWindow(WindResID, NIL, Pointer(-1));
 myWindowPeek := WindowPeek(RegWDEFWindow);
 myWindowPeek^.windowDefProc := NewHandle(0);
 myWindowPeek^.windowDefProc^ := Ptr(@MyWindowDef);
 SetWRefCon(RegWDEFWIndow, Ord4(MyGraphicsMenu));
 currentPatWind := GetNewWindow(2, NIL, pointer(-1));
 SetPort(currentPatWind);
 BackPat(gray);
 EraseRect(currentPatWind^.portRect);

 MainEventLoop;
END. {thats all folkes!}
{2}
Listing 2: TML Link File (Ignore for LS Pascal )
!PAS$Xfer

/Globals -4
TearMenu
PAS$Library
macintf
MacIntfGlue
/Resources
TearMenuRes
/Bundle
/Type  APPL TEAR
/End


Listing 3: REZ version resource file

resource ‘BNDL’ (128) {
 ‘TEAR’,
 0,
 { /* array TypeArray: 2 elements */
 /* [1] */
 ‘ICN#’,
 { /* array IDArray: 1 elements */
 /* [1] */
 0, 128
 },
 /* [2] */
 ‘FREF’,
 { /* array IDArray: 1 elements */
 /* [1] */
 0, 128
 }
 }
};

resource ‘DITL’ (3000) {
 { /* array DITLarray: 3 elements */
 /* [1] */
 {155, 142, 180, 205},
 Button {
 enabled,
 “Okay”
 },
 /* [2] */
 {6, 5, 112, 361},
 StaticText {
 disabled,
 “                                 - Tear “
 “Menu -\n\nWritten by Darryl Lovato of TML “
 “Systems, Inc.\n\nThis program shows how to”
 “ make a window tear off of a menu.  Idea”
 “ from Hypercard by Bill Atkinson.\n”
 },
 /* [3] */
 {115, 5, 149, 361},
 StaticText {
 enabled,
 “Complete Pascal source code for this pro”
 “gram is available from MacTutor Magazine”
 “.”
 }
 }
};

resource ‘DLOG’ (3000, preload) {
 {58, 74, 244, 436},
 dBoxProc,
 visible,
 goAway,
 0x0,
 3000,
 “New Dialog”
};

resource ‘FREF’ (128) {
 ‘APPL’,
 0,
 “”
};
resource ‘ICN#’ (128, purgeable, preload) {
 { /* array: 2 elements */
 /* [1] */
 $”000F F400 007A FD00 01FF F780 05FF 7FE0"
 $”07FF FFB0 0BFB FFD8 0FFF B578 1FDF F6FC”
 $”1F7E E8BC 1E77 A074 3E37 807C 1C00 006C”
 $”3FF0 3E3C 2E38 633C 3DE0 3C24 1E60 4C24"
 $”1400 4004 1C00 0004 0C00 4008 0400 0038"
 $”0404 6028 0001 8038 0200 0078 0008 1050"
 $”0103 C060 0180 0140 0780 0040 7D20 0440"
 $”4510 0820 4887 E050 4980 0088 7FFF FFF8",
 /* [2] */
 $”000F F400 007F FD00 01FF FF80 05FF FFE0"
 $”07FF FFF0 0FFF FFF8 0FFF FFF8 1FFF FFFC”
 $”1FFF FFFC 1FFF FFFC 3FFF FFFC 1FFF FFFC”
 $”3FFF FFFC 3FFF FFFC 3FFF FFFC 1FFF FFFC”
 $”1FFF FFFC 1FFF FFFC 0FFF FFF8 07FF FFF8"
 $”07FF FFF8 03FF FFF8 03FF FFF8 01FF FFF0"
 $”01FF FFE0 01FF FFC0 07FF FFC0 7FFF FFC0"
 $”7FFF FFE0 7FFF FFF0 7FFF FFF8 7FFF FFF8"
 }
};
resource ‘MENU’ (1) {
 1,
 textMenuProc,
 0x7FFFFFFD,
 enabled,
 apple,
 { /* array: 2 elements */
 /* [1] */
 “About Tear Menu...”, noIcon, “”, “”, plain,
 /* [2] */
 “-”, noIcon, “”, “”, plain
 }
};
resource ‘MENU’ (2) {
 2,
 textMenuProc,
 0x7FFFFFF5,
 enabled,
 “File”,
 { /* array: 1 elements */
 /* [1] */
 “Quit”, noIcon, “Q”, “”, plain
 }
};
resource ‘MENU’ (3) {
 3,
 textMenuProc,
 0x7FFFFFFD,
 enabled,
 “Edit”,
 { /* array: 6 elements */
 /* [1] */
 “Undo”, noIcon, “Z”, “”, plain,
 /* [2] */
 “-”, noIcon, “”, “”, plain,
 /* [3] */
 “Cut”, noIcon, “X”, “”, plain,
 /* [4] */
 “Copy”, noIcon, “C”, “”, plain,
 /* [5] */
 “Paste”, noIcon, “V”, “”, plain,
 /* [6] */
 “Clear”, noIcon, “”, “”, plain
 }
};
resource ‘WIND’ (1) {
 {100, 100, 292, 228},
 documentProc,
 invisible,
 goAway,
 0x0,
 “”
};
resource ‘WIND’ (2) {
 {81, 143, 224, 327},
 documentProc,
 visible,
 goAway,
 0x0,
 “Current Pattern”
};
data ‘TEAR’ (0) {
 $”1B54 6561 7220 4D65 6E75 2C20 6279 2044" 
 $”6172 7279 6C20 4C6F 7661 746F” 
};
resource ‘PAT#’ (100, purgeable) {
 { /* array PatArray: 96 elements */
 /* [1] */
 $”FFFF FFFF FFFF FFFF”,
 /* [2] */
 $”DDFF 77FF DDFF 77FF”,
 /* [3] */
 $”DD77 DD77 DD77 DD77",
 /* [4] */
 $”AA55 AA55 AA55 AA55",
 /* [5] */
 $”55FF 55FF 55FF 55FF”,
 /* [6] */
 $”AAAA AAAA AAAA AAAA”,
 /* [7] */
 $”EEDD BB77 EEDD BB77",
 /* [8] */
 $”8888 8888 8888 8888",
 /* [9] */
 $”B130 031B D8C0 0C8D”,
 /* [10] */
 $”8010 0220 0108 4004",
 /* [11] */
 $”FF88 8888 FF88 8888",
 /* [12] */
 $”FF80 8080 FF08 0808",
 /* [13] */
 $”80",
 /* [14] */
 $”8040 2000 0204 08",
 /* [15] */
 $”8244 3944 8201 0101",
 /* [16] */
 $”F874 2247 8F17 2271",
 /* [17] */
 $”55A0 4040 550A 0404",
 /* [18] */
 $”2050 8888 8888 0502",
 /* [19] */
 $”BF00 BFBF B0B0 B0B0",
 /* [20] */
 $””,
 /* [21] */
 $”8000 0800 8000 08",
 /* [22] */
 $”8800 2200 8800 22",
 /* [23] */
 $”8822 8822 8822 8822",
 /* [24] */
 $”AA00 AA00 AA00 AA”,
 /* [25] */
 $”FF00 FF00 FF00 FF”,
 /* [26] */
 $”1122 4488 1122 4488",
 /* [27] */
 $”FF00 0000 FF”,
 /* [28] */
 $”0102 0408 1020 4080",
 /* [29] */
 $”AA00 8000 8800 80",
 /* [30] */
 $”FF80 8080 8080 8080",
 /* [31] */
 $”081C 22C1 8001 0204",
 /* [32] */
 $”8814 2241 8800 AA”,
 /* [33] */
 $”40A0 0000 040A”,
 /* [34] */
 $”0384 4830 0C02 0101",
 /* [35] */
 $”8080 413E 0808 14E3",
 /* [36] */
 $”1020 54AA FF02 0408",
 /* [37] */
 $”8000 0000 08",
 /* [38] */
 $”80",
 /* [39] */
 $”0002 4000 0000 0080",
 /* [40] */
 $”0002 4000 0000 0880",
 /* [41] */
 $”8000 1000 8002 0020",
 /* [42] */
 $”8002 0010 8002 0010",
 /* [43] */
 $”0092 0000 9200 0092",
 /* [44] */
 $”0092 0008 8220 0092",
 /* [45] */
 $”0092 0028 8228 0092",
 /* [46] */
 $”1082 1082 1082 1082",
 /* [47] */
 $”2288 2288 2288 2288",
 /* [48] */
 $”2288 22A8 2288 2288",
 /* [49] */
 $”2288 22A8 2288 2A88",
 /* [50] */
 $”228A 22A8 2288 2A88",
 /* [51] */
 $”228A 22A8 2288 AA88",
 /* [52] */
 $”228A A2A8 2288 AA88",
 /* [53] */
 $”228A AAA8 2288 AAA8",
 /* [54] */
 $”228A AAA8 228A AAA8",
 /* [55] */
 $”AA11 AA45 AA11 AA54",
 /* [56] */
 $”AA51 AA45 AA11 AA55",
 /* [57] */
 $”AA55 AA45 AA55 AA54",
 /* [58] */
 $”AA55 AA45 AA55 AA55",
 /* [59] */
 $”AA55 AA55 AA55 AA55",
 /* [60] */
 $”AA55 BA55 AA55 AA55",
 /* [61] */
 $”AA55 BA55 AA55 AB55",
 /* [62] */
 $”AA55 BA55 AA55 AB75",
 /* [63] */
 $”EE55 BA55 EA55 AB55",
 /* [64] */
 $”EE55 BA55 EE55 AB55",
 /* [65] */
 $”EE55 BA55 EE55 BB55",
 /* [66] */
 $”EE55 BB55 EE55 BB55",
 /* [67] */
 $”EE55 BB55 EE5D BB55",
 /* [68] */
 $”EE55 BB55 EE5D FB55",
 /* [69] */
 $”EE55 FB55 EE5D FB55",
 /* [70] */
 $”EE55 FF55 EE55 FF55",
 /* [71] */
 $”FF55 FF55 FF55 FF55",
 /* [72] */
 $”FF55 FF5D FF55 FF55",
 /* [73] */
 $”FF55 FF5D FF55 FFD5",
 /* [74] */
 $”FF55 FFDD FF55 FFD5",
 /* [75] */
 $”FF55 FFDD FF55 FFDD”,
 /* [76] */
 $”FF57 FF5D FF75 FFD5",
 /* [77] */
 $”FF57 FF7D FF7D FFD7",
 /* [78] */
 $”FFDD FFFF FFF7 FF7F”,
 /* [79] */
 $”FFDF FFFF FFF7 FF7F”,
 /* [80] */
 $”FFFF FFF7 FFFF FF7F”,
 /* [81] */
 $”FFFF FFFF FFFF FF7F”,
 /* [82] */
 $”FFFF FFFF FFFF FFFF”,
 /* [83] */
 $”7FBF DFBF 6BDD BD7B”,
 /* [84] */
 $”FF03 0509 1121 4181",
 /* [85] */
 $”FF83 4529 1129 4583",
 /* [86] */
 $”FF93 5539 FF39 5593",
 /* [87] */
 $”FE93 5539 EF39 5593",
 /* [88] */
 $”FE93 1139 EF39 1193",
 /* [89] */
 $”1010 1038 EF38 1010",
 /* [90] */
 $”1192 5438 EF38 5492",
 /* [91] */
 $”1192 5438 EF38 5492",
 /* [92] */
 $”55AA 55BA 6DBA 55AA”,
 /* [93] */
 $”5FA9 51A3 458A 55AA”,
 /* [94] */
 $”55EA 7DA6 65BE 57AA”,
 /* [95] */
 $”55AA 4182 4182 55AA”,
 /* [96] */
 $”46A6 FFFF 4686 57AE”
 }
 /** Extra bytes follow.. */
 /* $”0000 0034 0001 1400"
};
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Chromium 64.0.3282.167 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 64.0.3282.167: [806388] High CVE-2018-6056:... Read more
Parallels Desktop 13.3.0 - Run Windows a...
Parallels allows you to run Windows and Mac applications side by side. Choose your view to make Windows invisible while still using its applications, or keep the familiar Windows background and... Read more
Bookends 13.0.6 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Bookends uses the cloud to sync reference libraries on all the Macs you use.... Read more
macOS 10.13.3 Supplemental Update 1.0 -...
macOS High Sierra Supplemental Update includes security improvements to Safari and WebKit to mitigate the effects of Spectre. Version 1.0: Update fixes an issue where using certain character... Read more
ffWorks 1.0.6 - Convert multimedia files...
ffWorks (was iFFmpeg), focused on simplicity, brings a fresh approach to the use of FFmpeg, allowing you to create ultra-high-quality movies without the need to write a single line of code on the... Read more
Adobe Acrobat 18.011.20035 - Powerful PD...
Acrobat DC is available only as a part of Adobe Creative Cloud, and can only be installed and/or updated through Adobe's Creative Cloud app. Adobe Acrobat DC with Adobe Document Cloud services is... Read more
Adobe Acrobat Reader 18.011.20035 - View...
Adobe Acrobat Reader allows users to view PDF documents. You may not know what a PDF file is, but you've probably come across one at some point. PDF files are used by companies and even the IRS to... Read more
EtreCheck 4.0.3 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
Yummy FTP Pro 2.0 - $29.99
Yummy FTP Pro is an advanced Mac file transfer app which provides a full-featured professional toolkit combined with blazing speeds and impeccable reliability, so whether you want to transfer a few... Read more
Opera 51.0.2830.34 - High-performance We...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more

Latest Forum Discussions

See All

Check out these 5 games that are a lot l...
So you're in love with Minecraft, but you're looking for something else to play as well? You've come to the right place then, because this list is all about games that are a bit like Minecraft. Some of them, more than others. [Read more] | Read more »
Our top 5 characters from casual RPG Cre...
Creature Quest definitely lives up to its name with a host of collectible creatures based on fantasy tales and world mythologies. To celebrate Creature Quest’s first birthday, we’re going to lay out what we think are the five best characters in the... | Read more »
Around the Empire: What have you missed...
Did you know that Steel Media has a whole swathe of other sites dedicated to all aspects of mobile gaming? Sure you'll get the very best iPhone news, reviews, and opinions right here at 148Apps, but we don't want you missing out on a single piece... | Read more »
All the best games on sale for iPhone an...
Oh hi there, and welcome to our round-up of the best games that are currently on sale for iPhone and iPad. You thought I didn't see you there, did you, skulking behind the bushes? Trust me though, the bushes aren't where the best deals are. The... | Read more »
The Battle of Polytopia Guide - How to H...
A new update just released for The Battle of Polytopia (formerly Super Tribes), which introduces online multiplayer. For all the fans of Midjiwan’s lite take on Civilization, this is certainly welcome news, but playing online isn’t as easy and... | Read more »
Here are the very best mobile games to p...
It's Valentine's Day! Did you get loads of cards and chocolates and other tacky, simple expressions of human affection? Did you send out tat because you find it almost impossible to express emotion unless there's a section dedicated to it at your... | Read more »
Florence (Games)
Florence 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Florence is an interactive storybook from the award-winning lead designer of Monument Valley about the heart-racing highs and... | Read more »
Purrfect Date (Games)
Purrfect Date 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Cats are a lil’ like marmite. Either you absolutely head-over-heels love’ em, or… nahhh, who are we kidding?! Everyone... | Read more »
More monsters to collect and evolve in C...
A laid-back mix of RPG and TCG, Creature Quest is all about building your deck, evolving your creatures and winning in battle. It’s the creation of VC Mobile, set up by Might and Magic producer Jon Van Caneghem. There are elements of that classic... | Read more »
Check out this awesome hands-on with the...
Well, PlayerUnknown's Battlegrounds has come out on mobile. This isn't a clone, this isn't a riff on the battleroyale mechanics of the game, it's the official mobile port by Tencent. But there's a little bit of a hitch. [Read more] | Read more »

Price Scanner via MacPrices.net

Apple refurbished Mac minis in stock again st...
Apple has restocked Certified Refurbished Mac minis starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: – 1.4GHz Mac mini: $419 $80 off MSRP – 2.6GHz Mac... Read more
Tuesday MacBook Deals: $250 off 15″ 2.9GHz Ma...
Adorama has the Silver 15″ 2.9GHz Apple MacBook Pro on sale today for $250 off MSRP. Shipping is free, and Adorama charges sales tax for residents in NY & NJ only: – 15″ 2.9GHz Silver MacBook Pro... Read more
Save up to $350 with these Apple Certified Re...
Apple has a full line of Certified Refurbished iMacs available for up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: – 27... Read more
B&H offers $200 discount on Silver 15″ Ma...
B&H Photo has Silver 15″ Apple MacBook Pros on sale for $200 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 15″ 2.8GHz Touch Bar MacBook Pro Silver (... Read more
12″ Apple iPad Pro Sale of the Year! Models u...
B&H Photo has 12″ #iPad Pros on sale for up to $150 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: – 12″ 64GB WiFi iPad Pro: $719 $80 off MSRP – 12″ 256GB WiFi... Read more
Deals on 32GB 9″ iPads: Up to $50 off MSRP, s...
B&H Photo has 2017 9.7″ 32GB iPads on sale for $299 including free shipping plus NY & NJ sales tax only. Their price is $30 off MSRP, and it’s currently the lowest price available for these... Read more
15″ 2.2GHz Retina MacBook Pro available for o...
Apple has Certified Refurbished 15″ 2.2GHz Retina MacBook Pros available for $1699. That’s $300 off MSRP for this model, and it’s the lowest price available for a 15″ MacBook Pro currently offered by... Read more
13″ 3.1GHz/256GB Silver Touch Bar MacBook Pro...
Amazon has the Silver 13″ 3.1GHz/256GB Touch Bar MacBook Pro (MPXX2LL/A) on sale for $1649.99 including free shipping. Their price is $150 off MSRP, and it’s the lowest price available for a new 13″... Read more
Saturday Sale: Amazon offers 13″ 1.8GHz/256GB...
Amazon has the 13″ 1.8GHz/256B Apple MacBook Air on sale today for $250 off MSRP including free shipping: – 13″ 1.8GHz/256GB MacBook Air (MQD42LL/A): $949.99, $250 off MSRP Their price is the lowest... Read more
Roundup of Apple Certified Refurbished 12″ Ma...
Apple has Certified Refurbished 2017 12″ Retina MacBooks available for $200-$240 off the cost of new models. Apple will include a standard one-year warranty with each MacBook, and shipping is free.... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Strategist, *Apple* Media Products, Content...
# Strategist, Apple Media Products, Content and Marketing Job Number: 113399632 Santa Clara Valley, California, United States Posted: 20-Feb-2018 Weekly Hours: 40.00 Read more
*Apple* Store Leader - Retail District Manag...
Job Description:Job SummaryAs more and more people discover Apple , they visit our retail stores seeking ways to incorporate our products into their lives. It's your Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.