mdefproc.a

;EASE$$$ READ ONLY COPY of file ÒMdefProc.aÓ
; 1.6   PKE 08/22/1989 Rolling in from reality sources (YAY)
;<1.7>  PKE 08/21/1989 NEEDED FOR 6.0.4: (really dba) Fix bug in bug fix. GrayRect takes
;       its parameter in A0, so A0 must be set up with TempRect before calling
;       GrayRect. I tried to fix the earlier bug by not relying on A0 -- big mistake.
;       Instead, get TempRect into a0.
; 1.5   PKE 08/15/1989  Rolling in from Reality sources
;<1.6>  dba 08/15/1989  NEEDED FOR 6.0.4: fix bug in GetItemHeight where it relies
;       on GetIconSize not trashing A0
;<1.5>  RLC 08/10/1989 Changed selector message to Help Mgr Pack to MOVEQ
;       #select,D0
; 1.1   CCH 11/11/1988 Fixed Header.
; 1.0   CCH 11/ 9/1988 Adding to EASE.
; OLD REVISIONS BELOW
;¥1.3   EMT 10/3/88 Roll in latest bug fixes.
; END EASE MODIFICATION HISTORY 
;----------------------------------------------------------------
;   © Apple Computer, Inc.  1982, 1983, 1984, 1985, 1986, 1987, 1988
;   All Rights Reserved
;----------------------------------------------------------------
;File mDefProc.ASM
;------------------------------------------------------------
;
;   Standard Menu Definition Procedure for Text Menus
;
;   written by Andy Hertzfeld   July 1982
;
;   Here is the default menu definition procedure for text menus.  It knows how to
;   draw a text menu, or select from within a text menu.  It is always called from the
;   window manager port with clipping set to the menuRect. (Not CalcMenuSize)
;
; MODIFICATION HISTORY:
;   27-Dec-82   AJH Broke off into separate file for resources
;   28-Jan-83   AJH made "GrayRect" use FillRect and a hardwired gray
;   17-Mar-83   AJH Fixed 4 pixel choosing offset
;   17-Mar-83   AJH no more forcing bold
;   28-Apr-83   AJH added "calcMenuSize" message
;   30-Oct-83   AJH changed disabling
;   06-Nov-83   AJH back to old disabling; special-cased "-" item
;   13-Feb-84   AJH speeded up CalcMenuSize message (linear instead of N squared)
;   11-Jan-85   JTC convert to MDS
;   14-Feb-85   JTC named rsrc.
;   15-Feb-85   SC  fixed applemark/commandMark bug in command keys
;   10-Apr-85   EHB fixed CalcMenuSize for items with 0 length
;   29-Jul-85   EHB converted back to porkshop
;v3 01-Aug-85   EHB adapted for variable height system fonts
;v4 26-Aug-85   EHB ROM/Ram version (tests ROM85)
;v5 27-Sep-85   EHB Added International menu display.
;                   Added emergency menu scrolling.
;   30-Sep-85   EHB Made scrolling smoother.
;   11-Oct-85   EHB Do test byte of low memory justification word, so intl. people
;                   can use the high byte for further discrimination (yuck).
;   15-Oct-85   EHB Fixed bugs in display of menu icons
;
;------------------ Lonely Hearts ROMs ------------------------
;
;       Dec-85  EHB Different low memory locations if on old ROMs
;
; ----------------- System File 3.0 ---------------------------
;
;   07-Jan-86   EHB Fixed enable bug for items > 31 (see C466 below)
;   07-Jan-86   EHB Don't leave extra space at bottom of screen (reversed 30 Jan)
;   30-Jan-86   EHB Re-did scrolling so icons would work
;
;   01-Oct-86   DAF Changed include headers
;   30-Oct-86   FJL C222    Fixes for hierarchical menus
;   04-Nov-86   FJL CXXX    General clean up of menu manager.
;                           When #ScriptMenuCmd ($1C) in itemCmd field item
;                           to be printed in script whose ID is in the itemIcon field --
;                           also, command keys draw as cmdletter/cmdchar rather
;                           than normal cmdchar/cmdletter (for International).
;                           Also slow down scrolling.
;   08-Dec-86   FJL C408    Added color support
;   25-Nov-86   FJL C466    Fixed ENABLETEST (local label) so enables items > 31 unless whole
;                           menu disabled.
;   10-Feb-87   FJL C792    Add scrolling indicator to top and bottom of scrollable menus.
;   20-Feb-87   FJL C838    Sped up menu scrolling by an amazing amount.
;   20-Feb-87   FJL C844    New routine PopUpMenuSelect.
;   06-Mar-87   FJL         Clean up all OnNuMac conditionals for System Disk --> Universal defproc
;   09-Mar-87   FJL         Add variable speed menu scrolling
;   17-Mar-87   FJL         Do invert for MacPlus/MacSE rather than redraw (for MacDraw custom menu)
;                           when choosing item
;   30-Mar-87   FJL PMAB155 Don't reference MenuDisable in mdefproc.a on 64K ROMs.
;   08-Apr-87   DBG&JTC S171 Save D2 (volatile register) around call to CalcMenuSize in PopUpMenu
;                           message.
;   14-Apr-87   FJL PMAB177 Use CopyBits instead of CopyMask for drawing hierarchical and scrolling
;                           arrows.  Do moveq #BitMapRec, d0 instead of move.w #BitMapRec, d0
;                           before call to NewHandle.
;
;------------------------------- System 4.2 and beyond -----------------------------------
;
;   14-Jul-87   FJL PMAB205 Juggler support -- support shrunken and small icons
;   21-Aug-87   FJL PMAB239 Calculate menu width correctly when have shrunken or small icons
;   15-Sep-87   FJL PMAB276 Allow item = 0 to popupmenuselect
;   PMAB364 23Jan88 EMT     Fix Pop-up menus to come up on any screen
;   S394    12Feb88 DBG     Fixed errant branch, which was reversed, causing crash on +/SE
;   S422    08Mar88 MED     Fixed mdefproc.a to use SetScriptFont uniformally instead of inaccurate calculation
;   S476    22Apr88 EMT     Fixed hierchical menus being forced below menu bar
;   S550    27Jul88 EMT     Removed references to WMgrPort for ROM
;                           Fixed problems when teSysJust set for right-to-left drawing
;                           Treat dash as special only if no icon or cmd.  Primarily for MultiFinder
;                           Handle color icons other than 32x32
;                           And some miscellaneous code cleanup
;---------------------------------------------------------------
 
;
; PROCEDURE TextMenuProc(   message     :Integer,
;                           theMenu     :menuHandle,
;                       VAR menuRect    :Rect,
;                           hitPt       :Point,
;                       VAR whichItem   :Integer);
;
;Msg        theMenu     menuRect            hitPt       whichItem
;------     ----------- -----------         -------     -----------
; 0 Draw    handle      entry: ptr to       not used    not used
;                       return: no chg
; 1 Choose  handle      entry: ptr to       mouse pt    entry: ptr to currently selected item
;                       return: no chg                  return: newly selected item
; 2 Calc    handle      not used            not used    not used
; 3 PopUp   handle      entry: none         top/left    entry: CrsrItem to be placed at HitPt
;                       return: menu rect               return: TopMenuItem
 
            BLANKS      ON
            STRING      ASIS
 
;----------------------------------------------------------------------------------------
;
;   Conditional Definitions
;
;----------------------------------------------------------------------------------------
 
    IF (&TYPE('forTESTING') = 'UNDEFINED') THEN
forTESTING EQU 0
    ENDIF
 
    IF (&TYPE('forRAM') = 'UNDEFINED') THEN
forRAM EQU 0
    ENDIF
 
            INCLUDE 'inc.sum.a'
            LOAD    'nequ.d'
            INCLUDE 'colorequ.a'
 
    IF forTESTING THEN                          ; uggghhhlllyyy
            INCLUDE 'myEquates.a'
    ENDIF
 
 
ShrunkenIconCmd EQU     $1D                     ; itemCmd == $1D ==> large icon plotted in 16x16
SmallIconCmd    EQU     $1E                     ; itemCmd == $1E ==> small icon plotted
;----------------------------------------------------------------------------------------
;
;   StackFrame and Global Definitions
;
;----------------------------------------------------------------------------------------
 
MDEF0           PROC    EXPORT
 
;
; Stack Frame Definition for TextMenuProc
;
 
MFHeight        EQU     -2              ; <1Aug85> cell height
MWidMax         EQU     MFHeight - 2    ; <1Aug85>
MDescent        EQU     MWidMax - 2     ; <1Aug85>
MAscent         EQU     MDescent - 2    ; <1Aug85>
MInfoRec        EQU     MAscent         ; <1Aug85>
MSpaceWidth     EQU     MInfoRec - 2    ; <S550 27Jul88 EMT>
saveForeColor   EQU     MSpaceWidth - 6 ; <FJL C408>
saveBackColor   EQU     saveForeColor-6 ; <FJL C408>
pixelDepth      EQU     saveBackColor-2 ; <FJL C408>
colorOffset     EQU     pixelDepth - 2  ; <FJL C408>
invertFlag      EQU     colorOffset - 2 ; <FJL C408>    0 = normal item, 1 = inverted item
scrollFlag      EQU     invertFlag - 2  ; <FJL 17Mar87> 0 = scrolling item, 1 = choosing item
HItemFlag       EQU     scrollFlag - 2  ; <FJL 17Mar87> 0 = no sub menu, 1 = item has submenu
iconHandle      EQU     HItemFlag - 4   ; <FJL C408>
HierArrowRect   EQU     iconHandle - 8  ; <FJL 25Jan87>
OrigMenuRect    EQU     HierArrowRect-8 ; <FJL C792>
ScrollSpeed     EQU     OrigMenuRect - 4; <FJL 09Mar87>
SlowPixels      EQU     ScrollSpeed - 2 ; <FJL 09Mar87>
onColorMachine  EQU     SlowPixels-2    ; <FJL 06Mar87>
lastItemStrPtr  EQU     onColorMachine-4    ; <KSM/RLC  31May89>
lastAttrPtr     EQU     lastItemStrPtr-4    ; <KSM/RLC  31May89>
LinkSize        EQU     lastAttrPtr     ; <FJL C792>
 
 
MWHICHITEM      EQU     8
MPopUpItem      EQU     MWhichItem      ; <FJL C844>
 
MPOINT          EQU     MWHICHITEM+4
MLeftTop        EQU     MPoint          ; <FJL C844>
 
MMENURECT       EQU     MPOINT+4
MMENUHANDLE     EQU     MMENURECT+4
MMESSAGE        EQU     MMENUHANDLE+4
 
FastSpeed       EQU     0
SlowSpeed       EQU     10
 
FirstMDMsg      EQU     0               ; first message
LastMDMsg       EQU     3               ; last message
 
 
;----------------------------------------------------------------------------------------
;
;   Start of Code -- save work registers and dispatch on message number
;
;----------------------------------------------------------------------------------------
 
            BRA.S   StartMDEF
 
; Standard Header
 
            DC.W    0                   ; flags word
            DC.B    'MDEF'              ; type
            DC.W    0                   ; ID
            DC.W    12                  ; version 4 = MacPlus
                                        ; version 5 = Alladin
                                        ; version 6 = onNuMac ROM
                                        ; version 10= Universal
                                        ; version 11= Universal 4.2                 <FJL PMAB205>
                                        ; version 12= Universal 6.0                 <PMAB364    23Jan88 EMT>
 
StartMDEF
            LINK    A6,#LinkSize        ; set up a stack frame                      <1Aug85>
            MOVEM.L D3-D7/A2-A4,-(SP)   ; save a whole bunch of work registers
 
            MOVE.L  MMENUHANDLE(A6),A3  ; keep menuHandle in A3
            move.l  a3, a0              ;                                           <FJL 27Jan87>
            _HLock                      ; lock it down
            clr     invertFlag(a6)      ; most drawing done in normal (not inverted) mode <FJL C408>
            clr     scrollFlag(a6)      ; only set this flag when call InvertItem   <FJL 17Mar87>
                                        ; while scrolling
            clr     onColorMachine(a6)  ; clear color machine flag                  <FJL 06Mar87>
            cmpi.w  #$3FFF, ROM85       ; color machine ?
            sls     onColorMachine(a6)  ; set byte to 1's if yes
 
            lea     GoMdefProc, a0      ; get the dispatch table base               <FJL>
            move.w  mMessage(a6), d0    ; get the message type
 
            cmpi    #LastMDMsg, d0      ; is the message within bounds?             <FJL>
            bhi.s   @InvalidMsg         ; oops, its too high
            cmpi    #FirstMDMsg, d0     ;
            blo.s   @InvalidMsg         ; oops, its too low
 
            add.w   d0, d0              ; double to get words
            add.w   GoMdefProc(d0), a0  ; compute the dispatch address
 
            jsr     (a0)                ; and dispatch
 
@InvalidMsg
            move.l  a3, a0              ; get menuHandle
            _HUnlock                    ; and unlock it before we leave
            MOVEM.L (SP)+,D3-D7/A2-A4   ; restore work registers
            UNLK    A6                  ; unbuild the stack frame
 
            MOVE.L  (SP)+,A0            ; get return address
            ADD     #18,SP              ; strip parameters
            JMP     (A0)                ; return to caller
 
; Dispatch Table
 
GoMdefProc      dc.w    DoDrawMsg-GoMdefProc            ; draw is message           #0
                dc.w    DoChooseMsg-GoMdefProc          ; choose menu size is msg   #1
                dc.w    DoCalcMsg-GoMdefProc            ; calc menu is msg          #2
                dc.w    DoPopUpItemMsg-GoMdefProc       ; calc top of popup item    #3
 
;********************************************************************************************
;*                                                                                          *
;* IF YOU ADD ANOTHER MESSAGE YOU MUST UPDATE THE VARIABLE "LastMDMsg" FOUND ABOVE !!!!!!   *
;*                                                                                          *
;********************************************************************************************
 
;----------------------------------------------------------------------------------------
;
;   Msg #1 -- Choose -- examine the mouse position and hilite the appropriate item
;
;----------------------------------------------------------------------------------------
 
DoChooseMsg
 
;
; --------------------------    DO SETUP STUFF  ---------------------------
;
            bsr     GetSizes            ; get font info into stackframe
 
            MOVE.L  MWHICHITEM(A6),A4   ; get pointer to whichItem
            MOVE.W  (A4),D3             ; remember oldWhichItem
            CLR     (A4)                ; set whichItem to zero
            MOVE.L  MMENURECT(A6),A2    ; get the menu rect                         <27Sep85>
                                        ; store original menurect in the stackframe <FJL C792>
            move.l  Top(a2), OrigMenuRect+Top(a6)
            move.l  Bottom(a2), OrigMenuRect+Bottom(a6)
            move.l  #FastSpeed, ScrollSpeed(a6) ; assume fast-speed                 <FJL 09Mar87>
            move    MFHeight(a6), d0    ; get height of scroll arrow                <FJL 09Mar87>
            asr     #1, d0              ; num pixels for slow scroll = height/2     <FJL 09Mar87>
            move    d0, SlowPixels(a6)
 
            clr     HItemFlag(a6)       ; assume "old" item has no submenu          <FJL 17Mar87>
            move    d3, d0              ; get item
            move.l  (a3),a0             ; get menuPtr
            bsr     GetItemRecord       ; look it up
            cmp.b   #HMenuCmd, ItemCmd(a1)  ; does item have sub-menu?
            bne.s   @NoSubMenu          ; no    ==> leave flag cleared
            move    #1, HItemFlag(a6)   ; yes ==> set flag
 
@NoSubMenu  MOVE.W  TopMenuItem,D4      ; get top of (scrolled) menu            <30Jan86>
            MOVE.L  MPOINT(A6),D5       ; get the mouse point                   <27Sep85>
            BEQ     NOITEMSEL           ; => special case for flashing          <27Sep85>
 
;
; -------------------   ADJUST MENURECT BASED ON SCROLLING ARROWS   ----------------
;
            move    AtMenuBottom, d0    ; check for down scrolling arrow            <FJL C792>
            cmp     Bottom(a2), d0      ; is AtMenuBottom > bottom of menu rect ?
            ble.s   @NoScroll           ; no, so chk top
            move    MFHeight(a6), d0    ; yes, so make menuRect smaller by down scrolling arrow rect
            sub     d0, Bottom(a2)
@NoScroll
            move    TopMenuItem, d0     ; check for up scrolling arrow
            cmp     Top(a2), d0         ; is TopMenuItem < top of menu rect ?
            bge.s   @NoScroll2          ; no, so just do PtInRect
            move    MFHeight(a6), d0    ; yes, so make menuRect smaller by up scrolling arrow rect
            add     d0, Top(a2)
@NoScroll2
;
; If the point isn't in the adjusted menuRect, check for autoscrolling
;
            CLR.W   -(SP)               ; make room for PtInRect result
            MOVE.L  D5,-(SP)            ; push the point
            MOVE.L  A2,-(SP)            ; push the rect
            _PtInRect                   ; test if the point is in the rect
            TST.B   (SP)+               ; was it?
            BNE     @3                  ; => yes, go select something
 
;-----------------------    CHECK FOR AUTOSCROLLING DOWN    -------------------------------
;
; Only scroll if mouse pt directly above/below menu.  This allows
; hierarchical menus to work properly -- scroll when mouse above/below menu,
; -- return to a previous menu if outside of the scrolling rectangles.
;
 
            cmp     left(a2), d5        ; to left of menu's left side?          <FJL C222>
            blt     NoItemSel           ; yes, so no item selected              <FJL C222>
            cmp     right(a2), d5       ; to right of menu's right side?        <FJL C222>
            bgt     NoItemSel           ; yes, so no item selected              <FJL C222>
 
            MOVE.W  MFHeight(A6),D7     ; get distance for scroll                   <30Sep85>
            SWAP    D5                  ; get mouse.v into low word                 <27Sep85>
            CMP.W   top(A2),D5          ; above top?                                <27Sep85>
            BGE     @2                  ; => no, check bottom                       <27Sep85>
            ADD.W   D7,D4               ; try to go up an item                      <27Sep85>
            CMP.W   top(A2),D4          ; menu top must be <= to MenuRect.Top       <30Jan86>
            BGT     NOITEMSEL           ; => can't go up                            <27Sep85>
 
                                        ; how far is mouse into scrolling arrow?    <FJL 09Mar87>
            move    top(a2), d0         ; get top of menu into d0                   <FJL 09Mar87>
            sub     d5, d0              ; subtract mouse.v                          <FJL 09Mar87>
            cmp     SlowPixels(a6), d0  ; is it more than slow num ?                <FJL 09Mar87>
            bgt.s   @ContDown                   ; yes ==> do it fast                <FJL 09Mar87>
            move.l  #SlowSpeed, ScrollSpeed(a6) ; no    ==> do it slow              <FJL 09Mar87>
 
@ContDown
;+++            move    AtMenuBottom, d0    ;                                       <FJL C792>
;+++            cmp     Bottom(a2), d0      ; is AtMenuBottom<> bottom of menu?
;+++            bne.s   @1                  ; yes, so just do scrolling
 
            move    AtMenuBottom, D0    ;                                           <FJL PMAB205>
            cmp     Bottom(A2), D0      ; is AtMenuBottom > bottom of menu ?
            bgt.s   @1                  ; yes -> no scrolling arrow needed
            add     MFHeight(a6), d0
            cmp     Bottom(A2), D0      ; is AtMenuBottom+scrollamt > bottom of menu ?  <FJL PMAB276>
            ble.s   @1                  ; yes -> no scrolling arrow needed              <FJL PMAB276>
 
; If we get here then we are scrolling down and the last item is showing.  Therefore
; we want to draw the down scroll arrow before scrolling.
 
            move.l  a2, a0              ; BlitScrollIndic expects menuRect ptr in A0
            bsr     BlitDownScrollIndic
            move    MFHeight(a6), d0    ; move bottom of menuRect up so arrow doesn't get scrolled
            sub     d0, Bottom(a2)      ; and fall into scrolling code
 
;-----------------------    DO THE AUTOSCROLLING    --------------------------------------
 
@1
            MOVE.W  D3,D0               ; get the current selection             <30Sep85>
            BSR InvertItem              ; and deselect it                       <30Sep85>
 
; When a HMenu is up and the item with the HMenu is the topmost or bottommost item
; garbage is left on the screen unless we bring down the HMenu first.
; Solution: 1) Don't scroll if an HMenu is up.
;           2) DrawMenu clears a flag in mbSaveLoc every time a menu is drawn.
;           3) If that flag is clear, then we set the flag and skip scrolling.
;               This gives MenuSelect a chance to bring down the HMenu before
;               the MDEF is called again.
;           4) If the flag is set, then it is okay to scroll.
 
;>>>>>------------- MacPlus/MacSE patches ------------------>>>>>
 
        IF forRAM THEN
 
            cmp.w       #$FFFF, ROM85           ; on old Mac or MacXL?
            beq.s       @OkToScroll             ; yes -> skip HMenu specific stuff
 
                                                ; RADIUS patches out complete menu mgr ==> could
                                                ;   have GetItemCmd installed, but mbSaveLoc
                                                ;   not initialized.
            cmpi.l      #$FFFFFFFF, mbSaveLoc   ; has the MBDF data structure been initialized?
            beq.s       @OkToScroll
 
            move.w      #$009F, d0              ; load _Unimplemented number
            _GetTrapAddress                     ; load _Unimplemented address
            move.l      a0, d1                  ; copy routine address
            move.w      #$004E, d0              ; load _GetItemCmd number
            _GetTrapAddress ,newTool            ; load _GetItemCmd address
            cmp.l       a0, d1                  ; new HMenu Mgr installed?
            beq.s       @OkToScroll             ; no -> skip HMenu specific stuff
 
        ENDIF   ; if forRAM
 
;<<<<<--------------------------------------<<<<<
 
            move.l  mbSaveLoc, a0       ; get mbUglyScroll in mbSaveLoc
            move.l  (a0), a0
            tst     mbUglyScroll(a0)    ; is mbUglyScroll set ?
            bne.s   @OkToScroll         ; yes, so HMenu was already brought down
            move    #1, mbUglyScroll(a0); no, so set field
            bra.s   @DoneScroll         ; and skip scrolling this time through
 
@OkToScroll
            MOVE.W  D4,topMenuItem      ; stuff new topItem                     <27Sep85>
 
            CLR.L   -(SP)               ; room for region #1                    <30Sep85>
            _NewRgn                     ; get it                                <30Sep85>
            MOVE.L  (SP),D6             ; save in D6                            <30Jan86>
            CLR.L   -(SP)               ; room for region #2                    <30Jan86>
            _NewRgn                     ; get it                                <30Jan86>
 
            bsr     SaveCurrentColors   ; save current colors in stack frame            <FJL C408>
            move    #mctRGB2, colorOffset(a6)   ; this offset is unimportant here       <FJL C408>
                                                ; since all we care about is bkgd color <FJL C408>
            bsr     SetColors           ; set proper colors for ScrollRect              <FJL C408>
;
; Delay depending on how far cursor is into the scroll arrow.                           <FJL 09Mar87>
;
            bsr     DoScrollWait
 
@DoTheScroll
            MOVE.L  A2,-(SP)            ; push rect                             <27Sep85>
            CLR.W   -(SP)               ; dh = 0                                <30Sep85>
            MOVE.W  D7,-(SP)            ; dv = itemHeight                       <30Sep85>
            MOVE.L  D6,-(SP)            ; push update region
            _ScrollRect                 ; scroll the menu                       <30Sep85>
 
            bsr     ChkScrollArrows     ; chk if scrolling arrows should still be up    <FJL C792>
            bsr     ResetPreviousColors ; reset colors stored in stackframe             <FJL C408>
 
            MOVE.L  (SP),-(SP)          ; point to region #2                    <30Jan86>
            _GetClip                    ; save the clip in it                   <30Jan86>
            MOVE.L  D6,-(SP)            ; point to update region                <30Jan86>
            _SetClip                    ; set clip to it                        <30Jan86>
 
            BSR     DrawScrolledItem    ; call fast routine to draw item        <FJL C838>
            ADD     D7, AtMenuBottom    ; update new menu bottom                <FJL C838>
 
            MOVE.L  (SP),-(SP)          ; point to saved clip                   <30Jan86>
            _SetClip                    ; and restore it                        <30Jan86>
            _DisposRgn                  ; dispose of region #2                  <30Jan86>
            _DisposRgn                  ; dispose of region #1                  <30Jan86>
 
;
; When scrolling, no item is selected, so clear the Item in MenuDisable global  <FJL C792>
;
@DoneScroll
 
        IF forRAM THEN
 
            tst.w   ROM85               ; on old Mac or MacXL?
            bmi.s   @NoMenuDisable      ; yes -> MenuDisable is not available in low-memory , so skip
 
        ENDIF   ;forRAM
 
            clr     MenuDisable+2       ; clear Item only, not ID
 
@NoMenuDisable
            BRA     DoChooseDone        ; and return                            <27Sep85>
 
 
;-----------------------    CHECK FOR AUTOSCROLLING UP  ----------------------------------
 
@2          MOVE.W  bottom(A2),D0       ; get bottom                            <30Jan86>
            CMP.W   D0,D5               ; below bottom?                         <30Jan86>
            BLT     NOITEMSEL           ; => no                                 <27Sep85>
            CMP.W   atMenuBottom,D0 ; done scrolling?                           <30Jan86>
            BGE     NOITEMSEL           ; => yes, nothing below us              <30Jan86>
            NEG.W   D7                  ; change direction of scroll            <30Sep85>
            ADD.W   D7,D4               ; else scroll down                      <27Sep85>
 
                                        ; how far is mouse into scrolling arrow?<FJL 09Mar87>
            move    d5, d0              ; get mouse.v into d0                   <FJL 09Mar87>
            sub     bottom(a2), d0      ; subtract bottom of menu               <FJL 09Mar87>
            cmp     SlowPixels(a6), d0  ; is it more than slow num ?            <FJL 09Mar87>
            bgt.s   @ContUp                     ; yes ==> do it fast            <FJL 09Mar87>
            move.l  #SlowSpeed, ScrollSpeed(a6) ; no    ==> do it slow          <FJL 09Mar87>
 
@ContUp
            move    TopMenuItem, d0     ;                                       <FJL C792>
            cmp     Top(a2), d0         ; is TopMenuItem <> top of menu rect ?
            bne     @1                  ; yes, so just do scrolling
 
; If we get here then we are scrolling up and the first item is showing.  Therefore
; we want to draw the up scroll arrow before scrolling.
 
            move.l  a2, a0              ; BlitScrollIndic expects menuRect ptr in A0
            bsr     BlitUpScrollIndic
            move    MFHeight(a6), d0    ; move top of menuRect up so arrow doesn't get scrolled
            add     d0, Top(a2)         ; and fall into scrolling code
            bra     @1
 
;--------------------------------   DO THE CHOOSE   ------------------------------------
 
; the point is in the menu, so waltz through the itemList keeping track of vertical
; position seeing which item it's in.  In the following loop, D4 holds the item number
; while D2 has the cumulative vertical space
;
@3
;
; With popup menus it is possible to have the mouse pt above TopMenuItem            <FJL 22Mar87>
; but no down-scrolling taking place because TopMenuItem may be below top
; of the menuRect.  "Choose" must recognize this case and branch to NoItemSel.
;
            CMP     Top(a2), D4         ; is TopMenuItem > top of menuRect ?
            BLE.S   @DoChoose           ; no    ==> ok to choose
            CMP     MPoint+V(a6), D4    ; yes ==> is TopMenuItem > mouse pt ?
            BGT.S   NoItemSel           ; yes ==> no choice
 
@DoChoose   MOVE.W  D4,D2               ; top of menu into D2                       <30Jan86>
            MOVEQ   #1,D4               ; start with first item                     <30Jan86>
 
MSELOOP     MOVE.L  (A3),A0             ; get menuPtr
            MOVE    D4,D0               ; get item number
            BSR     GETITEMRECORD       ; look it up
            BEQ.S   NOITEMSEL           ; if so, nothing selected
 
            BSR     GetItemHeight       ; get item height in D0                     <1Aug85>
            ADD     D0,D2               ; update vertical                           <1Aug85>
            CMP     MPOINT+V(A6),D2     ; compare with mouse point
            BGT.S   GOTSEL              ; when D2 is bigger, we found it
;
; we didn't reach it yet, so keep stepping down till we do
;
NEXTMSEL    ADDQ    #1,D4               ; bump to next item
            BRA.S   MSELOOP             ; loop till we find it
;
; we found it so update whichItem.  First we better make sure it's enabled
 
GOTSEL
;
; put item rect in mbSaveLoc so MenuSelect has it to do Hierarchical menu drag      <FJL C222>
; must store this regardless of whether item changed (consider case where an item
; has a HMenu and you move to the HMenu, and then back into the item with that HMenu).
;
            LEA     TEMPRECT,A0         ; get pointer to temporary rectangle
            MOVE.L  MMENURECT(A6),A1    ; point to menuRect
            MOVE.L  (A1)+,(A0)          ; copy menuRect into tempRect
            MOVE.L  (A1),4(A0)
            MOVE    D2,BOTTOM(A0)       ; D2 has the bottom coordinate
            SUB     D0,D2               ; subtract the height
            MOVE    D2,TOP(A0)          ; set up the top
 
;>>>>>------------- MacPlus/MacSE patches ------------------>>>>>
 
        IF forRAM THEN
 
            cmp.w       #$FFFF, ROM85           ; on old Mac or MacXL?
            beq.s       @SkipRectStore          ; yes -> skip HMenu specific stuff
 
                                                ; RADIUS patches out complete menu mgr ==> could
                                                ; have GetItemCmd installed, but mbSaveLoc
                                                ; not initialized.
            cmpi.l      #$FFFFFFFF, mbSaveLoc   ; has the MBDF data structure been initialized?
            beq.s       @SkipRectStore
 
            move.w      #$009F, d0              ; load _Unimplemented number
            _GetTrapAddress                     ; load _Unimplemented address
            move.l      a0, d1                  ; copy routine address
            move.w      #$004E, d0              ; load _GetItemCmd number
            _GetTrapAddress ,newTool            ; load _GetItemCmd address
            cmp.l       a0, d1                  ; new HMenu Mgr installed?
            beq.s       @SkipRectStore          ; no -> skip HMenu specific stuff
 
        ENDIF   ; if forRAM
 
;<<<<<--------------------------------------<<<<<
            move.l  mbSaveLoc, a0                   ; get handle to save loc
            move.l  (a0), a0                        ; dereference
            move.l  TempRect, mbItemRect(a0)        ; save top, left
            move.l  TempRect+4, mbItemRect+4(a0)    ; save bottom, right
 
@SkipRectStore
            BSR     ENABLETEST          ; make sure whole menu is enabled
            BEQ.S   DoInverting         ; if not, no selection
            MOVE    D4,(A4)             ; menu is enabled, so store item
            bra.s   DoInverting         ; and continue
 
;
; At this label the mouse is not in any item, so clear d4 so we return the          <FJL C531>
; correct value in low-memory MenuDisable.  Can only reach here by a branch.
;
NOITEMSEL   clr     d4                  ; at this label no item selected
 
;
; see if whichItem changed; if it has, unselect the old item and select the new one
;
DoInverting
            CMP     (A4),D3             ; have they changed?
            BEQ.S   GetDisabledItem     ; if not, we're all done, no hiliting change
 
 
            MOVE    D3,D0               ; unhilite old item
            BSR     INVERTITEM          ;
            MOVE    (A4),D0             ; hilite new item
            not     invertFlag(a6)      ; tell InvertItem to draw in reverse colors     <FJL C408>
            BSR     INVERTITEM          ;
            clr     invertFlag(a6)      ; reset invertFlag                              <FJL C408>
 
;
; "User ed" requested that apps be able to find out if a disabled menu item was chosen. <FJL C531>
; We return the ID and item in the global MenuDisable.  If the item is zero then        <FJL C531>
; no item was chosen (i.e. the mouse was outside the menu), or was in the title.        <FJL C531>
;
GetDisabledItem
 
            move.l  (a3), a0            ; get menu ptr
            swap    d4                  ; put item in hi-byte
            move    menuID(a0), d4      ; put menuID in lo-byte
            swap    d4                  ; restore d4
 
        IF forRAM THEN
 
            tst.w   ROM85               ; on old Mac or MacXL?
            bmi.s   @NoMenuDisable      ; yes -> MenuDisable is not available in low-memory , so skip
 
        ENDIF   ;forRAM
 
            move.l      d4, MenuDisable ; put in low-memory where apps can query it if they want
 
@NoMenuDisable
 
DoChooseDone
            move.l  OrigMenuRect(a6), Top(a2)   ; reset menuRect in case we changed it<FJL C792>
            move.l  OrigMenuRect+Bottom(a6), Bottom(a2)
 
            rts                         ; return to dispatcher
            
 
;-------------------------------    DONE CHOOSE MSG ------------------------------------
 
;---------------------------------------
;   Utility -- DoScrollWait                                                         <FJL 09Mar87>
;---------------------------------------
;
; Delay for ScrollSpeed ticks.  If cursor moves out of slow scroll area then leave wait loop.
;
DoScrollWait
            tst.l   ScrollSpeed(a6)     ; how fast should we scroll?
            beq.s   @NoWait             ; zero means fast as possible
 
            move.l  d3, -(sp)           ; save temp reg on the stack
            subq    #4, sp              ; space for result
            _TickCount                  ; get current tick count
            move.l  (sp)+, d3
            add.l   ScrollSpeed(a6), d3 ; we want to wait until tick count in d3
 
@Loop       subq    #4, sp              ; space for VAR parameter
            move.l  sp, -(sp)           ; push address of parameter
            _GetMouse
            move.l  (sp)+, d5           ; get mouse pt
            swap    d5                  ; get .v into lo-word
 
            tst     d7
            bge.s   @ScrollingDown
                                        ; how far is mouse into scrolling arrow?    <FJL 09Mar87>
            move    d5, d0              ; get mouse.v into d0                       <FJL 09Mar87>
            sub     bottom(a2), d0      ; subtract bottom of menu                   <FJL 09Mar87>
            cmp     SlowPixels(a6), d0  ; is it more than slow num ?                <FJL 09Mar87>
            bgt.s   @DoneWait           ; yes   ==> do it fast ==> stop waiting     <FJL 09Mar87>
            bra.s   @ContLoop
 
@ScrollingDown                          ; how far is mouse into scrolling arrow?
            move    top(a2), d0         ; get top of menu into d0
            sub     d5, d0              ; subtract mouse.v
            cmp     SlowPixels(a6), d0  ; is it more than slow num ?
            bgt.s   @DoneWait           ; yes ==> do it fast ==> stop waiting
@ContLoop
            subq    #4, sp              ; space for result
            _TickCount
            cmp.l   (sp)+, d3           ; reached desired tick count yet?
            bgt.s   @Loop               ; no    ==> keep looping
                                        ; yes ==> we're done waiting
@DoneWait
            move.l  (sp)+, d3           ; restore work register
@NoWait
            rts
 
;---------------------------------------
;   Utility -- ChkScrollArrows
;---------------------------------------
; if scrolling up, and if last item is appearing, then lower clip by height of      <FJL C792>
; rectangle containing indicator arrow, and erase arrow rectangle.
ChkScrollArrows
 
            tst     d7
            bge.s   @ChkScrollDown      ; if D7 >= 0 then scrolling down not up
            move    d7, d0              ; get amount of scroll
            neg     d0                  ; take negative since to make it positive
            add     MFHeight(a6), d0    ; add in height of scroll arrow
            add     Bottom(a2), d0      ; add to bottom of menuRect
            cmp     AtMenuBottom, d0    ; is new bottom of menuRect >= AtMenuBottom
            blt.s   @NotLastItem        ; no ==> not showing last item
 
; last item is being drawn -> open clip so scroll arrow gets erased and last item gets drawn <FJL C792>
 
            move.l  d6, a0              ; change the bottom of the update region
            move.l  (a0), a0            ; get ptr to rgn
            move    MFHeight(a6), d0    ; get menu item height
            add     d0, 2+Bottom(a0)    ; Bottom = Bottom + menu item height
            add     d0, Bottom(a2)      ; update bottom of menuRect                     <FJL C838>
            move.l  d6, -(sp)           ; and erase the whole region
            _EraseRgn
@NotLastItem
 
            rts
 
; if scrolling down, and if first item is appearing, then increase clip by height of    <FJL C792>
; rectangle containing indicator arrow, and erase arrow rectangle.
; NOTE: TopMenuItem has already been adjusted by scroll amount, so don't subtract it here
@ChkScrollDown
            move    Top(a2), d0         ; get Top of menuRect
            sub     MFHeight(a6), d0    ; sub height of scroll arrow
            cmp     TopMenuItem, d0     ; is new top of menuRect <= TopMenuItem
            bgt.s   @NotFirstItem       ; no ==> not showing first item
 
; first item is being drawn -> open clip so scroll arrow gets erased and first item gets drawn <FJL C792>
 
            move.l  d6, a0              ; change the top of the update region
            move.l  (a0), a0            ; get ptr to rgn
            move    MFHeight(a6), d0    ; get menu item height
            sub     d0, 2+Top(a0)       ; Top = Top - menu item height
            sub     d0, Top(a2)         ; update top of menuRect                        <FJL C838>
            move.l  d6, -(sp)           ; and erase the whole region
            _EraseRgn
@NotFirstItem
 
            rts
 
;---------------------------------------
;   Utility -- GetSizes
;---------------------------------------
; GetSizes reads the size of the current font into the stack frame.  It puts
; ascent+descent+leading into the leading field and tweaks width for chicago
 
GetSizes    LEA     MInfoRec(A6),A2     ; point to our info rec                     <1Aug85>
            MOVE.L  A2,-(SP)            ; push a pointer                            <1Aug85>
            _GetFontInfo                ; and get the font's info                   <1Aug85>
            MOVE.W  (A2)+,D0            ; get ascent                                <1Aug85>
            ADD.W   (A2)+,D0            ; add descent                               <1Aug85>
 
; fudge width if font is Chicago so that space between command key and command      <FJL 21Jan87>
; character look better.  Can't assume that a width of 14 means chicago, so check
; explicitly.
 
            TST.W   ROM85               ; running on new roms?
            BMI.S   @ChkCurFM           ; => no, then only check CurFMFamily
            TST.W   SysFontFam          ; We ar on post-MacPlus so can check SysFontFamily
            BNE.S   @NotChicago         ; If SysFontFam <> 0 then not Chicago
                                        ; If on post-MacPlus then check CurFMFamily too.
@ChkCurFM   TST.W   CurFMFamily         ; is CurFMFamily == 0 ?
            BNE.S   @NotChicago         ; no, so not Chicago
            SUBQ    #2,(A2)             ; yes its Chicago, so fudge width                   <1Aug85>
 
@NotChicago ADDQ    #2,A2               ; skip over widmax                                  <1Aug85>
            ADD.W   D0,(A2)             ; add leading, store total height in MFHeight(A6)   <1Aug85>
 
            SUBQ.L  #2, SP              ; Make room in stack                        <S550   27Jul88 EMT>
            MOVE.W  #' ', -(SP)         ; ch = space                                <S550   27Jul88 EMT>
            _CharWidth                  ; See how wide it is                        <S550   27Jul88 EMT>
            MOVE.W  (SP)+, MSpaceWidth(A6)  ; Put it in our stack frame             <S550   27Jul88 EMT>
 
            RTS
 
 
;---------------------------------------
;   Utility -- GetIconSize
;---------------------------------------
; GetIconSize is a utility which returns the height and width of an icon.  The item pointer is in
; A1 and the result is returned in D1.  The height is in the high word.         <S550   27Jul88 EMT>
GetIconSize
            cmpi.b  #ScriptMenuCmd, itemCmd(a1) ; is there a script defined?    <FJL CXXX>
            beq.s   @noIcon             ; yes, icon field stores scriptID       <FJL CXXX>
 
            TST.B   ITEMICON(A1)        ; does it have an icon?                 <1Aug85>
            BNE.S   @hasIcon            ; skip around if it does                <1Aug85>
@noIcon
            MOVEQ.L #0, D1              ; No icon - return 0                    <S550   27Jul88 EMT>
            RTS                         ; Go home                               <S550   27Jul88 EMT>
 
@hasIcon
            tst.b   onColorMachine(a6)  ; If color, than check color icon       <S550   27Jul88 EMT>
            beq.s   @noColor            ;                                       <S550   27Jul88 EMT>
 
; Get the cicn resource because its faster than calling GetCIcon                <S550   27Jul88 EMT>
            SUBQ.L  #4, SP              ; make room for function result         <S550   27Jul88 EMT>
            MOVE.L  #'cicn',-(SP)       ; push the resource type                <S550   27Jul88 EMT>
            MOVE.W  #$0100,D0           ; menu icons are 256-511                <S550   27Jul88 EMT>
            MOVE.B  ITEMICON(A1),D0     ;                                       <S550   27Jul88 EMT>
            MOVE.W  D0,-(SP)            ; push icon number                      <S550   27Jul88 EMT>
            _GetResource                ; get handle to cicn resource           <S550   27Jul88 EMT>
            MOVE.L  (SP)+, D1           ; get it in D1                          <S550   27Jul88 EMT>
            BEQ.S   @noColor            ; no color icon, must be regular icon   <S550   27Jul88 EMT>
 
            MOVE.L  D1, -(SP)           ; Since we don't know what resLoad is   <S550   27Jul88 EMT>
            _LoadResource               ; call LoadResource to be sure          <S550   27Jul88 EMT>
            MOVE.L  D1, A0              ; get cicn resource handle in a0        <S550   27Jul88 EMT>
            MOVE.L  (A0), A0            ; dereference, cicn begins with pixMap  <S550   27Jul88 EMT>
            MOVE.L  pBounds+botRight(A0), D1    ; get bottom,right in D1        <S550   27Jul88 EMT>
            SUB.L   pBounds+topLeft(a0), D1 ; height = bottom,right - top,left  <S550   27Jul88 EMT>
            BRA.S   @testShrunk         ;                                       <S550   27Jul88 EMT>
 
@noColor                                ;                                       <S550   27Jul88 EMT>
            MOVE.L  #$00200020, D1      ; Large b/w icons are 32 x 32           <S550   27Jul88 EMT>
 
@testShrunk                             ;                                       <S550   27Jul88 EMT>
            cmpi.b  #ShrunkenIconCmd, itemCmd(A1)   ; is there a shrunken icon? <FJL PMAB205>
            beq.s   @0                  ; yes -> branch
            cmpi.b  #SmallIconCmd, itemCmd(A1)  ; is there a small icon?        <FJL PMAB205>
            bne.s   @1                  ; no    -> branch                       <S550   27Jul88 EMT>
@0
            LSR.L   #1, D1              ; Divide by 2 to get smaller size       <S550   27Jul88 EMT>
            BCLR    #15, D1             ; Clear out because height could be odd <S550   27Jul88 EMT>
 
@1
            RTS
 
 
;---------------------------------------
;   Utility -- GetItemHeightA4                                              <FJL PMAB205>
;---------------------------------------
; GetItemHeight gets the height of the current menu item into D0.
; The item pointer is in A4.  Use GetItemHeight.
GetItemHeightA4
            MoveM.L A1, -(SP)           ; save work register
            Move.L  A4, A1              ; set up for call to GetItemHeight
            Bsr.S   GetItemHeight
            MoveM.L (SP)+, A1           ; restore work register
            Rts
 
;---------------------------------------
;   Utility -- GetItemHeight
;---------------------------------------
; GetItemHeight gets the height of the current menu item into D0.
; The item pointer is in A1.  Width of icon (if any) is in the high word of D1.
 
GetItemHeight
            BSR.S   GetIconSize         ; Returns height, width in D1           <S550   27Jul88 EMT>
            SWAP    D1                  ; Get height in low word                <S550   27Jul88 EMT>
 
            MOVE.W  MFHeight(A6),D0     ; get menu item height                  <1Aug85>
 
            ADDQ.W  #4, D1              ; Add 4 for good measure                <S550   27Jul88 EMT>
            CMP.W   D0, D1              ; Is height + 4 > MFHeight?             <S550   27Jul88 EMT>
            BLT.S   @1                  ; Nope, skip around                     <S550   27Jul88 EMT>
            MOVE.W  D1, D0              ; Yes, use height + 4 instead           <S550   27Jul88 EMT>
 
@1          RTS
 
 
;---------------------------------------
;   Utility -- EnableTest
;---------------------------------------
; EnableTest is a utility which tests if an item is enabled.  It expects a menuHandle
; in A3 and the item number in D4.  It returns the result in the Z-flag
 
ENABLETEST  MOVE.L  (A3),A0             ; get menu pointer
            MOVE.L  MENUENABLE(A0),D0   ; get enable flags
            CMPI.W  #31,D4              ; is item > 32                      <7Jan86><FJL C466>
            BGT.S   @0                  ; => no enable/disable              <7Jan86><FJL C466>
            BTST    D4,D0               ; is item enabled?
            BEQ.S   ETDONE              ; if not, return 0
@0          BTST    #0,D0               ; test menu bit
            BEQ.S   ETDONE              ; if off, return 0                  <S550   27Jul88 EMT>
            MOVE.W  D4, D0              ; Put item number in D0             <S550   27Jul88 EMT>
            BSR     GetItemRecord       ; Go get it                         <S550   27Jul88 EMT>
            BSR     IsDash              ; Is it a dash?                     <S550   27Jul88 EMT>
ETDONE      RTS                         ; return to caller
 
 
;---------------------------------------
;   Utility -- InvertItem
;---------------------------------------
; InvertItem is an internal utility that hilites/unHilites an item.  The item number is
; passed in D0.  It also assumes A3 has the menuHandle.  If the high bit of D0
; is set, bit-clear with gray instead of inverting the item (used by DoDrawMsg routine).
 
INVERTITEM  MOVEM.L D3-D4,-(SP)         ; save work registers
            MOVE    D0,D3               ; keep item number in safe place
            BEQ     INVERTDONE          ; if zero, ignore
            MOVE.W  TopMenuItem,D2      ; start at top of menu              <30Jan86>
            MOVEQ   #1,D4               ; D4 hold item index                <27Sep85>
 
IILOOP      MOVE    D4,D0               ; get item
            MOVE.L  (A3),A0             ; get menuPtr
            BSR     GETITEMRECORD       ; look it up
            beq     InvertDone          ; z-flag ==> can't find it          <FJL 22Mar87>
            BSR.S   GetItemHeight       ; get item height into D0           <1Aug85>
 
            CMP.B   D3,D4               ; found the item we want yet?
            BEQ.S   GOINVERT            ; if so, go invert it
            ADD     D0,D2               ; add total to cumulative v position
            ADDQ    #1,D4               ; bump to next position
            BRA.S   IILOOP              ; loop till we find it
 
; it's time to invert the item.  The menuRect contains the horizontal bounds, D2 contains
; the top of the vertical, D0 has the vertical size
 
GOINVERT    MOVE.B  1(A0),D1            ; remember 1st char of item
            LEA     TEMPRECT,A0         ; get pointer to temporary rectangle
            MOVE.L  MMENURECT(A6),A1    ; point to menuRect
            MOVE.L  (A1)+,(A0)          ; copy menuRect into tempRect
            MOVE.L  (A1),4(A0)
            MOVE    D2,TOP(A0)          ; D2 has the top coordinate
            ADD     D0,D2               ; add in the height
            MOVE    D2,BOTTOM(A0)       ; set up the bottom
 
;
; Instead of inverting the item's rectangle we redraw it.  If the invertFlag(a6)    <FJL C408>
; is set then SetColors will invert the colors properly for us.  If it isn't set    <FJL C408>
; then the item will just be redrawn in normal colors.                              <FJL C408>
;
            movem.l a2-a4/d3-d7, -(sp)  ; save same work registers as does DrawMsg
 
            move    #srcOr, -(sp)
            _TextMode                   ; set mode to srcOr
 
; set up for call to DrawTheItem.  Before doing this, we must clip to the item's rectangle
; so that outline and shadowed text will not draw outside of the item rect.  But, because
; scrolling with icons can produce "parts of items", we must clip to the intersection of the
; menu rect and the item rect.  AND we must clip to screen in case menu draws past screen bounds.
 
            subq    #4, sp              ; space for result
            _NewRgn
            move.l  (sp), -(sp)         ; make copy of region so can delete later
            _GetClip
 
            subq    #2, sp              ; space for boolean result
            move.l  MMenuRect(a6), -(sp); push menurect address
            pea     TempRect            ; push itemrect address
            pea     HierArrowRect(a6)   ; push dest rect (reuse stackframe variable)
            _SectRect
            addq    #2, sp              ; ignore result
 
            subq    #4, sp              ; get current portRect
            move.l  sp, -(sp)           ; make space on stack for return
            _GetPort
            move.l  (sp)+, a0           ; get port
 
            subq    #2, sp              ; space for boolean result
            pea     portRect(a0)        ; push portRect address
            pea     HierArrowRect(a6)   ; push clip rect address
            pea     HierArrowRect(a6)   ; push dest address
            _SectRect
            addq    #2, sp              ; ignore result
            pea     HierArrowRect(a6)   ; push clip rect
            _ClipRect
 
            tst     scrollFlag(a6)      ; being called from scroll routine?
            bne.s   @DoRedraw           ; yes, so do the drawing
 
; On MacPlus and MacSE do InvertRect instead of redrawing when choosing an item.    <FJL 17Mar87>
; Do this because MacDraw's custom "line" menu does not handle "choose item" message properly.
; Of course it's not as easy as that since we use the Choose message as a way to clean up
; the garbage left over when a hierarchical menu is brought down, and this assumes that
; the item is redrawn, NOT inverted.  If this is the case then HItemFlag will be set.
 
            tst     onColorMachine(a6)  ; on MacII ?
            bne.s   @DoRedraw           ; yes ==> always redraw
 
            tst     HItemFlag(a6)       ; does item have submenu?
            bne.s   @DoRedraw           ; yes ==> then redraw to eliminate garbage beneath submenu
 
            pea     TempRect            ; push ptr to item's rectangle
            _InverRect                  ; invert it
            bra.s   @RedrawDone         ; and leave
 
@DoRedraw
; erase the rect to the proper background color
            bsr     SaveCurrentColors   ; save current colors in stack frame            <FJL C408>
            move    #mctRGB2, colorOffset(a6)   ; this offset is unimportant here       <FJL C408>
                                                ; since all we care about is bkgd color <FJL C408>
            bsr     SetColors           ; set proper colors for EraseRect               <FJL C408>
 
            pea     TempRect            ; push a pointer to the rectangle
            _EraseRect                  ; erase it
 
            bsr     ResetPreviousColors ; reset colors after EraseRect
 
