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 -->

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Go from lowly lizard to wicked Wyvern in...
Do you like questing, and do you like dragons? If not then boy is this not the announcement for you, as Loongcheer Game has unveiled Quest Dragon: Idle Mobile Game. Yes, it is amazing Square Enix hasn’t sued them for copyright infringement, but... | Read more »
Aether Gazer unveils Chapter 16 of its m...
After a bit of maintenance, Aether Gazer has released Chapter 16 of its main storyline, titled Night Parade of the Beasts. This big update brings a new character, a special outfit, some special limited-time events, and, of course, an engaging... | Read more »
Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »

Price Scanner via MacPrices.net

New today at Apple: Series 9 Watches availabl...
Apple is now offering Certified Refurbished Apple Watch Series 9 models on their online store for up to $80 off MSRP, starting at $339. Each Watch includes Apple’s standard one-year warranty, a new... Read more
The latest Apple iPhone deals from wireless c...
We’ve updated our iPhone Price Tracker with the latest carrier deals on Apple’s iPhone 15 family of smartphones as well as previous models including the iPhone 14, 13, 12, 11, and SE. Use our price... Read more
Boost Mobile will sell you an iPhone 11 for $...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering an iPhone 11 for $149.99 when purchased with their $40 Unlimited service plan (12GB of premium data). No trade-in is required... Read more
Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobile’s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Apple’s one-year warranty is... Read more
Updated Apple MacBook Price Trackers
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16″ and 14″ MacBook Pros along with 13″ and 15″ MacBook... Read more
Every model of Apple’s 13-inch M3 MacBook Air...
Best Buy has Apple 13″ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices are the lowest currently available for new 13″ M3 MacBook Airs among... Read more
Sunday Sale: Apple iPad Magic Keyboards for 1...
Walmart has Apple Magic Keyboards for 12.9″ iPad Pros, in Black, on sale for $150 off MSRP on their online store. Sale price for online orders only, in-store price may vary. Order online and choose... Read more
Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more

Jobs Board

DMR Technician - *Apple* /iOS Systems - Haml...
…relevant point-of-need technology self-help aids are available as appropriate. ** Apple Systems Administration** **:** Develops solutions for supporting, deploying, Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
IT Systems Engineer ( *Apple* Platforms) - S...
IT Systems Engineer ( Apple Platforms) at SpaceX Hawthorne, CA SpaceX was founded under the belief that a future where humanity is out exploring the stars is Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.