TweetFollow Us on Twitter

Window Menu Bars
Volume Number:7
Issue Number:10
Column Tag:Color Workshop

Related Info: Menu Manager Memory Manager Color Quickdraw

Window Menu Bars Revisited

By John A. Love, III, Springfield, VA, MacTutor Contributing Editor

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

[ John is a member of the Washington Apple Pi Users’ Group from the greater Washington D.C. metropolitan area and can be reached on AppleLink {D3471} and on GEnie {J.LOVE7} ... with very, very special thanks to Ben Cranston from the Programmers’ Special Interest Group of Washington Apple Pi for his brilliance and his extraordinary patience ... ]

This article builds on James Matthews’ work presented in MacTutor, Nov 1988. My significant additions include:

Color menus.

Hierarchical menus.

Multiple windows with the capability to place varying Window MenuBars (WMB) in different windows.

Zooming and growable windows that allow the user to scroll the Window MenuBars horizontally by clicking on my horizontal Menu Scroll Activators (MSA).

By the way, you’ll notice that the above is a THINK Pascal Project, using version 3.Ø.2 and the appropriate Interface files and Libraries provided on the System 7 CD-ROM. Yes...my application is not only System 7 “compatible”, but System 7 “friendly”...but more on this later.

There are two fundamental sets of PROCEDUREs and FUNCTIONs that are mandatory:

• Some of Skippy White’s Off-Screen Map routines that were originally presented by MacDTS on CD-ROM. The ones I use are modified to address off-screen BitMaps/PixMaps rather than off-screen Devices. I presented my modifications in MacTutor, Nov 1990, “Spiffy Color Demo, Part I”. I am re-running them below because:

a) They really ought to serve as a programming standard and, therefore, are worth repeating.

b) I now use the FUNCTION CreateOffScreen to return a OffScreenRecHdl since I draw the window’s WMB in the associated off-screen Port & subsequently blit the Port’s bitMap/pixMap back to the screen using CopyBits. Since each window can have a different WMB, each window can have a different OffScreenRecHdl for blitting back upon the occurrence of Update and Activate Events. I originally implemented this logic so I could have these OffScreenRec handles hang around even when said window had been de-activated or dragged partly beyond the physical edge of the screen or dragged to a secondary monitor. However, I then decided to dispose of these handles immediately following the blitting back to screen ... otherwise, I would then have to periodically test, for example, if any of this dragging had occured and, if so, re-create all these off-screen Maps anyway.

• James Matthews’ routines such as wInsertMenu and wDrawMenuBar. I will attempt to lead you readers through the logic with particular emphasis on color and hierarchical Menus.

One note of caution ... I will not be presenting alot of the conventional parts of the code, for example the GetNextEvent/WaitNextEvent loop, the cursor-changing PROC etc. The entire THINK Pascal Project, Pascal source code and SARez source( w/included resources) consumes a tad over 600K which Kirk Chase will gladly sell you for a mere pittance.

Before the drum roll ends, I will also be talking about snipits of code that are just plain spiffy. For example, how do you retrieve a window’s window type ... before you generate a wrong answer such as a simple call to GetWVariant, watch out ... the variation codes of several rDocProc types duplicate those of several standard types. So, stay tuned ...

First in line is a complete listing of all external routines USEd by each Pascal UNIT ... the big picture, so-to-speak. I will amplify only on a few of them, those that are crucial to my off-screen BitMap/PixMap gymnastics as well as to Window MenuBars.

{1}

UNIT wBMMiscSubs;

INTERFACE

 USES
  Types, Quickdraw, Menus, TextEdit, Traps, Sound, wBMGlobals;

 PROCEDURE InitManagers;
 FUNCTION TestForColor (VAR pixelDepth: INTEGER): BOOLEAN;
 PROCEDURE LocalGlobal (VAR r: Rect);
 PROCEDURE GlobalLocal (VAR r: Rect);
 FUNCTION TrapIsAvailable (theTrap: INTEGER): BOOLEAN;
 FUNCTION WNEisImplemented: BOOLEAN;
 PROCEDURE PlaySound (mySound: Str255);
 FUNCTION GetStripAddressMask: LONGINT;
 FUNCTION QuickStrip (myPtr: Ptr): Ptr;
 FUNCTION GetMouseMovement (gMouse0: Point): Size;
 FUNCTION DoubleClick: BOOLEAN;
 PROCEDURE DimRgn (rgn: RgnHandle);
 FUNCTION Max (a, b: INTEGER): INTEGER;
 FUNCTION Min (a, b: INTEGER): INTEGER;
 FUNCTION GetWindowPartColor (window: WindowPtr; part:  INTEGER; VAR 
color: RGBColor): BOOLEAN;

UNIT OffscreenSubs;

INTERFACE

 USES
  Quickdraw, wBMInterface, wBMGlobals, wBMMiscSubs;

 FUNCTION GetMaxAreaDevice (globalRect: Rect): GDHandle;
 FUNCTION CreateOffScreen (VAR myRect: Rect): OffScreenRecHdl;
 PROCEDURE ToOnScreen (COSHdl: OffScreenRecHdl);
 PROCEDURE DisposOffScreen (VAR COSHdl: OffScreenRecHdl);


UNIT wBMScrollSubs;

INTERFACE

 USES
  Quickdraw, wBMGlobals, wBMMiscSubs;

 FUNCTION ScrollHoriz (wp: WindowPtr): ControlHandle;
 FUNCTION ScrollVert (wp: WindowPtr): ControlHandle;
 PROCEDURE ScrollShow (wp: WindowPtr);
 PROCEDURE ScrollHide (wp: WindowPtr);
 PROCEDURE InvalidScroll (wp: WindowPtr);
 PROCEDURE ValidScroll (wp: WindowPtr);
 PROCEDURE ScrollResize (wp: WindowPtr);
 FUNCTION GetWindowType (window: WindowPtr): INTEGER;

UNIT wBarMenuProc;

INTERFACE

 USES
  Quickdraw, wBMInterface, wBMGlobals, wBMMiscSubs, OffScreenSubs, wBMScrollSubs;

 FUNCTION wInitMenus: wMenuBarListHdl;

 FUNCTION wGetNewMBar (wp: WindowPtr; wMenuBarID: INTEGER): wMenuBarHandle;

 FUNCTION wGetMenuBar (wp: WindowPtr): wMenuBarHandle;

 PROCEDURE wSetMenuBar (theMenuBar: wMenuBarHandle; wp: WindowPtr);

 PROCEDURE wAddWMB (theMenuBar: wMenuBarHandle);

 PROCEDURE wDeleteWMB (wp: WindowPtr);

 PROCEDURE wClearMenuBarList (theMenuBarList: wMenuBarListHdl);

 PROCEDURE wInsertMenu (theMenuBar: wMenuBarHandle; theMenu: MenuHandle; 
beforeID: INTEGER);

 PROCEDURE wDeleteMenu (theMenuBar: wMenuBarHandle; menuID: INTEGER);

 PROCEDURE GetWBMrects (wp: WindowPtr; VAR WBMrect, leftMSArect, rightMSArect: 
Rect);

{ only local:                                          }
{ PROCEDURE wSetColorMenu (menusID, itemsID: INTEGER); }

 PROCEDURE wDrawMenuBar (theMenuBar: wMenuBarHandle);

 PROCEDURE wScrollMenuBar (theMenuBar: wMenuBarHandle);

 PROCEDURE wGetMSA (theMenuBar: wMenuBarHandle);

 PROCEDURE wDrawMSA (theMenuBar: wMenuBarHandle);

 PROCEDURE wClearMenuBar (theMenuBar: wMenuBarHandle);

 FUNCTION wMenuSelect (theMenuBar: wMenuBarHandle; startPt: Point): LONGINT;

 FUNCTION wMenuKey (theMenuBar: wMenuBarHandle; ch: char): LONGINT;

 PROCEDURE wHiliteMenu (theMenuBar: wMenuBarHandle; menuID: INTEGER);

 PROCEDURE wChangeMenuBarSize (wp: WindowPtr; zooming: BOOLEAN);

UNIT wBMWindSubs;

INTERFACE

 USES
  Quickdraw, Palettes, wBMInterface, wBMGlobals, wBMMiscSubs, wBMScrollSubs, 
wBarMenuProc, wBMBalloons;

 FUNCTION InitWindowStorage: allWSHdl;
 PROCEDURE CalcWindowRect (window: WindowPtr; VAR r: Rect);
 PROCEDURE DisplayWindow (window: WindowPtr; TLPR: Point);
 FUNCTION DoNewWindow (windowID, wMBARID: INTEGER; VAR offset: Point): 
BOOLEAN;
 PROCEDURE CloseOurWindow (window: WindowPtr);
 PROCEDURE DoCloseAll;

Next is my complete wBMGlobals.p file. I wouldn’t even bother with it except for the RECORD types that serve as the chief worker-bees for off-screen BitMaps/PixMaps, WMBs and multiple windows.

{2}

UNIT wBMGlobals;

INTERFACE

{ ------------------------------------------ }
{   Global constants:   }
{ ------------------------------------------ }

 CONST

{ General constant: }
  Enter = 3;
  ohFudge = 1;   { Guess what ????? }

{ low-memory global: }
  ROM85Loc = $28E;

{ Specific constants ... }

{ Stuff for main Menu ... }
  kMBarDisplayed = 128;
  mainMBARID = kMBarDisplayed;

  AppleMenuID = 1;
  AboutItem = 1;
  AdisabledItem = 2;
{ ---- }
  FileMenuID = 2;
  NewWindowItem = 1;
  CloseWindowItem = 2;
  FdisabledItem = 3;
  QuitItem = 4;
{ ---- }
  EditMenuID = 3;
  UndoItem = 1;
  EdisabledItem = 2;
  CutItem = 3;
  CopyItem = 4;
  PasteItem = 5;
  ClearItem = 6;

{ Stuff for Window Menu ... }
  kMBarNotDisplayed = 129;
  wMBARID = kMBarNotDisplayed;

  wAppleMenuID = 1001;
  wAboutItem = 1;
  wAdisabledItem = 2;
{ ---- }
  wFileMenuID = 1002;
  wNewWindowItem = 1;
  wCloseWindowItem = 2;
  wFdisabledItem = 3;
  wQuitItem = 4;
{ ---- }
  wEditMenuID = 1003;
  wUndoItem = 1;
  wEdisabledItem = 2;
  wCutItem = 3;
  wCopyItem = 4;
  wPasteItem = 5;
  wClearItem = 6;
{ -------------------------------------------- }
{ Hierarchical Menus ... }
{ -------------------------------------------- }
  wNewHierMenuID = 104;
  wNewHierItem = 1;
  wCloseHierMenuID = 105;
  wCloseHierItem = 1;
  wHierHierMenuID = 106;
  wHierHierItem = 1;

{ Window goodies ... }
  maxWindows = 20;  { A # subject only to memory. }
  kDefaultWindowID = 1001;
  mainWindowID = kDefaultWindowID;
  newWindowID = mainWindowID + 1;
  frame = 1;  { Window parts in Pixels ... }
  shadow = 1;
  title = 18;
  horizScrollID = 128;
  vertScrollID = 129;
  scrollWidth = 16;
  scrollHeight = scrollWidth;
  growBoxSize = scrollWidth - frame;

{ Miscellaneous stuff ... }
  logoID = 131;

{ -------------------------------------------------------------------------------------------------------------- 
}
{ ... for Error handling in my Off-screen map routine(s): }
{ -------------------------------------------------------------------------------------------------------------- 
}

  NewCOSHdlError = -10000;
  MaxDevError = -15000;
  NewBaseAddrPtrError = -20000;
  CloneHdlError = -25000;

{ ------------------------------------ }
{ MultiFinder stuff: }
{ ------------------------------------ }

{ _WaitNextEvent = $A860;  --  in new “Traps.p” interface }
{ _Unimplemented = $A89F;                                 }
  SysEnvironsVersion = 1;

{ OSEvent is the event number of the suspend/resume and }
{ mouse-moved Events sent by MultiFinder.  Once you     }
{ determine that an event is an OSEvent, look at the    }
{ High byte of the message sent with the event to       }
{ determine which kind it is.  To differentiate between }
{ suspend & resume, look at the resumeMask bit.         }

  OSEvent = app4Evt;
  suspendResumeMessage = 1;
  mouseMovedMessage = $FA;
  resumeMask = 1;

{ ------------------------------------------------------------------ 
}
{ ... for Window Menu Bar routines: }
{ ------------------------------------------------------------------ 
}

  noneHilited = -1;  { Stored in “wMenuBar.hilited” }
                     {   if nada.                   }
  menuTitleBit = 31; { Offset for Menu title bit in }
                     {   “enableFlags”.             }
  flashDelay = 10;   { For blinking Menu title }
             { and Menu item.          }         
  normalSize = 12;   { Radius FPD stuff ... }
  chicago16 = 16;    { Special FONT. }
  dontScrollMenu = 0;  { Pass to wDrawMenuBar }
                       {   if appropriate.    }
  atEnd = 0;          { ... as in InsertMenu(MenuHdl, 0); }
  noMBARrsrc = -1;    { There ‘aint’ any ... }
  mceMenuBar = 0;     { mctID & mctItem for }
     {   color Menus ...   }
  mceMenuTitle = 0;
  zooming = TRUE;
  regMenu = 0;        { NOT a Hierarchical Menu. }
  mainMenu = 0;       { NO parent Menu. }

{ ------------------------------------------ }
{     Global types:     }
{ ------------------------------------------ }

 TYPE

{ General stuff: }
  RgnHandlePtr = ^RgnHandle;
  wordPtr = ^INTEGER;
  longPtr = ^LONGINT;
{ BitMapPtr = ^BitMap;  --  in new “QuickDraw.p” interface }

{ The following is required to avoid calling }
{ _GetNewWindow with NIL as the “wStroage”   }
{ parameter.  Otherwise, we risk fragmenting }
{ the Application Heap.                      }
{                                            }
{ [Adapted from Dan Weston’s Assembly Code]  }
  oneWStorage = RECORD
    inUse: BOOLEAN;
    fill: BOOLEAN;
    ws: WindowRecord;
   END;

  allWStorage = RECORD
    ones: ARRAY[1..maxWindows] OF oneWStorage;
   END;

  allWSPtr = ^allWStorage;
  allWSHdl = ^allWSPtr;

{ Off Screen stuff: }
  OffScreenRec = RECORD
    CreateOffScreenError: OSErr;
    oldDevice: GDHandle;
    origPort: GrafPtr;
    drawingRect: Rect;
    myMaxDevice: GDHandle;
    myBits: Handle;
    offGrafPort: GrafPort;
    offGrafPtr: GrafPtr;
    offCGrafPort: CGrafPort;
    offCGrafPtr: CGrafPtr;
    ourCTHandle: CTabHandle;
    offBitMapPtr, onScreenBitsPtr: BitMapPtr;
   END;

  OffScreenRecPtr = ^OffScreenRec;
  OffScreenRecHdl = ^OffScreenRecPtr;

{ ... for Window Menus: }
  wMenuRec = RECORD
    mh: MenuHandle;
    menuType: INTEGER;  { Regular or Hierarchical. }
    parentID: INTEGER;  { Hierarchical stuff ...   }
    menuParentRgn, cumParentRgn: RgnHandle;
    titleRect: Rect;
    MenuDownOSHdl: OffScreenRecHdl;
   END;

  wMenuBar = RECORD
    numMenus: INTEGER;
    barLength: INTEGER;
    titleHilited: INTEGER;  { Menu # or “noneHilited”. }
    leftScrollPoly, rightScrollPoly: PolyHandle;
                { ... to Menu Scroll Activators (MSA). }
    saveCumScrollMenuX: INTEGER;
    barOSHdl: OffScreenRecHdl;
    wp: WindowPtr;
    wMCTable: MCTableHandle;
    wMenus: ARRAY[0..0] OF wMenuRec;
   END;

  wMenuBarPtr = ^wMenuBar;
  wMenuBarHandle = ^wMenuBarPtr;
{ ---------- }
  wMenuBarList = RECORD
    numWindows: INTEGER;
    wMBars: ARRAY[0..0] OF wMenuBarHandle;
   END;

  wMenuBarListPtr = ^wMenuBarList;
  wMenuBarListHdl = ^wMenuBarListPtr;

  aDynamicBalloon = RECORD { ... for my NEW dynamic windows. }
    dynamicStrID: INTEGER;
    dynamicStrIndex: INTEGER;
    dynamicR: Rect;
   END;

  { The BIG guys: }

  RadBWStatus = PACKED RECORD
  { For Internal use, ONLY !! }
    Signature, CPFlags, SSDelay, VertOffset: Char; 
    LargeFontEn, PluggedIn: Char;  { PluggedIn = DontRepos }
    MacBits: BitMapPtr;
    BigTicksPtr: Ptr;
    BigTicks: LONGINT;
    Reserved1: LONGINT;
    TopBigRAM, IdleHook: Ptr;
    Reserved2: LONGINT;
    CursorHook: Ptr;
   END;

  RadBWStatPtr = ^RadBWStatus;
  RadBWStatHdl = ^RadBWStatPtr;
{ ---------- }
  RadIIStatus = PACKED RECORD
    AutoCenter, AutoLower, TearOffMenus, ScreenDump: Char;
    LargeMenus, ScreenSaver, SaverActive, Reserved: Char;
    ScreenSaverDelay, InitVers: INTEGER;
    CardID: PACKED ARRAY[0..5] OF Char;
    ROMVers: PACKED ARRAY[0..5] OF INTEGER;
   END;

  RadIIStatPtr = ^RadIIStatus;
  RadIIStatHdl = ^RadIIStatPtr;
{ ---------- }
  PivotDataStruct = PACKED RECORD
    flipped, command, dLogFlags, xInternal, topOffset, bottomOffset: 
Char;
    tileFactor: INTEGER;
    reserved: PACKED ARRAY[0..4] OF Char;
    movementFlags: Char;
    parameter, result: LONGINT;
    resultRect: Rect;
   END;

  PivotDSPtr = ^PivotDataStruct;
  PivotDSHand = ^PivotDSPtr;
  { ---------- }
  radiusType = (none, radBW, radII);

  RadiusData = RECORD
    PivotHdl: PivotDSHand;
    CASE radType : radiusType OF
     none: (

     );
     radBW: (
       BWHdl: RadBWStatHdl;
     );
     radII: (
       IIHdl: RadIIStatHdl;
     );
   END;

  RadiusDataPtr = ^RadiusData;
  RadiusDataHdl = ^RadiusDataPtr;


{ -------------------------------------- }
{ Global variables:   }
{ -------------------------------------- }

 VAR

{ ... for Main PROGRAM: }
  gStripAddressMask: LONGINT;
  oldPort: GrafPtr;
  lScreen, gScreen, visRect, updateRect: Rect;
  ROM: wordPtr;
  mBarHt: INTEGER;
  AppleMenu, FileMenu, EditMenu: MenuHandle;
  aMac2, hasGrowIcon: BOOLEAN;
  colorDepth: INTEGER;
  TheWindow, FW: WindowPtr;
  windowCount, newCount, windType: INTEGER;
  windowStorage: allWSHdl;
  Event: EventRecord;
  windowLoc: INTEGER;
  ignore, moreNew, brandNew: BOOLEAN;
  offset, deltaOffset: Point;
  { ... to avoid flickering Menu Bar: }
  prevDA, prevWind, currDA, myAppl, applWind: BOOLEAN;
  Done, InWindow, InWBMenu: BOOLEAN;
  WNE, InForeGround: BOOLEAN;
  Sleep, finalTicks: LONGINT;
  ourControl: ControlHandle;

{ Window Menus ... }
  pnState: PenState;
  WBMrect, leftMSArect, rightMSArect, gWBMrect: Rect;
  mbHState: SignedByte;
  oldClip, onScreenRgn: RgnHandle;
  oldForeColor, oldBackColor: RGBColor;    { Color stuff ... }
  oldMCTable, newMCTable: MCTableHandle;
  found: BOOLEAN;
  mBarList: wMenuBarListHdl;
  mBar: wMenuBarHandle;
  newBarListSize, newWMBSize: Size;
  titleWidth, scrollPolyDXY: INTEGER;
{ Pixels between adjacent Menus & }
{   pixels to invert on each side }
{   of Menu title:                }  
  betweenTitles, invertOverlap: INTEGER; 
  aboveBelowItem, menuFrame, menuShadow, frameShad: INTEGER;
  whichMenu, whichItem: INTEGER;

{ Radius’ BIG screens ... }
  WMgrPort: GrafPtr;
  FPDRsrc: RadiusData;
  BIGfont: Handle;
  sizeFont: INTEGER;

{ System 7.0 ... }
  startBalloons, balloonsUp, saveBalloons: BOOLEAN;
  HelpMenu: MenuHandle;
  origNumHelpItems: INTEGER;
  dynamicBalloons: ARRAY[0..2] OF aDynamicBalloon;
  lastBalloon: INTEGER;

IMPLEMENTATION

END.   { UNIT = wBMGlobals }


Speaking of multiple windows and one of those snipits I promised you, the principal problem here centers on the fact that the majority of code I’ve seen repeatedly calls GetNewWindow, passing NIL as the wStorage Pointer. Bad news!!! The window record will be allocated as a non-relocatable object on the heap in which case you risk generating a fragmented heap. Dan Weston, in his positively super two-book set, The Complete Book of Macintosh Assembly Language Programming, passes a Pointer to the ws field of a oneWStorage RECORD and sets its inUse field. You see ... we’ve initialized a NewHandle to a allWStorage RECORD shortly after our call to InitManagers. This new handle contains, say, 20 oneWStorage RECORDs:

{3}

 FUNCTION InitWindowStorage: allWSHdl;
{ Call this hummer after “InitManagers”. }

  VAR
   wsHdl: allWSHdl;

 BEGIN

  InitWindowStorage := NIL;      { Worry-wart !! }
  wsHdl := allWSHdl(NewClearHandle(SizeOf(allWStorage)));
  IF MemError = noErr THEN
  BEGIN
   MoveHHi(Handle(wsHdl));
   HLock(Handle(wsHdl));
   ;
   windowCount := 0;
   InitWindowStorage := wsHdl;
  END;   { IF noErr }
 
 END;   { InitWindowStorage }
Every time you call GetNewWindow, you scan these 20 and stop at the first 
whose inUse = FALSE & set it to TRUE.  

 FUNCTION DoNewWindow (windowID, wMBARID: INTEGER; VAR offset: Point): 
BOOLEAN;
{ IF NOT DoNewWindow( ) THEN }
{  OhOh;                     }

  VAR
   i: INTEGER;

  FUNCTION FindWStorage (VAR index: INTEGER): BOOLEAN;

  BEGIN
   index := 1;
   WITH windowStorage^^ DO
   BEGIN
    WHILE (index <= maxWindows) & ones[index].inUse DO
     index := index + 1;
    ;
    IF index <= maxWindows THEN
    BEGIN
     ones[index].inUse := TRUE;
     FindWStorage := TRUE;
    END
    ELSE   { no more windows allowed }
     FindWStorage := FALSE;
   END;   { WITH }
  END;   { FindWStorage }


 BEGIN{ DoNewWindow }

  DoNewWindow := FALSE;
  ;
  moreNew := moreNew & FindWStorage(i);   { i is VARed. }
  IF NOT moreNew THEN
   EXIT(DoNewWindow);

  IF aMac2 THEN
   TheWindow := GetNewCWindow(windowID, @windowStorage^^.ones[i].ws, 
WindowPtr(-1))
  ELSE
   TheWindow := GetNewWindow(windowID, @windowStorage^^.ones[i].ws, WindowPtr(-1));
  ;
  IF TheWindow = NIL THEN
  BEGIN
 { Reverse effect of FindWStorage: }
   windowStorage^^.ones[i].inUse := FALSE;
   EXIT(DoNewWindow);
  END;
  ;
  SetPort(TheWindow);

  IF windowID = newWindowID THEN
  BEGIN
   ourControl := GetNewControl(horizScrollID, TheWindow);
   ourControl := GetNewControl(vertScrollID, TheWindow);
  END;   { retrieve Scroll Bars }

{ oldOffset --> newOffset: }
  offset := GetTLWindPortRect(TheWindow, offset);

  mBar := wGetNewMBar(TheWindow, wMBARID);
  IF mBar <> NIL THEN
   wAddWMB(mBar);
  ScrollResize(TheWindow); { Does nada if NO Scroll Bars. }
  DisplayWindow(TheWindow, offset);

{ Since an Update Event draws the MSAs & the Window Menu, }
{ Bar we do NOT want these drawn by the DoActivate PROC:  }
 
  brandNew := TRUE;

  DoNewWindow := TRUE;
  ;
  windowCount := windowCount + 1;
  moreNew := moreNew & (windowCount < maxWindows);

 END;   { DoNewWindow }

Every time you call CloseWindow, you scan the same 20 and stop when inUse = TRUE and WindowPtr = @oneWStorage.ws . At this point, of course, we reset the former to FALSE so that my DoNewWindow FUNCTION finds it available.

{4}

{ ---------------------------------------------- }
{ One at a time, folks !! }
{ ---------------------------------------------- }

 PROCEDURE CloseOurWindow (window: WindowPtr);

  VAR
   myPic: PicHandle;
   pal: PaletteHandle;
   aux: BOOLEAN;
   auxWind: AuxWinHndl;

The next snipit centers on my comparison of FrontWindow’s resultant WindowPtr with @oneWStorage.ws as I’ve already talked about..

PROBLEM-- oneWStorage is a field in a LOCKED allWStorage handle and, therefore, @oneWStorage.ws has its high bit set. Guess what ... FrontWindow’s WindowPtr has its high bit clear. I “borrowed” GetStripAddressMask and QuickStrip from Tech Note #213.

{5}

  PROCEDURE DisposeWStorage (wp: WindowPtr);

   VAR
    i: INTEGER;
    found: BOOLEAN;
    wsHState: SignedByte;

  BEGIN

   found := FALSE;

 { oneWStorage  dsec  0                                  }
 { inUse        byte                ; = 0                }
 { fill         byte                ; = 1                }
 { ws           byte  WindowSize    ; = 2                }
 {              dend                                     }
 {              ...                                      }
 {              move.l  windowStorage,a0                 }
 {              move.l  (a0),a4     ; Locked Master Ptr. }
 {              lea     ws(a4),a1   ; Bit #31 also set.  }
 {              cmpa.l  wp,a1       ; wp = 8(a6)         }
 {              ...                                      }

   wsHState := HGetState(Handle(windowStorage));
   windowStorage^ := allWSPtr(QuickStrip(Ptr(windowStorage^)));
   WITH windowStorage^^ DO
   BEGIN
    FOR i := 1 TO maxWindows DO
     IF ones[i].inUse THEN
      IF wp = @ones[i].ws THEN
      BEGIN
       found := TRUE;
       Leave;
      END;
    IF found THEN
     ones[i].inUse := FALSE  {Undo effect of FindWStorage.}
    ELSE   { should NOT happen !! }
     ;
   END;   { WITH }
   ;
 { We have NOT done anything to move memory, }
 { therefore _MoveHHi is NOT required.       }
   HSetState(Handle(windowStorage), wsHState);

  END;   { DisposeWStorage }


 BEGIN   { CloseOurWindow }

  IF window = NIL THEN
   EXIT(CloseOurWindow);

  IF WindowPeek(window)^.windowKind < 0 THEN
   CloseDeskAcc(WindowPeek(window)^.windowKind)
  ELSE
  BEGIN

   IF aMac2 THEN
   BEGIN
    pal := GetPalette(window);
    IF pal <> NIL THEN
     DisposePalette(pal);
   END;   { IF aMac2 }

   myPic := GetWindowPic(window);
   IF myPic <> NIL THEN
   BEGIN
    HUnlock(Handle(myPic));
    ReleaseResource(Handle(myPic));
   END;   { IF myPic <> NIL }

   wDeleteWMB(window);
   DisposeWStorage(window);
   CloseWindow(window);

   WITH offset DO
   BEGIN
    h := h - deltaOffset.h;
    IF h < 0 THEN
     h := 0;
    v := v - deltaOffset.v;
    IF v < 0 THEN
     v := 0;
   END;   { WITH }

   windowCount := windowCount - 1;
   ;
   IF windowCount = 0 THEN
   BEGIN
  { In case a lingering DA doesn’t properly }
  { handle its “doCursor” routine:          }
    InitCursor;
  { Wait till last is gone because all windows }
  { share a common Color Table.                }
    IF aMac2 THEN
    BEGIN
     aux := GetAuxWin(window, auxWind);
     IF aux THEN
      ReleaseResource(Handle(auxWind));
    END;   { IF aMac2 }
   END;   { IF no more windows }

   moreNew := TRUE;

  END;   { NOT a Desk Accessory window }

 END;   { CloseOurWindow }

Then comes my OffScreenRec which doesn’t make sense until we see the code later on ... so cool it ...

Next comes the stuff for WMBs. The wMenuBarList consists of a window count and an array of wMenuBarHandles. Gotta have the count so we know how many handles. Each of these handles consists of:

a) menu count and associated array of individual wMenuRecs. Again, this count tells us how many.

b) barLength tells us if we’re clicking the Mouse on ANY active Menu. If so, then we call PtInRect for the titleRect of each wMenuRec to find out which Menu.

c) titleHilited enters with wHiliteMenu which is called as our MouseDown travels from Menu-to-Menu: un-Hilite the old titleRect and Hilite the new.

d) left & right PolyHandles, my MSAs for horizontal scrolling of the WMB. Click on one of these dudes to scroll. If we scroll part of a titleRect out of view, call FillPoly(polyH, black); when we scroll back into view, call FillPoly(polyH, white) followed by FramePoly(polyH).

e) gotta save the amount we’ve scrolled the WMB so when we zoom back in from just zooming out, we can re-scroll to where we were.

f) it’s the OffScreenRecHdl we scroll for instantaneous blitting on screen.

g) the MCTableHandle handles color ... natch !!

h) each wMenuRec basically is just a Menuhandle together with some added info:

1) the menuType determines the placement of the titleRect ... for a regular Menu, it’s in the main WMB and for a hierarchical Menu, it’s the rect of the parent item.

2) the parentID for a hierarchical Menu is recorded to help us determine which wMenus[i] we’re looking at.

3) the two RgnHandles play in the wMenuSelect FUNCTION as our MouseDown bounces between regular, hierarchical and even hierarchical-hierarchical Menus. We create another OffScreenREcHdl for the drawing of the pulled-down Menu. Because of hierarchical Menus, several of these off-screen beauties may exist simultaneously. So we’ve gotta keep track of these off-screen handles so we can correctly dispose of them when we veer off-course ... either to a different Menu entirely or to a different item, an item that does NOT have a sub-Menu. The above RgnHandles help us to do just that.

4) The drawing of the pulled-down Menus occurs within MenuDownOSHdl.

Finally, holding up the rear, the BIG guns from Radius ...

Another snipit enters in the UNIT wBMMiscSubs with InitManagers. Instead of calling MoreMasters 10 times or whatever number turns you on, check out Tech Note #53.

Now, my off-screen gymnastics without many comments since the routines are essentially repeated from one of my former articles:

{6}

UNIT OffscreenSubs;

INTERFACE

 USES
  wBMInterface, wBMGlobals, wBMMiscSubs;

 FUNCTION GetMaxAreaDevice (globalRect: Rect): GDHandle;
 FUNCTION CreateOffScreen (VAR myRect: Rect): OffScreenRecHdl;
 PROCEDURE ToOnScreen (COSHdl: OffScreenRecHdl);
 PROCEDURE DisposOffScreen (VAR COSHdl: OffScreenRecHdl);


{ ********** }
 FUNCTION GetMaxAreaDevice (globalRect: Rect): GDHandle;