; and draw the item
            lea     TempRect, a0        ; get address of item's rectangle
            move    Top(a0), d3         ; get top
            add     MAscent(a6),d3      ; add in the ascent for baseline
;           move    Left(a0), d5        ; move left edge into d5                    <S550   27Jul88 EMT>
;           move    Right(a0), d6       ; move right edge into d6                   <S550   27Jul88 EMT>
;                                                                                   <S550   27Jul88 EMT>
;           move    d4,d0               ; get item                                  <S550   27Jul88 EMT>
;           move.l  (a3),a0             ; get menuPtr                               <S550   27Jul88 EMT>
;           bsr     GetItemRecord       ; look it up                                <S550   27Jul88 EMT>
;           move.l  a0,a2               ; keep string pointer in A2                 <S550   27Jul88 EMT>
;           move.l  a1,a4               ; keep properties in A4                     <S550   27Jul88 EMT>
 
            bsr     DrawTheItem         ; call drawing routine (it calls ResetPreviousColors)
 
@RedrawDone move.l  (sp), -(sp)         ; reset clip to region it was before drawing item
            _SetClip
            _DisposRgn
 
            movem.l (sp)+, a2-a4/d3-d7  ; restore work registers
 
INVERTDONE  MOVEM.L (SP)+,D3-D4         ; recover work regs
            RTS
 
;---------------------------------------
;   Utility -- GrayRect
;---------------------------------------
;   GrayRect is a utility that bit-clears the current "tempRect" with gray
;
; We assume that this routine is only called by Draw msg, that SaveCurrentColors    <FJL C408>
; has been called already, and that ResetPreviousColors will be called after this.  <FJL C408>
 
GRAYRECT
            MOVE.L  A0,-(SP)            ; push rect address
            MOVE.L  (A5),A0             ; get QuickDraw globals
            PEA     Gray(A0)            ; push gray
            _PenPat                     ; set pen to it
            MOVE    #PatBIC,-(SP)       ; push patBIC penMode
            _PenMode                    ; set penMode
            move    #mctRGB2, colorOffset(a6)   ; use text color for fore color <FJL C408>
            bsr     SetColors           ; set colors for bit clear              <FJL C408>
 
            _PaintRect                  ; "OR" on the dim pattern
 
            _PenNormal
 
            RTS
;---------------------------------------
;   Utility -- TweakPos
;---------------------------------------
; TweakPos is passed an element size in D0.  It gets a horizontal offset into
; D2 depending on whether things are right justified or not.  It also adjusts
; D5 and D6 (the left and right positions).
 
TweakPos
            MOVE    D5,D2               ; assume left to right                  <27Sep85>
;           ADDQ    #2,D2               ; and indent element a little           <27Sep85>   <S550   27Jul88 EMT>
            ADD.W   D0,D5               ; assume bump past icon                 <27Sep85>
            TST.B   TESysJust+1         ; check for right just                  <11oct85>
            BPL.S   @1                  ; => guessed right                      <27Sep85>
            SUB.W   D0,D6               ; else back up for icon                 <27Sep85>
            SUB.W   D0,D5               ; and fix up left                       <27Sep85>
            MOVE.W  D6,D2               ; and set position                      <27Sep85>
@1          RTS
 
;---------------------------------------
;   Utility -- DrawScrolledItem                                                 <FJL C838>
;---------------------------------------
; DrawScrolledItem is a faster way to draw the item that appears after a menu is scrolled.
; The old method was to redraw the whole menu, and because clipping was set to just
; the item that appeared no flashing occured.  The problem is that with the new features,
; most noticeably color and hierarchical menus, scrolling can be fairly slow.  Actually this
; method turns out to speed up scrolling by a factor of 2-3!!
;
DrawScrolledItem
 
            MOVE.W  D4,D2               ; top of menu into D2
            MOVEQ   #1, D4              ; start with first item
 
            TST     D7
            BGE.S   @ScrollingDown      ; if D7 >= 0 then scrolling down not up
@ScrollingUp
            MOVE    Bottom(a2), D3      ; fake mouse pt to be just above bottom of menu
            SUBQ    #1, D3              ; one pixel above menu bottom, or down scroll arrow
            BRA.S   @Loop
 
@ScrollingDown
            MOVE    Top(a2), D3         ; fake mouse pt to be just below top of menu
            ADDQ    #1, D3              ; one pixel below menu top, or up scroll arrow
 
 
@Loop       MOVE.L  (A3),A0             ; get menuPtr
            MOVE    D4,D0               ; get item number
            BSR     GetItemRecord       ; look it up
            BEQ.S   @LastItemSel        ; if none then must be last item
 
            BSR     GetItemHeight       ; get item height in D0
            ADD     D0,D2               ; update vertical
            CMP     D3,D2               ; compare with mouse point
            BGT.S   @GotSel             ; when D2 is bigger, we found it
;
; we didn't reach it yet, so keep stepping down till we do
;
            ADDQ    #1,D4               ; bump to next item
            BRA.S   @Loop               ; loop till we find it
;
; we found it so draw the item
;
@LastItemSel
            SUBQ    #1, D4              ; back up one item
 
@GotSel     MOVE    D4, D0              ; InvertItem wants item number in D0
            MOVE    #1, scrollFlag(a6)  ; set flag for InvertItem                   <FJL 17Mar87>
            BSR     InvertItem          ; InvertItem will draw the item
 
; Because of fucking icons, there could be just part of the scrolled item showing, so if
; we are scrolling up then redraw the item above too, or if scrolling down then redraw the
; item below.
 
            TST     D7
            BGE.S   @ScrollingDown2     ; if D7 >= 0 then scrolling down not up
@ScrollingUp2
            SUBQ    #1, D4              ; draw item above this one
            MOVE    D4, D0
            BSR     InvertItem
            BRA.S   @NoItemSel
 
@ScrollingDown2
            ADDQ    #1, D4              ; draw item below this one
            MOVE    D4, D0
            BSR     InvertItem
 
@NoItemSel  CLR     scrollFlag(a6)      ; clear flag after InvertItem call          <FJL 17Mar87>
            rts
 
 
;----------------------------------------------------------------------------------------
;
;   Msg #0 -- Draw Menu -- bits behind have been saved, menu structure has been drawn,
;                           and menu rectangle is cleared to proper color (all by mbarproc)
;
;----------------------------------------------------------------------------------------
;
; here is the part of the TextMenuProc that draws the menu.  For most of this routine,
; A3 holds the menuHandle, D4 is the item counter and D3 holds the cumulative
; vertical position.  DrawMenu is broken off for use in scrolling.
;
; To clear up a very tricky scrolling menu bug, we need to NOT SCROLL when a hierarchical menu
; is up in the last item (i.e. topmost or bottommost).  If we don't bring the HMenu down first
; a little bit of garbage is left on the screen.  We clear the field mbUglyScroll each
; time a menu is drawn, then set it when the first time into the scrolling routine.  Thereafter
; we check it and realize that the HMenu is already down, so it's ok to scroll.
;
; Changed so that caller sets global TopMenuItem so that can be forced to draw from <FJL C844>
 
DoDrawMsg
            bsr     GetSizes            ; get font info into stackframe
 
            MOVE.L  MMenuRect(A6),A0    ; get menu rect pointer                     <30Jan86>
            clr     atMenuBottom        ; clear bottom memory                       <FJL C222>
 
;>>>>>------------- MacPlus/MacSE patches ------------------>>>>>
 
        IF forRAM THEN
 
            cmp.w       #$FFFF, ROM85           ; on old Mac or MacXL?
            beq.s       @SetTMI                 ; yes -> skip HMenu specific stuff
 
                                                ; RADIUS patches out complete menu mgr ==> could
                                                ; have GetItemCmd installed, but mbSaveLoc
                                                ; not initialized.
            cmpi.l      #$FFFFFFFF, mbSaveLoc   ; has the MBDF data structure been initialized?
            beq.s       @SetTMI
 
            move.w      #$009F, d0              ; load _Unimplemented number
            _GetTrapAddress                     ; load _Unimplemented address
            move.l      a0, d1                  ; copy routine address
            move.w      #$004E, d0              ; load _GetItemCmd number
            _GetTrapAddress ,newTool            ; load _GetItemCmd address
            cmp.l       a0, d1                  ; new HMenu Mgr installed?
            bne.s       @ScrollClrOK            ; yes -> MenuSelect sets TopMenuItem properly
 
@SetTMI     MOVE.L      MMenuRect(A6),A0        ; get menu rect pointer                 <30Jan86>
            MOVE.W      top(A0),topMenuItem     ; no    -> say to draw from top         <30Jan86>
            bra.s       @SkipScrollClr          ; and skip HMenu specific stuff
@ScrollClrOK
        ENDIF   ; if forRAM
 
;<<<<<--------------------------------------<<<<<
            move.l  mbSaveLoc, a0       ; clear mbUglyScroll every time draw a menu <FJL C792>
            move.l  (a0), a0
            clr     mbUglyScroll(a0)
 
@SkipScrollClr
            bsr.s   DrawMenu            ; call draw menu
            bsr.s   ChkScrollIndic      ; draw scrolling indicator (if necessary) <FJL C792>
            rts
 
;---------------------------------------
;   Utility -- DrawMenu
;---------------------------------------
 
DRAWMENU    MOVEM.L a2-A4/D3-D7,-(SP)   ; save some regs                        <27Sep85>
            MOVEQ   #1,D4               ; start with first item
            MOVE.W  topMenuItem,D3      ; and point to top of first item
            ADD.W   MAscent(A6),D3      ; add in the ascent for baseline
 
; apps that screw around with the wmgrport textfont and textface unwittingly, have  <FJL CXXX>
; menu items show up in the wrong font/face/etc....
 
            CLR.L   -(SP)               ; push empty set for TextFace and TextFont
            _TextFace                   ; change textface to normal
            _TextFont                   ; change textfont to normal
 
            move    #srcOr, -(sp)       ; set text mode to srcOr                    <FJL C408>
            _TextMode                   ;                                           <FJL C408>
 
DRAW1MLOOP  MOVE.L  MMENURECT(A6),A0    ; get menuRect pointer                      <27Sep85>
;           MOVE.L  (A0)+,D5            ; get left edge                             <27Sep85>   <S550   27Jul88 EMT>
;           MOVE.L  (A0),D6             ; get right edge, too                       <27Sep85>   <S550   27Jul88 EMT>
;                                                                                               <S550   27Jul88 EMT>
;           MOVE    D4,D0               ; get item number in D0                                 <S550   27Jul88 EMT>
;           MOVE.L  (A3),A0             ; get menu pointer                                      <S550   27Jul88 EMT>
;           BSR     GETITEMRECORD       ; look it up                                            <S550   27Jul88 EMT>
;                                                                                               <S550   27Jul88 EMT>
;           MOVE.L  A0,A2               ; keep string pointer in A2                             <S550   27Jul88 EMT>
;           MOVE.L  A1,A4               ; keep properties in A4                                 <S550   27Jul88 EMT>
            bsr     DrawTheItem         ; call drawing routine
            BEQ.S   DONEDRAW            ; if null item, EXIT W/atBottom TRUE        <27Sep85>   <S550   27Jul88 EMT>
 
;
; we're done with this item so bump to the next one
;
            cmpi.b  #ScriptMenuCmd, itemCmd(a4) ; is there a script defined?        <FJL CXXX>
            beq.s   @1                  ; yes, icon field stores scriptID           <FJL CXXX>
 
            TST.B   ITEMICON(A4)        ; does it have an icon?
            BEQ.S   @1                  ; skip if it doesnt
            MOVE.W  D7,D0               ; get delta height
            LSR.W   #1,D0               ; divide by 2
            SUB.W   D0,D7               ; and get remainder
            ADD     D7,D3               ; bump the rest of the difference for icon
 
@1          ADD     MFHeight(A6),D3     ; bump to next baseline
            ADDQ    #1,D4               ; bump to next item
            BRA.s   DRAW1MLOOP          ; loop till done
 
; When we return to DoneDraw, D3 points to the baseline of the cell that would follow the
; last cell.  Back up to the bottom of the last cell and save as menubottom.
 
DONEDRAW    SUB.W   MAscent(A6),D3      ; back up to "top of cell"                  <30Jan86>
            MOVE.W  D3,AtMenuBottom     ; update bottom                             <30Jan86>
            MOVEM.L (SP)+,a2-A4/D3-D7   ; restore some regs                         <27Sep85>
            RTS
 
 
 
;---------------------------------------
;   Utility -- ChkScrollIndic                                                       <FJL C792>
;---------------------------------------
; Blit up the scrolling down arrow if we need to
;
ChkScrollIndic
            move.l  MMenuRect(a6), a0       ; get menu rect ptr
            move    AtMenuBottom, d0        ; get AtMenuBottom
            cmp     Bottom(a0), d0          ; is AtMenuBottom > bottom of MenuRect
            ble.s   @CkUpIndic              ; no ==> don't need down arrow, see if need up arrow
            bsr.s   BlitDownScrollIndic     ; yes ==> blit the down arrow
 
@CkUpIndic  move.l  MMenuRect(a6), a0       ; get menu rect ptr                     <FJL C844>
            move    TopMenuItem, d0         ; get TopMenuItem
            cmp     Top(a0), d0             ; is TopMenuItem < top of MenuRect
            bge.s   @DoneChk                ; no ==> don't need up arrow
            bsr.s   BlitUpscrollIndic       ; yes ==> blit the up arrow
@DoneChk    rts
 
;---------------------------------------
;   Utility -- BlitDownScrollIndic / BlitUpScrollIndic                                                  <FJL C792>
;---------------------------------------
; Blit up the scrolling arrows
;
BlitDownScrollIndic
            movem.l a3-a4/d4, -(sp)         ; store work registers
 
; calculate where bottom of menu is
            move    Bottom(a0), HierArrowRect+Bottom(a6)    ; store bottom
            move    Bottom(a0), HierArrowRect+Top(a6)       ; top = bottom - MFHeight
            move    MFHeight(a6), d0
            sub     d0, HierArrowRect+Top(a6)
            move    Left(a0), HierArrowRect+Left(a6)        ; store left
            move    Right(a0), HierArrowRect+Right(a6)      ; store right
            lea     DownArrow, a4           ; store arrow address in a4 for DoTheBlit
            bra.s   DoTheBlit
 
BlitUpScrollIndic
            movem.l a3-a4/d4, -(sp)         ; store work registers
 
; calculate where top of menu is
            move    Top(a0), HierArrowRect+Top(a6)          ; store top
            move    Top(a0), HierArrowRect+Bottom(a6)       ; bottom = top + MFHeight
            move    MFHeight(a6), d0
            add     d0, HierArrowRect+Bottom(a6)
            move    Left(a0), HierArrowRect+Left(a6)        ; store left
            move    Right(a0), HierArrowRect+Right(a6)      ; store right
            lea     UpArrow, a4         ; store arrow address in a4 for DoTheBlit
                                        ; and drop into DoTheBlit
 
DoTheBlit
            bsr     SaveCurrentColors       ; save current colors in stack frame
            move    #-1, d4                 ; force SetColors to get the title color
                                            ;   entry not an item entry
            move    #mctRGB2, colorOffset(a6)   ; set fore/back colors for this item
            bsr     SetColors               ; set proper colors for blit
 
; erase rect now that the fore/back colors are set properly
            pea     HierArrowRect(a6)
            _EraseRect
 
; create bitMap for arrow
            moveq   #bitMapRec, d0          ; alloc bitmap for 16Vert x 16Horiz x 1Deep bit map
            _NewHandle
            _HLock
            move.l  (a0), a3                ; dereference
            move    #2, rowBytes(a3)        ; 16 x 1 bits wide
            move.l  #$00000000,bounds(a3)   ; top = 0, left = 0
            move.l  #$00100010,bounds+4(a3) ; bottom = $10, right = $10
            move.l  a4, baseAddr(a3)        ; store correct arrow bitmap in baseAddr
 
; set arrow rect
;+++;   left = left + MWidMax
;+++;   right = newleft + MWidMax + 4
;+++            move    MWidMax(a6), d0
;+++            add     d0, HierArrowRect+Left(a6)
;+++            move    HierArrowRect+Left(a6), HierArrowRect+Right(a6)
;+++            add     #4, d0
;+++            add     d0, HierArrowRect+Right(a6)
 
; left = MenuRect.left + MWidMax                                    <FJL PMAB205>
; right = left + min(16,MFHeight(A6))
; bottom = top + min(16,MFHeight(A6))
            move    MWidMax(A6), d0
            add     HierArrowRect+Left(A6), d0
            move    d0, HierArrowRect+Left(A6)
            move    d0, HierArrowRect+Right(A6)
            moveq   #16, d0
            cmp.w   MFHeight(A6), d0
            bge.s   @1
            move    MFHeight(A6), d0
