; ; File: StandardMBDF.a ; ; Contains: menu bar definition procedure ; ; Written by: David Fung ; ; Copyright: © 1986-1992 by Apple Computer, Inc., all rights reserved. ; ; ; Change History (most recent first): ; ; 10/22/92 CSS Change some branch short instructions to word branches. ; <49> 4/30/92 DTY #1027995 : SetTitleColor expects a4 to point to a MenuInfo ; record on entry. The BannerMsg routine calls SetTitleColor ; without setting up a4. This kinda makes sense, since the menu ; bar doesnΥt have a MenuInfo record. However, if A4 contains ; trash, an error will occur. Make a4 nil in BannerMsg, and have ; SetTitleColor check to see if A4 contains nil. If it is, jump ; directly to @TryMenuBar. ; <48> 4/4/92 KSM #1019367,: Allow for slop factor before dropping System ; menus when app menus are too long. ; <47> 10/28/91 SAM/KSM Rolled in Regatta file. ; ; Regatta Change History: ; ; <3> 8/8/91 SAM Adding HardwarePrivateEqu.a ; <2> 5/28/91 SAM Removed Gestalt check for Square menu bar cuz this code gets called ; so frquently. Replaced it with a slightly less cool lomem check. ; <1> 8/8/91 SAM Split off from 7.0 GM sources. ; ; 7.0 Change History: ; ; <46> 6/11/91 gbm Take out conditional for Regatta... we want that to be ; "standard" now ; <45> 4/3/91 SAM Added GestaltEqu.a to the list of includes (for the Regatta ; build). ; <44> 4/2/91 SAM Changed the "If we have a Portable ROM then dont round the menu ; bar corners" check to ask Gestalt if there should be square menu ; bars (for the Regatta build). ; <43> 4/2/91 VL KSM,#86088: Fixed the problem of a crash drawing an icon to the ; Application Menu when the Application Menu is not in the ; MenuList. This is done by adding another exit condition to the ; loop finding the Application Menu. ; <42> 3/21/91 KSM dty,#84128: If DrawMenuBar is called with a hilited title, it ; will only restore the bits of the hilited menu. ; <41> 3/19/91 KSM ngk,#83253: BUT Gifford showed why letting the TITLE bits be ; purgable was not too swift. ; <40> 3/13/91 KSM ddc,#83253: Call SaveRestoreBits with purgable bits option (why ; didnΥt we do this before?) ; <39> 3/4/91 dba dty: get rid of SysVers conditionals ; <38> 2/22/91 VL KSM, #82413: ClipToTempRect didn't respect MBarHeight and that ; caused icons to be drawn even when the MBar is not visible (i.e. ; MBarHeight = 0). Fixed ClipToTempRect to use the minimum of ; MBarHeight and actual height of TempRect. ; <37> 1/21/91 DFH (KSM) Process Menu is now called Application Menu. ; <36> 1/7/91 JDR (dba) Changing the includes of Icons.a to IconUtilsPriv.a. ; <35> 11/13/90 KSM Remove some deadwood (redundant compare). ; <34> 9/23/90 KSM Fix a hit testing bug when no system menus are installed. ; <33> 9/19/90 KSM Fix MBDF to not call PenMode (supposed to call TextMode). ; <32> 9/15/90 KSM Better plotting of color apple menu icon. ; <31> 9/11/90 KSM Fix to BannerMsg- calls HiliteMenu(0) before drawing the menubar ; string to prevent the flash of dehiliting the menu later. ; <30> 9/6/90 KSM Change CALC (#2) message to add system menus iff there is an ; apple menu. Fix up some TO DO's to be current. ; <29> 8/17/90 dvb grayishTextCopy->grayishTextOr ; <28> 8/14/90 KSM Oops, fix the previous fix. ; <27> 8/10/90 PN Fix graying for non-color machines since drawstring on these ; machines does not recognize _PenPat(grayishtext). ; <26> 8/9/90 DC changed apple menu to use Icon Suite in stead of cicn. Fixed up ; color handling of icons again. ; <25> 8/6/90 DC fixed color environment arount ploticonsuite to allow for menu ; colorizers (Kolor, et al.) ; <24> 7/26/90 KSM fix hierarchical menu title hiliting bug by ignoring the ; parameter when told to unhilite a menu title ; <23> 7/20/90 DVB Fix for classic machines... ; <22> 7/17/90 DVB Add grayish items ; <21> 7/16/90 VL Added new messages (MoveICSToAM, MoveSICNToPM and MoveICSToPM) ; for Notification Mgr. MoveSIcon is renamed to MoveSICNToAM. ; <20> 6/8/90 dba use Begin/EndDrawingOffscreen ; <19> 6/8/90 dba create code for buffering redraws of the whole menu bar to avoid ; flicker; made many branches short ones ; <18> 6/5/90 KSM FIx bug in drawing menu items when 2 (or more) system menus are ; not draw because the app menus have encroached upon it (A11 ; fix). ; <17> 5/31/90 KSM Bug fix in HitBar-high word of D4 not cleared. Tweek system ; menus left 1 pixel for rt just. Also fixed A10 bugs MF(A6). ; Fixed IconUtils to be Icons.a ; <16> 5/31/90 KSM Bug fix in HitBar-high word of D4 not cleared. Tweek system ; menus left 1 pixel for rt just. Also fixed A10 bugs MF(A6). ; Fixed IconUtils to be Icons.a ; <15> 5/22/90 DC Changed name of PlotBestIcon to PlotIconSuite ; <14> 5/9/90 KSM New message (#15): BannerMsg (for Finder). ; <13> 5/9/90 KSM New message (#14) added: GetTitleRect. ; <12> 5/7/90 KSM Rect for system menus are now aligned with right side of title ; hilite. ; <11> 4/30/90 KSM Handle all the nasty issues when the app menus begin to encroach ; on system menus. ; <10> 4/29/90 KSM Changed the routine dispatch table to use the stack frame macros ; (since I'm about to add new calls). Forced drawing apple in B&W ; when monitor is in multi-bit B&W mode to avoid the ugly, striped ; apple. Cleaned up rectangle calcs for hilighting titles. Apple ; menu and Application Menu are now perfectly symmetrical. ; <9> 4/24/90 dba fix error I made in previous change (move addq.w inside the ; conditional) ; <8> 4/21/90 dba I is a idiot; it instead of if ; <7> 4/20/90 dba get rid of the two special anti-aliased color icons for apple on ; black and apple on white ; <6> 4/20/90 KSM Fix bug munging locked menulist handle. Use new interface to ; SaveRestoreBits calls. ; <5> 4/13/90 DFH Fixed DrawCommon to properly transform iconic title ; when hilighted. ; <4> 4/11/90 KSM Update calls to _GetAuxMenuItem to include itemnum param and add ; support for color icons. ; <3> 4/10/90 dba use SaveBits and RestoreBits; use fancy color Apple icons; ; include KevinΥs changes to support system menus; added support ; for icon menu titles; put in stupid kludge to make things work ; on the Mac II ; <2> 1/31/90 RLC Update HelpMgr calls and conditionally build in macros. ; <2.2> 9/26/89 CCH Added conditionals around references to SysVers equate for ROM. ; Minor fixes to changes from version 2.1 (hierarchical menu ; placement). ; <2.1> 9/25/89 DFH Added ExpandItem to get extra menu item information. ; <2.0> 8/29/89 RLC Changed calling structure to the HelpMgr (_Pack14). ; <1.9> 8/22/89 SES Removed references to nFiles. ; <1.8> 8/12/89 dba NEEDED FOR 6.0.4: reintroduced a bug fix lost in the transition ; from 6.0.3 sources; fixes problems with hierarchical menus above ; the menu bar ; <1.7> 8/10/89 RLC Changed selector message to Help Mgr Pack to MOVEQ #select,D0 ; <1.6> 6/2/89 KSM Updated conditionals for ROM/SYS build AGAIN. ; <1.5> 6/2/89 KSM Updated conditionals for ROM/SYS build. ; <1.4> 6/1/89 KSM BALLOON HELP support added. ; <1.3> 3/1/89 MSH Dave F provided the first pass at external video support ; (Topanga) and I tweaked it until it worked. ; <1.4> 2/10/89 DAF Modified MBDF for Harpo. This includes a number of ; modifications: 1) onLCDMac stack variable created to identify ; Harpo. 2) Rounded corner framing draws white or black depending ; on video mode iff on Harpo 3) Menubar is framed if on Harpo ; internal display, is one pixel taller, and titles start one ; pixel in. ; <1.2> 2/9/89 EMT Courtesy Walter Smith, fixed bug in GetMenuAscent. ; <1.1> 11/11/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <₯1.2> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles ; <₯1.1> 3/22/88 EMT Roll in menu manager patches from 6.0 system. ; 3/9/88 EMT Fix empty menu bug ; PMAB364> 1/23/88 EMT Fix Pop-up menus to come up on any screen ; 1/12/88 EMT Fix orphaned handles in MBDF ; 12/15/87 EMT Remove call to PurgeSpace in MBDF ; 12/3/87 EMT MBDF now uses MultiFinder temporary memory allocation. ; 10/20/87 EMT Change FullClip to use QD wideOpen region. Modify Draw message ; to include single title draw. Added MoveSIcon message for ; Notification Manager. Miscellaneous optimizations. ; ; System 4.2 ; ; 7/20/87 FJL MoveQ #0,D0 in several places to ensure parameter to _NewHandle ; is ok. ; 3/26/87 FJL Save and restore pen state for the application Tempo. ; 3/6/87 FJL Clean up all OnNuMac conditionals for System Disk --> Universal ; defproc ; 2/10/87 FJL C784 Leave TextMode srcOr, fixes BusFileVision ; 11/18/86 FJL A428 Lock handle for non-nuMac in SaveDemBits. Change ; DrawMenuBar so draws selected item after all titles are drawn, ; rather than in loop. ; 11/15/86 FJL C408 Added support for color menus ; 11/5/86 FJL CXXX General clean up and documentation. ; 10/27/86 FJL A278 Force menu font to be system font at all times. Hacked up ; HiliteMenu so it inverts/inverts on menu select/unselect for ; Alladin. (removed during clean up) ; 10/8/86 FJL C175 Expanded stackframe. Lock and unlock MenuList handle. ; Utility GetAscent. Fixed DrawMenu loop, and HiliteBar. Added ; 4-bit color apple. Utility CheckForApple. Fixed SaveBits ; problem. Fixed incorrect rect size in MakeUpdate. ; 9/15/86 DAF New today ; ; FUNCTION MenuBarProc ( selector: INTEGER; ; message: INTEGER; ; parameter1: INTEGER; ; parameter2: LONGINT): LONGINT ; ; Msg Selector Param1 Param2 Result ;--------- -------------- -------------- -------------- ------------- ; 0 Draw mbVariant none -1 = clear none ; 0 = all none ; = 6 B.O. none ; 1 Hit mbVariant none mouse point 0 = in bar, no hit ; -1= not in bar ; = 6 B.O. ; 2 Calc mbVariant none 0 = all none ; = 6 B.O. none ; 3 Init mbVariant none size none ; 4 Dispos mbVariant none none none ; 5 Hilite mbVariant none none ; 6 Height mbVariant none none none ; 7 Save mbVariant 6 B.O. ptr to menuRect none ; 8 Restor mbVariant none none none ; 9 GetRect mbVariant none ptr to menuRect ;10 SaveAlt mbVariant none 6 B.O. none ;11 ResetScroll mbVariant none 6 B.O. none ;12 GetMenuRgn mbVariant none region handle region handle ;13 MoveSICNToAM mbVariant distance sicon handle 0 = keep current icon ; 0=replace 0 = use title -1 = go to next icon ;14 GetTRect mbVariant = 6 B.O. ptr-to-menuRect none ; 0 = MenuBarRect ; -1 = Rect enclosing visible app menus ; -2 = Rect enclosing visible system menus ;15 BannerMsg mbVariant ptr to pString none ; lo byte=scriptID ; hi byte=teJust for textbox ;16 MoveICSToPM mbVariant distance ics handle 0 = keep current icon ; 0=replace 0 = use title -1 = go to next icon ;17 MoveICSToAM mbVariant distance ics handle 0 = keep current icon ; 0=replace 0 = use title -1 = go to next icon ;18 MoveSICNToPM mbVariant distance SICN handle 0 = keep current icon ; 0=replace 0 = use title -1 = go to next icon ; ; NOTES: 6 B.O. == 6 byte offset into menuList ; == hiword -- 0=normal, 1=selected, 2=disabled, 3=busy, ; 128+=SICN rsrcID to be blitted ; loword -- 0=flip bar, positive value=6 byte offset ; == hiword -- if =0 then is normal menu, ; else contains vertical mouse pt for HMenu top calc ; loword -- 6 B.O. ; ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ LOAD 'StandardEqu.d' INCLUDE 'InternalMacros.a' INCLUDE 'MFPrivate.a' INCLUDE 'IconUtilsPriv.a' INCLUDE 'MenuMgrPriv.a' INCLUDE 'Balloons.a' INCLUDE 'GestaltEqu.a' INCLUDE 'HardwarePrivateEqu.a' selectBeginDrawingOffscreen EQU 4 paramWordsBeginDrawingOffscreen EQU 4 MACRO _BeginDrawingOffscreen DoDispatch _SaveRestoreBits,selectBeginDrawingOffscreen,paramWordsBeginDrawingOffscreen ENDM selectEndDrawingOffscreen EQU 5 paramWordsEndDrawingOffscreen EQU 2 MACRO _EndDrawingOffscreen DoDispatch _SaveRestoreBits,selectEndDrawingOffscreen,paramWordsEndDrawingOffscreen ENDM if &type('useAntiAliasedApples') = 'UNDEFINED' then useAntiAliasedApples: equ 0 endif MACRO _DMSG &msg if &msg = '' then _Debugger else BRA.S @overstring @dbgStrBase: DC.B &msg ALIGN 2 @overstring: PEA @dbgStrBase _DebugStr endif ENDM ;-------------------------------------------------------------------------------------------- ; value for itemIconSize (but not itemCmd) <2.1> LargeIconCmd EQU $1F ; large icon plotted ; special values of the itemCmd field before expansion <2.1> ShrunkenIconCmd EQU $1D ; itemCmd == $1D ==> large icon plotted in 16x16 SmallIconCmd EQU $1E ; itemCmd == $1E ==> small icon plotted ; resource IDs of color icons that look like the Apple logo ;rAppleOnWhite equ -16385 ; anti-aliased apple on a white background ;rAppleOnBlack equ -16386 ; anti-aliased apple on a black background rAppleSuite equ -16386 ; I'm hijacking the assigned resource number of rAppleOnBlack rAppleWithMask equ 20 ; less attractive apple that works on any background ; Switches for drawing the icons ; bit 0 is for icon type and bit 1 is for menu type SICNInAppleMenu equ $00 SICNInApplicationMenu equ $02 ICSInAppleMenu equ $01 ICSInApplicationMenu equ $03 ;____________________________________________________________________________________________ ; ; StackFrame and Global Definitions ; ;____________________________________________________________________________________________ MenuBarDefProc PROC EXPORT MBDFRegSave REG D3-D6/A2-A4 mTitleSpace EQU 13 ; Space between menu titles in menu bar ; Stack Frame Definition for MBarProc ; FUNCTION MenuBarProc ( selector: INTEGER; message: INTEGER; ; parameter1: INTEGER; parameter2: LONGINT): LONGINT; resultsStackFrame Result DS.L 1 parametersStackFrame Selector DS.W 1 Message DS.W 1 Param1 DS.W 1 Param2 DS.L 1 localsStackFrame MenuRect DS.W 4 colorPortP DS.L 1 appleRect DS.W 4 applePixMapH DS.L 1 SelectFlag DS.W 1 TitleBackFlag DS.W 1 PixelDepth DS.W 1 theGDColorTbl DS.L 1 MenuDir DS.W 1 VMousePt DS.W 1 saveBackColor DS.W 3 saveForeColor DS.W 3 tempHandle DS.L 1 saveD3 DS.W 1 onLCDMac DS.B 1 ; if high bit is set, then internal Harpo display active onColorMachine DS.B 1 ; ; the following are for offscreen buffering of the menu in response to the draw message menuBarBuffer ds.l 1 ; handle to the offscreen buffer ; The following defines are for GetItemHeight which was copied from MDEF (UGGHHLLYYYY!) MFHeight DS.W 1 MWidMax DS.W 1 MDescent DS.W 1 MAscent DS.W 1 MInfoRec EQU MAscent ; <1Aug85> ; Extensions to a menu item <2.1> itemScript DS.W 1 ; item text script code itemIconGray DS.W 1 ; whether icon should be grayed itemIconSize DS.W 1 ; full-sized/small/shrunken itemIconHandle DS.L 1 ; handle to icon (or nil) itemHierarchicalID DS.W 1 ; hierarchical menu ID itemOrigAttrs DS.B 4 ; original attributes itemStackBase EQU * endStackFrame ; ------------------------------------------------------------------------------------- FirstMBMsg EQU 0 LastMBMsg EQU 18 ; ;-------------------------------------------------------------------------------------------- ; ; Start of Code -- save work registers and dispatch on message number. ; ; Set up: A2 -- WMgrPort ; A3 -- ptr to menu list ; ;-------------------------------------------------------------------------------------------- BRA.S StartMBDF ; Standard Header MBDFFlags DC.W 0 ; flags word DC.l ('MBDF') ; resource type DC.W 0 ; resource ID DC.W 13 ; version 0 = onNuMac ROM ; version 10 = Universal ; version 12 = Universal 6.0 ; version 13 = System 7.0 StartMBDF linksave MBDFRegSave subq.l #4,sp ; make room for saved port on the stack move.l sp,-(sp) ; Point to that result _GetPort clr onColorMachine(a6) ; clear color machine flag (and onLCDMac) cmpi.w #$3FFF, ROM85 ; color machine ? sls onColorMachine(a6) ; set byte to 1s if yes MOVE.W HwCfgFlags,D0 ; Get them Hardware Config Flags BTST.L #hwCbPwrMgr,D0 ; Do we have a PowerMgr? BEQ.S @100 ; -> Nope, assume rounded menu bar TST.B NTSC ; is it on the internal display? BNE.S @100 ; nope, so skip this BSET #7,onLCDMac(A6) ; set high-bit to mark internal display @100 tst.b onColorMachine(a6) beq.s @SetBWPort move.l WMgrCPort,a2 ; get color port bra.s @SetPort @SetBWPort MOVE.L WMgrPort,a2 ; get non-color port @SetPort MOVE.L A2,-(SP) ; set the WMgrPort _SetPort ; start by setting the window manager font to the system font clr.l -(sp) ; clear stack for next 2 calls _TextFont ; set font to system font _TextFace ; set style to plain MOVE.L MenuList,A0 ; get the menuList handle TST.L (A0) ; has it been purged? BNE.S @menuListOK ; => yes, go to purgeatory MOVEQ #MenuPrgErr,D0 ; get our error code _SysError ; and roast in eternal damnation @menuListOK ; lock the MenuList so a3 ptr doesn't move _HLock ; lots of alloc'ing in color apple routines MOVE.L (A0),A3 ; and get the pointer LEA GoBarProc,A0 ; get the dispatch table base MOVE.W message(A6),D0 ; get the message number cmpi #LastMBMsg, d0 ; is the message within bounds? bhi.s @InvalidMsg ; oops, its too high cmpi #FirstMBMsg, d0 ; blo.s @InvalidMsg ; oops, its too low ADD.W D0,D0 ; double to get words ADD.W GoBarProc(D0.w),A0 ; compute the dispatch address JSR (A0) ; do the routine @InvalidMsg _SetPort ; restore the caller's port move.l menuList, a0 ; set up to unlock menuList handle _HUnlock ; and unlock it restoreUnlinkReturn GoBarProc Table DT.W DrawBar ; draw is message #0 DT.W HitBar ; hit test is message #1 DT.W CalcBar ; calculate menu edges #2 DT.W InitBar ; init is message #3 DT.W DisposeBar ; dispose is message #4 DT.W HiliteBar ; hilite a title #5 DT.W HeightBar ; calculate mBar height #6 DT.W SaveBitsBar ; save menuBits #7 DT.W RestoreBitsBar ; restore menuBits #8 DT.W GetRectBar ; get menu's rectangle #9 DT.W SaveAltBar ; save other data #10 DT.W ResetScrollBar ; reset scrolling globals #11 DT.W ReturnMenuRgn ; return menu's region #12 DT.W MoveSICNToAM ; move small icon #13 DT.W GetTRect ; return title rect #14 <13> DT.W BannerMsg ; Use menubar as banner #15 <14> DT.W MoveICSToPM ; Move icon suite #16 DT.W MoveICSToAM ; Move icon suite to Apple Menu #17 DT.W MoveSICNToPM ; Move SICN to Application Menu #18 ;****************************************************************************************** ;* * ;* IF YOU ADD ANOTHER MESSAGE YOU MUST UPDATE THE VARIABLE "LastMBMsg" FOUND ABOVE !!!!!! * ;* * ;****************************************************************************************** ;----------------------------------------------- ; FullClip -- set clip wide open ;----------------------------------------------- FullClip MOVE.L GrafGlobals(A5), A0 ; MOVE.L wideOpen(A0), -(SP) ; set the clip to wide open _SetClip ; rts ;-------------------------------------------------------------------------------------------- ; ; Msg #3 -- Init -- allocate storage for saving bits behind for up to 5 menus ; ;-------------------------------------------------------------------------------------------- ; ; The Init Message initializes a data structure in which it stores information ; on up to 5 menus showing on the screen at once. This structure is documented ; in nToolEqu.a. It is allocated only once, the first time this message is passed ; after system startup. InitBar cmpi.l #-1, mbSaveLoc ; If first time after system start up, mbSaveLoc ; will have -1 in it bne.s @clearIt ; if not first time then just clear lastMBSave ; else, alloc space move.l #mbSaveSize, d0 ; alloc space for x-byte header plus ; 5 x-byte menu entries _NewHandle SYS,CLEAR ; alloc handle on system heap and clear it move.l a0, mbSaveLoc ; store the handle in low memory @clearIt move.l mbSaveLoc, a0 ; get mbSaveLoc move.l (a0), a0 ; dereference clr lastMBSave(a0) ; ===> no menus showing RTS ;-------------------------------------------------------------------------------------------- ; ; Msg #4 -- Dispose -- nothing for now since we leave mbSaveLoc handle in sys heap all the ; time, never mind the fact that no one sends this message. ; ;-------------------------------------------------------------------------------------------- DisposeBar ; RTS ;-------------------------------------------------------------------------------------------- ; ; Msg #6 -- Calc MB Height -- get MB Height into low memory global MBarHeight. ; ;-------------------------------------------------------------------------------------------- ; ; the Height Message just calculates the lomem variable MBarHeight ; It's here for backward compatibility with the original ROM usage. HeightBar BSR.S GetMenuInfo ; get font info for wmgr port MOVEQ #3,D1 ; get white space into D1 ADD.W D0,D1 ; add descent SWAP D0 ; get ascent ADD.W D0,D1 ; add ascent MOVE.W D1,MBarHeight ; save it in low memory RTS ;----------------------------------------------- ; Utility -- GetMenuInfo ;----------------------------------------------- ; ; GetMenuInfo is a utility that returns the ascent of the window manager's font in the high ; half of D0, and the descent in the low half. It trashes only insignificant registers. GetMenuInfo SUBQ #8,SP ; make room for a font info record MOVE.L SP,-(SP) ; point to 8 byte info record _GetFontInfo ; get font info for the system font MOVE.L (SP)+,D0 ; return ascent, descent in D0 SWAP D0 ; get ascent in lo-word ADD 2(SP), D0 ; add leading to ascent ADDQ #1, D0 ; add one for good measure SWAP D0 ; restore D0 ADDQ #4,SP ; flush record RTS ;----------------------------------------------- ; Utility -- GetMenuAscent ;----------------------------------------------- ; ; GetMenuAscent is a utility that returns the y-value for drawing the ; font above the menu bar in D4. GetMenuAscent BSR.S GetMenuInfo ; get the font ascent SWAP D0 ; get ascent in lo half ADD.W portRect+top(A2),D0 ; add in portRect offset <1.2> MOVEQ #0,D4 ; clear hi half of register MOVE.W D0,D4 ; get the ascent + leading RTS ;----------------------------------------------- ; Utility -- ClipMBar ;----------------------------------------------- ; ; ClipMBar is a utility that sets the port's clipRgn to the menu bar. ; ClipMBar MOVE.L CLIPRGN(A2),-(SP) ; push a handle to the clipRgn ; use portRect instead of assuming topLeft is (0,0) move portRect+Left(a2), -(sp); left move portRect+Top(a2), -(sp) ; top move PortRect+Right(A2),-(SP); right move portRect+Top(a2), -(sp) ; bottom = top + mBarHeight move MBarHeight, d0 add d0, (sp) _SetRecRgn ; clip to the menu bar RTS ;----------------------------------------------- ; Utility -- ClipToTempRect <11> ;----------------------------------------------- ; ; ClipToTempRect is a utility that sets the port's clipRgn to the application's menu area. ClipToTempRect LEA TempRect, A0 ; Get the base address of TempRect MOVE.L CLIPRGN(A2),-(SP) ; push a handle to the clipRgn MOVE.W left(A0), -(sp) ; left MOVE.W top(A0), -(sp) ; top move.w MBarHeight,d0 ; MBarBottom = top+MBarHeight <38> move.w bottom(a0),d1 ; bottom <38> add.w (sp),d0 ; sp points to top of TempRect <38> cmp.w d1,d0 ; use MIn(bottom,MBarBottom) <38> blt.s @useMBarHeight ; <38> move.w d1,d0 ; <38> @useMBarHeight ; <38> MOVE.W right(A0), -(sp) ; right move.w d0,-(sp) ; <38> _SetRecRgn ; clip to TempRect RTS ;-------------------------------------------------------------------------------------------- ; ; Msg #0 -- Draw the MB ; ;-------------------------------------------------------------------------------------------- ; ; the Draw Message simply(!) draws the entire menu bar, if parameter is 0. If parameter is -1, ; then draw just a cleared menu bar. Otherwise, draw one title. No result is returned DrawBar ; Set the clip region to the menu bar. If we are called to just clear the menu bar ; then the clip will stay set to this, else it will be set wide open BSR.s ClipMBar ; MOVE.L Param2(A6), D3 ; Get the parameter BGT Its1Title ; Skip if it's a 1 Title draw cmp.l #-1,d3 ; if clear, donΥt use buffer <19> beq.s @skipBuffering ; ignore the error <19> rsrv.w ; room for error <20> move.l clipRgn(a2),a0 ; start with the clipRgn <20> move.l (a0),a0 ; dereference it <20> pea rgnBBox(a0) ; pass the bounding box <20> pea menuBarBuffer(a6) ; pass place for buffer <20> _BeginDrawingOffscreen ; make the buffer <20> free.w ; ignore the error <20> @skipBuffering ; start by clearing the menubar area to the proper background color tst.b onColorMachine(a6) beq.s @DoErase bsr SaveCurrentColors ; save current colors in stackframe bsr GetPixelDepth ; put the current pixel depth in the stack frame cmpi.w #2, PixelDepth(a6) ; is this 2+ mode, and color ? blt.s @DoErase ; no, its 1 bit mode, so don't set color subq #4, sp ; save space for result clr.l -(sp) ; ID=0, Item=0 ===> menubar entry _GetMCEntry ; get the color entry move.l (sp)+, d0 ; get the result, and set z-flag if necessary beq.s @DoDefault ; zero ===> no entry so use default ; we got a menu bar entry from the color table, so use it to color the menu bar ; ; normally we would set the forecolor to black for the erase rounded corners, but Quickdraw now ; assumes that if both fore/back "revert" to black (or white) in one bit mode then it reverses ; the backcolor, so we have to set the forecolor to the default title color here, then reset ; the colors for the rounded corner erase. move.l d0, a0 ; get ptr to color entry in a0 pea mctRGB1(a0) ; push fore color pea mctRGB4(a0) ; push back color _RGBBackColor ; set the back color _RGBForeColor ; set the fore color bra.s @DoErase @DoDefault ; default is always black on white pea RGBBlack pea RGBWhite _RGBBackColor _RGBForeColor @DoErase PEA PORTRECT(A2) ; push a pointer to full screen rectangle BTST #7,onLCDMac(A6) ; is this Harpo BZ.S @regErase ; if so, then do usual _EraseRect BRA.S @doneErase @regErase MOVE.L #SCREENRADIUS,-(SP) ; push roundRect parameter _EraseRoundRect ; paint the menuBar white @doneErase ; erase around rounded corners because multiple screens leave little pieces of deskpat there tst.b onColorMachine(a6) beq.s @notColor pea RGBBlack ; set black on white for erasing rounded corners pea RGBWhite _RGBBackColor _RGBForeColor @notColor move.l portRect(a2), TempRect ; copy top, left move.l portRect+Bottom(a2), TempRect+Bottom ; copy bottom, right LEA TempRect,A0 ; get temp rect address BTST #7,onLCDMac(A6) ; is this Harpo BNZ.S @skipFrame ; if so, then no framing MOVE.L A0,-(SP) ; push the temp rect MOVE.L #$FFFDFFFD,-(SP) ; and make it bigger _InsetRect ; by 3 pixels on each side MOVE.L #$00030003,-(SP) ; get a wider pen _PenSize LEA TempRect, A0 ; get temp rect address again MOVE.L A0,-(SP) ; push the temp rect MOVE.L #$00160016,-(SP) ; and a radius for nice rounding _FrameRoundRect ; and black out the corners @skipFrame _PenNormal ; fix the pen back up ; use portRect instead of assuming topLeft is (0,0) MOVE.W PortRect+Right(A2),-(SP) ; push extreme right move portRect+Left(a2), d0 ; get left in lo-byte swap d0 ; put it in hi-byte move portRect+Top(a2), d0 ; get top add MBarHeight,D0 ; add menu bar height to get bottom SUBQ.W #1,D0 ; need bottom-1 MOVE.W D0,-(SP) ; push vertical for LineTo SWAP D0 ; get vertical in high word MOVE.L D0,-(SP) ; and push point for MoveTo _MoveTo ; move to left of line _LineTo ; draw the line bsr ResetPreviousColors ; reset colors before leaving ; if the parameter is -1, then return (just clear the bar). LEAVE CLIP SET TO MENU BAR !!! CMP.L #-1,Param2(A6) BEQ DrawDoneNoUnclipNoBuffering ; get ready to draw the menuList on the menuBar TST.W (A3) ; any menus in the menuList? BEQ DrawDone ; if not, we're done clr.w saveD3(a6) ; assume no title hilited MOVEQ #6,D3 ; start with first (leftmost) entry ;--------------------------------------------------------- ; main drawing loop ;--------------------------------------------------------- ; ; This is the loop that draws the titles on the menu bar. It handles hiliting ; and graying out. ; ; on entry A3 MenuListP menu list pointer. Note: handle is locked ; D3 index index into menu list (#6 byte offsets) ; calc'ed A4 MenuInfoP Ptr into menu data for currently drawn menu. ; ; TODO: DrawMenuBar with a hilited menu leaves a handle around. The handle ; contains the bits behind the previously hilited menu! The reason is that ; Excel was screwing around with the menubar and we couldn't be sure that ; the handle in mbBitsBehind actually contained a handle to the bits behind ; the hilited menu. So, we couldn't dispose of the menu without Excel ; blowing up every time. Aaghhh!!! DrawMLoop move d3, d0 ; set up for GetTitleRect BSR GetTitleRect ; get this title's rect in TempRect move.l menuOH(A3,D3),A0 ; get the selected menuHandle _HLock ; lock it down MOVE.L (A0),A4 ; and dereference handle BSR Draw1Title ; use utility to draw text and ; disable if necessary move.w theMenu, d0 ; get ID of hilited menu move.l menuOH(A3,D3),A4 ; reset a4, get the selected menuHandle MOVE.L (A4),A4 ; dereference handle cmp.w menuID(a4), d0 ; should this one be hilited? bne.s NextDraw ; no, then branch move d3, saveD3(a6) ; save d3 on the stack for use later ; we're done processing one menu -- bump to the next one and loop if there's more to do NEXTDRAW move.l menuOH(A3,D3),A0 ; get the selected menuHandle _HUnlock ; unlock it SkipSysLoop ADDQ #6,D3 ;bump index to next in list CMP (A3),D3 ;compare d3 with lastMenu. Are we done? BGT.S DONEDRAWMLOOP ; we're done MOVE.L menuOH(A3,D3), A0 ; get the selected menuHandle <18> MOVE.L (A0), A0 ; Get the menuptr MOVE.W menuID(A0), D0 ; Get the menuID CMP.W #-16384,D0 ; Is it a system menu BGE.S DrawMLoop ; Nope, keep going MOVE.W lastRight(A3), D0 ; Find right edge of reg menus CMP.W menuLeft(A3,D3), D0 ; Is it after right edge? BLE.S DrawMLoop ; Yes, it is BRA.S SkipSysLoop ; Skip this menu ; select the item that is selected (if any) now, AFTER drawing all the titles DONEDRAWMLOOP BSR ClipMBar ; Restore the clip to the whole menu bar <10> move saveD3(a6), d0 ; get savedID of hilited menu beq DrawDone ; branch if none CSS move d0,d3 ; and put it in d3 too bsr GetTitleRect ; get selected title's rect move.l menuOH(a3,d3),a0 ; get selected menuHandle _HLock ; lock it down move.l (a0), a4 ; dereference bsr DoSelected ; and select it move.l menuOH(a3,d3),a0 ; get selected menuHandle _HUnlock ; unlock it BSR ClipMBar ; Restore the clip to the whole menu bar <42> BRA.S DrawDone ; Its1Title ; CMP.W (A3), D3 ; Is it in the legal range? BGT.S DrawDone ; Skip if not MOVE.L D3, D0 ; Set up for GetTitleRect BSR GetTitleRect ; Get this title's rect in TempRect lea TempRect,a0 ; pass the item rectangle <19> bsr BeginMenuBuffering ; make a buffer for this item <19> MOVE.L menuOH(A3, D3), A0 ; Get the selected menuHandle _HLock ; Lock it down MOVE.L (A0), A4 ; And dereference handle BSR.S Draw1Title ; Draw it MOVE.W theMenu, D0 ; Get ID of highlighted menu CMP.W menuID(A4), D0 ; Should it be highlighted? BNE.S Its1Done ; Skip if not BSR DoSelected ; Select it Its1Done ; MOVE.L menuOH(A3, D3), A0 ; Get the menuHandle _HUnlock ; Unlock it ; be a good citizen and set the clip rgn to full open DrawDone rsrv.w ; make room for error <20> push.l menuBarBuffer(a6) ; hereΥs where we stored it <20> _EndDrawingOffscreen ; finish buffering, and draw something <20> free.w ; discard error <20> bsr FullClip DrawDoneNoUnclipNoBuffering RTS ;-------------------------------------------------------------- ; Utility -- Draw1Title -- draw one title in the menu bar ;-------------------------------------------------------------- ; ; Here is the code that draws a title on the menu bar. It handles ; hiliting and graying out. It shares DrawCommon with DoSelected. ; It also sets the proper title colors for color and black/white ; machines. ; ; on entry A3 MenuList menu list pointer! ; A4 menu ptr selected menu pointer ; D3 index index into menu list (#6 offsets) ; D0 param2 ; calc here D4 font info font ascent + leading (see GetMenuInfo) Draw1Title clr.w SelectFlag(a6) ; clear select flag ==> draw normal mode CMP.W #6, D3 ; Is it the apple menu? BNE.S DrawCommon ; Skip if not MOVE.L mbSaveLoc, A0 ; Get handle to save data MOVE.L (A0), A0 ; Dereference it MOVE.W #-1, mbIconState(A0) ; Reset icon rotation DrawCommon bsr GetMenuAscent ; returns y-val in D4 MOVE MENULEFT(A3,D3),-(SP) ; x coordinate is menuLeft[index]+8 move portRect+Left(a2), d0 ; add d0, (sp) ; adjust for portRect ADDQ #8,(SP) ; indent a little MOVE.W D4,-(SP) ; set y coordinate _MoveTo ; position the point to start drawing clr TitleBackFlag(a6) ; calling SetTitleColor from DrawTitle bsr SetTitleColor ; set color for title/background pea TempRect ; clear the title rect to the backColor _EraseRect ; DrawSimple is a simplified DrawCommon. It draws the title at the given pen point. DrawSimple bsr ClipToTempRect ; Keep drawing contained <11> move.w #srcOr, -(sp) ; set text mode to srcOr _TextMode tst.b onColorMachine(a6) beq.s DrawATitle cmpi.w #$0114, menudata(a4) ; is the title the AppleMark? bne.s DrawATitle ; no, so branch BSR GetPixelDepth ; Get the current pixel depth CMP.W #4, PixelDepth(A6) ; 4+ pixel depth? BLT.S DrawATitle ; Wrong depth, use system font BSR IsBWMode ; Check to see if we are in B&W mode <10> BEQ.S DrawATitle if useAntiAliasedApples then subq.w #6,sp ; make room for a color move.l sp,-(sp) _GetBackColor ; check background color cmp.l #$FFFFFFFF,(sp) ; is it white? bne.s @notWhite cmp.w #$FFFF,4(sp) ; is it white? bne.s @notWhite @white move.w #rAppleOnWhite,d0 ; get the apple on white bra.s @gotID @notWhite tst.l (sp) ; is it black? bne.s @notBlack tst.w 4(sp) ; is it black? bne.s @notBlack @black move.w #rAppleOnBlack,d0 ; get the apple on black bra.s @gotID @notBlack moveq #rAppleWithMask,d0 ; get the (less attractive) apple for any background @gotID addq.w #6,sp ; get rid of the color endif BSR CalcRightRectSize SUBQ.L #2, SP ; Make room for return value PEA TempRect ; push the address of the dest rectangle MOVEQ #atCenterTop, D0 ; get the alignment code MOVE.W D0, -(SP) ; push it. BTST #0, menuEnable+3(a4) ; is the title disabled? BNE.S @notGray ; if not, then don't use a transform MOVEQ #ttDisabled, D0 ; else use ttDisabled BRA.S @transform ; @notGray MOVEQ #ttNone, D0 ; @transform MOVE.W D0, -(SP) ; push the transform MOVE.W #rAppleSuite, -(SP) ; push the id of the color apple icon suite _PlotIconID ; plot the puppy ADDQ.L #2, SP ; Don't care about the result bsr ResetPreviousColors ; reset to original fore/back colors rts ; and return DrawATitle cmp.b #5,menuData(a4) ; is the string at least 5 bytes long? blo.s @notIcon cmp.b #1,menuData+1(a4) ; is the first character a 1? bne.s @notIcon BSR.S CalcRightRectSize subq #2, SP ; make room for result PEA TempRect ; push the title rect move.w #atAbsoluteCenter, -(sp) ; No need to do centering since the rect is of the right size btst #0, menuEnable+3(a4) ; is the title disabled? bne.s @noTransform ; if not, then don't use a transform moveq #ttDisabled, d0 ; else use ttDisabled bra.s @pushTransform ; @noTransform moveq #ttNone, d0 ; @pushTransform move.w d0, -(sp) ; push the transform move.l menuData+2(a4), -(sp) ; push the icon handle ; bsr ResetPreviousColors ; Reset the title colors ; tst.w selectFlag(a6) ; Is this sucker selected ; beq.s @colorsOK ; if not, go ahead and plot ; bsr ResetPreviousColors ; restore the old colors so they will be saved by setTitleColor ; clr.w selectFlag(a6) ; lie about the select state ; bsr SetTitleColor ; not.w selectFlag(a6) ; restore the select state @colorsOK _PlotIconSuite addq #2, SP ; dump the result bsr ResetPreviousColors ; set up old colors rts ; run away ; bra.s ChkDisable ; @notIcon PEA MenuData(A4) ; push pointer to title string MOVE #srcOr,-(SP) ; Just to be sure grayish isnt happening _TextMode TST.B onColorMachine(A6) BNE.S @DrawStringOnColorMachine _DrawString btst #0, menuEnable+3(a4) ; is the title disabled? bne.s dontchk ; no, continue bsr PaintTitleDisable ; disable the title by painting with gray bra.s dontchk @DrawStringOnColorMachine btst #0, menuEnable+3(a4) ; is the title disabled? bne.s @notDisabledOnColorMachine MOVE #grayishTextOr,-(SP) ; special funny mode _TextMode @notDisabledOnColorMachine _DrawString MOVE #srcOr,-(SP) ; should be txMode!!! _TextMode dontchk bsr ResetPreviousColors ; reset to original fore/back colors rts ; and return CalcRightRectSize MOVEM.L A0/D0, -(SP) LEA TempRect,A0 move.w right(A0), D0 ; Get the right side sub.w left(a0), D0 ; find the width cmp.w #$10, D0 ; Is it big enough to fit a small icon? ble.s @tooSmall asr.w #2, D0 ; Divide the gap in half add.w left(A0), D0 ; offset the left side move.w D0,left(A0) ; update Left add.w #1, top(A0) ; Tweek the top a bit @tooSmall move.l topLeft(A0),D0 ; get the top and left swap D0 ; put top in low word add.w #16, D0 ; add 16 swap D0 ; put left in low word add.w #16, D0 ; add 16 move.l D0, botRight(A0) ; Update bottom and right MOVEM.L (SP)+, A0/D0 RTS ;----------------------------------------------- ; Utility -- SaveCurrentColors ;----------------------------------------------- SaveCurrentColors pea saveBackColor(a6) ; push address of var parm _GetBackColor ; get the background color pea saveForeColor(a6) ; push address of var parm _GetForeColor ; get foreground color rts ;----------------------------------------------- ; Utility -- SetTitleColor ;----------------------------------------------- ; Set the foreground/background color for this ; title. If has colorQD then use real colors ; else just use black/white ; SetTitleColor tst.b onColorMachine(a6) beq @SetBW BSR.S SaveCurrentColors ; Save current colors in stack frame TST.W TitleBackFlag(A6) ; DrawTitle = 0, DrawStruct = 1 BEQ.S @FromTitle0 ; Branch if from DrawTitle LEA menuRect(A6), A0 ; RGetPixelDepth uses menu rect BRA.S @GetDepth ; Go get depth @FromTitle0 LEA portRect(A2), A0 ; RGetPixelDepth uses menu bar @GetDepth BSR RGetPixelDepth ; Get the current pixel depth cmpi.w #2, PixelDepth(a6) ; is this 2+ mode, and color ? blt.s @DefaultColors ; no, its 1 bit mode or mono move.l a4,d0 ; <49> Are we pointing to a MenuInfo record? bz.s @TryMenuBar ; <49> No. Get the color entry for the menu bar subq #4, sp ; save space for result move menuID(a4), -(sp) ; push ID clr -(sp) ; push Item=0 ===> title entry _GetMCEntry ; get the color entry move.l (sp)+, d0 ; get the result, and set z-flag if necessary beq.s @TryMenuBar ; nope no title entry, try menu bar entry ; got menu title entry, so put colors on stack move.l d0, a0 ; get entry address in a0 tst TitleBackFlag(a6) ; called from DrawTitle = 0, DrawStruct = 1 beq.s @FromTitle1 ; branch if from DrawTitle pea mctRGB1(a0) ; foreground unimportant for DrawStruct pea mctRGB4(a0) ; get specified background color bra.s @SetColors @FromTitle1 pea mctRGB1(a0) ; push title color pea mctRGB2(a0) ; push menu bar color bra.s @SetColors ; didn't get title entry, so try to get menu bar entry for menu color @TryMenuBar subq #4, sp ; save space for result clr.l -(sp) ; ID=0, Item=0 ===> menubar entry _GetMCEntry ; get the color entry move.l (sp)+, d0 ; get the result, and set z-flag if necessary beq.s @DefaultColors ; zero ===> no entry so use default ; got menu bar entry, so set colors move.l d0, a0 ; get entry address in a0 tst TitleBackFlag(a6) ; called from DrawTitle = 0, DrawStruct = 1 beq.s @FromTitle2 pea mctRGB3(a0) ; foreground unimportant for DrawStruct pea mctRGB2(a0) ; get default background from menubar entry bra.s @SetColors @FromTitle2 pea mctRGB1(a0) ; push default title color pea mctRGB4(a0) ; push menu bar color bra.s @SetColors ; set colors for default title @DefaultColors pea RGBBlack ; set foreground color to black pea RGBWhite ; set background color to white ; colors are on the stack for normal title, switch them if this is a selected title @SetColors tst.w selectFlag(a6) ; normal or selected? beq.s @1 ; normal ===> addresses ok on stack move.l (sp), a0 ; selected ===> switch addresses on stack move.l 4(sp), (sp) move.l a0, 4(sp) @1 _RGBBackColor ; color addresses are on the stack _RGBForeColor bra.s @DoneSetTitleColor ; set colors for selected title @SetBW moveq #WhiteColor, d0 ; set foreground color to white move.l d0, -(sp) moveq #BlackColor, d0 ; set background color to black move.l d0, -(sp) tst.w selectFlag(a6) ; normal or selected? beq.s @BWNormal ; normal, so branch _BackColor ; colors are on the stack _ForeColor bra.s @DoneSetTitleColor @BWNormal _ForeColor ; do calls in reverse if normal _BackColor @DoneSetTitleColor rts ;----------------------------------------------- BeginMenuBuffering ; Create an off-screen buffer for the menu bar, or a part of it. ; Then, attach this buffer to the port passed. ; The bits in the buffer are not initialized (must draw over the whole thing). ; This must be balanced by an EndMenuBuffering, which will blast the bits onto the screen. ; ; In: ; a0 pointer to rectangle for size of buffer rts ;----------------------------------------------- ; Utility -- ResetPreviousColors ;----------------------------------------------- ; Reset the foreground/background color for this ; title. If has colorQD then use saved colors ; else just use black/white ; ResetPreviousColors tst.b onColorMachine(a6) beq.s @ResetBW pea saveForeColor(a6) ; push addresses of color records pea saveBackColor(a6) _RGBBackColor ; set the background color _RGBForeColor ; get the foreground color bra.s @ResetDone @ResetBW moveq #BlackColor, d0 ; force foreground color to black move.l d0, -(sp) moveq #WhiteColor, d0 ; force background color to white move.l d0, -(sp) _BackColor _ForeColor @ResetDone rts ;----------------------------------------------- ; Utility -- PaintTitleDisable ;----------------------------------------------- ; If the title is disabled and there is no ; colorQD then paint TempRect with Gray ; ; Save and restore pen state for the application Tempo. PaintTitleDisable btst #0, menuEnable+3(a4) ; is the title disabled? bne.s @EndCheck ; no, so just return suba #psRec, sp ; save space for pen state on the stack move.l sp, -(sp) ; push pen state rec address _GetPenState ; get the pen state MOVE.L (A5),A0 ; get QuickDraw globals PEA Gray(A0) ; push gray _PenPat ; make that the pen pattern move #PatBIC,-(SP) ; set bit clear mode _PenMode ; set the penMode pea TempRect ; push the rect addr _PaintRect ; bit clear with gray move.l sp, -(sp) ; push pen state rec address _SetPenState ; reset to previous pen state adda #psRec, sp ; remove pen state rec from stack @EndCheck rts ;----------------------------------------------- ; Utility -- GetPixelDepth ;----------------------------------------------- ; ; Utility to get current pixel depth and put it in the stack frame. ; RGetPixelDepth uses the rectangle pointed to by A0. GetPixelDepth LEA portRect(A2), A0 ; Use WMgr's portRect RGetPixelDepth ; subq #4, sp ; space for GDHandle return MOVE.L A0, -(SP) ; rect for GetMaxDevice _GetMaxDevice ; get max pixel device MOVE.L (sp)+, A0 ; get the grafDevice MOVE.L (A0),A1 ; hndl->ptr MOVE.L GDPMap(A1),A1 ; get the device's pixmap MOVE.L (A1),A1 ; hndl->ptr move.w pmPixelSize(a1), PixelDepth(a6) ; and store the value rts ;----------------------------------------------- ; Utility -- IsBWMode ;----------------------------------------------- ; ; Utility to test the monochrome/color information for the menu's monitor. ; Returns: Z-Flag means Monochrome, otherwise not B&W IsBWMode subq #2+4, sp ; space for boolean and for GDHandle <19> PEA portRect(A2) ; Use WMgr's portRect _GetMaxDevice ; get max pixel device MOVE.W #gdDevType,-(SP) ; And we want to test the gdDevType _TestDeviceAttribute ; Go get it TST.B (SP)+ ; Set the Z-flag RTS ;-------------------------------------------------------------------------------------------- ; ; Msg #1 -- Hit Test -- is the mouse in the title bar, or in a menu, or in neither. ; ;-------------------------------------------------------------------------------------------- ; ; The Hit Message takes a point in parameter, and determines whether the mouse ; point is in a title rect of the MenuBar. ; 1. If point in title or menu return menu's index ; 2. If point in title bar but not in title return 0 ; 3. If point not in any title or menu then return -1 ; ; To allow for multiple screens the menu bar extends for the width of the portRect only ; Don't include the line under the menu bar as a hit, otherwise it is possible to ; to choose the first menu item immediately ; HitBar MOVE.L Param2(A6),D1 ; get the point SWAP D1 ; get the vert coord in lo word move portRect+Top(a2),d0 ; get top of menu bar in d0 cmp d0, d1 ; above menu bar ? blt @NotInBar add MBarHeight, d0 ; get bottom of menu bar in d0 cmp d0, d1 ; below menu bar ? bge.s @NotInBar ; don't include line at bottom of menu ; else can choose first item immediately ; Check the left and right sides of the menu bar SWAP D1 ; get the horiz coord in lo word move portRect+Left(a2),d0 ; get left of menu bar in d0 cmp d0, d1 ; to the left of the menu bar ? blt.s @NotInBar move portRect+Right(a2),d0 ; get right of menu bar in d0 cmp d0, d1 ; to the right of the menu bar ? bgt.s @NotInBar ; it's in the bar, check if it's in a menu title ; NOTE: all title bounds (e.g. lastRight and menuLeft) are zero-based offsets, before ; we start checking D1 against these we must first adjust it for portRect+Left(a2) MOVE.W portRect+Right(a2), D0 ; Right edge of menu bar SUB.W #mbMenu1Loc,D0 ; Right edge of right-hand system menu ;> CMP.W D0, D1 ; Is point to the right of it? ;> BGT.S @NoTitle ; No way itΥs in a title ;> SUB.W portRect+Left(a2), D1 ; adjust D1 for portRect+Left CMP.W #mbMenu1Loc, D1 ; is it to the left of the first title ? BLT.S @NoTitle ;______________________<11> ; Notes on new hit testing: ; 1) We donΥt return a hit on a system menu whose left edge is <= lastRight (it "fell off"). ; CalcBar set lastRight to the left edge of the last system menu if there were too many ; application menus, thus the last system menu can never "fall off." ; 2) We donΥt return a hit on any application menu whose left edge is past lastRight, but if ; if lastRight is somewhere in the middle of the menu, it will be allowed to hit in ; the area from itΥs left up to lastRight. ; Check either system set or application set ; _DMSG 'Welcome to Hitbar' MOVEQ #0,D4 ; Courtesy Microsoft Corp., Excel Division <16> MOVE.W lastMenu(A3), D4 ; D4 = lastMenu BEQ.S @NoTitle MOVE.W lastRight(A3), D3 ; D3 = lastRight BSR FindFirstSystemMenu6BO ; Put offset to first system menu in D0 BEQ.S @NoSystemMenusHitEntry ; OOPS, no system menus! CMP.W D3, D1 ; IF pt.h <= lastRight THEN BLE.S @CheckAppMenus ; Hit was in app list somewhere ; Check system menus for allowable hit range @sysChkLoop MOVE.W menuLeft(A3,D0.W), D2 ; Get the menu.left CMP.W D3, D2 ; WHILE menu.left < lastRight BGE.S @HitLoop ; Found 1st visible title, regs set up already CMP.W D4, D0 ; Is this the last menu? BGE.S @NoTitle ; If not, there are no visible system menus(?) ADD.W #6, D0 ; go to next menu BRA.S @sysChkLoop ; Check application menus for allowable hit range @regChkLoop MOVE.W menuLeft(A3,D0.W), D2 ; Get the menu.left CMP.W D3, D2 ; WHILE menu.left >= lastRight BLT.S @foundLastVisRegMenu ; Found last visible title @CheckAppMenus SUB.W #6, D0 ; Move to the previous menu BNE.S @regChkLoop ; And loop BRA.S @NoTitle ; Well, we put the check in for this above... @foundLastVisRegMenu ; We want to hit test from D0 -(downto)-> firstmenu MOVE.W D0, D4 ; D0 is where we want to start @NoSystemMenusHitEntry CMP.W D3, D1 ; IF pt.h <= lastRight THEN BGT.S @NoTitle ; bra if no sysmenus but hit beyond app menus MOVEQ #6, D0 ; the first menu 6BO ; Hit loop: loop D4 downto D0 @HitLoop CMP.W menuLeft(A3,D4), D1 ; IF pt.h >= menu.left THEN we got it! BGE.S @HitThisOne ; Yeah! CMP.W D0,D4 ; Are we done? BEQ.S @NoTitle ; Yep SUB.W #6, D4 BRA.S @HitLoop ;______________________<11> @HitThisOne MOVE.L D4,result(A6) ; return the menu @HitDone RTS @NoTitle CLR.L result(A6) ; if in menubar but no title, return menu number 0 BRA.S @HitDone ; and return ; Point not in bar, so check if in the rectangle of any menu on screen. Notice that this ; loop checks thru the menus backwards, starting with the last one up, which is correct. @NotInBar move.l mbSaveLoc, a0 ; get handle to mbar's save data move.l (a0), a3 ; dereference move.w lastMBSave(a3),d3 ; are there any menus? beq.s @NotInAnyMenu ; no, so return -1 @RectLoop clr.w -(sp) ; make room for PtInRect result move.l param2(a6), -(sp) ; push the point pea mbRectSave(a3,d3) ; push the rect address _PtInRect ; test if point in rect tst.b (sp)+ ; was it? bne.s @FoundMenu ; yes, so return menuIndex (6 byte offset) subi #mbEntrySize, d3 ; move to next index beq.s @NotInAnyMenu ; if index == 0 then checked them all bra.s @RectLoop ; index != 0 so check some more ; return the menuIndex in the lo-word of the result @FoundMenu clr.l result(a6) ; clear hi-word of result move.w mbMLOffset(a3,d3), result+2(a6) bra.s @HitDone ; and return @NotInAnyMenu MOVE.L MinusOne,result(A6) ; if not in bar return -1 BRA.S @HitDone ;-------------------------------------------------------------------------------------------- ; ; Msg #2 -- Calc -- Calculate left edges for some or all Menus in menuList data structure ; ;-------------------------------------------------------------------------------------------- ; ; The Calc Message recalculates left edge starting points for each menu, ; starting at the menuIndex passed in parameter. If parameter is zero, ; the entire menu structure is recalculated. Other than updating the MenuList, ; this routine returns no result. ; NOTE: These calculations are all zero-based. That is, if portRect+Left(a2) is non-zero ; the values calculated here are unaffected. Adjustments are made for portRect+Left ; when the values are used. ; Dave found a bug in this due to assumption of D4's value at start of routine ; now D4 is set explicitly (somebody used D0, then changed to D4 without proper initialization) CalcBar tst lastMenu(a3) ; are there any menus to calculate ? beq CalcDone ; no, so nothing to calculate MOVE.L SystemMenuList, A0 ; Get system menulist MOVE.L (A0), A1 ; deref system menulist handle TST.W lastMenu(A1) ; Are there any system menus? BEQ SystemMenusAreIN ; Well, there aren't any -- so they are all in! CSS BSR FindFirstSystemMenu6BO ; See if the system menus are in. BNE.S SystemMenusAreIN ; Yes, they are (D0 is offset to 1st one) MOVEQ #6,D0 MOVE.L menuOH(A3,D0.W),A1 ; Get menuhandle of leftmost menu MOVE.L (A1),A1 ; menuhandle -> menuptr CMPI.W #$0114,menuData(A1) ; Is it an apple menu? BNE.S SystemMenusAreIN ; NE means no apple menu, donΥt add system menus _HLock ; Lock SysList before munging (weΥre pointing into it) MOVE.L (A0),A1 ; handle -> ptr MOVEQ #0, D1 ; Clear the high word MOVE.W lastMenu(A1),D1 ; Get # of bytes of system menus ADDQ.L #6, A1 ; Point A1 to first system menu entry MOVEQ #6, D0 ; Get offset of 1st menu entry ADD.W lastMenu(A3), D0 ; D1 = Offset past lastMenu entry ; long = Munger(menulist, offset past regular menus, NIL, 0, ptr to 1st system menu, len sys menus) SUBQ.L #4, SP ; Make room for result MOVE.L MenuList,A0 ; Get the menulist MOVE.L A0, -(SP) ; handle -- Menulist handle pushed MOVE.L D0, -(SP) ; offset = past last one in existing list MOVE.L #0, -(SP) ; ptr1 = NIL MOVE.L #0, -(SP) ; len1 = 0 -- means insert (ptr2,len2) at offset MOVE.L A1, -(SP) ; ptr2 = first system menu MOVE.L D1, -(SP) ; len2 = #Bytes of system menus ADD.W D1, lastMenu(A3) ; Just for luck, add up the new stuff we're adding _HUnlock ; DonΥt Munge locked handles! _Munger ; oooh baby, munge me! MOVE.L MenuList, A0 ; Get (potentially) new menulist handle _HLock MOVE.L (A0), A3 ; Restore A3 to new value MOVE.L SystemMenuList, A0 ; Get system menulist _HUnlock ; Unlock it ADDQ.L #4, SP ; Ignore the results ; BRA.S MenusExist ; There are menus in the menulist now SystemMenusAreIN ; Now start the regular calc stuff ; tst lastMenu(a3) ; are there any menus to calculate ? ; beq CalcDone ; no, so nothing to calculate MenusExist MOVE.L Param2(A6),D4 ; get the menuIndex to start in TST.W D4 ; pick up as long, but treat as word BEQ.S @entireBar ; if it's zero, then do entire bar CMP.W (A3),D4 ; is it in the legal range? BGT CalcDone ; if greater, then skip MOVE.W menuLeft(A3,D4),D3 ; get the left edge for the starting title BRA.S CalcLoop ; and continue @entireBar MOVEQ #mbMenu1Loc,D3 ; first menu starts ten pixels in MOVEQ #6,D4 ; first menu's info starts at byte 6 MOVE.W D3,menuLeft(A3,D4) ; write it's menuLeft into the MenuList ; get the menu title string and measure it CalcLoop MOVE.L menuOH(A3,D4),A0 ; get the menuHandle MOVE.L (A0),A0 ; dereference it cmp.b #1,menuData+1(a0) ; is the first character a 1? bne.s @notSysMenu add.w #15,d3 ; all icons are 16 pixels wide, but do 15 <10> bra.s @done @notSysMenu SUBQ.L #2,SP ; make room for function return PEA menuData(A0) ; push a pointer to the menu text _StringWidth ; get the size of it ADD.W (SP)+,D3 ; add to this item's left edge @done ADD.W #mTitleSpace,D3 ; add space (determined empirically) ADDQ #6,D4 ; move to the next menu CMP.W (A3),D4 ; was this the last menu BGT.S CalcLoopDone ; it is, so leave this loop MOVE.W D3,menuLeft(A3,D4) ; place in the left edge of next BRA.S CalcLoop ; loop back CalcLoopDone MOVE.W D3,lastRight(A3) ; set right edge always (even tho we may update it) BSR FindFirstSystemMenu6BO ; Find first system menu MOVE.W D0,D4 ; Are there any? (Save offset in D4) BEQ CalcDone MOVE.W menuLeft(A3,D0.w), D0 ; Get the 1st system menu's left MOVE.W D0, lastRight(A3) ; Make that the last right of regular menus ; Compute the distance by which the last system menu's left edge should be adjusted ; and add this to each left edge of system menus, thereby right justifing them. MOVE.W lastMenu(A3),D0 ; Get the last system menu offset MOVE.W menuLeft(A3,D0),D0 ; Get the last system menuLeft as calculated MOVEQ #0, D1 ; Clear out high word SUB.W D0, D3 ; Last.right - Last.left + 1 [width of menu] ADD.W #1, D3 ; Width of menu as computed elsewhere (it guides this) ADD.W #mbMenu1Loc, D3 ; Width + mbMenu1Loc [symmetrical offset from right edge] MOVE.W portRect+right(A2),D1 ; Get the right edge of the world SUB.W D3, D1 ; Where the actual left edge should be SUB.W D0, D1 ; Distance between computed and actual lefts MOVE.W menuLeft(A3,D4), D0 ; Get left edge of the menu we are moving ; MOVE.W D0, lastRight(A3) ; Save as new last right (last one is correct) SysOffsetLoop ADD.W D1, menuLeft(A3,D4) ; Offset system menuΥs left edge (D4 is 1st sys) CMP.W lastMenu(A3),D4 ; was this the last menu BEQ.S SysOffsetLoopDone ; it is, so leave this loop ADDQ.W #6, D4 ; go to next one BRA.S SysOffsetLoop SysOffsetLoopDone ; <48> (the rest of this routine) ; At this point, D1 is the pixels we moved the system menus ; If D1 >= 0 then they moved right and there is space between ; the app menus and the system menus, so no overlap checking is necessary ; and lastRight is correct. TST.W D1 BGE.S CalcDone ; D1 > 0, there is no overlap: weΥre done. ; Bummer, app menus overlap the system menus. ; Find the "hard lastRight" - the left edge of the leftmost system menu we must keep BSR.S FindFirstSystemMenu6BO ; Find first system menu MOVE.W D0,D3 MOVE.W lastMenu(A3),D4 ; Must keep the app menu no matter what MOVE.W MBDFFlags,D1 ; Get the flags BEQ.S D4IsHardEdge6BO ; No special case LSR.W #4,D1 ; Only "keep count" bits ANDI.W #$F,D1 BEQ.S D4IsHardEdge6BO ; And weΥve got the 6B0 of the menu containing the hard edge ADD.W D1,D1 ; 2x MOVE.W D1,D0 ; 2x copy ADD.W D0,D0 ; 2x + 2x = 4x ADD.W D1,D0 ; 4x + 2x = 6x SUB.W D0,D4 ; lastMenu - 6B0 of savings CMP.W D3,D4 ; is computed menu < 1st system menu BGE.S D4IsHardEdge6BO ; no, use computed menu as hard right MOVE.W menuLeft(A3,D3), D0 ; Get 1st system menu left edge D0IsNewLR MOVE.W D0, lastRight(A3) ; Left edge is this ; So there's not much else to say, App menus overlap ; and we have to keep all the system menus.... CalcDone RTS D4IsHardEdge6BO MOVE.W lastRight(A3),D1 ; cache last right MOVE.W menuLeft(A3,D4),D2 ; prime menuLeft transSearchLoop MOVE.W menuLeft(A3,D4),D0 ; get menuLeft CMP.W D1,D0 ; Is menuLeft < lastRight? BLT.S foundTransMenu MOVE.W D0,D2 ; Save this one SUBQ #6,D4 ; Point to next previous system menu CMP.W D3,D4 ; At the last one? BGE.S transSearchLoop foundTransMenu MOVE.W MBDFFlags,D1 ; Get the flags ANDI.W #$F,D1 ; Only slop bits LSL.W #1,D1 ; Two pixel increments ADD.W D0,D1 ; menuLeft = menuLeft + slop CMP.W lastRight(A3),D1 ; Is menuLeft + slop >= lastRight ? BGE.S D0IsNewLR ; Keep this menu (above slop threshold) MOVE.W D2,D0 ; menuLeft is new last right BRA.S D0IsNewLR ;______________________________________________________________________________________________ ; Utility -- FindFirstSystemMenu6BO ; Returns the 6B0 of the 1st system menu found in the menulist in D0 (conditions set). ; Returns zero if no system menus are in the current menu bar. ; All registers (except D0 of course) are preserved. ; NOTE: We walk from last menu -> first since there usually are fewer system menus ; and they are at the end of the menu list FFSMSaveReg REG A0/A1 FindFirstSystemMenu6BO MOVEM.L FFSMSaveReg, -(SP) ; Save our regs MOVE.L MenuList, A0 ; Get the current menulist MOVE.L (A0), A0 ; dereference MOVEQ #0, D0 ; Clear high word MOVE.W lastMenu(A0), D0 ; Get the last menu offset BEQ.S @done ; If there are none, done @nextMenu MOVE.L menuOH(A0,D0.w), A1 ; Get the menu handle MOVE.L (A1), A1 ; dereference CMP.W #-16384, menuID(A1) ; IF menuID >= -16384 THEN BGE.S @pastSysMenus ; GOTO pastSysMenus SUBQ #6, D0 ; point to the next one in the menulist BNE.S @nextMenu ; and continue ; Falling out of loop, D0=0 and 1st is system menu @bumpAndExit ADDQ #6, D0 ; Bump D0 to point to next entry BRA.S @done ; And weΥre outa here @pastSysMenus CMP.W lastMenu(A0), D0 ; were there any system menus at all? BLT.S @bumpAndExit ; D0 moved, so we found at least 1 system menu MOVEQ #0,D0 ; Show that there is no partition @done MOVEM.L (SP)+, FFSMSaveReg ; Restore our regs RTS ;-------------------------------------------------------------------------------------------- ; ; Msg #5 -- Hilite -- do the indicated menu hiliting ; ;-------------------------------------------------------------------------------------------- ; ; The Hilite message redraws a single title to the hilite state specified ; in the hi word of parameter. States are: ; 0 unhilited/normal appearance -- ; restore the bits behind the title rect ; 1 selected appearance -- ; save the bits behind the menu title and draw the selected title ; 2 disabled appearance -- ; redraw the title using the "disabled" pattern as an overlay ; NOT SUPPORTED CURRENTLY ; 3 busy appearance -- ; redraw the title using the "busy" pattern as an overlay ; NOT SUPPORTED CURRENTLY ; 128+ blit SICN resource onto screen -- ; NOT SUPPORTED CURRENTLY ; ; The index of the title to perform hiliting on is in the lo-word of parameter ; (if 0, then the whole bar is hilited). ; ; NOTICE: The way we handle normal and selected menu titles is very different now. ; On MacPlus selecting a menu caused the menu title to be inverted, and ; unselecting it (HiliteMenu(0)) just inverted it again. This meant that ; menu titles were unreadable on programs that use the full screen. In this ; new model when a menu is selected the bits behind are saved, and the ; title is drawn in the reverse colors (e.g. white on black). HiliteMenu(0) ; then causes the bits behind to be restored. ; INTERESTING...: Because most apps that play with multiple heaps (e.g. TurboPascal) already ; know about the menuList, the handle to the bits behind a hilited title ; are saved in the menuList rather than the mbarproc private data. That ; way we don't have to worry about having multiple menus hilited under ; twitcher either (though we still can't have menus down across several ; apps at the same time) ; ; ASSUMPTIONS: ; 1. The menuID is valid, i.e. the menu is found in the menuList. ; ; On entry A3 MenuList menu list pointer. Its handle is locked. ; ; Calc values for A4 menu ptr selected/unselected menu ptr ; D3 index index into menu list (#6 offsets) ; D4 font info font ascent + leading (see GetMenuInfo) HiliteBar BSR ClipMBar ; MOVE.W param2+2(A6),D0 ; get the hilite selector BEQ FlipBar ; if index = 0 then flip bar <35> CSS CMP.W #1,param2(a6) ; hi-word has hilite BGT.S DoneHilite ; if not in range we support then bye-bye blt.s Unhilite ; unhiliting is totally different from hiliting CMP.W lastMenu(A3),D0 ; is it a legal menu title? <10>(lastRight->lastMenu) BGT.S DoneHilite ; nope, so return moveq #0, d3 ; clear d3 move.w d0, d3 ; keep 6 byte offset here BSR GetTitleRect ; get this title's rect in TempRect ; If we got here then everything is valid, so lock down the selected menuHandle MOVE.L menuOH(A3,D3),A0 ; get the selected menuHandle _HLock ; lock it down move.l (a0), a4 ; get selected menu ptr bsr.s DoSelected ; call save bits and draw routine move.l menuOH(A3,D3),A0 ; get the selected menuHandle _HUnlock ; and unlock it ; be a good citizen and set clip full open before we leave DoneHilite bsr FullClip ; set clip wide open RTS ; unhiliting works no matter what menu offset is passed in, since we just restore the bits Unhilite bsr DoNormal bra.s DoneHilite ;------------------------------------------------------------------- ; Hilite State is 0 -- unhilited/normal appearance -- restore bits ;------------------------------------------------------------------- DoNormal ; we clear TheMenu here because DrawMenuBar may be called by ; RestoreBits and we don't want to draw and later un-hilite the bits clr.w TheMenu move lastMenu(a3), d0 ; get last regular menu addq #6, d0 ; offset to HMenu header info subq #2, sp ; make room for result move.l menuTitleSave(a3,d0.w),-(sp) ; get title handle clr.l menuTitleSave(a3,d0.w) ; and clear out saved handle _RestoreBits addq #2, sp ; ignore the result clr.l SavedHandle ; set lomem to NIL rts ;------------------------------------------------------------------- ; Hilite State is 1 -- selected appearance -- save bits, draw title ;------------------------------------------------------------------- DoSelected moveq #0,d0 ; Title bits should NEVER be purgable <41> ; title rect is already in TempRect bsr SaveDemBits ; get the bits behind the title rect move lastMenu(a3), d0 ; get last regular menu addq #6, d0 ; offset to HMenu header info move.l SavedHandle, menuTitleSave(a3,d0.w) ; store new handle clr.l SavedHandle ; clear out lomem move.w #1, SelectFlag(a6) ; set select flag bsr DrawCommon ; use common code to draw rts ;----------------------------------------------- ; Utility -- FlipBar ;----------------------------------------------- ; use the hilite color to flip the bar to be sure hiliting happens FlipBar tst.b onColorMachine(a6) beq.s @DoInvert bsr SaveCurrentColors ; save current colors in stackframe bsr GetPixelDepth ; put the current pixel depth in the stack frame cmpi.w #2, PixelDepth(a6) ; is this 2+ mode, and color ? blt.s @DoInvert ; no, its 1 bit mode, so don't set color subq #4, sp ; save space for result clr.l -(sp) ; ID=0, Item=0 ===> menubar entry _GetMCEntry ; get the color entry move.l (sp)+, d0 ; get the result, and set z-flag if necessary beq.s @DoDefault ; zero ===> no entry so use default ; we got a menu bar entry from the color table, so use it to color the menu bar move.l d0, a0 ; get ptr to color entry in a0 pea mctRGB1(a0) ; push fore color pea mctRGB4(a0) ; push back color bra.s @DoColorSet @DoDefault ; default is always black on white pea RGBBlack pea RGBWhite @DoColorSet _RGBBackColor _HiliteColor bclr #HiliteBit, HiliteMode ; set hilite bit so uses hilite color @DoInvert ; finally we can invert the dang thing ; Set clip to intersection of screen's round rect and menu bar rect subq #4, sp ; alloc space for rgn handle _NewRgn ; alloc and leave on the stack _OpenRgn ; create rgn containing rounded screen pea portRect(a2) ; push portRect BTST #7,onLCDMac(A6) ; is this Harpo BZ.S @2 ; if not, then skip this _FrameRect BRA.S @3 @2 move.l #ScreenRadius, -(sp) ; push rounding factor _FrameRoundRect @3 move.l (sp), -(sp) ; push rgn handle _CloseRgn ; close and rgn on the stack move.l (sp), -(sp) ; srcA is rounded screen move.l clipRgn(a2), -(sp) ; srcB is currently set to menu bar rect move.l clipRgn(a2), -(sp) ; dest is same as srcB _SectRgn ; do intersect _DisposRgn ; rgn is on the stack PEA portRect(A2) ; push screen bounds rect _InverRect bsr ResetPreviousColors ; and restore colors before leaving BRA DoneHilite ;----------------------------------------------- ; Utility -- GetTitleRect ;----------------------------------------------- ; ; GetTitleRect is a utility that returns the adjusted bounding rect of the ; title whose menu title number is in the lo half of D0. ; The resultant rect is returned in TempRect. For titles, the rect is ; not the full bounds of the title, but the portion that is modified ; by hilite. If the requested title is 0, then the entire menu bar rect is ; returned including the topmost and bottommost lines. ; ; use portRect instead of assuming topLeft is (0,0) GetTitleRect TST.W D0 ; superflous test, but just to be safe BEQ WholeBar ; if 0, then return entire MBar rect LEA TEMPRECT,A0 ; get address of the rectangle move portRect+Top(a2), (a0) ; get top of menubar addq #1,(A0)+ ; top is one MOVE MENULEFT(A3,D0),(A0) ; left is menuLeft[index] move portRect+Left(a2), d1 ; add d1, (a0) ; offset from portRect properly SUBQ #1,(A0)+ ; really want left-1 move portRect+Top(a2), (a0) ; get top of menu bar move MBarHeight, d1 ; add d1,(A0) ; bottom = top + mbarheight SUBQ #1,(A0)+ ; need bottom-1 ; _DMSG 'Welcome to GetTitleRect' move portRect+Left(a2), (a0) ; set up for menu right MOVE.L A0, -(SP) ; Save A0 MOVE.L menuOH(a3,d0), A0 ; get the menu handle MOVE.L (A0), A0 ; handle -> ptr CMP.W #-16384, menuID(A0) ; Is it a system menu? MOVE.L (SP)+,A0 ; Restore A0 BGE.S @notSysMenu ; Wasn't a system menu CMP LASTMENU(A3),D0 ; is it the last one? BEQ.S @DoLastSysMenu ; The last one is a sys menu (use portRect.right) MOVE.W menuLeft(a3,d0), d1 ; get the left of this menu ADDQ #6,D0 ; bump to next slot MOVE.W menuLeft(a3,d0), d0 ; get the left of next menu CMP.W lastRight(a3), d1 ; Is menu.left < lastRight? BLT.S GTDone ; No, all or part is obscured BRA.S @useD0 ; Otherwise use menu.right @notSysMenu MOVE.W D0, D1 ; Save off 6B0 target BSR FindFirstSystemMenu6BO ; Get the 1st system menu BNE.S @1 ; There are system menus, so prev is last MOVE.W LASTMENU(A3), D0 ; DO the comparison against last bra.s @2 @1 SUB.W #6, D0 ; Bump down the comparison @2 EXG D0, D1 ; d0<=target d1<=6B0 of last reg menu CMP D0, D1 ; is it the last regular menu? BEQ.S @useLastRight ; The last one is a regular menu (use lastRight) @notLast move menuLeft(a3,d0), d1 ; get the left of this menu ADDQ #6,D0 ; bump to next slot move menuLeft(a3,d0), d0 ; get the left of next menu cmp.w lastRight(a3), d1 ; Is menu.left > lastRight? bgt.s GTDone ; Yes, the menu is into the last system menu cmp.w lastRight(a3), d0 ; Is menu.right > lastRight? ble.s @useD0 ; No, use menu.right else use lastRight @useLastRight move.w lastRight(a3), d0 ; use lastRight bra.s @useD0 @DoLastSysMenu move portRect+right(a2), d0 ; Get the right edge of the screen sub.w #mbMenu1Loc, d0 ; symmetrical w/ apple menu move D0, (A0) ; Slam the value bra.s GTDone ; And we're outa here @useD0 ADDQ #4,(A0) ; leave some margin on right add d0,(A0) ; right is lastRight GTDone RTS ; return to caller WholeBar LEA TempRect,A0 ; get address of the rectangle move portRect+Top(a2), (a0)+ ; top move portRect+Left(a2),(a0)+ ; left move portRect+Top(a2), (a0) ; bottom = top + mbarheight move MBarHeight, d1 ; add d1,(A0)+ ; MOVE.W PortRect+Right(A2),(A0) ; right is screen right BRA.S GTDone ; all done... ;-------------------------------------------------------------------------------------------- ; ; Msg #7 -- SaveBitsBar -- save bits behind menu, clear to proper color, and draw struct ; ;-------------------------------------------------------------------------------------------- ; ; The SaveBitsBar call saves the bits in a pulldown's menuRect, ; then clears and frames the rect. It takes the menuIndex to act on in ; param. This code now stores the menu's menuRect and SavedHandle in the structure ; inited by the mbarproc (see InitBar msg above), and returns a pointer to the ; menuRect field in that structure. SaveBitsBar bsr FullClip ; set clip wide open BSR RemoveAnyBalloon ; remove any help balloons that are showing ; Copy the passed menu rectangle into the stackframe move.l param2(a6), a0 lea menuRect(a6), a1 move.l Top(a0), Top(a1) move.l Bottom(a0), Bottom(a1) ; Copy the menu's rectangle to TempRect, and expand it by 4 pixels so that we save the bits ; behind the structure too. SaveDemBits expects the expanded rect in TempRect. LEA TEMPRECT,A0 ;point to the rectangle LEA menuRect(A6),A1 ;get menuRect of current menu MOVE.L A0,-(SP) ;push pointer to tempRect, too MOVE.W Top(A1),Top(A0) ; copy menuRect into tempRect ADDQ.W #3,Top(A0) ; save bottommost pixel in menu bar MOVE.W Left(A1),Left(A0) ; copy left MOVE.L Bottom(A1),Bottom(A0) ; copy botRight,too MOVE.L #$FFFCFFFC,-(SP) ; push -4,-4 _InsetRect ; expand saveRect by 4 pixels moveq #1,d0 ; Allow these bits to be purgable <41> bsr SaveDemBits ; save the bits into a bitmap or pixmap DrawStruct SUBQ #2,SP ; make room for result PEA menuRect(a6) ; push pointer to menuRect _EmptyRect ; look for an empty menu TST.B (SP)+ ; otherwise nothing will cast a shadow BNE SaveBitsDone ; => and we wouldn't want that to happen tst.b onColorMachine(a6) beq.s @DoErase move param1(a6), D0 ; get menuList offset from param1 MOVE.L menuOH(A3,D0),A1 ; get the menuData handle move.l (a1), a4 ; get menu ptr in a4 for SetTitleColor move #1, TitleBackFlag(a6) ; message that calling SetTitleColor from here clr selectFlag(a6) ; drawing normal (unselected) object bsr SetTitleColor ; set the proper background color @DoErase lea menuRect(a6), a4 ; load address of menuRect into a4 move.l a4, -(sp) ; push pointer to menuRect _EraseRect ; erase the menuRect tst.b onColorMachine(a6) beq.s @noColor bsr ResetPreviousColors ; and reset the previous colors @noColor ; paint the boundary and shadow -- first set up the pen _PenNormal move Left(a4), -(sp) ; subq #1, (sp) ; want Left-1 move (sp), -(sp) ; push it again move (sp), -(sp) ; and again move Top(a4), -(sp) ; _MoveTo ; MoveTo(Left-1, Top) move Bottom(a4), -(sp) ; push _LineTo ; LineTo(Left-1, Bottom) move Right(a4), -(sp) move Bottom(a4), -(sp) _LineTo ; LineTo(Right, Bottom) move Right(a4), -(sp) move Top(a4), -(sp) subq #1, (sp) ; want Top-1 _LineTo ; LineTo(Top-1, Right) move Top(a4), -(sp) subq #1, (sp) ; want Top-1 _LineTo ; LineTo(Left-1, Top-1) ; paint a drop shadow for the menu MOVE.L #$00020002,-(SP) ;push shadow factor _PenSize ;make penSize = shadow factor MOVE RIGHT(A4),D0 ;get right of menuRect MOVE D0,-(SP) ;push right MOVE TOP(A4),-(SP) ;push top ADD #2,(SP) ;want top+shadow MOVE D0,-(SP) ;push right MOVE BOTTOM(A4),D0 ;get bottom MOVE D0,-(SP) ;push bottom MOVE LEFT(A4),-(SP) ;push left ADD #2,(SP) ;want left+shadow MOVE D0,-(SP) ;push bottom _MoveTo ;MoveTo(left+shadow,bottom) _LineTo ;LineTo(right,bottom) _LineTo ;LineTo(right,top+shadow) _PenNormal ;restore normal pen SaveBitsDone ; First need to calculate MenuDir in stackframe move #mbRightDir, MenuDir(a6) ; assume it went "right" move.l mbSaveLoc, a0 ; get handle to mbarproc data storage move.l (a0), a0 ; dereference move lastMBSave(a0), d0 ; any menus saved yet? beq.s @gotDir ; no ==> therefore store "right" move mbRectSave+Left(a0,d0), d1 ; get left edge of previous menu cmp menuRect+Left(a6), d1 ; left of prev. menu < current menu left? blt.s @gotDir ; yes ==> menu went "right" move #mbLeftDir, MenuDir(a6) ; no ==> menu went "left" @gotDir ; Place the menuRect and SavedHandle in the mbar's structure. addi.w #mbEntrySize, lastMBSave(a0) ; update count of num menus on screen move.w lastMBSave(a0), d0 ; get num menus move.l menuRect(a6), mbRectSave(a0,d0.w) ; copy adjusted menuRect into save area move.l menuRect+4(a6), mbRectSave+4(a0,d0.w) move.l SavedHandle, mbBitsSave(a0,d0.w) ; copy handle to bits behind move.w MenuDir(a6), mbMenuDir(a0,d0.w) ; copy menu direction move.w Param1(a6), d1 move.w d1, mbMLOffset(a0,d0.w) ; copy menuList offset move.l menuOH(a3,d1.w), mbMLHandle(a0,d0.w) ; copy menuList handle RTS ;----------------------------------------------- ; Utility -- CalcMenuRect ;----------------------------------------------- ; Utility shared with msg #9 GetRect when the ; rect needs to calculated rather than just ; retrieved from the mbarproc data structure CalcMenuRect MOVE.L param2(A6),D0 ; get the param (6 byte offset into menuList) move.w param2(a6), VMousePt(a6); store vertical mouse pt in stackframe ; notice that it is move.w not move.l !! MOVE.L menuOH(A3,D0),A1 ; get the menuData handle MOVE.W menuLeft(A3,D0),D3 ; get the menuLeft too add portRect+Left(a2), d3 ; adjust for portRect MOVE.L (A1),A0 ; dereference it TST.L MENUWIDTH(A0) ; is size valid? BPL.S @SkipCalcSize ; yes, no need to recalc MOVE.L A1,-(SP) ; save menu record handle MOVE.L A1,-(SP) ; push handle for calc _CalcMenuSize ; get valid MENUWIDTH,MENUHEIGHT MOVE.L (SP)+,A0 ; get handle to menuRecord again move.l (a0), a0 ; and get the pointer for MakeMRect @SkipCalcSize BSR.s MakeMRect ; calc the MenuRect in stack frame rts ;----------------------------------------------- ; Utility -- MakeMRect ;----------------------------------------------- ; ; MakeMRect is a utility which calculates the boundsRect for the menu whose ; menuLeft is in D3, and whose menuData pointer is in A0. It returns ; this rect in the stack frame. It trashes D0-D1/A1 and modifies D3. ; ; use portRect instead of assuming topLeft is (0,0) MakeMRect ; set up the menuRect -- first adjust menuLeft to ensure the menu stays on the screen MOVE.W VMousePt(a6), d1 ; if != 0 ===> is a hierarchical menu BNE MakeHMRect ; branch if hierarchical menu MOVE.W #mbRightDir, MenuDir(a6); assume menu going right MOVE.W portRect+Top(a2), d1 ; get top of menubar add MBarHeight,D1 ; bottom = top + mbarheight MOVE.W D3,D0 ; get menuLeft in D0 ADD MENUWIDTH(A0),D0 ; get right edge ADDQ #8,D0 ; leave a little margin CMP PortRect+Right(A2),D0 ; compare with size of screen BLE.S StoreRect ; if smaller, we're cool ; adjust menuLeft so the menu fits on the screen MOVE.W #mbLeftDir, MenuDir(a6) ; change menu's direction ; <11> MOVE.W menuID(A0), D0 ; Get this menuID CMP.W #-16384, D0 ; Is it a system menu ( < 16384 ) BLT.S @AdjustMenuForSystemLook MOVE.W PortRect+Right(A2),D3 ; get right edge SUBQ #8,D3 ; leave some margin SUB MENUWIDTH(A0),D3 ; compute where left should be BRA.S StoreRect @AdjustMenuForSystemLook ; GetTitleRect writes into TempRect, so save off a copy first... LEA TempRect, A1 ; Get TempRect MOVE.L topLeft(A1), -(SP) ; Save topLeft MOVE.L botRight(A1), -(SP) ; Save botRight MOVE.L param2(A6), D0 ; Get the 6B0 into low word MOVEM.L A0/D1, -(SP) ; Save off regs for a sec BSR GetTitleRect ; Get the title rect into temprect MOVEM.L (SP)+, A0/D1 ; Restore regs MOVE.W right(A1), D3 ; Get the right edge of the title SUB.W MENUWIDTH(A0),D3 ; compute where left should be SUB.W #1,D3 ; the Pauline tweek <16> MOVE.L (SP)+, botRight(A1) ; Restore botRight MOVE.L (SP)+, topLeft(A1) ; Restore topLeft CMP.W PortRect+Left(A2),D3 ; IF assumedLeft <= portRect.left THEN BGT.S StoreRect ; Don't branch MOVE.W PortRect+Left(A2),D3 ; Get a new left ADD.W #4, D3 ; Add a slop factor StoreRect LEA MenuRect(A6),A1 ; get address of rectangle MOVE.W D1,(A1)+ ; set up top of menuRect MOVE.W D3,(A1)+ ; set up menuLeft ADD.W MENUHEIGHT(A0),D1 ; get height MOVE.W D1,(A1)+ ; set up bottom ADD.W MENUWIDTH(A0),D3 ; compute right of menuRect MOVE.W D3,(A1) ; move in right point RTS ;----------------------------------------------- ; Utility within a utility -- MakeHMRect ;----------------------------------------------- ; ; This is for a hierarchical menu, so do the following: ; 1. Make top line up with previous item unless menu hits bottom of the screen ; 2. Go same direction as last menu up ; 3. If hit edge of screen try to go in other direction ; 4. If hit edge of screen then give up and just plop it on the screen any old place ; On Entry: A0 ptr points to menuRecord for current menu ; d1 pt vertical mouse pt ; MakeHMRect ; d1 has vertical mouse pt when we get here. Stabilize menu so top item lines up ; with selected item on previous menu. If menu is too long then move top up until ; either the bottom is 8 pixels above the bottom of the screen or top comes within ; 7 pixels of the menu bar. movem.l d2-d5/a0-a3, -(sp) ; save work registers move.l d1, d5 ; move vertical mouse pt into d5 bsr GetSizes ; get font info in stackframe bsr GetA1SaveData ; get ptr to previous menu's data in a1 move mbTopScroll(a1), d2 ; get previous menu's top move.l mbMLHandle(a1), a3 ; get previous menu's handle moveq #1, d4 ; start with first item @ItemLoop move d4, d0 ; get item bsr GetItemRecord ; look it up, put item's string ptr in a0, ; properties ptr in a1 bsr GetItemHeight ; get item height in d0 add d0, d2 ; d2 now has bottom of item cmp d5, d2 ; is bottom of item below mouse pt ? bgt.s @FoundItem ; yes, so we found the item addq #1, d4 ; go to next item bra.s @ItemLoop ; and try next item @FoundItem sub d0, d2 ; d2 now has top of item to line up with move d2, d1 ; put it in d1 for rest of this routine movem.l (sp)+, d2-d5/a0-a3 ; restore work registers SUBQ.W #7, D1 ; move item top up 7 pixels (tune it!) <1.8> MOVE.W portRect+top(A2), D0 ; menu bar height is relative <1.8> ADD.W MBarHeight, D0 ; to top of portRect <1.8> CMP.W D0, D1 ; compare with menu bar height <1.8> bge.s @SetBottom ; if top not in menu bar then don't reset top MOVE.W D0, D1 ; top is in menu bar <1.8> @SetBottom addq.w #7, d1 ; Move top down 7 pixels. move d1, d0 ; get top in d0 temporarily add.w menuHeight(a0), d0 ; find menu bottom addi #12, d0 ; add 12 pixels so don't hit screen bottom exactly cmp.w portRect+Bottom(a2), d0 ; compare it to the bottom of the screen BLE.S @BottomOK ; if < or = to bottom then we are ok <1.8> ; menu extends beyond the bottom of the screen so recalc top MOVEQ.L #-12, D0 ; move it up 12 pixels from screen bottom <1.8> ADD.W portRect+Bottom(a2), d0 ; get screen bottom <1.8> sub.w menuHeight(a0), d0 ; d0 now has correct height move d0, d1 ; put it in back in d1 @BottomOK ; now calculate left, right and bottom bsr GetA1SaveData ; get ptr to previous menu's data in a1 move.w mbMenuDir(a1), MenuDir(a6) ; assume direction of last menu cmpi.w #mbLeftDir, MenuDir(a6) ; if going left then branch beq.s @MenuToLeft ; menu going right. Menuleft starts 4 pixels in from previous menu's right hand edge. @MenuToRight move.w mbRectSave+Right(a1), d0; get previous menu's right edge subi.w #4, d0 ; overlap 4 pixels move.w d0, d3 ; save location in d3 for StoreRect add menuWidth(a0), d0 ; get right edge by adding menu's width addq #8, d0 ; leave a little margin cmp PortRect+Right(a2), d0 ; compare with size of screen ble.s @DoneMakeH ; if smaller we're cool ; oops, menu needs to go left instead of right, ; menuRight starts 4 pixels from left edge of previous menu. move.w #mbLeftDir, MenuDir(a6) ; change direction in stackframe move.w mbRectSave+Left(a1), d0 ; get previous menu's left edge sub menuWidth(a0), d0 ; shift left edge to the left where it should be add.w #8, d0 ; overlap 8 pixels going left !!! move.w d0, d3 ; save location in d3 for StoreRect ; one last check, if left edge of menu flops over left edge of screen then bring ; it back onto the screen subq #8, d0 ; leave a little margin cmp PortRect+Left(a2), d0 ; compare with size of screen bge.s @DoneMakeH ; we're cool move PortRect+Left(a2), d0 ; damn, we need to reset rect again addq #8, d0 ; leave a little margin move d0, d3 ; and put loc in d3 for StoreRect move #mbRightDir, MenuDir(a6); change direction one last time bra.s @DoneMakeH ; done... ; menu going left. MenuRight starts 8 pixels in from previous menu's left hand edge. @MenuToLeft move.w mbRectSave+Left(a1), d0 ; get previous menu's left edge addi.w #8, d0 ; overlap 8 pixels going left sub menuWidth(a0), d0 ; shift left edge to the left where it should be move.w d0, d3 ; save location in d3 for StoreRect subq #8, d0 ; leave a little margin cmp PortRect+Left(a2), d0 ; compare with size of screen bgt.s @DoneMakeH ; if smaller we're cool ; oops, menu needs to go right instead of left, ; menuRight starts 4 pixels from right edge of previous menu. move.w #mbRightDir, MenuDir(a6); change direction in stackframe move.w mbRectSave+Right(a1), d0; get previous menu's right edge sub.w #4, d0 ; overlap 4 pixels move.w d0, d3 ; save location in d3 for StoreRect ; one last check, if right edge of menu flops over right edge of screen then bring ; it back onto the screen add.w menuWidth(a0), d0 ; get right edge of HMenu addq #8, d0 ; leave a little margin cmp PortRect+Right(a2), d0 ; compare with size of screen ble.s @DoneMakeH ; we're cool move PortRect+Right(a2), d0 ; damn, we need to reset rect again sub menuWidth(a0), d0 ; move it in from right edge of screen subq #8, d0 ; and a little more for good luck move d0, d3 ; and put loc in d3 for StoreRect move #mbLeftDir, MenuDir(a6) ; change direction one last time @DoneMakeH bra StoreRect ; and continue ;--------------------------------------- ; 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, A3 handles 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. GetItemRecord MOVE.L (A3),A0 ; get menu ptr <2.2> TST.w 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.w 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.w 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 Exit MOVE.L A0,D0 ; and set the z-flag 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 bsr.s ExpandItem ; puff item up to full size <2.1> bra.s EXIT ; and leave ; ExpandItem. Take basic menu item data and fill in more with _GetAuxMenuItem. ; New in <2.1>. ; On entry: A1 points to a menu item ; A3 is the menu handle ; ; On exit: A0 points to the item string of interest ; A1 points to that item's attribute byte list (on the stack) ; Eats D0, D1 ExpandItem ; copy menu item attributes to stack, split into distinct fields (unroll the ; variant in itemCmd). movem.l d2/a2,-(sp) ; save regs <2.2> move.l a1,a2 ; move pointer to safe register moveq #0,D1 ; clear D1 for byte arithmetic move.b (a1)+,d1 ; get length add d1,a1 ; bump to item properties lea itemStackBase(a6),a0 ; address of working copy ; set defaults (one at a time, to avoid odd-address problems since string be any length) move.b (a1)+,(a0)+ ; copy attribute byte move.b (a1)+,(a0)+ ; copy attribute byte move.b (a1)+,(a0)+ ; copy attribute byte move.b (a1)+,(a0)+ ; copy attribute byte clr.l (a0)+ ; set defaults clr.l (a0)+ ; set defaults clr.l (a0) ; set defaults lea itemStackBase(a6),a0 ; address of working copy, again ; check for script code moveq #0,d1 ; clear the air move.b itemCmd(a0),d1 ; get record variant field cmp.w #ScriptMenuCmd,d1 ; is there a script code? bne.s notScripted ; jump if not move.b itemIcon(a0),itemScript+1(a6) ; if scripted, icon has script number clr.b itemIcon(a0) ; reset field to say "no icon" bra.s doneConvert ; rejoin ; check for hierarchical item notScripted cmp.w #HMenuCmd,d1 ; hierarchical menu? bne.s notHierarchical ; jump if not move.b itemMark(a0),itemHierarchicalID+1(a6) clr.b itemMark(a0) ; reset to say "no mark" bra.s doneConvert ; rejoin ; check for icon and icon type notHierarchical cmp.w #ShrunkenIconCmd,d1 ; shrunken icon? beq.s sizedIcon ; jump if so cmp.w #SmallIconCmd,d1 ; small icon? beq.s sizedIcon ; jump if so tst.b itemIcon(a0) ; is there an icon? beq.s getAuxdata ; jump if not move.w #LargeIconCmd,itemIconSize(a6) ; save default icon type bra.s getAuxData ; and continue (don't clear itemCmd!) sizedIcon move.w d1,itemIconSize(a6) ; copy type to proper field doneConvert clr.b itemCmd(a0) ; reset field to say "no command key" getAuxData subq.l #2,sp ; room for return result move.l a3,-(sp) ; push menu handle move.l a2,-(sp) ; push pointer to menu item pea itemIconHandle(a6) ; push buffer address move.l #Sizeof_auxdata,-(sp) ; push buffer size _GetAuxMenuItem ; get the extra info addq.l #2,sp ; dump result move.l a2,a0 ; point at name (in list item) lea itemStackBase(a6),a1 ; point at the (extended) attributes tst.l itemIconHandle(a6) ; icon handle known now? beq.s doneExpand ; jump if not clr.b itemIcon(a1) ; nuke unneeded resource # doneExpand movem.l (sp)+,d2/a2 ; restore regs <2.2> rts ; return to sender ;--------------------------------------- ; 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> CMP.W #14,(A2) ; fudge width for chicago <1Aug85> BNE.S @notChicago ; => not chicago <1Aug85> SUBQ #2,(A2) ; <1Aug85> @notChicago ADDQ #2,A2 ; skip over widmax <1Aug85> ADD.W D0,(A2) ; store total height in MFHeight(A6) <1Aug85> RTS ;--------------------------------------- ; Utility -- GetItemHeight ;--------------------------------------- ; GetItemHeight gets the height of the current menu item into D0. ; The item pointer is in A1. GetItemHeight MOVE.W MFHeight(A6),D0 ; get menu item height <1Aug85> TST.W itemIconSize(A6) ; does it have an icon? <2.2> BEQ.S @gotHeight ; jump if not <2.2> MOVE #34,D1 ; size of large icon <2.2> CMP.W #LargeIconCmd,itemIconSize(a6) ; large icon? <2.2> BEQ.S @isLarge ; jump if so <2.2> MOVEQ #18,D1 ; else set to 18 <2.2> @isLarge CMP.W D0,D1 ; Is icon height > text height? <2.2> BLT.S @gotHeight ; Nope, skip around <2.2> MOVE.W D1,D0 ; Yes, use icon height instead <2.2> @gotHeight RTS ;----------------------------------------------- ; Utility -- SaveDemBits ;----------------------------------------------- ; ; Utility to create a bitmap or pixmap in which to save the bits in TempRect. ; Used by SaveBitsBar and HiliteMenu. ; ; On entry: TempRect has rectangle of bits to be saved. ; D0.b 1 if bits should be purgable, 0 if not <41> ; ; On exit: SavedHandle Has handle to bitmap or pixmap. ; If == 0 then couldn't alloc space. SaveDemBits subq #2,sp ; make room for error result pea TempRect move.b d0,-(sp) ; WITH purging <40><41> pea SavedHandle _SaveBits tst.w (sp)+ ; ignore error rts ;----------------------------------------------- ; Utility -- GetA0SaveData ;----------------------------------------------- ; ; utility to get pointer to last menu's save data in a0. GetA0SaveData move.l mbSaveLoc, a0 ; get handle to saved area move.l (a0), a0 ; dereference add.w lastMBSave(a0), a0 ; a0 points to last menu's data storage rts ;----------------------------------------------- ; Utility -- GetA1SaveData ;----------------------------------------------- ; ; Utility to get pointer to last menu's save data (from mbarproc struct) into a1. GetA1SaveData move.l mbSaveLoc, a1 ; get handle to saved area move.l (a1), a1 ; dereference add.w lastMBSave(a1), a1 ; a1 points to last menu's data storage rts ;----------------------------------------------- ; Utility -- RemoveAnyBalloon ;----------------------------------------------- RemoveAnyBalloon SUBQ #2,SP ; room for Boolean _HMGetBalloons ; what is the state of What Is? mode? TST.B (SP)+ BEQ.S @noHelper CLR.W -(SP) ; remove any balloons that are showing _HMRemoveBalloon TST (SP)+ @noHelper RTS ;-------------------------------------------------------------------------------------------- ; ; Msg #8 -- Restore -- retore bits behind a menu ; ;-------------------------------------------------------------------------------------------- ; ; This call restores the bits that were saved under a menu pulldown. ; If there was insufficient memory to save the bits, then an appropriate ; update event is posted. This call takes the menuIndex of the menu to be ; restored in parameter (this is only needed if data was not saved). ; RestoreBitsBar bsr FullClip ; set clip wide open BSR.s RemoveAnyBalloon ; remove any help balloons that are showing bsr.s GetA0SaveData ; get ptr to last menu's save data subq #2, sp ; make room the result move.l mbBitsSave(a0), -(sp) ; get handle to saved "bits-behind" _RestoreBits addq #2, sp ; ignore the result ; update number of menus on screen move.l mbSaveLoc, a0 ; get handle move.l (a0), a0 ; dereference subi.w #mbEntrySize, lastMBSave(a0) ; one fewer menu showing on screen RTS ;-------------------------------------------------------------------------------------------- ; ; Msg #9 -- GetRect -- return a ptr to a menuRect and reset other data needed by multiple ; menus. ; ;-------------------------------------------------------------------------------------------- ; ; This call returns a ptr to a menu's rectangle. The menuIndex (6 byte offset) is in ; the lo-word of of param. If it can't find the menuIndex, it calculates the menuRect. ; ; This routine is called by MenuSelect every time it loops thru. It needs to do this because ; if a HMenu was just displayed the last loop thru, then MenuSelect's menuRect will ; be incorrect. ; ; This routine is also called just before MrMacHook is called since MrMacHook needs the ; menu's rectangle and we normally don't have the rectangle until after the menu is drawn. ; ; This routine is now called by MenuSelect before executing the Save Msg. This way we ; isolate the calculation of the menu's rectangle from the code that save the bits and ; draws the menu structure. This allows PopUpMenuSelect to use the Save Msg. GetRectBar move.l Param2(a6), d0 ; get the param move.l mbSaveLoc, a0 ; get handle to mbar's save data move.l (a0), a0 ; dereference move.w lastMBSave(a0), d1 ; are there any menus? beq.s @MenuNotFound ; no, so go calculate size instead @MenuLoop cmp.w mbMLOffset(a0,d1), d0 ; did we find the menuID? beq.s @MenuFound ; yes, so branch subi #mbEntrySize, d1 ; move to next index beq.s @MenuNotFound ; if at end of list then didn't find menu bra.s @MenuLoop ; loop if more @MenuFound lea mbRectSave(a0,d1), a1 ; get address of rect move.l a1, Result(a6) ; and return it as the Result @RectBarDone rts @MenuNotFound bsr CalcMenuRect ; calculate the menu rectangle since we couldn't ; find it in the mbarproc data structure lea TempRect, a0 ; move rect into TempRect for result lea menuRect(a6), a1 move.l (a1), (a0) ; move Top/Left move.l 4(a1), 4(a0) ; move Bottom/Right move.l a0, Result(a6) ; return address of TempRect bra.s @RectBarDone ;-------------------------------------------------------------------------------------------- ; ; Msg #10 -- SaveAlt -- save other data pertinent to the menu after it is drawn ; ;-------------------------------------------------------------------------------------------- ; ; This message is called directly after the MDEF has drawn a menu. At that time the two ; scrolling globals topMenuItem and atMenuBottom are known. ; ; The reason the mbar proc saves these globals instead of having MenuSelect do it is because ; the mbarproc is already set up to save info about each menu (its rect, direction and offset) ; and so it is trivial to save two more words about each menu. The alternative would have ; been to have MenuSelect reproduce a lot of the code that the mbarproc has to manipulate this ; saved data. SaveAltBar move.l Param2(a6), d0 ; get the param move.l mbSaveLoc, a0 ; get handle to mbar's save data move.l (a0), a0 ; dereference move.w lastMBSave(a0), d1 ; are there any menus? beq.s @SaveAltBarDone ; no, so return @MenuLoop cmp.w mbMLOffset(a0,d1), d0 ; did we find the menuID? beq.s @MenuFound ; yes, so branch subi #mbEntrySize, d1 ; move to next index beq.s @SaveAltBarDone ; if at end of list then didn't find menu bra.s @MenuLoop ; loop if more @MenuFound move topMenuItem, mbTopScroll(a0,d1.w) ; save scrolling globals move atMenuBottom, mbBotScroll(a0,d1.w) @SaveAltBarDone rts ;-------------------------------------------------------------------------------------------- ; ; Msg #11 -- ResetScroll -- reset the scrolling globals for the given menu ; ;-------------------------------------------------------------------------------------------- ; ; Reset the global variables topMenuItem and atMenuBottom. ; ; This routine is called by MenuSelect every time it loops thru. It needs to do this because ; if a HMenu was just displayed the last loop thru, then not only will MenuSelects menuRect ; be incorrect, but the two scrolling globals are reset by the MDEF when it is asked to ; draw the menu and these must be reset. ResetScrollBar move.l Param2(a6), d0 ; get the param move.l mbSaveLoc, a0 ; get handle to mbar's save data move.l (a0), a0 ; dereference move.w lastMBSave(a0), d1 ; are there any menus? beq.s @ResetBarDone ; no, so return @MenuLoop cmp.w mbMLOffset(a0,d1.w), d0 ; did we find the menuID? beq.s @MenuFound ; yes, so branch subi #mbEntrySize, d1 ; move to next index beq.s @ResetBarDone ; if at end of list then didn't find menu bra.s @MenuLoop ; loop if more @MenuFound move mbTopScroll(a0,d1.w), topMenuItem ; reset scrolling globals for this menu move mbBotScroll(a0,d1.w), atMenuBottom @ResetBarDone rts ;-------------------------------------------------------------------------------------------- ; ; Msg #12 -- GetMenuRgn -- return the menu bar's region ; ;-------------------------------------------------------------------------------------------- ; ; ReturnMenuRgn move.l Param2(a6), -(sp) ; push the param on the stack ; use portRect instead of assuming topLeft is (0,0) move portRect+Left(a2), -(sp); left move portRect+Top(a2), -(sp) ; top move PortRect+Right(A2),-(SP); right move portRect+Top(a2), -(sp) ; bottom = top + mBarHeight move MBarHeight, d0 add d0, (sp) _SetRecRgn ; clip to the menu bar move.l Param2(a6), Result(a6) ; return handle passed in as the result @ReturnRgnDone rts ;-------------------------------------------------------------------------------------------- ; ; Msg #13 -- MoveSIcon -- move small icon into title of apple menu ; ;-------------------------------------------------------------------------------------------- MoveSICNToAM MOVE.B #SICNInAppleMenu, D6 ; Entry for moving SICN to Apple Menu BRA.S MoveIcon MoveSICNToPM MOVE.B #SICNInApplicationMenu, D6 ; Entry for moving SICN to Application Menu BRA.S MoveIcon MoveICSToAM MOVE.B #ICSInAppleMenu, D6 ; Entry for moving icon suite to Apple Menu BRA.S MoveIcon MoveICSToPM MOVE.B #ICSInApplicationMenu, D6 ; Entry for moving icon suite to Application Menu MoveIcon CLR.L Result(A6) ; Return 0 on (possible) failures MOVEQ #6, D3 ; 6 B.O. = 6 (first title) CMP.W (A3), D3 ; Is it in the legal range? BGT NoMoveS ; Skip if not MOVE.W lastMenu(A3), D0 ; Get last regular menu ADDQ.W #6, D0 ; Get to HMenu header TST.L menuTitleSave(A3, D0) ; Is a title highlighted? BNE NoMoveS ; Skip if so BTST #1, D6 ; if Apple Menu BNE.S @FindApplicationMenu MOVE.L menuOH(A3, D3), A0 ; Get handle to first menu MOVE.L (A0), A4 ; Get ptr to first menu CMP.W #$0114, menuData(A4) ; if (menuData != apple sign) BNE NoMoveS ; exit BRA.S @MenuFound @FindApplicationMenu ; else bsr FindFirstSystemMenu6BO ; See whether we have a system menu <43> beq NoMoveS ; if no system menu, exit <43> move.l d0,d3 ; put 6BO into our offset (d3) <43> @FindAppMenuLoop ; <43> cmp.w lastMenu(a3),d3 ; Is current menu is in menulist <43> bgt NoMoveS ; no => exit <43> MOVE.L menuOH(A3, D3), A0 ; Is current menu the Application menu? <43> MOVE.L (A0), A4 CMP.W #kApplicationMenuID, menuID(A4) BEQ.S @MenuFound ADDQ #6, D3 ; go to the next menu BRA.S @FindAppMenuLoop ; end while @MenuFound ; end if _HLock ; lock the menuhandle BSR ClipMBar ; Set clipRgn to menu bar CLR.W SelectFlag(A6) ; Draw normal mode CLR.W TitleBackFlag(A6) BSR SetTitleColor ; Set the colors (also saves current colors) MOVE.L D3, D0 BSR GetTitleRect BSR.S CalcRightRectSize ; grow or shrink TempRect to 16x16 MOVE.W Param1(A6), D4 ; Get the scroll distance BEQ.S @NoScroll ; Skip if no scroll SUBQ.L #4, SP ; Make room for the Update Rgn _NewRgn MOVE.L (SP)+, D5 PEA TempRect ; theRect MOVE.W D4, -(SP) ; dh = Param1 CLR.W -(SP) ; dv = 0 MOVE.L D5, -(SP) ; updateRgn _ScrollRect ; Scroll it MOVE.L D5, -(SP) ; rgn _SetClip ; Clip to the updateRgn MOVE.L D5, -(SP) ; rgn _DisposRgn BRA.S @ScrollDone @NoScroll PEA TempRect ; theRect _EraseRect @ScrollDone ; The IconState variable keeps track of where the current icon/title is. Currently it ; is interpreted to be the number of pixels left to shift in. MOVE.L mbSaveLoc, A0 ; Get handle to save data MOVE.L (A0), A0 ; Dereference it MOVE.W mbIconState(A0), D5 ; Get the icon state BGT.S @SameOld ; Still working on same icon ; A new icon is coming in. Reset the icon state to the title width MOVE.W TempRect+right, D5 ; Width of title SUB.W TempRect+left, D5 ; is width of TempRect @SameOld MOVE.W TempRect+left, D1 ; Pen normally based upon left edge of TempRect TST.L Param2(A6) ; Using an icon? BNE.S @anIcon ; Skip if so MOVE.W menuLeft(A3, D3), D1 ; Menu title based upon menuleft[index] ADD.W portRect+left(A2), D1 ; + portRect.left ADDQ.W #8, D1 ; + 8 @anIcon MOVE.W D4, D0 ; Get the shift distance BLT.S @ShiftLeft BGT.S @ShiftRight ; The icon/title is to be replaced in its entirety. MOVEQ #0, D5 ; Set icon state to 0 BRA.S @ShiftCommon @ShiftLeft ; The icon/title is moving left. ADD.W D0, D5 ; Decrement the icon state (D0<0) ADD.W D5, D1 ; Add it to pen BRA.S @ShiftCommon @ShiftRight ; The icon/title is moving right. SUB.W D0, D5 ; Decrement the icon state (D0>0) SUB.W D5, D1 ; Subtract it from pen @ShiftCommon MOVE.L clipRgn(A2), A0 ; Get the clip region MOVE.L (A0), A0 ; Dereference it MOVE.W D1, -(SP) ; x coordinate for pen BSR GetMenuAscent ; Returns value in D4 MOVE.W D4, -(SP) ; y coordinate for pen _MoveTo ; Set the pen location TST.L param2(A6) ; Get the icon handle BEQ.S @NoIcon ; Skip if none MOVE.L #$FFF40000, appleRect+topLeft(A6) ; top = -12, left = 0 MOVE.L #$00040010, appleRect+botRight(A6) ; bottom = 4, right = 16 PEA appleRect(A6) ; theRect for OffsetRect SUBQ.L #4, -(SP) ; Make room for pen MOVE.L SP, -(SP) ; Point to it _GetPen _OffsetRect ; Offset icon's rect by pen position BTST #0, D6 BEQ.S @IsaSICN SUBQ #2, SP ; make room for result PEA appleRect(a6) ; push the title rect MOVE.W #atAbsoluteCenter, -(SP) ; No need to do centering since the rect is of the right size MOVE.W #ttNone, -(SP) ; assume no transformation needed MOVE.L param2(A6), -(SP) ; push the icon handle _PlotIconSuite ADDQ #2, SP ; dump the result BRA.S MoveSDone @IsaSICN PEA appleRect(A6) ; theRect for PlotSIcon MOVE.L param2(a6), -(SP) ; theSIcon for PlotSIcon BSR.S PlotSIcon ; Plot it BRA.S MoveSDone @NoIcon BSR DrawSimple ; Draw the regular title MoveSDone MOVEQ #0, D0 ; Assume same icon MOVE.L mbSaveLoc, A0 ; Get handle to save data MOVE.L (A0), A0 ; Dereference it MOVE.W D5, mbIconState(A0) ; Save the icon state BGT.S @SameIcon ; Skip if still positive MOVEQ #-1, D0 ; Flag new icon needed @SameIcon MOVE.L D0, Result(A6) ; Return the result BSR ResetPreviousColors ; Restore the colors BSR FullClip ; Set the clipRgn back to full open MOVE.L menuOH(A3, D3), A0 ; Get the menuHandle _HUnlock ; Unlock it NoMoveS RTS ;-------------------------------------------------------------------------------------------- ; PROCEDURE PlotSIcon(theRect: Rect; theIcon: SIconHandle) PlotSIcon LEA IconBitMap, A1 ; Get address of the icon mgr bitMap MOVE.L 4(SP), D0 ; Get the icon handle BEQ.S DoneIPlot ; If nil, don't plot MOVE.L D0, A0 ; Get the Icon Handle in address reg MOVE.L (A0), (A1)+ ; baseAddr = master pointer MOVE.W #2, (A1)+ ; rowBytes = 2 CLR.L (A1)+ ; topLeft = 0, 0 MOVE.L #$00100010, (A1) ; botRight = 16, 16 MOVE.L 8(SP), D1 ; Get theRect LEA IconBitMap, A1 ; Point A1 at the bitMap again MOVE.L A1, -(SP) ; srcBits = iconBitMap MOVE.L GrafGlobals(A5), A0 MOVE.L thePort(A0), A0 PEA portBits(A0) ; dstBits = portBits PEA bounds(A1) ; srcRect = iconBitMap.bounds MOVE.L D1, -(SP) ; dstRect = theRect CLR.W -(SP) ; srcCopy CLR.L -(SP) ; maskRgn = nil _CopyBits DoneIPlot MOVE.L (SP)+, A0 ; Get return address ADDQ.L #8, SP ; Strip parameters JMP (A0) ; And return to caller ;-------------------------------------------------------------------------------------------- ; ; Msg #14 -- GetTRect -- Return the title rect of the menu given in param2 ; ;-------------------------------------------------------------------------------------------- ; ; Return the rectangle enclosing the area specified. ; NOTE: This call depends entirely on the GetTitleRect routine to calculate the ; bounding rectangle for each menu. DonΥt change it without changing this. ; It also assumes lastRight is the right edge of the visible app menus. ; ; Param1 Result ; ------------- ------------------------------------------------------------------ ; = 6 B.O. Return the title rect for that menu ; = 0 Return the rectangle enclosing the menu bar ; -1 Return the rectangle enclosing the system menus which are visible ; -2 Return the rectangle enclosing the apps menus which are visible ; GetTRect MOVE.L #0, result(A6) ; We always return zero LEA TempRect, A1 ; Get the address of tempRect MOVE.W param1(A6), D0 ; Which part of the menubar should we return? BMI.S @specialRect ; Wants special rect information CMP.W lastMenu(A3), D0 ; Is this a valid offset? BGT.S @returnEmptyRect ; Bail if someone is trying to run us off the road BSR GetTitleRect ; Puts the title rect into tempRect @StuffFromTemp MOVE.L param2(A6), A0 ; Get the address of the rectangle MOVE.L (A1)+, (A0)+ ; Copy topLeft MOVE.L (A1)+, (A0)+ ; Copy bottomRight RTS @specialRect TST.W lastMenu(A3) ; Are there any menus? BEQ.S @returnEmptyRect ; OH, NO! there are none! ADDQ #1, D0 ; Is it -1 (App menu case) ? BEQ.S @AppRect ADDQ #1, D0 ; Is it -2 (System menu case) ? BEQ.S @SystemRect @returnEmptyRect MOVEQ #0,D0 ; Get a zero MOVE.L D0, topLeft(A1) ; Set topLeft(TempRect) MOVE.L D0, botRight(A1) ; Set botRight(TempRect) BRA.S @StuffFromTemp ; Return that empty rect @SystemRect MOVEQ #0, D0 ; Clear out high word BSR FindFirstSystemMenu6BO ; Find the first system menu BEQ.S @returnEmptyRect ; Equal if no system menus @nextSysLoop MOVE.L D0, -(SP) ; Save across GetTitleRect call BSR GetTitleRect ; Get its title rect (left >= right if obscured) MOVE.L (SP)+, D0 ; Restore it MOVE.W left(A1), D1 ; Get the left side CMP.W right(A1), D1 ; IF left < right THEN {empty} BLT.S @foundVisSys ; found 1st visible system menu ADDQ #6, D0 CMP.W lastMenu(A3), D0 ; IF D0 <= lastMenu THEN BLE.S @nextSysLoop ; goto nextSysLoop BRA.S @returnEmptyRect ; We should never get here since the last system menu ; was never supposed to be obscured (BUT...) @foundVisSys MOVE.W left(A1), -(SP) ; Save the left side of visible system area MOVE.W lastMenu(A3), D0 ; Get the last menu 6 B.O. BSR GetTitleRect ; Get its title rect MOVE.W (SP)+, D0 ; Restore first vis menu.left from stack MOVE.W D0, left(A1) ; Force in the new left side BRA.S @StuffFromTemp ; And return this rect @AppRect MOVEQ #6, D0 ; Get the 1st menu 6 B.O. BSR GetTitleRect ; Get its title rect MOVE.W lastRight(A3), D0 ; Get the last right MOVE.W D0, right(A1) ; Stuff right with lastRight BRA.S @StuffFromTemp ; And return this rect ;-------------------------------------------------------------------------------------------- ; ; Msg #15 -- BannerMsg -- Draw the given string in the given script in the menubar ; ;-------------------------------------------------------------------------------------------- ; ; Erase the menu bar area and TextBox in the given string in the menu bar. ; ; Param1 Param2 ; -------------------------- ------------------------- ; ptr to pString none ; lo byte=scriptID ; hi byte=teJust for textbox ; BannerMsg moveq #0,a4 ; <49> Zero it out for the call to SetTitleColor CLR.W -(SP) ; Unhilite any hilited menu _HiliteMenu MOVE.L param2(A6), -(SP) ; Save off the old parameter value before clearing MOVE.L #-1, param2(A6) ; -1 is the clear indicator BSR DrawBar ; Draw a cleared menubar MOVE.L (SP)+, param2(A6) ; Restore the old parameter value MOVE.W param1(A6), D0 ; Get param1 TST.B D0 ; Is it script? BGE.S @noScript ; Nope AND.W #$7F, D0 ; Mask out the junk SUBQ #4, SP ; Make room for script result MOVE.W D0, -(SP) ; Push script ID MOVE.W #smScriptSysFondSize, -(SP) _GetScript _TextFont _TextSize @noScript move.w #srcOr, -(sp) ; set text mode to srcOr _TextMode MOVEQ #0, D0 ; Zero get the entire menubar rect BSR GetTitleRect ; Put rect into temprect PEA TempRect ; Get the address of tempRect MOVE.W #mbMenu1Loc, -(SP) ; This will be the horz inset MOVE.W #1, -(SP) _InsetRect ; TempRect has the TextBox rect MOVEQ #0, D0 ; Clear all bytes MOVE.W D0, SelectFlag(a6) ; clear select flag ==> draw normal mode MOVE.W D0, TitleBackFlag(a6) ; calling SetTitleColor from DrawTitle BSR SetTitleColor ; set color for title/background ;TextBox(p, size, r, style); MOVE.W param1(A6), D1 ; Get param1 ASR #8, D1 ; Roll down to the teJust MOVE.L param2(A6), A0 ; Get the stringPointer MOVE.B (A0), D0 ; Copy the length byte ADDQ #1, A0 ; Skip the length byte MOVE.L A0, -(SP) ; Pointer to text MOVE.L D0, -(SP) ; Length PEA TempRect ; the rect address MOVE.W D1, -(SP) ; the teJust _TextBox BSR ResetPreviousColors ; reset to original fore/back colors RTS ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ END