; ; File: StandardMDEF.a ; ; Contains: Standard text menu definition procedure. ; ; Originally written by Andy Hertzfeld in July 1982. ; ; Copyright: © 1982-1992 by Apple Computer, Inc. All rights reserved. ; ; This file is used in these builds: ROM, disk ; ; Change History (most recent first): ; ; 12/7/92 CSS Update from Reality: ; <64> 12/4/92 KSM Don't call DisposHandle if NIL upon exiting even though the call ; can handle it. It wastes time and inhibits debugging other ; things. ; 11/5/92 SWC Changed PackMacs.a->Packages.a. ; 10/16/92 RB Removed SOME of the NOT forROM conditionals, since some of that ; code did not make sense anymore for SuperMario ROMs. This fixed ; the disabled menu items not being drawn in gray color instead of ; gray pattern. ; <63> 8/22/91 KSM csd,#Bruges: fix font/face cleanup problem in script systems. ; <62> 3/26/91 KSM rlc,#85632: Reset the font back to the default after script ; changed it. ; <61> 3/22/91 KSM dty,#83819: Reroll change <55> per Gang Of 5. ; <60> 3/22/91 DTY bbm, #oops: Change <59> started plotting the label colours and ; other small icons in a 32x32 grid because a beq was entered as a ; bra. Change that branch to the way it should be. ; <59> 3/20/91 KSM dcc,#82082: Fix bug where cicn rect size is used to plot ; nomarksmallicons. ; <58> 3/15/91 DTY gbm, #83819: Unroll <55> because Go5 said donÕt fix. ; <57> 3/4/91 dba dty: kill SysVers conditionals ; <56> 2/27/91 KSM ngk,#ngk-b5-001: Fix #51 (BRC#80417) uncovered a fudge in the ; DoCalcItemMsg msg which is no longer correct (ADDQ #4,d7) and ; was removed. ; <55> 2/27/91 KSM rlc,#83819: Call RemoveBalloon before scrolling to avoid wrong ; balloon bits being restored. ; <54> 2/25/91 KSM dcc,#DCC003: DonÕt use ttDisabled mode to plot icons in B&W mode ; when the item is disabled. Painting gray over that icon might ; completely erase it. ; <53> 2/20/91 KSM stb,#1003794: Don't call ProcessMgr unless trap is implemented ; (i.e., at boot time). ; <52> 2/11/91 KSM NGK,#None: Fix non-7.0 build problem. ; <51> 2/10/91 KSM RLC,#79297: Speed up CalcMenuSize by calling GetItemRecord in a ; loop! This avoids calling ExpandItem each time. Each time ; through the drawing loop, TextFace and TextMode were being ; called. The strategy has been changed to now set up the ; environment outside the loop, then change it only when necessary ; and change it back before the next iteration. 22% speed up. ; RLC,#80417: A branch in calc size routine never added the ; padding to the item width for items w/ small icons or h-menus. ; RLC,#80417: Also (from same bug report) we find that the calc ; for h-menus of id=256 never got the space for the arrow added to ; them NGK,#82082: NEVER try to plot a CICN when itÕs a ; NoMarkSmallIcon ; <50> 1/14/91 KSM Clean up and speed up GetItemHeight (round 2). ; <49> 1/13/91 KSM Update register saving conventions for GetItemHeight (No ; longer saves D4 and D5). ; <48> 12/12/90 KSM Fix for disabled items: use new icon utility calls to plot ; all icons in "true gray" , and draw h-menu arrow in true gray. ; Also fix cicn centering bug when icon is smaller than text (Finder Label menu). ; Alex you saved TOO MANY registers in GetItemHeight, routines depend on D7 being set up! ; <47> 11/29/90 RLC Move the tip of the balloon 8 pixels inside the menu ; item's rect. (The help manager used to do this instead of having ; the MDEF do it. This meant that all custom MDEF's would have ; their tips be 8 pixels off horizontally). ; <46> 11/19/90 kaz GetItemHeight now looks at the text face to return the height ; (as outline & shadow are taller than plain). DrawMenu loop uses ; GetItemHeight instead of MFHeight. ; <45> 11/12/90 kaz Broke out GetItemWidth() as a utility from CalcMenu() Ñ ; CalcMenuItem() will now return the individual item size instead ; of menuWidth. ; <44> 11/9/90 RLC Remove check of menu title bit in MenuEnable flags when ; passing itemHelpString to the __HMShowMenuBalloon call. ; <43> 11/2/90 KSM TextMode 31 was left on after a drawItemMsg. ; <42> 10/29/90 kaz drawItemMsg now draws the background in color; Color calls no ; longer RTS for popup CDEF. ; <41> 10/16/90 RLC When calling HMShowMenuBalloon, don't pass itemHelpString in ; itemReserved parameter if entire menu is disabled (probably by ; modal dialog menu being up). Otherwise, the help manager puts up ; the Aux menu information when, in fact, the menu item and title ; should have gotten the 'modal dialog menu' help message. ; <40> 10/10/90 KSM Fix bug where we couldnÕt draw more than 256 items (real ; important). ; <39> 9/28/90 KSM Fix bug where no icon is drawn for items that have ; hierarchical menus (instead, we draw only a large icon). ; <38> 9/16/90 RLC (KSM also) Change call to HMShowMenuBalloon to pass the ; helpstring StringHandle (in itemReserved parameter longword) ; found in AppleMenu & System Menus after calling _GetAuxMenuItem. ; Make sure all fields of AuxMenuItem Record are clear b4 calling ; _GetAuxMenuItem. ; <37> 9/15/90 KSM Consolidate the blitting arrows code. Save 126 bytes. ; <36> 9/11/90 KSM Remove some unnecessary register saving in DoCalcItemMsg and ; DoDrawItemMsg. Update DoCalcItemMsg to call _CalcMenuSize and ; GetSizes to set up stack frame correctly. ; <35> 9/11/90 gbm make PixPats be allocated in the system heap, since they need to ; stay around in the color window manager port when apps go away ; <34> 9/7/90 KSM Add enabledState to stackframe to factor out multiple calls to ; EnableTest. Fix auxmenuitem stack frame to be in sych with ; MFPrivate.a. Intense speed up of GetItemRecord by caching some ; data in locals. ; <33> 8/24/90 BG Conditionalized System 7.0 feature so that it doesn't interfere ; with building ROMs. ; <32> 8/21/90 RLC Remove all of that extraneous LastStrAttrPtr junk and make the ; calls to mChooseMsg not always call HMRemoveBalloon() [FASTER!]. ; <31> 8/17/90 dvb More grayish problem ; <30> 8/17/90 dvb grayishTextCopy->grayishTextOr ; <29> 8/15/90 BG In DRAWITEXT, there was a check after the item had been drawn to ; see whether one is onColorMachine and to not gray the item out ; if -onColorMachine- is true. This is not correct and the check ; was removed. There was a comment indicating what the code was ; originally supposed to do that had been removed and that comment ; was restored as well. If there _is_ some problem with trying to ; gray out menu items on color machines, it SHOULDNT be fixed by ; just not graying out the item. Have a nice day. ; <28> 8/13/90 JSM Fix previous fix. ; <27> 8/10/90 PN Fix graying for non-color machines since drawstring on these ; machines does not recognize _PenPat(grayishtext). ; <26> 8/9/90 DC Fixed up color environment again to look even better (I hope) ; <25> 8/6/90 DC Fix up color environment around PlotIconSuite for menu ; colorizers (Kolor et al.) ; <24> 8/6/90 RLC Change _Button to _Stilldown to fix multiple calls to mChoose ; message redrawing balloon. ; <23> 8/2/90 kaz TruncateString() now saves D1 (sys just). Fixes a bug with ; DrawItem w/ sysJust == right. ; <22> 7/20/90 DVB Fix for b&w systems ; <21> 7/17/90 DVB Enable grayish menu items ; <20> 6/12/90 PKE NEEDED FOR SIXPACK: Fixed bug in default setting of itemScript. ; <19> 6/11/90 kaz Removed condensing for drawItemMsg per HI request. ; <18> 6/4/90 kaz Fixed a bug where DoCalcItemMsg tried to get the menuWidth off ; the menu handle rather than the menu ptr. ; <17> 5/31/90 DC Changed the name of selected transform constant from ; ttPrimitiveSelected to ttSelected (Sorry) ; <16> 5/30/90 DC Changed name of icon interface from IconUtils.a to Icons.a ; <15> 5/23/90 ngk Icon ID for StandardFile will now use an offset from -4000 ; rather than 256. ; <14> 5/22/90 DC Changed name of PlotBestIcon to PlotIconSuite ; <13> 4/25/90 DFH Fix "gray" icon plotting to use ttOffline rather than ; ttDisabled. Looks way better. ; <12> 4/23/90 RLC Remove help mgr macros and include the Balloons.a file instead. ; <11> 4/11/90 RLC Fix quik typo in ttSelected, (SP) ; <10> 4/11/90 KSM Update calls to _GetAuxMenuItem to include itemnum param and add ; support for color icons. ; <10> 4/11/90 KSM Update calls to _GetAuxMenuItem to include itemnum param and add ; support for color icons. ; <9> 3/19/90 EMT Removed unneccessary ROM85 test. ; <8> 3/14/90 JSM Fix bug calculating width for menu items with sub-menus, also ; was adding 1 pixel indent for NoMarkSmallIconCmd items width ; calculations to wrong register. ; <7> 3/8/90 HJR Remove extra IF hasPopupCDEF statement so that file will ; assemble. ; <6> 3/8/90 BBH fix check for mDrawItemMsg in truncatestring (screwed up the ; comparison). sorry ; <5> 3/8/90 BBH use TruncString instead of my braindead routine. Also, we check ; to see if the MDEF message is mDrawItemMsg (which is the only ; case we will want to truncate) to eliminate the truncation check ; for regular mDrawMsg's. ; <4> 3/5/90 BBH added popup cdef support to mdef ; <3> 1/31/90 JSM Add NoMarkSmallIconCmd itemCmd for Standard File. ; <2> 1/23/90 RLC Update BalloonHelp macros. ; <2.4> 11/17/89 dba got rid of checks for 64K ROMs; tightened up 7.0-specific parts ; <2.3> 9/26/89 CCH added conditionals around references to SysVers equate for ROM. ; <2.2> 9/25/89 DFH extending menu item information. Icon border is one pixel. ; Version 13. ; <2.1> 9/12/89 RLC fix Balloon Positioner for menus. ; <2.0> 8/30/89 KSM fix bug (BRC#44525) in PopUp calculation which allow pop-up to ; go off top of screen ; <1.9> 8/29/89 RLC changed calling convention to the HelpMgr & tweaked the ; HMShowMenuBalloon call ; <1.8> 8/22/89 SES removed references to nFiles. ; <1.7> 8/21/89 PKE NEEDED FOR 6.0.4: (really dba) Fix bug in bug fix. GrayRect ; takes its parameter in A0, so A0 must be set up with TempRect ; before calling GrayRect. I tried to fix the earlier bug by not ; relying on A0 -- big mistake. Instead, get TempRect into a0. ; <1.6> 8/15/89 dba NEEDED FOR 6.0.4: fix bug in GetItemHeight where it relies on ; GetIconSize not trashing A0 ; <1.5> 8/10/89 RLC Changed selector message to Help Mgr Pack to MOVEQ #select,D0 ; <1.4> 6/2/89 KSM Updated conditionals for ROM/SYS build AGAIN. ; <1.3> 6/2/89 KSM Updated conditionals for ROM/SYS build. ; <1.2> 6/1/89 KSM BALLOON HELP support added. ; <1.1> 11/11/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <¥1.3> 10/3/88 EMT Roll in latest bug fixes. ; 7/27/88 EMT Removed references to WMgrPort for ROM Fixed problems when ; teSysJust set for right-to-left drawing Treat dash as special ; only if no icon or cmd. Primarily for MultiFinder Handle color ; icons other than 32x32 And some miscellaneous code cleanup ; 4/22/88 EMT Fixed hierchical menus being forced below menu bar ; 3/8/88 MED Fixed StandardMDEF.a to use SetScriptFont uniformally instead of ; inaccurate calculation ; 2/12/88 DBG Fixed errant branch, which was reversed, causing crash on +/SE ; PMAB364> 1/23/88 EMT Fix Pop-up menus to come up on any screen ; 9/15/87 FJL PMAB276 Allow item = 0 to popupmenuselect ; 8/21/87 FJL PMAB239 Calculate menu width correctly when have shrunken or ; small icons ; 7/14/87 FJL PMAB205 Juggler support -- support shrunken and small icons ; 4/14/87 FJL PMAB177 Use CopyBits instead of CopyMask for drawing ; hierarchical and scrolling arrows. Do moveq #BitMapRec, d0 ; instead of move.w #BitMapRec, d0 before call to NewHandle. ; 3/30/87 FJL PMAB155 DonÕt reference MenuDisable in StandardMDEF.a on 64K ; ROMs. ; 3/17/87 FJL Do invert for MacPlus/MacSE rather than redraw (for MacDraw ; custom menu) when choosing item ; 3/9/87 FJL Add variable speed menu scrolling ; 3/6/87 FJL Clean up all OnNuMac conditionals for System Disk --> Universal ; defproc ; 2/20/87 FJL C844 New routine PopUpMenuSelect. ; 2/20/87 FJL C838 Sped up menu scrolling by an amazing amount. ; 2/10/87 FJL C792 Add scrolling indicator to top and bottom of scrollable ; menus. ; 12/8/86 FJL C408 Added color support ; 11/25/86 FJL C466 Fixed ENABLETEST (local label) so enables items > 31 unless ; whole menu disabled. ; 11/4/86 FJL CXXX General clean up of menu manager. When #ScriptMenuCmd ($1C) ; in itemCmd field item to be printed in script whose ID is in the ; itemIcon field -- also, command keys draw as cmdletter/cmdchar ; rather than normal cmdchar/cmdletter (for International). Also ; slow down scrolling. ; 10/30/86 FJL C222 Fixes for hierarchical menus ; 10/1/86 DAF Changed include headers ; 1/30/86 EHB Re-did scrolling so icons would work ; 1/7/86 EHB DonÕt leave extra space at bottom of screen (reversed 30 Jan) ; 1/7/86 EHB Fixed enable bug for items > 31 (see C466 below) ; 10/15/85 EHB Fixed bugs in display of menu icons ; 10/11/85 EHB Do test byte of low memory justification word, so intl. people ; can use the high byte for further discrimination (yuck). ; 9/30/85 EHB Made scrolling smoother. ; 9/27/85 EHB Added International menu display. Added emergency menu ; scrolling. ; 8/26/85 EHB ROM/Ram version (tests ROM85) ; 8/1/85 EHB adapted for variable height system fonts ; 7/29/85 EHB converted back to porkshop ; 4/10/85 EHB fixed CalcMenuSize for items with 0 length ; 2/15/85 SC fixed applemark/commandMark bug in command keys ; 2/14/85 JTC named rsrc. ; 1/11/85 JTC convert to MDS ; 2/13/84 AJH speeded up CalcMenuSize message (linear instead of N squared) ; 11/6/83 AJH back to old disabling; special-cased "-" item ; 10/30/83 AJH changed disabling ; 4/28/83 AJH added "calcMenuSize" message ; 3/17/83 AJH no more forcing bold ; 3/17/83 AJH Fixed 4 pixel choosing offset ; 1/28/83 AJH made "GrayRect" use FillRect and a hardwired gray ; 12/27/82 AJH Broke off into separate file for resources ; ; To Do: ; *** Fix all this pixel tweeking! It is unecessary if it was done correctly. ; ; ; PROCEDURE TextMenuProc( message :Integer, ; theMenu :menuHandle, ; VAR menuRect :Rect, ; hitPt :Point, ; VAR whichItem :Integer); ; ;Msg theMenu menuRect hitPt whichItem ;------ ----------- ----------- ------- ----------- ; 0 Draw handle entry: ptr to not used not used ; return: no chg ; 1 Choose handle entry: ptr to mouse pt entry: ptr to currently selected item ; return: no chg return: newly selected item ; 2 Calc handle not used not used not used ; 3 PopUp handle entry: none top/left entry: CrsrItem to be placed at HitPt ; return: menu rect return: TopMenuItem ;=============================================================================================== ; start addition ; 4 DrawItem handle entry: ptr to not used < BBH 12/4/89 >entry: theItem to draw ; return: no chg < BBH 12/4/89 >return: no chg ; NOTE that foreground/background colors are not set for this message ; (application should have set these up beforehand) ; ; 5 CalcItem handle entry: ptr to not used < BBH 12/4/89 >entry: theItem to calc ; return: topLeft no change return: no change ; botRight sized appropriately ; end addition ;=============================================================================================== LOAD 'StandardEqu.d' INCLUDE 'ColorEqu.a' INCLUDE 'Packages.a' INCLUDE 'MFPrivate.a' INCLUDE 'IconUtilsPriv.a' INCLUDE 'Balloons.a' mDrawItemMsg EQU 4 mCalcItemMsg EQU 5 ArrowSize EQU $20 ; Size of the arrow data (bytes) BalloonTipOverlap EQU $8 ; Amount help balloon overlaps menu (pixels) PlotSUITE EQU (paramPlotIconSuite << 8) + (selectPlotIconSuite AND $FF) ; <54> PlotICON EQU (paramPlotIconHandle << 8) + (selectPlotIconHandle AND $FF) ; <54> PlotSICN EQU (paramPlotSICNHandle << 8) + (selectPlotSICNHandle AND $FF) ; <54> PlotCIcon EQU (paramPlotCIconHandle << 8) + (selectPlotCIconHandle AND $FF) ; <54> ; extensions to a menu item <2.2> itemHierarchicalID EQU 4 ; hierarchical menu ID Sizeof_stackitem EQU 6 ; number of bytes before aux item itemIconHandle EQU Sizeof_stackitem+auxMenuIconHandle ; handle to icon (or nil) itemIconSize EQU Sizeof_stackitem+auxMenuIconSize ; full-sized/small/shrunken itemIconGray EQU Sizeof_stackitem+auxMenuIconGray ; whether icon should be grayed itemScript EQU Sizeof_stackitem+auxMenuScript ; item text script code itemHelpString EQU Sizeof_stackitem+auxMenuHelpString ; string for balloon help Sizeof_extendeditem EQU Sizeof_stackitem+Sizeof_auxdata ; size of our stack item ; value for itemIconSize (but not itemCmd) <2.2> LargeIconCmd EQU $1F ; large icon plotted FamilyIconCmd EQU $20 ; icon cache or suite (_PlotIconSuite knows for sure!) ; special values of the itemCmd field before expansion <2.2> ShrunkenIconCmd EQU $1D ; itemCmd == $1D ==> large icon plotted in 16x16 SmallIconCmd EQU $1E ; itemCmd == $1E ==> small icon plotted NoMarkSmallIconCmd EQU $1A ; itemCmd == $1A ==> small icon with no mark ; Assumes no item in menu will ever be marked, ; and doesn't leave space to left of menu item ; for one. Used in popup in Standard File. ;---------------------------------------------------------------------------------------- ; ; StackFrame and Global Definitions ; ;---------------------------------------------------------------------------------------- MDEF0 PROC EXPORT ; ; Stack Frame Definition for TextMenuProc ; PROCEDURE TextMenuProc( message :Integer, ; theMenu :menuHandle, ; VAR menuRect :Rect, ; hitPt :Point, ; VAR whichItem :Integer); StackFrame RECORD {A6Link},DECR ParamBegin EQU * ; parameters start after this point MMESSAGE DS.W 1 ; message MMENUHANDLE DS.L 1 ; theMenu MMENURECT DS.L 1 ; VAR menuRect MPOINT DS.L 1 ; hitPt MWHICHITEM DS.L 1 ; VAR whichItem MLeftTop EQU MPOINT MPopUpItem EQU MWHICHITEM ParamSize EQU ParamBegin-* ; size of all the passed parameters RetAddr DS.L 1 ; place holder for return address A6Link DS.L 1 ; place holder for A6 link MFHeight DS.W 1 ; NOTE: This is really the "leading" field of fontinfo MWidMax DS.W 1 MDescent DS.W 1 MAscent DS.W 1 MInfoRec EQU MAscent MSpaceWidth DS.W 1 saveForeColor DS.W 3 saveBackColor DS.W 3 pixelDepth DS.W 1 colorOffset DS.W 1 invertFlag DS.W 1 ; 0 = normal item, 1 = inverted item scrollFlag DS.W 1 ; 0 = scrolling item, 1 = choosing item HItemFlag DS.W 1 ; 0 = no sub menu, 1 = item has submenu iconHandle DS.L 1 HierArrowRect DS.W 4 OrigMenuRect DS.W 4 ScrollSpeed DS.L 1 SlowPixels DS.W 1 onColorMachine DS.W 1 enableState DS.W 1 ; Inside DrawItem only! (0=disabled, 1=enabled) irTmpItemNo DS.W 1 ; Temp item number irItemNo DS.W 1 ; Item number last checked (0 means none yet) irItemAddr DS.L 1 ; Points to length byte of item expandItemErr DS.W 1 ; Error returned from ExpandItem processMgrIn DS.B 1 ; ZERO if not in or not checked, NON-zero if implemented processMgrChkd DS.B 1 ; ZERO if unimplemented check not yet done arrowHandle DS.L 1 ; Handle used for plotting arrows stackItem DS.B Sizeof_extendeditem tempString DS.B 256 LinkSize EQU * ; size of all the local variables ENDR FastSpeed EQU 0 SlowSpeed EQU 10 FirstMDMsg EQU 0 ; first message LastMDMsg EQU 5 ; last message ;---------------------------------------------------------------------------------------- ; ; Start of Code -- save work registers and dispatch on message number ; ;---------------------------------------------------------------------------------------- BRA.S StartMDEF ; Standard Header DC.W 0 ; flags word DC.L ('MDEF') ; type DC.W 0 ; ID DC.W 13 ; version 4 = MacPlus ; version 5 = Alladin ; version 6 = onNuMac ROM ; version 10= Universal ; version 11= Universal 4.2 ; version 12= Universal 6.0 ; version 13= System 7.0 <2.2> StartMDEF MDEFSaveReg REG D3-D7/A2-A4 WITH StackFrame LINK A6,#LinkSize ; set up a stack frame <1Aug85> MOVEM.L MDEFSaveReg,-(SP) ; save a whole bunch of work registers MOVE.L MMENUHANDLE(A6),A3 ; keep menuHandle in A3 move.l a3, a0 ; _HLock ; lock it down clr invertFlag(a6) ; most drawing done in normal (not inverted) mode clr scrollFlag(a6) ; only set this flag when call InvertItem ; while scrolling clr onColorMachine(a6) ; clear color machine flag cmpi.w #$3FFF, ROM85 ; color machine ? sls onColorMachine(a6) ; set byte to 1s if yes lea GoMdefProc, a0 ; get the dispatch table base move.w mMessage(a6), d0 ; get the message type clr.w enableState(a6) ; Just set to something for now <34> clr.w irTmpItemNo(A6) ; clear the temp value clr.w irItemNo(A6) ; clear the item # clr.l irItemAddr(A6) ; clear the address clr.w expandItemErr(a6) ; No Error yet clr.b processMgrIn(a6) ; DonÕt know if Process Mgr installed <53> clr.b processMgrChkd(a6) ; HavenÕt done Process Mgr check yet <53> clr.l arrowHandle(a6) ; Set handle to nil initially <48> cmpi #LastMDMsg, d0 ; is the message within bounds? bhi.s @InvalidMsg ; oops, its too high cmpi #FirstMDMsg, d0 ; blo.s @InvalidMsg ; oops, its too low add.w d0, d0 ; double to get words add.w GoMdefProc(d0), a0 ; compute the dispatch address jsr (a0) ; and dispatch @InvalidMsg move.l a3, a0 ; get menuHandle _HUnlock ; and unlock it before we leave move.l arrowHandle(a6),d0 ; the arrow handle or NIL <48><64> beq.s @skipDispose ; Don't bother if already NIL <64> move.l d0,a0 ; Get ready for DisposeHandle <64> _DisposeHandle ; DisposeHandle can deal with NIL <48> @skipDispose MOVEM.L (SP)+,MDEFSaveReg ; restore work registers UNLK A6 ; unbuild the stack frame MOVE.L (SP)+,A0 ; get return address ADD #ParamSize,SP ; strip parameters JMP (A0) ; return to caller ; Dispatch Table GoMdefProc dc.w DoDrawMsg-GoMdefProc ; draw is message #0 dc.w DoChooseMsg-GoMdefProc ; choose menu size is msg #1 dc.w DoCalcMsg-GoMdefProc ; calc menu is msg #2 dc.w DoPopUpItemMsg-GoMdefProc ; calc top of popup item #3 dc.w DoDrawItemMsg-GoMdefProc ; draw item #4 dc.w DoCalcItemMsg-GoMdefProc ; calc item #5 ;******************************************************************************************** ;* * ;* IF YOU ADD ANOTHER MESSAGE YOU MUST UPDATE THE VARIABLE "LastMDMsg" FOUND ABOVE !!!!!! * ;* * ;******************************************************************************************** ;---------------------------------------------------------------------------------------- ; ; Msg #1 -- Choose -- examine the mouse position and hilite the appropriate item ; ;---------------------------------------------------------------------------------------- DoChooseMsg ; ; -------------------------- DO SETUP STUFF --------------------------- ; bsr GetSizes ; get font info into stackframe MOVE.L MWHICHITEM(A6),A4 ; get pointer to whichItem MOVE.W (A4),D3 ; remember oldWhichItem CLR (A4) ; set whichItem to zero MOVE.L MMENURECT(A6),A2 ; get the menu rect <27Sep85> ; store original menurect in the stackframe move.l Top(a2), OrigMenuRect+Top(a6) move.l Bottom(a2), OrigMenuRect+Bottom(a6) move.l #FastSpeed, ScrollSpeed(a6) ; assume fast-speed move MFHeight(a6), d0 ; get height of scroll arrow asr #1, d0 ; num pixels for slow scroll = height/2 move d0, SlowPixels(a6) clr HItemFlag(a6) ; assume "old" item has no submenu move d3, d0 ; get item move.l (a3),a0 ; get menuPtr bsr GetItemRecord ; look it up tst.w itemHierarchicalID(a1) ; does item have sub-menu? <2.2> beq.s @NoSubMenu ; no ==> leave flag cleared <2.2> move #1, HItemFlag(a6) ; yes ==> set flag @NoSubMenu MOVE.W TopMenuItem,D4 ; get top of (scrolled) menu <30Jan86> MOVE.L MPOINT(A6),D5 ; get the mouse point <27Sep85> BEQ NOITEMSEL ; => special case for flashing <27Sep85> ; ; ------------------- ADJUST MENURECT BASED ON SCROLLING ARROWS ---------------- ; move AtMenuBottom, d0 ; check for down scrolling arrow cmp Bottom(a2), d0 ; is AtMenuBottom > bottom of menu rect ? ble.s @NoScroll ; no, so chk top move MFHeight(a6), d0 ; yes, so make menuRect smaller by down scrolling arrow rect sub d0, Bottom(a2) @NoScroll move TopMenuItem, d0 ; check for up scrolling arrow cmp Top(a2), d0 ; is TopMenuItem < top of menu rect ? bge.s @NoScroll2 ; no, so just do PtInRect move MFHeight(a6), d0 ; yes, so make menuRect smaller by up scrolling arrow rect add d0, Top(a2) @NoScroll2 ; ; If the point isnÕt in the adjusted menuRect, check for autoscrolling ; CLR.W -(SP) ; make room for PtInRect result MOVE.L D5,-(SP) ; push the point MOVE.L A2,-(SP) ; push the rect _PtInRect ; test if the point is in the rect TST.B (SP)+ ; was it? BNE @3 ; => yes, go select something ;----------------------- CHECK FOR AUTOSCROLLING DOWN ------------------------------- ; ; Only scroll if mouse pt directly above/below menu. This allows ; hierarchical menus to work properly -- scroll when mouse above/below menu, ; -- return to a previous menu if outside of the scrolling rectangles. ; cmp left(a2), d5 ; to left of menuÕs left side? blt NoItemSel ; yes, so no item selected cmp right(a2), d5 ; to right of menuÕs right side? bgt NoItemSel ; yes, so no item selected MOVE.W MFHeight(A6),D7 ; get distance for scroll <30Sep85> SWAP D5 ; get mouse.v into low word <27Sep85> CMP.W top(A2),D5 ; above top? <27Sep85> BGE @2 ; => no, check bottom <27Sep85> ADD.W D7,D4 ; try to go up an item <27Sep85> CMP.W top(A2),D4 ; menu top must be <= to MenuRect.Top <30Jan86> BGT NOITEMSEL ; => canÕt go up <27Sep85> ; how far is mouse into scrolling arrow? move top(a2), d0 ; get top of menu into d0 sub d5, d0 ; subtract mouse.v cmp SlowPixels(a6), d0 ; is it more than slow num ? bgt.s @ContDown ; yes ==> do it fast move.l #SlowSpeed, ScrollSpeed(a6) ; no ==> do it slow @ContDown move AtMenuBottom, D0 ; cmp Bottom(A2), D0 ; is AtMenuBottom > bottom of menu ? bgt.s @1 ; yes -> no scrolling arrow needed add MFHeight(a6), d0 cmp Bottom(A2), D0 ; is AtMenuBottom+scrollamt > bottom of menu ? ble.s @1 ; yes -> no scrolling arrow needed ; If we get here then we are scrolling down and the last item is showing. Therefore ; we want to draw the down scroll arrow before scrolling. move.l a2, a0 ; BlitScrollIndic expects menuRect ptr in A0 bsr BlitDownScrollIndic move MFHeight(a6), d0 ; move bottom of menuRect up so arrow doesnÕt get scrolled sub d0, Bottom(a2) ; and fall into scrolling code ;----------------------- DO THE AUTOSCROLLING -------------------------------------- @1 bsr RemoveAnyBalloon ; Be sure to remove any balloon before inverting <55> MOVE.W D3,D0 ; get the current selection <30Sep85> BSR InvertItem ; and deselect it <30Sep85> ; When a HMenu is up and the item with the HMenu is the topmost or bottommost item ; garbage is left on the screen unless we bring down the HMenu first. ; Solution: 1) DonÕt scroll if an HMenu is up. ; 2) DrawMenu clears a flag in mbSaveLoc every time a menu is drawn. ; 3) If that flag is clear, then we set the flag and skip scrolling. ; This gives MenuSelect a chance to bring down the HMenu before ; the MDEF is called again. ; 4) If the flag is set, then it is okay to scroll. IF NOT forROM THEN ; <2.2> ; RADIUS patches out complete menu mgr ==> could ; have GetItemCmd installed, but mbSaveLoc ; not initialized. cmpi.l #$FFFFFFFF, mbSaveLoc ; has the MBDF data structure been initialized? beq.s @OkToScroll move.w #$009F, d0 ; load _Unimplemented number _GetTrapAddress ; load _Unimplemented address move.l a0, d1 ; copy routine address move.w #$004E, d0 ; load _GetItemCmd number _GetTrapAddress ,newTool ; load _GetItemCmd address cmp.l a0, d1 ; new HMenu Mgr installed? beq.s @OkToScroll ; no -> skip HMenu specific stuff ENDIF ; if NOT forROM move.l mbSaveLoc, a0 ; get mbUglyScroll in mbSaveLoc move.l (a0), a0 tst mbUglyScroll(a0) ; is mbUglyScroll set ? bne.s @OkToScroll ; yes, so HMenu was already brought down move #1, mbUglyScroll(a0); no, so set field bra.s @DoneScroll ; and skip scrolling this time through @OkToScroll MOVE.W D4,topMenuItem ; stuff new topItem <27Sep85> CLR.L -(SP) ; room for region #1 <30Sep85> _NewRgn ; get it <30Sep85> MOVE.L (SP),D6 ; save in D6 <30Jan86> CLR.L -(SP) ; room for region #2 <30Jan86> _NewRgn ; get it <30Jan86> bsr SaveCurrentColors ; save current colors in stack frame move #mctRGB2, colorOffset(a6) ; this offset is unimportant here ; since all we care about is bkgd color bsr SetColors ; set proper colors for ScrollRect ; ; Delay depending on how far cursor is into the scroll arrow. ; bsr DoScrollWait @DoTheScroll MOVE.L A2,-(SP) ; push rect <27Sep85> CLR.W -(SP) ; dh = 0 <30Sep85> MOVE.W D7,-(SP) ; dv = itemHeight <30Sep85> MOVE.L D6,-(SP) ; push update region _ScrollRect ; scroll the menu <30Sep85> bsr ChkScrollArrows ; chk if scrolling arrows should still be up bsr ResetPreviousColors ; reset colors stored in stackframe MOVE.L (SP),-(SP) ; point to region #2 <30Jan86> _GetClip ; save the clip in it <30Jan86> MOVE.L D6,-(SP) ; point to update region <30Jan86> _SetClip ; set clip to it <30Jan86> BSR DrawScrolledItem ; call fast routine to draw item ADD D7, AtMenuBottom ; update new menu bottom MOVE.L (SP),-(SP) ; point to saved clip <30Jan86> _SetClip ; and restore it <30Jan86> _DisposRgn ; dispose of region #2 <30Jan86> _DisposRgn ; dispose of region #1 <30Jan86> ; ; When scrolling, no item is selected, so clear the Item in MenuDisable global ; @DoneScroll clr MenuDisable+2 ; clear Item only, not ID BRA DoChooseDone ; and return <27Sep85> ;----------------------- CHECK FOR AUTOSCROLLING UP ---------------------------------- @2 MOVE.W bottom(A2),D0 ; get bottom <30Jan86> CMP.W D0,D5 ; below bottom? <30Jan86> BLT NOITEMSEL ; => no <27Sep85> CMP.W atMenuBottom,D0 ; done scrolling? <30Jan86> BGE NOITEMSEL ; => yes, nothing below us <30Jan86> NEG.W D7 ; change direction of scroll <30Sep85> ADD.W D7,D4 ; else scroll down <27Sep85> ; how far is mouse into scrolling arrow? move d5, d0 ; get mouse.v into d0 sub bottom(a2), d0 ; subtract bottom of menu cmp SlowPixels(a6), d0 ; is it more than slow num ? bgt.s @ContUp ; yes ==> do it fast move.l #SlowSpeed, ScrollSpeed(a6) ; no ==> do it slow @ContUp move TopMenuItem, d0 ; cmp Top(a2), d0 ; is TopMenuItem <> top of menu rect ? bne @1 ; yes, so just do scrolling ; If we get here then we are scrolling up and the first item is showing. Therefore ; we want to draw the up scroll arrow before scrolling. move.l a2, a0 ; BlitScrollIndic expects menuRect ptr in A0 bsr BlitUpScrollIndic move MFHeight(a6), d0 ; move top of menuRect up so arrow doesnÕt get scrolled add d0, Top(a2) ; and fall into scrolling code bra @1 ;-------------------------------- DO THE CHOOSE ------------------------------------ ; the point is in the menu, so waltz through the itemList keeping track of vertical ; position seeing which item itÕs in. In the following loop, D4 holds the item number ; while D2 has the cumulative vertical space ; @3 ; ; With popup menus it is possible to have the mouse pt above TopMenuItem ; but no down-scrolling taking place because TopMenuItem may be below top ; of the menuRect. "Choose" must recognize this case and branch to NoItemSel. ; CMP Top(a2), D4 ; is TopMenuItem > top of menuRect ? BLE.S @DoChoose ; no ==> ok to choose CMP MPoint+V(a6), D4 ; yes ==> is TopMenuItem > mouse pt ? BGT.S NoItemSel ; yes ==> no choice @DoChoose MOVE.W D4,D2 ; top of menu into D2 <30Jan86> MOVEQ #1,D4 ; start with first item <30Jan86> MSELOOP MOVE.L (A3),A0 ; get menuPtr MOVE D4,D0 ; get item number BSR GETITEMRECORD ; look it up BEQ.S NOITEMSEL ; if so, nothing selected BSR GetItemHeight ; get item height in D0 <1Aug85> ADD D0,D2 ; update vertical <1Aug85> CMP MPOINT+V(A6),D2 ; compare with mouse point BGT.S GOTSEL ; when D2 is bigger, we found it ; ; we didnÕt reach it yet, so keep stepping down till we do ; NEXTMSEL ADDQ #1,D4 ; bump to next item BRA.S MSELOOP ; loop till we find it ; ; we found it so update whichItem. First we better make sure itÕs enabled GOTSEL ; ; put item rect in mbSaveLoc so MenuSelect has it to do Hierarchical menu drag ; must store this regardless of whether item changed (consider case where an item ; has a HMenu and you move to the HMenu, and then back into the item with that HMenu). ; LEA TEMPRECT,A0 ; get pointer to temporary rectangle MOVE.L MMENURECT(A6),A1 ; point to menuRect MOVE.L (A1)+,(A0) ; copy menuRect into tempRect MOVE.L (A1),4(A0) MOVE D2,BOTTOM(A0) ; D2 has the bottom coordinate SUB D0,D2 ; subtract the height MOVE D2,TOP(A0) ; set up the top IF NOT forROM THEN ; <2.2> ; RADIUS patches out complete menu mgr ==> could ; have GetItemCmd installed, but mbSaveLoc ; not initialized. cmpi.l #$FFFFFFFF, mbSaveLoc ; has the MBDF data structure been initialized? beq.s @SkipRectStore move.w #$009F, d0 ; load _Unimplemented number _GetTrapAddress ; load _Unimplemented address move.l a0, d1 ; copy routine address move.w #$004E, d0 ; load _GetItemCmd number _GetTrapAddress ,newTool ; load _GetItemCmd address cmp.l a0, d1 ; new HMenu Mgr installed? beq.s @SkipRectStore ; no -> skip HMenu specific stuff ENDIF ; if NOT forROM move.l mbSaveLoc, a0 ; get handle to save loc move.l (a0), a0 ; dereference move.l TempRect, mbItemRect(a0) ; save top, left move.l TempRect+4, mbItemRect+4(a0) ; save bottom, right @SkipRectStore BSR ENABLETEST ; make sure whole menu is enabled BEQ.S DoInverting ; if not, no selection MOVE D4,(A4) ; menu is enabled, so store item bra.s DoInverting ; and continue ; ; At this label the mouse is not in any item, so clear d4 so we return the ; correct value in low-memory MenuDisable. Can only reach here by a branch. ; NOITEMSEL clr d4 ; at this label no item selected ; ; see if whichItem changed; if it has, unselect the old item and select the new one ; DoInverting CMP (A4),D3 ; have they changed? BEQ.S GetDisabledItem ; if not, weÕre all done, no hiliting change bsr RemoveAnyBalloon ; Be sure to remove any balloon before inverting <55> MOVE D3,D0 ; unhilite old item BSR INVERTITEM ; MOVE (A4),D0 ; hilite new item not invertFlag(a6) ; tell InvertItem to draw in reverse colors BSR INVERTITEM ; clr invertFlag(a6) ; reset invertFlag ; ; "User ed" requested that apps be able to find out if a disabled menu item was chosen. ; We return the ID and item in the global MenuDisable. If the item is zero then ; no item was chosen (i.e. the mouse was outside the menu), or was in the title. ; GetDisabledItem SUBQ #2,SP ; room for Boolean _HMGetBalloons ; what is the state of What Is? mode? (This is a FAST call) TST.B (SP)+ BEQ.S @FlashInProgress SUBQ #2,SP ; check status of button ; _Button ; call button if helpmgr includes OSEventAvail patch _StillDown TST.B (SP)+ ; if true then button is still down BEQ.S @FlashInProgress ; else the item is flashing so donÕt flash the balloon BSR.S ShowMenuBalloon ; show the balloon for the chosen item @FlashInProgress move.l (a3), a0 ; get menu ptr swap d4 ; put item in hi-byte move menuID(a0), d4 ; put menuID in lo-byte swap d4 ; restore d4 move.l d4, MenuDisable ; put in low-memory where apps can query it if they want DoChooseDone move.l OrigMenuRect(a6), Top(a2) ; reset menuRect in case we changed it move.l OrigMenuRect+Bottom(a6), Bottom(a2) rts ; return to dispatcher ShowMenuBalloon MOVE.L D4,-(SP) ; <48> Save only the needed registers! MOVE.L (A3),A0 ; get menuPtr MOVE D4,D0 ; get item number BSR GETITEMRECORD ; look it up BSR IsDash ; Is it a dash? (other attrs?) BNE.S @needBubble ; no, just return the item num MOVEQ #-1,D4 ; else make item num -1 for dash @needBubble ; FUNCTION HMShowMenuBalloon(itemNum,itemMenuID: INTEGER; ; itemFlags,itemReserved: LONGINT; ; tip: Point; alternateRect: RectPtr; tipProc: Ptr; ; theProc,variant: INTEGER): OSErr; SUBQ #2,SP ; room for result MOVE.W D4,-(SP) ; item number MOVE.L (A3), A0 ; get menu ptr MOVE.W menuID(A0),-(SP) ; push menuID MOVE.L MENUENABLE(A0),D0 ; <41> get menu flags in D0 MOVE.L D0,-(SP) ; <41> push menu flags MOVE.L stackItem+itemHelpString(A6),-(SP) ; push help string handle in itemReserved MOVE.L MBSaveLoc,A0 ; get MBSave handle MOVE.L (A0),A0 ; deref MOVE.W mbItemRect+bottom(A0),D4 SUB.W mbItemRect+top(A0),D4 LSR.W #1,D4 ; find half way down from top of menu MOVE.L mbItemRect+botRight(A0),D0 ; use the right side of the menu rect SUBQ.W #BalloonTipOverlap,D0 ; <47> tweak the horizontal part SWAP D0 SUB.W D4,D0 ; put the tip in the middle of the right vert SWAP D0 MOVE.L D0,-(SP) ; push the tip PEA mbItemRect(A0) ; push the alternaterect CLR.L -(SP) ; NIL tipProc CLR.L -(SP) ; theProc & variant = 0 _HMShowMenuBalloon ADDQ #2,SP ; toss result MOVE.L (SP)+,D4 ; <48> RTS ;------------------------------- DONE CHOOSE MSG ------------------------------------ ;--------------------------------------- ; Utility -- RemoveAnyBalloon <55 KSM> ;--------------------------------------- ; ; Insure no balloon is currently displayed. This utility was addded as change <55> ; RemoveAnyBalloon subq #2,sp ; room for Boolean _HMGetBalloons ; Get state of WhatIs mode (Show Balloons?) tst.b (sp) ; EQ means off (leave result on stack for now) beq.s @helpIsOff _HMRemoveBalloon ; Remove any balloons before scrolling @helpIsOff addq #2,sp ; room for Boolean rts ;--------------------------------------- ; Utility -- DoScrollWait ;--------------------------------------- ; ; Delay for ScrollSpeed ticks. If cursor moves out of slow scroll area then leave wait loop. ; DoScrollWait tst.l ScrollSpeed(a6) ; how fast should we scroll? beq.s @NoWait ; zero means fast as possible move.l d3, -(sp) ; save temp reg on the stack subq #4, sp ; space for result _TickCount ; get current tick count move.l (sp)+, d3 add.l ScrollSpeed(a6), d3 ; we want to wait until tick count in d3 @Loop subq #4, sp ; space for VAR parameter move.l sp, -(sp) ; push address of parameter _GetMouse move.l (sp)+, d5 ; get mouse pt swap d5 ; get .v into lo-word tst d7 bge.s @ScrollingDown ; how far is mouse into scrolling arrow? move d5, d0 ; get mouse.v into d0 sub bottom(a2), d0 ; subtract bottom of menu cmp SlowPixels(a6), d0 ; is it more than slow num ? bgt.s @DoneWait ; yes ==> do it fast ==> stop waiting bra.s @ContLoop @ScrollingDown ; how far is mouse into scrolling arrow? move top(a2), d0 ; get top of menu into d0 sub d5, d0 ; subtract mouse.v cmp SlowPixels(a6), d0 ; is it more than slow num ? bgt.s @DoneWait ; yes ==> do it fast ==> stop waiting @ContLoop subq #4, sp ; space for result _TickCount cmp.l (sp)+, d3 ; reached desired tick count yet? bgt.s @Loop ; no ==> keep looping ; yes ==> weÕre done waiting @DoneWait move.l (sp)+, d3 ; restore work register @NoWait rts ;--------------------------------------- ; Utility -- ChkScrollArrows ;--------------------------------------- ; if scrolling up, and if last item is appearing, then lower clip by height of ; rectangle containing indicator arrow, and erase arrow rectangle. ChkScrollArrows tst d7 bge.s @ChkScrollDown ; if D7 >= 0 then scrolling down not up move d7, d0 ; get amount of scroll neg d0 ; take negative since to make it positive add MFHeight(a6), d0 ; add in height of scroll arrow add Bottom(a2), d0 ; add to bottom of menuRect cmp AtMenuBottom, d0 ; is new bottom of menuRect >= AtMenuBottom blt.s @NotLastItem ; no ==> not showing last item ; last item is being drawn -> open clip so scroll arrow gets erased and last item gets drawn move.l d6, a0 ; change the bottom of the update region move.l (a0), a0 ; get ptr to rgn move MFHeight(a6), d0 ; get menu item height add d0, 2+Bottom(a0) ; Bottom = Bottom + menu item height add d0, Bottom(a2) ; update bottom of menuRect move.l d6, -(sp) ; and erase the whole region _EraseRgn @NotLastItem rts ; if scrolling down, and if first item is appearing, then increase clip by height of ; rectangle containing indicator arrow, and erase arrow rectangle. ; NOTE: TopMenuItem has already been adjusted by scroll amount, so donÕt subtract it here @ChkScrollDown move Top(a2), d0 ; get Top of menuRect sub MFHeight(a6), d0 ; sub height of scroll arrow cmp TopMenuItem, d0 ; is new top of menuRect <= TopMenuItem bgt.s @NotFirstItem ; no ==> not showing first item ; first item is being drawn -> open clip so scroll arrow gets erased and first item gets drawn move.l d6, a0 ; change the top of the update region move.l (a0), a0 ; get ptr to rgn move MFHeight(a6), d0 ; get menu item height sub d0, 2+Top(a0) ; Top = Top - menu item height sub d0, Top(a2) ; update top of menuRect move.l d6, -(sp) ; and erase the whole region _EraseRgn @NotFirstItem rts ;--------------------------------------- ; Utility -- GetSizes ;--------------------------------------- ; GetSizes reads the size of the current font into the stack frame. It puts ; ascent+descent+leading into the leading field and tweaks width for chicago GetSizes LEA MInfoRec(A6),A2 ; point to our info rec <1Aug85> MOVE.L A2,-(SP) ; push a pointer <1Aug85> _GetFontInfo ; and get the fontÕs info <1Aug85> MOVE.W (A2)+,D0 ; get ascent <1Aug85> ADD.W (A2)+,D0 ; add descent <1Aug85> ; fudge width if font is Chicago so that space between command key and command ; character look better. CanÕt assume that a width of 14 means chicago, so check ; explicitly. TST.W SysFontFam ; We ar on post-MacPlus so can check SysFontFamily BNE.S @NotChicago ; If SysFontFam <> 0 then not Chicago ; If on post-MacPlus then check CurFMFamily too. TST.W CurFMFamily ; is CurFMFamily == 0 ? BNE.S @NotChicago ; no, so not Chicago SUBQ #2,(A2) ; yes its Chicago, so fudge width <1Aug85> @NotChicago ADDQ #2,A2 ; skip over widmax <1Aug85> ADD.W D0,(A2) ; add leading, store total height in MFHeight(A6) <1Aug85> SUBQ.L #2, SP ; Make room in stack MOVE.W #' ', -(SP) ; ch = space _CharWidth ; See how wide it is MOVE.W (SP)+, MSpaceWidth(A6) ; Put it in our stack frame RTS ;--------------------------------------- ; Utility -- GetIconSize ;--------------------------------------- ; GetIconSize is a utility which returns the height and width of an icon. ; On entry: A1 points to the item ; On exit: D1 contains the result (height is in the high word) GetIconSize TST.W itemIconSize(A1) ; does it have an icon? <2.2> BNE.S @hasIcon ; skip around if it does <1Aug85> @noIcon MOVEQ.L #0, D1 ; No icon - return 0 RTS ; Go home @hasIcon tst.b onColorMachine(a6) ; If color, than check color icon beq.s @noColor ; cmpi.w #NoMarkSmallIconCmd, itemIconSize(A1) ; Never look for a cicn in this case <59> beq.s @noColor ; <59><60> ; <51> the check of itemIconSize indicates if we have an icon, this check prevents the use of icon #256 ; for things like smallIcon, shrunkIcon, etc. ; tst.b itemIcon(a1) ; icon specÕd in resource type? <2.2><51> ; beq.s @noColor ; jump if not <2.2><51> ; Get the cicn resource because its faster than calling GetCIcon SUBQ.L #4, SP ; make room for function result MOVE.L #'cicn',-(SP) ; push the resource type MOVE.W #$0100,D0 ; menu icons are 256-511 MOVE.B itemIcon(A1),D0 ; MOVE.W D0,-(SP) ; push icon number _GetResource ; get handle to cicn resource MOVE.L (SP)+, D1 ; get it in D1 BEQ.S @noColor ; no color icon, must be regular icon MOVE.L D1, -(SP) ; Since we donÕt know what resLoad is _LoadResource ; call LoadResource to be sure MOVE.L D1, A0 ; get cicn resource handle in a0 MOVE.L (A0), A0 ; dereference, cicn begins with pixMap MOVE.L pBounds+botRight(A0), D1 ; get bottom,right in D1 SUB.L pBounds+topLeft(a0), D1 ; height = bottom,right - top,left BRA.S @testShrunk ; @noColor ; MOVE.L #$00200020, D1 ; Large b/w icons are 32 x 32 @testShrunk ; cmpi.w #FamilyIconCmd, itemIconSize(A1) ; is there an icon suite/cache? beq.s @0 ; yes -> branch cmpi.w #ShrunkenIconCmd, itemIconSize(A1) ; is there a shrunken icon? <2.2> beq.s @0 ; yes -> branch cmpi.w #SmallIconCmd, itemIconSize(A1) ; is there a small icon? <2.2> beq.s @0 ; yes -> branch cmpi.w #NoMarkSmallIconCmd, itemIconSize(A1) ; is this a small icon with no mark? bne.s @1 ; no -> branch @0 LSR.L #1, D1 ; Divide by 2 to get smaller size BCLR #15, D1 ; Clear out because height could be odd @1 RTS ;--------------------------------------- ; Utility -- GetItemHeightA4 ;--------------------------------------- ; GetItemHeight gets the height of the current menu item into D0. ; On entry: A4 points to the item GetItemHeightA4 MoveM.L A1, -(SP) ; save work register Move.L A4, A1 ; set up for call to GetItemHeight Bsr.S GetItemHeight MoveM.L (SP)+, A1 ; restore work register Rts ;--------------------------------------- ; Utility -- GetItemHeight ;--------------------------------------- ; GetItemHeight gets the height of the current menu item into D0. ; On entry: A1 points to the item ; On exit: D1 has icon width (if any) in the high word. ; Trashes: D0, D1 GetItemHeight GIHtReg REG d1-d2/a0-a2 ; TextFace can trash d0-d2 and a0-a1 (d0 is OK) ; and GetSizes trashes a2 bsr.s GetIconSize swap d1 ; We need to check to see if the style will change the MFHeight moveq #0,d0 ; clear out high byte move.b ITEMSTYLE(a1),d0 ; get style setting beq.s @MFHeightIsOK ; Save standard FontInfo so we only call GetSizes once move.l a3,-(sp) ; Save a work register lea MInfoRec(A6),a3 move.l (a3)+,-(sp) ; Save ascent/descent move.l (a3)+,-(sp) ; Save widMax/MFHeight (leading) move.w MSpaceWidth(a6),-(sp) ; Save MSpaceWidth movem.l GIHtReg,-(sp) swap d0 ; WARNING: Assumes highword is ZERO from above! move.l d0,-(sp) ; Set up for BOTH TextFace calls _TextFace ; Set to new face bsr.s GetSizes ; Compute the new MFHeight _TextFace ; Restore back TextFace(0) move.w MFHeight(a6),d0 ; Get new MFHeight into d0 for calc movem.l (sp)+,GIHtReg move.w (sp)+,MSpaceWidth(a6) ; Restore MSpaceWidth move.l (sp)+,-(a3) ; Restore widMax/MFHeight (leading) move.l (sp)+,-(a3) ; Restore ascent/descent move.l (sp)+,a3 bra.s @MFHeightIsCalculated @MFHeightIsOK move.w MFHeight(a6),d0 ; Get the MFHeight @MFHeightIsCalculated addq.w #2,d1 ; Compute Icon height + 2 cmp.w d0,d1 ; Is Icon height + 2 < MFHeight? blt.s @fontLarger ; if yes, use font height move.w d1,d0 @fontLarger rts ;--------------------------------------- ; Utility -- GetItemWidth ;--------------------------------------- ; GetItemWidth gets the width of the current menu item into D0. ; On entry: A1 points to the item's attr byte list ; A4 is the item string ; D7 has icon width (if any) ; Trashes: D0, D1, D7 GetItemWidth MOVE.W MWidMax(A6),D1 ; get char width <1Aug85> CMP.W #NoMarkSmallIconCmd,itemIconSize(A1) ; small icon with no mark? BNE.S @addMark ; no, add in space for mark ADDQ.W #1,D7 ; add in one pixel indent for small icon BRA.S @noMark ; and continue @addMark ADD.W D1,D7 ; add once for mark <1Aug85> @noMark TST.W itemHierarchicalID(a1) ; does item have sub-menu? BNE.S @spaceForCmd ; yes, include room for hierarchical arrow TST.B itemCmd(A1) ; is there a commmand? <2.2><51=BRC#80417> BEQ.S @justAddMargin ; if not, skip but still must add margin! <51=BRC#80417> @spaceForCmd ADD.W D1,D7 ; add twice for command equivalent <1Aug85> ADD.W D1,D7 ; <1Aug85> @justAddMargin ; <51=BRC#79297> ADDQ.W #8,D7 ; plus an eight pixel margin <1Aug85> MOVEQ #-1,d1 ; Two words (non-zero) to indicate no TextFont/Face chgs <51> MOVE.L d1,-(sp) ; is pushed onto the stack <51> MOVEQ #0,D1 ; clear out high byte MOVE.B ITEMSTYLE(A1),D1 ; get style setting beq.s @NoFaceChg ; <51=BRC#79297> MOVE.W D1,-(SP) ; push the style _TextFace ; tell LisaGraf about new style clr.w 2(sp) ; Say we need to clean up face <51=BRC#79297> @NoFaceChg ; If there is a script defined for this item, then set font for proper string width calc, ; do calc, and restore font to #0. ; use utility routine for setting the font from the script move.w itemScript(a1),d0 ; pass script number <2.2> bmi.s @NoScriptChg ; skip setting if default <2.2><20> bsr SetScriptFont ; set TextFont according to script clr.w (sp) ; Say we need to clean up font <51> @NoScriptChg CLR -(SP) ; make room for stringWidth result MOVE.L A4,-(SP) ; move string pointer _StringWidth ; find out the width ADD.W (SP)+,D7 ; add width to extra ; Now clean up TextFont/TextFace as required <51=BRC#79297> move.w (sp)+,d0 ; Clear if we need to restore the font bne.s @chkFace move.w d0,-(sp) _TextFont @chkFace move.w (sp)+,d0 ; Clear if we need to restore the face bne.s @chksDone move.w d0,-(sp) _TextFace @chksDone MOVE.W D7, D0 ; return the value RTS ;--------------------------------------- ; Utility -- EnableTest ;--------------------------------------- ; EnableTest is a utility which tests if an item is enabled. It expects a menuHandle ; in A3 and the item number in D4. It returns the result in the Z-flag ENABLETEST MOVE.L (A3),A0 ; get menu pointer MOVE.L MENUENABLE(A0),D0 ; get enable flags CMPI.W #31,D4 ; is item > 32 <7Jan86> BGT.S @0 ; => no enable/disable <7Jan86> BTST D4,D0 ; is item enabled? BEQ.S ETDONE ; if not, return 0 @0 BTST #0,D0 ; test menu bit BEQ.S ETDONE ; if off, return 0 MOVE.W D4, D0 ; Put item number in D0 BSR GetItemRecord ; Go get it BSR IsDash ; Is it a dash? ETDONE RTS ; return to caller ;--------------------------------------- ; Utility -- InvertItem ;--------------------------------------- ; InvertItem is an internal utility that hilites/unHilites an item. ; ; On entry: D0 Item number ; A3 Menu handle ; ; If the high bit of D0 is set, bit-clear with gray instead of inverting the ; item (used by DoDrawMsg routine). INVERTITEM MOVEM.L D3-D4,-(SP) ; save work registers MOVE D0,D3 ; keep item number in safe place BEQ INVERTDONE ; if zero, ignore MOVE.W TopMenuItem,D2 ; start at top of menu <30Jan86> MOVEQ #1,D4 ; D4 hold item index <27Sep85> IILOOP MOVE D4,D0 ; get item MOVE.L (A3),A0 ; get menuPtr BSR GETITEMRECORD ; look it up beq InvertDone ; z-flag ==> canÕt find it BSR.S GetItemHeight ; get item height into D0 <1Aug85> CMP.W D3,D4 ; found the item we want yet? <40> BEQ.S GOINVERT ; if so, go invert it ADD D0,D2 ; add total to cumulative v position ADDQ #1,D4 ; bump to next position BRA.S IILOOP ; loop till we find it ; itÕs time to invert the item. The menuRect contains the horizontal bounds, D2 contains ; the top of the vertical, D0 has the vertical size GOINVERT MOVE.B 1(A0),D1 ; remember 1st char of item LEA TEMPRECT,A0 ; get pointer to temporary rectangle MOVE.L MMENURECT(A6),A1 ; point to menuRect MOVE.L (A1)+,(A0) ; copy menuRect into tempRect MOVE.L (A1),4(A0) MOVE D2,TOP(A0) ; D2 has the top coordinate ADD D0,D2 ; add in the height MOVE D2,BOTTOM(A0) ; set up the bottom ; ; Instead of inverting the itemÕs rectangle we redraw it. If the invertFlag(a6) ; is set then SetColors will invert the colors properly for us. If it isnÕt set ; then the item will just be redrawn in normal colors. ; movem.l a2-a4/d3-d7, -(sp) ; save same work registers as does DrawMsg ; set up for call to DrawTheItem. Before doing this, we must clip to the itemÕs rectangle ; so that outline and shadowed text will not draw outside of the item rect. But, because ; scrolling with icons can produce "parts of items", we must clip to the intersection of the ; menu rect and the item rect. AND we must clip to screen in case menu draws past screen bounds. subq #4, sp ; space for result _NewRgn move.l (sp), -(sp) ; make copy of region so can delete later _GetClip subq #2, sp ; space for boolean result move.l MMenuRect(a6), -(sp); push menurect address pea TempRect ; push itemrect address pea HierArrowRect(a6) ; push dest rect (reuse stackframe variable) _SectRect addq #2, sp ; ignore result bsr PushThePort move.l (sp)+, a0 ; get port subq #2, sp ; space for boolean result pea portRect(a0) ; push portRect address pea HierArrowRect(a6) ; push clip rect address pea HierArrowRect(a6) ; push dest address _SectRect addq #2, sp ; ignore result pea HierArrowRect(a6) ; push clip rect _ClipRect tst scrollFlag(a6) ; being called from scroll routine? bne.s @DoRedraw ; yes, so do the drawing ; On MacPlus and MacSE do InvertRect instead of redrawing when choosing an item. ; Do this because MacDrawÕs custom "line" menu does not handle "choose item" message properly. ; Of course itÕs not as easy as that since we use the Choose message as a way to clean up ; the garbage left over when a hierarchical menu is brought down, and this assumes that ; the item is redrawn, NOT inverted. If this is the case then HItemFlag will be set. tst.b onColorMachine(a6) ; on MacII ? bne.s @DoRedraw ; yes ==> always redraw tst HItemFlag(a6) ; does item have submenu? bne.s @DoRedraw ; yes ==> then redraw to eliminate garbage beneath submenu pea TempRect ; push ptr to itemÕs rectangle _InverRect ; invert it bra.s @RedrawDone ; and leave @DoRedraw ; erase the rect to the proper background color bsr SaveCurrentColors ; save current colors in stack frame move #mctRGB2, colorOffset(a6) ; this offset is unimportant here ; since all we care about is bkgd color bsr SetColors ; set proper colors for EraseRect pea TempRect ; push a pointer to the rectangle _EraseRect ; erase it bsr ResetPreviousColors ; reset colors after EraseRect ; and draw the item lea TempRect, a0 ; get address of itemÕs rectangle move Top(a0), d3 ; get top add MAscent(a6),d3 ; add in the ascent for baseline bsr DrawTheItem ; call drawing routine (it calls ResetPreviousColors) @RedrawDone move.l (sp), -(sp) ; reset clip to region it was before drawing item _SetClip _DisposRgn movem.l (sp)+, a2-a4/d3-d7 ; restore work registers INVERTDONE MOVEM.L (SP)+,D3-D4 ; recover work regs RTS ;--------------------------------------- ; Utility -- GrayRect ;--------------------------------------- ; GrayRect is a utility that bit-clears the current "tempRect" with gray ; ; We assume that this routine is only called by Draw msg, that SaveCurrentColors ; has been called already, and that ResetPreviousColors will be called after this. GRAYRECT move.l theZone, -(sp) ; we set the zone to the system zone so the <35 gbm> move.l sysZone, theZone ; pixpat gets created there <35 gbm> MOVE.L A0,-(SP) ; push rect address MOVE.L (A5),A0 ; get QuickDraw globals PEA Gray(A0) ; push gray _PenPat ; set pen to it MOVE #PatBIC,-(SP) ; push patBIC penMode _PenMode ; set penMode move #mctRGB2, colorOffset(a6) ; use text color for fore color bsr SetColors ; set colors for bit clear _PaintRect ; "OR" on the dim pattern _PenNormal move.l (sp)+, theZone ; restore the correct heap <35 gbm> RTS ;--------------------------------------- ; Utility -- TweakPos ;--------------------------------------- ; TweakPos is passed an element size in D0. It gets a horizontal offset into ; D2 depending on whether things are right justified or not. It also adjusts ; D5 and D6 (the left and right positions). TweakPos MOVE D5,D2 ; assume left to right <27Sep85> ; ADDQ #2,D2 ; and indent element a little <27Sep85> ADD.W D0,D5 ; assume bump past icon <27Sep85> TST.B TESysJust+1 ; check for right just <11oct85> BPL.S @1 ; => guessed right <27Sep85> SUB.W D0,D6 ; else back up for icon <27Sep85> SUB.W D0,D5 ; and fix up left <27Sep85> MOVE.W D6,D2 ; and set position <27Sep85> @1 RTS ;--------------------------------------- ; Utility -- CenterRectInMFHeight ;--------------------------------------- ; CenterRectInMFHeight fixes the rect pointed to by a0 when the icon height ; is smaller than the item height. ; On Entry: A0 points to the rect ; On Exit: The rect is centered within MFHeight ; Trashes D0, but A0 is preserved CenterRectInMFHeight move.w bottom(a0),d0 ; Compute rect height (bottom-top) sub.w top(a0),d0 sub.w MFHeight(a6),d0 ; IF (iconHt-MFHeight) >= 0 THEN branch bge.s @dontBumpRectDown neg.w d0 ; d0 = MFHeight - icon ht subq.w #1,d0 ; already 1 down from top lsr.w #1,d0 ; get 1/2 delta add.w d0,top(a0) add.w d0,bottom(a0) @dontBumpRectDown rts ;--------------------------------------- ; Utility -- DrawScrolledItem ;--------------------------------------- ; DrawScrolledItem is a faster way to draw the item that appears after a menu is scrolled. ; The old method was to redraw the whole menu, and because clipping was set to just ; the item that appeared no flashing occured. The problem is that with the new features, ; most noticeably color and hierarchical menus, scrolling can be fairly slow. Actually this ; method turns out to speed up scrolling by a factor of 2-3!! ; DrawScrolledItem MOVE.W D4,D2 ; top of menu into D2 MOVEQ #1, D4 ; start with first item TST D7 BGE.S @ScrollingDown ; if D7 >= 0 then scrolling down not up @ScrollingUp MOVE Bottom(a2), D3 ; fake mouse pt to be just above bottom of menu SUBQ #1, D3 ; one pixel above menu bottom, or down scroll arrow BRA.S @Loop @ScrollingDown MOVE Top(a2), D3 ; fake mouse pt to be just below top of menu ADDQ #1, D3 ; one pixel below menu top, or up scroll arrow @Loop MOVE.L (A3),A0 ; get menuPtr MOVE D4,D0 ; get item number BSR GetItemRecord ; look it up BEQ.S @LastItemSel ; if none then must be last item BSR GetItemHeight ; get item height in D0 ADD D0,D2 ; update vertical CMP D3,D2 ; compare with mouse point BGT.S @GotSel ; when D2 is bigger, we found it ; ; we didnÕt reach it yet, so keep stepping down till we do ; ADDQ #1,D4 ; bump to next item BRA.S @Loop ; loop till we find it ; ; we found it so draw the item ; @LastItemSel SUBQ #1, D4 ; back up one item @GotSel MOVE D4, D0 ; InvertItem wants item number in D0 MOVE #1, scrollFlag(a6) ; set flag for InvertItem BSR InvertItem ; InvertItem will draw the item ; Because of icons, there could be just part of the scrolled item showing, so if ; we are scrolling up then redraw the item above too, or if scrolling down then ; redraw the item below. TST D7 BGE.S @ScrollingDown2 ; if D7 >= 0 then scrolling down not up @ScrollingUp2 SUBQ #1, D4 ; draw item above this one MOVE D4, D0 BSR InvertItem BRA.S @NoItemSel @ScrollingDown2 ADDQ #1, D4 ; draw item below this one MOVE D4, D0 BSR InvertItem @NoItemSel CLR scrollFlag(a6) ; clear flag after InvertItem call rts ;---------------------------------------------------------------------------------------- ; ; Msg #0 -- Draw Menu -- bits behind have been saved, menu structure has been drawn, ; and menu rectangle is cleared to proper color (all by mbarproc) ; ;---------------------------------------------------------------------------------------- ; ; here is the part of the TextMenuProc that draws the menu. For most of this routine, ; A3 holds the menuHandle, D4 is the item counter and D3 holds the cumulative ; vertical position. DrawMenu is broken off for use in scrolling. ; ; To clear up a very tricky scrolling menu bug, we need to NOT SCROLL when a hierarchical menu ; is up in the last item (i.e. topmost or bottommost). If we donÕt bring the HMenu down first ; a little bit of garbage is left on the screen. We clear the field mbUglyScroll each ; time a menu is drawn, then set it when the first time into the scrolling routine. Thereafter ; we check it and realize that the HMenu is already down, so itÕs ok to scroll. ; ; Changed so that caller sets global TopMenuItem so that can be forced to draw from DoDrawMsg bsr GetSizes ; get font info into stackframe MOVE.L MMenuRect(A6),A0 ; get menu rect pointer <30Jan86> clr atMenuBottom ; clear bottom memory IF NOT forROM THEN ; <2.2> ; RADIUS patches out complete menu mgr ==> could ; have GetItemCmd installed, but mbSaveLoc ; not initialized. cmpi.l #$FFFFFFFF, mbSaveLoc ; has the MBDF data structure been initialized? beq.s @SetTMI move.w #$009F, d0 ; load _Unimplemented number _GetTrapAddress ; load _Unimplemented address move.l a0, d1 ; copy routine address move.w #$004E, d0 ; load _GetItemCmd number _GetTrapAddress ,newTool ; load _GetItemCmd address cmp.l a0, d1 ; new HMenu Mgr installed? bne.s @ScrollClrOK ; yes -> MenuSelect sets TopMenuItem properly @SetTMI MOVE.L MMenuRect(A6),A0 ; get menu rect pointer <30Jan86> MOVE.W top(A0),topMenuItem ; no -> say to draw from top <30Jan86> bra.s @SkipScrollClr ; and skip HMenu specific stuff @ScrollClrOK ENDIF ; if NOT forROM move.l mbSaveLoc, a0 ; clear mbUglyScroll every time draw a menu move.l (a0), a0 clr mbUglyScroll(a0) @SkipScrollClr bsr.s DrawMenu ; call draw menu bsr.s ChkScrollIndic ; draw scrolling indicator (if necessary) rts ;--------------------------------------- ; Utility -- DrawMenu ;--------------------------------------- DRAWMENU MOVEM.L a2-A4/D3-D7,-(SP) ; save some regs <27Sep85> MOVEQ #1,D4 ; start with first item MOVE.W topMenuItem,D3 ; and point to top of first item ; apps that screw around with the wmgrport textfont and textface unwittingly, have ; menu items show up in the wrong font/face/etc.... CLR.L -(SP) ; push zero for TextFace and TextFont _TextFace ; change textface to normal _TextFont ; change textfont to normal DRAW1MLOOP MOVE.L MMENURECT(A6),A0 ; get menuRect pointer <27Sep85> ADD.W MAscent(A6),D3 ; add in the ascent for baseline bsr DrawTheItem ; call drawing routine BEQ.S DONEDRAW ; if null item, EXIT W/atBottom TRUE <27Sep85> ; We can't just use MFHeight & MAscent 'cuz there might be outlines/shadow text, etc SUB.W MAscent(A6), D3 ; get rid of the ascent here so we can BSR GetItemHeightA4 ; get the true item height ADD D0, D3 ; and add it to cumulative total ; DrawTheItem w/ icons will increment D3 (baseline) for some bizarre ; "centering" scheme. We try to undo the damage here TST.W itemIconSize(A4) ; does it have an icon? <2.2> BEQ.S @1 ; skip if it doesnÕt SUB.W MFHeight(A6),D0 ; undoes the algorithm in NotDash LSR.W #1,D0 SUB.W D0, D3 @1 ADDQ #1,D4 ; bump to next item BRA.s DRAW1MLOOP ; loop till done ; When we return to DoneDraw, D3 points to the baseline of the cell that would follow the ; last cell. Back up to the bottom of the last cell and save as menubottom. DONEDRAW SUB.W MAscent(A6),D3 ; back up to "top of cell" <30Jan86> MOVE.W D3,AtMenuBottom ; update bottom <30Jan86> MOVEM.L (SP)+,a2-A4/D3-D7 ; restore some regs <27Sep85> RTS ;--------------------------------------- ; Utility -- ChkScrollIndic ;--------------------------------------- ; Blit up the scrolling down arrow if we need to ; ChkScrollIndic move.l MMenuRect(a6), a0 ; get menu rect ptr move AtMenuBottom, d0 ; get AtMenuBottom cmp Bottom(a0), d0 ; is AtMenuBottom > bottom of MenuRect ble.s @CkUpIndic ; no ==> donÕt need down arrow, see if need up arrow bsr.s BlitDownScrollIndic ; yes ==> blit the down arrow @CkUpIndic move.l MMenuRect(a6), a0 ; get menu rect ptr move TopMenuItem, d0 ; get TopMenuItem cmp Top(a0), d0 ; is TopMenuItem < top of MenuRect bge.s @DoneChk ; no ==> donÕt need up arrow bsr.s BlitUpscrollIndic ; yes ==> blit the up arrow @DoneChk rts ;--------------------------------------- ; Utility -- BlitDownScrollIndic / BlitUpScrollIndic ;--------------------------------------- ; Blit up the scrolling arrows ; BlitSaveReg REG a4/d4 BlitDownScrollIndic movem.l BlitSaveReg, -(sp) ; store work registers ; calculate where bottom of menu is movem.l (a0),d0-d1 ; Copy Rect into registers movem.l d0-d1,HierArrowRect(a6) ; copy to hier rect swap d1 ; make d1 right,bottom sub.w MFHeight(a6), d1 ; bottom-MFHeight move.w d1, HierArrowRect+Top(a6) ; top=bottom-MFHeight lea DownArrow, a4 ; store arrow address in a4 for DoTheBlit bra.s DoTheBlit BlitUpScrollIndic movem.l BlitSaveReg, -(sp) ; store work registers ; calculate where top of menu is movem.l (a0),d0-d1 ; Copy Rect into registers movem.l d0-d1,HierArrowRect(a6) ; copy to hier rect swap d0 ; make d1 left,top add.w MFHeight(a6), d0 ; top-MFHeight move.w d0, HierArrowRect+bottom(a6); bottom=top+MFHeight lea UpArrow, a4 ; store arrow address in a4 for DoTheBlit ; and drop into DoTheBlit DoTheBlit bsr SaveCurrentColors ; save current colors in stack frame move #-1, d4 ; force SetColors to get the title color ; entry not an item entry move #mctRGB2, colorOffset(a6) ; set fore/back colors for this item bsr SetColors ; set proper colors for blit ; erase rect now that the fore/back colors are set properly pea HierArrowRect(a6) _EraseRect move MWidMax(A6), d0 add d0,HierArrowRect+Left(A6) ; note top is ok already st enableState(A6) ; Up and down arrows are never grayed bsr.s BlitCommon movem.l (sp)+, BlitSaveReg ; restore work registers bsr ResetPreviousColors ; reset colors stored in stackframe rts ;--------------------------------------- ; Utility -- BlitCommon ;--------------------------------------- ; Blit the bits pointed to by A4 ; On Entry: A4 points to bits to be blitted ; HierArrowRect(A6) has rect to blit into (topLeft is setup) ; thePort has been set ; Trashes: D0, A4 BlitCommon ; fix up HierArrowRect to have height/width = min(16,MFHeight) move.w MFHeight(a6), d0 ; get height cmpi.w #16, d0 ; which is smaller? ble.s @MFIsSmaller move.w #16, d0 ; 16 is the smaller value @MFIsSmaller move.l HierArrowRect(a6), HierArrowRect+4(a6) ; Copy topLeft to botRight add.w d0,HierArrowRect+right(a6) add.w d0,HierArrowRect+bottom(a6) ; The icon utils require a real handle to plot the arrow move.l arrowHandle(a6),a0 ; Did we already allocate this? move.l a0,d0 bne.s @justCopyTheData moveq #ArrowSize,d0 _NewHandle bne.s @cantDoIt move.l a0,arrowHandle(a6) ; Save the handle in case we have more hier items @justCopyTheData move.l (a0),a1 ; Dest ptr is in handle move.l a4,a0 ; Src ptr is arrow bits moveq #(ArrowSize/4)-1,d0 ; Size is always 32 (d0=#longs to move - 1) @arrowLoop move.l (a0)+,(a1)+ dbf d0,@arrowLoop lea HierArrowRect(a6),a0 ; Put the rectPtr into a0 <54> bsr CenterRectInMFHeight moveq #atNone,d1 ; Put the alignment into d0 <54> move.l arrowHandle(a6),a1 ; Put the icon handle into a1 <54> ; NOTE: The clr.w below only affects the h-menu arrow. The itemIconGray flag ; only applies to this itemÕs icon, but not the h-arrow. Since we use a common ; subroutine to plot both the icon and the h-arrow, we must clear this flag before ; plotting the arrow, and thereby assume the icon has already been plotted. clr.w stackItem+itemIconGray(A6) ; Assumes itemÕs icon drawn before h-menu <54> move.w #PlotSICN,d0 ; And plot the SICN <54> bsr.s IconPlotFromHandle ; Go plot it <54> @cantDoIt rts ;--------------------------------------- ; Utility -- IconPlotFromHandle <54> ;--------------------------------------- ; Set up for and call to PlotIconSuite, PlotIconHandle, PlotSICNHandle, or PlotCIconHandle ; Since they all take the same arguments, this saves code. ; On Entry: a0 is the RectPtr ; a1 is the IconHandle ; d0 is the call to make (PlotXXXX constant) ; High byte is #of params, low byte is selector # ; d1.w is the alignment ; On Exit: d0 contains result and ccÕs are set ; FUNCTION PlotIconSuite(theRect: Rect; align: INTEGER; transform: INTEGER; theIconSuite: Handle): OSErr; ; FUNCTION PlotIconHandle(theRect: Rect; align: INTEGER; transform: INTEGER; theIcon: Handle): OSErr; ; FUNCTION PlotSICNHandle(theRect: Rect; align: INTEGER; transform: INTEGER; theSICN: Handle): OSErr; ; FUNCTION PlotCIconHandle(theRect: Rect; align: INTEGER; transform: INTEGER; theCIcon: CIconHandle): OSErr; ; NOTE: The ttDisabled transform conflicts with the BitClearItem used on disabled items ; (avoids the use of slow grayishTextMode only on B&W machines currently). ; Icons drawn in ttDisabled mode and subsequently BitClearÕd will become completely erased! ; The tests below insure that disabled items on B&W machines never use ttDisabled for the icon. ; It is O.K. on any machine to use this mode when only the itemIconGray flag is true since the ; entire item will not be BitClearÕd. The Pascal-ish comments below indicate the intention. IconPlotFromHandle subq.w #2,sp ; Make room for result move.l a0,-(sp) ; Push the rect ptr move.w d1,-(sp) ; Push the alignment moveq #ttNone,d1 ; transform := ttNone; tst.b enableState(a6) ; if (enableState=false) then begin bne.s @checkIconGray tst.b onColorMachine(a6) ; if (onColorMachine=true) then bne.s @mustDisable ; transform := ttDisabled; bra.s @haveTransform ; otherwise on B&W machine, donÕt use it @checkIconGray tst stackItem+itemIconGray(A6) ; end else if (itemIconGray=true) then beq.s @haveTransform ; EQ -> ProcessMgr doesnÕt was it gray either @mustDisable moveq #ttDisabled,d1 ; transform := ttDisabled; @haveTransform move.w d1,-(sp) ; Push the transform move.l a1,-(sp) ; Push the icon data handle _IconDispatch move.w (sp)+,d0 ; Return result rts ;--------------------------------------- ; Utility -- BlitHierArrow ;--------------------------------------- ; Blit up the hierarchical arrow ; BlitHierArrow ; calculate where arrow should go move.l a4,-(sp) subq #4, sp move.l sp, -(sp) ; reserve space on stack for result _GetPen move.l (sp)+, d0 ; get y,x swap d0 ; get x,y sub MAscent(a6), d0 ; move up by the font ascent to get top of item swap d0 ; have top, left of where will blit arrow move.l d0, HierArrowRect(a6) ; store top, left lea HierArrow, A4 bsr.s BlitCommon move.l (sp)+,a4 rts ;--------------------------------------- ; Utility -- IsDash ;--------------------------------------- ; IsDash is a utility which tests if an item is the special dash separator. ; It returns the result in the Z-flag IsDash CMP.B #$2D,1(A0) ; first char a dash? BNE.S @NoDash ; No dash, skip. tst.w itemIconSize(A1) ; Does it have an icon? <2.2> BNE.S @NoDash ; No dash, skip. TST.B itemCmd(A1) ; Does it have a cmd? @NoDash RTS ; Return result in Z ;---------------------------------------- ; Utility -- PushThePort ;---------------------------------------- ; Push the port onto the stack (subroutine to save code). PushThePort MOVE.L (SP),-(SP) ; copy return address PEA 4(SP) ; write over old return address with port _GetPort ; get the port, but leave it on the stack rts ;---------------------------------------- ; Utility -- DrawTheItem ;---------------------------------------- ; separated actual drawing routine out so ; can ChooseMsg can call it since we now ; redraw the selected item rather than ; just inverting it. ; ; Used to be: ; On entry: d3 ItemÕs baseline, top of item + fontÕs ascent ; d4 Item Number ; d5 left edge, pixels ; d6 right edge, pixels ; a2 itemÕs string pointer ; a4 itemÕs properties pointer ; -- GetSizes has been called ; ; Now: ; On entry: D3 ItemÕs baseline, top of item + fontÕs ascent ; D4 Item Number ; A0 Menu rectangle pointer (for left and right edge) ; A3 Menu handle ; -- GetSizes has been called ; -- GetItemRecord has been called ; -- D5, D6, A2, and A4 are all set up just like old times ; ; On exit: Z Set if the item does not exist ; DrawTheItem MOVE.W Left(A0), D5 ; Get the left edge MOVE.W Right(A0), D6 ; Get the right edge MOVE.W D4, D0 ; Prepare item number for GetItemRecord MOVE.L (A3), A0 ; Dereference menu handle BSR GetItemRecord ; Go get it BEQ NoDrawItem ; Skip whole mess if not a valid item MOVE.L A0, A2 ; Store string pointer in A2 MOVE.L A1, A4 ; And properties in A4 bsr SaveCurrentColors ; save fore/back colors in stackframe move #mctRGB2, colorOffset(a6) ; use the item color if there is an entry bsr SetColors ; set colors BSR.S EnableTest ; Check the enabled state of this item SNE enableState(a6) ; Set TRUE if not enabled MOVE.L A2, A0 ; Get string pointer for IsDash MOVE.L A4, A1 ; And properties too BSR.S IsDash ; Is it a dash? BNE NotDash ; If not, draw item normally ;--------------------------------------- ; Utility -- DrawDash ;--------------------------------------- ; handle the case of a dash item by drawing a line DrawDash ;ksm37 move #mctRGB2, colorOffset(a6) ; use the item color if there is an entry ;ksm37 bsr SetColors ; set colors TST.B onColorMachine(A6) BEQ.S @ditherGrayLine ; FUNCTION GetGray(device: GDHandle; backGround: RGBColor; VAR foreGround: RGBColor): BOOLEAN; sub #12,sp ; put (back,fore) colors on stack pea (sp) _GetBackColor pea 6(sp) _GetForeColor subq #6,sp ; Make room for result & gdhandle move.l MMenuRect(a6),-(sp) ; Global menu rect _GetMaxDevice ; leave main device on stack lea 6(sp),a0 ; Get address of back color move.l a0,-(sp) ; Push back pea 6(a0) ; Push fore _GetGray ; Do we have a gray? move.b (sp)+,d0 bne.s @rgbGrayLine ; NE (TRUE) means we have the gray add #12,sp bra.s @ditherGrayLine @rgbGrayLine addq #6,sp ; Get rid of back color pea (sp) _RGBForeColor addq #6,sp ; Get rid of fore color bra @b @ditherGrayLine MOVE.L (A5),A0 ; get QuickDraw globals PEA Gray(A0) ; set pattern to gray _PenPat @b MOVE.W D3,-(SP) ; save y position MOVE.W D5,-(SP) ; push x position MOVE.W MFHeight(A6),D0 ; center the dash LSR.W #1,D0 ; by backing up to top of cell SUB.W MAscent(A6),D0 ; and going halfway down ADD.W D0,D3 ; add to current position MOVE.W D3,-(SP) ; push new y position _MoveTo MOVE.W D6,-(SP) ; push right edge MOVE D3,-(SP) ; push y _LineTo ; draw the line MOVE.W (SP)+,D3 ; restore baseline _PenNormal ; This wonÕt create a new pixpat @oldMac2 BRA DoneDrawItem ; dive back into mainstream NotDash ; IF NOT forROM THEN ; only do this for System builds, not ROMs <33> rb TST.B onColorMachine(a6) ; on color machine? BEQ.S @skipPenMode ; no, skip _TextMode TST.B enableState(a6) ; <34> BNE.S @skipPenMode ; Yes=>go set mode MOVEQ #grayishTextOr,D0 ; disabled item on color machine MOVE.W D0,-(SP) _TextMode @skipPenMode ; <51=BRC#79297> ; ENDIF ; { NOT forROM } <33> rb ADDQ.W #2, D5 ; Add the 2 pixels here instead move.w itemIconSize(A4),D0 ; does it have an icon? <2.2> beq.s DrawMark ; if not, skip ; for icon, center the baseline in the itemÕs rect Bsr GetItemHeightA4 ; get itemÕs height in D0 SUB.W MFHeight(A6),D0 ; subtract font height <1Aug85> MOVE.W D0,D7 ; save font height in D7 <1Aug85> LSR.W #1,D0 ; get delta <1Aug85> ADD.W D0,D3 ; keep baseline in D3 <1Aug85> ; --------------------- draw the mark -------------------------- DrawMark CMP.W #NoMarkSmallIconCmd,itemIconSize(A4) ; small icon with no mark? BEQ.S CHKDRAWICON ; no mark if so MOVE.W MWidMax(A6),D0 ; get char width <27Sep85> BSR TweakPos ; get hpos into D2, adjust d5,d6 <27Sep85> TST.B itemMark(A4) ; does it have a mark? BEQ.S CHKDRAWICON ; if not, skip MOVE.W D2,-(SP) ; MOVE D3,-(SP) ; push v position _MoveTo ; position pen move #mctRGB1, colorOffset(a6) ; tell SetColors to get the MARK bsr SetColors ; set mark colors CLR D0 ; clear out high part MOVE.B ITEMMARK(A4),D0 ; get the mark character MOVE.W D0,-(SP) ; push it _DrawChar ; --------------------- draw the icon -------------------------- CHKDRAWICON ; when itemIconSize == ShrunkenIconCmd ($1D) we draw the icon into a 16x16 ; area instead of the normal 32x32 ; when itemIconSize == SmallIconCmd ($1E) we draw a small icon into a 16x16 ; area ; ; when itemIconSize == FamilyIconCmd ($20) we draw an icon suite into a 16x16 area MOVE.L A4, A1 ; Copy A4 into A1 for GetIconSize BSR GetIconSize ; Get the height, width of the icon TST.L D1 ; Is there one? BEQ DrawCmdChar ; if not, skip ; draw the icon. First back up to top of rect LEA TEMPRECT,A0 ; get pointer to rectangle MOVE.L A0,-(SP) ; push rect for plotIcon call MOVE.L D1, -(SP) ; Save height, width on stack MOVE.W D3,D1 ; get baseline <1Aug85> MOVE.W D7,D0 ; font height from D7 <15Oct85> LSR.W #1,D0 ; get delta <15Oct85> SUB.W D0,D1 ; subtract delta <15Oct85> SUB.W MAscent(A6),D1 ; subtract font height <15Oct85> ADDQ.W #1,D1 ; down from top of item <15Oct85> MOVE.L (SP)+, D0 ; Restore it into D0 instead MOVE.W D1,(A0)+ ; and stuff top <1Aug85> MOVE.W D5, D2 ; Assume left-to-right CMP.W #NoMarkSmallIconCmd,itemIconSize(A4) ; small icon with no mark? BNE.S @CheckJust ; no, continue ADDQ.W #1,D2 ; add 1 pixel to left indent @CheckJust TST.B TESysJust+1 ; Test for right just BPL.S @LeftRight ; Guessed right MOVE.W D6, D2 ; Otherwise get right side SUB.W D0, D2 ; And subtract out width CMP.W #NoMarkSmallIconCmd,itemIconSize(A4) ; small icon with no mark? BNE.S @LeftRight ; no, continue SUBQ.W #1,D2 ; subtract one pixel from left @LeftRight ; MOVE.W D2,(A0)+ ; push left <27Sept85> MOVE.L -4(A0),(A0) ; copy bottom right ADD.L D0, (A0) ; Add height, width to get bottom, right ADD.W MSpaceWidth(A6), D0 ; Add single space to width of icon BSR TweakPos ; get hpos into D2, adjust D5,D6 LEA TEMPRECT,A0 BSR CenterRectInMFHeight ; Check to see if we have a suite/cached icon cmpi.w #FamilyIconCmd, itemIconSize(A4) ; is there an icon suite/cache? bne.s @skipPlotFamiliarIcon ; no -> branch bsr SetColors ; set up the colors for a non-inverted item move.l (sp)+,a0 ; Put rect ptr into a0 <54> move.l itemIconHandle(a4),a1 ; Data handle into a1 <54> moveq #atAbsoluteCenter,d1 ; Put in the exact center <54> move.w #PlotSUITE,d0 ; Use _PlotIconSuite <54> bsr.s IconPlotFromHandle ; <54> bra DonePlot ; and we're done @skipPlotFamiliarIcon tst.b onColorMachine(a6) beq.s @DoPlotIcon CMP.W #NoMarkSmallIconCmd,itemIconSize(A4) ; small icon with no mark? <51> beq.s @DoPlotIcon ; No mark small icons are never cicnÕs <51> ; attempt to get color icon first and if unsuccessful then get regular icon tst.b itemIcon(a4) ; icon specÕd in resource? <2.2> beq.s @DoPlotIcon ; jump if not <2.2> subq #4, sp ; make room for function result move #$0100, d0 ; menu icons are 256-511 move.b itemIcon(a4), d0 ; get icon number - 256 move d0, -(sp) ; push icon number _GetCIcon move.l (sp)+, iconHandle(a6) ; get icon handle, and save in stackframe beq.s @DoPlotIcon ; no color icon, must be regular icon ;_______________________________________________________________________________________________<48> ; This is the new plotting stuff for cicn's. It uses the new Icon Utils call PlotCIconHandle. ; Color icons from cicn resources will NO LONGER invert. It looks like sh*t anyway and ; is inconsistent with the way we draw icon suites. So, here goes.. ; The fgnd and bkgnd colors are preserved across the call. ; FUNCTION PlotCIconHandle(theRect: Rect; align: INTEGER; transform: INTEGER; ; theCIcon: CIconHandle): OSErr; ; Now plot that cicn using DaveÕs cool new call made just for the MDEF... move.l (sp)+,a0 ; Save off the rectptr (already on stack) move.l iconHandle(a6),a1 ; <54> moveq #atNone,d1 ; alignment <54> move.w #PlotCIcon,d0 ; Use _PlotCIconHandle <54> bsr.s IconPlotFromHandle ; <54> ;_______________________________________________________________________________________________<48> move.l iconHandle(a6), -(sp) ; dispose of CIcon _DisposCIcon bra.s DrawCmdChar ; and continue @DoPlotIcon ;_______________________________________________________________________________________________<48> moveq #1,d2 ; d2=0 means plot SICN, d2<>0 means plot large MOVE.W #$0100,D1 ; d1 is base of icon IDs; std. menu icons are 256-511 move.l #'ICON',a1 ; a1 is resource type for icon ; check for special icons - small, or no-mark small move.w itemIconSize(A4),d0 ; Icon kind is in d0 cmpi.w #SmallIconCmd, d0 ; is it a small icon? beq.s @stdSmallIcon ; yes -> get std. small icon cmpi.w #NoMarkSmallIconCmd, d0 ; is it a small icon with no mark? bne.s @gotIconInfo ; no -> get std. icon @noMarkSmallIcon MOVE.W #genericIconBase,d1 ; StdFile icons begin at genericIconBase @stdSmallIcon moveq #0,d2 ; use SICN plotting move.l #'SICN',a1 ; use SICN resource @gotIconInfo ; calculate icon ID moveq #0,d0 MOVE.B itemIcon(A4),D0 ; Set up the icon offset ADD.W d1,d0 ; get the resource to plot subq #4,sp ; Make room for GetResource result move.l a1,-(sp) ; push rsrc type MOVE.W D0,-(SP) ; push icon number _GetResource ; get the icon handle (keep it on stack) move.l (sp)+,d0 ; did we get one? ; get out of here if there was no resource movea.l (sp)+,a0 ; Get rect ptr off stack without changing ccÕs beq.s DonePlot move.l d0,a1 ; Put the rsrc handle into a1 <54> moveq #atAbsoluteCenter,d1 ; alignment <54> move.w #PlotICON,d0 ; Use _PlotIconHandle <54> tst.w d2 ; Which plot to use? <54> bne.s @useICON ; NE means plot ICON <54> move.w #PlotSICN,d0 ; Use _PlotSICNHandle <54> @useICON bsr.s IconPlotFromHandle ; Go do the plot <54> ;_______________________________________________________________________________________________<48> DonePlot ; ------------ draw the command character or hierarchical arrow ------------------ ; There can only be one or the other, not both DrawCmdChar TST.B itemCmd(A4) ; is there a command key? <2.2> BNE.S NeedPadding ; yes <2.2> TST.W itemHierarchicalID(a4) ; is there a H Menu? <2.2> BEQ.S DRAWITEXT ; if not, skip NeedPadding move #mctRGB3, colorOffset(a6) ; tell SetColors to get the CMD bsr SetColors ; set colors for command character MOVE.W MWidMax(A6),D0 ; get width <27Sep85> ADD.W D0,D0 ; *2 <27Sep85> SUB.W D0,D6 ; assume it will go on right <27Sep85> MOVE D6,-(SP) ; put it on stack <27Sep85> TST.B TESysJust+1 ; check for right just <11oct85> BPL.S @1 ; => guessed right <27Sep85> ADDQ #2,D5 ; else indent a little FIRST MOVE.W D5,(SP) ; else do it from left <27Sep85> ADD.W D0,D5 ; and bump left position <27Sep85> ADD.W D0,D6 ; else back up for icon <27Sep85> @1 MOVE.W D3,-(SP) ; push vertical position _MoveTo ; position pen ; if this item has a sub-menu, then blit an arrow in the command key ; field to indicate its existence . tst.w itemHierarchicalID(a4) ; is there a H Menu? <2.2> beq.s @DoCmdKey ; no, so do as key equivalent <2.2> bsr.s BlitHierArrow ; draw the Hierarchical arrow bra.s DrawIText ; continue @DoCmdKey MOVE.B TESysJust+1,D1 ; need special justification? EXT.W D1 ; make it a signed word BNE.S @JustifiedCmd ; => yes MOVE.W #commandMark,-(SP) ; push command character <15Feb85> _DrawChar ; draw the character CLR.W D0 ; clear high part MOVE.B itemCmd(A4),D0 ; get command character MOVE.W D0,-(SP) ; push command char _DrawChar ; draw it BRA.S DrawIText @JustifiedCmd ; draw commandletter/propeller CLR D0 ; clear high part MOVE.B itemCmd(A4),D0 ; get command character MOVE.W D0,-(SP) ; push command char _DrawChar ; draw it MOVE.W #commandMark,-(SP) ; push command character <15Feb85> _DrawChar ; draw the character ; ---------------- draw the text of the item (position in D5) ---------------------- DRAWITEXT move #mctRGB2, colorOffset(a6) ; tell SetColors to get the TEXT bsr SetColors ; set colors for text CLR D0 ; clear it out MOVE.B ITEMSTYLE(A4),D0 ; get the style parameter beq.s @noFaceChg ; <51=BRC#79297> MOVE.W D0,-(SP) ; Set style parameter _TextFace ; get into that face @noFaceChg ; <51=BRC#79297> ; if there is a script for this font then set it move.w itemScript(a4), d0 ; get script number <2.2> bmi.s @1 ; skip if default <2.2><20> bsr SetScriptFont ; no, set the proper font @1 MOVE.B TESysJust+1,D1 ; need special justification? <11oct85> EXT.W D1 ; make it a signed word <11oct85> BNE.S @DrawIntl ; => yes <27Sep85> MOVE.W D5,-(SP) ; and baseline left <27Sep85> MOVE.W D3,-(SP) ; else push baseline vertical <27Sep85> _MoveTo ; push the pen <27Sep85> ;------------------------------------------------------------ ; ; NOTE NOTE NOTE NOTE ; If menu message is not mDrawItemMsg, we will immediately return from this routine ; JSR TruncateString ; D5 left, D6 right, A2 the string ; returns pointer to tempString(A6) where ; the truncated copy is ; may also set the condense bit in the current port ; ; NOTE that style cleanup is done at @2 below ; ;------------------------------------------------------------ MOVE.L A2,-(SP) ; point to the string <27Sep85> _DrawString ; and draw it <27Sep85> BRA.S @2 ; ; do International stuff here if TESysJust is negative ; @DrawIntl LEA TempRect,A0 ; build rect for TextBox <27Sep85> SUBQ #1,D5 ; textBox indents by one <27Sep85> MOVE.W D3,(A0) ; get y position <27Sep85> MOVE.W MAscent(A6),D0 ; move up to top of rect <27Sep85> SUB.W D0,(A0)+ ; <27Sep85> MOVE.W D5,(A0)+ ; D5 is left <27Sep85> MOVE.W D3,(A0) ; as top and bottom <27Sep85> MOVE.W MDescent(A6),D0 ; and move down to bottom <27Sep85> ADD.W D0,(A0)+ ; <27Sep85> MOVE.W D6,(A0) ; and setup right <27Sep85> ;------------------------------------------------------------ ; ; NOTE NOTE NOTE NOTE ; If menu message is not mDrawItemMsg, we will immediately return from this routine ; JSR TruncateString ; D5 left, D6 right, A2 the string ; returns pointer to tempString(A6) where ; the truncated copy is ; may also set the condense bit in the current port ; ; NOTE that style cleanup is done at @2 below ; ;------------------------------------------------------------ MOVEQ #0,D0 ; get length <27Sep85> MOVE.B (A2)+,D0 ; into D0 <27Sep85> MOVE.L A2,-(SP) ; push text pointer <27Sep85> MOVE.L D0,-(SP) ; and length <27Sep85> PEA TempRect ; push rect of rects <27Sep85> MOVE.W D1,-(SP) ; and justification word <11oct85> _TextBox @2 ; note that TruncateString may truncate the string and set the condensed bit ; so the style cleanup is necessary belowÉ MOVE.B ITEMSTYLE(A4),d0 ; did we change the face? bne.s @styleCleanup ; Force clean of of face <63> move.w itemScript(a4), d0 ; did we change the font? <62><63> bge.s @styleCleanup ; Force clean of of face/font <62><63> CMP.W #mDrawItemMsg, mMessage(a6) ; <51=BRC#79297> BNE.S @nostyleCleanup ; always clean up on a drawItem msg ; <51=BRC#79297><63> @styleCleanup CLR.L -(SP) ; push empty set for TextFace and TextFont _TextFace ; restore textface to normal _TextFont ; restore textfont to normal @nostyleCleanup ; <51=BRC#79297> ; if the item is disabled, gray it out <29> TST.B enableState(A6) ; If enabled, donÕt bitclear or reset textmode BNE.S DoneDrawItem ;IF (not forROM) THEN rb TST.B onColorMachine(A6) ; If color, we drew in gray so donÕt bitclear BNE.S @fixcolor ;ENDIF rb BSR.S BitClearItem ;IF (not forROM) THEN rb @fixColor MOVE.W #srcOr,-(SP) _TextMode ;ENDIF rb DoneDrawItem bsr ResetPreviousColors ; restore colors saved in the stackframe MOVEQ #1, D0 ; Force Z flag off for normal return NoDrawItem ; ; Z flag is already set rts ; and return to caller ;--------------------------------------- ; Utility -- BitClearItem ; attempt to speed graying of menu items ;--------------------------------------- ; Paint the item with gray. Speed up is about 20%!! ; ; On Entry: D4 item number ; BitClearItem movem.l d3/d7, -(sp) ; save work registers TST.W itemIconSize(A4) ; does it have an icon? <2.2> BEQ.S @1 ; skip if it doesnt MOVE.W D7,D0 ; get delta height LSR.W #1,D0 ; divide by 2 SUB.W D0,D7 ; and get remainder ADD D7,D3 ; bump the rest of the difference for icon @1 ADD MFHeight(A6),D3 ; bump to next baseline LEA TEMPRECT,A0 ; get pointer to temporary rectangle MOVE.L MMenuRect(a6), A1 ; get pointer to menu rect MOVE.L (A1),(A0) ; copy menuRect into tempRect MOVE.L 4(A1),4(A0) SUB MAscent(A6), D3 ; move up by the font ascent to get bottom of item MOVE D3, Bottom(A0) ; store as bottom Bsr GetItemHeightA4 ; get item height into D0 Sub.W D0, D3 lea TempRect,a0 ; get rectangle in A0 <1.7> MOVE D3,top(a0) ; D3 has the height <1.6> <1.7> BSR GRAYRECT ; bit clear tempRect with gray @ClearDone movem.l (sp)+, d3/d7 ; restore work registers rts ;--------------------------------------- ; Utility -- SetScriptFont ;--------------------------------------- ; Input d0: script number ; ; set the scriptÕs base font. No need to check if script manager is installed ; since AddResMenu has already done that ; SetScriptFont clr.l -(sp) ; make room for long result ; make d0 an argument, the script number and.w #$00FF,d0 ; get bottom byte for script move d0, -(sp) ; push script number move #smScriptSysFond, -(sp) ; push base font verb _GetScript move.l (sp)+, d0 ; get result blt.s @verbErr ; verb error if d0 < 0 move d0, -(sp) ; push font number _TextFont @verbErr rts ;--------------------------------------- ; Utility -- GetItemRecord ;--------------------------------------- ; GetItemRecord is the main utility used for accessing the menu item data structure. ; It has a register interface to save code. ; ; On entry: A0 points to a menuInfo block, ; D0 has the item number of interest. ; ; On exit: A0 points to the item string of interest ; A1 points to that itemÕs attribute byte list. ; If the item canÕt be found, A0 and A1 both return NIL. ; ; Eats: D0 and D1 ; ; TODO: If this is called inside a loop, we have a factorial function!! ; Therefore look where this is called from and see if we canÕt be smarter about ; how to move thru the menulist ;<51> ; We are smarter now because we just cache the last item we used ; THEREFORE this routine SHOULD be used to index thru the ; menu data structure in ALL cases! GETITEMRECORD TST D0 ; make sure item number is valid BLE.S NOITEM ; if itÕs not, donÕt bother ;<34>begin move.w D0,irTmpItemNo(A6) ; save off the initial item number move.w irItemNo(A6), D1 beq.s @oldEntry cmp.w D0,D1 ; is this the one we saved? beq.s @cacheSavedTheDay ; EQ means weÕve cached this one bgt.s @oldEntry ; GT means the cache is past D0 ; Well, our cache is somewhere before D0, preflight loop entry sub.w D1,D0 ; Offset the item number for loop entry move.l irItemAddr(A6),A1 ; Get that itemÕs address moveq #0,D1 ; clear D1 for byte arithmetic move.b (A1)+,D1 ; get length that item addq #4,D1 ; Fudge it for the initial condition add D1,A1 ; Point past properties bra.s GETILOOP @cacheSavedTheDay move.l irItemAddr(A6),A1 tst.b (A1) ; is this the NIL item? beq.s NOITEM ; if so, we really didnÕt get one move.l a1,a0 ; put the item string into a0 lea stackItem(a6),a1 ; cached attributes to A1 bra.s EXIT ;<34>end @oldEntry MOVEQ #0,D1 ; clear D1 for byte arithmetic LEA MENUDATA(A0),A1 ; get menuData handle MOVE.B (A1)+,D1 ; get title length ADD D1,A1 ; skip over title string ; here is the item search loop. A1 points to the beginning of the next item. GETILOOP SUBQ #1,D0 ; is this the one weÕre looking for? BEQ.S GOTITEM ; if so, we got it MOVE.B (A1)+,D1 ; get length of current item BEQ.S NOITEM ; length zero marks end of list ; ADDQ #4,D1 ; there are 4 bytes of item properties ADD D1,A1 ; bump to next item BRA.S GETILOOP ; loop till done ; the item couldnÕt be found so return NIL NOITEM SUB.L A0,A0 ; zero A0 MOVE.L A0,A1 ; and A1 too EXIT MOVE.L A0,D0 ; and set the z-flag <2.2> 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.w irTmpItemNo(A6), irItemNo(A6) ; Save off the item weÕve cached <34> move.l A1,irItemAddr(A6) ; Save off the address <34> BSR.S ExpandItem ; puff item up to full size <2.2> BRA.S EXIT ; and leave <2.2> ; ExpandItem. Take basic menu item data and fill in more with _GetAuxMenuItem. ; New in <2.1>. ; On entry: A1 points to a menu item ; A3 is the menu handle ; ; On exit: A0 points to the item string of interest ; A1 points to that itemÕs attribute byte list (on the stack) ; Eats D0, D1 ExpandItem ; copy menu item attributes to stack, split into distinct fields (unroll the variant in itemCmd). movem.l d2/a2,-(sp) ; save regs <2.2> ; Clear out entire MF data area first lea stackItem(a6),a0 ; address of working copy moveq #0,d0 move #(Sizeof_extendeditem/2)-1,d0 @loop clr.w (a0)+ dbf d0,@loop move.l a1,a2 ; move pointer to safe register moveq #0,D1 ; clear D1 for byte arithmetic move.b (a1)+,d1 ; get length add.w d1,a1 ; bump to item properties lea stackItem(a6),a0 ; address of working copy ; set defaults (one at a time, to avoid odd-address problems since string be any length) move.b (a1)+,(a0)+ ; copy attribute byte - itemIcon move.b (a1)+,(a0)+ ; copy attribute byte - itemCmd move.b (a1)+,(a0)+ ; copy attribute byte - itemMark move.b (a1)+,(a0)+ ; copy attribute byte - itemStyle lea stackItem(a6),a0 ; address of working copy, again move.w #iuSystemScript,itemScript(a0) ; set default (negative) for itemScript <20> ; check for script code moveq #0,d1 ; clear the air move.b itemCmd(a0),d1 ; get record variant field cmp.w #ScriptMenuCmd,d1 ; is there a script code? bne.s notScripted ; jump if not clr.w itemScript(a0) ; clear out for wordizing the byte <20> move.b itemIcon(a0),itemScript+1(a0) ; if scripted, icon has script number clr.b itemIcon(a0) ; reset field to say "no icon" bra.s doneConvert ; rejoin ; check for hierarchical item notScripted cmp.w #HMenuCmd,d1 ; hierarchical menu? bne.s notHierarchical ; jump if not move.b itemMark(a0),itemHierarchicalID+1(a0) add.w #256,itemHierarchicalID(a0) ; force h-menu id to be nonzero (h-menu base id = 256) <51=BRC#80417> clr.b itemMark(a0) ; reset to say "no mark" clr.b itemCmd(a0) ; reset to say "no command key" bra.s unsizedIcon ; go do the icon ; check for icon and icon type notHierarchical cmp.w #ShrunkenIconCmd,d1 ; shrunken icon? beq.s sizedIcon ; jump if so cmp.w #SmallIconCmd,d1 ; small icon? beq.s sizedIcon ; jump if so cmp.w #NoMarkSmallIconCmd,d1 ; small icon with no mark? beq.s sizedIcon ; jump if so unsizedIcon tst.b itemIcon(a0) ; is there an icon? beq.s getAuxdata ; jump if not move.w #LargeIconCmd,itemIconSize(a0) ; save default icon type bra.s getAuxData ; and continue (donÕt clear itemCmd!) sizedIcon move.w d1,itemIconSize(a0) ; copy type to proper field doneConvert clr.b itemCmd(a0) ; reset field to say "no command key" getAuxData tst.w expandItemErr(a6) ; did we get an error for this menu? bne.s @skipAuxCall ; Need to check if Process Mgr is installed in case we are called at <53> ; boot time from things like StdFile (InitPicker, etc.) <53> tst.b processMgrIn(a6) ; Is Process Mgr installed? <53> bne.s @pmgrInstalled ; NE means it is <53> tst.b processMgrChkd(a6) ; Have we done Process Mgr check yet? <53> bne.s @skipAuxCall ; NE means we did and it isnÕt there! <53> st.b processMgrChkd(a6) ; Show we have done Process Mgr check <53> move.l a0,-(sp) move.w #$009F, d0 ; load _Unimplemented number <53> _GetTrapAddress ; load _Unimplemented address <53> move.l a0, d1 ; copy routine address <53> move.w #$008F, d0 ; load OSDispatch number <53> _GetTrapAddress ,newTool ; load OSDispatch address <53> cmp.l a0, d1 ; Process Mgr installed? <53> sne.b d0 ; Ones if Process Mgr installed <53> move.l (sp)+,a0 ; Restore saved register <53> move.b d0,processMgrIn(a6) ; was Process Mgr installed? <53> beq.s @skipAuxCall ; EQ means unimplemented, so skip call <53> @pmgrInstalled ; <53> subq.l #2,sp ; room for return result move.l a3,-(sp) ; push menu handle move.l a2,-(sp) ; push pointer to menu item pea itemIconHandle(a0) ; push buffer address move.l #Sizeof_auxdata,-(sp) ; push buffer size _GetAuxMenuItem ; get the extra info move.w (sp)+,expandItemErr(a6) ; Save off the error code @skipAuxCall move.l a2,a0 ; point at name (in list item) lea stackItem(a6),a1 ; point at the (extended) attributes tst.l itemIconHandle(a1) ; icon handle known now? beq.s doneExpand ; jump if not clr.b itemIcon(a1) ; nuke unneeded resource # doneExpand movem.l (sp)+,d2/a2 ; restore regs <2.2> rts ; return to sender ;---------------------------------------------------------------------------------------- ; ; Msg #2 -- Calc Menu Size ; ;---------------------------------------------------------------------------------------- ; Calculate the menu size for the given text menu. The handle is in A3. ; ; DONE: Menus with icons did not show scroll arrows properly after you had ; scrolled all the way up, then start to scroll down again. The reason ; was that the menu height is not an even multiple of MFHeight. ; This code returns an even multiple of MFHeight if the menu scrolls. DoCalcMsg ; IF NOT forROM THEN ; <2.2> rb BSR.S PushThePort ; CMP.W #$3FFF, ROM85 ; color machine ? TST.B onColorMachine(A6) ; color machine ? BEQ.S @SetBWPort ; MOVE.L WMgrCPort, -(SP) ; get color port BRA.S @SetPort ; @SetBWPort ; MOVE.L WmgrPort,-(SP) ; push the wmgr port, do not use color port here. @SetPort ; _SetPort ; set it ; ENDIF ; if NOT forROM rb ; since calc msg could be called at any time, we need to reset the wmgrÕs textfont here else ; could get incorrectly sized menus clr.l -(sp) ; clear stack for TextFont/Face <51=BRC#79297> _TextFont ; use system font in menus <51=BRC#79297> _TextFace ; use standard face in menus <51=BRC#79297> bsr GetSizes ; get font sizes from wmgr port BSR.S PushThePort MOVE.L (SP)+, A0 ; Put it in A0 ; MOVE.L WMgrPort,A0 ; get the port <27Sep85> MOVE.W PortRect+bottom(A0),D5 ; get the screen bottom <27Sep85> SUB.W portRect+top(A0), D5 ; subtract the top ; the maximum size for a menu is screen height minus menubar height minus a fudge factor. GetMBHeight SUB.W MBarHeight,D5 ; get what low memory says sub #16, d5 ; hierarchical menus need a little more margin MOVEQ #0,D6 ; set initial to 0 IF 0 THEN ; We now call GetItemRecord to index thru the items (itÕs fast now) ; <51=BRC#79297> MOVEQ #1,D0 ; find item 1 MOVE.L (A3),A0 ; point to the menuRecord BSR.S GetItemRecord ; point to first item BEQ DoCalcDone1 ; if zero, weÕre done MOVE.L A0,A4 ; keep pointer in A4 ENDIF MOVEQ #1,D4 ; D4 is the item number counter ; <51=BRC#79297> ; ; here is the main loop of calcMenuSize. Process each item one at a time, keeping the ; height and maximum width in D6 ; CMLOOP MOVE.L D4,D0 ; find current item record ; <51=BRC#79297> MOVE.L (A3),A0 ; point to the menuRecord ; <51=BRC#79297> BSR.S GetItemRecord ; point to first item ; <51=BRC#79297> BEQ DoCalcDone1 ; if zero, weÕre done ; <51=BRC#79297> MOVE.L A0,A4 ; keep pointer in A4 ; <51=BRC#79297> MOVEQ #0,D7 ; set "extra" width to zero MOVE.L (A3),A0 ; handle -> pointer MOVEQ #0,D0 ; clear out high part MOVE.B (A4),D0 ; get length of item BEQ DoCalcDone ; if zero, weÕre done with this menu ; handle the vertical BSR GetItemHeight ; get height of item into D0 SWAP D1 ; Get width of icon into low word MOVE.W D1, D7 ; Copy width into D7 ADD.W MSpaceWidth(A6), D7 ; Add in width of a single space @0 SWAP D6 ; get vertical into low word <27Sep85> ADD.W D0,D6 ; increment vertical height <27Sep85> CMP.W D5,D6 ; past bottom of screen? <27Sep85> BLT.S @1 ; => no <27Sep85> SUB.W D0,D6 ; yes, donÕt make menu taller <27Sep85> ; handle the horizontal @1 SWAP D6 ; but get vertical in high first <27Sep85> BSR GetItemWidth ; calc the width of the requested item < kaz #44> CMP D0,D6 ; compare with maxWidth BGE.S CALCNEXT ; if max is bigger, go process next one MOVE D0,D6 ; this one was the biggest ; ; go process next item; loop till we get a null one ; CALCNEXT IF 0 THEN ; Calling GetItemRecord keeps us from calling ExpandItem unnecessarily. <51=BRC#79297> MOVEQ #0,D0 ; zero high part MOVE.B (A4),D0 ; get the length of current item LEA 5(A4,D0),A4 ; point to the next item MOVE.L a4,a1 ; for expansion <2.2> BSR ExpandItem ; et, voila! <2.2> ENDIF ADDQ #1,D4 ; Point to next item <51=BRC#79297> BRA CMLOOP ; loop till done ; weÕve scanned all the items update menuHeight and menuWidth DoCalcDone ADDQ.W #4,D6 ; add some extra for right margin DoCalcDone1 ; if NIL menu, return 0 ; Ensure that the menu is not too wide. BSR.S PushThePort MOVE.L (SP)+, A0 ; Put it in A0 MOVE.W portRect+Right(A0), D0 ; Get right edge SUB.W portRect+Left(A0), D0 ; Subtract left edge to get width SUB.W #16, D0 ; Subtract a little more for margin CMP.W D0, D6 ; Is menu too wide? BLE.S @1 ; Nope, move along MOVE.W D0, D6 ; Too wide, clip its wings @1 ; MOVE.L (A3),A0 ; get menu pointer MOVE.W D6,MENUWIDTH(A0) ; update menu width SWAP D6 @SizeOK MOVE.W D6,MENUHEIGHT(A0) ; update menu height ; GetItemWidth/GetItemHeight preserve TextFace internally now <51=BRC#79297> ; CLR.W -(SP) ; better restore style to normal ; _TextFace ; set the style ; IF NOT forROM THEN ; <2.2> rb _SetPort ; restore original grafPort ; ENDIF ; if NOT forROM rb rts ; all done! so return to dispatcher ;---------------------------------------------------------------------------------------- ; ; Msg #3 -- Calc TopMenuItem and MenuRect so that the top of PopUpItem is at TopLeft ; ;---------------------------------------------------------------------------------------- ; Begin by calculating how far the top of WhichItem is from the top of the menu. ; Then place the menu. The various possibilities are: ; 1. The whole menu fits on the screen and PopUpItem lines up with TopLeft ; 2. The whole menu fits on the screen and PopUpItem cannot line up with TopLeft without ; causing the menu to scroll. In this case adjust menuRect so that complete menu is ; is on the screen, but PopUpItem is as close to TopLeft as possible. ; 3. The whole menu is not on the screen. In this case adjust the menuRect so that as much ; of the menu is showing as possible on the screen, and position PopUpItem so that ; it is showing and as close as possible to TopLeft. ; ; Return the MenuRect and TopMenuItem. TopMenuItem is returned in the VAR PopUpItem param.; ; ; Historical Note: It would be desireable to have popups change vertical size as they scrolled, ; instead of having all that white space when the scrolling menu is first ; displayed. The reason for this is due to the design of the MBDF. ; The MBDF saves the bits behind and draws the drop shadow at the same ; time. If there were two messages instead, one to save the bits behind ; and one to draw the drop shadow, the we could save all of the bits behind ; the menurect, from the top of the screen to the bottom, and then change ; the menuÕs vertical height without worrying about saving more bits each ; time it got bigger. But we canÕt, so... ; ; Pass PopUpItem = 0 and force top of menuRect to Top parameter DoPopUpItemMsg BSR GetSizes ; get font info into the stack MOVE.L MPopUpItem(A6), A4 ; get ptr to PopUpItem MOVE (A4), D3 ; store item in D3 CLR D2 ; top of menu starts at zero CLR D6 ; ditto MOVEQ #1, D4 ; start with first item @Loop CMP D3,D4 ; have we reached the PopUpItem yet? BGT.S @1 ; no ==> continue calculating MOVE D6, D2 ; yes ==> save itemÕs vertical in D2, and continue ; ; We didnÕt reach it yet, so get the height and keep stepping down. ; @1 MOVE.L (A3),A0 ; get menuPtr MOVE D4,D0 ; get item number BSR GetItemRecord ; look it up BEQ.S @LoopComplete ; if item not found then must be end of item list BSR GetItemHeight ; get item height in D0 ADD D0,D6 ; update vertical ADDQ #1,D4 ; bump to next item BRA.S @Loop ; loop till we get to end of item list ; If we couldnÕt find the item then default to item number 1 @LoopComplete TST D2 ; is D2 still zero ? BNE.S @GotItem ; no ==> got the item, and itÕs vertical is in D2 MOVEQ #1, D4 ; yes ==> couldnÕt find item, use item #1 ; Distance from top of menu to top of PopUpItem is now in D2. @GotItem MOVE.L (A3), A0 ; get menu ptr TST.L MenuWidth(A0) ; is the size valid? BPL.S @SkipCalcSize ; yes, so no need to recalc (oooohhhh, recursion) MOVE.L D2, -(SP) ; Save D2 around call MOVE.L A3, -(SP) ; push menu handle _CalcMenuSize ; get valid height and width MOVE.L (SP)+, D2 ; Restore D2 @SkipCalcSize ; ; First check if menu has to scroll, i.e. its height is larger than the screen size ; minus 8 pixels of slop. ; ; Register Usage:-- A0 menuRect ptr ; A1 port ptr ; A2 menu ptr ; A3 menu handle ; A4 PopUpItem ptr ; -- D2 Distance from top of menu to PopUpItem ; D3 PopUpItem ; D4 TopMenuItem ; D5 Desired top of PopUpItem, the "Top" in MLeftTop ; D6 Total menu height, including all menu items ; BSR.S PushThePort MOVE.L (SP)+, A1 ; put port in A1 MOVE.L MMenuRect(A6), A0 ; put ptr to menuRect in A0 MOVE.L (A3), A2 ; put menu ptr in A2 MOVE MLeftTop+2(a6), D5 ; put desired Top of PopUpItem in D5 MOVE D5, D4 ; put TopMenuItem = D5 - D2 in D4 SUB D2, D4 Cmpi.w #0, D3 ; is PopUpItem = 0 ? Bne.s @StdPopUp ; no -> branch Move portRect+Bottom(A1),D0 ; calc max allowable menu height = bottom of Sub D5, D0 ; screen - 8 - Top of PopUpItem Sub #8, D0 Cmp D6, D0 ; is max allowable menu height < total menuHeight ? Blt.s @HasToScroll Bra.S @WontScroll @StdPopUp MOVE portRect+Bottom(A1),D0 ; calculate max allowable menu height based on SUB portRect+Top(A1), D0 ; screen height - 8 pixels of slop ; SUB #8, D0 ; <2.0 BRC#44525> Remove the even value (they never round well) SUB #7, D0 ; <2.0 BRC#44525> This is not enough slop to prevent rounding problems SUB.W MFHeight(A6), D0 ; <2.0 BRC#44525> Subtracting item height gives enough CMP D6, D0 ; is max allowable menu height < total menuHeight ? BLT.S @HasToScroll ; yes ==> has to scroll ;------------------------------------------------------------------------------------------------- ; If here, then the complete menu WILL fit on the screen ;------------------------------------------------------------------------------------------------- ; Check the following possibilities: ; 1. Top and bottom are both on the screen ==> leave it alone, PopUpItem and TopLeft will match ; 2. Top is on screen, bottom is not ==> move bottom of menurect up until it is at least ; 5 pixels above the bottom of the screen. Leave TopMenuItem alone ; 3. Bottom is on screen, top is not ==> move top of menurect down until it is at least ; 5 pixels below the top of the screen. Leave TopMenuItem alone @WontScroll MOVE D4, Top(A0) ; assume TopMenuItem, and top and bottom of menu are ok MOVE D4, (A4) ; return TopMenuItem in VAR PopUpItem MOVE D4, Bottom(A0) ADD D6, Bottom(A0) MOVE portRect+Top(A1),D0 ; get the top of the screen ADD MBarHeight, D0 ; move down 2 pixels from menubar ADD #2, D0 CMP D0, D4 ; is TopMenuItem < 2 pixels below menu bar? BGE.S @ChkBottom ; no ==> therefore Top is ok ; yes ==> therefore move top down by multiple of MFHeight ; until we get at least 2 pixels below the menu bar MOVE D4, D1 ; start at TopMenuItem @TopLoop ADD MFHeight(a6), D1 ; move down to next item CMP D0, D1 ; is top of menu >= 2 pixels below menu bar? BLT.S @TopLoop ; no ==> havenÕt moved top down far enough yet MOVE D1, Top(A0) ; yes ==> store new top ADD D6, D1 MOVE D1, Bottom(A0) ; store bottom of menu BRA.S @AdjustLeftRight ; do left/right adjustment @ChkBottom MOVE D4, D0 ; find bottom of menu = TopMenuItem + total menu height ADD D6, D0 MOVE portRect+Bottom(A1),D1 ; calc bottom of screen - 5 pixels SUB #5, D1 CMP D1, D0 ; is Bottom of menu > 5 pixels above screen bottom ? BLE.S @AdjustLeftRight ; no ==> therefore Bottom is ok too ; yes ==> move bottom up by multiple of MFHeight until ; we get at least 5 pixels above the screen bottom @BotLoop SUB MFHeight(a6), D0 ; move up to next item CMP D1, D0 ; is bottom of menu <= 5 pixels above screen bottom ? BGT.S @BotLoop ; no ==> havenÕt moved bottom up far enough yet MOVE D0, Bottom(A0) ; store bottom SUB D6, D0 ; calc top of menu MOVE D0, Top(a0) BRA.S @AdjustLeftRight ; do left/right adjustment ;------------------------------------------------------------------------------------------------- ; If here then the complete menu WILL NOT fit on the screen ;------------------------------------------------------------------------------------------------- ; Leave TopMenuItem alone, but calculate where menurect should go so that when the items scroll ; they fill up the menu exactly, i.e. as the menu is scrolled, TopMenuItem will match the ; top of the menu rect at some point exactly. If we donÕt do this there may be strange ; behavior when the menu is scrolled completely down, i.e. the top item is showing. ; ; If PopUpItem = 0 then force top of menu to be at Top/Left ; ; @HasToScroll MOVE D4, (A4) ; return TopMenuItem in VAR PopUpItem Move D4, D1 ; set up D1 Move D1, Top(A0) ; assume PopUpItem = 0 and store Top of menuRect Cmpi.w #0, D3 ; is PopUpItem = 0 ? Beq.s @CalcBottom ; yes -> branch and only calc the bottom of the rect MOVE portRect+Top(a1), D0; calc 2 pixels below the top of the screen ADDQ #2, D0 ; CMP D0, D4 ; is TopMenuItem > 2 pixels below top of screen? BLE.S @CalcBelow ; no ==> branch and calc top of menuRect as ; (MFHeight x N) **BELOW** TopMenuItem ; yes ==> fall thru and calc top of menuRect as ; (MFHeight x N) **ABOVE** TopMenuItem ; ; Start at TopMenuItem, and move **UP** by increments of MFHeight until we reach at ; least 2 pixels below the menubar. ; MOVE D4, D1 ; start at TopMenuItem @UpLoop SUB MFHeight(a6), D1 ; move up one MFHeight CMP D0, D1 ; is top of menu rect < 2 pixels below the menubar ? BGE.S @UpLoop ; no ==> keep moving up ADD MFHeight(a6), D1 ; yes ==> force top of menurect to be on the screen MOVE D1, Top(a0) ; store top of menurect BRA.S @CalcBottom ; calc bottom of menurect ; ; Start at TopMenuItem, and move **DOWN** by increments of MFHeight until we reach at ; least 2 pixels below the menubar. ; @CalcBelow MOVE D4, D1 ; start at TopMenuItem @DownLoop ADD MFHeight(a6), D1 ; move down one MFHeight CMP D0, D1 ; is top of menu rect >= 2 pixels below the menubar ? BLT.S @DownLoop ; no ==> keep moving down MOVE D1, Top(a0) ; store top of menurect ; ; Start at top of menurect and move down by multiples of MFHeight until the bottom of the ; menurect is about 5 pixels above the screen bottom. This makes the menurect an exact ; multiple of MFHeight. ; @CalcBottom MOVE portRect+Bottom(a1), D0 ; calc 5 pixels above screen bottom SUBQ #5, D0 @BotLoop2 ADD MFHeight(a6), D1 ; move down by one MFHeight CMP D0, D1 ; is bottom of menurect > 5 pixels above screen bottom ? BLE.S @BotLoop2 ; no ==> keep moving down SUB MFHeight(a6), D1 ; yes ==> force bottom of menurect onto the screen MOVE D1, Bottom(a0) ; store bottom of menuRect ;------------------------------------------------------------------------------------------------- ; Now adjust menuLeft and menuRight if menu hangs over left or right edge of the screen. ;------------------------------------------------------------------------------------------------- @AdjustLeftRight MOVE MLeftTop(A6), D0 ; get left edge MOVE.W portRect+Left(A1), D2 ; Get left edge of screen ADDQ.W #4, D2 ; Leave room for border CMP.W D2, D0 ; Compare with left edge of screen BGE.S @TryRight ; If greater, itÕs OK ; Adjust so the menu fits on the screen. MOVE D2, D0 ; make left edge equal to (fake) screen edge @TryRight MOVE.W D0, D1 ; ADD.W MenuWidth(A2), D1 ; calc right edge MOVE.W portRect+Right(A1), D2 ; Get right edge of screen SUBQ.W #4, D2 ; Leave room for border CMP.W D2, D1 ; Compare with right edge of screen BLE.S @StoreLeftRight ; if smaller, weÕre cool ; Adjust so the menu fits on the screen. MOVE D2, D1 ; make right edge equal to (fake) screen edge MOVE.W D1, D0 ; SUB.W menuWidth(A2), D0 ; left = right - menuWidth @StoreLeftRight MOVE.W D0, Left(A0) ; store left MOVE.W D1, Right(A0) ; store right RTS ;=============================================================================================== ; start addition ;---------------------------------------------------------------------------------------- ; ; Msg #4 -- Draw Item -- going to draw an item in the menu in the given rectangle ; ;---------------------------------------------------------------------------------------- ; ; here is the part of the TextMenuProc that draws the menu. For most of this routine, ; A3 holds the menuHandle, D4 is the item to be drawn ; DoDrawItemMsg bsr GetSizes ; get font info into stackframe MOVE.L MMENURECT(A6),A0 ; < BBH 12/4/89 > get the menuRect MOVE.W top(A0),D3 ; < BBH 12/4/89 > get the top of the rectangle to draw in ADD.W MAscent(A6),D3 ; < BBH 12/4/89 > add in the ascent for baseline MOVE.L MWHICHITEM(A6),A0 ; < BBH 12/4/89 > get the item to draw MOVE.W (A0),D4 ; < BBH 12/4/89 > dereference ; We need to color the background for the item bsr SaveCurrentColors ; save fore/back colors in stackframe move #mctRGB2, colorOffset(a6) ; use the item color if there is an entry bsr SetColors ; set colors MOVE.L MMENURECT(A6),-(SP) ; get menuRect pointer _EraseRect bsr ResetPreviousColors ; and set back to the previous stuff MOVE.L MMENURECT(A6),A0 ; get menuRect pointer bsr DrawTheItem ; call drawing routine rts ;---------------------------------------------------------------------------------------- ; ; Msg #5 -- Calc Item -- calculate rectangle for given item ; ;---------------------------------------------------------------------------------------- ; ; here is the part of the TextMenuProc that draws the menu. For most of this routine, ; A3 holds the menuHandle, D4 is the item to be drawn ; DoCalcItemMsg MOVE.L A3, -(SP) ; push menu handle _CalcMenuSize ; get valid height and width BSR GetSizes ; get font info into the stack MOVE.L MWHICHITEM(A6),A0 ; < BBH 12/4/89 > get the item to calculate MOVE.W (A0),D0 ; < BBH 12/4/89 > dereference MOVE.L (a3),a0 ; get pointer to menu BSR GETITEMRECORD ; look it up BEQ.S @noItem ; if so, nothing selected MOVEA.L A0,A4 ; store the string in a4 for GetItemWidth ; a1 = item attr byte list BSR GetItemHeight ; get height of item in D0, icon size in D1 SWAP D1 ; get icon width in low word MOVE.W D1,D7 ; store there for GetItemWidth ADD.W MSpaceWidth(A6), D7 ; Add in width of a single space ;; <56> removed ADDQ.W #4, D7 fudging factor MOVE.L MMENURECT(A6),A0 ; get the menuRect MOVE.W top(A0),D3 ; get the top ADD.W D0,D3 ; add height MOVE.W D3,bottom(A0) ; set the bottom BSR GetItemWidth ; gimme the width of the item in D0 MOVE.L MMENURECT(A6),A0 ; get the menuRect MOVE.W left(A0),D3 ; get left of menu ADD.W D0, D3 ; add the width MOVE.W D3,right(A0) ; and set the right BRA.S @done @noItem MOVE.L MMENURECT(A6),A0 ; get the menuRect MOVE.W top(A0), bottom(A0) ; no width or height MOVE.W left(A0), right(A0) @done rts ; end addition ;=============================================================================================== ;---------------------------------------- ; Utility -- SaveCurrentColors ;---------------------------------------- ; Save the current fore/back colors in the stackframe. ; Get the deviceÕs pixel depth in the stackframe too. ; Only need to save if color machine SaveCurrentColors tst.b onColorMachine(a6) beq.s @SaveEnd pea saveForeColor(a6) ; push location to save fore color pea saveBackColor(a6) ; push location to save back color _GetBackColor ; and get Õem _GetForeColor SUBQ #4,SP MOVE.L SP,-(SP) ; point to top of stack _GetPort ; get the current port move.l (sp)+, a0 subq #4, sp ; space for GDHandle return pea portRect(a0) ; draw menus on main screen _GetMaxDevice ; get max pixel device MOVE.L (sp)+, A0 ; get the grafDevice MOVE.L (A0),A0 ; hndl->ptr MOVE.L GDPMap(A0),A1 ; get the deviceÕs pixmap MOVE.L (A1),A1 ; hndl->ptr move.w pixelSize(a1), PixelDepth(a6) ; and store the value @SaveEnd rts ;---------------------------------------- ; Utility -- ResetPreviousColors ;---------------------------------------- ; Restore the fore/back colors from those saved ; in the stackframe in SaveCurrentColors. ; Need to reset on both color and b/w machines. Assume b/w machine always have ; black on white. ResetPreviousColors tst.b onColorMachine(a6) beq.s @ResetBW pea saveForeColor(a6) ; push location of saved fore color pea saveBackColor(a6) ; push location of saved back color _RGBBackColor _RGBForeColor bra.s @ResetEnd @ResetBW tst invertFlag(a6) ; normal or inverted colors ? <51=BRC#79297> beq.s @ResetEnd ; 0 = normal colors, so no need to reset <51=BRC#79297> moveq #BlackColor, d0 ; always reset to black on white move.l d0, -(sp) _ForeColor moveq #WhiteColor, d0 move.l d0, -(sp) _BackColor @ResetEnd rts ;---------------------------------------- ; Utility -- SetColors ;---------------------------------------- ; ; On Entry: A3 MenuHandle ; D4 Item Number ; colorOffset(a6) Offset into menu color table indicating mark/text/cmd ; Used: A0, D1 SetColors tst.b onColorMachine(a6) beq @SetBW cmpi.w #2, PixelDepth(a6) ; is this 2+ mode and color ? blt.s @SetDefault ; if 1 bit mode then use Black/White only tst invertFlag(a6) ; normal or inverted colors ? beq.s @1 ; 0 = normal colors, so branch ; for inverted menu colors always invert the background color with the item nameÕs color move #mctRGB2, colorOffset(a6) @1 subq #4, sp ; save space for result move.l (a3), a0 ; get menu ptr move menuID(a0), -(sp) ; push ID move d4, -(sp) ; push Item _GetMCEntry ; get itemÕs color entry move.l (sp)+, d1 ; get the result, and set/un-set z-flag beq.s @TryTitleEntry ; couldnÕt find item entry so try title entry move.l d1, a0 ; get color record ptr in A0 move colorOffset(a6), d0 ; offset for mark/cmd/char pea (a0, d0) ; push foreground color pea mctRGB4(a0) ; push background color bra.s @DoTheSet ; branch to do actual color setting @TryTitleEntry subq #4, sp ; save space for result move.l (a3), a0 ; get menu ptr move menuID(a0), -(sp) ; push ID clr -(sp) ; Item = 0 ===> title entry _GetMCEntry ; get titleÕs color entry move.l (sp)+, d1 ; get the result, and set/un-set z-flag beq.s @TryMenuBarEntry ; couldnÕt find title entry so try menu bar entry move.l d1, a0 ; get color record ptr in A0 move #mctRGB3, d0 ; offset for items default color pea (a0, d0) ; push foreground color pea mctRGB4(a0) ; push background color bra.s @DoTheSet ; branch to do actual color setting @TryMenuBarEntry subq #4, sp ; save space for result clr.l -(sp) ; ID = 0, Item = 0 ===> menu bar entry _GetMCEntry ; get menu barÕs color entry move.l (sp)+, d1 ; get the result, and set/un-set z-flag beq.s @SetDefault ; couldnÕt find menu bar entry so use black/white move.l d1, a0 ; get color record ptr in A0 move #mctRGB3, d0 ; offset for items default color pea (a0,d0) ; push foreground color pea mctRGB2(a0) ; push background color bra.s @DoTheSet ; and branch to do the actual color setting @SetDefault pea RGBBlack ; use black as default forecolor pea RGBWhite ; use white as default background color @DoTheSet tst invertFlag(a6) ; normal or inverted colors ? beq.s @2 ; 0 = normal colors, so branch _RGBForeColor ; set fore/back colors _RGBBackColor bra.s @SetColorsDone @2 _RGBBackColor ; set back/fore colors _RGBForeColor bra.s @SetColorsDone @SetBW tst invertFlag(a6) ; normal or inverted colors ? <51=BRC#79297> beq.s @SetColorsDone ; 0 = normal colors, so branch <51=BRC#79297> moveq #WhiteColor, d0 ; <51=BRC#79297> move.l d0, -(sp) ; <51=BRC#79297> _ForeColor ; <51=BRC#79297> moveq #BlackColor, d0 ; <51=BRC#79297> move.l d0, -(sp) ; <51=BRC#79297> _BackColor ; <51=BRC#79297> @SetColorsDone ; <51=BRC#79297> rts ;---------------------------------------- ; Utility -- TruncateString ;---------------------------------------- ; ; On Entry: A4 item information ; D1 system justification ; D5 left ; D6 right ; A2 pointer to string ; on exit: A2 pointer to tempString(A6) with truncated string ; Used: A0, A1, D0, D1 ; TruncateString ; note that for normal draw messages, we will not need to truncate ; because of the mCalcItemMsg will give us enough room (we hope) ; CMP.W #mDrawItemMsg, mMessage(a6) BEQ.S @GoTruncate ; (fixed <6>) rts @GoTruncate MOVEM.L D1/D3,-(SP) ; save register ; are we big enough? MOVE.W D6, D3 ; D2 get the width = right SUB.W D5, D3 ; minus left SUB.W #1, D3 ; minus right indent CLR.W -(SP) ; returned length MOVE.L A2,-(SP) ; push string _StringWidth ; will smash D1 MOVE.W (SP)+,D0 ; get result CMP.W D0,D3 BGT.S @TruncateDone ; D3>D0 (size avail > string width) ; copy the string please MOVEQ #0,D0 ; clear length MOVE.L A2, A0 ; < BBH 12/4/89 > LEA.L tempString(A6),A1 ; < BBH 12/4/89 > MOVE.L A1,A2 ; store in a2 which is the string to return MOVE.B (A0),D0 ; < BBH 12/4/89 > ADDQ #1,D0 _BlockMove ; < BBH 12/4/89 > ;Removed 'cuz it's ugly <#19 kaz> ; set the condensed bit please ; MOVE.B ITEMSTYLE(A4),D0 ; BSET #condenseBit,D0 ; add condensed ; MOVE.W D0,-(SP) ; and set it ; _TextFace SUBQ #2,SP ; returns whether string truncated MOVE.W D3,-(SP) ; width MOVE.L A2,-(SP) ; put the string pointer MOVE.W #smTruncEnd, -(SP) ; truncate at end _TruncString ADDQ #2,SP ; pop result (and ignore it) @TruncateDone MOVEM.L (SP)+,D1/D3 ; restore work register RTS ;-------------------------------------------------------------------------------------------- ; ; End of Code. Begin Data Definitions. ; ;-------------------------------------------------------------------------------------------- ; bounds rect for hier arrow is top=0, left=0, bottom=$10, right=$10 HierArrow DC.W $0000, $0000, $0020, $0030, $0038, $003C, $003E, $003F DC.W $003E, $003C, $0038, $0030, $0020, $0000, $0000, $0000 ; bounds rect for down arrow is top=0, left=0, bottom=$10, right=$10 DownArrow DC.W $0000, $0000, $0000, $0000, $0000, $7FF0, $3FE0, $1FC0 DC.W $0F80, $0700, $0200, $0000, $0000, $0000, $0000, $0000 ; bounds rect for up arrow is top=0, left=0, bottom=$10, right=$10 UpArrow DC.W $0000, $0000, $0000, $0000, $0000, $0200, $0700, $0F80 DC.W $1FC0, $3FE0, $7FF0, $0000, $0000, $0000, $0000, $0000 END