@1          add     d0, HierArrowRect+Right(A6)
            move    HierArrowRect+Top(A6), HierArrowRect+Bottom(A6)
            add     d0, HierArrowRect+Bottom(A6)
 
; get current portRect
            subq    #4, sp
            move.l  sp, -(sp)               ; make space on stack for return
            _GetPort
            move.l  (sp)+, a0               ; get port
 
; copy from the bitMap into the port
            move.l  a3, -(sp)               ; push src bitMap ptr
            pea     portBits(a0)            ; push dest pointer (for the screen)
            pea     bounds(a3)              ; push src bounds rect
            pea     HierArrowRect(a6)       ; push dest bounds rect
            move    #srcOr, -(sp)           ; srcOr
            clr.l   -(sp)                   ; no maskRgn
            _CopyBits
 
            move.l  a3, a0                  ; get bitMap ptr
            _RecoverHandle                  ; get bitMap handle
            _DisposHandle                   ; and toss it
            movem.l (sp)+, a3-a4/d4         ; restore work registers
 
            bsr     ResetPreviousColors     ; reset colors stored in stackframe
 
            rts
            
;---------------------------------------
;   Utility -- IsDash
;---------------------------------------
; IsDash is a utility which tests if an item is the special dash separator.
; It returns the result in the Z-flag                                               <S550   27Jul88 EMT>
IsDash
            CMP.B   #$2D,1(A0)          ; first char a dash?
            BNE.S   @NoDash             ; No dash, skip.
            TST.B   itemIcon(A1)        ; Does it have an icon?
            BNE.S   @NoDash             ; No dash, skip.
            TST.B   itemCmd(A1)         ; Does it have a cmd?
@NoDash
            RTS                         ; Return result in Z
 
;----------------------------------------
;   Utility -- DrawTheItem
;----------------------------------------
; separated actual drawing routine out so
; can ChooseMsg can call it since we now
; redraw the selected item rather than
; just inverting it.
;
; Used to be:                                                                       <S550   27Jul88 EMT>
; On entry:     d3      Item's baseline, top of item + font's ascent
;               d4      Item Number
;               d5      left edge, pixels
;               d6      right edge, pixels
;               a2      item's string pointer
;               a4      item's properties pointer
;               --      GetSizes has been called
;
; Now:                                                                              <S550   27Jul88 EMT>
; On entry:     D3      Item's baseline, top of item + font's ascent
;               D4      Item Number
;               A0      Menu rectangle pointer (for left and right edge)
;               A3      Menu handle
;               --      GetSizes has been called
;               --      GetItemRecord has been called
;               --      D5, D6, A2, and A4 are all set up just like old times
;
; On exit:      Z       Set if the item does not exist
;
DrawTheItem
            MOVE.W  Left(A0), D5        ; Get the left edge                         <S550   27Jul88 EMT>
            MOVE.W  Right(A0), D6       ; Get the right edge                        <S550   27Jul88 EMT>
 
            MOVE.W  D4, D0              ; Prepare item number for GetItemRecord     <S550   27Jul88 EMT>
            MOVE.L  (A3), A0            ; Dereference menu handle                   <S550   27Jul88 EMT>
            BSR     GetItemRecord       ; Go get it                                 <S550   27Jul88 EMT>
            BEQ     NoDrawItem          ; Skip whole mess if not a valid item       <S550   27Jul88 EMT>
            MOVE.L  A0, A2              ; Store string pointer in A2                <S550   27Jul88 EMT>
            MOVE.L  A1, A4              ; And properties in A4                      <S550   27Jul88 EMT>
 
            bsr     SaveCurrentColors   ; save fore/back colors in stackframe       <FJL C408>
 
            MOVE.L  A2, A0              ; Get string pointer for IsDash             <S550   27Jul88 EMT>
            MOVE.L  A4, A1              ; And properties too                        <S550   27Jul88 EMT>
            BSR.S   IsDash              ; Is it a dash?                             <S550   27Jul88 EMT>
            BNE.S   NotDash             ; If not, draw item normally                <S550   27Jul88 EMT>
 
;---------------------------------------
;   Utility -- DrawDash
;---------------------------------------
; handle the case of a dash item by drawing a line
DrawDash
            move    #mctRGB2, colorOffset(a6) ; use the item color if there is an entry <FJL C408>
            bsr     SetColors           ; set colors                                    <FJL C408>
 
            MOVE.L  (A5),A0             ; get QuickDraw globals
            PEA     Gray(A0)            ; set pattern to gray
            _PenPat
 
            MOVE.W  D3,-(SP)            ; save y position
            MOVE.W  D5,-(SP)            ; push x position
            MOVE.W  MFHeight(A6),D0 ; center the dash
            LSR.W   #1,D0               ; by backing up to top of cell
            SUB.W   MAscent(A6),D0      ; and going halfway down
            ADD.W   D0,D3               ; add to current position
            MOVE.W  D3,-(SP)            ; push new y position
            _MoveTo
 
            MOVE.W  D6,-(SP)            ; push  right edge
            MOVE    D3,-(SP)            ; push  y
            _LineTo                     ; draw  the line
            MOVE.W  (SP)+,D3            ; restore baseline
 
            _PenNormal                  ; pen back to normal
            BRA     DoneDrawItem        ; dive  back into mainstream
 
NotDash
            ADDQ.W  #2, D5              ; Add the 2 pixels here instead             <S550   27Jul88 EMT>
            cmpi.b  #ScriptMenuCmd, itemCmd(a4) ; is there a script defined?        <FJL CXXX>
            beq.s   DrawMark            ; yes, icon field stores scriptID           <FJL CXXX>
 
            MOVE.B  ITEMICON(A4),D0     ; does it have an icon?
            BEQ.S   DrawMark            ; if not, skip
 
; for icon, center the baseline in the item's rect
 
            Bsr     GetItemHeightA4     ; get item's height in D0
            SUB.W   MFHeight(A6),D0     ; subtract font height                      <1Aug85>
            MOVE.W  D0,D7               ; save font height in D7                    <1Aug85>
            LSR.W   #1,D0               ; get delta                                 <1Aug85>
            ADD.W   D0,D3               ; keep baseline in D3                       <1Aug85>
 
; --------------------- draw the mark   --------------------------
 
DrawMark    MOVE.W  MWidMax(A6),D0      ; get char width                            <27Sep85>
            BSR     TweakPos            ; get hpos into D2, adjust d5,d6            <27Sep85>
 
;           When itemCmd == HMenuCmd ($1B) the itemMark field is used to store      <FJL C222>
;           the hierarchical menu number so don't draw a mark by mistake.           <FJL C222>
 
            cmpi.b  #HMenuCmd, itemCmd(a4)  ; hierarchical menu for this item?      <FJL C222>
            beq.s   ChkDrawIcon
 
            TST.B   ITEMMARK(A4)        ; does it have a mark?
            BEQ.S   CHKDRAWICON         ; if not, skip
 
            MOVE.W  D2,-(SP)            ;
            MOVE    D3,-(SP)            ; push v position
            _MoveTo                     ; position pen
 
            move    #mctRGB1, colorOffset(a6) ; tell SetColors to get the MARK      <FJL C408>
            bsr     SetColors           ; set mark colors                           <FJL C408>
 
            CLR D0                      ; clear out high part
            MOVE.B  ITEMMARK(A4),D0     ; get the mark character
            MOVE.W  D0,-(SP)            ; push it
            _DrawChar
 
 
; --------------------- draw the icon   --------------------------
 
CHKDRAWICON
;           when itemCmd == ScriptMenuCmd ($1C) the itemIcon field is used to       <FJL CXXX>
;           store the script ID number, so don't draw an icon by mistake.           <FJL CXXX>
 
;           when itemCmd == ShrunkenIconCmd ($1D) we draw the icon into a 16x16     <FJL PMAB205>
;           area instead of the normal 32x32
 
;           when itemCmd == SmallIconCmd ($1E) we draw a small icon into a 16x16    <FJL PMAB205>
;           area
 
;           cmpi.b  #ScriptMenuCmd, itemCmd(a4) ; script for this item?             <FJL CXXX>
;           beq     DrawCmdChar
;
;           TST.B   ITEMICON(A4)        ; does it have an icon?                     <15Oct85>
 
            MOVE.L  A4, A1              ; Copy A4 into A1 for GetIconSize           <S550   27Jul88 EMT>
            BSR     GetIconSize         ; Get the height, width of the icon         <S550   27Jul88 EMT>
            TST.L   D1                  ; Is there one?                             <S550   27Jul88 EMT>
            BEQ     DrawCmdChar         ; if not, skip
;
; get horizontal position into D2
;
;           MOVEQ   #40,D0              ; get field size (width) for large icon     <27Sep85>
;
;           Cmpi.b  #ShrunkenIconCmd, itemCmd(A4)   ;is this a shrunken icon ?      <FJL PMAB205>
;           Beq.s   @SmallDst           ; yes   -> branch                           <FJL PMAB205>
;           Cmpi.b  #SmallIconCmd, itemCmd(A4)      ;is this a small icon ?
;           Bne.s   @DoTweak            ; no    -> branch
;@SmallDst  Bsr     GetItemHeightA4     ; get item height for small icons into D0
;@DoTweak   BSR     TweakPos            ; get hpos into D2, adjust D5,D6            <27Sep85>
 
; draw the icon.  First back up to top of rect
 
            LEA     TEMPRECT,A0         ; get pointer to rectangle
            MOVE.L  A0,-(SP)            ; push rect for plotIcon call
 
            MOVE.L  D1, -(SP)           ; Save height, width on stack               <S550   27Jul88 EMT>
            MOVE.W  D3,D1               ; get baseline                              <1Aug85>
            MOVE.W  D7,D0               ; font height from D7                       <15Oct85>
            LSR.W   #1,D0               ; get delta                                 <15Oct85>
            SUB.W   D0,D1               ; subtract delta                            <15Oct85>
            SUB.W   MAscent(A6),D1      ; subtract font height                      <15Oct85>
            ADDQ.W  #2,D1               ; down from top of item                     <15Oct85>
            MOVE.L  (SP)+, D0           ; Restore it into D0 instead                <S550   27Jul88 EMT>
 
;           cmpi.b  #ShrunkenIconCmd, itemCmd(A4); is this a shrunken icon ?        <FJL PMAB205>
;           beq.s   @SetupSmallDstIcon          ; yes -> branch                     <FJL PMAB205>
;           cmpi.b  #SmallIconCmd, itemCmd(A4)  ; is this a smallicon ?
;           bne.s   @SetupRegularIcon
;
;@SetupSmallDstIcon
;           move    D1, (A0)+           ; and stuff top
;           move    D2, (A0)            ; push left
;           subq.w  #3, (A0)+           ; fudge to line up small icon on the left
;           move.l  -4(A0),(A0)         ; copy bottom/right
;           add     #16, (A0)+          ; bottom := top + 16
;           add     #16, (A0)           ; right := left + 16
;           bra.s   @DoneSetup
;
;
;@SetupRegularIcon
            MOVE.W  D1,(A0)+            ; and stuff top                         <1Aug85>
            MOVE.W  D5, D2              ; Assume left-to-right                  <S550   27Jul88 EMT>
            TST.B   TESysJust+1         ; Test for right just                   <S550   27Jul88 EMT>
            BPL.S   @LeftRight          ; Guessed right                         <S550   27Jul88 EMT>
 
            MOVE.W  D6, D2              ; Otherwise get right side              <S550   27Jul88 EMT>
            SUB.W   D0, D2              ; And subtract out width                <S550   27Jul88 EMT>
 
@LeftRight                              ;                                       <S550   27Jul88 EMT>
            MOVE.W  D2,(A0)+            ; push left                             <27Sept85>  <S550   27Jul88 EMT>
;           ADDQ.W  #3,(A0)+            ; indent a little                       <15Oct85>
            MOVE.L  -4(A0),(A0)         ; copy bottom right
            ADD.L   D0, (A0)            ; Add height, width to get bottom, right    <S550   27Jul88 EMT>
 
;           ADD     #32,(A0)+           ; bottom := top + 32
;           ADD     #32,(A0)            ; right := left + 32
;@DoneSetup
 
            ADD.W   MSpaceWidth(A6), D0 ; Add single space to width of icon         <S550   27Jul88 EMT>
            BSR     TweakPos            ; get hpos into D2, adjust D5,D6            <S550   27Jul88 EMT>
 
;>>>>>------------- NuMac ------------------>>>>>
 
;+++        IF onNuMac THEN
            tst.b   onColorMachine(a6)
            beq.s   @DoPlotIcon
 
; attempt to get color icon first and if unsuccessful then get regular icon     <FJL C408>
            subq    #4, sp              ; make room for function result
            move    #$0100, d0          ; menu icons are 256-511
            move.b  itemIcon(a4), d0    ; get icon number - 256
            move    d0, -(sp)           ; push icon number
            _GetCIcon
            move.l  (sp)+, iconHandle(a6)   ; get icon handle, and save in stackframe
            beq.s   @DoPlotIcon         ; no color icon, must be regular icon
 
; check to be sure icon is <= 32 x 32
; no longer care about icon size                                                <S550   27Jul88 EMT>
;           move.l  iconHandle(a6), a0  ; get icon handle
;           move.l  (a0), a0            ; dereference, a0 points at pixMap
;           move.l  pBounds+Top(a0), d0 ; get top, left
;           move.l  pBounds+Bottom(a0), d1  ; get bottom, right
;           sub     d0, d1              ; width = right - left
;           cmp     #32, d1             ; width == 32 ?
;           bne.s   @DispIcon           ; if not then don't plot it
;           swap    d0
;           swap    d1
;           sub     d0, d1              ; height = bottom - top
;           cmp     #32, d1             ; height == 32?
;           bne.s   @DispIcon           ; if not then don't plot it
 
; force colors to black on white for PlotCIcon regardless of InvertFlag,
; unless it's 1 or 2 bit mode in which case we want it white on black so icon mask
; is inverted properly
            cmpi.w  #4, PixelDepth(a6)  ; is this 4+ mode ?
            blt.s   @FunkySettings      ; no, so branch and do funky color setting
            pea     RGBBlack            ; in 4+ mode force black on white always
            _RGBForeColor
            pea     RGBWhite
            _RGBBackColor
            bra.s   @1
 
@FunkySettings                          ; in 1 or 2 bit, use black on white for normal
                                        ; and white on black for selected
            pea     RGBBlack
            pea     RGBWhite
            tst     invertFlag(a6)      ; invert mode?
            bne.s   @2                  ; yes --> branch
            _RGBBackColor
            _RGBForeColor
            bra.s   @1
 
@2          _RGBForeColor
            _RGBBackColor
 
; everything checks out so plot it
@1          move.l  iconHandle(a6), -(sp)   ; got a color icon so push it on the stack
            _PlotCIcon                      ; rect is already on the stack
 
;@DispIcon does not properly clean up stack.  Good thing we don't use it anymore.
            move.l  iconHandle(a6), -(sp)   ; dispose of CIcon
            _DisposCIcon
            bra.s   DrawCmdChar             ; and continue
 
;+++        ENDIF
 
;<<<<<--------------------------------------<<<<<
 
 
@DoPlotIcon
            Cmpi.B  #SmallIconCmd, itemCmd(A4)  ; is it a small icon ?          <FJL PMAB205>
            Bne.S   @GetLargeIcon       ; no    -> get large icon
            Clr.L   -(SP)               ; yes -> get small icon
            Move.L  #'SICN', -(SP)      ; push res type
            Bra.S   @GetIconCommon      ; and use common code
 
@GetLargeIcon
            CLR.L   -(SP)               ; make room for function result
            MOVE.L  #'ICON',-(SP)       ; push the resource type
@GetIconCommon
            MOVE.W  #$0100,D0           ; menu icons are 256-511
            MOVE.B  ITEMICON(A4),D0     ; does it have an icon?
            MOVE    D0,-(SP)            ; push icon number
            _GetResource                ; get the icon handle
 
            move.l  #$00100010, D0      ; assume src icon is 16x16
            moveq   #2, D1              ; and rowbytes is 2
            cmpi.b  #SmallIconCmd, itemCmd(a4)  ; is it?
            beq.s   @PushIconSrcSize    ; yes -> branch
            add.l   d0,d0               ; double it to make 32x32
            add.l   d1,d1               ; double rowbytes too
@PushIconSrcSize
            move.l  d0,-(sp)            ; push size
            move    d1,-(sp)            ; push rowbytes
 
            move    #mctRGB2, colorOffset(a6) ; use the item color if there is an entry <FJL C408>
            bsr     SetColors           ; set colors                                    <FJL C408>
 
@PlotIt     bsr     PlotAnySizeIcon ; plot the icon                                     <FJL PMAB205>
 
@DonePlot
 
; --------------------- draw the command character  --------------------------
 