{ Find the greatest overlap device }
{ for the given global rectangle.  }

  VAR
   area: LONGINT;
   maxArea: LONGINT;
   device: GDHandle;
   intersection: Rect;

 BEGIN

  GetMaxAreaDevice := NIL;
  ;
  maxArea := 0;
  ;
  device := GetDeviceList;

  WHILE device <> NIL DO
  BEGIN
   IF TestDeviceAttribute(device, screenDevice) THEN
    IF TestDeviceAttribute(device, screenActive) THEN
     IF SectRect(globalRect, device^^.gdRect, intersection) THEN
     BEGIN
      WITH intersection DO
       area := LONGINT(right - left) * LONGINT(bottom - top);
      IF area > maxArea THEN
      BEGIN
       GetMaxAreaDevice := device;
       maxArea := area;
      END;   { IF area > maxArea }
     END;   { IF SectRect ... }
   device := GetNextDevice(device);
  END;   { WHILE device <> NIL }

 END;   { GetMaxAreaDevice }


 FUNCTION CreateOffScreen (VAR myRect: Rect): OffScreenRecHdl;
{ Reference: Tech Note #120                             }
{ with special thanks to:                               }
{                   Forrest Tanaka and                  }
{                   Jon Zap of MacDTS                   }
{                                                       }
{ NOTE: Local window coordinates are input, but local   }
{ device coordinates are returned for drawing purposes. }

  VAR
   offRowBytes, sizeOfOff, tempSeed: LONGINT;
   localRect, globRect: Rect;
   i, maxDepth: INTEGER;
   err: OSErr;
   COSHdl: OffScreenRecHdl;


  PROCEDURE ErrorOut (error: OSErr);

  BEGIN
   IF error = NewCOSHdlError THEN
    CreateOffScreen := NIL
   ELSE
   BEGIN
    COSHdl^^.CreateOffScreenError := error;
    CreateOffScreen := COSHdl;
   END;

   EXIT(CreateOffScreen);
  END;   { ErrorOut }


 BEGIN   { CreateOffScreen }

  COSHdl := OffScreenRecHdl(NewClearHandle(SizeOf(OffScreenRec)));
  ;
  IF MemError <> noErr THEN
   ErrorOut(NewCOSHdlError);
  ;
  MoveHHi(Handle(COSHdl));
  HLock(Handle(COSHdl));   { Lock this sucker down !! }

  WITH COSHdl^^ DO
  BEGIN

 { CreateOffScreenError := noErr;   --   We hope !! }
   GetPort(origPort);   { Used by ToOnScreen. }
   drawingRect := myRect;   { Saved for use after }
                            { call to ToOnScreen. }

   globRect := myRect;   { We’re about to switch   }
                         { the Port to off-screen: }
   LocalGlobal(globRect);

   IF NOT aMac2 THEN
   BEGIN
    offGrafPtr := @offGrafPort;
    OpenPort(offGrafPtr);
    maxDepth := 1;
   END   { ... a low-life machine }
   ELSE
   BEGIN

    myMaxDevice := GetMaxDevice (globRect);
    IF myMaxDevice = NIL THEN
     ErrorOut(MaxDevError);

    oldDevice := GetGDevice;
    SetGDevice(myMaxDevice);
    ;
    offCGrafPtr := @offCGrafPort;   { Initialize this guy. }
    OpenCPort(offCGrafPtr);
    MoveHHi(Handle(offCGrafPtr^.portPixMap));   { Arrgh !! }
    HLock(Handle(offCGrafPtr^.portPixMap));
    maxDepth := offCGrafPtr^.portPixMap^^.pixelSize;

   END;   { ELSE: aMac2 }

{ CanNOT use my GlobalLocal PROC because we may have dragged }
{ our window to a secondary screen.  “Global” here is with   }
{ respect to the main screen and “Local” is with respect to  }
{ the secondary screen.                   }
{                                                            }
{ From Forrest Tanaka:                                       }
{ When GetMaxDevice returns the secondary screen’s GDevice & }
{ we set that to the current GDevice, then OpenCPort creates }
{ a CGrafPort which has a portRect=GetMainDevice^^.gdPMap^^. }
{ bounds which is in the global coordinates for all the      }
{ screens’ pixel images with a topLeft = (0,0).  The new     }
{ CGrafPort.portPixMap^^.bounds is in the local coordinates  }
{ of the secondary screen with a topLeft = (0,-640), e.g.    }
{                                                            }
{ In effect, the port that OpenCPort gives you is NOT a      }
{ port because the portRect pertains to the wrong screen.    }
{ This means that calling GlobalLocal shifts the localRect   }
{ waaaaay over somewhere ... BECAUSE the difference between  }
{ the above portRect and portPixMap^^.bounds is SO large!!!  }

   localRect := globRect;
   WITH screenBits.bounds DO
   OffsetRect(localRect, left, top);
   ;
   IF aMac2 THEN
   BEGIN
    RectRgn(offCGrafPort.visRgn, localRect)
    offCGrafPort.portRect := localRect;
   END
   ELSE
   BEGIN
    RectRgn(offGrafPort.visRgn, localRect);
    offGrafPort.portRect := localRect;
  END;

   WITH localRect DO
   BEGIN
    offRowBytes := (maxDepth * (right - left) + 15) DIV 16;      
    IF ODD(offRowBytes) THEN
    offRowBytes := offRowBytes + 1;
    offRowBytes := offRowBytes * 2; 
    sizeOfOff := LONGINT(bottom - top) * offRowBytes;
   END;   { WITH }

   myBits := NewClearHandle(sizeOfOff);
   IF MemError <> noErr THEN
    ErrorOut(NewBaseAddrPtrError);
   MoveHHi(myBits);
   HLock(myBits);

   IF aMac2 THEN
   BEGIN
    WITH offCGrafPtr^.portPixMap^^ DO
    BEGIN
     baseAddr := myBits^;
     rowBytes := offRowBytes + $8000;     bounds := localRect;
    END;   { WITH }

    offBitMapPtr := BitMapPtr(offCGrafPtr^.portPixMap^);
   END   { IF aMac2 }

   ELSE   { definitely ... “YUCKY” black-and-white. }

   BEGIN
    WITH offGrafPtr^.portBits DO
    BEGIN
     baseAddr := myBits^;
     rowBytes := offRowBytes;
     bounds := localRect;
    END;

    offBitMapPtr := @offGrafPtr^.portBits;
   END;

   IF aMac2 THEN
   BEGIN

    ourCTHandle := myMaxDevice^^.gdPMap^^.pmTable;
    err := HandToHand(Handle(ourCTHandle));    { Clone it. }
    IF err <> noErr THEN
     ErrorOut(CloneHdlError);

    WITH ourCTHandle^^ DO
     FOR i := 0 TO ctSize DO
      ctTable[i].value := i;

    ourCTHandle^^.ctFlags := BAND(ourCTHandle^^.ctFlags, $7FFF);
    tempSeed := GetCTSeed;   { Thanks, Scott Knaster !! }
    ourCTHandle^^.ctSeed := tempSeed;
    offCGrafPtr^.portPixMap^^.pmTable := ourCTHandle;

   END;   { IF aMac2 }

   myRect := localRect; { Return local device coords. }

  END;   { WITH COSHdl^^ DO }

  ErrorOut(noErr);   { Whew !! }

 END;   { CreateOffScreen}

{ ******************* }
{ Back to “Square 1”: }
{ ******************* }

 PROCEDURE ToOnScreen (COSHdl: OffScreenRecHdl);

 BEGIN

  WITH COSHdl^^ DO   { COSHdl is locked coming in. }
  BEGIN
   SetPort(origPort);
   IF aMac2 THEN
    SetGDevice(oldDevice);
  END;   { WITH }

 END;   { ToOnScreen}


 PROCEDURE DisposOffScreen (VAR COSHdl: OffScreenRecHdl);

  LABEL
   100;

 BEGIN

  IF COSHdl = NIL THEN
   EXIT(DisposOffScreen);

  WITH COSHdl^^ DO
  BEGIN

   IF CreateOffScreenError = MaxDevError THEN
    GOTO 100;

 { NewBaseAddrPtrError or CloneHdlError or noErr ... }

   IF aMac2 THEN
   BEGIN
    IF CreateOffScreenError = noErr THEN
     DisposHandle(Handle(ourCTHandle));
    HUnlock(Handle(offCGrafPtr^.portPixMap));
    CloseCPort(offCGrafPtr);
   END
   ELSE
    ClosePort(offGrafPtr);

   IF CreateOffScreenError <> NewBaseAddrPtrError THEN
   BEGIN
    HUnlock(myBits);
    DisposHandle(myBits);
   END;

  END;   { WITH }
100:
  HUnlock(Handle(COSHdl));
  DisposHandle(Handle(COSHdl));
  COSHdl := NIL;   { Mark as gone ... }

 END;   { DisposOffScreen }

END. { UNIT = OffscreenSubs }

Another snipit centers on the fact that my HandleCursor PROC demands knowledge of what kind of window FrontWindow is:

{7}

 FUNCTION GetWindowType (window: WindowPtr): INTEGER;
{ Here, window type = Window Definition ID.     }

  CONST
   RomMapInsertLoc = $B9E;
   mapTrue = $FFFF;

  VAR
   varCode, WDEFRsrcID, wType: INTEGER;
   WDEFHandle: Handle;
   WDEFType: ResType;
   WDEFName: Str255;

 BEGIN

  varCode := GetWVariant(window);

{ Now, what about rDocProc types since their Variation  }
{ Codes duplicate those of some standard types such as  }
{ documentProc & dBoxProc.  I could call:               }
{                                                       }
{ regionSize := WindowPeek(window)^.strucRgn^^.rgnSize; }
{                                                       }
{ If regionSize = 10, then rgnBBox is rectangular; so   }
{ if <> 10, we’ve got an rDocProc.  HOWEVER,  if the    }
{ window is invisible because I’ve not yet called       }
{ _ShowWindow, rgnBBox is empty and regionSize STILL    }
{ equals 10.  The solution is simple ... call           }
{ GetWindowType when the window is being activated.     }
{ Better yet ... the solution presented below, thanks   }
{ to MacDTS, avoids this workaround.  In addition,      }
{ MacDTS’ solution avoids the pitfalls of “Murphy”      }
{ inventing a totally new window type with a regionSize }
{ that dupes that of rDocProc.                          }

  WDEFHandle := Handle(QuickStrip(Ptr(WindowPeek(window)^.windowDefProc)));
  ;
  LoadResource(WDEFHandle);   { May have been purged ... }
{ !! Thanks !!, Ben Cranston: }  
  wordPtr(RomMapInsertLoc)^ := mapTrue; 
  GetResInfo(WDEFHandle, WDEFRsrcID, WDEFType, WDEFName);

  wType := 16 * WDEFRsrcID + varCode;

  IF (wType = documentProc) | (wType = zoomDocProc) THEN
   hasGrowIcon := TRUE
  ELSE
   hasGrowIcon := FALSE;
  ;
  hasGrowIcon := hasGrowIcon | (ScrollHoriz(window) <> NIL) | (ScrollVert(window) 
<> NIL);

  GetWindowType := wType;

 END;   { GetWindowType }


Another snipit goodie pertains to determining if we’re staring at a regular or a Desk Accessory Menu. I need this hummer because my “HandleCursor” routine is a part of my “doPeriodic” loop

{8}

  FUNCTION daMenu: BOOLEAN;
{ I know ... NEVER assume knowledge of Menu }
{ Record structures ... BUT ...             }

   CONST
    MenuListLoc = $A1C;

   TYPE
    rMenuRec = RECORD
      menuOH: MenuHandle;
      menuLeft: INTEGER;    { Left edge of Menu. }
     END;   { rMenuRec }

    hMenuRec = RECORD
      menuHOH: MenuHandle;
      reserved: INTEGER;
     END;   { hMenuRec }

    MenuList = RECORD
      lastMenu: INTEGER;    { Offset to last regular } 
                            {  MenuHandle.           }
      lastRight: INTEGER;   { Right edge of last }
                            {  Menu’s title.     }
      mbResID: INTEGER;
      rMenu: ARRAY[0..0] OF rMenuRec;
    { The following fields are also present:             }
    {                                                    }
    { lastHMenu: INTEGER;  --  Offset from here to last  }
    {                          hierarchical Menu.        }
    { menuTitleSave: PixMapHandle;                       }
    { When my daMenu routine is called, there are NO     }
    { hierarchical Menus:                                }
    { hMenu: ARRAY[0..0] OF hMenuRec;                    }
    
    END;   { MenuList }

    MenuListPtr = ^MenuList;
    MenuListHdl = ^MenuListPtr;


   VAR
    MLHdl: MenuListHdl;
    nbrMenusX6, menuCounter, theMenuID: INTEGER;


 BEGIN

   MLHdl := MenuListHdl(longPtr(MenuListLoc)^);
   nbrMenusX6 := ORD(MLHdl^^.lastMenu);
   menuCounter := (nbrMenusX6 DIV 6) - 1;

   WHILE menuCounter >= 0 DO
   BEGIN
    theMenuID := MLHdl^^.rMenu[menuCounter].menuOH^^.menuID;
  { Watch out !!! with System 7 ...              }
  { ... the Help Menu (kHMHelpMenuID = -16490) & }
  { ... the Application Menu (ID = ???)          }
    IF (theMenuID < 0) & (theMenuID >= -16384) THEN
     Leave;
    menuCounter := menuCounter - 1;
   END;   { scanning the MenuBar }

 { I could have used:                                  }
 {           daMenu := theMenuID < 0;                  }
 { because I KNOW my app has menus.  However, to make  }
 { this routine applicable to ANY app, what if ANY app }
 { had zip menus and there were no DA menus, then I    }
 { would have to initialize with:                      }
 {           theMenuID := 0;                           }
 { putting an extra statement in my time-critical      }
 { “doPeriodic” loop.                                  }
   daMenu := menuCounter >= 0;

  END;   { daMenu }


Here comes the firehose full of code pertaining to Window MenuBars ... some of the stuff, such as MenuDefProc you folks will recognize as unchanged from James Matthews’ article while others I did change slightly (e.g., Jim’s MenuDefGlue). Anywho, folks, they are waiting for you on disk ...

This next routine is called by wInitMenus in order to sprinkle the Radius “magic” here and there:

{9}

 PROCEDURE InitBigScreen (VAR RadStatus: RadiusData; VAR fontSize: INTEGER);

  CONST
  largeMenuBar = 5;     { Bit # in CPFlags field }
       {   for non-MacII.        }
   RadiusID = 0;

  VAR
   statusHdl, pivotHand: Handle;


 BEGIN

  SetResLoad(TRUE);

  pivotHand := PivotDSHand(GetNamedResource(‘INFO’, ‘Radius Pivot Display’));
  IF pivotHand = NIL THEN
   LoadResource(pivotHand);
  RadStatus.PivotHdl := PivotDSHand(pivotHand);

  IF NOT aMac2 THEN
   statusHdl := GetNamedResource(‘INFO’, ‘Radius Display’)
  ELSE
   statusHdl := GetNamedResource(‘INFO’, ‘Radius II Display’);

  IF statusHdl = NIL THEN
  BEGIN
  LoadResource(statusHdl);
   IF statusHdl = NIL THEN         {Still !!! }
   BEGIN
    RadStatus.radType := none;
    fontSize := normalSize;
    EXIT(InitBigScreen);
   END;   { STILL! }
  END;   { Zip }

  IF NOT aMac2 THEN
  BEGIN
   IF BTST(RadBWStatHdl(statusHdl)^^.CPFlags, largeMenuBar)     
   THEN
   BEGIN
    RadBWStatHdl(statusHdl)^^.LargeFontEn := chr(1);
    AddResource(statusHdl, ‘INFO’, RadInfoID, ‘Radius Display’);
    fontSize := chicago16;
 { ID = 128*font number + size: }
    BIGfont := GetResource(‘FONT’, 128 * systemFont + chicago16);
    IF BIGfont = NIL THEN
 LoadResource(BIGfont);
    RadBWStatHdl(statusHdl)^^.LargeFontEn := chr(0);
    RadBWStatHdl(statusHdl)^^.PluggedIn:= chr(0);
    AddResource(statusHdl, ‘INFO’, RadInfoID, ‘Radius Display’);
   END
   ELSE
    fontSize := normalSize;
   ;
   RadStatus.radType := radBW;
   RadStatus.BWHdl := RadBWStatHdl(statusHdl);
  END

  ELSE   { aMac2 }

  BEGIN
   IF ord(RadIIStatHdl(statusHdl)^^.LargeMenus) <> 0 THEN
   BEGIN
    fontSize := chicago16;
    BIGfont := GetResource(‘FONT’, chicago16);
    IF BIGfont = NIL THEN
  LoadResource(BIGfont);
   END
   ELSE
    fontSize := normalSize;
   ;
   RadStatus.radType := radII;
   RadStatus.IIHdl := RadIIStatHdl(statusHdl);
  END;

 END;   { InitBigScreen }

Speaking of wInitMenus, note that we set the values of four parms with/without the Radius big screen monitors:

1) between titles -- see James Matthews’ article.

2) aboveBelowItem -- prevents half a menu item string showing for a vertically scrolling Menu.

3) menuFrame, menuShadow -- box around a pulled-down Menu.

scrollPolyDXY plays in wGetMSA. Jim discusses invertOverlap.

{10}

 FUNCTION wInitMenus: wMenuBarListHdl;
{ Call immediately after “InitManagers”: }
{                                        }
{ Creates a wMenuBarList and quantifies  }
{ assorted & sordid global parms.        }

  VAR
   wMBL: wMenuBarListHdl;

 BEGIN

  wMBL := wMenuBarListHdl(NewClearHandle(SizeOf(wMenuBarList)));
  ;
  IF MemError <> noErr THEN
  BEGIN
   wInitMenus := NIL;
   EXIT(wInitMenus);
  END;   { Whoops !! }

{ wClearMenuBarList(wMBL);  --  NOT needed here !! }
  wInitMenus := wMBL;

{ ++ stuff for BIGees: }

  InitBigScreen(FPDRsrc, sizeFont);
  IF sizeFont > normalSize THEN
  BEGIN
   betweenTitles := 18;
   aboveBelowItem := 3;
   menuFrame := 2 * frame;
   menuShadow := 2 * shadow;
  END
  ELSE   { small potatoes }
  BEGIN
   betweenTitles := 14;
   aboveBelowItem := 2;
   menuFrame := frame;
   menuShadow := shadow;
  END;   { ELSE }

  frameShad := menuFrame + menuShadow;
  scrollPolyDXY := mBarHt DIV 2;
{ Neighboring MENUs share inverted space: }
  invertOverlap := (betweenTitles DIV 2) + 1;

 END;   { wInitMenus }

wGetNewMBar is called every time I create a new window. Please pay close attention to the code that addresses color. This is where I store the attached Menu resource’s Menu Color Table (MCTableHandle) into wMenuBarHandle^^.wMCTable. I need this info in order to draw the Menu’s colors.

{11}

 FUNCTION wGetNewMBar (wp: WindowPtr; wMenuBarID: INTEGER): wMenuBarHandle;
{ Pass wMenuBarID = noMBARrsrc if you wish to start fresh }
{ and call wInsertMenu yourself.                          }

  CONST
   none = 0;

  TYPE
   rMenuBar = RECORD
     numMenus: INTEGER;
     menuIDs: ARRAY[0..0] OF INTEGER;
    END;
   rMenuBarPtr = ^rMenuBar;
   rMenuBarHdl = ^rMenuBarPtr;

  VAR
   rMBar: rMenuBarHdl;
   mh: MenuHandle;
   i: INTEGER;
   theWorld: SysEnvRec;
   itDoesntMatter: OSErr;

 BEGIN

  wGetNewMBar := NIL;   { Assume the pits !! }
  ;
  IF wp = NIL THEN
   EXIT(wGetNewMBar);

  rMBar := rMenuBarHdl(GetResource(‘MBAR’, wMenuBarID));

{ Out with the old Window Menu Bar if there’s one }
{ and in with the new:                            }
  wDeleteWMB(wp);
  ;
  mBar := wMenuBarHandle(NewClearHandle(SizeOf(wMenuBar)));
  IF MemError <> noErr THEN
  BEGIN
   IF rMBar <> NIL THEN
    ReleaseResource(Handle(rMBar));
   EXIT(wGetNewMBar);
  END;   { Whoops !! }
  mBar^^.titleHilited := noneHilited;
  wSetMenuBar(mBar, wp);

