; ; File: MenuMgr.a ; ; Contains: Menu Manager for MacIntosh User Interface ToolBox ; ; This file contains the MacIntosh menu manager, which is based on Bill AtkinsonÕs ; Lisa menu manager. ; ; Written by: Andy Hertzfeld ; ; Copyright: © 1982-1993 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; <20> 11/5/93 IH Sync with Excelsior. ; 6/14/93 kc Roll in Ludwig (this replaces SM16). ; 5/3/93 chp Flush the caches for MDEF handles smaller than 32 bytes. It used ; to be 16 bytes, but a 22-byte, unflushed, fake defproc has been ; discovered in Software Ventures Microphone II and Microphone ; Pro. (RADAR #1082386) ; 3/8/93 fau Modified the checkin to only flush the cache for those ; MDEFs that are only 16 bytes or less in size. See the comment ; for more description. ; 5/21/93 CSS Remove call and import of SMgrCalcRect in InitMenus routine per ; P. Edberg's review. ; 1/12/93 CSS Rollin a patch from MenuMgrPatch.a to syncronize the keyboard ; menu within draw menubar. Fixes Radar bug #1057927. ; 11/18/92 CSS Cache flush hack to get Persuasion to work without putting ; cache flushing back in hlock. I am cache flushing when I ; call the MDEF. ; 11-06-92 jmp MenuSelect was NOT preserving A2, so I fixed it. ; 11/5/92 SWC Changed PackMacs.a->Packages.a. ; 8/13/92 JSM Changes from where no man has gone before: change references to ; MrMacHook to MBarHook to avoid confusing future generations, ; move call to SetTickCounters in MenuSelect after menuDelaySave ; and menuDragSave are set up, get rid of unused local tRect1 in ; MenuSelect, put back in the RTS at the end of InitMenus that was ; mysteriously deleted long ago. ; 6/22/92 RB Rolled-in the Help Manager patch to MenuSelect from ; BalloonPthc28.a, HMMenuSelectPatch and cleaned up MenuSelect a ; little bit. ; 6/12/92 CS Roll-in Reality Changes: ; <31> 6/12/92 FM Remove obsolete call to the internal ScriptMgr routine SwapIcon. ; <30> 6/1/92 DTY Remove InsrtResMenu from this file. Always use the one from ; MenuMgr.c. Make GetIndex an Exported procedure so that it can ; be used from MenuDispatch.a in the ROM build. ; <29> 5/24/92 JSM DonÕt use forTesting (always false), TearOffMenus (always ; false), or ScriptMgrKeyboardMenu (always true) conditionals. ; <28> 5/14/92 KSM #1028474,: Speed up MenuKey by not upper-casing the command ; key character for a menu item when there isnÕt one (ASCII NULL). ; <27> 5/14/92 KSM #1029927,: Roll back to version <19> (what an unbelievable ; mess!). ; 5/27/92 JSM Changes from Reality: DonÕt use forTesting (always false) or ; TearOffMenus (always false). NOTE: Before this file is rolled ; back into Reality, someone needs to put back in all the forROM ; and hasCQD conditionals Philip deleted. This file ¥is¥ used in ; System builds, and is patched in on non-color QD machines. ; 4/8/92 PN Fix previous header ; 4/8/92 PN Throw out extraneous push and pop stackpointer in SetMenuBar ; 4/6/92 PN Change GetMenuBar to the way it was. forROM condition does ; belong here after all. ScriptMgrKeyboardMenu condition needs to ; be investigated and either put back in or leave out . ; 4/3/92 PN Clean up patch roll-ins to make them more readable. Changes are ; in DrawMenuBar/HiliteMenu/GetMenubar/SetMenuBar and alse get rid ; of forROM and hasCQD conditions since this file is used in ROM ; only ; <5> 3/24/92 PN Back out FixBTSTBugInMenuKey since it's been rolled in already. ; Eliminate the forROM condition ; in Upchar to use only the correct version. Roll in ; PatchMDDrawMenuBar,PatchMDHiliteMenu, PatchMDMenuKey, ; PatchMDMenuSelect from ModalDialogMenuPatches.a. ; <4> 3/9/92 PN Roll in HMClearMenuBarPatch PatchProc _ClearMenuBar from ; Balloonptch28.a ; <2> 2/13/92 PN ; Roll in FixBTSTbuginMenuKey, SetMenuBarAddsSystemMenus, ; GetMenuBarDoesNotReturnSystemMenus, Savea5AroundCallMDEFPRoc, ; DrawMenuBarIfInvalidOnMenuSelect, ; DrawMenuBarIfInvalidOnHiliteMenu, ValidateMenuBarWhenDrawing, ; PatchInsertMenu in SystemMenuPatch.a ; <> ¥ÊHMClearMenuBarPatch still needs to be rolled in ¥ ; <1> ¥ Pre-SuperMario comments follow ¥ ; <26> 1/25/92 csd In order to let Cube-E go alpha, IÕm reversing the change to ; GetMenuBar that was made in <22> (the change history says it was ; made in <24>) since it doesnÕt work. ; <25> 1/21/92 PN Get rid of duplicate EQU in MenuMgr.a ; (CmdChar,MenuResult,mItemResult,searchMenu HorRMenus,KeyFrame) ; <24> 1/21/92 PN Rolled in SetMenuBarAddsSystemMenus from SystemMenusPatch.a ; Rolled in GetMenuBarDoesNotReturnSystemMenus from ; SystemMenusPatch.a ; Rolled in PatchInsertMenu from SystemMenusPatch.a ; Rolled in ValidateMenuBarWhenDrawing from InvalMenuBarPatch.a ; Rolled in DrawMenuBarIfInvalidOnHiliteMenu from ; InvalMenuBarPatch.a ; Rolled in FixBTSTBugInMenuKey from MenuMgrPatch.a ; <23> 1/20/92 PN Roll in patches into MenuMgr.a, in this file using the routine ; InsrResMenu from MenuMgr.c ; <22> 1/20/92 PN Roll-in all the linked patches into MenuMgr.a ; <21> 12/31/91 RB Undo change <20>, I tell you.. you gotta read the change ; history...nice try ; <20> 12/31/91 RB Added an END directive to get rid of the warning. ; <19> 10/10/91 PKE #1012672, For Cube-E (and Bruges): Use new SCUpperText routine ; in MenuKey instead of UpperText, so we are independent of any ; grafPort font. ; <18> 8/28/91 JSM Leave InsrtResMenu here for ROM builds for now. ; <17> 8/22/91 KSM csd,#Bruges: Change MenuKey to call _UpperText instead of ; _UprString,MARKS (in the subroutine UpChar). This is the ; internationally correct routine (new for 7.0). 2) Conditionalize ; out InsertResMenu here, now in MenuMgr.c ; <16> 7/9/91 JSM Remove obsolete 7.0 related SysVers conditionals. ; <15> 3/31/91 dba gbm, csd: change DisposeMenu so it handles properly the case ; when a resource-based menu has been purged ; <12> 3/6/91 gbm dba: Take out change <11>, because Philip didnÕt understand that ; this would break the system build. ; <11> 3/5/91 PN Fix the warning by putting back the END statement at the end ; <10> 12/14/90 KSM Fix bug in MenuKey where it is BTSTing a register for each ; item, but when the item is greater than 31, the BTST instruction ; wraps and we get flags for previous items. ; <9> 9/28/90 KSM Guarantee A5 world for calls into MDEFs. ; <8> 9/15/90 KSM Patch InsMenuItem to fix a PixelPaint bug!!*! ; <7> 7/30/90 KSM On the first day Ed was gone, we found a bug he created in ; version 2. An arbitrary line in ÒMenuChangedÓ was commented out. ; <6> 7/26/90 KSM fix DarinÕs stupid STRING ASIS bug ; <5> 7/23/90 dba change name of GetItemStyle so it doesnÕt conflict with glue ; <4> 5/13/90 SMB Removed SMgr patches in InitMenus and DrawMenuBar if not ; ÔForROMÕ since adding the Keyboard Menu. Will not patch out the ; ROM version of InitMenus since its call to SMgrCalcRect is ; harmless. However, am patching the SMgr's SwapIcon routine ; (called by DrawMenuBar) to do nothing. Need ScriptPriv.a all the ; time now due to the new flag used here. ; <3> 4/29/90 KSM Fix a bug in SetItemProperty which only is a bug if we turn on ; TearOffMenus againÉ ; <2> 12/19/89 EMT PROCize for more efficient dead code stripping. Nuked ; GetMenuInfo. Rearranged procedures for better branches. Renamed ; topEdge and leftEdge to not conflict with ColorEqu.a ; <1.9> 11/17/89 dba got rid of checks for 64K ROMs ; <1.8> 10/31/89 dba concatenated source files MenuMgr1.a and MenuMgr2.a to this one ; <2.7> 8/29/89 KSM Uses new vector routines to call Script Manager from RAM ; <1.9> 8/22/89 SES Changed mctSanityChk (which was in nFiles) to mctReserved (which ; is the official equ). ; <1.6> 8/22/89 SES removed references to nFiles. ; <2.5> 8/16/89 dba NEEDED FOR 6.0.4: InitProcMenu bug fixed: MBDF ID was not put in ; MenuList if MenuList was already allocated (InitMenus already ; called) ; <2.4> 8/8/89 dba NEEDED FOR 6.0.4: used TearOffMenus conditional; fixed ; InitProcMenu ; <2.3> 7/11/89 EMT Backed out 07Sep88 change to InitProcMenu to make Excel 2.2 ; happy. Needed for Aurora, Esprit, and 6.0.4. ; <2.2> 6/14/89 JSM Fixed System 7.0 IF statement (700 => $700). ; <2.1> 6/14/89 KSM Fixed stack handling. ; <2.0> 6/14/89 DAF Added missing Big Bang conditional. ; <1.9> 6/14/89 KSM Added command key tear off method ; <1.7> 6/14/89 KSM Fixed incorrect branch offset ; <1.4> 6/5/89 CCH Conditionalized out include of MenuDispatch.a. ; <1.8> 6/2/89 KSM Changed all (NOT forRAM) to (forROM). ; <1.6> 6/2/89 KSM Updated conditionals for ROM/SYS build ; <1.3> 6/2/89 KSM Added include for MenuDispatch. ; <1.5> 6/1/89 KSM TEAR OFF MENU feature added. ; <1.4> 4/29/89 KSM Updated comments for 1.3 ; <1.3> 4/25/89 KSM Fixed GetMenuBar bug to check for NIL MenuList and ; returns NIL instead of crashing. This problem exists because ; MultiFinder "faceless" applications donÕt call ; InitWindows/InitMenus, but they do call SystemTask or ; WaitNextEvent which allows drivers to run. Drivers (like Deneba ; SoftwareÕs Spelling Coach) which call GetMenuBar when the ; Backgrounder is running - CRASH. ; Also Fixed DelMCEntries bug to correctly delete ; the entries in the table correctly (not just 1st one). Also ; keeps it from running rampant thru memory if next to last was ; deleted. ; <1.2> 2/20/89 rwh re-spelled conditional in comment, wonÕt show up in searches. ; <1.1> 11/10/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <1.5> 11/2/88 GGD Got rid of machine specific conditionals in favor of feature ; based conditionals. ; <1.4> 10/27/88 PKE added script manager support for initmenus ; <1.3> 10/7/88 rwh make NuMac support work for MvMac as well ; <¥1.2> 10/3/88 EMT Roll in latest bug fixes. ; <¥1.2> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles ; PMAB568> 9/7/88 EMT Fix DeleteMenu so that highlighted menus are unhighlighted ; before being deleted. Custom menus should blink; fix ill-fated ; C222. Call MenuHook in CheckDragging And some miscellaneous code ; cleanup. ; PMAB568> 9/7/88 EMT AppendMenu calls CharByte to make sure meta characters are real. ; PMAB539> 7/19/88 EMT PopUpMenuSelect will now call CalcMenuSize when it invalidates ; sizes. ; 4/18/88 DHD Fix InsertMenu patch to compare with -1 instead of checking ; negative for BeforeIDÕs throughout the code. This was already ; done for the first test, but subsequent ones were missed. See ; PMAB214. ; <¥1.1> 3/22/88 EMT Roll in menu manager patches from 6.0 system. ; PMAB417> 3/3/88 EMT Patch GetMenuBar and SetMenuBar to handle saved bits correctly. ; 2/24/88 DBG Fixed bug in PMAB364 which caused crash in PopupMenuSelect. ; PMAB364> 1/23/88 EMT Fix Pop-up menus to come up on any screen ; PMAB303> 11/21/87 EMT Use ROM override to install MBDF from S297 instead of ; MBDFPatchHndl. ; PMAB282> 9/20/87 FJL DonÕt let DelMenuItem fool with EnableBits when item > 31. ; PMAB280> 9/18/87 FJL Set MBarEnable around SystemMenu call only if MBar not already ; owned by DA. ; PMAB280> 9/18/87 FJL Removed some overzealous lines added in PMAB255 ; PMAB255> 9/1/87 FJL Call HiliteMenu around DrawMenuBar so donÕt leave any bits ; behind dangling. ; PMAB255> 8/31/87 FJL DonÕt insert enable bit if item is > 31 ; PMAB233> 8/7/87 FJL HiliteMenu must do nothing if MBarHeight <= 3. ; PMAB214> 7/20/87 FJL InsertMenu inserts in HMenuList if (beforeID == -1) rather than ; (<= -1) ; 7/20/87 FJL Check HwCfgFlags for valid PRAM when getting HMenu drag and ; delay settings ; ; System 4.2 ; ; 3/26/87 FJL Changed MenuKey so that popups may have menu keys. ; 3/24/87 DAF Fixed DelMenuItem to call DelMCEntry only on nuMac. ; 3/6/87 FJL Clean up all NuMac conditionals for System Disk <1.2> ; 2/22/87 FJL New routines, GetItemCmd, SetItemCmd, PopUpMenuSelect ; 2/17/87 FJL Fixed FlashMenuBar to pass MenuList offset to mbarproc rather ; than menuID. ; 2/13/87 FJL Changed AddResMenu to call IUMagString. To do so needed to lock ; the menuHandle. This causes problems with Munger since it canÕt ; relocate the locked block. Therefore only lock the handle around ; the IUMagString call. ; 12/2/86 FJL EnableItem and DisableItem now ignore items > 31. ; 11/20/86 FJL Interesting problem in HiliteMenu ; 11/15/86 FJL Added support for color menus ; 11/10/86 FJL Use GetResource to get the mbarproc each time we call it. ; 11/2/86 RDC Added pad char to menu table for asm problem ; 11/2/86 RDC Changed equ name to fix asm problem ; 10/27/86 FJL The application OVERVUE assumed D1 was clear on exit from ; MenuSelect, so we clear it for them (cough cough) ; 10/15/86 FJL Added hierarchical menus. ; 10/1/86 FJL Exported InitProcMenu.See notes in MenuMgr1.a for fix to ; MenuSelect bug, etc. ; 9/24/86 DAF New menuBar defproc menu manager. See StandardMBDF.a also ; 9/24/86 DAF Updated MenuSelect for menuBar defproc ; JTC Cleaned up GetTheMDef/UnlkMDef for 32-bit robustness. ; 8/20/86 DAF Menu Bar DefProc modifications (see StandardMBDF.a) ; 8/8/86 FJL Fix to InitProcMenu and InitMenus for possible _GetResource ; error. Problem when moved mouse out of menu bar quickly, fixed ; with change in MenuSelect. Scrolling menus were drawing outside ; of their region, so set ClipRect in DrawTheMenu. Changed ; InitMenus so doesnÕt realloc menu struct if global menuList is ; not NIL (this allows InitWindows to call InitMenus to get ; MBarHeight without reallocing space when user calls InitMenus). ; Fix to _HiliteMenu -- when HiliteMenu was called with a ; non-existent menuID it would store that ID in theMenu global and ; cause the mbarproc to flip the bar when HiliteMenu(0) was next ; called. ; 6/30/86 EHB Made MenuSelect save off more bits for color. ; 4/10/86 SAB rolled in a patch from ROM75 to fix inserting into the middle of ; a resmenu. ; 2/19/86 BBM Made some modifications to work under MPW ; ; Lonely Hearts ROMs (Macintosh Plus) ; ; 11/2/85 EHB Reinstated call to _TextFont in InsertMenu (no one should change ; it, but...). ; 9/30/85 EHB Removed underline of FONDs in AddResMenu (put back CalcMenuSize) ; 9/6/85 EHB GetItemProperty was clearing a word result instead of a byte. ; 8/5/85 EHB .DEF CalcMBHeight for use by wmgr ; 8/5/85 EHB Modified for variable sized system font ; 7/9/85 EHB Get MDEF 0 from ROM map ; 5/21/85 EHB Made AddResMenu, InsertResMenu sort items as they go in ; 5/9/85 EHB Added new procedure InsMenuItem -- like append menu, but inserts ; anywhere. Now AppendMenu,InsMenuItem,AddResMenu,InsrtResMenu all ; share same insert code. ; 5/7/85 EHB In AddResMenu, make sure each name added is unique. Compare is ; done using CompString, also used by the Res Manager for ; getNamedResource. ; 5/3/85 EHB Oops! forgot to delete enable bits in DelMenuItem. All better ; now. ; 4/23/85 EHB In Insert/AddResMenu, if adding 'FONT', add 'FOND' too. ; 4/15/85 EHB Added new procedure DelMenuItem -- remove a menu item from its ; menu ; 4/15/85 EHB In routine MenuKey, use UprString to upshift the passed ; keystroke. ; 4/11/85 EHB Check for purged menuList and menu on all internal references If ; purged, I generate DS #54 (MenuPrgErr). ; 4/11/85 EHB Made menus of 0 size work. To do this, tweaked DirtyMenuSize to ; invalidate size with -1 instead of 0. ; 4/9/85 EHB Do GetMouse after WaitMouseUp to avoid invalid flashes CLR.L ; FuncResult(A6) to avoid returning invalid items ; 3/13/85 EHB Fixed stack frame for MenuSelect ; 3/13/85 EHB Fixed stack offset in DirtyMenuSize (oops!) ; 3/6/85 EHB Use update to restore menus if out of memory ; 3/5/85 EHB Added Routine DirtyMenuSize so that CalcMenuSize only gets ; called before drawing. ; 3/5/85 EHB Call CalcMenuSize, if necessary, before drawing ; 3/5/85 EHB In AddResMenu, preserve state of resLoad ; 1/24/85 EHB In SetItemProperty, donÕt CalcMenuSize if item = check mark ; 1/24/85 EHB Preserved the clip region in FlashMenuBar ; 1/24/85 EHB Tweaked DrawTheMenu to not save the menu bar ; 1/24/85 EHB Reset alarm parity in DrawMenuBar ; 9/7/83 AJH save in DrawMBar ; 8/27/83 AJH saved a little code in CalcMenuSize (use common subroutine) ; 8/27/83 AJH Made it include "SysErr" ; 8/27/83 AJH handled out of memory case in SaveBits by deep-shitting ; 8/23/83 BLH (with LAK) Fixed bug in GetMHandle (didnÕt return result!) ; 8/19/83 AJH Moved loc of menu flash bits. ; 8/13/83 SC The code scrunch-a-matic pass... Made NoIndex fall into GotIndex ; Moved getIndex, invertTitle. Added utility GetNInvert. Made ; saveBits inline. ; 8/9/83 AJH Made it reference "WmgrGray" ; 6/30/83 AJH fixed bug in InsrtResMenu when thereÕs none of that type ; 6/15/83 AJH Added InsrtResMenu ; 6/14/83 AJH made SetItem call CalcMenuSize ; 5/18/83 AJH fixed GetMHandle bug ; 5/11/83 AJH Added CountMItems ; 5/6/83 AJH fixed PlotIcon bug (didnt set up topLeft) ; 4/28/83 AJH moved calcMenuSize into the defProc ; 4/21/83 AJH Made CalcMenuSize add some extra for command line ; 4/17/83 AJH Made MenuKey know about desk ornament menus ; 4/13/83 AJH Tweaked MBarEnable logic in MenuSelect ; 4/4/83 AJH Made it get menuFlash from parameter RAM ; 3/18/83 AJH Made InvertTitle go one pixel higher ; 3/16/83 AJH Made CalcMenuSize not bold disabled items ; 3/15/83 AJH Made Enable/DisableItem not recalc menu size ; 2/13/83 AJH Made PlotIcon use copyBits instead of XferRect ; 2/5/83 AJH Changed "AddRsrcMenu" to "AddResMenu" to keep Caroline happy ; 2/5/83 AJH AddRsrcMenu -> AddResMenu; made it not load the objects ; 1/28/83 AJH Added "FlashMenuBar" ; 1/28/83 AJH Improved CalcMenuSize ; 1/25/83 AJH Fixed outline/shadow reversal bug ; 1/25/83 AJH Fixed MenuSelect mouse-ahead problem ; 1/24/83 AJH Added support for deskOrns stealing the menuBar ; 1/23/83 LAK Adapted for new equate files. ; 1/21/83 AJH Fixed bug in GetSizeLeft in SetItem ; 1/20/83 AJH Fixed purged defProc problem (lock after LoadResource) ; 12/27/82 AJH Moved menuData to end of block; defProc as resource ; 12/19/82 AJH Added "AddRsrcMenu" call ; 12/11/82 AJH Made space between menus less wide (14 pixels) ; 11/22/82 AJH Made TextMenuProc and CalcMenuSize externally accessible ; 11/16/82 AJH Made the menuBar 4 pixels wider ; 11/7/82 AJH Made menuKey case insensitive ; 10/25/82 AJH Made space between menus wider for 512 dots (12 -> 18) ; 10/16/82 AJH Made it independent of screen size (use wmgr^.portRect) ; 10/10/82 AJH Converted to QuickDraw Trap Interface ; 9/20/82 AJH Fixed problem in DeleteMenu ; 9/7/82 AJH Added "DrawMBar" entry point ; 9/7/82 AJH Made DrawMBar a separate routine to save code ; 8/22/82 AJH Got rid of menu manager dependency on icon manager ; 8/2/82 AJH Converted for new memory manager; no more ohÕs! ; 7/24/82 AJH Fixed left corner problem in DrawMenuBar ; 6/29/82 AJH New today. ; ;------------------------------------------------------------------------- ; ; Conditional Definitions and Includes ; ;------------------------------------------------------------------------- string asis LOAD 'StandardEqu.d' include 'InternalMacros.a' ; include 'DialogsPriv.a' ; INCLUDE 'ColorEqu.a' INCLUDE 'MenuMgrPriv.a' INCLUDE 'Packages.a' ; for IUMagString INCLUDE 'ScriptPriv.a' ; <1.7> for Ram vectors to ScriptMgr internal routines INCLUDE 'Balloons.a' ; INCLUDE 'BalloonsPriv.a' ; IMPORT Find6BOFromID MACHINE MC68020 ; needed for cache flush fau GetParamRamData PROC ENTRY ;------------------------------------------------ ; Utility -- GetParamRamData ;------------------------------------------------ ; Get menuDelay and menuDrag tick counts from ; parameter ram and store in mbSaveLoc ; ; Trashes: A0, D0 move.l mbSaveLoc, a0 ; get mbSaveLoc lo-mem move.l (a0), a0 ; dereference move.b #0, mbMenuDelay(a0) ; set default in case no new pram move.b #0, mbMenuDrag(a0) ; ditto btst #5, HwCfgFlags ; is larger pram valid ? beq.s @SetLowMem ; no -> branch, no pram lea mbMenuDelay(a0), a0 ; a0 has address of buffer moveq #1, d0 ; want one byte swap d0 ; put #1 in hi-byte move #menuDelay, d0 ; param ram address in lo-byte _ReadXPRam move.l mbSaveLoc, a0 ; get mbSaveLoc lo-mem move.l (a0), a0 ; dereference lea mbMenuDrag(a0), a0 ; a0 has address of buffer moveq #1, d0 ; want one byte swap d0 ; put #1 in hi-byte move #menuDrag, d0 ; param ram address in lo-byte _ReadXPRam @SetLowMem move.l mbSaveLoc, a0 ; see if need to set defaults move.l (a0), a0 ; dereference tst.b mbMenuDelay(a0) bne.s @1 ; not zero --> donÕt set default addi.b #8, mbMenuDelay(a0) ; default == 8 Ticks (tried and true by FJL) @1 tst.b mbMenuDrag(a0) bne.s @GetParmDone ; not zero --> donÕt set default addi.b #60, mbMenuDrag(a0) ; default == 1 second (no reason not to be huge ; default value because of way dragging works) @GetParmDone rts ENDPROC InitProcMenu PROC EXPORT ; Begin <2.3 EMT> ; ; procedure InitProcMenu ( mbResID : integer); ; ; The resID is stored in the MenuList header as a word at location $4. ; The low 3 bits of mbResID are used as the variant!! The whole mbResID ; is used as the resID. ; ; This routine performs the same function as InitMenus, except it allows ; specification of the MBDF resID rather than assuming MBDF=0. ; ; ; MBarProc routine ; move.l (sp)+,a0 ; get the return address <2.4> move.w (sp)+,d1 ; get the MBDF resource ID <2.4> move.l a0,-(sp) ; put return address back on the stack <2.4> IMPORT IMCommon bra IMCommon ; go join InitMenus <2.4> ; End <2.3 EMT> ENDPROC INITMENUS PROC EXPORT ; ; PROCEDURE InitMenus -- initialize the menu manager by allocating an empty menuList ; MOVEQ #0,D1 ; standard rom based MBDF is #0 ENTRY IMCommon IMCommon ; D0 contains resID now. <2.4> MOVE.W #MapTRUE,ROMMapInsert ; set flag to load from ROM SUBQ #4,SP ; make room for function return MOVE.L #'MBDF',-(SP) ; load the standard menu bar defProc MOVE.W D1,-(SP) ; push the resID _GetResource ; load it move.l (SP)+, MBDFHndl ; save defproc handle in lomem bne.s @gotIt ; if handle not NIL, then continue TST.W D1 ; standard rom based MBDF is #0 BNE.S INITMENUS ; Try the default MOVE.W #dsMBarNFnd,D0 ; if defproc could not be loaded, die _SysError ; @gotIt ; ; InitApplZone clears MenuList global. ; If it is NIL, then init data structures, ; else they are already inited, so return. move.l MenuList,d0 ; test the menu list handle <2.5> ble.s CreateMenuList ; if NIL then menu list needs to be created <2.5> move.l d0,a0 ; get the menu list; it already exists <2.5> move.l (a0),a0 ; dereference the menu list <2.5> move.w d1,mbResID(a0) ; store MBDF ID <2.5> bra.s IMDone ; now, weÕre done <2.5> CreateMenuList bsr.s InitMList ;allocate and initialize a menuList block MOVE.L A0,MENULIST ;make it the current menuList MOVE.L (A0), A0 ; get the menuPtr move.w D1, mbResID(a0) ; store resID clr theMenu ; clear lo mem so no hilited menu move.l a1, MenuCInfo ; store the color table too IMPORT GetMBColors bsr GetMBColors ; get menubar color info from the system MOVEQ #$0C,D0 ;only use 2 bits worth AND.B SPMisc2,D0 ;get pRam flags LSR #2,D0 ;get menuFlash in the low bits MOVE D0,MenuFlash ;set up menuFlash field CLR.W MBarEnable ;initally, application owns MBar CLR.L MBarHook ; init MBarHook CLR.L MENUHOOK ;init user hook ; tell the MBarProc to init any data structures MOVEQ #3,D0 ; set up for the init message MOVE.L #0,D1 ; parameter is 0 for cleared bar only IMPORT CallMBarProc BSR CallMBarProc ; execute the defproc,ignoring the result IMPORT GETPARAMRAMDATA bsr GETPARAMRAMDATA ;read MenuDrag/MenuDelay into mbSaveLoc _ClearMenuBar ;initialize menuBar parameters and clear it _DrawMenuBar IMDone RTS ; this was mistakenly deleted at some point ; InitMList allocÕs a menuList with no menus and no hierarchical menus ENTRY InitMList InitMList moveq #mctEntrySize, d0 ; allocate one record in the color tbl _NewHandle ; move.l (a0), a1 ; dereference move #mctLastIDIndic, mctID(a1) ; store -99 as ID ==> last entry move.l a0, -(SP) ; store it on the stack temporarily moveq #InitMListSize, d0 ; get size of menuList d.s. _NewHandle CLEAR ; alloc it move.l (a0), a1 ; dereference the handle ;set up the menu header move.w #mbMenu1Loc, lastRight(a1) ; set lastRight to ten (decimal) move.l (SP)+, a1 ; get the color tbl handle in a1 rts ENDPROC GetMBColors PROC ENTRY ;----------------------------------------------- ; Utility -- GetMBColors ;----------------------------------------------- ; See if there is a menubar color table entry. It will automatically look for one in ; the applications resfile then in the system res file. ; move.b #1, -(SP) ; force Resource Load to true _SetResLoad subq #4, SP ; make room for the result move.l #'mctb', -(SP) ; push resource type clr.w -(SP) ; push menuID 0 = menu bar _GetResource ; get the resource move.l (SP)+, a0 ; get the handle in a0 move.l a0, d0 ; set z-flag beq.s @1 ; handle is nil, so no color table _HGetState ; get state of resource move.b d0, -(SP) ; store them on the stack move.l a0, -(SP) ; store handle on stack too _HLock ; lock the handle down temporarily move.l (a0), a0 ; get ptr to resource move (a0)+, -(SP) ; push number of table entries move.l a0, -(SP) ; push base address of table _SetMCEntries ; call trap move.l (SP)+, a0 ; get handle move.b (SP)+, d0 ; and previous state _HSetState ; return handle to previous state @1 rts ENDPROC CLEARMENUBAR PROC EXPORT ; ; PROCEDURE ClearMenuBar -- clear the menuBar/menuList data structure ; ;¥HMClearMenuBarPatch roll in from BalloonPatch28.a IMPORT ptchHMGetBalloons JSR ptchHMGetBalloons ; what is the state of What Is? mode? BEQ.S @BalloonsOff ; EQ means no, so, let's not do anything. SUBQ #2,SP ; remove any balloons that might have been up _HMRemoveBalloon ; do the remove TST.W (SP)+ ; toss result @BalloonsOff IMPORT GetA0List BSR GetA0List ; check for purged list MOVE.L MENULIST,A0 ; get handle to menuList _DisposHandle ; dispose of the handle move.l MenuCInfo, a0 ; get handle to color tbl _DisposHandle ; and toss it IMPORT InitMList bsr InitMList ; init a new one move.l a0, menuList ; and store it move.l a1, MenuCInfo ; and store it too IMPORT GetMBColors bsr GetMBColors ; get menubar color info from the system CLR.W THEMENU ; no menu is hilited RTS ENDPROC GetMenuRgn Proc Export ; Utility GetMenuRgn -- returns the region occupied by the MenuBar. ; Move.l (Sp)+,D0 ; Save the return address. Move.l (Sp)+,D1 ; Get the callerÕs RgnHandle. Move.l D0,-(Sp) ; Restore return address. Moveq #12,D0 ; Call MBarProc to return RgnHandle. Import CallMBarProc Bsr CallMBarProc ; Call the DefProc. Rts Endproc CalcMBHeight PROC EXPORT ; ; call MBarProc to calc height MOVEQ #6,D0 ; set up for the height message, no params EXPORT CallMBarProc ; CallMBarProc ;------------------------------------------------------------------------------------------- ; ; Utility -- CallMBarProc ; ; On Entry: d0 lo-word=message number, hi-word=parameter1 ; d1 parameter2 ; Use: a0 ; On Exit: d0 return value ; ; mbResID: comes from menuList ; mbVariant: the low 3 bits of mbResID are the variant ; ; Note that we store the MBDFÕs Hndl in low memory location MBDFHndl but this is for ; convenience only. We do not count on its being there between calls to this utility. ; ;------------------------------------------------------------------------------------------- movem.l d4, -(SP) ; save work register CLR.L -(SP) ; make room for defproc return MOVE.L MenuList,A0 ; get the menuList head MOVE.L (A0),A0 ; handle->pointer move mbResID(a0), -(SP) ; get resource ID <24Jan87> andi.w #0007, (SP) ; use low 3 bits only MOVE.W D0,-(SP) ; push the message number swap d0 ; get parameter1 in lo-word move.w d0, -(SP) ; push parameter1 MOVE.L D1,-(SP) ; push parameter2 ; ; get the mbarproc each time we call it instead of counting on low mem to be correct ; subq #4, SP ; space for return result move.l #'MBDF', -(SP) move mbResID(a0), -(SP) ; get resource ID MOVE.W #MapTRUE,ROMMapInsert ; set flag to load from ROM _GetResource move.l (SP)+, MBDFHndl MOVE.L MBDFHndl,A0 ; get the menu bar defproc handle _HGetState ; get the current state move.l d0, d4 ; save state in d4 _HLock ; lock it MOVE.L (A0),A0 ; get a pointer to it JSR (A0) ; jump to it ; returned from defproc, return handle to previous state before exiting MOVE.L MBDFHndl,A0 ; get the handle move.l d4, d0 ; get previous state from d4 _HSetState ; reset previous state MOVE.L (SP)+,D0 ; get the defproc return movem.l (SP)+, d4 ; restore work register RTS ; and return ENDPROC DELETEMENU PROC EXPORT ; ; PROCEDURE DeleteMenu(menuID: INTEGER) -- delete a given menu from the menuList. ; Note that deleteMenu will not de-allocate the menu, since it may be in other ; menuLists. ; ; Look first in the Hmenu list, then in the regular menu list ; Delete all color table entries for this menuID MOVE.W theMenu, D0 ; Get the currently highlighted menu CMP.W 4(SP), D0 ; Is it this one? BNE.S @NotHilited ; Nope, skip CLR.W -(SP) ; _HiliteMenu ; Unhighlight it @NotHilited ; move 4(SP), -(SP) ; push the menuID move #mctAllItems, -(SP) ; push flag meaning all items _DelMCEntries ; call delete routine moveq #0, d1 ; clear d1 for GetHIndex MOVE.W 4(SP),D1 ; get the menuID IMPORT GetHIndex bsr GetHIndex ; try H Menu bne.s @FoundHMenu ; found a HMenu so delete it IMPORT GetIndex BSR GETINDEX ; get the index into D0 beq.s TwoBytExit ; didnÕt find either, so nada to delete @FoundMenu IMPORT GetA1List BSR GetA1List ; get menuList into A1 CMP.W LASTMENU(A1),D0 ;is this one the last one? BNE.S @OneLessMenu ;if not, go and delete it ; special case deleting the last menu ; make lastRight = old menuLeft MOVE.W MenuLeft(A1,D0),lastRight(A1) ;set new lastRight @OneLessMenu SUBQ #6,LASTMENU(A1) ; one less menu in list bra.s @MungeIt ; and delete it @FoundHMenu IMPORT GetHA1List bsr GetHA1List ; get HMenuList into A1 subq #6, lastHMenu(a1) ; one less menu in list @MungeIt moveq #0, d1 ; clear all of d1 move.w d0, d1 ; move low word of d0 only, hiword has garbage move.l menuList, a0 ; get menuList handle move.l (a0), a0 ; dereference adda.l d1, a0 ; get pointer to 6 bytes to be deleted subq #4, SP ; space for result move.l menuList, -(SP) ; move the menuList handle onto the stack move.l d1, -(SP) ; d1 has offset into menuList or HMenuList move.l a0, -(SP) ; ptr to target string moveq #6, d0 ; len1 = 6 bytes move.l d0, -(SP) moveq #4, d0 move.l d0, -(SP) ; make replacement string non-NIL so deletes properly ; just point at an even byte in low-mem clr.l -(SP) ; and its length is zero ===> delete _Munger ; oooohhh -- aaaahhh -- do it baby addq #4, SP ; ignore dem results MOVEQ #2,D0 ; set up for the menu-edge-calc msg CLR.L D1 ; calc entire bar IMPORT CallMBarProc BSR CallMBarProc ; execute the defproc ; Now delete all of the entries in the color table for this ENTRY TwoBytExit TWOBYTEXIT MOVE.L (SP)+,A0 ;get return address ADDQ #2,SP ;strip parameter JMP (A0) ;return to caller ENDPROC GetHIndex PROC ENTRY ;--------------------------------------------------------------------------------------------- ; ; GetHIndex is similar to GetIndex but it looks thru the hierarchical menu list for a ; menu of the given menuID. The menuID is passed in D1 and the index is returned in ; D0. If the menuID canÕt be found, D0 returns zero. If D1 = $FFFFFFFF then D0 returns ; the index to the HMenu header info. The z-flag can be used to determine if one was ; found. ; move.l d3, -(SP) ; save work register tst.l d1 ; is index 0? beq.s @HNotFound ; if so, return 0 IMPORT GetA1List bsr GetA1List ; get menuList ptr into a1 move lastMenu(a1), d2 ; get # regular menus addq #6, d2 ; now d2 has index to H Menu header info cmpi.l #$FFFFFFFF, d1 ; is index = $FFFFFFFF? beq.s @GotHIndex ; yes, so return index to H Menu info ; no, so look thru H Menus move (a1,d2), d3 ; get # hierarchical menus beq.s @HNotFound ; if none then H Menu not found ; there are H Menus, so search them for the rsrcID in D1 add d2, d3 ; d3 is now index to last H Menu exg d2, d3 ; d2 - index to last H Menu ; d3 - index to H Menu header info @GetHILoop move.l menuHOH(a1,d2), a0 ; get the handle move.l (a0), a0 ; get the pointer cmp menuID(a0), d1 ; is this the right menuID beq.s @GotHIndex ; yes, so return @ChkNxtIndex subq #6, d2 ; bump down to next entry cmp d2, d3 ; are we at the H Menu header info? bne.s @GetHILoop ; no, so continue checking ; yes, drop thru and return 0 meaning not found @HNotFound moveq #0, d2 ; ; take the index in d2 and return it in d0 ; @GotHIndex move.l (SP)+, d3 ; restore work register move d2, d0 ; get index in d0 and set z-flag rts ENDPROC EXPORT GETINDEX GETINDEX PROC ENTRY ;--------------------------------------------------------------------------------------------- ; ; GetIndex is a utility routine that returns an index into the menuList given a ; menuId. The menuId is passed in D1 while the index is returned in D0. If the ; menuId can't be found, D0 will return a zero. A0, A1 and D2 are trashed. ; The Z-flag can be used to determine if one was found. As a special bonus, on ; exit A0 points to the menu, if a menu was found. ; TST D1 ; is index 0? BEQ.S NOINDEX ; if so, return 0 IMPORT GetA1List BSR GetA1List ; get menuList into A1 MOVE LASTMENU(A1),D2 ; get # of menus BEQ.S NOINDEX ; if none, say we can't find it ; ; here is the search loop. Get the next handle, and check the menuID ; GILOOP MOVE.L MENUOH(A1,D2),D0 ; get the handle MOVE.L D0,A0 ; get handle in A-reg MOVE.L (A0),A0 ; handle -> pointer CMP MENUID(A0),D1 ; is this the one? BEQ.S GOTINDEX ; if they match, we're done ; NEXTINDEX SUBQ #6,D2 ; bump to next entry BNE.S GILOOP ; loop if there's more to do ; ; we couldn't find it so return zero in D0 ; NOINDEX MOVEQ #0,D2 ; return 0 ; ; we found it so return index in D0 ; GOTINDEX MOVE D2,D0 ; get index in D0 RTS ENDPROC INSERTMENU PROC EXPORT ; ; PROCEDURE InsertMenu(menu: menuInfoHandle; beforeId: INTEGER); ; ; insert a menu into the menuList. beforeID is the menuID of the menu ; that the new menu should be inserted before. If beforeID canÕt be found, ; the new menu is inserted at the end of the list. If the menu is already ; in the list, donÕt insert it ; ; If beforeID = -1 then insert menu at front of HMenuList ; Used < 0 as the criteria for inserting in HMenus, changed to = -1 ; Roll in PatchInsertMenu in SystemMenuPatch.a ; When this patch sees a system menu (-16385 thru -32768), it adds it to the system menu bar. ; If the system menu bar doen't exist, this patch creates it. ; If the menu is not a system menu, ensure that the beforeID is modified so that the ; menu is inserted before the system menu partition. IMPORT FindFirstSystemMenu6BO InsertStack RECORD {base},DECR ParamBegin: EQU * ; start parameters after this point menuHdl DS.L 1 beforeID DS.W 1 ParamSize: EQU ParamBegin-* retAddr DS.L 1 base DS.W 0 LocalSize: EQU * ENDR WITH InsertStack CMP.W #$FFFF, beforeID(SP) ; beforeID = -1 ==> H Menu beq OldInsertMenu ; If a system menu is being inserted, put it into the System Menu Bar MOVE.L menuHdl(SP), A0 ; Get the MenuHandle MOVE.L (A0), A0 ; dereference SUBQ.L #4,SP ; Make Room for result & VAR MOVE.W menuID(A0),-(SP) ; Push the menuID PEA 4(SP) ; Point to VAR _IsSystemMenu ; Do it the standard way ADDQ.L #2,SP ; Eat the result TST.B (SP)+ ; Is it a system menu? BNE.S @DoSystemMenu ; EQ means it is a system menu ; Menu for main list, be sure it is inserted before all the system menus BSR FindFirstSystemMenu6BO ; Find the system menu partition beq OldInsertMenu ; Do old stuff if no system menus MOVE.W D0, D1 ; Save off 6BO of 1st system menu MOVE.W beforeID(SP), D0 ; Get the beforeID BEQ.S @forceBeforeSys ; branch if zero BSR Find6BOFromID ; Find its offset BEQ.S @forceBeforeSys ; branch if the beforeID not in list CMP.W D1, D0 ; Is it after the system partition? ble OldInsertMenu ; No, do as caller wanted MOVE.W D0, D1 ; It is after the system partition @forceBeforeSys ; the beforeID must be changed to before the 1st system menu MOVE.L MenuList, A0 ; get the menulist MOVE.L (A0), A0 ; deref MOVE.L menuOH(A0,D1.W), A0 ; get the menuhandle to insert before MOVE.L (A0), A0 ; deref MOVE.W menuID(A0), beforeID(SP) ; Make beforeID be 1st system menu bra OldInsertMenu ; Now go do it @DoSystemMenu ; If menuID already exists in system menulist, we're done! MOVE.L MenuList, A1 ; Save Menulist MOVE.L SystemMenuList, MenuList ; Store system as menulist JSR Find6BOFromID ; Is this menuID already in the list? MOVE.L A1, MenuList ; Restore Menulist TST.W D0 ; Was the menuID found? BNE.S @Done ; Don't double insert it, done. ; Swap the two menu lists so this menu inserts into the system menu MOVE.W beforeID(SP), D0 ; Get the beforeID BEQ.S @AddAtEnd ; Yes, branch MOVE.L MenuList, A1 ; Save Menulist MOVE.L SystemMenuList, MenuList ; Store system as menulist JSR Find6BOFromID ; Look up the beforeID MOVE.L A1, MenuList ; Restore Menulist TST.W D0 ; Was the menuID found? BNE.S @DoTheAdd @AddAtEnd MOVE.L SystemMenuList, A0 ; Get system menulist MOVE.L (A0), A0 ; deref MOVE.W lastMenu(A0), D0 ; Get last menu ADDQ.W #6, D0 ; Insert "before" the end @DoTheAdd SUBQ.L #4, SP ; Make room for result MOVE.L SystemMenuList, -(SP) ; handle MOVE.W D0, -(SP) ; Move the offset CLR.W -(SP) ; as a long with high cleared CLR.L -(SP) ; ptr1 = 0 CLR.L -(SP) ; len1 = 0 PEA 6+20(SP) ; ptr2 = menuhandle parameter MOVEQ.L #6, D0 MOVE.L D0, -(SP) ; len2 = 6 _Munger ; Munge away! Left coord will be junk. ADDQ.L #4, SP ; Dump result ; Remember to update the lastMenu field MOVE.L SystemMenuList, A0 ; Get system menulist MOVE.L (A0), A0 ; handle -> ptr ADDQ.W #6, lastMenu(A0) ; Bump the count @Done MOVE.L (SP)+, A0 ; Get the return address ADDQ.L #ParamSize, SP ; Cut back the parameters JMP (A0) OldInsertMenu movem.l d3/a3-a4,-(SP) ; save working registers cmp.w #$FFFF, 16(SP) ; beforeID = -1 ==> H Menu beq.s @InsertHMenu ; yes, so branch IMPORT GetA0List BSR GetA0List ; get menuList into A0 MOVE.L A0,A3 ; get pointer into A3 move.l 18(SP),a0 ; get menuInfoHandle move.l (a0),a0 ; get ptr to menu block MOVE menuID(a0), d1 ; get menuId of menu to be installed IMPORT GetIndex BSR GETINDEX ; is it already in the list? BNE @DONEINSERT ; donÕt insert same one twice move.w 16(SP),d1 ; get beforeID BSR GETINDEX ; get index into menuList of beforeID menu bne.s @AllocEntry ; if we found one, branch and insert it ; the "beforeID" menu was not in the list, so insert this one at the end of the list MOVE LASTMENU(A3),D0 ; get # of menus in menuList. addq #6, d0 ; and insert this one AFTER it BRA.S @AllocEntry ; go insert it ; ; insert a H Menu at the front of the HMenuList if id not already in the HMenuList @InsertHMenu IMPORT GetHA0List bsr GetHA0List ; get ptr to HMenuList in A0 move.l a0, a3 ; and save it in a3 move.l 18(SP), a0 ; get menuInfoHandle move.l (a0),a0 ; get ptr to menu block moveq #0, d1 ; clear d1 (for GetHIndex call) move menuID(a0), d1 ; get menuId of menu to be installed IMPORT GetHIndex bsr GetHIndex ; is it already in the list? bne.s @DoneInsert ; donÕt insert same one twice addq #6, lastHMenu(a3) ; bump total of HMenus move.l MinusOne, d1 ; set up for GetHIndex call bsr GetHIndex ; get index to HMenuList header info in d0 addq #6, d0 ; point to first entry in HMenuList ; ; Now, use _Munger to insert space into the new, wild and wooly, dynamic menuList. ; ; allocate 6 bytes and store the menuInfoHandle in it @AllocEntry moveq #0, d3 ; clear d3 move.w d0, d3 ; store menuList offset in d3 clr.l TempRect ; use TempRect for temp data clr.l TempRect+4 ; clear temp data loc first lea TempRect, a0 move.l 18(SP), menuOH(a0) ; init regular menu, store the menuInfoHandle cmp.w #$FFFF, 16(SP) ; beforeID = -1 ==> H Menu ;// tst.w 16(SP) ; is this a H Menu? beq.s @InitHEntry ; yes, so init header info differently IMPORT GetA1List bsr GetA1List ; get menuList ptr in A1, A3 could be bad! addq #6, lastMenu(A1) ; bump total number of menus ;// bra.s @MungeIt ; and continue @InitHEntry ;////move.l 18(SP), menuHoH(a0) ; store menuInfoHandle ; ; now Munge those 6 bytes into the menuList ; @MungeIt subq #4, SP ; space for result move.l menuList, -(SP) ; move the menuList handle onto the stack move.l d3, -(SP) ; d3 has offset into menuList clr.l -(SP) ; no target string clr.l -(SP) ; len1 = 0 ===> want an insert move.l a0, -(SP) ; push replacement string move.l #6, -(SP) ; and itÕs length _Munger ; oooohhh -- aaaahhh -- do it baby addq #4, SP ; ignore dem results cmp.w #$FFFF, 16(SP) ; beforeID = -1 ==> H Menu ;// tst.w 16(SP) ; is this a H Menu? beq.s @DoneInsert ; yes, so no need for menu-edge recalc MOVEQ #2,D0 ; set up for the menu-edge-calc msg CLR.L D1 ; calc entire bar IMPORT CallMBarProc BSR CallMBarProc ; execute the defproc @DONEINSERT movem.l (SP)+,d3/a3-a4 ; restore registers ENTRY SixBytExit SIXBYTEXIT MOVE.L (SP)+,A0 ; get return address ADDQ #6,SP ; strip parameters JMP (A0) ; return to caller ENDPROC DrawMBar PROC EXPORT ; Utility DrawMBar -- clear the menuBar and draw the line underneath it, leaving ; the wmgrPort clipRgn clipped to it. This is a separate routine so InitWindows ; can call it to save code. MOVEQ #0,D0 ; set up for the draw message MOVE.L #-1,D1 ; parameter is -1 for cleared bar only IMPORT CallMBarProc BSR CallMBarProc ; execute the defproc RTS ENDPROC DRAWMENUBAR PROC EXPORT ; ; PROCEDURE DrawMenuBar -- draw the current menuList on the menuBar ; ; Call HiliteMenu around DrawMenuBar so that donÕt have dangling bits behind all around ; Clear the low memory bits whenever we draw the menu bar. ; CSS ;Roll in SynchKeyboardMenuState Ñ Make sure the keyboard menu state corresponds to the ; applicationÕs desired setting (enable/disable) in the ; application-specific global flag, scriptDisableKybds ; from MenuMgrPatch.a, this patch says that it shouldn't be rolled in because the ; it should be in the process manager. Well, for 7.1 it is not in the process manager, ; so I am rolling it in anyways. moveq #smKeySynchKbdMenuState,d0 ; Set up the KeyScript verb move.w d0,-(sp) ; to just synchronize the keyboard menu _KeyScript ; Do it. ;end Roll in SyncKeyboardMenuState ;Roll in ValidateMenuBarWhenDrawing bclr #MenuBarInvalidBit,MenuBarInvalidByte ; clear the local invalid bit bclr #MenuBarGlobalInvalidBit,MenuBarGlobalInvalidByte ; clear the global invalid bit <6> ;Roll in PatchMDDrawMenuBar from ModialDiaglogMenuPatches.a import PushMenuState,PopMenuState ; jsr PushMenuState ; Potentially save off the menu state Move.W TheMenu, -(SP) ; save off currently hilited menu Clr.W -(SP) ; call HiliteMenu(0) _HiliteMenu BSET #7,AlarmState ; reset alarm parity MOVEQ #0,D0 ; set up for the draw message MOVE.L #0,D1 ; parameter is non-neg to draw bar text IMPORT CallMBarProc BSR CallMBarProc ; execute the defproc _HiliteMenu ; TheMenu is already on the stack. jsr PopMenuState ; Restore the menu state if it was saved RTS ENDPROC FlashMenuBar PROC EXPORT ;------------------------------------------------------------------------------------ ; ; FlashMenuBar ; ;------------------------------------------------------------------------------------ ; ; PROCEDURE FlashMenuBar(menuID: INTEGER); ; ; FlashMenuBar inverts the title of a given menu item. If the menuID is 0, ; it inverts the whole menu bar. ; ; No longer is it possible to have more than one menu hilited at once due to saving ; the bits behind the menu title. This routine has been changed so that when ; menuID <> 0 if TheMenu=MenuID then it clears that menu, else it just uses the HilitMenu code. ; tst 4(SP) ; test menuID beq.s @FlashWholeBar ; menuID == 0 ==> flip bar move theMenu, d0 ; get currently hilited menu beq.s @DoHiliteMenu ; if no menu hilited, then use HiliteMenu code cmp 4(SP), d0 ; flashing currently hilited menu ? bne.s @DoHiliteMenu ; no ==> so use HiliteMenu code ; yes ==> so turn this title off move 4(SP), d1 ; get menuID of new selection IMPORT GetIndex bsr GetIndex ; convert ID to offset in menuList beq.s @FlashExit ; couldnÕt find in list, so exit IMPORT TurnIndexOff bsr TurnIndexOff ; MenuList offset is in D0 clr theMenu ; clear low-mem theMenu to show no menu hilited IMPORT TwoBytExit bra TwoBytExit @DoHiliteMenu IMPORT HiliteMenu bra HiliteMenu ; menuID <> 0 ==> use HiliteMenu code @FlashWholeBar ; call mbarproc to invert menu. MOVEQ #0,D0 ; menuIndex = 0 ==> flip bar IMPORT TurnIndexOn BSR TurnIndexOn ; call mbarproc @FlashExit BRA TwoBytExit ; save code by returning thru common label ENDPROC TurnIndexOff PROC ENTRY ;-------------------------------------------------------------------------------------------- ; TurnIndexOff and TurnIndexOn take a menuIndex in D0 and set itÕs hilite state ; to the appropriate level. These calls replace InvertTitle. ; ; On Entry: D0 Offset into MenuList of menu to be hilited/unhilited ; MOVEQ #0,D1 ; set hi word to 0 for normal text BRA TurnIndexCom ; ENTRY TurnIndexOn TurnIndexOn MOVEQ #1,D1 ; set hi word to one for selected text TurnIndexCom SWAP D1 ; MOVE.W D0,D1 ; set lo word to new selection MOVEQ #5,D0 ; set up the hilite message ; fall thru to execute the defproc ; returns to caller directly IMPORT CallMBarProc BRA CallMBarProc ENDPROC HILITEMENU PROC EXPORT ; ; PROCEDURE HiliteMenu(menuID: INTEGER); -- hilite the title of the menu with the ; specified menuID. Since only one menu can be hilited at a time, unhilite any other one ; ; if MBarHeight <= 3 then donÕt hilite. Otherwise MBarProc will save off a VERY LARGE ; handle for the bits behind the menu title. ; HiliteMenu draw menu bar if invalid ; ROLL IN ValidateMenuBarWhenDrawing IMPORT ValidateMenuBar jsr ValidateMenuBar ; Roll in PatchMDHiliteMenu ; The saves menus state, calls old HiliteMenu, then restores state import PushMenuState,PopMenuState ; parametersStackFrame menuID ds.w 1 ; the menuID endStackFrame linkSave jsr PushMenuState ; Potentially save off the menu state move.w menuID(a6),-(sp) ; Push the parameter Cmpi.W #3, MBarHeight ; is height > 3 Bgt.S @HeightOK ; yes -> ok Bra.S HLNone ; no -> nope, skip entirely ; first, turn off the current hilited title if present @HeightOK MOVE.W theMenu,D1 ; get the currently hilited menu BEQ.S HLOn ; if theMenu is 0, then donÕt unhilite CMP.W (SP),D1 ; is this the currently hilited menu BEQ.S HLDone ; already hilited, so skip IMPORT GetIndex BSR GetIndex ; convert to menuIndex beq.s HLOn ; if zero, invalid menuID MOVEQ #0,D1 ; clear hi half for normal text MOVE.W D0,D1 ; move to D1 MOVEQ #5,D0 ; set up the hilite message IMPORT CallMBarProc BSR CallMBarProc ; execute the defproc ; now, turn on the selected menu HLOn MOVE.W (SP),D1 ; get menuID of new selection BSR GetIndex ; convert to menuIndex BEQ.S HLNone ; if zero, invalid menuID SWAP D0 ; save menuIndex in hi half MOVE.W #1,D0 ; set hi word to one for selected text SWAP D0 ; flip half back to correct positions MOVE.L D0,D1 ; copy to D1 for CallMBarProc MOVEQ #5,D0 ; set up the hilite message BSR CallMBarProc ; execute the defproc HLDone MOVE.W (SP)+,theMenu ; update theMenu bra Done ; donÕt store the menuID if we couldnÕt find the index. No index means the ; menuID doesnÕt exist on the menu bar, and storing a non-existent menuID ; in theMenu global causes the next HiliteMenu(0) to flip the bar (ugh-ly). HLNone ; get the return address addq.l #2, SP ; throw away the parameter clr.w theMenu ; update theMenu Done jsr PopMenuState ; Restore the menu state if it was saved restoreUnlinkReturn ENDPROC ENABLEITEM PROC EXPORT ; PROCEDURE EnableItem(menuHandle,item) -- enable an item in a menu or, if the item ; number is zero, enable the entire menu. It has no effect if the item is already ; enabled. ; IMPORT EnableFetch BSR ENABLEFETCH ;set up registers with shared code cmp #31, d0 ; is the item > 31 ? bhi.s EnableDone ; yes, so leave without updating flags BSET D0,D1 ;enable the item ENTRY EnableCom ENABLECOM MOVE.L D1,MENUENABLE(A0) ; update the menuÕs flags ENTRY EnableDone EnableDone IMPORT SixBytExit BRA SIXBYTEXIT ; common exit saves code ENDPROC ENABLEFETCH PROC ENTRY MOVE.L 10(SP),A0 ; get the menu handle MOVE.L (A0),A0 ; handle to pointer MOVE 8(SP),D0 ; get bit index MOVE.L MENUENABLE(A0),D1 ; pick up current state of flags RTS ENDPROC DISABLEITEM PROC EXPORT ; ; PROCEDURE DisableItem(menuHandle, item) -- disable an item in a menu, or if the item ; is zero, disable the entire menu. Shares code with EnableItem to stay small ; IMPORT EnableFetch BSR ENABLEFETCH ;set up registers cmp #31, d0 ; is the item > 31 ? bls.s @ok IMPORT EnableDone jmp EnableDone ; yes, so leave without updating flags @ok BCLR D0,D1 ;disable the item IMPORT EnableCom BRA ENABLECOM ;go update flags and return ENDPROC GETMENUPTR PROC ENTRY ;------------------------------------------------------------------------------------------- ; GetMenuPtr is a utility routine that given an index into the current menuList in D5, ; returns a pointer to the menu in A0. It returns a handle to the same menu in A1. ; BSR.S GetA0List ; get menuList pointer into A0 MOVE.L MENUOH(A0,D5),A1 ; get menu handle GMPContinue TST.L (A1) ; has menu been purged? BEQ.S ListPurged ; => yes, go to purgeatory MOVE.L (A1),A0 ; handle -> pointer RTS ENTRY GetA0List GetA0List ;------------------------------------------------------------------------------------------- ; GetA0List is a routine to get the menuList pointer into A0. GetA1List is a routine to ; get the menuList pointer into A1. The reason for two routines is due to the complexity ; and risk of getting the dozen routines that get menuList pointer to agree with each other. ; These routines check to see if the menuList has been purged. If it has it generates ; a DS #54 (MenuPrgErr). MOVE.L MenuList,A0 ; get the menuList handle TST.L (A0) ; has it been purged? BEQ.S ListPurged ; => yes, go to purgeatory MOVE.L (A0),A0 ; else get the pointer RTS ; and return ENTRY GetA1List GetA1List MOVE.L MenuList,A1 ; get the menuList handle TST.L (A1) ; has it been purged? BEQ.S ListPurged ; => yes, go to purgeatory MOVE.L (A1),A1 ; else get the pointer RTS ; and go to heaven ListPurged MOVEQ #MenuPrgErr,D0 ; get our error code _SysError ; and roast in eternal damnation ENTRY GetHA0List GetHA0List ;------------------------------------------------------------------------------------------- ; GetHA0List is a routine to get the HMenuList pointer into A0. GetHA1List is a routine to ; get the HMenuList pointer into A1. The reason for two routines is due to the complexity ; and risk of getting the dozen routines that get HMenuList pointer to agree with each other. ; These routines check to see if the menuList has been purged. If it has it generates ; a DS #54 (MenuPrgErr). ; bsr.s GetA0List ; get the menuList ptr in a0 adda.w lastMenu(a0), a0 ; a0 now points at last regular menu addq #6, a0 ; a0 now points at HMenuList header info rts ENTRY GetHA1List GetHA1List bsr.s GetA1List ; get the menuList ptr in a1 adda.w lastMenu(a1), a1 ; a1 now points at last regular menu addq #6, a1 ; a1 now points at HMenuList header info rts ENDPROC ;----------------------------------------------- ; Stack Frame Definitions for MenuSelect and PopUpMenuSelect ;----------------------------------------------- STARTPT EQU 8 ; 1st parameter is 8, and is 4 bytes long FUNCRESULT EQU 12 ; longword function result (menu,item) ITEMRESULT EQU 14 ; item portion of funcResult MENURECT EQU -8 ; rectangle (8 bytes) MSavePort EQU MENURECT-4 ; saved grafPort msLastMenu EQU MSavePort-2 ; how many menus are on the screen DelayTicks EQU msLastMenu - 4 ; how long mouse in HItem DragTicks EQU DelayTicks - 4 ; how long mouse moving towards HMenu menuDelaySave EQU DragTicks - 1 ; store menuDelay from param ram menuDragSave EQU menuDelaySave - 1 ; store menuDrag from param ram lastFuncResult EQU menuDragSave - 2 ; funcResult last time thru MSLoop lastItemResult EQU lastFuncResult - 2 ; itemResult last time thru MSLoop firstMenuID EQU lastItemResult - 2 ; ID of REGULAR menu up NewHMenuOffset EQU firstMenuID - 2 ; offset into MenuList of new HMenu SelectFrame EQU NewHMenuOffset ; number of bytes to save msHMenuStorage EQU 4 ; 4 bytes per menu needed for temp storage MENUSELECT PROC EXPORT ;------------------------------------------------------------------------------------------------ ; ; MenuSelect -- main loop that tracks mouse in title bar and thru hierarchical menus ; ;------------------------------------------------------------------------------------------------ ; ; FUNCTION MenuSelect(mousePt:Point): LongInt -- MenuSelect is the most important ; routine in the menu manager. It is called when the application receives a ; mouse button down event on the menuBar and retains control until the mouse button ; goes up. It returns a long integer contain 2 16 bit values. The high word ; is called "whichMenu" and holds the menuId of the menu that was chosen; if its ; zero, no menu was chosen. The low word is called "whichItem" and contains the item ; number of the selected item. If no choice was selected, the longWord result is zero ; MenuSelect draw menu bar if invalid ; ROLL IN DrawMenuBarIfInvalidOnMenuSelect IMPORT ValidateMenuBar IMPORT ptchHMUpdateHelpMenu IMPORT ptchHMShowHelpAboutDialog IMPORT ptchHMToggleWhatIs jsr ValidateMenuBar ;Roll in PatchMDMenuSelect ;The saves menus state, calls old MenuSelect, then restores state import PushMenuState,PopMenuState ; resultsStackFrame result ds.l 1 ; the MenuSelect result parametersStackFrame startPt ds.l 1 ; the start point endStackFrame linkSave A2 ; To preserve A2! MOVE.L MenuList,D0 ; check if menu list is nil. rb, start BEQ.S @CallOldCode ; if NIL just call the old trap JSR ptchHMUpdateHelpMenu ; update the menu checked status MOVE.L ExpandMem,A2 ; <33> point to the expand mem ptr MOVE.L ExpandMemRec.emHelpGlobals(A2),A2 ; <33> A2 = global ptr CLR.W hmgSystemMenuID(A2) ; <33> clear the last system menu ID CLR.W hmgSystemMenuItem(A2) ; <33> clear the last system menu item ST hmgInMenuSelectFlag(A2) ; <33> say that we're in MenuSelect @CallOldCode ; rb, end jsr PushMenuState ; Potentially save off the menu state subq #4,sp ; Make room for result move.l startPt(a6),-(sp) ; Push the parameter jsr OrigninalMenuSelect ; move.l (sp)+,result(a6) ; Store the result jsr PopMenuState ; Restore the menu state if it was saved MOVE.L result(a6),D0 ; get the result of the _MenuSelect call rb, start MOVE.L ExpandMem,A2 ; <33> point to the expand mem ptr MOVE.L ExpandMemRec.emHelpGlobals(A2),A2 ; <33> A2 = global ptr SWAP D0 ; put menu ID in low word for test TST.W D0 ; was the menu ID non-zero? BNE.S @NormalMenuSelect ; yes, so just return result of _MenuSelect MOVE.W hmgSystemMenuID(A2),D1 ; return the last system menu ID BEQ.S @NormalMenuSelect ; if zero then the menu wasn't the help menu SWAP D1 ; put menu ID in hiword MOVE.W hmgSystemMenuItem(A2),D1 ; return the last help menu item @HandleHelpMenu CMP #kHMAboutHelpItem,D1 ; was it the about item BNE.S @TryShowBalloonsItem ; no, check for Show/Hide Balloons item JSR ptchHMShowHelpAboutDialog ; show the about dialog BRA.S @HelpMenuHandled ; exit w/ zeroed menu result long @TryShowBalloonsItem CMP.W #kHMShowBalloonsItem,D1 ; was the selection Show/Hide Balloons?? BNE.S @DoneHelpMenu ; no, it was some other item JSR ptchHMToggleWhatIs ; toggles state of "Show Balloons" global, BRA.S @HelpMenuHandled ; exit w/ zeroed menu result long @DoneHelpMenu MOVE.L D1,D0 ; put the setup menu result in D0 for result(A6) BRA.S @CorrectedResult ; exit @HelpMenuHandled MOVEQ #0,D0 ; say that hi and lo words are zero @NormalMenuSelect SWAP D0 ; put item number back in lo word @CorrectedResult MOVE.L D0,result(a6) ; stuff the non-corrected result CLR.W hmgInMenuSelectFlag(A2) ; <33> say that we're out of MenuSelect restoreUnlinkReturn OrigninalMenuSelect LINK A6,#SelectFrame ;set up a stack frame MOVEM.L D2-D7/A2-a4,-(SP) ;save work registers CLR.W -(SP) ;push zero for this _HiliteMenu ;make sure no menu is hilited CLR.L FUNCRESULT(A6) ;assume nothing will be selected clr.l MenuDisable ; clear the low-memory location MenuDisable ; <1.9 KSM> Removed this check to allow double-click processing to work properly ; Double-click is one possibility for tearing off menus. (Kevin, I think that this ; WaitMouseUp should still be here. You should find another way to keep the guy here ; in MenuSelect for the double-click case.) CLR.W -(SP) ;push zero for this _WaitMouseUp ;is the mouse still down? TST.B (SP)+ ;examine result BEQ DONEMSELECT ;if not still down, donÕt bother ; need to set the port here else ClipRects do not work PEA MSavePort(A6) _GetPort move.l wMgrCPort, a2 ; get color port move.l a2, -(SP) ; set the port _SetPort ; ; during the main loop of menuSelect, D3 holds the mouse point, D4 holds the old ; menuIndex into the menuList and D5 holds the current menuIndex. A4 holds handle to ; HMenu ID storage (of menus currently up). ; ; First initialize these variables ; CLR D5 ; current menuIndex is empty CLR D4 ; oldMenuIndex is empty clr msLastMenu(a6) ; clear msLastMenu index clr.l lastItemResult(a6) ; clear both lastFuncResult and lastItemResult clr firstMenuID(a6) ; no menu selected at start move.l mbSaveLoc, a0 ; store MenuDrag and MenuDelay in stackframe move.l (a0), a0 move.b mbMenuDelay(a0), menuDelaySave(a6) move.b mbMenuDrag(a0), menuDragSave(a6) IMPORT SetTickCounters ; call SetTickCounters after ; menuDelaySave and menuDragSave are set up bsr SetTickCounters ; set DelayTicks and DragTicks MOVE.L STARTPT(A6),D3 ; start off with initial mouse point move.l #5*msHMenuStorage, d0 ; alloc space for 5 menuIndices [words] ; and 5 items [words] _NewHandle move.l a0, a4 ; store it in a4 for the duration of MenuSelect ; NOTE: a4 is used as an implicit parameter ; to MenuSelect subroutines ;------------------------------------------------ ; Menu Select Loop ;------------------------------------------------ ; Call the mBar defProcÕs hit routine to see where the mouse is. ; Major revisions for hierarchical menus. MSLoop MOVEQ #1,D0 ; hit message is #1 MOVE.L D3,D1 ; send point in parameter IMPORT CallMBarProc BSR CallMBarProc ; execute the defproc TST.L D0 ; where is the hit? BMI.s SameMenu ; branch if its not in a title or any menu beq.s InTitleNoMenu ; branch if its IN the menubar but NOT IN a title MOVE.w D0,D5 ; move result to D5 BSR GetMenuPtr ; get the menuData handle move menuID(a0),funcResult(a6) ;return which Menu the mouse is currently in bra.s ChgMenu ; ; if in menu bar but not in a title, want to bring down all menus ; no menus and no funcResult ; InTitleNoMenu clr d5 ; no menu clr funcResult(a6) ; no menu, so no result either ; At this point, D5 contains the menuIndex of the menu that the mouse points at, ; or a zero if no menu is pointed at. Check to see if this menu is different than ; the previous one pointed at ChgMenu cmp d5, d4 ; menuIndex = oldMenuIndex ? beq.s SameMenu ; if the same, nothing to pull down IMPORT MenuChanged bsr MenuChanged ; change variables that affect current menu bmi DoneMS ; n-flag set means that MBarHook aborted MenuSelect SameMenu tst d5 ; examine menu index beq.s NextMouse ; donÕt choose an item unless thereÕs one down IMPORT ResetRectScrollData bsr ResetRectScrollData ; before choosing item be sure menuRect(a6) is ; correct as are scrolling globals IMPORT ChooseItem bsr ChooseItem ; choose item by calling mdefproc IMPORT CheckHItem bsr CheckHItem ; check for hierarchical stuff ; I put GetMouse after WaitMouseUp. This ensures that FlashTheMenu is called with the ; same mouse position that was processed above. NextMouse ; I Put GetMouse after WaitMouseUp MUpEntryPt CLR.W -(SP) ;make room for stillDown result _WaitMouseUp ;is the button still down? TST.B (SP)+ ;test _WaitMouseUp result BEQ.S @MouseUp ; => if up, flash user (oh Mr. Mac!) ; mouse still down, so get the mouse position and store in D3 SUBQ #4,SP ;allocate place to get mouse MOVE.L SP,-(SP) ;use temp buffer for mouse point _GetMouse ;get mouse in wmgr coordinates MOVE.L (SP)+,D3 ;keep mouse point in D3 ; The mouse button is still down. WeÕve read the mouse position already, ; so call the user hook (if its installed) and loop. MOVE.L MENUHOOK,D0 BEQ.S @NoMenuHook MOVE.L D0,A0 JSR (A0) @NoMenuHook BRA.s MSLOOP ; => continue tracking mouse ;------------------------------------------------ ; End of Menu Select Loop ;------------------------------------------------ @MouseUp ; the mouse button went up. Give feedback to the user if she made a choice TST D5 ;was one selected? BEQ.S NOFLASH ;if not, dont bother ; ; If the item has a hierarchical menu attached DO NOT return the menu or item ; bsr GetMenuPtr ; get ptr to chosen menu in a0 (which we want for ; GetItemRecord call) move itemResult(a6), d0 IMPORT GetItemRecord bsr GetItemRecord ; on return a1 points to items property bytes beq.s @FlashIt ; if z-flag set then item not found cmpi.b #HMenuCmd, itemCmd(a1) ; does this item have a hierarchical menu? bne.s @FlashIt ; no, so branch and flash clr itemResult(a6) ; yes, so clear the item bra.s @JustRestore ; and skip the flashing @FlashIt IMPORT FlashFeedback BSR FLASHFEEDBACK ;flash the choice for feedback @JustRestore IMPORT RestoreAllBits BSR RestoreAllBits ;restore bits under all menus ; if no item selected, then no menu either ; NOFLASH TST ITEMRESULT(A6) ; was an item selected? BNE.S @SetTheMenu ; if so, weÕre cool CLR.W FUNCRESULT(A6) ; otherwise, no menu was either MOVE firstMenuID(a6),D0 ; better make sure no menu hilited in menu bar BEQ.S @SetTheMenu ; if itÕs zero, then we can skip unhiliting it move d5, d0 ; set up for TurnIndexOff ;*** WRONG WRONG WRONG; the only reason this works is that the MBDF ignores the index ;*** this value is always wrong once a hierarchical menu has been tracked IMPORT TurnIndexOff BSR TurnIndexOff ; otherwise turn it off clr firstMenuID(a6) ; and remember that no menu hilited in title bar @SetTheMenu MOVE firstMenuID(a6),TheMenu ;remember menuID of hilited menu ;+++ tst funcResult(a6) ; is it a system menu? ; CanÕt just use funcResult(a6) since could ; be a HMenu associated with the desk acc tst TheMenu ; Is it a system menu? BMI.s DoSysMenu ; if < 0 then handle it TST.W MBarEnable ;does deskOrn own the menuBar? BMI.s DoSysMenu ;if so, go tell it about it ENTRY DoneMS DONEMS move.l a4, a0 ; set up for DisposHandle _DisposHandle ; and toss temp storage MOVE.L MSavePort(A6),-(SP) ;get old port _SetPort ;restore callers grafPort ENTRY DoneMSelect DONEMSELECT MOVEM.L (SP)+,D2-D7/A2-a4 ;restore registers UNLK A6 ;dismantle stack frame MOVE.L (SP)+,(SP) ;strip sole parameter clr.l d1 ; clear D1 because some stupid app ; assumes it is zero ; the next 3 lines are a little kludge. Infrequently lastMBSave is non-zero when exiting ; MenuSelect, though it should always be zero. Just to be safe force it to be zero. move.l mbSaveLoc, a0 ; get mbSaveLoc move.l (a0), a0 ; dereference clr lastMBSave(a0) ; force no menus down RTS ;return to caller ;----------------------------------------------- ; Utility -- DoSysMenu ;----------------------------------------------- ; ; handle system menus ; ; HMenus cause problems here. Since the menu ID (funcResult) is not = to the DAÕs ; menu ID, SystemMenu will never find the DA in the DA list. To force it to pass ; the HMenu ID we can set MBarEnable temporarily. ; ; Need to allow a DA that owns the menu bar to reset MBarEnable in the middle of _SystemMenu ; Had to move around some parts of this routine. Only set/clear MBarEnable when MBar not ; already owned by DA. ; DoSysMenu tst.w MBarEnable ; who owns menu bar? bmi.s @1 ; desk acc ==> weÕre cool move TheMenu, MBarEnable ; set MBarEnable with DAÕs ID move.l FuncResult(a6),-(SP) ; push the result _SystemMenu ; invoke desk manager clr.l FuncResult(a6) ; pretend we didnÕt get anything ; NOTE: clears funcResult AND itemResult !!! clr.w MBarEnable ; clear MBarEnable bra.s @Done @1 move.l FuncResult(a6),-(SP) ; push the result _SystemMenu ; invoke desk manager clr.l FuncResult(a6) ; pretend we didnÕt get anything ; NOTE: clears funcResult AND itemResult !!! @Done BRA.S DoneMS ;let common code finish up ;------------------------------------------------------------------------------------------------ ; End of MenuSelect ;------------------------------------------------------------------------------------------------ ENDPROC ; PopUpMenuSelect Equates: PopUpMenuH EQU StartPt ; menu handle parameter, same offset as StartPt ; after the stack is fixed PopUpItem EQU SelectFrame - 2 ; PopUpItem parameter msTopEdge EQU PopUpItem - 2 ; Top parameter msLeftEdge EQU msTopEdge - 2 ; Left parameter msTopLeft EQU msLeftEdge ; Top left point of menu PopUpSelectFrame EQU msLeftEdge PopUpMenuSelect PROC EXPORT ;; ;------------------------------------------------------------------------------------------------ ; ; PopUpMenuSelect -- brings up a menu in a user-specified location, then ; tracks mouse in the menu and thru any hierarchical menus ; ;------------------------------------------------------------------------------------------------ ; ; FUNCTION PopUpMenuSelect(theMenu: menuHandle; top, left, PopUpItem: integer): LongInt ; ; PopUpMenuSelect is called when an application receives a mouse down in a pop-up menu area. ; A pop-up menu area is typically a box with a shadow. It first brings up the menu with ; the left edge given by the parameter Left, and the top of PopUpItem at Top. It tracks the ; mouse just like MenuSelect, allowing five levels of hierarchical menus. It ignores ; mouse movement into the menubar by changing the low-memory location MBHeight to zero before ; it starts (it does so so that it can call the mbarproc with a HitMessage, and have the ; mbarproc ignore the menubar area). It returns a LongInt that has the same meaning as ; MenuSelect. ; Begin by removing parameters so that we are left with the same parameter setup as MenuSelect. ; This allows us to use all of the subroutines from MenuSelect. move 4(SP), d0 ; save PopUpItem move.l 6(SP), d1 ; save left, top move.l (SP), 6(SP) ; move RTS, leave 4 bytes of parameter on the stack addq #6, SP ; and update stack ptr link a6,#PopUpSelectFrame ; set up a stack frame movem.l d2-d7/a2-a4,-(SP) ; save work registers move d0, PopUpItem(a6) ; store parameters in stackframe move.l d1, msTopLeft(a6) ; store Left and Top in one instruction clr.l funcResult(A6) ; assume nothing will be selected clr.l MenuDisable ; clear the low-memory location MenuDisable subq #2, SP ; leave room for result _WaitMouseUp ; is the mouse still down? tst.b (SP)+ ; examine result beq @EndPopUpMS ; if not StillDown, donÕt bother ; need to set the port here else ClipRects do not work PEA MSavePort(A6) _GetPort move.l wMgrCPort, a2 ; get color port move.l a2, -(SP) ; set the port _SetPort ; ; during the main loop of PopUpMenuSelect, D3 holds the mouse point, D4 holds the old ; menuIndex into the menuList and D5 holds the current menuIndex. A4 holds handle to ; HMenu ID storage (of menus currently up). ; ; First initialize these variables ; clr d5 ; current menuIndex is empty clr d4 ; oldMenuIndex is empty clr msLastMenu(a6) ; clear msLastMenu index IMPORT SetTickCounters bsr SetTickCounters ; set DelayTicks and DragTicks clr.l lastItemResult(a6) ; clear both lastFuncResult and lastItemResult move.l mbSaveLoc, a0 ; store MenuDrag and MenuDelay in stackframe move.l (a0), a0 move.b mbMenuDelay(a0), menuDelaySave(a6) move.b mbMenuDrag(a0), menuDragSave(a6) move.l #5*msHMenuStorage, d0 ; alloc space for 5 menuIndices [words] ; and 5 items [words] _NewHandle move.l a0, a4 ; store it in a4 for the duration of MenuSelect ; NOTE: a4 is used as an implicit parameter ; to PopUpMenuSelect subroutines ;------------------------------------------------ ; PopUpMenuSelect Loop ;------------------------------------------------ ; First bring up the pop-up menu, then track it. move.l PopUpMenuH(a6), a0 ; get menuID move.l (a0), a0 ; dereference menuHandle move menuID(a0), d1 ; store the menuID in D1 for GetHIndex call IMPORT GetHIndex bsr GetHIndex ; convert ID to index move d0, d4 ; save index in D4 beq @EndPopUpMS ; zero index ==> couldnÕt find it (shouldnÕt happen) ; Alter WMgr portRect to point to the rect of the device the cursor is on MOVE.L CrsrDevice, A1 ; Get the cursor GDevice MOVE.L (A1), A1 ; Dereference MOVE.L gdRect+topLeft(A1), portRect+topLeft(A2) ; Copy to MOVE.L gdRect+botRight(A1), portRect+botRight(A2) ; WMgr portRect IMPORT DirtyHMenus BSR DirtyHMenus ; Dirty size of all hierchical menus MOVE.L PopUpMenuH(A6), -(SP) ; Push the menuHandle _CalcMenuSize ; And recalculate it move d4, d5 ; copy saved index to D5 IMPORT DrawFirstMenu bsr DrawFirstMenu ; use special routine to place first menu move MBarHeight, -(SP) ; save MBarHeight on the stack clr MBarHeight ; clear MBarHeight so Hit Message to mbarproc ; ignores menu bar. @PopUpMSLoop moveq #1, d0 ; hit message is #1 move.l d3, d1 ; send point in parameter IMPORT CallMBarProc bsr CallMBarProc ; execute the defproc tst.l d0 ; where is the hit? bmi.s @SameMenu ; branch if its not in a title or any menu ; else itÕs in a menu move d0, d5 ; move result to D5 bsr GetMenuPtr ; get the menuData handle move menuID(a0),funcResult(a6) ;return which Menu the mouse is currently in ; At this point, D5 contains the menuIndex of the menu that the mouse points at, ; or a zero if no menu is pointed at. Check to see if this menu is different than ; the previous one pointed at cmp d5, d4 ; menuIndex = oldMenuIndex ? beq.s @SameMenu ; if the same, nothing to pull down IMPORT MenuChanged bsr MenuChanged ; change variables that affect current menu bmi.s @DonePopUpMS ; n-flag set means that MBarHook aborted MenuSelect @SameMenu tst d5 ; examine menu index beq.s @NextMouse ; donÕt choose an item unless thereÕs one down IMPORT ResetRectScrollData bsr ResetRectScrollData ; before choosing item be sure menuRect(a6) is ; correct as are scrolling globals IMPORT ChooseItem bsr ChooseItem ; choose item by calling mdefproc IMPORT CheckHItem bsr CheckHItem ; check for hierarchical stuff @NextMouse clr -(SP) ; make room for stillDown result _WaitMouseUp ; is the button still down? tst.b (SP)+ ; test _WaitMouseUp result beq.s @MouseUp ; => if up, flash user (oh Mr. Mac!) ; mouse still down, so get the mouse position and store in D3 subq #4,SP ; allocate place to get mouse move.l SP,-(SP) ; use temp buffer for mouse point _GetMouse ; get mouse in wmgr coordinates move.l (SP)+,d3 ; keep mouse point in D3 ; The mouse button is still down. WeÕve read the mouse position already, ; so call the user hook (if its installed) and loop. move.l MenuHook, d0 beq.s @NoMenuHook move.l d0, a0 jsr (a0) @NoMenuHook bra.s @PopUpMSLoop ; => continue tracking mouse ;------------------------------------------------ ; End of PopUpMenuSelect Loop ;------------------------------------------------ @MouseUp ; the mouse button went up. Give feedback to the user if she made a choice tst d5 ;was one selected? beq.s @NoFlash ;if not, dont bother ; ; If the item has a hierarchical menu attached DO NOT return the menu or item ; bsr GetMenuPtr ; get ptr to chosen menu in a0 (which we want for ; GetItemRecord call) move ItemResult(a6), d0 IMPORT GetItemRecord bsr GetItemRecord ; on return a1 points to itemÕs property bytes beq.s @FlashIt ; if z-flag set then item not found cmpi.b #HMenuCmd, itemCmd(a1) ; does this item have a hierarchical menu? bne.s @FlashIt ; no ==> branch and flash clr ItemResult(a6) ; yes ==> so clear the item bra.s @JustRestore ; and skip the flashing @FlashIt IMPORT FlashFeedback bsr FlashFeedBack ; flash the choice for feedback @JustRestore IMPORT RestoreAllBits bsr RestoreAllBits ; restore bits under all menus ; if no item selected, then no menu either @NoFlash tst ItemResult(a6) ; any Item? (we could get here several ways, ; so do it this way) bne.s @DonePopUpMS ; yes ==> then leave Func alone clr funcResult(A6) ; no Item ==> so clear Func too @DonePopUpMS move (SP)+, MBarHeight ; restore previous MBarHeight saved on the stack ; Restore WMgr portRect. WMgrCPort is in A2 MOVE.L WMgrPort, A0 ; Get b&w WMgrPort MOVE.L portRect+topLeft(A0), portRect+topLeft(A2) ; Copy to MOVE.L portRect+botRight(A0), portRect+botRight(A2) ; WMgr portRect IMPORT DirtyHMenus BSR DirtyHMenus ; Dirty size of all hierchical menus IMPORT DoneMS bra DoneMS ; use common code @EndPopUpMS IMPORT DoneMSelect bra DoneMSelect ; use common end code ENDPROC DirtyHMenus PROC ENTRY ;----------------------------------------------- ; Utility -- DirtyHMenus ;----------------------------------------------- ; ; Mark the size of all hierchical menus as dirty. Used by PopUpMenuSelect. ; IMPORT GetHA0List BSR GetHA0List ; get HMenuList ptr in A0 MOVE.W lastHMenu(a0), d5 ; get #HMenus ; we know there are HMenus so check them backwards MOVE.L MinusOne, d1 ; set up for GetHIndex IMPORT GetHIndex BSR GetHIndex ; d0 now has index to HMenuList header info ADD.W d0, d5 ; d5 has index to last HMenu MOVE.W d0, d6 ; d6 has index to HMenuList header @MenuLoop BSR GetMenuPtr ; get menu ptr in A0 from ID in D5 ; PB403: use A1 (handle), not A0 (pointer) MOVE.L A1,-(SP) ; push menu handle BSR.S DirtyMenuSize ; invalidate size SUBQ.W #6, d5 ; bump to next menu CMP.W d6, d5 ; at end of list? BGT.S @MenuLoop ; no, so try the next menu RTS ENTRY DirtyMenuSize DirtyMenuSize ; ;----------------------------------------------- ; Utility -- DirtyMenuSize ;----------------------------------------------- ; ; Utility DirtyMenuSize(menuHandle) -- Say that the menuÕs size is no longer valid by ; setting the width and height to -1. MOVE.L 4(SP),A0 ; get menuHandle MOVE.L (A0),A0 ; get menuPointer MOVE.L #-1,MenuWidth(A0) ; clear size MOVE.L (SP)+,(SP) ;strip parameter RTS ;return to caller ENDPROC CALCMENUSIZE PROC EXPORT ; PROCEDURE CalcMenuSize(menuHandle) -- scan the menuData of a menu and set the menuÕs ; width and heigth fields accordingly, by invoking the menu definition proc SUBQ.L #4, SP ; MOVE.L SP, -(SP) ; _GetPort ; MOVE.L WMgrCPort, A1 ; Get color port MOVE.L A1, -(SP) ; Set the port _SetPort ; MOVE #2,-(SP) ; Tell mProc to calc size MOVE.L 10(SP),A0 ; Get the menu handle MOVE.L A0,-(SP) ; Push it CLR.L -(SP) ; Pass 12 bytes of bogus addresses/junk CLR.L -(SP) CLR.L -(SP) MOVE.L (A0),A0 ; Get the menu ptr IMPORT CallMDefProc BSR CallMDefProc ; Call the menu definition proc _SetPort ; Restore the port (on stack) ENTRY StripIt StripIt MOVE.L (SP)+,(SP) ;strip parameter RTS ;return to caller ENDPROC SetTickCounters PROC ENTRY ;------------------------------------------------ ; Utility -- SetTickCounters ;------------------------------------------------ ; Set (Reset) stackframe tick counters DelayTicks ; and DragTicks. Get counts from parameter ram ; data that has been stored in stackframe. ; subq #4, SP ; space for result _TickCount ; get tick count move.l (SP), DelayTicks(a6) ; set DelayTicks clr.l d0 move.b menuDelaySave(a6), d0 ; get delta from param ram add.l d0, DelayTicks(a6) move.l (SP)+, DragTicks(a6) ; set DragTicks move.b menuDragSave(a6), d0 ; get delta from param ram add.l d0, DragTicks(a6) rts ENDPROC ResetRectScrollData PROC ENTRY ;------------------------------------------------ ; Utility -- ResetRectScrollData ;------------------------------------------------ ; ; The mouse is in a menu or title. If the last time thru MSLoop a HMenu was ; brought up, then menuRect(a6) will have the HMenuÕs rect and not the rect ; the mouse is currently in, so ask the MBarProc to give us the rect the ; mouse is in. Next ask the mbarproc to restore the scrolling globals ; topMenuItem, atMenuBottom for the menu the mouse is in. ; moveq #9, d0 ; rect message is #9 moveq #0, d1 ; clear hi-word of d1 since mbarproc WILL ; have this menu in its data structure already move d5, d1 ; send 6 byte offset in parameter IMPORT CallMBarProc bsr CallMBarProc ; execute the defproc move.l d0, a0 ; move ptr into a0 move.l Top(a0), menuRect(a6) ; move Top, Left move.l Bottom(a0), menuRect+4(a6) ; move Bottom, Right moveq #11, d0 ; reset scroll globals message is #11 move d5, d1 ; send 6 byte offset in parameter bsr CallMBarProc ; execute the defproc rts ENDPROC MenuChanged PROC ENTRY ;----------------------------------------------- ; Utility -- MenuChanged ;----------------------------------------------- ; 1. If mouse moved into a new menu title then: ; A. restore all menus on the screen ; B. draw a new one ; C. reset stackframe data for the new menu. ; 2. If just move into a menu that is already down then: ; A. just reset stackframe data for the new menu ; ; On entry: d4 has index to last menu ; d5 has index to new menu ; On exit: d4 == d5 == index to new menu ; ; start by clearing stackframe variables clr.w itemResult(A6) ; no item chosen... tst d4 ; was there one up already? beq.s @SkipRestore ; if not, skip restoring IMPORT GetA0List bsr GetA0List ; get menuList ptr into a0 cmp lastMenu(a0), d5 ; is the new menu in regular menuList? bgt.s @EndMenuChg ; no, its a HMenu thatÕs already down: ; so... 1) donÕt restore any menus ; 2) donÕt pull a new one down ; 3) donÕt call MBarHook ; ; if we got to here ==> mouse in the title of a NEW 'regular' menu, so restore all ; of the menus that are currently showing on the screen ; tst d5 ; a menu chosen ? beq.s @1 ; no, so skip resetting data IMPORT ResetRectScrollData bsr ResetRectScrollData ; before choosing item be sure menuRect(a6) is ; correct as are scrolling globals @1 IMPORT RestoreSomeBits BSR RestoreSomeBits ; restore bits under menus IMPORT SetTickCounters bsr SetTickCounters ; set tick counters for HMenus ; did RestoreSomeBits leave exactly one menu up ? cmpi #msHMenuStorage, msLastMenu(a6) beq.s @EndMenuChg ; yes, so skip menu draw MOVE D4,D0 ; get menuIndex for title invert IMPORT TurnIndexOff BSR TurnIndexOff ; unhilite old title @SkipRestore ; if the new menuIndex is non-zero (i.e., one was chosen), pull down the menu. move.w funcResult(a6), firstMenuID(a6) ; save ID of first menu down (for TheMenu) tst d5 ;is there a new one chosen? beq.s @EndMenuChg ;if not, go read the mouse again MOVE D5,D0 ; get menu index IMPORT TurnIndexOn BSR TurnIndexOn ; hilite the menu bar MOVE.L MBarHook,D0 ; is MBarHook installed? BEQ.S @DoTheDraw ;too bad, heÕs not ; ; ask the mbarproc for the menuÕs rectangle since MBarHook needs it. Remember that MBarHook ; is only called before regular menus go up, never HMenus. ; moveq #9, d0 ; rect message is #9 moveq #0, d1 ; clear d1 since this menu is a regular menu, ; not a HMenu move d5, d1 ; send 6 byte offset in parameter IMPORT CallMBarProc bsr CallMBarProc ; execute the defproc move.l d0, a0 ; get address of rectangle in a0 move.l (a0), menuRect(a6) ; move top,left into stackframe move.l 4(a0), menuRect+4(a6) ; move bottom, right into stackframe MOVE.L MBarHook,A0 ;get address in register PEA MENURECT(A6) ;tell the hook where to draw JSR (A0) ;call it TST D0 ;did it get him? ; beq.s @DoTheDraw ; yes, and he says to continue with MenuSelect move #-1, d5 ; oops, he told us to abort, so set n-flag bra.s @EndMenuChg ; and leave without drawing anything @DoTheDraw IMPORT DrawTheMenu bsr DrawTheMenu ; draw the menu @EndMenuChg MOVE D5, D4 ;old menuIndex = current menuIndex rts ENDPROC ChooseItem PROC ENTRY ;----------------------------------------------- ; Utility -- ChooseItem ;----------------------------------------------- ; PEA MENURECT(A6) ;donÕt let menuProc write outside of rect _ClipRect ;clip to menuRect BSR GETMENUPTR ;get handle to menu in A1 ; MOVE #MCHOOSEMSG,-(SP) ;tell menu to choose itself MOVE.L A1,-(SP) ;push menu handle PEA MENURECT(A6) ;push menuRect MOVE.L D3,-(SP) ;push mouse point PEA ITEMRESULT(A6) ;push place to stick result IMPORT CallMDefProc BSR CallMDefProc ; Call the menu definition proc ; ; every time the menu is chosen it could have scrolled, so re-save the scrolling data ; moveq #10, d0 ; set up for "save alt data" call move d5, d1 ; param is menuIndex of menu the mouse is in IMPORT CallMBarProc bsr CallMBarProc ; execute mbar defproc (ignore result in d0) rts ENDPROC CheckHItem PROC ENTRY ;----------------------------------------------- ; Utility -- CheckHItem ;----------------------------------------------- ; Check if itemResult(a6) has a hierarchical menu, and if so update various stackframe ; structures. If user has delayed in item long enough then put up the hier menu. ; ; On Entry: A1 ptr to itemÕs property bytes ; ; If no item selected then reset stackframe data and leave, but DONÕT restore any HMenus ; that might be up. (If no item selected then mouse is in the menu bar or outside all menus) ; bsr GetMenuPtr ; get ptr to menuInfo into a0 from index in d5 move itemResult(a6), d0 ; set up for GetItemRecord call, move item to d0 beq.s @NoItem ; if no item currently selected then leave ; ; If item does not have a hierarchical item then reset stackframe data, ; restore any HMenus up to the menu the mouse pt is in ; IMPORT GetItemRecord bsr GetItemRecord ; ptr to itemÕs record returned in a0 ; its properties in a1 cmpi.b #HMenuCmd, itemCmd(a1) ; does it have a hierarchical menu? bne.s @NotHItem ; no, then leave ; ; If funcResult or itemResult are not the same as last time thru the MSLoop then reset ; stackframe data and restore any HMenus up to the menu the mouse pt is in ; move funcResult(a6), d0 ; do this for "cmp" to work cmp lastFuncResult(a6), d0 ; is it the same menu as last time thru? bne.s @NotSameItem ; no, so reset data and menus move itemResult(a6), d0 ; do this for "cmp" to work cmp lastItemResult(a6), d0 ; is it the same item as last time thru? bne.s @NotSameItem ; no, so reset data move.l a1, -(SP) ; store work register on the stack subq #4, SP ; space for result _TickCount ; get current Ticks move.l (SP)+, d0 ; get Ticks in d0 move.l (SP)+, a1 ; restore work register cmp.l DelayTicks(a6), d0 ; have we reached right number of ticks ? blt.s @EndChkHItem ; no, so continue ; ; N ticks have passed with mouse in same item that has hierarchical menu, so bring ; the dang thing up. A1 has ptr to itemÕs properties. ; moveq #0, d1 ; clear out d1 for GetHIndex move.b itemMark(a1), d1 ; set up for GetHIndex -- move HMenu ID into d1 IMPORT GetHIndex bsr GetHIndex ; get the index in menuList in d0 beq.s @NotHItem ; oops, got invalid HMenu ID, so just ignore it move d0, d5 ; set up for DrawTheMenu IMPORT DrawTheMenu bsr DrawTheMenu ; and draw it move d5, NewHMenuOffset(a6) ; save d5 in stackframe move d4, d5 ; set up for call to ResetScrollRect IMPORT ResetRectScrollData bsr ResetRectScrollData ; and reset the scroll/rect for menu mouse is in IMPORT CheckDragging bsr CheckDragging ; check for mouse dragging towards HMenu ; If we get thru CheckDragging three states can exist: ; 1) The mouse is now in the HMenu --> select an item there ; 2) The mouse is in another menu item in the original menu --> bring HMenu down ; 3) The mouse has moved out of the menu --> bring HMenu down bra.s @EndChkHItem @NoItem @NotHItem @NotSameItem ; ; now restore bits behind any menus up ; IMPORT RestoreSomeBits bsr RestoreSomeBits ; Restore the bits behind all menus up to the ; one the mouse is currently in. IMPORT SetTickCounters bsr SetTickCounters ; reset tick counters @EndChkHItem move itemResult(a6), lastItemResult(a6) ; save values from this time thru move funcResult(a6), lastFuncResult(a6) rts ENDPROC CheckDragging PROC ENTRY ;----------------------------------------------- ; Utility -- CheckDragging ;----------------------------------------------- ; Allow the user to move the mouse towards the hierarchical ; menu for DragTicks. ; Wait for the mouse to leave the item, when it does, look ; to see if it is moving towards the menu. If it is moving ; towards the HMenu then wait MenuDrag ticks. ; ; On Entry: D5 Offset of newly drawn HMenu in MenuList. ; We need lots of registers, so save D5 in stackframe movem.l d4, -(SP) ; save d4 on stack subq #4, SP ; get mouse pt in D3 move.l SP, -(SP) ; temp mouse buffer on stack _GetMouse move.l (SP)+, d3 @InRectLoop ; see if mouse up yet clr -(SP) ; make room for stilldown result _WaitMouseUp ; is the button still down? tst.b (SP)+ ; test result beq @DoneDragging ; if up then done dragging ; call the mbarproc to see if mouse has entered the new HMenu moveq #1, d0 ; hit message is #1 move.l d3, d1 ; send point in parameter IMPORT CallMBarProc bsr CallMBarProc ; execute the defproc cmp NewHMenuOffset(a6), d0 ; is the hit in the newly drawn HMenu? beq @DoneDragging ; yes, so no more dragging needed ; not in new HMenu, so see if it is still in the itemÕs rect subq #2, SP ; save space for PtInRect result subq #4, SP ; space for GetMouse result move.l SP, -(SP) ; temp mouse buffer on stack _GetMouse ; point is on the stack move.l (SP), d3 ; store pt in d3 and leave on stack for PtInRect ; The mouse button is still down. WeÕve read the mouse position already, ; so call the user hook (if its installed) and loop. MOVE.L MENUHOOK,D0 ; BEQ.S @NoMHook ; MOVE.L D0,A0 ; JSR (A0) ; @NoMHook ; move.l mbSaveLoc, a0 ; get itemÕs rect from mbSaveLoc move.l (a0), a0 ; dereference pea mbItemRect(a0) ; push rect _PtInRect move.b (SP)+, d0 ; get boolean result bne.s @InRectLoop ; still in rect, wait for it to leave ; if get here then mouse has moved out of itemRect but not into HMenu. ; First get menurect of HMenu by calling mbarproc. D3 has latest mouse pt from ; which we will draw the triangle allowing mouse to move towards HMenu. moveq #9, d0 ; CalcRect message is #9 moveq #0, d1 ; clear hi-word of d1 since mbarproc WILL ; have this menu in its data structure already move NewHMenuOffset(a6), d1 ; send MenuList offset as parameter IMPORT CallMBarProc bsr CallMBarProc ; execute the defproc move.l d0, a0 move.l (a0), d4 ; store top, left in d4 move Bottom(a0), d5 ; store bottom, left in d5 swap d5 move Left(a0), d5 cmp d3, d4 ; if horizontal of D4 < D3 then menu to left bgt.s @1 ; yes --> menu to left ; if menu is to the left then want to use ; right edge for angle calculations, otherwise ; will get angles too close to 90 degrees move Right(a0), d4 ; store top, right in d4 move Right(a0), d5 ; store bottom, right in d5 ; reset MenuDrag as of when mouse left the itemÕs rect @1 IMPORT SetTickCounters bsr SetTickCounters ; On Entry: D3 original mouse pt ; D4 top, left edge of HMenu ; D5 bottom, left edge of HMenu ; D7 hi-word has right pixel of newly drawn HMenu ; Used: D6 latest mouse pt ; D7 for intermediate calculations @DragLoop ; see if mouse up yet clr -(SP) ; make room for stilldown result _WaitMouseUp ; is the button still down? tst.b (SP)+ ; test result beq @DoneDragging ; if up then done dragging ; see if have returned to the item rect, if so return to @InRectLoop, otherwise the same ; HMenu that is currently up will appear again. At the same time we are getting the mouse ; pt in D6. subq #2, SP ; save space for PtInRect result subq #4, SP ; space for GetMouse result move.l SP, -(SP) ; temp mouse buffer on stack _GetMouse ; point is on the stack move.l (SP), d6 ; store pt in d6 and leave on stack for PtInRect ; The mouse button is still down. WeÕve read the mouse position already, ; so call the user hook (if its installed) and loop. MOVE.L MENUHOOK,D0 ; BEQ.S @NoMHook2 ; MOVE.L D0,A0 ; JSR (A0) ; @NoMHook2 ; move.l mbSaveLoc, a0 ; get itemÕs rect from mbSaveLoc move.l (a0), a0 ; dereference pea mbItemRect(a0) ; push rect _PtInRect move.b (SP)+, d0 ; get boolean result bne.s @InRectLoop ; BACK IN ITEMÕS RECT, WAIT FOR IT TO LEAVE AGAIN!!! ; call the mbarproc to see if mouse has entered the new HMenu moveq #1, d0 ; hit message is #1 move.l d6, d1 ; send point in parameter IMPORT CallMBarProc bsr CallMBarProc ; execute the defproc cmp NewHMenuOffset(a6), d0 ; is the hit in the newly drawn HMenu? beq.s @DoneDragging ; yes, so no more dragging needed ; see if current mouse pt (D6) is within triangle bounded by D3, D4 and D5 ; ; /D4 ; / | ; / | ; / | ; D3 D6 | An obvious place to save code, but not on ROM build day!! ; \ | ; \ | ; \ | ; \D5 ; ; first check whether menuÕs direction was right or left or previous menu @ChkToRight cmp d3, d4 ; if horizontal of D4 < D3 then menu to left blt.s @ChkToLeft ; first see if D6 < D3 horizontally cmp d3, d6 ; is D6 < D3 blt.s @DoneDragging ; yes, so moving wrong way ;draw a line from D3 to D6, calculate its slope and from that its angle MOVE.L D6, D1 ; MOVE.L D3, D0 ; BSR.S @SlopeFromLine ; move d0, d7 ; ;draw a line from D3 to D4, calculate its slope and from that its angle MOVE.L D4, D1 ; MOVE.L D3, D0 ; BSR.S @SlopeFromLine ; cmp d0, d7 ; is angle to mouse >= angle to D4 ? blt.s @DoneDragging ; no, so mouse outside triangle ;draw a line from D3 to D5, calculate its slope and from that its angle MOVE.L D5, D1 ; MOVE.L D3, D0 ; BSR.S @SlopeFromLine ; cmp d0, d7 ; is angle to mouse >= angle to D4 ? bgt.s @DoneDragging ; yes, so mouse outside triangle bra.s @ChkTimeOut ;draw a line from D0 to D1, calculate its slope and from that its angle. Returned in D0. @SlopeFromLine ; LEA -10(SP), SP ; 2 (AngleFromSlope) + 4 (FixRatio) + 4 (DeltaPoint) MOVE.L D1, -(SP) MOVE.L D0, -(SP) _DeltaPoint ; now have dv and dh on the stack _FixRatio _AngleFromSlope MOVE.W (SP)+, D0 RTS @ChkToLeft ; first see if D6 > D3 horizontally cmp d3, d6 ; is D6 > D3 bgt.s @DoneDragging ; yes, so moving wrong way ;draw a line from D3 to D6, calculate its slope and from that its angle MOVE.L D3, D1 ; MOVE.L D6, D0 ; BSR.S @SlopeFromLine ; move d0, d7 ; ;draw a line from D3 to D4, calculate its slope and from that its angle MOVE.L D3, D1 ; MOVE.L D4, D0 ; BSR.S @SlopeFromLine ; cmp d0, d7 ; is angle to mouse <= angle to D4 ? bgt.s @DoneDragging ; no, so mouse outside triangle ;draw a line from D3 to D5, calculate its slope and from that its angle MOVE.L D3, D1 ; MOVE.L D5, D0 ; BSR.S @SlopeFromLine ; cmp d0, d7 ; is angle to mouse <= angle to D4 ? blt.s @DoneDragging ; yes, so mouse outside triangle ; fall thru to @ChkTimeOut @ChkTimeOut ; mouse is still moving towards HMenu, see if timeout yet subq #4, SP ; space for result _TickCount ; get current Ticks move.l (SP)+, d0 ; get Ticks in d0 cmp.l DragTicks(a6), d0 ; have we reached DragTicks ? bge.s @DoneDragging ; yes, so quit dragging bra.s @DragLoop ; no, so keep dragging @DoneDragging movem.l (SP)+, d4 ; restore work register move d4, d5 ; restore d5 (since d4==d5 before HMenu was drawn) rts ENDPROC RestoreBits PROC ENTRY ;----------------------------------------------- ; Utility -- RestoreBits ;----------------------------------------------- ; ; RESTOREBITS is a utility that takes the bits that were saved by SaveBits and ; puts them back on the screen. ; subq #msHMenuStorage, msLastMenu(a6) ; reduce counter MOVEQ #8,D0 ; set restore message IMPORT CallMBarProc BRA CallMBarProc ; execute the defproc (result in D0) ; and let CallMBarProc return ENDPROC RestoreSomeBits PROC ENTRY ;----------------------------------------------- ; Utility -- RestoreSomeBits ;----------------------------------------------- ; RestoreSomeBits loops thru each menu up on the screen looking to see if it should ; be restored, and if it should be, restoring it. The condition for restoration is ; if the mouse pt is in the current menu then donÕt restore it. ; move.l (a4), a0 ; get ptr to temp storage move msLastMenu(a6), d0 ; get offset to last menu on screen beq.s @RSBNone ; if no menus then exit (should never happen but...) cmp -4(a0, d0), d5 ; is the 'last' menu the one the mouse is in? beq.s @RSBNone ; yes, so donÕt restore any, and donÕt redraw menu @RSBLoop move.l (a4), a0 ; get ptr to temp storage move msLastMenu(a6), d0 ; get offset to last menu on screen beq.s @RSBNone ; if no menus then exit cmp -4(a0, d0), d5 ; is the 'last' menu the one the mouse is in? beq.s @RSBDone ; yes, so done restoring move -2(a0, d0), itemResult(a6) ; no, so restore previous selected item IMPORT RestoreBits bsr RestoreBits ; restore dem bits bra.s @RSBLoop ; and loop @RSBDone ; ; If here then at least one menu was restored, and as a result of the HMenu ; overlap the menu has strange black and white patches. Calling ChooseItem ; with the item that was selected in the menu before the HMenu was ; brought up will cause both old and new items to be redrawn. tst msLastMenu(a6) ; any menus left up ? beq.s @RSBNone ; no, so donÕt choose anything IMPORT ChooseItem bsr ChooseItem ; tell MDEF to choose after redraw @RSBNone RTS ENDPROC RestoreAllBits PROC ENTRY ;----------------------------------------------- ; Utility -- RestoreAllBits ;----------------------------------------------- ; RestoreAllBits loops thru every menu up on the screen and restores the bits ; behind each in turn. It is called when 1) the mouse button has gone up, or 2) the mouse ; has gone into another menu title. ; tst msLastMenu(a6) ; could have already restored all beq.s @RestoreDone ; the menus ? IMPORT RestoreBits bsr RestoreBits ; restore dem bits bra.s RestoreAllBits ; yes, so loop @RestoreDone RTS ENDPROC DrawFirstMenu PROC ENTRY ;----------------------------------------------- ; Utility -- DrawFirstMenu ;----------------------------------------------- ; DrawFirstMenu draws the first pop-up menu. This is separate because of the special placement ; needed for the pop-up menu. The top left edge of the item PopUpItem must match the parameters ; Top and Left. All subsequent menus are drawn using the same routines that MenuSelect uses. ; ; TODO: Call MBarHook after sending msg #3 to MDEF but before drawing menu. addq #msHMenuStorage, msLastMenu(a6) ; bump up counter move msLastMenu(a6), d0 ; get offset into temp storage move.l (a4), a0 ; get ptr to temp storage move d5, -4(a0, d0) ; store MenuList offset move itemResult(a6), -2(a0,d0) ; and item number ; Call MDEF to calculate where pop-up menu should go. This is a new message to the MDEF. ; Pass: MenuHandle, Top, Left, Item ; Return: MenuRect, TopMenuItem move #3, -(SP) ; message = calc item top bsr GetMenuPtr ; get a handle to the menu record into A1 using ; menuIndex in D5, and ptr in A0 move.l a1,-(SP) ; push menu handle pea menuRect(a6) ; push menuRect pointer move.l msTopLeft(a6), -(SP) ; push left and top at same time pea PopUpItem(a6) ; push the itemÕs address IMPORT CallMDefProc BSR CallMDefProc ; Call the menu definition proc ; Call MBDF to save bits behind and draw the drop shadow MOVEQ #7, D0 ; set up for save message SWAP D0 ; put parameter1 in hi-word of D0 MOVE D5, D0 ; parameter1 is menuList offset SWAP D0 LEA menuRect(a6), A0 ; parameter2 is address of menuRect MOVE.L A0, D1 ; put in D1 for CallMBarProc IMPORT CallMBarProc BSR CallMBarProc ; tell it to save. No result. ; MDEF returns TopMenuItem in WhichItem parameter, store it in low-memory move PopUpItem(a6), TopMenuItem IMPORT CallDrawMDEF bsr CallDrawMDEF ; ask the MDEF to draw the menu @DoneDraw RTS ENDPROC DRAWTHEMENU PROC ENTRY ;----------------------------------------------- ; Utility -- DrawTheMenu ;----------------------------------------------- ; DrawTheMenu is an internal utility that draws the structure of a menu. It uses ; the menu whose index is in D5. ; ; call the mBar defproc to draw the pulldown and save the bits ; behind. ; cmpi #5*msHMenuStorage, msLastMenu(a6) ; are there 5 menus up already??? beq.s @DoneDraw ; yes, so leave without doing anything addq #msHMenuStorage, msLastMenu(a6) ; bump up counter move msLastMenu(a6), d0 ; get offset into temp storage move.l (a4), a0 ; get ptr to temp storage move d5, -4(a0, d0) ; store menuID move itemResult(a6), -2(a0,d0) ; and item number clr.l d1 ; clear out d1 for mbarproc call cmpi #msHMenuStorage, msLastMenu(a6) ; is this a hierarchical menu? ; If so, we need to send the vertical ; mouse pt to mbarproc beq.s @NotHMenu ; no, so just do normal stuff move.l d3, d1 ; yes, so move mouse pt into d1. Vertical ; mouse pt is in hi-word of d3 @NotHMenu MOVEQ #9,D0 ; set up for the rect message MOVE.w D5,D1 ; parameter is the menuIndex (affects lo-word ; of D1 only, hi-word still has vert mouse pt) IMPORT CallMBarProc BSR CallMBarProc ; execute the defproc (result in D0) MOVE.L D0,A0 ; move menuRect ptr to A-reg MOVE.L (A0),menuRect(A6) ; copy the rect MOVE.L 4(A0),menuRect+4(A6) ; MOVEQ #7, D0 ; set up for save message SWAP D0 ; put parameter1 in hi-word of D0 MOVE D5, D0 ; parameter1 is menuList offset SWAP D0 LEA menuRect(a6), A0 ; parameter2 is address of menuRect MOVE.L A0, D1 ; put in D1 for CallMBarProc BSR CallMBarProc ; tell it to save. No result. move menuRect+Top(a6), TopMenuItem ; tell MDEF to draw from top of menu IMPORT CallDrawMDEF bsr CallDrawMDEF ; ask the MDEF to draw the menu @DoneDraw RTS ENDPROC CallDrawMDEF PROC ENTRY ;----------------------------------------------- ; Utility -- CallDrawMDEF ;----------------------------------------------- ; CallDrawMDEF is an internal utility that asks the MDEF ; to draw the menu whose offset is in D5. Immediately after ; the menu is drawn the MBDF is told to save the two scrolling ; globals topMenuItem and atMenuBottom. See note in MBDF ; about why this was done this way. ; ; before drawing, clip to intersection of menuRect and portRect in case user has multiple screens ; Just clip to menuRect now. ; subq #2, SP ; space for boolean result ; pea menuRect(a6) ; push src rectangle 1 ; pea portRect(a2) ; push src rectangle 2 ; pea tRect1(a6) ; push dest rectangle ; _SectRect ; addq #2, SP ; ignore result ; ; PEA tRect1(a6) ;donÕt let menuProc write outside of rect PEA menuRect(A6) ; Just use menuRect now. _ClipRect ;clip to menuRect CLR.W -(SP) ;message = draw BSR GETMENUPTR ;get a handle to the menu record into A1 using ; menuIndex in D5 MOVE.L A1,-(SP) ;push menu handle PEA menuRect(A6) ;push menuRect pointer SUBQ #8,SP ;point and whichItem are not looked at IMPORT CallMDefProc BSR CallMDefProc ; Call the menu definition proc moveq #10, d0 ; set up for "save alt data" call move d5, d1 ; param is menuIndex of menu the mouse is in IMPORT CallMBarProc bsr CallMBarProc ; execute mbar defproc (ignore result in d0) rts ENDPROC CallMDefProc PROC ENTRY ;----------------------------------------------- ; Utility -- CallMDefProc(message: INTEGER; theMenu: MenuHandle; VAR menuRec: ; Rect; hitPt: Point; VAR whichItem: INTEGER); ; (menuRecord pointer in A0) ;----------------------------------------------- ; Utility CallMDefProc -- given a menuRecord pointer in A0, calls the menu definition ; procedure. It does this by de-referencing the defProc handle, reloading it into ; memory if necessary. If there is no MenuDefProc, it simply cleans up the stack and returns. ; This routine replaces GetTheMProc UnlockMProc, and UnlkMDef. paramSize EQU 18 MOVEM.L D3/A5, -(SP) ; Save some registers MOVE.L MenuDefHandle(A0),D3 ; get the handle BEQ.S @NoMenuDef ; Skip if there is none. LEA 8+4(SP), A0 ; Original parameters MOVEQ #paramSize, D0 ; Size of parameters SUB.L D0, SP ; Prepare to make a copy of the parameters MOVE.L SP, A1 ; Copy _BlockMove ; Do it. MOVE.L D3,-(SP) ; get the MDEF handle _LoadResource ; load it MOVE.L D3, A0 ; get the MDEF handle ; Some programmers are pretty slimy and load a MDEF that is empty. They then fau ; stuff some code into it. However, since HLOCK does not flush the cache anymore, fau ; the code that they stuff into it might not get written back to memory. To solve this, fau ; we check here whether the MDEF resource size is less than, say, 32 bytes. If so, we chp ; assume that they have already loaded the MDEF and modified it, so we flush the cache fau ; for them. _GetHandleSize ; How big is our MDEF Handle fau cmp.l #32,D0 ; Is it "small" chp bhi.s @RealMDEF ; no, don't flush the cache fau jsr ([jCacheFlush]) ; else, flush the caches. fau @RealMDEF ; fau _HLock ; lock it the gentlemanÕs way MOVE.L (A0),A0 ; handle -> pointer MOVE.L CurrentA5, A5 ; fix up his A5 world JSR (A0) ; call it MOVE.L D3, A0 ; get the MDEF handle _HUnlock ; unlock the gentlemanÕs way @NoMenuDef MOVEM.L (SP)+, D3/A5 ; Restore some registers MOVE.L (SP)+, A0 ; get the return address LEA paramSize(SP), SP ; strip off the parameters JMP (A0) ; and return ENDPROC CALLCHOOSE PROC EXPORT ; ; CallChoose is a utility procedure to call a menuÕs menuProc to select an item ; MOVE #MCHOOSEMSG,-(SP) ;the message is choose BSR GETMENUPTR ;get handle to menu specified by D5 MOVE.L A1,-(SP) ;push menuHandle PEA MENURECT(A6) ;push rectangle of current menu MOVE.L D1,-(SP) ;mouse point PEA TOOLSCRATCH ;scratch location to store result IMPORT CallMDefProc BSR CallMDefProc ; Call the menu definition proc ; ; delay based on TICKS ; move.l #3, a0 ; 1/20 second delay (tune it!) _Delay ; for the Unix folks RTS ENDPROC FLASHFEEDBACK PROC ENTRY ;----------------------------------------------- ; Utility -- FlashFeedBack ;----------------------------------------------- ; ; FlashFeedBack is a utility routine that implements flash feedback on menu selections. ; tThe "MenuFlash" global determines the number of flashes ; MOVE D4,-(SP) ;save work register MOVE MENUFLASH,D4 ;get menu flash count BEQ.S FLASHDONE ;if zero, no flashing at all MOVE ITEMRESULT(A6),TOOLSCRATCH ;was anything selected? BEQ.S FLASHDONE ;if not, donÕt give feedback PEA MENURECT(A6) ;clip to the menu _ClipRect ; ; Here is the flash loop. It uses TICKS for timing. ; FLASHLOOP MOVEQ #0,D1 ;zero point to force selection off IMPORT CallChoose BSR CALLCHOOSE ;call the menuProc to turn it off MOVE.L D3,D1 ;now use real point to turn it on BSR CALLCHOOSE ;call menuProc to turn it on SUBQ #1,D4 ;any more times? BNE.S FLASHLOOP ;do it flashCount times IMPORT FullClip BSR FULLCLIP ;restore full screen clipping FLASHDONE MOVE (SP)+,D4 ;restore D4 RTS ;return to caller ENDPROC FULLCLIP PROC EXPORT ;----------------------------------------------- ; Utility -- FullClip ;----------------------------------------------- ; FullClip is a utility that sets the clipping region of the wmgrPort to the portRect ; It is used to save code. ; ; Note: It is not really necessary to set clip full open here because the mbarproc is ; called after this to restore the menu, and it sets the clip full open. But ; because it is so close to ROM build we wonÕt take it out. ; MOVE.L GrafGlobals(A5), A0 ; MOVE.L wideOpen(A0), -(SP) ; set the clip to wide open _SetClip ; RTS ENDPROC MenuChoice PROC EXPORT ;------------------------------------------------------------------------------------ ; ; FUNCTION MenuChoice : LONGINT; ; ;------------------------------------------------------------------------------------ ; FUNCTION MenuChoice : LONGINT; ; ; Returns the menuID in the hi-word and menu Item in the lo-word from the lo-mem location ; MenuDisable ($B54). This feature was requested by User-Ed who want to use ; it with training programs. ; move.l MenuDisable, 4(SP) ; set function result rts ENDPROC GetMenuBar PROC EXPORT ;------------------------------------------------------------------------------------ ; ; GetMenuBar ; do not return system menus in the returned menu list <22> PN ;------------------------------------------------------------------------------------ ; ; FUNCTION GetMenuBar: MenuListHandle -- allocate a menuList data structure and copy ; the current menuList into it ; ;¥ roll in GetMenuBarDoesNotReturnSystemMenus from SystemMenuPatches.a ; GetMenuBarDoesNotReturnSystemMenus Ñ do not return system menus in the returned menu list IF forROM THEN IMPORT FindFirstSystemMenu6BO jsr FindFirstSystemMenu6BO ; Are there any system menus? beq OriginalTrap MOVE.L d3,-(SP) ; Save off a work register MOVEQ #0,D3 MOVE.W D0,D3 ; Save off index SUBQ.L #4,SP ; Make room for result JSR OriginalTrap MOVE.L (SP)+,A0 ; Get copy of menulist MOVE.L A0,8(SP) ; Return as result BEQ.S @done ; EQ means no menulist or memfull ; Munger(menuH, d3, NIL, d1, POINTER(-1), 0); MOVE.L (A0),A1 ; Get copymenulist ptr moveq #0,d1 ; clear out high word <10> MOVE.W lastMenu(A1),D1 ; Offset to last menu (could be zero but weÕve chkd that) ADDQ.W #6,D1 ; Offset past last menu entry SUB.W d3,D1 ; D1 = Offset to last menu - Offset to 1st sysmenu ; (i.e., # bytes for system menus) SUB.W D1,lastMenu(A1) ; Set new count for the list SUBQ.L #4,SP ; Make room for Munger result MOVE.L A0,-(SP) ; Push the handle MOVE.L d3,-(SP) ; offset=first system menu offset CLR.L -(SP) ; ptr1=NIL <10> MOVE.L D1,-(SP) ; len1=# of bytes to delete MOVE.L A0,-(SP) ; ptr2=anything non-nil will do CLR.L -(SP) ; len2=0 means delete _Munger ; Rip out system menus ADDQ.L #4,SP ; ignore Munger result @done MOVE.L (SP)+,d3 ; Restore work register RTS OriginalTrap ENDIF ;¥ roll in GetMenuBarDoesNotReturnSystemMenus from SystemMenuPatches.a move.l menuList, a0 ; get the menuList handle MOVE.L A0, 4(SP) ; Is this NIL? If yes, return as function result beq.s @1 ; YES, - faceless MF app is running _HandToHand ; make a copy of it move.l a0, 4(SP) ; return it as the function result MOVE.L (A0), A0 ; Dereference it MOVE.W lastMenu(A0), D0 ; Get last regular menu CLR.L menuTitleSave+6(A0, D0) ; Clear out saved handle @1 ; Branch here when menulist is NIL rts ; ENDPROC GetMCInfo PROC EXPORT ; ;------------------------------------------------------------------------------------ ; ; GetMCInfo ; ;------------------------------------------------------------------------------------ ; ; FUNCTION GetMCInfo: MenuCTblHandle -- allocate a new color table, and copy the ; current one into it. ; move.l MenuCInfo, a0 ; get the color table handle _HandToHand ; make a copy of it beq.s @OK ; check error result moveq #0, a0 ; on error return zero @OK move.l a0, 4(SP) ; return it as the function result rts ENDPROC SetMenuBar PROC EXPORT ;------------------------------------------------------------------------------------ ; ; SetMenuBar ; ;------------------------------------------------------------------------------------ ; ; PROCEDURE SetMenuBar(menuListHandle) -- copy the parameter menu list into the current ; menu List. ; SetMenuBarAddsSystemMenus Ñ SetMenuBar should add the system menus to the current menu list ; Roll in SetMenuBarAddsSystemMenus from SystemMenuPatch.a CLR.W -(SP) ; A new menu bar invalidates the _HiliteMenu ; currently selected title move.l menuList, a0 ; get the old menuList _DisposHandle ; and dispose of it move.l 4(SP), a0 ; get the parameter menuList handle move.l (SP)+, (SP) ; strip the parameter _HandToHand ; make a copy of the parameter list move.l a0, menuList ; store the new menuList MOVE.L a0,D0 ; Get result BEQ.S @done ; EQ means no menulist or memfull ; Call the MBDF to put in the system menus MOVEQ #2,D0 ; set up for the menu-edge-calc msg CLR.L D1 ; calc entire bar IMPORT CallMBarProc jsr CallMBarProc @done RTS ENDPROC SetMCInfo PROC EXPORT ; ;------------------------------------------------------------------------------------ ; ; SetMCInfo ; ;------------------------------------------------------------------------------------ ; ; PROCEDURE SetMCInfo(menuCTblHandle) -- copy the parameter menu color table into the ; current menu color table. MemErr will be set for caller if HandToHand failed. move.l 4(SP), a0 ; get the parameter menuList handle move.l (SP)+, (SP) ; strip the parameter _HandToHand ; make a copy of the parameter list bne.s @NoMemory ; check error result ; on error do not change color table @OK move.l MenuCInfo, a1 ; get the old color table move.l a0, MenuCInfo ; store the new menuList move.l a1, a0 ; move old color table handle to a0 _DisposHandle ; and dispose of it IMPORT MenuCTblSanityChk bsr MenuCTblSanityChk ; check the table for consistency @NoMemory rts ; return ENDPROC DISPOSEMENU PROC EXPORT ;------------------------------------------------------------------------------------ ; ; DisposeMenu ; ;------------------------------------------------------------------------------------ ; PROCEDURE DisposeMenu(menuHandle) -- dispose of the dynamic storage used by the ; menu data structure ; <15> DisposeMenu supports disposing both menus that are resource handles and other menus. ; Thus, it has the responsibility of disposing the handle and removing it from the ; resource map. One way to do this would be to call DetachResource and then DisposeHandle, ; since the Resource Manager is tolerant of non-resource handles, and would just return ; an error. However, the Process Manager depends on ReleaseResource to keep track of ; Apple menu handles, so we instead do a ReleaseResource, followed by a DisposeHandle if ; the ReleaseResource returns resNotFound (which is what it will do if you pass it something ; other than a resource handle). move.l 4(sp),-(sp) ; first, call ReleaseResource on the menu handle _ReleaseResource subq #2,sp ; check the error _ResError cmp.w #resNotFound,(sp)+ ; did ReleaseResource dispose the handle? bne.s Done ; yes, we are done move.l 4(sp),a0 ; now call DisposeHandle on the menu handle _DisposeHandle Done move.l (sp)+,(sp) ; strip menu handle parameter rts ENDPROC DispMCInfo PROC EXPORT ; ;------------------------------------------------------------------------------------ ; ; DispMCInfo ; ;------------------------------------------------------------------------------------ ; PROCEDURE DispMCInfo(menuCTblHandle) -- dispose of the dynamic storage used by the ; menu color table MOVE.L 4(SP),A0 ; get menu color table Handle _DisposHandle ; itÕs not a resource, so just toss it move.l (SP)+, (SP) ; strip parameter RTS ENDPROC CHECKITEM PROC EXPORT ; ; PROCEDURE CheckItem(menuHandle,itemNumber, checked: BOOLEAN) -- check or unCheck ; an item. Strategy: transform the boolean into the proper char right on the stack ; TST.B 4(SP) ;test the boolean BEQ.S CNOMARK ;go use noMark symbol MOVE #CHECKMARK,4(SP) IMPORT SetItemMark BRA SETITEMMARK ;go mark it CNOMARK MOVE #NOMARK,4(SP) ;unCheck it BRA SETITEMMARK ;go do it ENDPROC GETITEMMARK PROC EXPORT ; ; PROCEDURE GetItemMark(menuHandle,itemNumber,VAR markChar) -- get the current value of ; an itemÕs markfield. Use GetItemProperty. ; MOVEQ #ITEMMARK,D2 ;set up property selector IMPORT GetItemProperty BRA GETITEMPROPERTY ;do it! ENDPROC GETITEMICON PROC EXPORT ; ; PROCEDURE GetItemIcon(menuHandle,itemNumber,VAR iconChar) -- get the current value of ; an itemÕs icon field. Use GetItemProperty. ; MOVEQ #ITEMICON,D2 ;set up property selector IMPORT GetItemProperty BRA GETITEMPROPERTY ;do it! ENDPROC GETITEMCMD PROC EXPORT ; ; ; PROCEDURE GetItemCmd(menuHandle,itemNumber,VAR cmdChar) -- get the current value of ; an itemÕs cmd field. Use GetItemProperty. Needed for hierarchical menus. ; MOVEQ #ITEMCMD,D2 ;set up property selector IMPORT GetItemProperty BRA GETITEMPROPERTY ;do it! ENDPROC __GETITEMSTYLE PROC EXPORT ; ; PROCEDURE GetItemStyle(menuHandle,itemNumber,VAR styleChar) -- get the current value of ; an itemÕs style field. Use GetItemProperty. ; MOVEQ #ITEMSTYLE,D2 ;set up property selector IMPORT GetItemProperty BRA GETITEMPROPERTY ;do it! ENDPROC SETITEMMARK PROC EXPORT ; ; PROCEDURE SetItemMark(menuHandle,itemNumber,markChar) -- set the current value of an ; itemÕs mark field. Use SetItemProperty. ; MOVEQ #ITEMMARK,D2 ;set up property selector IMPORT SetItemProperty BRA SETITEMPROPERTY ENDPROC SETITEMICON PROC EXPORT ; ; PROCEDURE SetItemIcon(menuHandle,itemNumber, iconChar) -- set the current value of ; an itemÕs icon field. Use SetItemProperty. ; MOVEQ #ITEMICON,D2 ;set up property selector IMPORT SetItemProperty BRA SETITEMPROPERTY ;do it! ENDPROC SETITEMCMD PROC EXPORT ; ; ; PROCEDURE SetItemCmd(menuHandle,itemNumber, cmdChar) -- set the current value of ; an itemÕs cmd field. Use SetItemProperty. Needed for hierarchical menus. ; MOVEQ #ITEMCMD,D2 ;set up property selector IMPORT SetItemProperty BRA SETITEMPROPERTY ;do it! ENDPROC SETITEMSTYLE PROC EXPORT ; ; PROCEDURE SetItemStyle(menuHandle,itemNumber,styleChar) -- set the current value of ; an itemÕs style field. Use SetItemProperty. ; MOVEQ #ITEMSTYLE,D2 ;set up property selector IMPORT SetItemProperty BRA SETITEMPROPERTY ;do it! ENDPROC GETITEMPROPERTY PROC ENTRY ; ; PROCEDURE GetItemProperty(menuHandle,itemNumber, VAR propertyValue) -- is an internal ; routine similar to SetItemProperty that gets a property of a requested item. ; The property is selected by the small integer in D2. ; MOVE.L 10(SP),A0 ;get menuHandle MOVE.L (A0),A0 ;turn into menu pointer MOVE 8(SP),D0 ;get item number IMPORT GetItemRecord BSR GETITEMRECORD ;look it up MOVE.L 4(SP),A0 ;get result pointer CLR.B (A0) ;assume result of zero MOVE.L A1,D0 ;did we find the item? BEQ.S TENBYTEXIT ;if not, weÕre done MOVE.B 0(A1,D2),1(A0) ;move the requested property byte ENTRY TenBytExit TENBYTEXIT MOVE.L (SP)+,A0 ;get return address ADD #10,SP ;strip 10 bytes of parameters JMP (A0) ;return to caller ENDPROC SETITEMPROPERTY PROC ENTRY ; ; PROCEDURE SetItemProperty(menuHandle,itemNumber,propertyValue) -- an internal routine ; to set a property byte of an item. A small integer offset in D2 determines ; which property. ; MOVE.L 8(SP),A0 ;get menuHandle MOVE.L (A0),A0 ;handle -> pointer MOVE 6(SP),D0 ;get item number IMPORT GetItemRecord BSR GETITEMRECORD ;find the item BEQ.S TWOPARMEXIT ;if not, skip MOVE.B 5(SP),0(A1,D2) ;move in the property byte SUBQ #ItemMark,D2 ; is it the check mark? BEQ.S TwoParmExit ; yes, donÕt recalculate MOVE.L 8(SP),-(SP) ;push the menuHandle IMPORT DirtyMenuSize BSR DirtyMenuSize ; invalidate size ENTRY TwoParmExit TWOPARMEXIT MOVE.L (SP)+,A0 ;get return address ADDQ #8,SP ;strip 8 bytes of parameters JMP (A0) ;return to caller ENDPROC GETITEMRECORD PROC ENTRY ; ; GetItemRecord is the main utility used for accessing the menu item data structure. ; It has a register interface to save code. On entry, A0 points to a menuInfo block, ; while D0 has the item number of interest. On exit, A0 points to the item string ; of interest while A1 points to that itemÕs attribute byte list. If the item canÕt ; be found, A0 and A1 both return NIL and the z-flag is set. ; TST D0 ; make sure item number is valid BLE.S NOITEM ; => invalid, donÕt bother DOITEM MOVEQ #0,D1 ; clear D1 for byte arithmetic LEA MENUDATA(A0),A1 ; get menuData ptr MOVE.B (A1)+,D1 ; get title length ADD D1,A1 ; skip over title string ; ; here is the item search loop. A1 points to the beginning of the next item. ; GETILOOP SUBQ #1,D0 ; is this the one weÕre looking for? BEQ.S GOTITEM ; if so, we got it MOVE.B (A1),D1 ; get length of current item BEQ.S NOITEM ; length zero marks end of list ADDQ #5,D1 ; 4 bytes of properties + 1 length ADD D1,A1 ; bump to next item BRA.S GETILOOP ; loop till done ; ; the item couldnÕt be found so return NIL ; put string pointer into D1 in case we want to find end byte ; NOITEM MOVE.L A1,D1 ; return pointer to 0 byte in D1 SUB.L A0,A0 ;zero A0 MOVE.L A0,A1 ;and A1 too MOVE.L A0,D0 ;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 MOVE.L A1,A0 ;A0 points to item string MOVE.B (A1)+,D1 ;get length ADD D1,A1 ;bump to item properties RTS ;return to caller (z-clear) ENDPROC GetMCEntry PROC EXPORT ; ;------------------------------------------------------------------------------------ ; ; GetMCEntry ; ;------------------------------------------------------------------------------------ ; FUNCTION GetMCEntry(ID, Item : integer) : CMenuStruct -- ; Find a color table entry for the given ID/Item combination. Return an index into ; the color table, or a zero if the entry wasnÕt found. ; move.l d2, -(sp) ; save work register move.l MenuCInfo, a0 ; get color table handle move.l (a0), a0 ; dereference move 8(sp), d0 ; get Item move 10(sp), d1 ; get ID clr d2 ; start search at beginning of the table IMPORT FindCEntry bsr FindCEntry ; do the search beq.s @NotFound ; oops couldnÕt find it lea (a0,d2), a0 ; get the table entry address in a0 move.l a0, 12(sp) ; return it as the result bra.s @GetDone ; and return @NotFound move.l #0, 12(sp) ; return zero as result @GetDone move.l (sp)+, d2 ; restore work register move.l (sp)+, a0 ; get return address addq #4, sp ; strip the parameters jmp (a0) ; and return ENDPROC DelMCEntries PROC EXPORT ;------------------------------------------------------------------------------------- ; ; DelMCEntries ; ;------------------------------------------------------------------------------------- ; ; PROCEDURE DelMCEntries (ID, Item : integer) ; ; Given an ID and Item number, this routine will find the appropriate ; entry in the menu color table and delete it. If the item number is ; equal to #mbAllItems (-98), then all items for the given ID will be deleted. ; movem.l d2-d4, -(SP) ; save work registers move 16(SP), d3 ; get Item number move 18(SP), d4 ; get menuID clr.l d2 ; start search at beginning of table @DeleteLoop move d3, d0 ; set up for FindCEntry move d4, d1 ; Get MenuCInfo each time since munger chgs it move.l MenuCInfo, a0 ; get handle to color table move.l (a0), a0 ; dereference IMPORT FindCEntry bsr FindCEntry; find the entry beq.s @DoneDelete ; z-flag set ==> couldnÕt find it ; we have a match on both ID and Item so delete it using Munger @DeleteIt subq #4, SP ; space for result move.l MenuCInfo, -(SP) ; move the color table handle onto the stack move.l d2, -(SP) ; d2 is offset into color table pea (a0,d2) ; push ptr to target string move.l #mctEntrySize, -(SP) ; len1 = 6 bytes moveq #4, d0 move.l d0, -(SP) ; make replacement string non-NIL so deletes ; properly, point at an even byte in lo-mem clr.l -(SP) ; and its length is zero ==> delete _Munger addq #4, SP ; ignore the result ; DonÕt need to bump D2 because munger moved data down to where D2 points ; addi #mctEntrySize, d2 ; start looking at next table entry cmpi #mctAllItems, d3 ; is the Item = "all items" flag? beq.s @DeleteLoop ; yes, so loop @DoneDelete IMPORT MenuCTblSanityChk bsr MenuCTblSanityChk ; check the table for consistency movem.l (SP)+, d2-d4 ; restore work registers move.l (SP)+, a0 ; get return address addq #4, SP ; strip parameters jmp (a0) ENDPROC FindCEntry PROC ENTRY ;----------------------------------------------- ; Utility -- FindCEntry ;----------------------------------------------- ; This utility will find the color table entry for the ; given ID and Item and table offset. ; ; Special case seaching: if ID = mctAllIds (=-97) ===> return any ID with correct Item ; if Item = mctAllItems (=-98) ===> return any Item with correct ID ; ; 1) If it finds the entry the z-flag will not be set and ; it returns an index into the table in d2. ; 2) If it doesnÕt find the entry the z-flag will be set, ; and d2 will be the offset to the end of the table. ; ; On Entry: A0 ptr pointer to color table ; D0 Item item number looking for, if = mctAllItems (-98) then any item number ; D1 ID ID of menu looking for, if = mctAllIds (-97) then any ID number ; D2 offset offset into the table where we should start looking ; ; On Exit: D2 offset offset into the color table where the given ID/Item was found ; z-flag set if not found ; ; Called From: cmpi #mctLastIDIndic, mctID(a0,d2) ; are we at the last entry? beq.s @DoneFind ; yes, so branch cmpi #mctAllIds, d1 ; are we finding all IDs for the given Item? beq.s @CheckItem ; yes, so go and check Item for this entry cmp mctID(a0,d2), d1 ; do we have a match with the given ID? bne.s @CheckNextID ; no, so branch and try some more ; we have a match on the ID, so check if the Item matches @CheckItem cmpi #mctAllItems, d0 ; are we finding all items for the given ID? beq.s @DoneFind ; yes, so just grab this entry cmp mctItem(a0,d2), d0 ; do we have a match with the Item? beq.s @DoneFind ; yes, so branch and try some more ; didnÕt find it so try the next item @CheckNextID addi #mctEntrySize, d2 ; offset to next color table entry bra FindCEntry ; and loop @DoneFind cmpi #mctLastIDIndic, mctID(a0, d2) ; set z-flag if didnÕt find the entry rts ; (check if at last entry flag) ENDPROC SetMCEntries PROC EXPORT ; ;------------------------------------------------------------------------------------ ; ; SetMCEntries ; ;------------------------------------------------------------------------------------ ; PROCEDURE SetMCEntries(numEntries: integer; colorEntries: CMenuStruct) -- ; Enter all of the given color entries in the menu color table. If an entry ; exists it will be replaced, if itÕs new it will be added. ; movem.l d2-d3, -(sp) ; save work register move 16(sp), d3 ; get numEntries subq #1, d3 ; sub 1 to get right offset to end of table mulu #mctEntrySize, d3 ; start at last entry ; reuse the following code to reset registers that may have been trashed by Munger ; itÕs just as easy to reset these each time thru, shouldnÕt be a speed hit @FindItLoop move.l 12(sp), a1 ; get ptr to colorEntries move.l MenuCInfo, a0 ; get handle to color table move.l (a0), a0 ; dereference ; first see if the entry exists in the table already move mctID(a1,d3), d1 ; set up d0, d1 for FindCEntry call move mctItem(a1,d3), d0 clr.l d2 ; d2 = 0 ===> start at top of table IMPORT FindCEntry bsr FindCEntry beq.s @InsertEntry ; couldnÕt find it so insert it ; found it in the table, so change the entry in place (table offset was returned in d2) ; store RGB1, 2, 3 and 4 add.l d3, a1 add.l d2, a0 exg a0, a1 moveq #mctEntrySize, d0 _BlockMove ;+++ move.l mctRGB1(a1,d3), mctRGB1(a0,d2) ; store RGB1 ;+++ move mctRGB1+4(a1,d3), mctRGB1+4(a0,d2) ;+++ move.l mctRGB2(a1,d3), mctRGB2(a0,d2) ; store RGB2 ;+++ move mctRGB2+4(a1,d3), mctRGB2+4(a0,d2) ;+++ move.l mctRGB3(a1,d3), mctRGB3(a0,d2) ; store RGB3 ;+++ move mctRGB3+4(a1,d3), mctRGB3+4(a0,d2) ;+++ move.l mctRGB4(a1,d3), mctRGB4(a0,d2) ; store background color, donÕt worry ;+++ move mctRGB4+4(a1,d3), mctRGB4+4(a0,d2) ; if this is wrong here, since we ; will make a sanity check later bra.s @DoNextEntry ; loop to the next entry ; didnÕt find entry so insert it at the end of the table, this is good because this forces the ; first entry to always be the menubar entry (if there is one) and since that is the most ; frequently accessed entry it is best to have it in the front. @InsertEntry subq #4, sp ; save space for result move.l MenuCInfo, -(sp) ; move the color table handle onto the stack move.l d2, -(sp) ; d2 is offset to the end of the color table clr.l -(sp) ; no target string clr.l -(sp) ; len1 = 0 ===> want to insert pea (a1,d3) ; push ptr to insertion string move.l #mctEntrySize, -(sp) ; and itÕs length _Munger addq #4, sp ; ignore the result @DoNextEntry subi #mctEntrySize, d3 ; go to next entry bge.s @FindItLoop ; if > or = 0 then continue @SetMenuColorDone IMPORT MenuCTblSanityChk bsr MenuCTblSanityChk ; look thru color table and clean it all up movem.l (sp)+, d2-d3 ; restore work register move.l (sp)+, a0 ; get return address addq #6, sp ; strip parameters jmp (a0) ; and return ENDPROC ClearSanityChks PROC ENTRY ;----------------------------------------------- ; Utility within a Utility -- ClearSanityChks ;----------------------------------------------- ; Cruise thru the color table, and clear the mctSanityChk ; field for every entry. Later we will set this field as ; we update entries during the sanity chk. Ones that ; werenÕt checked were missed, and will be handled in a ; second pass where default colors will be entered. move.l MenuCInfo, a0 ; get color table handle move.l (a0), a0 ; dereference clr d2 ; start at top of table @ClearLoop cmpi #mctLastIDIndic, mctID(a0,d2) ; are we at the last entry? beq.s @ClearDone ; yes, so weÕre done clr mctReserved(a0,d2) ; no, so clear the sanity check field <1.9> addi #mctEntrySize, d2 ; bump index to next entry bra.s @ClearLoop ; and loop @ClearDone rts ENDPROC MenuCTblSanityChk PROC ENTRY ;----------------------------------------------- ; Utility -- MenuCTblSanityChk ;----------------------------------------------- ; Check thru the whole color table and be sure all ; of the entries are consistent: ; 1) Item = 0 ===> title, so store menu bar color in mctRGB2 slot ; 2) Item != 0 ==> not title, so store menu background color in mctRGB4 slot ; CkMBColor EQU -6 ; RGB for menu bar CkBackColor EQU CkMBColor - 6 ; RGB for current IDÕs background color CkIDSave EQU CkBackColor - 2 ; save d2 as we loop thru Items for an ID CkFrame EQU CkIDSave ; size of stackframe link a6, #CkFrame ; set up a stack frame move.l d2, -(sp) ; save work register IMPORT ClearSanityChks bsr ClearSanityChks ; clear sanity checks for all table entries move.l MenuCInfo, a0 ; get table handle move.l (a0), a0 ; dereference ; 1) Find menubar color. Menubar has ID == 0, Item == 0, and menubar color is stored in ; mctRGB4 field. It should be copied to RGB2 field for every title entry (Item == 0) clr d0 ; Item 0 clr d1 ; ID 0 clr d2 ; start at beginning of table IMPORT FindCEntry bsr FindCEntry bne.s @GotMBColor ; found it so get color ; didnÕt find menu bar entry, so use default menubar color -- white moveq #-1, d0 move.l d0, CkMBColor(a6) ; set RG move d0, CkMBColor+4(a6) ; set B bra.s @1 ; and branch ; get color we found @GotMBColor move.l mctRGB4(a0,d2), CkMBColor(a6) ; set R & G move mctRGB4+4(a0,d2), CkMBColor+4(a6) ; set B @1 addq.w #1, mctReserved(a0,d2) ; set sanity check field <1.9> ; 2) Find each title entry (Item = 0), set its menubar color, get its background color and ; save it in the stackframe, then find each of its items and set their background colors clr CkIDSave(a6) ; start at top of table @IDLoop clr d0 ; Item 0 move #mctAllIds, d1 ; any ID move CkIDSave(a6), d2 ; get saved d2 value bsr FindCEntry ; look for the next title entry in the table beq.s @SecondPass ; z-flag set means we hit the end of the table move d2, CkIDSave(a6) ; save d2 since weÕll want to start there next time addi #mctEntrySize, CkIDSave(a6) ; actually want to start at NEXT entry! addq #1, mctReserved(a0,d2) ; set sanity check field <1.9> tst mctID(a0,d2) ; did we get the menu bar entry? beq.s @IDLoop ; yes, skip it and continue move.l CkMBColor(a6), mctRGB2(a0,d2) ; set title menubar color R & G move CkMBColor+4(a6), mctRGB2+4(a0,d2) ; set title menubar color B move.l mctRGB4(a0,d2), CkBackColor(a6) ; get menu background color R & G move mctRGB4+4(a0,d2), CkBackColor+4(a6) ; get menu background color B move mctID(a0,d2), d1 ; put ID we found in d1 move #mctAllItems, d0 ; find any Item with that ID clr d2 ; start at beginning of the table @ItemLoop bsr FindCEntry ; look for an entry beq.s @IDLoop ; got the end of the table, so find the next ID addq.w #1, mctReserved(a0,d2) ; set sanity check field <1.9> tst mctItem(a0,d2) ; did we get the title entry? beq.s @NextItemSetUp ; yes, so skip this entry and continue move.l CkBackColor(a6), mctRGB4(a0,d2) ; set Item background R & G move CkBackColor+4(a6), mctRGB4+4(a0,d2) ; set Item background B @NextItemSetUp addi #mctEntrySize, d2 ; start next Item search at NEXT table entry bra.s @ItemLoop ; 3) ItÕs possible that there are Items in the table that have no title entry -- these ; items would have zero in the SanityCheck field. So for every entry with SanityCheck = 0 ; set the background color to the menu bar default, or white if there is no default. @SecondPass clr d0 ; Item 0 clr d1 ; ID 0 clr d2 ; start at beginning of table bsr FindCEntry bne.s @GotMBColor2 ; found it so get color ; didnÕt find menu bar entry, so use default background color -- white moveq #-1, d0 move.l d0, CkBackColor(a6) ; set RG move d0, CkBackColor+4(a6) ; set B bra.s @2 ; and branch ; save the color we found in the stackframe @GotMBColor2 move.l mctRGB2(a0,d2), CkBackColor(a6) ; set R & G move mctRGB2+4(a0,d2), CkBackColor+4(a6) ; set B @2 clr d2 ; start search at beginning of color table @SecondPassLoop bsr.s FindSanityChks ; get the next one that wasnÕt set beq.s @SanityDone ; z-flag set means end of table, so done ; found one, so set its background color move.l CkBackColor(a6), mctRGB4(a0,d2) ; set R & G move CkBackColor+4(a6), mctRGB4+4(a0,d2) ; set B addi #mctEntrySize, d2 ; skip to next table entry bra.s @SecondPassLoop ; and find the next one @SanityDone move.l (sp)+, d2 ; restore work register unlk a6 ; toss the stack frame rts FindSanityChks ;----------------------------------------------- ; Utility within a Utility -- FindSanityChks ;----------------------------------------------- ; Cruise thru the color table, and find the next ; entry whose SanityCheck field in zero. cmpi #mctLastIDIndic, mctID(a0,d2) ; are we at the last entry? beq.s @FindDone ; yes, so weÕre done tst mctReserved(a0,d2) ; is the sanity field set? <1.9> beq.s @FoundEntry ; nope, so branch addi #mctEntrySize, d2 ; yes, so bump index to next entry bra.s FindSanityChks ; and loop @FoundEntry moveq #1, d0 ; z-flag not set tells caller that we found an entry @FindDone rts ENDPROC PROC ;----------------------------------------------- ; MenuKey Stack Frame Definitions ;----------------------------------------------- ; CmdChar EQU 9 ; command char is in lo-byte of param [byte/word] MenuResult EQU 10 ; menu ID part of result mItemResult EQU 12 ; Item part of result searchMenu EQU -8 ; looking for the parent of... HorRMenus EQU searchMenu - 2 ; looking thru HMenus (=0), or Regular Menus (=1) KeyFrame EQU HorRMenus - 2 ; Utility UpChar -- Upshift the character in D0 ; Given a character in D0, it uses the UprString routine to upshift the char ; (stripping diacriticals) and returns it in D0 UpChar MOVE.B D0,-(SP) ; push character ; Use the following for SuperMario move.l sp,-(sp) ; push text ptr <19> move.w #1,-(sp) ; push length <19> move.w #smSystemScript,-(sp) ; use system script, ignore port <19> _SCUpperText ; (stack based!) <19> MOVE.B (SP)+,D0 ; return shifted character RTS EXPORT MENUKEY MENUKEY ;------------------------------------------------------------------------------------------------ ; ; MenuKey -- determine if a command key is valid and if so what menu and item it refers to ; ;------------------------------------------------------------------------------------------------ ; ; FUNCTION MenuKey(commandChr): LongInt -- menuKey is kind of a companion routine to ; MenuSelect; it is called when a command character is typed and scans the current ; menu data structure, returning a (whichMenu, whichItem) pair that corresponds to the ; selected command. If a command is not recognized, the result returned is zero ; ; Check thru the regular menus first, then the hierarchical menus. Use D6 as flag ; so we know whether checking regular or H Menus ; ; Hilite the "parent" menu when a hierarchical menu is chosen. ; Roll in PatchMDMenuKey import PushMenuState,PopMenuState ; resultsStackFrame result ds.l 1 ; the menukey result parametersStackFrame ch ds.w 1 ; the char to pass thru endStackFrame linkSave jsr PushMenuState ; Potentially save off the menu state subq #4,sp ; Make room for MenuKey result move.w ch(a6),-(sp) ; Push the character jsr OriginalMenuKey ; move.l (sp)+,result(a6) ; Save off the result jsr PopMenuState ; Restore the menu state if it was saved restoreUnlinkReturn OriginalMenuKey link a6, #KeyFrame ; set up stackframe MOVEM.L D3-D6/A3,-(SP) ;save work registers move.b CmdChar(a6), d0 ; get character to search for BSR.S UpChar ; upshift in D0 MOVE.B D0,D4 ; and save in D4 IMPORT GetA0List bsr GetA0List ; get menuList pointer into A0 move lastMenu(a0), d5 ; go to last menu clr d6 ; zero flag == checking regular menus ; here is the outer loop where each menu in the menuList is considered KEYBARLOOP BSR GETMENUPTR ;get menu pointer in A0 from index in D5 MOVE.L A0,A3 ;stash in A3 for safe keeping BTST #0,MENUENABLE+3(A3) ;is this menu enabled? BEQ.S NEXTBAR ;if not, skip it MOVEQ #1,D3 ;start with item number 1 ; ; here is the inner loop where each item is considered ; KEYITEMLOOP MOVE.L MENUENABLE(A3),D0 ;get enable flags BTST D3,D0 ;make sure this item is enabled BEQ.S KEYNEXTITEM ;if not, skip it EnabledKeyItemLoop ; <10> Loops to here when item in D3 > 31 MOVE.L A3,A0 ;get menuPtr in A0 MOVE D3,D0 ;get item number in D0 IMPORT GetItemRecord BSR GETITEMRECORD ;search for item BEQ.S NEXTBAR ;if not, this menu is exhausted MOVE.B ItemCmd(A1),D0 ;get the command char BEQ.S KEYNEXTITEM ; donÕt upshift if there is no cmd-key BSR.S UpChar ; upshift it in D0 ;NOTE: WeÕve reserved the values $1B thru $1F in cmdItem as having meanings other than ; than that of a command key. ; Value: $1B (HMenuCmd) - item has hierarchical menu ; (menuID of HMenu is in itemMark field) ; $1C (ScriptMenuCmd) - item has script defined ; (script number is in itemIcon field) ; $1D - $1F - undefined at this time ; cmpi.b #FirstAltMenuCmd, d0 ; item between $1B and $1F? blt.s @DoCompare ; no, so continue cmpi.b #LastAltMenuCmd, d0 ; / bhi.s @DoCompare ; no, so continue bra.s KeyNextItem ; if here then cmdItem is between ; $1B and $1F so skip comparison @DoCompare CMP.B D0,D4 ;do they match? BEQ.S GOTMKEY ;if they do, weÕve found it! KEYNEXTITEM ADDQ #1,D3 ;bump to next item CMPI.W #31,D3 ;<10> items > 31 are always enabled BHI.S EnabledKeyItemLoop ;<10> so skip moving the flags and the btst BRA.S KEYITEMLOOP ;loop till we find it or no more NEXTBAR subq #6, d5 ; bump to next item cmp d6, d5 ; have we reached the value in d6? bgt.s KeyBarLoop ; loop till we reach it tst d6 ; does d6 have a value? bne.s KeyNotFound ; yes, so have checked regular AND HMenus ; ; d6 was equal to zero, so now check thru the hierarchical menus ; IMPORT GetHA0List bsr GetHA0List ; get HMenuList ptr in A0 move lastHMenu(a0), d5 ; get #HMenus beq.s KeyNotFound ; none, so donÕt check Õem ; yes there are menus so check them backwards move.l MinusOne, d1 ; set up for GetHIndex call IMPORT GetHIndex bsr GetHIndex ; d0 now has ptr to HMenuList header info add d0, d5 ; d5 points at last HMenu move d0, d6 ; d6 points at HMenuList header bra.s KeyBarLoop ; and start checking ; ; no corresponding command key was found, so return zero as the result ; KEYNOTFOUND clr.l menuResult(a6) ; clear the function result -- menu and item MKEYDONE MOVEM.L (SP)+,D3-D6/A3 ; restore work registers unlk a6 ; dismantle the stack frame IMPORT TwoBytExit BRA TWOBYTEXIT ; standard exit saves code ; ; we got a good key so return the result (whichMenu, whichItem) ; GOTMKEY BSR GETMENUPTR ;get pointer to correct menuID move menuID(a0), menuResult(a6) ; store the menuID move d3, mItemResult(a6) ; and the Item move menuResult(a6), searchMenu(a6) ; init searchMenu(a6) tst d6 ; is d6 clear? beq.s @HiliteMBar ; yes, so was a regular menu clr HorRMenus(a6) ; init HorRMenus(a6) to HMenus moveq #8, d4 ; d4 is recursive test counter bsr.s FindParentMenu ; no, so find the HMenuÕs parent @HiliteMBar MOVE searchMenu(a6),-(SP) ;push menuID as parameter _HiliteMenu ;hilite it ; ; check to see if this one belongs to a desk ornament ; TST MBarEnable ;does desk ornament own menuBar? BMI.S @DeskMKey ;if so, handle it ;+++ move.l menuResult(a6), d0 ; if theMenu negative? ; CanÕt just use menuResult(a6) since could ; be a HMenu associated with the desk acc tst TheMenu ; Is it a system menu? BPL.S MKEYDONE ;if not, weÕre done ; ; the menu belonged to a desk ornament so tell the desk manager about it ; ; HMenus cause problems here. Since the menu ID (funcResult) is not = to the DAÕs ; menu ID, SystemMenu will never find the DA in the DA list. To force it to pass ; the HMenu ID we can set MBarEnable temporarily. ; ; Need to allow a DA that owns the menu bar to reset MBarEnable in the middle of _SystemMenu ; Had to move around some parts of this routine. Only set/clear MBarEnable when MBar not ; already owned by DA. ; @DeskMKey tst.w MBarEnable ; who owns menu bar? bmi.s @1 ; desk acc ==> weÕre cool move TheMenu, MBarEnable ; set MBarEnable with DAÕs ID move.l menuResult(a6),-(sp) ; push the result _SystemMenu ; invoke desk manager clr.l menuResult(a6) ; pretend we didnÕt get anything ; NOTE: clears funcResult AND itemResult !!! clr.w MBarEnable ; clear MBarEnable bra.s MKeyDone @1 move.l menuResult(a6),-(sp) ; push the result _SystemMenu ; invoke desk manager clr.l menuResult(a6) ; pretend we didnÕt get anything ; NOTE: clears funcResult AND itemResult !!! BRA.S MKEYDONE ;all done FindParentMenu ;----------------------------------------------- ; Utility -- FindParentMenu ;----------------------------------------------- ; ; We have a hierarchical menu, so we need to find its regular menu "parent" and hilite it. ; It could be several levels of hierarchy deep, so look thru the HMenus until ; we donÕt find it, then look thru the regular menus to get the parent. This code ; doesnÕt allow recursively defined menus, it stops looking after 8 menus (I didnÕt want ; to test the boundary condition of whether it is 5 or 6 or 7 that should stop at with ; five levels of hierarchy, so just made it 8 to be safe). ; ; Allowed a hierarchical menu to not have a parent in the menubar. Did this so ; that could have menu keys on popup menus. ; subq #1, d4 ; reduce recursive count beq.s @NoParent ; got to zero, so must be recursive IMPORT GetHA0List bsr GetHA0List ; get HMenuList ptr in A0 move lastHMenu(a0), d5 ; get #HMenus ; we know there are HMenus so check them backwards move.l MinusOne, d1 ; set up for GetHIndex IMPORT GetHIndex bsr GetHIndex ; d0 now has index to HMenuList header info add d0, d5 ; d5 has index to last HMenu move d0, d6 ; d6 has index to HMenuList header @MenuLoop bsr GetMenuPtr ; get menu ptr in A0 from ID in D5 move.l a0, a3 ; stash in A3 for safe keeping moveq #1, d3 ; start with item number 1 ; ; inner loop where each item is considered ; @ItemLoop move.l a3, a0 ; set up for GetItemRecord, put menuPtr in a0 move.l d3, d0 ; and put item number in d0 IMPORT GetItemRecord bsr GetItemRecord ; search for item beq.s @NextMenu ; if not, this menu is exhausted cmpi.b #HMenuCmd, itemCmd(a1) ; does this menu have a HMenu? bne.s @NextItem ; no, so keep looking moveq #0, d1 ; clear d1 move.b itemMark(a1), d1 ; get menuID of HMenu for this item cmp searchMenu(a6), d1 ; is this the menu we are looking for? bne.s @NextItem ; no, so keep looking move menuID(a3), searchMenu(a6) ; found a parent so save it tst HorRMenus(a6) ; still searching HMenus? beq.s FindParentMenu ; yes, so try again with the parent menuID bra.s @FindParentEnd ; no, so found oldest ancestor amongst regular menus @NextItem addq #1, d3 ; go to next item bra.s @ItemLoop @NextMenu subq #6, d5 ; bump to next menu cmp d6, d5 ; at end of list? bgt.s @MenuLoop ; no, so try the next menu ; ; if weÕre here then have exhausted HMenuList without finding a parent, so we now search ; the regular menu list to find the oldest ancestor of the HMenu being returned as the result. ; tst HorRMenus(a6) ; HorRMenus = 0 means just finished checking ; hierarchical menus, try regular menus beq.s @WereOK bra.s @FindParentEnd ; HorRMenus = 1 means finished checking ; regular menus, stop trying, and return @NoParent move #dsHMenuFindErr, d0 ; error code for recursive menus _SysError @WereOK addq #1, HorRMenus(a6) ; flag that searching regular menus IMPORT GetA0List bsr GetA0List ; get menuList ptr into A0 move lastMEnu(a0), d5 ; go to last regular menu clr d6 ; stop searching when index == 0 bra.s @MenuLoop ; go find it @FindParentEnd rts ENDPROC GETITEM PROC EXPORT ; ; PROCEDURE GetItem(menuHandle,itemNumber,VAR string); -- get the text of a menu item ; MOVE.L 10(SP),A0 ;get menuInfo handle MOVE.L (A0),A0 ;handle to pointer MOVE.W 8(SP),D0 ;get item number IMPORT GetItemRecord BSR GETITEMRECORD ;look it up ; MOVE.L 4(SP),A1 ;get result stringPtr,(zflag preserved) BEQ.S NOITEM1 ;if not, return empty string ; ; use blockMove to copy the string ; MOVEQ #0,D0 ;clear out D0 MOVE.B (A0),D0 ;get length of string ADDQ #1,D0 ;move length byte, too _BLOCKMOVE ;let memory manager move it fast DONEGI IMPORT TenBytExit BRA TENBYTEXIT ;standard exit saves code ; ; item not found, so return the null string ; NOITEM1 CLR.B (A1) ;set result string length to zero BRA.S DONEGI ;standard exit saves code ENDPROC NEWMENU PROC EXPORT ; ; FUNCTION NewMenu(menuID,titleString):menuHandle -- allocate a new menu block with ; the specified menuID and title. ; MOVEQ #0,D1 ;clear out the high part MOVEQ #MenuBlkSize+2,D0 ;get size of menuInfo block MOVE.L 4(SP),A0 ;point to the title string MOVE.B (A0),D1 ;get its length ADD.W D1,D0 ;compute real length _NEWHANDLE ;allocate it MOVE.L A0,10(SP) ;return menuHandle as result MOVE.L (A0),A1 ;get menu pointer MOVE.W D1,-(SP) ;save title size for later ; ; initialize the fields of the menu definition record ; MOVE.W 10(SP),(A1)+ ;init menuID CLR.L (A1)+ ;zero width and heigth initially ; initialize the menu defProc handle MOVEQ #0,D0 ; standard rom based MDEF is #0 SUBQ #4,SP ;make room for function result MOVE.L #'MDEF',-(SP) ;push MDEF resource type move.W d0, -(SP) ;push the rsrcID MOVE.W #MapTRUE,ROMMapInsert ;get MDEF 0 from the ROM Map <9 July 85> _GetResource ;get it MOVE.L (SP)+,A0 ;get mDef handle in A0 ; since GetResource can allocate memory, better rebuild the ptr from its handle MOVE.L 12(SP),A1 ;get menuHandle MOVE.L (A1),A1 ;get menuPtr ADDQ #MenuDefHandle,A1 ;bump to defHandle MOVE.L A0,(A1)+ ;install menuProc MOVE.L MinusOne,(A1)+ ;everythingÕs enabled to start ; ; move in the title string MOVE.W (SP)+,D1 ;get length of string MOVE.L 4(SP),A0 ;get string ptr @1 MOVE.B (A0)+,(A1)+ ;move in the string DBRA D1,@1 ;loop till done ; ; add the string of length zero on the end ; CLR.B (A1)+ ;string of length zero IMPORT SixBytExit BRA SIXBYTEXIT ;all done -- standard exit saves code ENDPROC ; ; AppendMenu Stack Frame Definition ; ITEMPROPERTIES EQU -280 ;4 attribute bytes of item ITEMSTATE EQU ITEMPROPERTIES+4 ;one byte parse state field ITEMFLAGS EQU ITEMSTATE+1 ;one byte enable flag field ITEMCOUNT EQU ITEMFLAGS+1 ;integer -- number of chars in buffer ITEMBUFFER EQU ITEMCOUNT+2 ;256 byte buffer for items ;+4 for copying properties ItemFontNum EQU ItemProperties - 2 ; use for GetFNum call FontFondFlag EQU ItemFontNum - 2 ; 0 = not font/fond, 1 = font/fond ItemLinkSize EQU FontFondFlag ; APPENDMENU PROC EXPORT ; ; PROCEDURE AppendMenu(menuHandle,itemString) -- add the list of items represented by ; the item string to the menu. The itemString may contain one or more items, seperated ; by carriage returns or semicolon characters. The item strings are also scanned for ; special meta-characters that change their initial properties. MOVE.L (SP)+,A0 ; add an "afterItem" param so MOVE.W #999,-(SP) ; it looks like an InsMenuItem call MOVE.L A0,-(SP) ; and fall into InsMenuItem EXPORT INSMENUITEM INSMENUITEM ; ; PROCEDURE InsMenuItems(MenuHandle: Handle; itemstring: str255; itemNum: INTEGER) ; -- insert the items in the itemstring after the specified item (to insert at ; beginning, pass item of 0). ItemString is parsed just like the itemstring in ; AppendMenu. Multiple items are inserted in the reverse of their order in the ; string. IMPORT TenBytExit TST.L 6(SP) ; Is the StringPtr NIL? <8> BEQ.S @PixelPaintError ; EQ means it is - BAIL <8> MOVE.L 10(SP),D0 ; Is the menuHandle NIL? <8> BEQ.S @PixelPaintError ; EQ means it is, bail <8> BTST #0,D0 ; Is the handle odd? <8> BNE.S @PixelPaintError ; NE means it is odd, bail <8> LINK A6,#ItemLinkSize ; allocate local space MOVEM.L D3-D7/A2-A4,-(SP) ; save some work registers MOVE.L 10(A6),A4 ; get itemString ptr in A4 MOVE.L 14(A6),A3 ; get menuHandle in A3 MOVE.W 8(A6),D6 ; get insert point in D6 ADDQ #1,D6 ; make it a true index IMPORT AddString BSR AddString ; make menu items out of the string MOVEM.L (SP)+,D3-D7/A2-A4 ; restore the registers UNLK A6 ; unbuild the stack frame @PixelPaintError ; <6> BRA TenBytExit ; standard exit save code ENDPROC AddString PROC ENTRY ; AddString parses the specified string, placing it into the ITEMBUFFER, and setting up ; the other item properties. When it encounters the end of an item, it transfers ; it from the buffer into the menu. ; On Entry: A3 MenuHandle ; A4 ItemString pointer ; D6 Item to insert before ; CLR D3 ; ; MOVE.B (A4)+,D3 ;get length of itemString IMPORT InitItem BSR INITITEM ; initialize local buffer for new item ; SUBQ #1,D3 ; bias for DBRA loop MOVEQ.L #0, D3 ; Initialize counter BRA.S EndApLoop ; Go to end of loop ; ; process each character in the itemString, one character at a time ; APLOOP SUBQ.L #2, SP ; Make room for result MOVE.L A4, -(SP) ; textBuf pointer MOVE.W D3, -(SP) ; textOffset _CharByte ; MOVE.W (SP)+, D2 ; Stuff result into D2 MOVE.B (A4, D3), D0 ;get next character IMPORT AppendChar BSR APPENDCHAR ;process it ; DBRA D3,APLOOP ;process each character EndApLoop ; ADDQ.L #1, D3 ; Increment character index CMP.B (A4), D3 ; Done yet? BLS.S APLOOP ; Nope, continue IMPORT CloseItem BSR CLOSEITEM ;close out any item that may be open MOVE.L A3,-(SP) ; push menu handle IMPORT DirtyMenuSize BSR DirtyMenuSize ; invalidate size RTS ENDPROC INITITEM PROC ENTRY ; ; InitItem initializes the item buffer ; LEA ITEMPROPERTIES(A6),A0 ;get address of item properties CLR.L (A0)+ ;clear property parameters CLR.L (A0) ;clear out state/flags/count RTS ENDPROC APPENDCHAR PROC ENTRY ; AppendChar does all the real work. It processes the character in D0 by checking out ; what state its in. If in a command state, it uses the character to update a ; property byte. In normal state, characters go into a buffer that is added to the ; menu when a carriage return or semicolon is scanned ; MOVEQ #0,D1 MOVE.B ITEMSTATE(A6),D1 ;get current state BEQ.S NORMSTATE ;if normal state, go handle it ; CMP.B #ITEMICON+1,D1 ;is it an icon item? BNE.S @1 ;if not,skip SUB #$30,D0 ;adjust ASCII ; @1 CMP.B #ITEMSTYLE+1,D1 ;is it a style? BNE.S UPDATEPROP ;handle style characters special ; ; handle style properties special by scanning table and oring bits ; MOVEQ #4,D2 ;start at last one @2 CMP.B STYLECHRTAB(D2),D0 ;is it in the table? BEQ.S ADDTOSTYLE ;if so, modify D0 DBRA D2,@2 ;bump to next one ; ; if its not in table, just ignore it ; RTS ; ; Meta character definition table -- this table defines which meta-character ; perform what functions; the order is icon,command,mark,style,delimiter,delimiter, ; disable. ; MCHARTABLE DC.B '^' ;arrow is the icon character DC.B '/' ;slash is command character DC.B '!' ;exclamation point is mark character DC.B '<' ;less-than is the style character DC.B $0D ;carriage return is one delimiter DC.B ';' ;semi-colon is the other DC.B '(' ;leftParen is disable character dc.b HMenuCmd ;hierarchical menu character ($1B) ;****** BE SURE THE ABOVE TABLE IS OF EVEN LENGTH IF YOU ADD NEW SYMBOLS ********* ; ; style character table ; STYLECHRTAB DC.B 'BIUOS' ;bold,italic,underline,outline,shadow ALIGN ADDTOSTYLE LEA ITEMPROPERTIES-1(A6),A0 ;get property table address MOVE.B 0(A0,D1),D0 ;get current property BSET D2,D0 ;set appropriate property UPDATEPROP LEA ITEMPROPERTIES-1(A6),A0 ;get address of item property table cmp #8, d1 ; do we have a hierarchical menu here? bne.s @NotHierMenu ; no, so branch move.w #2, d1 ; for a HMenu move.b #HMenuCmd, 0(a0, d1) ; ==> itemCmd (byte 2) = $1B(HMenuCmd) move.w #3, d1 ; ==> itemMark(byte 3) = char in d0 @NotHierMenu MOVE.B D0,0(A0,D1) ;update the property CLR.B ITEMSTATE(A6) ;return state to normal RTS ; ; Handle the normal state by scanning for any of the 8 (not 7) special characters ; NORMSTATE TST.W D2 ; See if it is a single byte character BNE.S MultiChar ; Skip if not LEA MCHARTABLE,A0 ;get address of character table MOVEQ #7,D1 ;scan it backwards, 8 characters now NSLOOP CMP.B 0(A0,D1),D0 ;is it one of the special ones? BNE.S @loop IMPORT SpecialChar JMP SPECIALCHAR ;if so, go handle it @loop DBRA D1,NSLOOP ; ; it wasnÕt in the exception table so it must be a normal character. Just append it ; to the item buffer. ; MultiChar ; MOVE ITEMCOUNT(A6),D1 ;get total number of characters LEA ITEMBUFFER(A6),A0 ;get address of buffer MOVE.B D0,0(A0,D1) ;stick character in buffer ADDQ #1,ITEMCOUNT(A6) ;bump buffer index RTS ENDPROC ; ; it was one of the special characters -- first see if its a property command -- ^ / ! < $1B ; SPECIALCHAR PROC ENTRY ; Get around bug in assembler with short branches. CMP #3,D1 ; which char was it? BLE.S @PropertyChar ; if 0 through 3, is a property cmd cmp #7, d1 ; is it the hierarchical menu character? bne.s CheckTerm ; not a hierarchical item ; ; it was a property meta-character so update the state accordingly ; @PropertyChar ADDQ #1,D1 ;bump state MOVE.B D1,ITEMSTATE(A6) ;update state RTS ; ; check for termination characters like carriage return or semicolon ; CHECKTERM SUBQ #6,D1 ;was it enable character? BNE.S CLOSEITEM ;it must have been a termination character ; ; disable the item ; ST ITEMFLAGS(A6) ;flag the item to be disabled RTS ENTRY CloseItem CLOSEITEM ; ; CloseItem is called to add the item in the buffer (and its associated properties) to ; the actual menu data structure. After this is done, re-initialize for the next item ; On entry, the item insertion index is in D6 ; MOVE ITEMCOUNT(A6),D0 ;get the # of characters in buffer BEQ.S CLOSEDONE ;if none, weÕre done IMPORT InsertTheItem BSR InsertTheItem ; put the new item into the menu IMPORT InitItem BSR INITITEM ; prepare for next item CLOSEDONE RTS ENDPROC GetGoodIndex PROC ENTRY ; --------------- ; Utility GetGoodIndex -- takes an index into the menu list in D6 and a menu handle in A3. ; Returns a valid insertion index in D5. Trashes D0-D2, A0-A1 ; MOVE.W D6,D5 ; get proposed index SUBQ #2,SP ; count menu items MOVE.L A3,-(SP) ; push menu handle _CountMItems MOVE.W (SP)+,D0 ; get count ADDQ #1,D0 ; make it an insertion index CMP.W D0,D5 ; if D5 is bigger BLE.S @0 ; then use count+1 MOVE.W D0,D5 ; preserve in D5 @0 Rts ENDPROC InsertTheItem PROC ENTRY ; ; InsertTheItem -- inserts the item in the item buffer before the item designated by D6. ; If D6 is bigger than the last item, append the item to the end of the list. Keeps true ; insertion item # in D5 IMPORT GetGoodIndex BSR GetGoodIndex ; index in D6 -> good index in D5 MOVE.W D5,D0 ; get insertion index MOVE.L (A3),A0 ; get menu pointer IMPORT GetItemRecord BSR GetItemRecord ; point to itemÕs string BEQ.S @1 ; => out of range. End pointer in D1 MOVE.L A0,D1 ; else get pointer in D1 ; only need to insert enable bit if insert within range. (bits at end are all alike) MOVE.L (A3),A0 ; get menu list pointer IMPORT InsertEnableBit BSR InsertEnableBit ; insert bit in posÕn in D5 @1 LEA ITEMBUFFER(A6),A0 ; point to string data MOVE.L A0,A2 ; save insertion string in A2 MOVE.W ITEMCOUNT(A6),D2 ; get the string length ADDA.W D2,A0 ; point past end of string LEA ITEMPROPERTIES(A6),A1 ; get address of properties MOVEQ #3,D0 ; and move in 4 property bytes @2 MOVE.B (A1)+,(A0)+ ; move a byte DBRA D0,@2 ; loop till done SUBQ #1,A2 ; point to insertion count byte ADD.W #5,D2 ; get length of data into D2 EXT.L D2 ; (itemCount + 1 length + 4 property) MOVE.L D1,A1 ; get address of data SUB.L (A3),A1 ; get offset into menu list SUBQ #4,SP ; weÕre here to get results MOVE.L A3,-(SP) ; push handle to menu list MOVE.L A1,-(SP) ; push offset into menu list CLR.L -(SP) ; no source string CLR.L -(SP) MOVE.L A2,-(SP) ; just an insertion string MOVE.L D2,-(SP) ; and its length _Munger ADDQ #4,SP ; ignore results TST.B ITEMFLAGS(A6) ; was it disabled? BEQ.S InsertDone ; => no, donÕt need to disable MOVE.L A3,-(SP) ; push menu handle MOVE.W D5,-(SP) ; and item number BSR DisableItem ; and disable it InsertDone RTS ENDPROC InsertEnableBit PROC ENTRY ; InsertEnableBit -- insert a bit into the MenuEnable byte, turned on. ; Index is in D5, menulist pointer is in A0. ; Trashes D0,D2. ; ;DONE: donÕt do this if D5 > 31 otherwise we wind up screwing up the rotation. ; Recall that all items > 31 are always enabled cmp #31, d5 ; is the item > 31 ? bhi.s @DoneInsert ; yes, so leave without updating flags MOVE.L MenuEnable(A0),D2 ; get current enable flags ROR.L D5,D2 ; rotate n bits MOVE.W D5,D0 ; get 32-n with extend SUB.W #32,D0 ; by negating n-32 NEG.W D0 ; extend is inserted 1 bit ROXR.L D0,D2 ; rotate in others MOVE.L D2,MenuEnable(A0) ; replace the flags @DoneInsert RTS ENDPROC GETMHANDLE PROC EXPORT ; FUNCTION GetMHandle(menuID): menuHandle -- convenience procedure which returns ; a menuHandle given a menuID. If the menuID cannot be found in the current menuList, ; NIL is returned ; ; Look in HMenu list first, then in regular portion of MenuList ; CLR.L 6(SP) ;set result to NIL moveq #0, d1 ;clear hi-word for GetHIndex call MOVE 4(SP),D1 ;get menuID IMPORT GetHIndex bsr GetHIndex ; look in H Menus for the menuID bne.s @GotRMenu ; branch if menuID in HMenus IMPORT GetIndex BSR GETINDEX ; get menuIndex beq.s @1 ; branch if couldnÕt find it at all @GotRMenu MOVE D5,-(SP) ;preserve D5 MOVE D0,D5 ;get menuIndex in D5 BSR GETMENUPTR ;get handle to menu in A1 MOVE (SP)+,D5 ;restore D5 MOVE.L A1,6(SP) ;set function result IMPORT TwoBytExit @1 BRA TWOBYTEXIT ;standard exit saves code ENDPROC DELMENUITEM PROC EXPORT ; ; PROCEDURE DelMenuItem(MenuHandle:Handle; itemNum: INTEGER) -- delete the specified ; item from the specified menu. Shoves an extra return address on the stack to ; make stack parallel with SetItem, below. MOVE.L (SP),-(SP) ; old RTS -> phony newItem MOVEM.L D3-D4/A2-A4,-(SP) ; save work registers ; begin by removing itemÕs entry in menu color table MOVE.L 30(SP),A3 ; get menu handle MOVE.L (A3),A0 ; get menu ptr move menuID(a0), -(sp) ; push menuID on stack MOVE.W 30(SP),-(sp) ; push itemNum on stack _DelMCEntries ; and remove item's menu color entry ; set up for rest of DelMenuItem MOVE.L 30(SP),A3 ; get menu handle MOVE.L (A3),A0 ; get menu for GetItemRecord MOVE.W 28(SP),D0 ; get item for GetItemRecord ; need to delete the itemÕs enable bit from MenuEnable Cmpi.W #31, D0 ; item number > 31 ? Bhi.S @1 ; yes -> skip enable bits stuff MOVE.L MenuEnable(A0),D1 ; get enable bits for menu items MOVE.W D0,D2 ; get 32-n with extend set SUB.W #32,D2 ; by negating n-32 NEG.W D2 ROXL.L D2,D1 ; shift in new high bit (set) ROL.L D0,D1 ; leave deleted bit in extend MOVE.L D1,MenuEnable(A0) ; and save updated enable bits @1 IMPORT GetItemRecord BSR GetItemRecord ; look up the specified BNE.S @continue IMPORT SetIDone JMP SetIDone ; => item not found @continue MOVEQ #5,D4 ; 4 property bytes + 1 length byte MOVEQ #0,D2 ; length of replacement string MOVE.L D2,A2 ; and NIL replacement string IMPORT SICommon BRA SICommon ; go parasitize host... ENDPROC SETITEM PROC EXPORT ; PROCEDURE SetItem(menuHandle:Handle; itemNum: INTEGER; newItem: String) -- change ; the specified item to the new string, keeping the same attributes as the old one MOVEM.L D3-D4/A2-A4,-(SP) ;save work registers MOVE.L 30(SP),A3 ;get menu handle MOVE.W 28(SP),D3 ;get item number MOVE.L 24(SP),A2 ;get string pointer MOVE.W D3,D0 ;get item in D0 MOVE.L (A3),A0 ;get menu ptr in A0 IMPORT GetItemRecord BSR GETITEMRECORD ;find our entry BEQ.S SETIDONE ;if not, weÕre done MOVEQ #1,D4 ; get 1 for length byte MOVEQ #1,D2 ; get 1 for length byte ADD.B (A2),D2 ; add in length of new string ENTRY SICommon SICommon MOVE.L A0,A4 ; remember item ptr in A4 SUB.L (A3),A4 ; offset = item pointer - menu start ADD.B (A0),D4 ; Length = D4 + menuString length SUBQ #4,SP ; make room for result MOVE.L A3,-(SP) ; push menu handle MOVE.L A4,-(SP) ; offset to string to be replaced CLR.L -(SP) ; no search string MOVE.L D4,-(SP) ; old length MOVE.L A2,-(SP) ; ptr to new MOVE.L D2,-(SP) ; length of new _Munger ADDQ #4,SP ; ignore result MOVE.L A3,-(SP) ; push the menu handle IMPORT DirtyMenuSize BSR DirtyMenuSize ; invalidate size ; ; all done with SetItem ; ENTRY SetIDone SETIDONE MOVEM.L (SP)+,D3-D4/A2-A4 ;restore work registers IMPORT TenBytExit BRA TENBYTEXIT ;standard exit saves code ENDPROC SETMENUFLASH PROC EXPORT ; ; PROCEDURE SetMenuFlash(flashCount: INTEGER) -- set the system global "flashCount" to ; a new value, controlling the duration of the flash feedback given when a menu item ; is selected ; MOVE.W 4(SP),MENUFLASH ;update flashcount IMPORT TwoBytExit BRA TWOBYTEXIT ;standard exit saves code ENDPROC AddResMenu PROC EXPORT IMPORT InsrtResMenu ; ; PROCEDURE AddResMenu(theMenu: menuHandle; theType: RsrcType); ; ; AddResMenu appends all the names of a given resource type class ; to the menu passed as a parameter. It ignores names with a period or ; percent sign as their first character. It is simply a cover for InsrtResMenu, ; which it falls into. ; MOVE.L (SP)+,A0 ; get return address MOVE.W #999,-(SP) ; push large "afterItem" MOVE.L A0,-(SP) ; restore return address JMP InsrtResMenu ENDPROC CountMItems PROC EXPORT ; FUNCTION CountMItems(mHandle: MenuHandle): INTEGER ; ; CountMItems returns the number of items in a given menu ; ; TODO: Do not call GetItemRecord, since this just loops again! Stupid way to do it. ; MOVEQ #0,D2 ;start with item 0 CountMLoop ADDQ #1,D2 ;bump item number MOVE.L 4(SP),A0 ;get menu handle MOVE.L (A0),A0 ;handle -> pointer MOVE.W D2,D0 ;get item number in D0 IMPORT GetItemRecord BSR GetItemRecord ;look it up BNE.S CountMLoop ;if we got it, bump count and try again ; we couldnÕt get the item in D2, so D2 must have the number of items + 1 SUBQ #1,D2 ;get number of items MOVE.W D2,8(SP) ;return it as the result MOVE.L (SP)+,(SP) ;strip the parameter RTS ;return to caller ENDPROC PlotIcon PROC EXPORT ;----------------------------------------------------------------------------------------------- ; PROCEDURE PlotIcon(theRect: Rect; theIcon: IconHandle) ; ; Plots a given icon at a given place in your local coordinate system. ; theMode is the LisaGraf penMode for the transfer ; LEA ICONBITMAP,A1 ;get address of icon mgr bitMap MOVE.L 4(SP),D0 ;get the icon handle BEQ.S DONEIPLOT ;if NIL, dont plot MOVE.L D0,A0 ;get iconHandle in address reg MOVE.L (A0),(A1)+ ;icon mptr is the base address MOVE #4,(A1)+ ;set up rowBytes CLR.L (A1)+ ;set up topLeft MOVE.L #$00200020,(A1) ;set up botRight MOVE.L 8(SP),D1 ;get theRect LEA IconBitMap,A1 ;point A1 at bitmap again ; ; push parameters for copyBits call ; MOVE.L A1,-(SP) ;source bitMap is iconBitMap MOVE.L GrafGLOBALS(A5),A0 ;get lisaGraf global baseaddress MOVE.L THEPORT(A0),A0 ;get thePort PEA PORTBITS(A0) ;thatÕs the destination bitmap PEA BOUNDS(A1) ;boundsRect of bitmap is source MOVE.L D1,-(SP) ;theRect is the destination CLR.W -(SP) ;theMode is srcCopy (0) CLR.L -(SP) ;no mask region _CopyBits ;let Bill blit those bits DONEIPLOT IMPORT TwoParmExit BRA TWOPARMEXIT ;standard exit saves code ENDPROC