DrawCmdChar
            TST.B   ITEMCMD(A4)         ; is there one?
            BEQ.S   DRAWITEXT           ; if not, skip
 
            cmpi.b  #ScriptMenuCmd, itemCmd(a4) ; script for this item?                 <FJL CXXX>
            beq.s   DrawIText           ; if so, skip                                   <FJL CXXX>
 
            cmpi.b  #ShrunkenIconCmd, itemCmd(a4)   ; shrunken icon?                    <FJL PMAB205>
            beq.s   DrawIText           ; if so, skip
 
            cmpi.b  #SmallIconCmd, itemCmd(a4)  ; small icon?                           <FJL PMAB205>
            beq.s   DrawIText           ; if so, skip
 
            move    #mctRGB3, colorOffset(a6) ; tell SetColors to get the CMD           <FJL C408>
            bsr     SetColors           ; set colors for command character              <FJL C408>
 
            MOVE.W  MWidMax(A6),D0      ; get width                                     <27Sep85>
            ADD.W   D0,D0               ; *2                                            <27Sep85>
 
            SUB.W   D0,D6               ; assume it will go on right                    <27Sep85>
            MOVE    D6,-(SP)            ; put it on stack                               <27Sep85>
            TST.B   TESysJust+1         ; check for right just                          <11oct85>
            BPL.S   @1                  ; => guessed right                              <27Sep85>
            ADDQ    #2,D5               ; else indent a little FIRST                    <S550   27Jul88 EMT>
            MOVE.W  D5,(SP)             ; else do it from left                          <27Sep85>
            ADD.W   D0,D5               ; and bump left position                        <27Sep85>
            ADD.W   D0,D6               ; else back up for icon                         <27Sep85>
 
@1          MOVE.W  D3,-(SP)            ; push vertical position
            _MoveTo                     ; position pen
;
; if this item has a sub-menu, then blit an arrow in the command key                    <FJL C222>
; field to indicate its existence .                                                     <FJL C222>
;
            cmpi.b  #HMenuCmd, itemCmd(a4)  ; is there a H Menu?                        <FJL C222>
            bne.s   @NormalCmd              ; no, so do as normal                       <FJL C222>
 
            bsr     BlitHierArrow           ; draw the Hierarchical arrow
 
            bra.s   DrawIText               ; continue                                  <FJL C222>
 
@NormalCmd  MOVE.B  TESysJust+1,D1      ; need special justification?                   <FJL CXXX>
            EXT.W   D1                  ; make it a signed word                         <FJL CXXX>
            BNE.S   @JustifiedCmd       ; => yes                                        <FJL CXXX>
 
            MOVE.W  #commandMark,-(SP)  ; push command mark (propeller)                 <15Feb85>
            _DrawChar                   ; draw the character
            CLR D0                      ; clear high part
            MOVE.B  ITEMCMD(A4),D0      ; get command character
            MOVE.W  D0,-(SP)            ; push command char
            _DrawChar                   ; draw it
            bra.s   DrawIText           ; and continue
 
@JustifiedCmd                           ; draw commandletter/propeller                  <FJL CXXX>
            CLR D0                      ; clear high part
            MOVE.B  ITEMCMD(A4),D0      ; get command character
            MOVE.W  D0,-(SP)            ; push command char
            _DrawChar                   ; draw it
            MOVE.W  #commandMark,-(SP)  ; push command character                        <15Feb85>
            _DrawChar                   ; draw the character
 
; ----------------  draw the text of the item (position in D5)  ----------------------
 
DRAWITEXT
 
            move    #mctRGB2, colorOffset(a6) ; tell SetColors to get the TEXT          <FJL C408>
            bsr     SetColors           ; set colors for text                           <FJL C408>
 
            CLR D0                      ; clear it out
            MOVE.B  ITEMSTYLE(A4),D0    ; push the style parameter
            MOVE.W  D0,-(SP)            ; push style parameter
            _TextFace                   ; get into that face
 
; if there is a script for this font then set it
 
            cmpi.b  #ScriptMenuCmd, itemCmd(a4) ; script for this item?         <FJL CXXX>
            bne.s   @1                  ; no, so skip                           <FJL CXXX>
            move.b  itemIcon(a4), d0    ; pass script number                    <S422   08Mar88 MED>
            bsr     SetScriptFont       ; yes, so set the proper font           <FJL CXXX>
 
@1          MOVE.B  TESysJust+1,D1      ; need special justification?           <11oct85>
            EXT.W   D1                  ; make it a signed word                 <11oct85>
            BNE.S   @DrawIntl           ; => yes                                <27Sep85>
 
            MOVE.W  D5,-(SP)            ; and baseline left                     <27Sep85>
            MOVE.W  D3,-(SP)            ; else push baseline vertical           <27Sep85>
            _MoveTo                     ; push the pen                          <27Sep85>
 
            MOVE.L  A2,-(SP)            ; point to the string                   <27Sep85>
            _DrawString                 ; and draw it                           <27Sep85>
            BRA.S   @2
;
; do International stuff here if TESysJust is negative
;
@DrawIntl   LEA     TempRect,A0         ; build rect for TextBox                <27Sep85>
            SUBQ    #1,D5               ; textBox indents by one                <27Sep85>
            MOVE.W  D3,(A0)             ; get y position                        <27Sep85>
            MOVE.W  MAscent(A6),D0      ; move up to top of rect                <27Sep85>
            SUB.W   D0,(A0)+            ;                                       <27Sep85>
            MOVE.W  D5,(A0)+            ; D5 is left                            <27Sep85>
            MOVE.W  D3,(A0)             ; as top and bottom                     <27Sep85>
            MOVE.W  MDescent(A6),D0     ; and move down to bottom               <27Sep85>
            ADD.W   D0,(A0)+            ;                                       <27Sep85>
            MOVE.W  D6,(A0)             ; and setup right                       <27Sep85>
 
            MOVEQ   #0,D0               ; get length                            <27Sep85>
            MOVE.B  (A2)+,D0            ; into D0                               <27Sep85>
            MOVE.L  A2,-(SP)            ; push text pointer                     <27Sep85>
            MOVE.L  D0,-(SP)            ; and length                            <27Sep85>
            PEA     TempRect            ; push rect of rects                    <27Sep85>
            MOVE.W  D1,-(SP)            ; and justification word                <11oct85>
            _TextBox
 
@2          CLR.L   -(SP)               ; push empty set for TextFace and TextFont
            _TextFace                   ; restore textface to normal
            _TextFont                   ; restore textfont to normal
;
; if the item is disabled, gray it out
;
            BSR     ENABLETEST          ; is it enabled?
            BNE.S   DoneDrawItem        ; branch if it is
            bsr.s   BitClearItem        ; bit clear the item, notice that colors are set properly
 
DoneDrawItem
            bsr     ResetPreviousColors ; restore colors saved in the stackframe <FJL C408>
            MOVEQ   #1, D0              ; Force Z flag off for normal return    <S550   27Jul88 EMT>
 
NoDrawItem                              ;                                       <S550   27Jul88 EMT>
; Z flag is already set                                                         <S550   27Jul88 EMT>
            rts                         ; and return to caller
 
 
;---------------------------------------
;   Utility -- BitClearItem             ; attempt to speed graying of menu items    <FJL 26Jan87>
;---------------------------------------
; Paint the item with gray.  Speed up is about 20%!!
;
;   On Entry:   D4      item number
;
BitClearItem
            movem.l d3/d7, -(sp)        ; save work registers
 
            TST.B   ITEMICON(A4)        ; does it have an icon?
            BEQ.S   @1                  ; skip if it doesnt
            MOVE.W  D7,D0               ; get delta height
            LSR.W   #1,D0               ; divide by 2
            SUB.W   D0,D7               ; and get remainder
            ADD     D7,D3               ; bump the rest of the difference for icon
 
@1          ADD MFHeight(A6),D3 ; bump to next baseline
 
            LEA     TEMPRECT,A0         ; get pointer to temporary rectangle
            MOVE.L  MMenuRect(a6), A1   ; get pointer to menu rect
            MOVE.L  (A1),(A0)           ; copy menuRect into tempRect
            MOVE.L  4(A1),4(A0)
            SUB     MAscent(A6), D3     ; move up by the fon't ascent to get bottom of item
            MOVE    D3, Bottom(A0)      ; store as bottom
 
            Bsr     GetItemHeightA4     ; get item height into D0               <FJL PMAB205>
            Sub.W   D0, D3
            lea     TempRect,a0         ; get rectangle in A0                   <1.7>
            MOVE    D3,top(a0)          ; D3 has the height                     <1.6> <1.7>
            BSR     GRAYRECT            ; bit clear tempRect with gray
 
@ClearDone
            movem.l (sp)+, d3/d7        ; restore work registers
            rts
 
;---------------------------------------
;   Utility -- SetScriptFont
;---------------------------------------
; Input     d0:     script number
;
; set the script's base font.  No need to check if script manager is installed
; since AddResMenu has already done that
;
SetScriptFont
            clr.l       -(sp)               ; make room for long result
;;          clr         d0                  ; clear lo-word
;;          move.b      itemIcon(a4), d0    ; get script number
 
; make d0 an argument, the script number                                    <S422   08Mar88 MED>
 
            and.w       #$00FF,d0           ; get bottom byte for script    <S422   08Mar88 MED>
            move        d0, -(sp)           ; push script number
            move        #smScriptSysFond, -(sp) ; push base font verb
            _GetScript
            move.l      (sp)+, d0           ; get result
            blt.s       @verbErr            ; verb error if d0 < 0
            move        d0, -(sp)           ; push font number
            _TextFont
 
@verbErr    rts
 
;---------------------------------------
;   Utility -- BlitHierArrow
;---------------------------------------
; Blit up the hierarchical arrow
;
BlitHierArrow
 
            movem.l a3/d4, -(sp)            ; store work registers
 
; calculate where arrow should go
            subq    #4, sp
            move.l  sp, -(sp)               ; reserve space on stack for result
            _GetPen
            move.l  (sp)+, d4               ; get y,x
            swap    d4                      ; get x,y
            sub     MAscent(a6), d4         ; move up by the fon't ascent to get top of item
            swap    d4                      ; have top, left of where will blit arrow
            move.l  d4, HierArrowRect(a6)   ; store top, left
            move.l  d4, HierArrowRect+4(a6) ; calculate bottom, right
            move    MFHeight(a6), d4        ; get height
            cmpi    #16, d4                 ; make height/width = 16 unless smaller than 16.<FJL PMAB205>
            ble.s   @1
            move    #16, d4
@1          add     d4, HierArrowRect+Bottom(a6); bottom = top + height
            add     d4, HierArrowRect+Right(a6) ; right = left + width
 
; create bitMap for arrow
            moveq   #bitMapRec, d0          ; alloc bitmap for 16Vert x 16Horiz x 1Deep bit map
            _NewHandle
            _HLock
            move.l  (a0), a3                ; dereference
            move    #2, rowBytes(a3)        ; 16 x 1 bits wide
            move.l  #$00000000,bounds(a3)   ; top = 0, left = 0
            move.l  #$00100010,bounds+4(a3) ; bottom = 0, right = 0
            lea     HierArrow, a1           ; get mask data address
            move.l  a1, baseAddr(a3)        ; store it
 
; get current portRect
CommonBlit  subq    #4, sp
            move.l  sp, -(sp)               ; make space on stack for return
            _GetPort
            move.l  (sp)+, a0               ; get port
 
; copy from the bitMap into the port
            move.l  a3, -(sp)               ; push src bitMap ptr
            pea     portBits(a0)            ; push dest pointer (for the screen)
            pea     bounds(a3)              ; push src bounds rect
            pea     HierArrowRect(a6)       ; push dest bounds rect
            move    #srcOr, -(sp)           ; srcOr
            clr.l   -(sp)                   ; no maskRgn
            _CopyBits
 
            move.l  a3, a0                  ; get bitMap ptr
            _RecoverHandle                  ; get bitMap handle
            _DisposHandle                   ; and toss it
            movem.l (sp)+, a3/d4            ; restore work registers
 
            rts
 
;---------------------------------------
;   Utility -- GetItemRecord
;---------------------------------------
 
;   GetItemRecord is the main utility used for accessing the menu item data structure.
;   It has a register interface to save code.  On entry, A0 points to a menuInfo block,
;   while D0 has the item number of interest.  On exit, A0 points to the item string
;   of interest while A1 points to that item's attribute byte list.  If the item can't
;   be found, A0 and A1 both return NIL.
;
; TODO: If this is called inside a loop, then we have a factorial function!!
;       Therefore look where this is called from and see if we can't be smarter about
;       how to move thru the menulist
 
GETITEMRECORD
            TST D0                      ; make sure item number is valid
            BLE.S   NOITEM              ; if it's not, don't bother
;
            MOVEQ   #0,D1               ; clear D1 for byte arithmetic
            LEA     MENUDATA(A0),A1     ; get menuData handle
            MOVE.B  (A1)+,D1            ; get title length
            ADD     D1,A1               ; skip over title string
;
; here is the item search loop.  A1 points to the beginning of the next item.
;
GETILOOP    SUBQ    #1,D0               ; is this the one we're looking for?
            BEQ.S   GOTITEM             ; if so, we got it
            MOVE.B  (A1)+,D1            ; get length of current item
            BEQ.S   NOITEM              ; length zero marks end of list
;
            ADDQ    #4,D1               ; there are 4 bytes of item properties
            ADD     D1,A1               ; bump to next item
            BRA.S   GETILOOP            ; loop till done
;
;   the item couldn't be found so return NIL
;
NOITEM      SUB.L   A0,A0               ; zero A0
            MOVE.L  A0,A1               ; and A1 too
            MOVE.L  A0,D0               ; and set the z-flag
            CLR.L   lastItemStrPtr(A6)  ; <KSM/RLC  31May89>
            CLR.L   lastAttrPtr(A6)     ; <KSM/RLC  31May89>
            RTS                         ; return to caller
;
; we found the item so return a pointer to it in A0 and a pointer to the item properties
; in A1
;
GOTITEM     TST.B   (A1)                ; is this the NIL item?
            BEQ.S   NOITEM              ; if so, we really didn't get one
;
            MOVE.L  A1,A0               ; A0 points to item string
            MOVE.B  (A1)+,D1            ; get length
            ADD     D1,A1               ; bump to item properties
            MOVE.L  A0,lastItemStrPtr(A6)   ; <KSM/RLC  31May89>
            MOVE.L  A1,lastAttrPtr(A6)      ; <KSM/RLC  31May89>
            RTS                         ; return to caller
 
;----------------------------------------------------------------------------------------
;
;   Msg #2 -- Calc Menu Size
;
;----------------------------------------------------------------------------------------
; Calculate the menu size for the given text menu.  The handle is in A3.
;
; DONE: <FJL PMAB205> Menus with icons did not show scroll arrows properly after you had
;                       scrolled all the way up, then start to scroll down again.  The reason
;                       was that the menu height is not an even multiple of MFHeight.
;                       This code returns an even multiple of MFHeight if the menu scrolls.
 
DoCalcMsg
        IF forRAM THEN
            SUBQ    #4,SP
            MOVE.L  SP,-(SP)                ; point to top of stack
            _GetPort                        ; get the current port
 
;           CMP.W   #$3FFF, ROM85           ; color machine ?                           <PMAB364    23Jan88 EMT>
            TST.B   onColorMachine(A6)      ; color machine ?                           <S394   12Feb88 DBG>
            BEQ.S   @SetBWPort              ;                                           <PMAB364    23Jan88 EMT>
 
            MOVE.L  WMgrCPort, -(SP)        ; get color port                            <PMAB364    23Jan88 EMT>
 
            BRA.S   @SetPort                ;                                           <PMAB364    23Jan88 EMT>
 
@SetBWPort                                  ;                                           <PMAB364    23Jan88 EMT>
            MOVE.L  WmgrPort,-(SP)          ; push the wmgr port, do not use color port here.
 
@SetPort                                    ;                                           <PMAB364    23Jan88 EMT>
            _SetPort                        ; set it                                    <PMAB364    23Jan88 EMT>
        ENDIF   ; if forRAM
 
; since calc msg could be called at any time, we need to reset the wmgr's textfont here else
; could get incorrectly sized menus
 
            clr     -(sp)                   ; clear stack for TextFont                  <FJL CXXX>
            _TextFont                       ; use system font in menus                  <FJL CXXX>
            bsr     GetSizes                ; get font sizes from wmgr port             <FJL CXXX>
 
            SUBQ.L  #4, SP                  ;                                           <PMAB364    23Jan88 EMT>
            MOVE.L  SP, -(SP)               ;                                           <PMAB364    23Jan88 EMT>
            _GetPort                        ; Get the current port                      <PMAB364    23Jan88 EMT>
            MOVE.L  (SP)+, A0               ; Put it in A0                              <PMAB364    23Jan88 EMT>
 
;           MOVE.L  WMgrPort,A0             ; get the port                              <27Sep85>
            MOVE.W  PortRect+bottom(A0),D5  ; get the screen bottom                     <27Sep85>
            SUB.W   portRect+top(A0), D5    ; subtract the top                          <S476   22Apr88 EMT>
 