{ & so sue me -- I’m paranoid !! }  
  IF (rMBar <> NIL) & (rMBar^^.numMenus > 0) THEN 
  BEGIN
 { Save & restore main Menu Color Table }
 { so that GetMenu does NOT change it. }
   IF aMac2 THEN
    oldMCTable := GetMCInfo;

   FOR i := 0 TO (rMBar^^.numMenus - 1) DO
   BEGIN
    mh := GetMenu(rMBar^^.menuIDs[i]);
    IF mh <> NIL THEN   { Paranoid-ville again !! }
    BEGIN
     IF i = 0 THEN   { = Apple Menu }
     BEGIN
      itDoesntMatter := SysEnvirons(1, theWorld);
      IF theWorld.systemVersion < $0700 THEN
      BEGIN
       SetItemIcon(mh, AboutItem, none);
       SetItemCmd(mh, AboutItem, char(none));
      END;
      AddResMenu(mh, ‘DRVR’);   { + DAs }
     END;   { Apple Menu }
     wInsertMenu(mBar, mh, atEnd);
   { For calling GetMenu & AddResMenu lots. }
     DetachResource(Handle(mh)); 
    END;   { IF mh <> NIL }
   END;   { FOR }
   ;
   ReleaseResource(Handle(rMBar));

   IF aMac2 THEN
   BEGIN
    newMCTable := GetMCInfo;   { Safe on the Stack !! }
    SetMCInfo(oldMCTable);
  { Save for drawing & selecting. }
    mbar^^.wMCTable := newMCTable; 
   END;   { IF aMac2}
  END;   { IF a rMBar }

  wGetNewMBar := mBar;

 END;   { wGetNewMBar }


wGetMenuBar is used to retrieve the given window’s wMenuBarHandle for subsequent feeding to wDrawMenuBar and wDrawMSA for Update and Activate Events.

{12}

 FUNCTION wGetMenuBar (wp: WindowPtr): wMenuBarHandle;

  VAR
   i: INTEGER;

 BEGIN

  found := false;
  i := 0;
  ;
  wGetMenuBar := NIL;
  IF mBarList = NIL THEN
   EXIT(wGetMenuBar);

  WITH mBarList^^ DO
  BEGIN
   IF numWindows > 0 THEN
    WHILE (NOT found) & (i < numWindows) DO
     IF WMBars[i]^^.wp = wp THEN
      found := true
     ELSE
      i := i + 1                   { End of WHILE }

   ELSE   { zip windows }
    ;

   IF found THEN
    wGetMenuBar := WMBars[i];
  END;   { WITH }

 END;   { wGetMenuBar }

Just as James Matthews’ did it:

 PROCEDURE wSetMenuBar (theMenuBar: wMenuBarHandle; wp: WindowPtr);

 BEGIN
  theMenuBar^^.wp := wp;        { Simple, aint it ?!!? }
 END;   { wSetMenuBar }

 For example: 
    windPtr := GetNewWindow(...); 
    menuBar := wGetNewMBar(windPtr, barID); 
    IF menuBar <> NIL THEN
       wAddWMB(menuBar); 

 PROCEDURE wAddWMB (theMenuBar: wMenuBarHandle);

  VAR
   i: INTEGER;

 BEGIN

  newBarListSize := SizeOf(wMenuBarList) + (mBarList^^.numWindows + 1) 
* 4;
  IF newBarListSize > GetHandleSize(Handle(mBarList)) THEN
   IF MemError = noErr THEN
    SetHandleSize(Handle(mBarList), newBarListSize);

  IF MemError = noErr THEN
   WITH mBarList^^ DO
   BEGIN
    WMBars[numWindows] := theMenuBar;
    numWindows := numWindows + 1
   END;   { WITH }

 END;   { wAddWMB }


Used when closing a window:

{13}

 PROCEDURE wDeleteWMB (wp: WindowPtr);

  VAR
   i, j: INTEGER;

 BEGIN

  found := false;
  i := 0;

  IF mBarList^^.numWindows > 0 THEN
  BEGIN

   WHILE (NOT found) & (i < mBarList^^.numWindows) DO
    IF mBarList^^.WMBars[i]^^.wp = wp THEN
     found := true
    ELSE
     i := i + 1;   { End of WHILE }

   IF found THEN
   BEGIN
    wClearMenuBar(mBarList^^.WMBars[i]);
    DisposHandle(Handle(mBarList^^.WMBars[i]));
  { Not the last one in the List. }
    IF i <> (mBarList^^.numWindows - 1) THEN 
     FOR j := (i + 1) TO (mBarList^^.numWindows - 1) DO
      mBarList^^.WMBars[j - 1] := mBarList^^.WMBars[j]
    ELSE
  { Delete the last one.  Already done, }
  { so nada required here.              }
     ;
    mBarList^^.numWindows := mBarList^^.numWindows - 1;
    newBarListSize := GetHandleSize(Handle(mBarList)) - 4;
    IF MemError = noErr THEN
     SetHandleSize(Handle(mBarList), newBarListSize);
   END;   { IF found }

  END   { IF numWindows >0 }

  ELSE   { zip windows }
   ;

 END;   { wDeleteWMB }


To tell you the truth, I do NOT even use wClearMenuBarList, but it’s here for the sake of symmetry with wDrawMenuBar.

{14}

 PROCEDURE wClearMenuBarList (theMenuBarList: wMenuBarListHdl);
{ For now, I do NOT use the passed parm because it’s a }
{ global.  This may change in the future, however.      }

  CONST
   WindowListLoc = $9D6;   { 1st window in linked list. }

  VAR
   window: WindowPeek;

 BEGIN

  window := WindowPeek(longPtr(WindowListLoc));
  WHILE window <> NIL DO
  BEGIN
   wDeleteWMB(WindowPtr(window));
   window := window^.nextWindow;
  END;   { WHILE }

  { The following has already happened after execution }
  { of above WHILE loop:                               }
  {                                                    }
  { theMenuBarList^^.numWindows := 0;                  }
  { SetHandleSize(Handle(theMenuBarList),              }
  {               SizeOf(wMenuBarList));               }

 END;   { wClearMenuBarList }

These two routines are called by wInsertMenu & wDeleteMenu, respectively.

{15}

 FUNCTION IncreaseSize (theMenuBar: wMenuBarHandle): OSErr;

  VAR
   hState: SignedByte;

 BEGIN
  newWMBSize := SizeOf(wMenuBar) + (theMenuBar^^.numMenus + 1) * SizeOf(wMenuRec);
  IF newWMBSize > GetHandleSize(Handle(theMenuBar)) THEN
   IF MemError = noErr THEN
   BEGIN
    hState := HGetState(Handle(theMenuBar));
    HUnlock(Handle(theMenuBar));
    SetHandleSize(Handle(theMenuBar), newWMBSize);
  { Just in case entry state is locked: }
    MoveHHi(Handle(theMenuBar));
    HSetState(Handle(theMenuBar), hState);
   END;
  ;
  IncreaseSize := MemError;
 END;   { IncreaseSize }


 FUNCTION DecreaseSize (theMenuBar: wMenuBarHandle): OSErr;

  VAR
   hState: SignedByte;

 BEGIN
  newWMBSize := SizeOf(wMenuBar) + (theMenuBar^^.numMenus - 1) * SizeOf(wMenuRec);
  IF newWMBSize < GetHandleSize(Handle(theMenuBar)) THEN
   IF MemError = noErr THEN
   BEGIN
    hState := HGetState(Handle(theMenuBar));
    HUnlock(Handle(theMenuBar));
    SetHandleSize(Handle(theMenuBar), newWMBSize);
    MoveHHi(Handle(theMenuBar));
    HSetState(Handle(theMenuBar), hState);
   END;
  ;
  DecreaseSize := MemError;
 END;   { DecreaseSize }

Called when inserting & deleting a Menu so the Menu’s titleRect can be quantified.

{16}

 FUNCTION GetTitleWidth (theMenu: MenuHandle): INTEGER;

  VAR
   oldTxSize, oldTxFont, oldTxMode: INTEGER;
   oldTxStyle: Style;

 BEGIN
  oldTxSize := thePort^.txSize;
  oldTxFont := thePort^.txFont;
  oldTxStyle := thePort^.txFace;
  TextSize(sizeFont);
  TextFont(systemFont);
  TextFace([]);
  ;
  GetTitleWidth := StringWidth(theMenu^^.menuData);
  ;
  TextSize(oldTxSize);
  TextFont(oldTxFont);
  TextFace(oldTxStyle);
 END;   { GetTitleWidth }

This routine is present for the same reason as aboveBelowItem as discussed above. 
 See wMenuSelect.

 FUNCTION GetItemIconSize (theMenu: MenuHandle; item: INTEGER): INTEGER;

  CONST
   reducedIconCmd = $1D;
   smallIconCmd = $1E;

  VAR
   iconNbr: Byte;
   sizeIcon: INTEGER;
   theCICN: CIconHandle;
   cmdChar: char;

 BEGIN

  GetItemIcon(theMenu, item, iconNbr);
  IF iconNbr = 0 THEN
   sizeIcon := 0

  ELSE

  BEGIN
   IF aMac2 THEN
   BEGIN

    theCICN := GetCIcon(iconNbr + 256);

    IF theCICN <> NIL THEN
    BEGIN
     WITH theCICN^^.iconPMap.bounds DO
      sizeIcon := bottom - top;
     DisposCIcon(theCICN);
    END
    ELSE   { no cicn }
     sizeIcon := 32;

   END   { aMac2 }
   ELSE
    sizeIcon := 32;

   GetItemCmd(theMenu, item, cmdChar);
   IF (cmdChar = chr(reducedIconCmd)) | (cmdChar = chr(smallIconCmd)) 
THEN
    sizeIcon := sizeIcon DIV 2;
  END;   { Has either an ICON, a CICN, a reduced icon or a SICN }

  GetItemIconSize := sizeIcon;

 END;   { GetItemIconSize }

Continued in next frame
Volume Number:7
Issue Number:10
Column Tag:Color Workshop

Related Info: Menu Manager Memory Manager Color Quickdraw

Window Menu Bars Revisited (code)


When I insert a hierarchical Menu, I do so after all regular Menus. Also note that I account for the fact that all Menu items #32 and beyond are considered enabled as stipulated by the Menu Manager.

The arithmetic for determining the titleRect for a regular Menu dittos James Matthews’ algorithm. The titleRect for a hierarchical Menu is simply the rect for the parent item. We’ve just seen a picture worth at least two pages of prose ...

Note below that I store menuType and parentID in the wMenuRec RECORD. For a regular Menu, parentID = 0. I need these two pieces of info so I can subsequently determine what Menu type I’m looking at and, if a hierarchical Menu, so I can back-calculate to the Menu’s enclosing frame (see RedrawParentItem within wMenuSelect).

{17}

 PROCEDURE wInsertMenu (theMenuBar: wMenuBarHandle; theMenu: MenuHandle; 
beforeID: INTEGER);
{ Insert a Menu into a defined wMenuBar: }

  VAR
   hierID, index, i, j: INTEGER;
   found, enabled: BOOLEAN;
   parentMenuHdl: MenuHandle;
   oldPort: GrafPtr;
   cmdChar, parentMark: char;
   parentItemRect, parentFrameRect: Rect;
   currentHeight, prevHeight, sizeIcon: INTEGER;

 BEGIN

  IF beforeID = atEnd THEN
  BEGIN

   i := 0;
   WHILE (i < theMenuBar^^.numMenus) & (theMenuBar^^.wMenus[i].menuType 
= regMenu) DO
    i := i + 1;

   IF i < theMenuBar^^.numMenus THEN
 { Insert after end of regular portion of Window Menu Bar, }
 { which occurs just prior to the Hierarchical portion.    }
   BEGIN
    wInsertMenu(theMenuBar, theMenu, theMenuBar^^.wMenus[i].mh^^.menuID);
    EXIT(wInsertMenu);
   END
   ELSE
   BEGIN
    IF IncreaseSize(theMenuBar) <> noErr THEN
     EXIT(wInsertMenu);
    titleWidth := GetTitleWidth(theMenu);
   END;   { ELSE: i = numMenus }

  END   { beforeID = atEnd }

  ELSE IF beforeID = hierMenu THEN
  BEGIN

   hierID := theMenu^^.menuID;
   i := 0;
   found := false;
   ;
 { Scan entire wMenuBar. }
   WHILE (i < theMenuBar^^.numMenus) & NOT found DO
   BEGIN
    parentMenuHdl := theMenuBar^^.wMenus[i].mh;
  { Scan each menu. }
    FOR j := 1 TO CountMItems(parentMenuHdl) DO
    BEGIN
     GetItemCmd(parentMenuHdl, j, cmdChar);
     IF cmdChar = char(hMenuCmd) THEN
     BEGIN
      GetItemMark(parentMenuHdl, j, parentMark);
      IF ord(parentMark) = hierID THEN
      BEGIN
       found := true;
       Leave;   { FOR loop }
      END;   { IF ord() }
     END;   { Hierarchical Menu }
    END;   { FOR }

    i := i + 1;         { IF found, i = correct # plus 1. }
   END;   { WHILE }

   IF found THEN      { ... is it enabled ??? }
    IF j < 32 THEN
     enabled := BitTst(@theMenuBar^^.wMenus[i - 1].mh^^.enableFlags, 
menuTitleBit - j)
    ELSE
     enabled := true;   { Items 32 & beyond. }

   IF found & enabled & (IncreaseSize(theMenuBar) = noErr) THEN
   BEGIN
 { ’tis re-locked by IncreaseSize PROC. }
    WITH theMenuBar^^, wMenus[numMenus] DO     
    BEGIN

    mh := theMenu; { Place at end = Hierarchical portion. }
    menuType := hierMenu;
    parentID := parentMenuHdl^^.menuID;
  { These fields are filled-in later by wMenuSelect   }
  { for both Hierarchical and Regular menus:          }
  {                                                   }
  {   menuParentRgn, cumParentRgn and MenuDownOSHdl   }
  {                                                   }
  { You’ll notice that I ignore these fields when     }
  { inserting and deleting a Regular menu because     }
  { Hierarchical menus are inserted AFTER all Regular }
  { menus and are deleted immediately after use.      }

   END;  { WITH theMenuBar^^, wMenus[numMenus] }

 { titleRect = parent item’s rect.               }
 {                                               }
 { For starters, setup left & right coordinates: }

   WITH parentItemRect DO
   BEGIN
  { [i-1] belongs to parentMenuHdl. }
    WITH theMenuBar^^.wMenus[i - 1] DO
     IF menuType = regMenu THEN
      left := titleRect.left + menuFrame
     ELSE
      left := titleRect.right - 4 * menuFrame + menuFrame;
     CalcMenuSize(parentMenuHdl);
     right := left + parentMenuHdl^^.menuWidth;
    END;   { WITH parentItemRect }

    WITH theMenuBar^^.wMenus[i - 1] DO
     IF menuType = regMenu THEN
      currentHeight := titleRect.bottom + menuFrame
     ELSE
      currentHeight := titleRect.top + menuFrame;

    FOR index := 1 TO j DO
    BEGIN
     prevHeight := currentHeight;
     sizeIcon := GetItemIconSize(parentMenuHdl, index);
     currentHeight := currentHeight + aboveBelowItem + Max(sizeFont, 
sizeIcon) + aboveBelowItem;
    END;   { FOR }

  { Complete the other two dimensions. }
    WITH parentItemRect DO
    BEGIN
     top := prevHeight;
     bottom := currentHeight;
    END;   { WITH parentItemRect }

    WITH theMenuBar^^, wMenus[i - 1] DO
    BEGIN
   { Change ONLY right & left coords ... }       
     parentFrameRect := parentItemRect;
     WITH parentFrameRect DO
     BEGIN
      left := left - menuFrame;
       right := right + menuFrame + menuShadow;
      END;   { WITH parentFrameRect }

      GetPort(oldPort);
    { ---- }
      SetPort(wp);
      LocalGlobal(parentFrameRect);
    { WMgrPort’s portBits.bounds in global coordinates: }
      WITH gScreen DO 
      BEGIN
       IF parentFrameRect.right > right - 2 * menuFrame THEN  { Shift 
left. }
        IF menuType = regMenu THEN
         OffsetRect(parentFrameRect, right - 2 * menuFrame - parentFrameRect.right, 
0)
        ELSE
         OffsetRect(parentFrameRect, -(titleRect.right - titleRect.left 
- 8 * menuFrame + (parentFrameRect.right - parentFrameRect.left)), 0);
       ;
       IF parentFrameRect.left < left + 2 * menuFrame THEN    { Shift 
right. }
       OffsetRect(parentFrameRect, left + 2 * menuFrame - parentFrameRect.left, 
0);
      END;   { WITH gScreen }
    { Back to local window coordinates. }
      GlobalLocal(parentFrameRect); 
    { ---- }
      SetPort(oldPort);

      parentItemRect := parentFrameRect;
      WITH parentItemRect DO
      BEGIN
       left := left + menuFrame;
       right := right - menuFrame - menuShadow;
      END;
      ;
   { [numMenus] belongs to inserted sub-Menu: }
      wMenus[numMenus].titleRect := parentItemRect;
      numMenus := numMenus + 1;
     END;   { WITH theMenuBar^^, wMenus[i - 1] }

   END;   { IF found & enabled & IncreaseSize }

   EXIT(wInsertMenu);

  END   { beforeID = hierMenu }

  ELSE   { Smack in the middle somewhere !! }
  BEGIN

   IF IncreaseSize(theMenuBar) <> noErr THEN
    EXIT(wInsertMenu);

   titleWidth := GetTitleWidth(theMenu);

   WITH theMenuBar^^ DO
   BEGIN

    i := 0;
    WHILE (i < numMenus) & (wMenus[i].mh^^.menuID <> beforeID) DO
     i := i + 1;
    ;
    IF i <> numMenus THEN
    BEGIN
     FOR j := numMenus DOWNTO (i + 1) DO
     BEGIN
      wMenus[j].mh := wMenus[j - 1].mh;
      wMenus[j].menuType := wMenus[j - 1].menuType;
      wMenus[j].parentID := wMenus[j - 1].parentID;
       { Overkill just to copy top & bottom ... }
      wMenus[j].titleRect := wMenus[j - 1].titleRect;
       { ... now, adjust right & left if a regular Menu. }
      IF wMenus[j].menuType = regMenu THEN
       OffsetRect(wMenus[j].titleRect, titleWidth + betweenTitles, 0);
     END;   { FOR j := numMenus DOWNTO (i + 1) }
    END;   { IF i <> numMenus }

   END;   { WITH }

  END;   { in middle }

{ Some wierd arithmetic ... }

  WITH theMenuBar^^, wMenus[i].titleRect DO
  BEGIN

   top := wp^.portRect.top;
   ;
   bottom := top + mBarHt - menuFrame;
   ;
   left := wp^.portRect.left;
 { Make room for Menu Scroll Activator  --  see “wDrawMSA”: }
   IF i = 0 THEN   
    left := left + 2 * scrollPolyDXY + menuFrame + betweenTitles - invertOverlap
   ELSE
    left := left + wMenus[i - 1].titleRect.right - invertOverlap + betweenTitles 
- invertOverlap;
   ;
   right := left + invertOverlap + titleWidth + invertOverlap;

   IF numMenus = 0 THEN    { 1st call to wInsertMenu. }
    barLength := betweenTitles + titleWidth + betweenTitles
   ELSE
    barLength := barLength + titleWidth + betweenTitles;

   wMenus[i].mh := theMenu;
   wMenus[i].menuType := regMenu;
   wMenus[i].parentID := mainMenu;
   numMenus := numMenus + 1;

  END;   { WITH }

 END;   { wInsertMenu }

wDeleteMenu simply reverses the effect of wInsertMenu.

{18}

 PROCEDURE wDeleteMenu (theMenuBar: wMenuBarHandle; menuID: INTEGER);

  VAR
   i, j: INTEGER;

 BEGIN

  i := 0;
  WITH theMenuBar^^ DO
   WHILE (i < numMenus) & (wMenus[i].mh^^.menuID <> menuID) DO
    i := i + 1;                    { End of 1st WITH }
  ;
  IF i <> theMenuBar^^.numMenus THEN
  BEGIN
   IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
    titleWidth := GetTitleWidth(theMenuBar^^.wMenus[i].mh);

   WITH theMenuBar^^ DO
   BEGIN

    IF wMenus[i].menuType = regMenu THEN
     IF numMenus = 1 THEN        { Soon to be zero. }
      barLength := 0
     ELSE
      barLength := barLength - titleWidth - betweenTitles;

    FOR j := (i + 1) TO (numMenus - 1) DO
    BEGIN
     wMenus[j - 1].mh := wMenus[j].mh;
     wMenus[j - 1].menuType := wMenus[j].menuType;
     wMenus[j - 1].parentID := wMenus[j].parentID;
     wMenus[j - 1].titleRect := wMenus[j].titleRect;
     IF wMenus[j - 1].menuType = regMenu THEN
      OffsetRect(wMenus[j - 1].titleRect, -(titleWidth + betweenTitles), 
0);
    END;   { FOR j := (i + 1) TO (numMenus - 1) }

   END;   { 2nd WITH }

   IF DecreaseSize(theMenuBar) = noErr THEN
    ;
   theMenuBar^^.numMenus := theMenuBar^^.numMenus - 1;
  END;   { IF i <> theMenuBar^^.numMenus }

 END;   { wDeleteMenu }

I use GetWBMrects primarily to quantify the rects containing my MSAs which, in turn, play in my DoMouseDown PROC.

{19}

 PROCEDURE GetWBMrects (wp: WindowPtr; VAR WBMrect, leftMSArect, rightMSArect: 
Rect);

  PROCEDURE ZeroRect (VAR r: Rect);

  BEGIN

   WITH r DO
   BEGIN
    top := 0;
    left := 0;
    bottom := 0;
    right := 0;
   END;   { WITH }

  END;   { ZeroRect }

 BEGIN   { GetWBMrects }

  IF wGetMenuBar(wp) <> NIL THEN
  BEGIN

 { + quantifies “hasGrowIcon” for update Event: }
   windType := GetWindowType(wp);
   WBMrect := wp^.portRect;
   WITH WBMrect DO
   BEGIN
    IF hasGrowIcon THEN
     right := right - (scrollWidth - frame);
    bottom := top + mBarHt;
   END;

   leftMSArect := WBMrect;
   WITH leftMSArect DO
     right := left + 2 * scrollPolyDXY + menuFrame;

   rightMSArect := WBMrect;
   WITH rightMSArect DO
     left := right - 2 * scrollPolyDXY - menuFrame;

  END   { window has a Window Bar Menu }
  ELSE
  BEGIN
   ZeroRect(WBMrect);
   ZeroRect(leftMSArect);
   ZeroRect(rightMSArect);
  END;   { ELSE }

  dynamicBalloons[0].dynamicStrID := 128;
  IF windType = rDocProc THEN
   dynamicBalloons[0].dynamicStrIndex := 3
  ELSE
   dynamicBalloons[0].dynamicStrIndex := 6;
  dynamicBalloons[0].dynamicR := leftMSArect;
  ;
  dynamicBalloons[1].dynamicStrID := 128;
  IF windType = rDocProc THEN
   dynamicBalloons[1].dynamicStrIndex := 2
  ELSE
   dynamicBalloons[1].dynamicStrIndex := 5;
  dynamicBalloons[1].dynamicR := WBMrect;
{ Between MSAs:. }
  InsetRect(dynamicBalloons[1].dynamicR, leftMSArect.right, 0);   
  ;
  dynamicBalloons[2].dynamicStrID := 128;
  IF windType = rDocProc THEN
   dynamicBalloons[2].dynamicStrIndex := 4
  ELSE
   dynamicBalloons[2].dynamicStrIndex := 7;
  dynamicBalloons[2].dynamicR := rightMSArect;

 END;   { GetWBMrects }

GetColors, RestoreColors and wSetColorMenu play with color Menus and all three are called by both wDrawMenuBar and wMenuSelect:

{20}

 PROCEDURE GetColors;

 BEGIN

  IF aMac2 THEN
  BEGIN
   GetBackColor(oldBackColor);
   GetForeColor(oldForeColor);
  END;   { IF }

 END;   { GetColors }


 PROCEDURE RestoreColors;

 BEGIN

  IF aMac2 THEN
  BEGIN
   RGBBackColor(oldBackColor);
   RGBForeColor(oldForeColor);
  END;   { IF }

 END;   { RestoreColors }

 PROCEDURE wSetColorMenu (menusID, itemsID: INTEGER);
{ Without redefining Apple’s built-in MenuDefProc, }
{ we’re restricting ourselves to ALL Item text     }
{ (including the mark & CMD-key) being he same     }
{ color and ditto for the background color of ALL  }
{ Items.                                           }

  VAR
   MCTBEntry: MCEntryPtr;
 { What we actually got back from GetMCTBEntry       }
 { compared with what we asked for, the latter       }
 { being the original parms passed to wSetColorMenu: }
   returnedMenuID, returnedMenuItem: INTEGER;

  FUNCTION GetMCTBEntry (VAR menuID, itemID: INTEGER): MCEntryPtr;

   VAR
    mctbEntryPtr: MCEntryPtr;

  BEGIN

   GetMCTBEntry := NIL; { NOT very optimistic, are we ?!!? }

   mctbEntryPtr := GetMCEntry(menuID, itemID);

   IF mctbEntryPtr = NIL THEN
 { Could NOT find what we asked for, so recurse }
 { UP the chain:                                }
 {                                              }
 {  if no specified Item entry, then look for   }
 {    Title entry                               }
 {  if no asked-for Title entry, then look for  }
 {    MenuBar entry                             }
 {  if no specified MenuBar entry, then our     }
 {    ‘mctb’ resource is NOT correct            }
   BEGIN

    IF (menuID <> mceMenuBar) & (itemID <> mceMenuTitle) THEN
    BEGIN     { Asked for item }
     itemID := mceMenuTitle;
     GetMCTBEntry := GetMCTBEntry(menuID, itemID);
    END
    ELSE IF (menuID <> mceMenuBar) & (itemID = mceMenuTitle) THEN
    BEGIN     { Asked for title }
     menuID := mceMenuBar;
     itemID := mceMenuBar;
     GetMCTBEntry := GetMCTBEntry(menuID, itemID);
    END
    ELSE IF (menuID = mceMenuBar) & (itemID = mceMenuBar) THEN
     ;   { Ran out of steam !!! }

   END
   ELSE
    GetMCTBEntry := mctbEntryPtr;

  END;   { GetMCTBEntry }


 BEGIN   { wSetColorMenu }

  IF NOT aMac2 THEN
   EXIT(wSetColorMenu);

{ VARed ... what we actually get back from GetMCTBEntry. }
  returnedMenuID := menusID; 
  returnedMenuItem := itemsID; 
  ;
  MCTBEntry := GetMCTBEntry(returnedMenuID, returnedMenuItem);
  IF MCTBEntry = NIL THEN
   EXIT(wSetColorMenu);

  WITH MCTBEntry^ DO

   IF (returnedMenuID <> mceMenuBar) & (returnedMenuItem <> mceMenuTitle) 
THEN
   BEGIN                 { Asked for AND got a Menu Item. }
    RGBBackColor(mctRGB4);
    RGBForeColor(mctRGB2);
   END   { an Item element}

   ELSE IF (returnedMenuID <> mceMenuBar) & (returnedMenuItem = mceMenuTitle) 
THEN
   BEGIN
    RGBBackColor(mctRGB4);
    IF itemsID = mceMenuTitle THEN 
   { Asked for AND got a Menu Title. }
     RGBForeColor(mctRGB1)
    ELSE      { Asked for an Item, recursed to a Title. }
     RGBForeColor(mctRGB3);
   END   { a Title element }

   ELSE IF (returnedMenuID = mceMenuBar) & (returnedMenuItem = mceMenuBar) 
THEN
   BEGIN
  { Here, if you ask for the MenuBar entry, I assume }
  { you’re just interested in the background color   }
  { because you’re coloring the overall MenuBar via  }
  { _EraseRect.  If you’re really interested in the  }
  { background color of the pulled-down Menu, then   }
  { ask for a Menu Title or a Menu Item entry.       }
    IF menusID = mceMenuBar THEN 
   { Got what we asked for !! }
     RGBBackColor(mctRGB4)
    ELSE IF itemsID = mceMenuTitle THEN
  { Asked for a Title, recursed to MenuBar. }
    BEGIN
     RGBBackColor(mctRGB2);
     RGBForeColor(mctRGB1);
    END
    ELSE   { Asked for an Item, recursed TWICE to MenuBar. }
    BEGIN
     RGBBackColor(mctRGB2);
     RGBForeColor(mctRGB3);
    END
   END;   { got back a MenuBar element}
           { End of WITH }

 END;   { wSetColorMenu }

Note that I lock theMenuBar passed to wDrawMenuBar, but do NOT have that luxury with wMenuSelect. The reason for the latter is because I recurse however many times it takes to get to the appropriate hierarchical Menu no matter how deep it’s buried. More on this recursing & cursing later ...

{21}

 PROCEDURE wDrawMenuBar (theMenuBar: wMenuBarHandle);
{ Draw a wMenuBar with appropriate highlighting: }

  LABEL
   100, 200;

  VAR
   active: BOOLEAN;
   y0, i: INTEGER;
   lsWBMrect, offBarRect, titleR, visDrawingRect: Rect;
   titleRgn: RgnHandle;
 { Keep safe on Stack to avoid Memory Manager blues ... }
   safeTitle: Str255;

 BEGIN

  IF theMenuBar^^.numMenus = 0 THEN        { Nada !! }
   EXIT(wDrawMenuBar);

  mbHState := HGetState(Handle(theMenuBar));
  MoveHHi(Handle(theMenuBar));
{ ... because some TRAPs called inside the }
{     WITH block move memory.              }
  HLock(Handle(theMenuBar));

  GetPort(oldPort);
  SetPort(theMenuBar^^.wp);
  oldClip := NewRgn;
  GetClip(oldClip);
  ;
  GetColors;
  IF aMac2 THEN
  BEGIN
   oldMCTable := GetMCInfo;
   SetMCInfo(theMenuBar^^.wMCTable);
  END;   { IF aMac2 }

{ GetWBMrects already called by wDrawMSA. }
  lsWBMrect := WBMrect; 
  LocalGlobal(lsWBMrect);

{ Local window coordinates are input to & local screen }
{ coordinates are returned from CreateOffScreen:       }

  WITH theMenuBar^^ DO
  BEGIN

   active := (ORD(WindowPeek(wp)^.hilited) <> 0);

{ offBarRect may end up being wider than window’s portRect. }
   WITH offBarRect DO
   BEGIN
    top := WBMrect.top;
    bottom := WBMrect.bottom - menuFrame;
    left := leftMSArect.right;
    right := left + barLength;
    IF right < rightMSArect.left THEN
     right := rightMSArect.left;
   END;   { WITH offBarRect }

   IF barOSHdl <> NIL THEN
   BEGIN
    LocalGlobal(offBarRect);
    WITH lScreen.bounds DO            { _GlobalToLocal }
     OffsetRect(offBarRect, left, top);
    GOTO 100;
   END;   { Still there }

   barOSHdl := CreateOffScreen(offBarRect);
   IF (QuickStrip(Ptr(barOSHdl)) = NIL) | (barOSHdl^^.CreateOffScreenError 
<> noErr) THEN
    GOTO 200;

 { ELSE draw into off-screen Port as follows: }

   TextSize(sizeFont);
   TextFont(systemFont);
   TextFace([]);
   TextMode(srcOr);

 { We canNOT call _GlobalToLocal here because we’ve }
 { changed the portBits.bounds rectangle of our      }
 { off-screen port within “CreateOffScreen”.         }

   WITH lScreen.bounds DO  { Bounds BEFORE change. }
    OffsetRect(lsWBMrect, left, top);
   ;
   ClipRect(offBarRect);
   wSetColorMenu(mceMenuBar, mceMenuBar);
   EraseRect(offBarRect);  { Eliminate all stray matter. }

   y0 := (mBarHt - menuFrame - sizeFont) DIV 2;
   ;
   FOR i := 0 TO (numMenus - 1) DO
   BEGIN

    IF wMenus[i].menuType = hierMenu THEN
     Cycle;

    titleR := wMenus[i].titleRect;
  { Convert to local screen coordinates: }
    OffsetRect(titleR, lsWBMrect.left, lsWBMrect.top);
{Eliminate the overshoot placed there to invert title,}
{because all we wish to do is draw the title string:  }
    InsetRect(titleR, invertOverlap, 0);
    ;
    MoveTo(titleR.left, titleR.bottom - y0);
    wSetColorMenu(wMenus[i].mh^^.menuID, mceMenuTitle);
    safeTitle := wMenus[i].mh^^.menuData;
    DrawString(safeTitle);

{Gray-out disabled Menu titles ONLY if window is active.}
{We dim the whole Window Bar Menu below if window isn’t.}
{The latter allows for CMD-dragging the window.         }

    IF active & NOT BitTst(@wMenus[i].mh^^.enableFlags, menuTitleBit) 
THEN
    BEGIN
     titleRgn := NewRgn;
     RectRgn(titleRgn, titleR);
     DimRgn(titleRgn);
     DisposeRgn(titleRgn);
    END;   { Gray-out disabled title }

   END;   { FOR ... drawing off-screen }
100:
   ToOnScreen(barOSHdl);          { Back to “Square 1”. }

   WITH barOSHdl^^ DO
   BEGIN
    visDrawingRect := drawingRect;

    ClipRect(drawingRect);

    BackColor(whiteColor);      { So funny colorization }
    ForeColor(blackColor);      {   does NOT happen !!  }
    ;
  { Adjust if overlapping right MSA. }
    WITH visDrawingRect DO 
     IF right > rightMSArect.left THEN
      right := rightMSArect.left;
    onScreenRgn := NewRgn;
    RectRgn(onScreenRgn, visDrawingRect);
    CalcVis(WindowPeek(wp));    { Radius’ TOM INIT. }
    SectRgn(onScreenRgn, wp^.visRgn, onScreenRgn);
    CopyBits(offBitMapPtr^, thePort^.portBits, offBarRect, drawingRect, 
srcCopy, onScreenRgn);

  { Consider you’re CMD-dragging ... }
    IF NOT active THEN
     DimRgn(onScreenRgn);
    ValidRgn(onScreenRgn);
    DisposeRgn(onScreenRgn);
   END;   { WITH barOSHdl^^ }
200:
   DisposOffScreen(barOSHdl);

  END;   { WITH theMenuBar^^ }

{ Deliberately last ... we’re safe now  !! }
  HSetState(Handle(theMenuBar), mbHState); 
                                                        
  RestoreColors;
  IF aMac2 THEN
   SetMCInfo(oldMCTable);
  ;
  SetClip(oldClip);
  DisposeRgn(oldClip);
  SetPort(oldPort);

{ Appropriate highlighting = none. }
  wHiliteMenu(theMenuBar, 0); 

 END;   { wDrawMenuBar }

Here’s another PROC wherein I need access to my MSA rects. When I scroll, I merely offset the titleRects of the regular Menu’s titleRects (the hierarchical Menus and their titleRects are NOT present except when I’m choosing a Menu item within wMenuSelect). After offseting the titleRects, I redraw the MSAs and then the window’s MenuBar ... simple ain’t it ?!*!?

{22}

 PROCEDURE wScrollMenuBar (theMenuBar: wMenuBarHandle);

  CONST
   toRight = 1;
   toLeft = -1;

  VAR
   mouseLoc: Point;
   nbrMenus, direction, temp, deltaScroll, i: INTEGER;

 BEGIN

  nbrMenus := theMenuBar^^.numMenus;

  GetMouse(mouseLoc);
  IF PtInRect(mouseLoc, leftMSArect) THEN
   direction := toRight
  ELSE IF PtInRect(mouseLoc, rightMSArect) THEN
   direction := toLeft
  ELSE
   EXIT(wScrollMenuBar);          { Should NOT happen !! }

  WHILE WaitMouseUp DO
  BEGIN
   IF direction = toRight THEN
   BEGIN
    temp := leftMSArect.right + betweenTitles - invertOverlap - mBar^^.wMenus[0].titleRect.left;
    IF temp <= 0 THEN
     Leave
    ELSE
     deltaScroll := Min(StringWidth(‘A’), temp);
   END
   ELSE     { direction = toLeft }
   BEGIN
    temp := rightMSArect.left - (mBar^^.wMenus[nbrMenus - 1].titleRect.right 
- invertOverlap + betweenTitles);
    IF temp >= 0 THEN
     Leave
    ELSE
   { Absolute value. }
     deltaScroll := Min(StringWidth(‘A’), -temp);
   END;

   deltaScroll := direction * deltaScroll;
   FOR i := 0 TO (nbrMenus - 1) DO
    OffsetRect(theMenuBar^^.wMenus[i].titleRect, deltaScroll, 0);
   wDrawMSA(theMenuBar);
   wDrawMenuBar(theMenuBar);
  END;   { WHILE }

 END;   { wScrollMenuBar }

Get ’em and weep, I mean ‘draw’ :

PROCEDURE wGetMSA (theMenuBar: wMenuBarHandle);

  VAR
   dx, dy, over, back, up, down: INTEGER;
   tempPoly: PolyHandle;

 BEGIN

  WITH WBMrect DO
  BEGIN
   GetPort(oldPort);
   SetPort(theMenuBar^^.wp);

   GetWBMrects(theMenuBar^^.wp, WBMrect, leftMSArect, rightMSArect);

 { ---------------------------------------------------------------------- 
}
 { Get MSA at left of Window Bar Menu: }

   dx := 3 * (scrollPolyDXY DIV 2);
   dy := (bottom - menuFrame - top - scrollPolyDXY) DIV 2;
   over := scrollPolyDXY;
   back := -over;
   up := -scrollPolyDXY;
   down := scrollPolyDXY DIV 2;

   IF theMenuBar^^.leftScrollPoly = NIL THEN
   BEGIN
  { I can’t believe I did this ?!*!?          }
  { theMenuBar^^.leftScrollPoly := OpenPoly;  }
    tempPoly := OpenPoly;
    theMenuBar^^.leftScrollPoly := tempPoly;
    MoveTo(left + dx, bottom - menuFrame - dy);
    Line(0, up);                { Vertical part ...     }
    Line(back, down);           { ... horizontal parts: }
    Line(over, down);
    ClosePoly;
   END;   { Doesn’t exist, so make a new one }

  { ------------------------------------------------------------------------ 
}
  { Get MSA at right of Window Bar Menu: }

   IF theMenuBar^^.rightScrollPoly = NIL THEN
   BEGIN
    tempPoly := OpenPoly;
    theMenuBar^^.rightScrollPoly := tempPoly;
    MoveTo(right - dx, bottom - menuFrame - dy);
    Line(0, up);                 { Vertical part ...     }
    Line(over, down);            { ... horizontal parts: }
    Line(back, down);
    ClosePoly;
   END;   { IF }

   SetPort(oldPort);
  END;   { WITH WBMrect }

 END;   { wGetMSA }


 PROCEDURE wDrawMSA (theMenuBar: wMenuBarHandle);
{ ... AND the bottom line bordering the Window Bar Menu.   }

  LABEL
   100;

  VAR
   dx, dy: INTEGER;
   aux: BOOLEAN;
   frameColor: RGBColor;

 BEGIN

  WITH WBMrect DO
  BEGIN
   GetPort(oldPort);
   SetPort(theMenuBar^^.wp);
   GetPenState(pnState);

 { ------------------------------------------------------------------------------------------------------------ 
}
 { Get the Window Bar Menu rect & draw a line beneath it: }

   wGetMSA(theMenuBar);              { Calls GetWBMrects. }
   gWBMrect := WBMrect;
   LocalGlobal(gWBMrect);
   IF NOT SectRect(gWBMrect, gScreen, visRect) THEN
    GOTO 100;
   GlobalLocal(visRect);
   onScreenRgn := NewRgn;
   RectRgn(onScreenRgn, visRect);
   SectRgn(onScreenRgn, theMenuBar^^.wp^.visRgn, onScreenRgn);
   oldClip := NewRgn;
  GetClip(oldClip);
  SetClip(onScreenRgn);
  ;
   aux := GetWindowPartColor(theMenuBar^^.wp, wFrameColor, frameColor);
   IF (colorDepth > 1) & aux THEN
   BEGIN
    GetForeColor(oldForeColor);
    RGBForeColor(frameColor);
   END;   { Draw in color }
   ;
   PenNormal;
   PenSize(menuFrame, menuFrame);
   MoveTo(left, bottom - menuFrame);
   Line(right - left, 0);

 { ---------------------------------------------------------------- }
 { Draw MSA at left of Window Menu: }

   IF theMenuBar^^.wMenus[0].titleRect.left < leftMSArect.right + betweenTitles 
- invertOverlap THEN
    FillPoly(theMenuBar^^.leftScrollPoly, black)
   ELSE
   BEGIN
    FillPoly(theMenuBar^^.leftScrollPoly, white);
    FramePoly(theMenuBar^^.leftScrollPoly);
   END;

 { ------------------------------------------------------------------------------------------------------ 
}
 { Draw vertical line separating MSA from Menu titles: }

   MoveTo(left + 2 * scrollPolyDXY, bottom - menuFrame);
   Line(0, -(bottom - top - menuFrame));

 { -------------------------------------------------------------------------- 
}
 { Draw MSA at right of Window Bar Menu: }

   IF theMenuBar^^.wMenus[theMenuBar^^.numMenus - 1].titleRect.right 
- invertOverlap + betweenTitles > rightMSArect.left THEN
    FillPoly(theMenuBar^^.rightScrollPoly, black)
   ELSE
   BEGIN
    FillPoly(theMenuBar^^.rightScrollPoly, white);
    FramePoly(theMenuBar^^.rightScrollPoly);
   END;
   ;
   MoveTo(right - 2 * scrollPolyDXY - menuFrame, bottom - menuFrame); 
                               { + vertical }
   Line(0, -(bottom - top - menuFrame));   {   line.    }

   IF ORD(WindowPeek(theMenuBar^^.wp)^.hilited) = 0 THEN
    DimRgn(onScreenRgn);

   ValidRgn(onScreenRgn);
   DisposeRgn(onScreenRgn);
   SetClip(oldClip);
   DisposeRgn(oldClip);
 
   IF (colorDepth > 1) & aux THEN
    RGBForeColor(oldForeColor);
100:
   SetPenState(pnState);
   SetPort(oldPort);
   ValidRect(visRect);
  END;   { WITH }

 END;   { wDrawMSA }

Kill the polyHandles. Note that barOSHdl is always = NIL because immediately after I create this OffScreenRecHdl within wDrawMenuBar and subsequently bit it back on-screen, I then call DisposOffscreen.

{23}

 PROCEDURE wClearMenuBar (theMenuBar: wMenuBarHandle);
{ Called internally by wDeleteWMB to }
{ kiss some Handles goodbye.         }

 BEGIN

  mbHState := HGetState(Handle(theMenuBar));
  MoveHHi(Handle(theMenuBar));
  HLock(Handle(theMenuBar));

  WITH theMenuBar^^ DO
  BEGIN
   wHiliteMenu(theMenuBar, 0);

 { So sue me ... I’m paranoid !! }
   IF leftScrollPoly <> NIL THEN 
   BEGIN
    KillPoly(leftScrollPoly);
    leftScrollPoly := NIL;   { Mark as gone ... }
   END;
   ;
   IF rightScrollPoly <> NIL THEN
   BEGIN
    KillPoly(rightScrollPoly);
    rightScrollPoly := NIL;
   END;

   IF barOSHdl <> NIL THEN
    DisposOffScreen(barOSHdl);   { Sets barOSHdl := NIL }
  END;   { WITH }

  HSetState(Handle(theMenuBar), mbHState);

 END;   { wClearMenuBar }


Now, the recursing & cursing ...

The local routine ItDoesFit is used when you’ve dragged the window close to the screen’s phycical bottom edge, not leaving enough room to draw at least three items if there’s more than three to begin with.

GetParentMenuInfo is used to quantify the index for both RgnHandles, cumParentRgn & menuParentRgn, when dealing with hierarchical Menus.

See the intro comments for RedrawParentItem for its purpose in life.

wMenuSelect is no longer the nightmare it initially was, thanks to Ben Cranston. Initially I had locked the passed wMenuBarHandle & surrounded darn near the entire PROC with a WITH theMenuBar^^. But then, with recursion for a hierarchical Menu, I called wInsertMenu which immediately unlocked wMenuBarHandle & called MoveHHi. Oh where, o’ where did the handle go ... thanks Ben !!!!!

{24}

 FUNCTION wMenuSelect (theMenuBar: wMenuBarHandle; startPt: Point): LONGINT;
{ Pull down the Menus and let the user select an Item: }
{ NOTE -- “startPt” is in Global coordinates, but      }
{         ONLY to be compatible with _MenuSelect.      }

  LABEL
   100, 200;

  CONST
   TopMenuItemLoc = $A0A;
   AtMenuBottomLoc = $A0C;
   MenuFlashAddr = $A24;
   HiliteMode = $938;

  VAR
   oldPort: GrafPtr;  { Many Locals because of recursion   }
   oldClip: RgnHandle;
   oldForeColor, oldBackColor: RGBColor;
   screenBounds, betweenMSAs, visAllTitles, visThisTitle, visString: 
Rect;
   menuRect, menuFrameRect, lsMenuRect, lsWBMrect, lsTitleRect: Rect;
   lStartPt, hierPt, NILPt: Point;
   itemsHeight, i, j, blink: INTEGER;
   saveScrollInfo: LONGINT;
   menuFlashP: wordPtr;
   strayed: BOOLEAN;
   cmdChar, itemMark: char;
   hierMenuHdl: MenuHandle;
   origMCTable, parentMCTable, hierMCTable: MCTableHandle;
   hierSelect: LONGINT;
   onCScreen: CGrafPort;
   onCScreenPtr: CGrafPtr;
   onBWScreen: GrafPort;
   onBWScreenPtr: GrafPtr;
   MenuDownOSHdl: OffScreenRecHdl;
 { Murphy’s Memory Manager ... }
   tempRgn1, tempRgn2, tempRgn3: RgnHandle;


  FUNCTION ItDoesFit (theMenu: MenuHandle; maxMenuHeight: INTEGER; VAR 
cumMenuHeight: INTEGER): BOOLEAN;
{ Get maximum cum height that can fit }
{ within the specified max height.    }

   VAR
    prevMenuHeight, index, sizeItemIcon: INTEGER;

  BEGIN

   ItDoesFit := true;                    { Be upbeat !! }
   IF theMenu^^.menuHeight <= maxMenuHeight THEN
   BEGIN
    cumMenuHeight := theMenu^^.menuHeight;
    EXIT(ItDoesFit);
   END;

   cumMenuHeight := 0;                { For starters ... }

   FOR index := 1 TO CountMItems(theMenu) DO
   BEGIN
    prevMenuHeight := cumMenuHeight;
    sizeItemIcon := GetItemIconSize(theMenu, index);
    cumMenuHeight := cumMenuHeight + aboveBelowItem + Max(sizeFont, sizeItemIcon) 
+ aboveBelowItem;
    IF cumMenuHeight > maxMenuHeight THEN
     Leave;   { FOR loop }
   END;   { FOR }

   IF index - 1 < 3 THEN
    ItDoesFit := false
   ELSE IF sizeItemIcon = 0 THEN 
  { ... of first item NOT shown. }
    cumMenuHeight := prevMenuHeight
   ELSE
  { Prevents drawing of the top pixels of }
  { any icon in first item NOT shown:    }
    cumMenuHeight := prevMenuHeight - aboveBelowItem;

  END;   { ItDoesFit }


  FUNCTION GetParentMenuInfo (theMenuBar: wMenuBarHandle; hierMenuNbr: 
INTEGER): LONGINT;
{ Returns parent menu # in Hi word and }
{ parent item # in the low word:       }
{   NEVER say it can NEVER fail !!!    }

   VAR
    hierID, parentMenuNum, j: INTEGER;
    parentMenuHdl: MenuHandle;
    cmdChar, parentMark: char;
    temp: LONGINT;

  BEGIN

   WITH theMenuBar^^ DO
   BEGIN
    parentMenuNum := 0;
    WHILE (parentMenuNum < numMenus) & (wMenus[hierMenuNbr].parentID 
<> wMenus[parentMenuNum].mh^^.menuID) DO
     parentMenuNum := parentMenuNum + 1;

    IF parentMenuNum = numMenus THEN
   { It better NOT be !!! }
     ;
    hierID := wMenus[hierMenuNbr].mh^^.menuID;
    parentMenuHdl := wMenus[parentMenuNum].mh;
   END;   { WITH }

   FOR j := 1 TO CountMItems(parentMenuHdl) DO
   BEGIN
    GetItemCmd(parentMenuHdl, j, cmdChar);
    IF cmdChar = char(hMenuCmd) THEN
    BEGIN
     GetItemMark(parentMenuHdl, j, parentMark);
     IF ord(parentMark) = hierID THEN
      Leave;   { FOR loop }
    END;
   END;   { FOR }

   temp := parentMenuNum;
   temp := BitShift(temp, 16) + j;
   GetParentMenuInfo := temp;

  END;   { GetParentMenuInfo }

  PROCEDURE RedrawParentItem (theMenuBar: wMenuBarHandle; hierMenuNbr: 
INTEGER);
{ Apple’s MenuDefProc does NOT call _InverRect for a }
{ color Mac, but rather _EraseRect followed by a      }
{ redraw of the Menu item  with reversed background   }
{ and hilite colors.  As you can see below, however,  }
{ I am prone to cheating:                             }


 { CONST                    }
 {  TopMenuItemLoc = $A0A;  }
 {  AtMenuBottomLoc = $A0C; }

   VAR
    saveScrollInfo: LONGINT;          { MUST be local !!! }
    parentMenuInfo: LONGINT;
    parentMenuNum, redrawitem: INTEGER;
    redrawPt: Point;
    parentMenuHdl: MenuHandle;
    parentMenuRect: Rect;

  BEGIN

   IF NOT aMac2 THEN
    EXIT(RedrawParentItem);

   parentMenuInfo := GetParentMenuInfo(theMenuBar, hierMenuNbr);
   parentMenuNum := HiWord(parentMenuInfo);
   redrawItem := LoWord(parentMenuInfo);

   WITH theMenuBar^^.wMenus[parentMenuNum] DO
   BEGIN
    parentMenuHdl := mh;
    parentMenuRect := menuParentRgn^^.rgnBBox;
   END;
   ClipRect(parentMenuRect);
   WITH lScreen.bounds DO    { LocalToGlobal }
    OffsetRect(parentMenuRect, -left, -top);

   SetPt(redrawPt, 0, 0);
   saveScrollInfo := longPtr(TopMenuItemLoc)^;
   wordPtr(TopMenuItemLoc)^ := parentMenuRect.top;
   wordPtr(AtMenuBottomLoc)^ := parentMenuRect.bottom;
   MenuDefGlue(mChooseMsg, parentMenuHdl, parentMenuRect, redrawPt, redrawItem);
   longPtr(TopMenuItemLoc)^ := saveScrollInfo;

  END;   { RedrawParentItem }


 BEGIN   { wMenuSelect }

{ Note that starting here, we sure could use      }
{ WITH theMenuBar^^ & WITH wMenus[i] statements  }
{ for shorthand.  However, we’d then need to call }
{ HLock.  This would be okay except when we later }
{ implement Hierarchical menus via a recursive to }
{ ourself (wMenuSelect).  This unnecessarily      }
{ keeps a locked Handle around for a long time.   }
{ [ See “The Secret Life of the Memory Manager”   }
{   by Richard Clark n “develop”, Volume 1,       }
{   Issue 2, April 1990                        ]  }
{ In addition, for Hierarchical menus, we call    }
{ wInsertMenu and wDeleteMenu which in turn call  }
{ the IncreaseSize and DecreaseSize PROCs.  These }
{ latter PROCs move “theMenuBar” because we need  }
{ to temporarily unlock this handle   therefore   }                  
          

  GetPort(oldPort);
  SetPort(theMenuBar^^.wp);
  oldClip := NewRgn;
  GetClip(oldClip);
  ;
  IF aMac2 THEN
  BEGIN
{ “GetColors” is local due to recursion. }
   GetBackColor(oldBackColor); 
   GetForeColor(oldForeColor);
   origMCTable := GetMCInfo;
   SetMCInfo(theMenuBar^^.wMCTable);
  END;   { IF aMac2 }
  ;
  menuFlashP := wordPtr(MenuFlashAddr);

  WHILE WaitMouseUp DO
  BEGIN

   whichItem := 0;             { May NOT be in a titleRect. }

 { Find the Menu title that user is selecting. }
   i := theMenuBar^^.numMenus - 1;
   GlobalToLocal(startPt);     { Local window coordinates. }
   WHILE (i >= 0) & NOT PtInRect(startPt, theMenuBar^^.wMenus[i].titleRect) 
DO
    i := i - 1;

   IF i >= 0 THEN             { Have Menu drop ... }
   BEGIN

    lsTitleRect := theMenuBar^^.wMenus[i].titleRect;
    ;
    IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
    BEGIN

   { Otherwise strayed = TRUE momentarily as you hit the  }
   { line bordering titleRect & menuRect in the process   }
   { of pulling down a MENU (see below):                  }
     lsTitleRect.bottom := lsTitleRect.bottom + menuFrame;

   {   ... AND if the Window Menu Bar is scrolled ...     }
   { don’t forget about the invertOverlap arithmetic      }
   { which would enable the Mouse to be over the expanded }
   { titleRect WITHOUT the first/last title   }
   { character being visible.  The equations below avoid  }
   { this happenstance.  In addition, “menuFrame” is used }
   { to account for a character width > an image width as }
   { well as a character origin > 0.                      }

     screenBounds := gScreen;       { = GrayRgn’s rgnBBox. }
     GlobalLocal(screenBounds);
     betweenMSAs := WBMrect;
     InsetRect(betweenMSAs, leftMSArect.right, 0);
     IF NOT SectRect(screenBounds, betweenMSAs, visAllTitles) THEN
      GOTO 100;                      { Will NOT happen !! }

     IF NOT SectRect(visAllTitles, lsTitleRect, visThisTitle) THEN
      GOTO 100;                      { Ditto !! }

     visString := visThisTitle;
     WITH visString DO
     BEGIN
      IF (leftMSArect.right > right - invertOverlap - 2 * menuFrame) 
| (screenBounds.left > right - invertOverlap - 2 * menuFrame) THEN
       right := right - invertOverlap - 2 * menuFrame;
      ;
      IF (rightMSArect.left < left + invertOverlap + 2 * menuFrame) | 
(screenBounds.right < left + invertOverlap + 2 * menuFrame) THEN
       left := left + invertOverlap + 2 * menuFrame;
     END;   { WITH visString }
     IF EmptyRect(visString) THEN
      GOTO 100;

    END;   { a regular Menu }

    LocalGlobal(lsTitleRect);
  { Needed for vertical scrolling: }
    lsWBMrect := WBMrect; 
  { ... or rightMSArect.left: }
    InsetRect(lsWBMrect, leftMSArect.right, 0);
    LocalGlobal(lsWBMrect);

    LocalToGlobal(startPt);

    CalcMenuSize(theMenuBar^^.wMenus[i].mh);

    WITH theMenuBar^^.wMenus[i], titleRect DO
     IF menuType = regMenu THEN
      SetRect(menuFrameRect, left, bottom, left + menuFrame + mh^^.menuWidth 
+ frameShad, bottom + menuFrame + mh^^.menuHeight + frameShad)
     ELSE
      SetRect(menuFrameRect, right - 4 * menuFrame, top, right - 4 * 
menuFrame + menuFrame + mh^^.menuWidth + frameShad, top + menuFrame + 
mh^^.menuHeight + frameShad);

 { If Menu overlaps the screen’s edges, }
 { trim and/or shift it:                }
    LocalGlobal(menuFrameRect);
    WITH gScreen DO 
    BEGIN
     IF menuFrameRect.bottom > bottom - 2 * menuFrame THEN
      menuFrameRect.bottom := bottom - 2 * menuFrame;
     ;
     IF menuFrameRect.right > right - 2 * menuFrame THEN  
    { Shift left. }
      IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
       OffsetRect(menuFrameRect, right - 2 * menuFrame - menuFrameRect.right, 
0)
      ELSE
       OffsetRect(menuFrameRect, -(theMenuBar^^.wMenus[i].titleRect.right 
- theMenuBar^^.wMenus[i].titleRect.left - 8 * menuFrame + (menuFrameRect.right 
- menuFrameRect.left)), 0);
     ;
     IF menuFrameRect.left < left + 2 * menuFrame THEN    
    { Shift right. }
      OffsetRect(menuFrameRect, left + 2 * menuFrame - menuFrameRect.left, 
0);
    END;   { WITH gScreen }
    GlobalLocal(menuFrameRect); { --> local window coords. }

    WITH menuFrameRect DO
     IF ItDoesFit(theMenuBar^^.wMenus[i].mh, bottom - top - menuFrame 
- frameShad, itemsHeight) THEN
      bottom := top + menuFrame + itemsHeight + frameShad
     ELSE IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
     BEGIN      { Damn SysBeep drove me nuts/nuttier !!! }
      wHiliteMenu(theMenuBar, theMenuBar^^.wMenus[i].mh^^.menuID);
      Delay(flashDelay * 2, finalTicks);
      wHiliteMenu(theMenuBar, 0);
      Delay(flashDelay * 2, finalTicks);
      GOTO 100;
     END
     ELSE
     BEGIN
    { From Open(C)Port on the previous go-around. }
      SetPort(oldPort);        
      WITH lScreen.bounds DO
       OffsetRect(lsTitleRect, left, top);  { GlobalToLocal }
      Delay(flashDelay * 2, finalTicks);
      IF aMac2 THEN
     { i = Hierarchical Menu # }
       RedrawParentItem(theMenuBar, i)        
      ELSE
      BEGIN
       ClipRect(lsTitleRect);
       InvertRect(lsTitleRect);
      END;
      Delay(flashDelay * 2, finalTicks);
    { So we can reset its clipRgn on exit: }
      SetPort(theMenuBar^^.wp);                
      Leave;
     END;   { does NOT fit & WITH menuFrameRect }

  { MenuDefProc’s “mChooseMsg” handles hiliting }
  { for a Hierarchical menu item:               }
    IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
     wHiliteMenu(theMenuBar, theMenuBar^^.wMenus[i].mh^^.menuID);

    MenuDownOSHdl := CreateOffScreen(menuFrameRect);
    IF (QuickStrip(Ptr(MenuDownOSHdl)) = NIL) | (MenuDownOSHdl^^.CreateOffScreenError 
<> noErr) THEN
    BEGIN
     DisposOffScreen(MenuDownOSHdl);
     GOTO 200;
    END;   { Whoops !! }

    ClipRect(menuFrameRect);  { Draw off-screen ... }
    EraseRect(menuFrameRect); { Eliminate all stray matter. }

  { An alternate “ToOnScreen” so our Menu can overlap }
  { the window’s boundaries rather than be confined   }
  { to just its portRect:                             }
    IF aMac2 THEN
    BEGIN
     SetGDevice(MenuDownOSHdl^^.oldDevice);
     onCScreenPtr := @onCScreen;
     OpenCPort(onCScreenPtr);
   { For multiple screens ... }
     RectRgn(onCScreenPtr^.visRgn, gScreen);
     onCScreenPtr^.portRect := gScreen;
    END   { IF aMac2 }
    ELSE
    BEGIN
     onBWScreenPtr := @onBWScreen;
     OpenPort(onBWScreenPtr);
     RectRgn(onBWScreenPtr^.visRgn, gScreen);
     onBWScreenPtr^.portRect := gScreen;
    END;   { ELSE = “Yucky” black-and-white }

    ClipRect(menuFrameRect);
  { Save current screen image: }
    BackColor(whiteColor);
    ForeColor(blackColor);
    CopyBits(thePort^.portBits, MenuDownOSHdl^^.offBitMapPtr^, menuFrameRect, 
menuFrameRect, srcCopy, NIL);

    TextSize(sizeFont);
    TextFont(systemFont);
    TextFace([]);
    TextMode(srcOr);

  { NOW, the magic ~~ Mike Shuster, MacTutor <Dec, 85> }

    menuRect := menuFrameRect;
    WITH menuRect DO
    BEGIN                    { Draw frame, then shadow. }
     GetPenState(pnState);
     PenNormal;

     right := right - menuShadow;
     bottom := bottom - menuShadow;
     wSetColorMenu(theMenuBar^^.wMenus[i].mh^^.menuID, mceMenuTitle);
     EraseRect(menuRect);     { Inside shadow. }
     PenSize(menuFrame, menuFrame);
     FrameRect(menuRect);
   { Inside frame AND shadow: }
     InsetRect(menuRect, menuFrame, menuFrame);     
     ;
     MoveTo(left + menuShadow, bottom + menuFrame);
     PenSize(menuShadow, menuShadow);
     Line((right - left + menuFrame), 0);
     MoveTo(right + menuFrame, bottom + frameShad);
     Line(0, -(bottom - top + menuFrame));

     SetPenState(pnState);
    END;   { WITH menuRect }

    lsMenuRect := menuRect;         { Save for later ... }

    WITH lScreen DO
    BEGIN
     OffsetRect(menuRect, -left, -top);  { LocalToGlobal }
     OffsetRect(lsTitleRect, left, top); { GlobalToLocal  }
     OffsetRect(lsWBMrect, left, top);
    END;   { WITH lScreen }

  { ... or parentID = mainMenu. }
    IF theMenuBar^^.wMenus[i].menuType = regMenu THEN  
    BEGIN
     tempRgn1 := NewRgn;
     RectRgn(tempRgn1, lsWBMrect);
     theMenuBar^^.wMenus[i].cumParentRgn := tempRgn1;
     tempRgn2 := NewRgn;
     RectRgn(tempRgn2, lsMenuRect);
     theMenuBar^^.wMenus[i].menuParentRgn := tempRgn2;
    END
    ELSE
    BEGIN
   { i = Hierarchical Menu # }
     j := HiWord(GetParentMenuInfo(theMenuBar, i)); 
     tempRgn1 := NewRgn;
     tempRgn2 := theMenuBar^^.wMenus[j].cumParentRgn;
     tempRgn3 := theMenuBar^^.wMenus[j].menuParentRgn;
     UnionRgn(tempRgn2, tempRgn3, tempRgn1);
     theMenuBar^^.wMenus[i].cumParentRgn := tempRgn1;
     tempRgn2 := NewRgn;
     RectRgn(tempRgn2, lsMenuRect);
     theMenuBar^^.wMenus[i].menuParentRgn := tempRgn2;
    END;

  { Start fresh with each scrollable Menu: }
    saveScrollInfo := longPtr(TopMenuItemLoc)^;
    wordPtr(TopMenuItemLoc)^ := menuRect.top;
    wordPtr(AtMenuBottomLoc)^ := menuRect.bottom;

 { I encountered a few “cosmetic” problems with Apple’s   }
 { MenuDefProc.                                           }
 {   1) the disabled dotted line will overwrite the right }
 {      border of the frame.                              }
 {   2) if there is an icon immediately below the last    }
 {      item that shows in a scrolling menu, the bottom   }
 {      border of the frame is overwritten by a portion   }
 {      of said icon.                                     }
 { The call to ClipRect solves both:                      }
    ClipRect(lsMenuRect);
  { whichItem := 0; -- at beginning of WHILE WaitMouseUp DO }
    MenuDefGlue(mDrawMsg, theMenuBar^^.wMenus[i].mh, menuRect, startPt, 
whichItem);

    strayed := false;  { = Mouse on Menu Item OR on Menu }
      { title OR NOT on another Menu.   }
    WHILE WaitMouseup & NOT strayed DO   
  { While still selecting in this Menu ... }
    BEGIN
     GetMouse(startPt);
     lStartPt := startPt;
   { LocalToGlobal }
     SubPt(lScreen.topLeft, startPt);   
     MenuDefGlue(mChooseMsg, theMenuBar^^.wMenus[i].mh, menuRect, startPt, 
whichItem);

     IF whichItem <> 0 THEN              { Item is enabled. }
     BEGIN
      GetItemCmd(theMenuBar^^.wMenus[i].mh, whichItem, cmdChar);

      IF cmdChar = char(hMenuCmd) THEN   { a sub Menu ... }
      BEGIN
       IF aMac2 THEN
        parentMCTable := theMenuBar^^.wMCTable;
        hierPt := startPt;
        GetItemMark(theMenuBar^^.wMenus[i].mh, whichItem, itemMark);
        hierMenuHdl := GetMenu(ord(itemMark));
        wInsertMenu(theMenuBar, hierMenuHdl, hierMenu);
        DetachResource(Handle(hierMenuHdl));
        IF aMac2 THEN
        BEGIN
         hierMCTable := GetMCInfo;
         SetMCInfo(parentMCTable);
         theMenuBar^^.wMCTable := hierMCTable;
        END;   { IF aMac2 }
        hierSelect := wMenuSelect(theMenuBar, hierPt);
        wDeleteMenu(theMenuBar, ord(itemMark));
        ;
        whichMenu := HiWord(hierSelect);
        whichItem := LoWord(hierSelect);

        IF whichItem <> 0 THEN     
      { So a parent Menu Item does NOT blink: }
        BEGIN
         strayed := true;
         Leave;
        END;
       END

       ELSE  { a regular Menu }
        whichMenu := theMenuBar^^.wMenus[i].mh^^.menuID;

     END;   { enabled Item }

     strayed := NOT PtInRgn(lStartPt, theMenuBar^^.wMenus[i].menuParentRgn) 
& NOT PtInRect(lStartPt, lsTitleRect) & PtInRgn(lStartPt, theMenuBar^^.wMenus[i].cumParentRgn);
    END;   { WHILE WaitMouseup & NOT strayed }

    IF (whichItem <> 0) & NOT strayed THEN
     FOR blink := 1 TO menuFlashP^ DO
     BEGIN
      SetPt(NILPt, 0, 0);
      MenuDefGlue(mChooseMsg, theMenuBar^^.wMenus[i].mh, menuRect, NILPt, 
whichItem);
      Delay(flashDelay DIV 4, finalTicks);
      MenuDefGlue(mChooseMsg, theMenuBar^^.wMenus[i].mh, menuRect, startPt, 
whichItem);
      Delay(flashDelay DIV 4, finalTicks);
     END;   { blinking the selected item }

    ClipRect(menuFrameRect);
    BackColor(whiteColor);
    ForeColor(blackColor);
{ Blit back original screen image.  For a Hierarchical menu }
{ item, the off-screen bitMap/pixMap will include a part of }
{ the inverted parent item.  Therefore, we must first blit  }
{ back and THEN re-invert !!!                              }
    CopyBits(MenuDownOSHdl^^.offBitMapPtr^, thePort^.portBits, menuFrameRect, 
menuFrameRect, srcCopy, NIL);

  { Un-hilite the title: }
    IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
     wHiliteMenu(theMenuBar, 0)
    ELSE IF aMac2 THEN
   { i = Hierarchical Menu # }
     RedrawParentItem(theMenuBar, i)   
    ELSE
    BEGIN
     ClipRect(lsTitleRect);
     InvertRect(lsTitleRect);
    END;

    IF aMac2 THEN
     CloseCPort(onCScreenPtr)
    ELSE
     ClosePort(onBWScreenPtr);

    SetPort(theMenuBar^^.wp);
  { Original menuFrameRect in window coordinates: }
    ValidRect(MenuDownOSHdl^^.drawingRect);
    DisposOffScreen(MenuDownOSHdl);

    DisposeRgn(theMenuBar^^.wMenus[i].menuParentRgn);
    DisposeRgn(theMenuBar^^.wMenus[i].cumParentRgn);
    longPtr(TopMenuItemLoc)^ := saveScrollInfo;
    IF theMenuBar^^.wMenus[i].menuType = hierMenu THEN
     Leave;

   END   { IF i >= 0 }

   ELSE   { User is not over a Menu. }
    ;
100:
   GetMouse(startPt);
   LocalToGlobal(startPt);

  END;   { WHILE WaitMouseUp }

  IF whichItem = 0 THEN
   wMenuSelect := 0
  ELSE
   wMenuSelect := BitShift(whichMenu, 16) + whichItem;
200:
  IF aMac2 THEN
  BEGIN
   RGBBackColor(oldBackColor);     { “SetColors” is local }
   RGBForeColor(oldForeColor);     {   due to recursion.  }
   SetMCInfo(origMCTable);
  END;   { aMac2 }
  ;
  SetClip(oldClip);
  DisposeRgn(oldClip);
  SetPort(oldPort);

 END;   { wMenuSelect }

There’s nothing super different in wMenuKey from Jim Matthews’ code except I utilized GetItemCmd to shorten it a tad.

{25}

 FUNCTION wMenuKey (theMenuBar: wMenuBarHandle; ch: char): LONGINT;

  VAR
   i, j, whichMenu, whichItem: INTEGER;
   found, enabled: BOOLEAN;
   cmdChar: char;


  FUNCTION equalChars (c1, c2: char): BOOLEAN;
  { Filter out difference between UPPER and lower case: }

  BEGIN
   IF c1 IN [‘a’..’z’] THEN
    c1 := char(ord(c1) + ord(‘A’) - ord(‘a’));
   IF c2 IN [‘a’..’z’] THEN
    c2 := char(ord(c2) + ord(‘A’) - ord(‘a’));
   equalChars := (c1 = c2);
  END;   { equalChars }


 BEGIN   { wMenuKey }

  mbHState := HGetState(Handle(theMenuBar));
  MoveHHi(Handle(theMenuBar));
  HLock(Handle(theMenuBar));

  found := false;
  i := 0;

  WITH theMenuBar^^ DO
  BEGIN

   WHILE (NOT found) & (i < numMenus) DO
   BEGIN

    WITH wMenus[i] DO
     FOR j := 1 TO CountMItems(mh) DO
     BEGIN

      GetItemCmd(mh, j, cmdChar);
      IF equalChars(cmdChar, ch) THEN
      BEGIN
       found := true;
       whichMenu := mh^^.menuID;
       whichItem := j;
       Leave;   { FOR loop }
      END;   { IF equalChars }

     END;   { FOR scanning each individual Menu & }
             {   WITH wMenus[i]                    }
    i := i + 1;         { IF found, i = correct # plus 1. }

   END;   { WHILE scanning each whole Menu }

   IF found THEN
   BEGIN
 { The Item is enabled if both it AND }
 { its Menu title are enabled:        }
    IF j < 32 THEN
     enabled := BitTst(@wMenus[i - 1].mh^^.enableFlags, menuTitleBit 
- j)
    ELSE
     enabled := true;                { Items 32 & beyond. }
    enabled := enabled & BitTst(@wMenus[i - 1].mh^^.enableFlags, menuTitleBit);
   END;   { IF found }

  END;   { WITH theMenuBar^^ }

  HSetState(Handle(theMenuBar), mbHState);

  IF found & enabled THEN
  BEGIN
   wHiliteMenu(theMenuBar, whichMenu);
   Delay(flashDelay, finalTicks);
   wHiliteMenu(theMenuBar, 0);
   wMenuKey := BitShift(whichMenu, 16) + whichItem;
  END   { IF found & enabled }
  ELSE
   wMenuKey := 0;

 END;   { wMenuKey }

The prolific comments tell the whole gory story ...

{26}

 PROCEDURE wHiliteMenu (theMenuBar: wMenuBarHandle; menuID: INTEGER);
{ NOTE that this PROC is used only for a regular Menu item. }
{ Apple’s MenuDefProc handles a hierarchical Menu item.     }
{ For a regular Menu item, we invert the portion of the     }
{ titleRect that is both totally visible on the screen and  }
{ between the two MSAs.                                     }

  CONST
 { What happened to a simple InvertRect ?!!? }
   HiliteMode = $938;

  VAR
   origPort: GrafPtr;
   origClip: RgnHandle;
   i: INTEGER;
   screenBounds, betweenMSAs, visAllTitles, visThisTitle, visString: 
Rect;
 { Gotta be local to avoid interference }
 { with the global = mbHState:          }
   lmbHState: SignedByte;       
   oldMCTable: MCTableHandle;   { Color stuff ... }
   oldForeColor, oldBackColor, hiliteForeColor, hiliteBackColor: RGBColor;
   oldTxSize, oldTxFont, oldTxMode: INTEGER;
   oldTxStyle: Style;

 BEGIN

{ Needed because wHiliteMenu is called with pressing }
{ a CMD-key whereupon a window may not be around.    }
  IF FrontWindow = NIL THEN
   EXIT(wHiliteMenu);

  lmbHState := HGetState(Handle(theMenuBar));
  IF NOT BitTst(@lmbHState, 0) THEN
  BEGIN
   MoveHHi(Handle(theMenuBar));
   HLock(Handle(theMenuBar));
  END;   { NOT already locked !! }

  WITH theMenuBar^^ DO
  BEGIN
   GetPort(origPort);
   SetPort(wp);
   origClip := NewRgn;
   GetClip(origClip);
   ;
 { Just as with wMenuSelect PROC because wMenuKey calls us.  }
   oldTxSize := thePort^.txSize;
   oldTxFont := thePort^.txFont;     
   oldTxStyle := thePort^.txFace;
   oldTxMode := thePort^.txMode;
   TextSize(sizeFont);
   TextFont(systemFont);
   TextFace([]);
   TextMode(srcOr);
   ;
   IF aMac2 THEN
   BEGIN
    GetForeColor(oldForeColor);
    GetBackColor(oldBackColor);
    oldMCTable := GetMCInfo;
    SetMCInfo(theMenuBar^^.wMCTable);
   END;

   screenBounds := gScreen;
   GlobalLocal(screenBounds);
   betweenMSAs := WBMrect;
 { ... or rightMSArect.left: }
   InsetRect(betweenMSAs, leftMSArect.right, 0);
   IF SectRect(screenBounds, betweenMSAs, visAllTitles) THEN
   BEGIN

  { Un-highlight previously highlighted Menu title by }
  { re-inverting it or re-drawing it if on a machine  }
  { with Color QuickDraw.  This is similiar to the    }
  { gyrations within Apple’s MenuDefProc.  The latter }
  { does NOT call _InverRect for a color Mac, but    }
  { rather _EraseRect followed by a redraw of the     }
  { Menu item.                                        }
    IF titleHilited <> noneHilited THEN
    BEGIN
     WITH wMenus[titleHilited], titleRect DO
     BEGIN
      IF SectRect(visAllTitles, titleRect, visThisTitle) THEN
      BEGIN     { ALWAYS true if hilited. }
       ClipRect(visThisTitle);
       IF aMac2 THEN             { See wDrawMenuBar PROC. }
       BEGIN
        wSetColorMenu(mceMenuBar, mceMenuBar);
        EraseRect(visThisTitle);
        MoveTo(left + invertOverlap, bottom - (mBarHt - menuFrame - sizeFont) 
DIV 2);
        wSetColorMenu(mh^^.menuID, mceMenuTitle);
        DrawString(mh^^.menuData);
       END
       ELSE
        InvertRect(visThisTitle);
        ValidRect(visThisTitle);
      END;   { IF SectRect: visThisTitle NOT empty }
     END;   { WITH }
     ;
     titleHilited := noneHilited;   { So we don’t re-invert. }
    END;   { IF hilited }

    IF menuID <> 0 THEN
    BEGIN
     i := 0;
     WHILE (i < numMenus) & (wMenus[i].mh^^.menuID <> menuID) DO
      i := i + 1;

     IF i <> numMenus THEN
      WITH wMenus[i] DO
      BEGIN
       IF SectRect(visAllTitles, titleRect, visThisTitle) THEN
       BEGIN
       visString := visThisTitle;
       WITH visString DO
       BEGIN
       IF (leftMSArect.right > right - invertOverlap - 2 * menuFrame) 
| (screenBounds.left > right - invertOverlap - 2 * menuFrame) THEN
       right := right - invertOverlap - 2 * menuFrame;
       ;
       IF (rightMSArect.left < left + invertOverlap + 2 * menuFrame) 
| (screenBounds.right < left + invertOverlap + 2 * menuFrame) THEN
       left := left + invertOverlap + 2 * menuFrame;
       END;   { WITH visString }

       IF NOT EmptyRect(visString) THEN
       BEGIN
        ClipRect(visThisTitle);
        IF aMac2 THEN
        BEGIN
       { Text’s color becomes the background color and the  }
       { MenuBar’s background color becomes the foreground. }
         wSetColorMenu(menuID, mceMenuTitle);
         GetForeColor(hiliteBackColor);
         HiliteColor(hiliteBackColor);
         wSetColorMenu(mceMenuBar, mceMenuBar);
       { GetBackColor(hiliteForeColor); }
       { RGBBackColor(hiliteForeColor); }
         BitClr(Ptr(HiliteMode), pHiliteBit);
        END;   { on a color machine }
        InvertRect(visThisTitle);
        ValidRect(visThisTitle);
        ;
        titleHilited := i;
       END;   { visString NOT empty }
       END;   { IF SectRect: visThisTitle NOT empty }
      END;   { IF i <> numMenus & WITH }
    END   { IF menuID <> 0 }
    ELSE  { as in HiliteMenu(0). }
     ;    { Taken care of by IF titleHilited <> noneHilited }

   END;   { IF SectRect: visAllTitles NOT empty }

   IF aMac2 THEN
   BEGIN
    SetMCInfo(oldMCTable);
    RGBForeColor(oldForeColor);
    RGBBackColor(oldBackColor);
   END;
   ;
   TextSize(oldTxSize);
   TextFont(oldTxFont);
   TextFace(oldTxStyle);
   TextMode(oldTxMode);
   ;
   SetClip(origClip);
   DisposeRgn(origClip);
   SetPort(origPort);
  END;   { WITH theMenuBar^^ }

  HSetState(Handle(theMenuBar), lmbHState);

 END;   { wHiliteMenu }

Called in response to zooming & growing the window.

Note: NOT zooming = growing.

{27}

 PROCEDURE wChangeMenuBarSize (wp: WindowPtr; zooming: BOOLEAN);

 BEGIN

  mBar := wGetMenuBar(wp);
  ;
  IF mBar <> NIL THEN
  BEGIN        { Only a part of wClearMenuBar ... }
   GetWBMrects(wp, WBMrect, leftMSArect, rightMSArect);

   wHiliteMenu(mBar, 0);

   IF NOT zooming THEN  
  { doZoom calls InvalRect(wp^.portRect) }
    InvalRect(rightMSArect);

   IF mBar^^.rightScrollPoly <> NIL THEN
   BEGIN
    KillPoly(mBar^^.rightScrollPoly);
    mBar^^.rightScrollPoly := NIL;       { Mark as gone !! }
   END;

   IF zooming & (mBar^^.leftScrollPoly <> NIL) THEN
   BEGIN
    KillPoly(mBar^^.leftScrollPoly);
    mBar^^.leftScrollPoly := NIL;
   END;
  END;   { window has a WBM }

 END;   { wChangeMenuBarSize }

END.   { UNIT = wBarMenuProc }

Thank goodness it’s over ...

I lie ... even though I have NOT presented the source in “wBMBalloons.p” here, the application incorporates Balloon Help as in big System 7.0 ...and here’s a sneak preview ...

{28}
UNIT wBMBalloons;

INTERFACE

 USES
  Types, Quickdraw, Menus, TextEdit, Traps, GestaltEqu, Balloons, wBMGlobals, 
wBMMiscSubs, wBMScrollSubs;

 FUNCTION HelpManagerActive: BOOLEAN;
 FUNCTION BalloonsOn: BOOLEAN;
 FUNCTION BalloonShowing: BOOLEAN;
 PROCEDURE FindAndShowDynamicBalloons (balloonsUp: BOOLEAN; window: WindowPtr);
 PROCEDURE HideBalloons (balloonsUp: BOOLEAN);
 PROCEDURE ShowBalloons (balloonsUp: BOOLEAN);
 PROCEDURE ResetBalloons (balloonsUp: BOOLEAN);

NOW it’s over, really and truly ..

Well ... almost!!! What about AppleEvents? ... it’s on disk!!

{29}

UNIT myAppleEvents;

INTERFACE

 USES
 Types, Memory, OSUtils, Quickdraw, Events, Files, AppleTalk, PPCToolbox, 
Processes, EPPC, Notification, AppleEvents, Script, Packages, Dialogs, 
CTBUtilities, Connections, GestaltEqu, wBMGlobals, wBMMiscSubs;

 FUNCTION AppleEventsActive: BOOLEAN;
 FUNCTION PPCToolboxActive: BOOLEAN;
 FUNCTION DoAEOpenApplication (message: AppleEvent; reply: AppleEvent; 
refcon: LONGINT): OSErr;
 FUNCTION DoAEOpenDocuments (message: AppleEvent; reply: AppleEvent; 
refcon: LONGINT): OSerr;
 FUNCTION DoAEPrintDocuments (message: AppleEvent; reply: AppleEvent; 
refcon: LONGINT): OSErr;
 FUNCTION DoAEQuitApplication (message: AppleEvent; reply: AppleEvent; 
refcon: LONGINT): OSErr;
 FUNCTION InitAppleEvents: OSErr;
 FUNCTION MissedAnyParameters (VAR event: EventRecord; message: AppleEvent): 
BOOLEAN;
 PROCEDURE DoHighLevelEvent (event: EventRecord);

P.P.S The SARez resource code is on dis k too

SEE!!!

the little guy here this must prove I’m done -->

 
AAPL
$116.47
Apple Inc.
+0.16
MSFT
$47.98
Microsoft Corpora
-0.72
GOOG
$537.50
Google Inc.
+2.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

Cobook 3.0.7 - Intelligent address book....
Cobook Contacts is an intuitive, engaging address book. Solve the problem of contact management with Cobook Contacts and its simple interface and powerful syncing and integration possibilities.... Read more
StatsBar 1.9 - Monitor system processes...
StatsBar gives you a comprehensive and detailed analysis of the following areas of your Mac: CPU usage Memory usage Disk usage Network and bandwidth usage Battery power and health (MacBooks only)... Read more
Cyberduck 4.6 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Evernote 6.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 2.11 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital... Read more
Herald 5.0.1 - Notification plugin for M...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), and 4.0.8 (for OS X 10.9) are no longer supported by the developer. Herald is a notification plugin for Mail.app, Apple's Mac OS X email... Read more
Firetask 3.7 - Innovative task managemen...
Firetask uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask's "Today" view shows all relevant... Read more
TechTool Pro 7.0.6 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PhotoDesk 3.0.1 - Instagram client for p...
PhotoDesk lets you view, like, comment, and download Instagram pictures/videos! (NO Uploads! / Image Posting! Instagram forbids that! AND you *need* an *existing* Instagram account). But you can do... Read more

Latest Forum Discussions

See All

Ubisoft Gives Everyone Two New Ways to E...
Ubisoft Gives Everyone Two New Ways to Earn In-Game Stuff for Far Cry 4 Posted by Jessica Fisher on November 21st, 2014 [ permalink ] | Read more »
Golfinity – Tips, Tricks, Strategies, an...
Dig this: Would you like to know what we thought of being an infinite golfer? Check out our Golfinity review! Golfinity offers unlimited ways to test your skills at golf. Here are a few ways to make sure your score doesn’t get too high and your... | Read more »
Dark Hearts, The Sequel to Haunting Meli...
Dark Hearts, The Sequel to Haunting Melissa, is Available Now Posted by Jessica Fisher on November 21st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Meowza! Toyze Brings Talking Tom to Life...
Meowza! | Read more »
Square Enix Announces New Tactical RPG f...
Square Enix Announces New Tactical RPG for Mobile, Heavenstrike Rivals. Posted by Jessica Fisher on November 21st, 2014 [ permalink ] With their epic stories and gorgeous graphics, | Read more »
Quest for Revenge (Games)
Quest for Revenge 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: The great Kingdom of the west has fallen. The gods ignore the prayers of the desperate. A dark warlord has extinguished... | Read more »
Threadz is a New Writing Adventure for Y...
Threadz is a New Writing Adventure for You and Your Friends Posted by Jessica Fisher on November 21st, 2014 [ permalink ] In the tradition of round-robin storytelling, | Read more »
SteelSeries Stratus XL Hardware Review
Made by: SteelSeries Price: $59.99 Hardware/iOS Integration Rating: 4 out of 5 stars Usability Rating: 4.5 out of 5 stars Reuse Value Rating: 4.25 out of 5 stars Build Quality Rating: 4.5 out of 5 stars Overall Rating: 4.31 out of 5 stars | Read more »
ACDSee (Photography)
ACDSee 1.0.0 Device: iOS iPhone Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Capture, perfect, and share your photos with ACDSee. The ACDSee iPhone app combines an innovative camera, a powerful photo... | Read more »
ProTube for YouTube (Entertainment)
ProTube for YouTube 2.0.2 Device: iOS Universal Category: Entertainment Price: $1.99, Version: 2.0.2 (iTunes) Description: ProTube is the ultimate, fully featured YouTube app. With it's highly polished design, ProTube offers ad-free... | Read more »

Price Scanner via MacPrices.net

15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale today for $1749. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of Parallels Desktop... Read more
27-inch 3.5GHz 5K iMac in stock today and on...
 B&H Photo has the new 27″ 3.5GHz 5K iMac in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP, and it’s the lowest price available... Read more
21-inch 1.4GHz iMac on sale for $979, save $1...
B&H Photo has the new 21″ 1.4GHz iMac on sale for $979.99 including free shipping plus NY sales tax only. Their price is $120 off MSRP. B&H will also include free copies of Parallels Desktop... Read more
13-inch 1.4GHz/256GB MacBook Air on sale for...
B&H Photo has lowered their price on the 13″ 1.4GHz/256GB MacBook Air to $1059.99 including free shipping plus NY sales tax only. Their price is $140 off MSRP, and it’s the lowest price for this... Read more
Save up to $400 with Apple refurbished 2014 1...
The Apple Store has restocked Apple Certified Refurbished 2014 15″ Retina MacBook Pros for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and shipping... Read more
New 13-inch 1.4GHz MacBook Air on sale for $8...
 Adorama has the 2014 13″ 1.4GHz/128GB MacBook Air on sale for $899.99 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. B&H Photo has the 13″ 1.4GHz/128GB MacBook... Read more
Apple Expected to Reverse Nine-Month Tablet S...
Apple and Samsung combined accounted for 62 percent of the nearly 36 million branded tablets shipped in 3Q 2014, according to early vendor shipment share estimates from market intelligence firm ABI... Read more
Stratos: 30 Percent of US Smartphone Owners t...
Stratos, Inc., creator of the Bluetooth Connected Card Platform, has announced results from its 2014 Holiday Mobile Payments Survey. The consumer survey found that nearly one out of three (30 percent... Read more
2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has lowered their price on the new 1.4GHz Mac mini to $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Store Leader Program - College Gradu...
Job Description: Job Summary As an Apple Store Leader Program agent, you can continue your education as you major in the art of leadership at the Apple Store. You'll Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.