; the maximum size for a menu is screen height minus menubar height minus a fudge factor.
 
GetMBHeight
            TST.W   ROM85                   ; running on new roms?                      <EHB 26Aug85>
            BMI.S   @0                      ; => no, use old menubar height             <EHB 26Aug85>
            SUB.W   MBarHeight,D5           ; get what low memory says                  <EHB 5Aug85>
            BNE.S   @1                      ; => it's a good height                     <EHB 5Aug85>
@0          SUB.W   #20,D5                  ; else stuff default height                 <EHB 5Aug85>
@1
 
            sub     #16, d5                 ; hierarchical menus need a little more margin  <FJL C222>
 
; make d5 an even multiple of MFHeight so that scrolling with different sized items <FJL PMAB205>
; will work properly.
;+++            dc.w    $a9ff
;+++            Divu    MFHeight(A6), d5    ; (max menu height) div (MFHeight)
;+++            Move    D5,D6               ; get quotient
;+++            MoveQ   #0,D5               ; clear D5
;+++            Move    D6,D5               ; return quotient
;+++            Mulu    MFHeight(A6), D5    ; max menu height = MFHeight x quotient
 
            MOVEQ   #0,D6               ; set initial <height,width> to 0
            MOVEQ   #1,D0               ; find item 1
            MOVE.L  (A3),A0             ; point to the menuRecord
            BSR.S   GetItemRecord       ; point to first item
            BEQ     DoCalcDone1         ; if zero, we're done                           <EHB 10-Apr-85>
            MOVE.L  A0,A4               ; keep pointer in A4
;
; here is the main loop of calcMenuSize.  Process each item one at a time, keeping the
; height and maximum width in D6
;
CMLOOP
            MOVEQ   #0,D7               ; set "extra" width to zero
 
            MOVE.L  (A3),A0             ; handle -> pointer
            MOVEQ   #0,D0               ; clear out high part
            MOVE.B  (A4),D0             ; get length of item
            BEQ     DoCalcDone          ; if zero, we're done with this menu
            LEA     1(A4,D0),A1         ; point A1 at the properties
 
; handle the vertical
 
            BSR     GetItemHeight       ; get height of item into D0
            SWAP    D1                  ; Get width of icon into low word           <S550   27Jul88 EMT>
            MOVE.W  D1, D7              ; Copy width into D7                        <S550   27Jul88 EMT>
            ADD.W   MSpaceWidth(A6), D7 ; Add in width of a single space            <S550   27Jul88 EMT>
 
;           cmpi.b  #ScriptMenuCmd, itemCmd(a1) ; is there a script defined?    <FJL CXXX>
;           beq.s   @0                  ; yes, icon field stores scriptID       <FJL CXXX>
;
;           TST.B   ITEMICON(A1)        ; is there an icon for this item?
;           BEQ.S   @0                  ; if not, don't adjust height
;           MOVEQ   #40,D7              ; add 40 to width for icons
;           MOVEQ   #36,D0              ; and 36 to height for icons            <27Sep85>
;
;           Cmpi.B  #ShrunkenIconCmd, itemCmd(A1)   ; is there a shrunken icon? <FJL PMAB205>
;           Beq.s   @NewWidth           ; yes   -> different width
;           Cmpi.B  #SmallIconCmd, itemCmd(A1)  ; is there a small icon ?
;           Bne.S   @0                  ; no    -> branch
;@NewWidth  MoveQ   #20, D7             ; yes -> width is half size of regular icon
;           Bsr     GetItemHeight       ;       get height into D0
 
@0          SWAP    D6                  ; get vertical into low word                <27Sep85>
            ADD.W   D0,D6               ; increment vertical height                 <27Sep85>
            CMP.W   D5,D6               ; past bottom of screen?                    <27Sep85>
            BLT.S   @1                  ; => no                                     <27Sep85>
            SUB.W   D0,D6               ; yes, don't make menu taller               <27Sep85>
 
; handle the horizontal
 
@1          SWAP    D6                  ; but get vertical in high first            <27Sep85>
            MOVE.W  MWidMax(A6),D1      ; get char width                            <1Aug85>
            ADD.W   D1,D7               ; add once for mark                         <1Aug85>
 
            cmpi.b  #ScriptMenuCmd, itemCmd(a1) ; is there a script defined?        <FJL CXXX>
            beq.s   @2                  ; yes, then no command                      <FJL CXXX>
            cmpi.b  #ShrunkenIconCmd, itemCmd(a1) ; is there a shrunken icon?       <FJL PMAB239>
            beq.s   @2                  ; yes, then no command                      <FJL PMAB239>
            cmpi.b  #SmallIconCmd, itemCmd(a1)      ; is there a small icon defined?    <FJL PMAB239>
            beq.s   @2                  ; yes, then no command                      <FJL PMAB239>
 
            TST.B   ITEMCMD(A1)         ; is there a commmand?
            BEQ.S   @2                  ; if not, skip
            ADD.W   D1,D7               ; add twice for command equivalent          <1Aug85>
            ADD.W   D1,D7               ;                                           <1Aug85>
            ADD.W   #8,D7               ; plus an eight pixel margin                <1Aug85>
@2
            MOVEQ   #0,D1               ; clear out high byte
            MOVE.B  ITEMSTYLE(A1),D1    ; get style setting
 
@3          MOVE.W  D1,-(SP)            ; push the style
            _TextFace                   ; tell LisaGraf about new style
 
;
; If there is a script defined for this item, then set font for proper string width calc,
; do calc, and restore font to #0.
;
            cmpi.b  #ScriptMenuCmd, itemCmd(a1) ; is there a script defined?    <FJL CXXX>
            bne.s   @NoScript           ; yes, icon field stores scriptID       <FJL CXXX>
 
;;          clr     d0                  ; clear it out                          <FJL CXXX>
;;          move.b  itemCmd(a1), d0     ; get scriptID                          <FJL CXXX>
;;          mulu    #512, d0            ; calculate font num = ID*512-512+$4000 <FJL CXXX>
;;          addi    #$3C00, d0          ;                                       <FJL CXXX>
;;          move    d0, -(sp)           ; push font num                         <FJL CXXX>
;;          _TextFont                   ; and set font                          <FJL CXXX>
 
; use utility routine for setting the font from the script
 
            move.b  itemIcon(a1), d0    ; pass script number                    <S422   08Mar88 MED>
            bsr     SetScriptFont       ; set TextFont according to script      <S422   08Mar88 MED>
            
            clr     -(sp)               ; make room for StringWidth result      <FJL CXXX>
            move.l  a4, -(sp)           ; move string pointer                   <FJL CXXX>
            _StringWidth                ; find out the width                    <FJL CXXX>
            clr     -(sp)               ; restore font to normal                <FJL CXXX>
            _TextFont                   ;                                       <FJL CXXX>
            bra.s   @ContCalc           ; and continue with the calculation     <FJL CXXX>
 
@NoScript   CLR     -(SP)               ; make room for stringWidth result
            MOVE.L  A4,-(SP)            ; move string pointer
            _StringWidth                ; find out the width
 
@ContCalc   ADD.W   (SP)+,D7            ; add width to extra
            CMP     D7,D6               ; compare with maxWidth
            BGE.S   CALCNEXT            ; if max is bigger, go process next one
            MOVE    D7,D6               ; this one was the biggest
;
; go process next item; loop till we get a null one
;
CALCNEXT
            MOVEQ   #0,D0               ; zero high part
            MOVE.B  (A4),D0             ; get the length of current item
            LEA     5(A4,D0),A4         ; point to the next item
            BRA     CMLOOP              ; loop till done
 
;   we've scanned all the items update menuHeight and menuWidth
 
DoCalcDone  ADDQ.W  #4,D6               ; add some extra for right margin
DoCalcDone1                             ; if NIL menu, return 0             <EHB 10-Apr-85>
; Ensure that the menu is not too wide.
            SUBQ.L  #4, SP                  ;                                           <PMAB364    23Jan88 EMT>
            MOVE.L  SP, -(SP)               ;                                           <PMAB364    23Jan88 EMT>
            _GetPort                        ; Get the current port                      <PMAB364    23Jan88 EMT>
            MOVE.L  (SP)+, A0               ; Put it in A0                              <PMAB364    23Jan88 EMT>
            MOVE.W  portRect+Right(A0), D0  ; Get right edge                            <PMAB364    23Jan88 EMT>
            SUB.W   portRect+Left(A0), D0   ; Subtract left edge to get width           <PMAB364    23Jan88 EMT>
            SUB.W   #16, D0                 ; Subtract a little more for margin         <PMAB364    23Jan88 EMT>
            CMP.W   D0, D6                  ; Is menu too wide?                         <PMAB364    23Jan88 EMT>
            BLE.S   @1                      ; Nope, move along                          <PMAB364    23Jan88 EMT>
            MOVE.W  D0, D6                  ; Too wide, clip its wings                  <PMAB364    23Jan88 EMT>
@1                                          ;                                           <PMAB364    23Jan88 EMT>
            MOVE.L  (A3),A0                 ; get menu pointer
            MOVE.W  D6,MENUWIDTH(A0)        ; update menu width
            SWAP    D6
 
; if menu is taller than max allowable (which is now an even multiple of MFHeight)  <FJL PMAB205>
; then make it equal to the max allowable.
 
;+++            Cmp.W   D5,D6               ; too tall ?
;+++            Blt.S   @SizeOK             ; => no
;+++            Move.W  D5,D6               ; yes, make it equal to max allowable
@SizeOK
            MOVE.W  D6,MENUHEIGHT(A0)       ; update menu height
 
            CLR.W   -(SP)                   ; better restore style to normal
            _TextFace                       ; set the style
 
        IF forRAM THEN
            _SetPort                        ; restore original grafPort                 <PMAB364    23Jan88 EMT>
        ENDIF   ; if forRAM
 
            rts                             ; all done! so return to dispatcher
 
 
;----------------------------------------------------------------------------------------
;
;   Msg #3 -- Calc TopMenuItem and MenuRect so that the top of PopUpItem is at TopLeft
;
;----------------------------------------------------------------------------------------
; Begin by calculating how far the top of WhichItem is from the top of the menu.
; Then place the menu.  The various possibilities are:
;   1. The whole menu fits on the screen and PopUpItem lines up with TopLeft
;   2. The whole menu fits on the screen and PopUpItem cannot line up with TopLeft without
;       causing the menu to scroll.  In this case adjust menuRect so that complete menu is
;       is on the screen, but PopUpItem is as close to TopLeft as possible.
;   3. The whole menu is not on the screen.  In this case adjust the menuRect so that as much
;       of the menu is showing as possible on the screen, and position PopUpItem so that
;       it is showing and as close as possible to TopLeft.
;
; Return the MenuRect and TopMenuItem.  TopMenuItem is returned in the VAR PopUpItem param.;
;
; Historical Note:  It would be desireable to have popups change vertical size as they scrolled,
;                   instead of having all that white space when the scrolling menu is first
;                   displayed.  The reason for this is due to the design of the MBDF.
;                   The MBDF saves the bits behind and draws the drop shadow at the same
;                   time.  If there were two messages instead, one to save the bits behind
;                   and one to draw the drop shadow, the we could save all of the bits behind
;                   the menurect, from the top of the screen to the bottom, and then change
;                   the menu's vertical height without worrying about saving more bits each
;                   time it got bigger.  But we can't, so...
;
;   <FJL PMAB205> Pass PopUpItem = 0 and force top of menuRect to Top parameter
 
DoPopUpItemMsg
            BSR     GetSizes            ; get font info into the stack
            MOVE.L  MPopUpItem(A6), A4  ; get ptr to PopUpItem
            MOVE    (A4), D3            ; store item in D3
            CLR     D2                  ; top of menu starts at zero
            CLR     D6                  ; ditto
;+++            Tst.W   D3                  ; item == 0 ?                       <FJL PMAB234><FJL PMAB276>
;+++            Beq.S   @LoopComplete       ; yes -> special case               <FJL PMAB234><FJL PMAB276>
                MOVEQ   #1, D4              ; start with first item
 
@Loop       CMP D3,D4                   ; have we reached the PopUpItem yet?
 
            BGT.S   @1                  ; no ==> continue calculating           <FJL PMAB205><FJL PMAB234>
            MOVE    D6, D2              ; yes ==> save item's vertical in D2, and continue
;
; We didn't reach it yet, so get the height and keep stepping down.
;
@1          MOVE.L  (A3),A0             ; get menuPtr
            MOVE    D4,D0               ; get item number
            BSR     GetItemRecord       ; look it up
            BEQ.S   @LoopComplete       ; if item not found then must be end of item list
            BSR     GetItemHeight       ; get item height in D0
            ADD     D0,D6               ; update vertical
 
            ADDQ    #1,D4               ; bump to next item
            BRA.S   @Loop               ; loop till we get to end of item list
 
; If we couldn't find the item then default to item number 1
 
@LoopComplete
            TST     D2                  ; is D2 still zero ?
            BNE.S   @GotItem            ; no ==> got the item, and it's vertical is in D2
            MOVEQ   #1, D4              ; yes ==> couldn't find item, use item #1
 
; Distance from top of menu to top of PopUpItem is now in D2.
 
@GotItem    MOVE.L  (A3), A0            ; get menu ptr
            TST.L   MenuWidth(A0)       ; is the size valid?
            BPL.S   @SkipCalcSize       ; yes, so no need to recalc (oooohhhh, recursion)
            MOVE.L  D2, -(SP)           ; Save D2 around call <S171 DBG&JTC 08Apr87>
            MOVE.L  A3, -(SP)           ; push menu handle
            _CalcMenuSize               ; get valid height and width
            MOVE.L  (SP)+, D2           ; Restore D2 <S171 DBG&JTC 08Apr87>
 
@SkipCalcSize
;
; First check if menu has to scroll, i.e. its height is larger than the screen size
; minus 8 pixels of slop.  <FJL PMAB205, no longer include menubar height in this calc>
;
; Register Usage:-- A0      menuRect ptr
;                   A1      port ptr
;                   A2      menu ptr
;                   A3      menu handle
;                   A4      PopUpItem ptr
;               -- D2       Distance from top of menu to PopUpItem
;                   D3      PopUpItem
;                   D4      TopMenuItem
;                   D5      Desired top of PopUpItem, the "Top" in MLeftTop
;                   D6      Total menu height, including all menu items
;
            SUBQ    #4, SP              ; get current portRect
            MOVE.L  SP, -(SP)           ; make space on stack of return
            _GetPort
            MOVE.L  (SP)+, A1           ; put port in A1
 
            MOVE.L  MMenuRect(A6), A0   ; put ptr to menuRect in A0
            MOVE.L  (A3), A2            ; put menu ptr in A2
            MOVE    MLeftTop+2(a6), D5  ; put desired Top of PopUpItem in D5
            MOVE    D5, D4              ; put TopMenuItem = D5 - D2 in D4
            SUB     D2, D4
 
            Cmpi.w  #0, D3              ; is PopUpItem = 0 ?                    <FJL PMAB205>
            Bne.s   @StdPopUp           ; no    -> branch
            Move    portRect+Bottom(A1),D0  ; calc max allowable menu height = bottom of
            Sub     D5, D0                  ;   screen - 8 - Top of PopUpItem
            Sub     #8, D0
            Cmp     D6, D0              ; is max allowable menu height < total menuHeight ?
            Blt.s   @HasToScroll
            Bra.S   @WontScroll
 
@StdPopUp   MOVE    portRect+Bottom(A1),D0  ; calculate max allowable menu height based on
            SUB     portRect+Top(A1), D0    ;   screen height - 8 pixels of slop
            SUB     #8, D0
            CMP     D6, D0              ; is max allowable menu height < total menuHeight ?
            BLT.S   @HasToScroll        ; yes ==> has to scroll
 
;-------------------------------------------------------------------------------------------------
; If here, then the complete menu WILL fit on the screen
;-------------------------------------------------------------------------------------------------
; Check the following possibilities:
;   1. Top and bottom are both on the screen ==> leave it alone, PopUpItem and TopLeft will match
;   2. Top is on screen, bottom is not ==> move bottom of menurect up until it is at least
;           5 pixels above the bottom of the screen.  Leave TopMenuItem alone
;   3. Bottom is on screen, top is not ==> move top of menurect down until it is at least
;           5 pixels below the top of the screen.  Leave TopMenuItem alone
 
@WontScroll MOVE    D4, Top(A0)         ; assume TopMenuItem, and top and bottom of menu are ok
            MOVE    D4, (A4)            ; return TopMenuItem in VAR PopUpItem
            MOVE    D4, Bottom(A0)
            ADD     D6, Bottom(A0)
 
            MOVE    portRect+Top(A1),D0 ; get the top of the screen
            ADD     MBarHeight, D0      ; move down 2 pixels from menubar
            ADD     #2, D0
            CMP     D0, D4              ; is TopMenuItem < 2 pixels below menu bar?
            BGE.S   @ChkBottom          ; no ==> therefore Top is ok
 
                                        ; yes ==> therefore move top down by multiple of MFHeight
                                        ;           until we get at least 2 pixels below the menu bar
            MOVE    D4, D1              ; start at TopMenuItem
@TopLoop    ADD     MFHeight(a6), D1    ; move down to next item
            CMP     D0, D1              ; is top of menu >= 2 pixels below menu bar?
            BLT.S   @TopLoop            ; no    ==> haven't moved top down far enough yet
            MOVE    D1, Top(A0)         ; yes ==> store new top
            ADD     D6, D1
            MOVE    D1, Bottom(A0)      ; store bottom of menu
            BRA.S   @AdjustLeftRight    ; do left/right adjustment                      <PMAB364    23Jan88 EMT>
 
@ChkBottom  MOVE    D4, D0              ; find bottom of menu = TopMenuItem + total menu height
            ADD     D6, D0
            MOVE    portRect+Bottom(A1),D1  ; calc bottom of screen - 5 pixels
            SUB     #5, D1
            CMP     D1, D0              ; is Bottom of menu > 5 pixels above screen bottom ?
            BLE.S   @AdjustLeftRight    ; no ==> therefore Bottom is ok too             <PMAB364    23Jan88 EMT>
 
                                        ; yes ==> move bottom up by multiple of MFHeight until
                                        ;           we get at least 5 pixels above the screen bottom
@BotLoop    SUB     MFHeight(a6), D0    ; move up to next item
            CMP     D1, D0              ; is bottom of menu <= 5 pixels above screen bottom ?
            BGT.S   @BotLoop            ; no    ==> haven't moved bottom up far enough yet
            MOVE    D0, Bottom(A0)      ; store bottom
            SUB     D6, D0              ; calc top of menu
            MOVE    D0, Top(a0)
            BRA.S   @AdjustLeftRight    ; do left/right adjustment                      <PMAB364    23Jan88 EMT>
 
;-------------------------------------------------------------------------------------------------
; If here then the complete menu WILL NOT fit on the screen
;-------------------------------------------------------------------------------------------------
; Leave TopMenuItem alone, but calculate where menurect should go so that when the items scroll
; they fill up the menu exactly, i.e. as the menu is scrolled, TopMenuItem will match the
; top of the menu rect at some point exactly.  If we don't do this there may be strange
; behavior when the menu is scrolled completely down, i.e. the top item is showing.
;
; If PopUpItem = 0 then force top of menu to be at Top/Left         <FJL PMAB205>
;
;
@HasToScroll
            MOVE    D4, (A4)            ; return TopMenuItem in VAR PopUpItem
 
            Move    D4, D1              ; set up D1                             <FJL PMAB205>
            Move    D1, Top(A0)         ; assume PopUpItem = 0 and store Top of menuRect
            Cmpi.w  #0, D3              ; is PopUpItem = 0 ?
            Beq.s   @CalcBottom         ; yes   -> branch and only calc the bottom of the rect
 
            MOVE    portRect+Top(a1), D0; calc 2 pixels below the top of the screen <FJL PMAB205>
            ADDQ    #2, D0              ;
            CMP     D0, D4              ; is TopMenuItem >  2 pixels below top of screen?
            BLE.S   @CalcBelow          ; no    ==> branch and calc top of menuRect as
                                        ;           (MFHeight x N) **BELOW** TopMenuItem
                                        ; yes ==> fall thru and calc top of menuRect as
                                        ;               (MFHeight x N) **ABOVE** TopMenuItem
;
; Start at TopMenuItem, and move **UP** by increments of MFHeight until we reach at
;   least 2 pixels below the menubar.
;
            MOVE    D4, D1              ; start at TopMenuItem
@UpLoop     SUB     MFHeight(a6), D1    ; move up one MFHeight
            CMP     D0, D1              ; is top of menu rect < 2 pixels below the menubar ?
            BGE.S   @UpLoop             ; no    ==> keep moving up
            ADD     MFHeight(a6), D1    ; yes ==> force top of menurect to be on the screen
            MOVE    D1, Top(a0)         ; store top of menurect
            BRA.S   @CalcBottom         ; calc bottom of menurect
 
;
; Start at TopMenuItem, and move **DOWN** by increments of MFHeight until we reach at
;   least 2 pixels below the menubar.
;
@CalcBelow  MOVE    D4, D1              ; start at TopMenuItem
@DownLoop   ADD     MFHeight(a6), D1    ; move down one MFHeight
            CMP     D0, D1              ; is top of menu rect >= 2 pixels below the menubar ?
            BLT.S   @DownLoop           ; no    ==> keep moving down
            MOVE    D1, Top(a0)         ; store top of menurect
;
; Start at top of menurect and move down by multiples of MFHeight until the bottom of the
;       menurect is about 5 pixels above the screen bottom.  This makes the menurect an exact
;   multiple of MFHeight.
;
@CalcBottom MOVE    portRect+Bottom(a1), D0 ; calc 5 pixels above screen bottom
            SUBQ    #5, D0
@BotLoop2   ADD     MFHeight(a6), D1    ; move down by one MFHeight
            CMP     D0, D1              ; is bottom of menurect > 5 pixels above screen bottom ?
            BLE.S   @BotLoop2           ; no    ==> keep moving down
            SUB     MFHeight(a6), D1    ; yes ==> force bottom of menurect onto the screen
            MOVE    D1, Bottom(a0)      ; store bottom of menuRect
 
;-------------------------------------------------------------------------------------------------
; Now adjust menuLeft and menuRight if menu hangs over left or right edge of the screen.
;-------------------------------------------------------------------------------------------------
 
@AdjustLeftRight
            MOVE    MLeftTop(A6), D0    ; get left edge
            MOVE.W  portRect+Left(A1), D2   ; Get left edge of screen                   <PMAB364    23Jan88 EMT>
            ADDQ.W  #4, D2              ; Leave room for border                         <PMAB364    23Jan88 EMT>
            CMP.W   D2, D0              ; Compare with left edge of screen              <PMAB364    23Jan88 EMT>
            BGE.S   @TryRight           ; If greater, it's OK                           <PMAB364    23Jan88 EMT>
 
; Adjust so the menu fits on the screen.
            MOVE    D2, D0              ; make left edge equal to (fake) screen edge    <PMAB364    23Jan88 EMT>
 
@TryRight
            MOVE.W  D0, D1              ;                                               <PMAB364    23Jan88 EMT>
            ADD.W   MenuWidth(A2), D1   ; calc right edge                               <PMAB364    23Jan88 EMT>
            MOVE.W  portRect+Right(A1), D2  ; Get right edge of screen                  <PMAB364    23Jan88 EMT>
            SUBQ.W  #4, D2              ; Leave room for border                         <PMAB364    23Jan88 EMT>
            CMP.W   D2, D1              ; Compare with right edge of screen             <PMAB364    23Jan88 EMT>
            BLE.S   @StoreLeftRight     ; if smaller, we're cool
 
; Adjust so the menu fits on the screen.
            MOVE    D2, D1              ; make right edge equal to (fake) screen edge   <PMAB364    23Jan88 EMT>
            MOVE.W  D1, D0              ;                                               <PMAB364    23Jan88 EMT>
            SUB.W   menuWidth(A2), D0   ; left = right - menuWidth                      <PMAB364    23Jan88 EMT>
 
@StoreLeftRight
            MOVE.W  D0, Left(A0)        ; store left                                    <PMAB364    23Jan88 EMT>
            MOVE.W  D1, Right(A0)       ; store right                                   <PMAB364    23Jan88 EMT>
            RTS
 
;----------------------------------------
;   Utility -- SaveCurrentColors                                            <FJL C408>
;----------------------------------------
; Save the current fore/back colors in the stackframe.
; Get the device's pixel depth in the stackframe too.
; Only need to save if color machine
 
SaveCurrentColors
 
;>>>>>------------- NuMac ------------------>>>>>
 
;+++        IF  onNuMac THEN
            tst.b   onColorMachine(a6)
            beq.s   @SaveEnd
 
            pea     saveForeColor(a6)   ; push location to save fore color
            pea     saveBackColor(a6)   ; push location to save back color
            _GetBackColor               ; and get 'em
            _GetForeColor
 
 
            SUBQ    #4,SP
            MOVE.L  SP,-(SP)                ; point to top of stack
            _GetPort                        ; get the current port
            move.l  (sp)+, a0
 
            subq    #4, sp                  ; space for GDHandle return
            pea     portRect(a0)            ; draw menus on main screen
            _GetMaxDevice                   ; get max pixel device
            MOVE.L  (sp)+, A0               ; get the grafDevice
            MOVE.L  (A0),A0                 ; hndl->ptr
            MOVE.L  GDPMap(A0),A1           ; get the device's pixmap
            MOVE.L  (A1),A1                 ; hndl->ptr
            move.w  pixelSize(a1), PixelDepth(a6)   ; and store the value
 
;+++        ENDIF
 
@SaveEnd
 
;<<<<<--------------------------------------<<<<<
 
            rts
 
;----------------------------------------
;   Utility -- ResetPreviousColors                                          <FJL C408>
;----------------------------------------
; Restore the fore/back colors from those saved
; in the stackframe in SaveCurrentColors.
; Need to reset on both color and b/w machines.  Assume b/w machine always have
; black on white.
 
ResetPreviousColors
 
;>>>>>------------- NuMac ------------------>>>>>
 
;+++        IF  onNuMac THEN
            tst.b   onColorMachine(a6)
            beq.s   @ResetBW
 
            pea     saveForeColor(a6)   ; push location of saved fore color
            pea     saveBackColor(a6)   ; push location of saved back color
            _RGBBackColor
            _RGBForeColor
            bra.s   @ResetEnd
 
;+++        ELSE                            ;===============================================
@ResetBW
            moveq   #BlackColor, d0     ; always reset to black on white
            move.l  d0, -(sp)
            _ForeColor
            moveq   #WhiteColor, d0
            move.l  d0, -(sp)
            _BackColor
 
;+++        ENDIF
 
;<<<<<--------------------------------------<<<<<
@ResetEnd
            rts
 
;----------------------------------------
;   Utility -- SetColors                                                    <FJL C408>
;----------------------------------------
;
; On Entry:     A3                  MenuHandle
;               D4                  Item Number
;               colorOffset(a6)     Offset into menu color table indicating mark/text/cmd
; Used:     A0, D1
 
SetColors
 
;>>>>>------------- NuMac ------------------>>>>>
 
;+++        IF  onNuMac THEN
            tst.b   onColorMachine(a6)
            beq     @SetBW
 
            cmpi.w  #2, PixelDepth(a6)  ; is this 2+ mode and color ?
            blt.s   @SetDefault         ; if 1 bit mode then use Black/White only
 
            tst     invertFlag(a6)      ; normal or inverted colors ?
            beq.s   @1                  ; 0 = normal colors, so branch
 
; for inverted menu colors always invert the background color with the item name's color
            move    #mctRGB2, colorOffset(a6)
 
@1
            subq    #4, sp              ; save space for result
            move.l  (a3), a0            ; get menu ptr
            move    menuID(a0), -(sp)   ; push ID
            move    d4, -(sp)           ; push Item
            _GetMCEntry                 ; get item's color entry
            move.l  (sp)+, d1           ; get the result, and set/un-set z-flag
            beq.s   @TryTitleEntry      ; couldn't find item entry so try title entry
 
            move.l  d1, a0              ; get color record ptr in A0
            move    colorOffset(a6), d0 ; offset for mark/cmd/char
            pea     (a0, d0)            ; push foreground color
            pea     mctRGB4(a0)         ; push background color
            bra.s   @DoTheSet           ; branch to do actual color setting
 
@TryTitleEntry
            subq    #4, sp              ; save space for result
            move.l  (a3), a0            ; get menu ptr
            move    menuID(a0), -(sp)   ; push ID
            clr     -(sp)               ; Item = 0 ===> title entry
            _GetMCEntry                 ; get title's color entry
            move.l  (sp)+, d1           ; get the result, and set/un-set z-flag
            beq.s   @TryMenuBarEntry    ; couldn't find title entry so try menu bar entry
 
            move.l  d1, a0              ; get color record ptr in A0
            move    #mctRGB3, d0        ; offset for items default color
            pea     (a0, d0)            ; push foreground color
            pea     mctRGB4(a0)         ; push background color
            bra.s   @DoTheSet           ; branch to do actual color setting
 
@TryMenuBarEntry
            subq    #4, sp              ; save space for result
            clr.l   -(sp)               ; ID = 0, Item = 0 ===> menu bar entry
            _GetMCEntry                 ; get menu bar's color entry
            move.l  (sp)+, d1           ; get the result, and set/un-set z-flag
            beq.s   @SetDefault         ; couldn't find menu bar entry so use black/white
 
            move.l  d1, a0              ; get color record ptr in A0
            move    #mctRGB3, d0        ; offset for items default color
            pea     (a0,d0)             ; push foreground color
            pea     mctRGB2(a0)         ; push background color
            bra.s   @DoTheSet           ; and branch to do the actual color setting
 
@SetDefault
            pea     RGBBlack            ; use black as default forecolor
            pea     RGBWhite            ; use white as default background color
 
@DoTheSet   tst     invertFlag(a6)      ; normal or inverted colors ?
            beq.s   @2                  ; 0 = normal colors, so branch
 
            _RGBForeColor               ; set fore/back colors
            _RGBBackColor
            bra.s   @SetColorsDone
 
@2          _RGBBackColor               ; set back/fore colors
            _RGBForeColor
 
            bra.s   @SetColorsDone
 
;+++        ELSE                            ;===============================================
@SetBW
            moveq   #BlackColor, d0
            move.l  d0, -(sp)
            moveq   #WhiteColor, d0
            move.l  d0, -(sp)
 
            tst     invertFlag(a6)      ; normal or inverted colors ?
            beq.s   @3                  ; 0 = normal colors, so branch
 
            _ForeColor
            _BackColor
            bra.s   @SetColorsDone
 
@3          _BackColor
            _ForeColor
 
;+++        ENDIF
 
;<<<<<--------------------------------------<<<<<
 
@SetColorsDone
 
            rts
 
;-----------------------------------------------------------------------------------------------
; PROCEDURE PlotAnySizeIcon(theRect: Rect; theIcon: IconHandle; iconSize: Point;
;                           rowBytes: Integer)                                      <FJLPMAB205>
;
;   Plots a given icon of arbitrary size at a given place in your local coordinate system.
;
 
PlotAnySizeIcon
                LEA     ICONBITMAP,A1           ;get address of icon mgr bitMap
                MOVE.L  10(SP),D0               ;get the icon handle
                BEQ.S   DONEIPLOT               ;if NIL, dont plot
                MOVE.L  D0,A0                   ;get iconHandle in address reg
;
                MOVE.L  (A0),(A1)+              ;icon mptr is the base address
                MOVE    4(sp),(A1)+             ;set up rowBytes
                CLR.L   (A1)+                   ;set up topLeft
                MOVE.L  6(SP),(A1)              ;set up botRight
;
                MOVE.L  14(SP),D1               ;get theRect
                LEA     IconBitMap,A1           ;point A1 at bitmap again
;
; push parameters for copyBits call
;
                MOVE.L  A1,-(SP)                ;source bitMap is iconBitMap
                MOVE.L  GrafGLOBALS(A5),A0      ;get lisaGraf global baseaddress
                MOVE.L  THEPORT(A0),A0          ;get thePort
                PEA     PORTBITS(A0)            ;that's the destination bitmap
;
                PEA     BOUNDS(A1)              ;boundsRect of bitmap is source
                MOVE.L  D1,-(SP)                ;theRect is the destination
                CLR.W   -(SP)                   ;theMode is srcCopy (0)
                CLR.L   -(SP)                   ;no mask region
                _CopyBits                       ;let Bill blit those bits
 
DONEIPLOT       MOVE.L  (SP)+,A0                ;get return address
                ADD     #14,SP                  ;strip 12 bytes of parameters
                JMP     (A0)                    ;return to caller
 
;
;--------------------------------------------------------------------------------------------
;
;   End of Code.  Begin Data Definitions.
;
;--------------------------------------------------------------------------------------------
 
            ; bounds rect for hier arrow is top=0, left=0, bottom=$10, right=$10
 
HierArrow   DC.W    $0000, $0000, $0020, $0030, $0038, $003C, $003E, $003F
            DC.W    $003E, $003C, $0038, $0030, $0020, $0000, $0000, $0000
 
            ; bounds rect for down arrow is top=0, left=0, bottom=$10, right=$10
 
DownArrow   DC.W    $0000, $0000, $0000, $0000, $0000, $7FF0, $3FE0, $1FC0
            DC.W    $0F80, $0700, $0200, $0000, $0000, $0000, $0000, $0000
 
            ; bounds rect for up arrow is top=0, left=0, bottom=$10, right=$10
 
UpArrow     DC.W    $0000, $0000, $0000, $0000, $0000, $0200, $0700, $0F80
            DC.W    $1FC0, $3FE0, $7FF0, $0000, $0000, $0000, $0000, $0000
 
            END                     ; of menu defproc!!