; ; File: ControlMgr.a ; ; Contains: Control Manager for Macintosh User Interface ToolBox ; ; Written by: Andy Hertzfeld August 4, 1982 ; ; Copyright: © 1982-1993 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 6/17/93 KW (LW9 fau) Clear the emControlHandle pointer after executing ; DragTheRgn, so it doesn't stick around. (LW8 fau) When setting ; DragFlag, only a byte was being set, and it is a word lowmem. ; 6/14/93 kc Roll in Ludwig. ; 5/3/93 chp Flush the caches for CDEF handles smaller than 32 bytes. It used ; to be 16 bytes, but a 22-byte, unflushed, fake defproc has been ; discovered in Software Ventures Microphone II and Microphone ; Pro. (RADAR #1082386) ; 3/8/93 fau Modified the previous fix to do a flush if the handle is less or ; equal to 16 bytes. See the comment for more description. ; 1/15/93 fau In the routine CallControl, added a cache flush if the Control ; Def Proc routine code is not in ROM. Some third party apps (bug ; #1059553 and #1060508) pass a CDEF Proc Handle to a jump table ; that relied on Hlock performing a cache flush. We test for a ; ROM address so as not to impact performance when the CDEF proc ; is ID 0 or 1, which are fairly commone ones!. ; 6/7/93 CSS In DragControl, stash the control handle in expandmem so when we ; call DragTheRgn we will have it to call back to the control if ; we need to (i.e. only if it is a thumb). ; 4/30/93 CSS We are using DragFlag in DragTheRgn to know if we should use ; special means to drag the control for the thumb. We need to ; clear it once we are done with it. ; 4/21/93 CSS _TrackControl calls dragcontrol to implement the dragging of a ; thumb. If there is a custom drag message in the CDEF, ; dragcontrol returns to trackcontrol saying that the thumb didn't ; move and the application isn't notified to update the content ; affected by the control. Fix _TrackControl, if dragcontrol says ; no movement occured, to also check if the value of the control ; changed. If the value of the control changed then return to the ; app without clearing the part number (and therefore the app will ; update the content correctly). ; 1/29/93 RB 1/15/93 fau In the routine CallControl, added a cache ; flush if the Control Def Proc routine code is not in ROM. Some ; third party apps (bug #1059553 and #1060508) pass a CDEF Proc ; Handle to a jump table that relied on Hlock performing a cache ; flush. We test for a ROM address so as not to impact performance ; when the CDEF proc is ID 0 or 1, which are fairly commone ones!. ; 7/23/92 fau Fixed a bug in TrackControl when using a custom tracking ; procedure: The ThrottleScrollingSpeed patch was blowing away ; D0, where the procedure's address was stored and the call to the ; procedure was using the globals value (which is -1 for a custom ; tracking procedure). I now save D0 before the patch and then ; restore it afterwards. ; 7/15/92 RB Fixed a bug in DisposeControl where the control handle needed to ; be tested specifically, instead of counting on the status ; register being setup by a move to an address register. ; <3> 7/1/92 JSM Merge changes from SuperMario: roll-in FixNewControl32Bit, ; PatchDisposeControlForCorrectLayer, ; PatchDisposeControlForInvisibleControlsIIci, ; CheckMemErrInSetCTitle, and ThrottleScrollingSpeed from ; ControlMgrPatches.a. ; <2> 9/30/91 JSM Add a header, donÕt use hasCQD conditional - all future ROMs ; will have color QuickDraw, donÕt use is32BitClean conditional - ; all future ROMs will be. ; <1.3> 10/31/89 dba concatenated source files ControlMgr1.a and ControlMgr2.a to ; this one ; ; Note: This file used to be split into three pieces. Here are the modification histories for each: ; ;---------------------------------------------------------------------------------------------------- ; Modification History for ControlMgr.a ;---------------------------------------------------------------------------------------------------- ; ; 1.3 dba 10/31/1989 concatenated source files ControlMgr1.a and ControlMgr2.a to this one ; 1.2 SES 08/22/1989 Removed references to nFiles. ; 1.1 CCH 11/10/1988 Fixed Header. ; 1.0 CCH 11/ 9/1988 Adding to EASE. ;¥1.1 CCH 9/23/1988 Got rid of inc.sum.d and empty nFiles ; 1.0 BBM 2/11/88 Adding file for the first time into EASEÉ ; ; 01-Sep-82 AJH Added "PlotSymbol" entry point ; 20-Sep-82 AJH got rid of DragThumb ; 29-Sep-82 AJH Added CheckBoxProc ; 26-Sep-82 AJH Added KillControls ; 10-Oct-82 AJH Converted for QuickDraw Trap Interface ; 01-Nov-82 AJH changed FindWindow to FindControl ; 28-Dec-82 AJH made defProcs resources ; ;----------------------------------------------------------------------- ; 23 Jan 83 LAK Adapted for new equate files. ; 27-Apr-85 EHB only CallDControl if the control is in portRect ; don't test for visible in DrawControls, done in CallDControl ; Added UpdateControls(w:windowPtr;u:RgnHandle), which only updates ; the controls in the update region. ; 9-Jul-85 EHB Added setup of ROMMapInsert for ROM resources ; 15-Jul-85 EHB No longer rely on D0,D1 being preserved in calls to SetPort/GetPort (in ownerPort) ; 15-Oct-85 EHB Added routine DrawOneControl which somehow fell through the cracks earlier ;_______________________________________________________________________ ; ; Post Lonely Hearts ;_______________________________________________________________________ ; ; <19feb86> BBM Made some modifications to work under MPW ; DAF added two new color calls to control manager ; For code sharing, these routines are in the ; window manager (WindowMgr3.a). ; DAF added GetCVariant. ; DAF Fixed CallControl to SystemError if CDEF not loaded by LoadResource. This ; is because Juggler can gracefully terminate the app without killing all. ; ;---------------------------------------------------------------------------------------------------- ; Modification History for ControlMgr1.a ;---------------------------------------------------------------------------------------------------- ; ; 1.6 SES 08/22/1989 Removed references to nFiles. Updated equates accordingly. ; 1.5 DAF 07/13/1989 FOR AURORA BUILD - fixed 32-bit register trashing ; problem in DisposControl. ; 1.4 DAF 06/14/1989 Corrected auxCtlRec disposal in 32-bit addressing mode ; (DisposControl) ; 1.3 EMT 02/22/1989 Uses is32BitClean conditional; only uses new message in 32 bit mode. ; 1.2 EMT 02/09/1989 dded new messages for 32-bit clean Control Manager. ; 1.1 CCH 11/10/1988 Fixed Header. ; 1.0 CCH 11/ 9/1988 Adding to EASE. ; 1.1 GGD 11/ 2/1988 Got rid of machine specific conditionals in favor of ; feature based conditionals. ; 1.0 BBM 2/11/88 Adding file for the first time into EASEÉ ; ; 22-Aug-82 AJH Added DragControl ; 29-Aug-82 AJH Added hilite parameter to draw message ; 29-Aug-82 AJH Implemented hilite state "-1" ; 30-Aug-82 AJH Fixed SetCtlValue to use max and min when value is ; out of bounds ; 31-Aug-82 AJH Added slopRect parameter to dragging ; 09-Sep-82 AJH Fixed register trashing bug in NewControl ; 20-Sep-82 AJH Made TrackControl handle indicators ; 22-Sep-82 AJH Integrated list routines ; 25-Sep-82 AJH Made NewControl ensure high byte of controlHandle is zero ; 26-Sep-82 AJH Added KillControls, made drawControls preserve penState ; 27-Sep-82 AJH Fixed bug in DeleteList ; 05-Oct-82 AJH Added some code-saving optimizations; added actionProc field ; 10-Oct-82 AJH Converted for QuickDraw Trap Interface ; 18-OCt-82 AJH Fixed bug in SetCtlMax/Min ; 14-Nov-82 AJH Made unHiliting use part codes to avoid flashing ; 30-Nov-82 AJH Made TrackControl pass controlHandle to actionProc ; 21-Dec-82 AJH Fixed TrackControl result when tracking indicator ; 21-Dec-82 AJH Fixed failure to dispose old string in SetCTitle bug ; 28-Dec-82 AJH made defProcs resources; string at end instead of handle ; 24-Jan-83 AJH made CallDControl do nothing if the control is invisible ; 24-Jan-83 AJH made SetCtlMin/Max do range checking ; 31-Jan-83 AJH clear high byte in CallControl before calling LoadResource ; 05-Feb-83 AJH made TrackControl for indicator use actionProc ; 13-Feb-83 AJH made SetCtlValue not draw when pinned against min or max ; 09-Mar-83 AJH cleaned up custom drag interface ; 16-Mar-83 AJH fixed contrlAction bug in TrackControl with indicators ; 03-Apr-83 AJH made NewControl use defProc 0 when it cant find requested one ; 08-Jun-83 AJH changed a bunch of internal BSRs to traps ; 15-Aug-83 AJH monster code krunch after code review (Capps, Jerome) ; 29-Aug-83 AJH/SC if local actionProc odd, send a track message ; 09-Sep-83 AJH hilite before calling actionProc in TrackControl ; ;---------------------------------------------------------- ; ; 27-Apr-85 EHB only CallDControl if the control is in portRect ; don't test for visible in DrawControls, done in CallDControl ; Added UpdateControls(w:windowPtr;u:RgnHandle), which only updates ; the controls in the update region. ; 9-Jul-85 EHB Added setup of ROMMapInsert for ROM resources ; 15-Jul-85 EHB No longer rely on D0,D1 being preserved in calls to SetPort/GetPort (in ownerPort) ; 15-Oct-85 EHB Added routine DrawOneControl which somehow fell through the cracks earlier ; ;----------------------------- Lonely Heifer ROMs ------------------------------------- ; ; 16-Jan-86 EHB Removed SectRect in CallDControl because it broke MacExpress ; DAF Made DisposeControl dispose of auxCtlRec and colortable. ; DAF Made some 32/24-bit corrections in callControl. ; DAF Added GetCVariant. Changed callControl to use this new call ; DAF saved D1 across NewControl for Insight G/L 's Notes DA. ; It expects the hi half of D1 to be unchanged. ; DAF Set contrlVis FALSE in EraseControl to fix MSWord's ruler. Moved this ; code from HideControl (which uses EraseControl). ; DAF Fixed 32-bit stuff to look at MMU32Bit rather than MMUFlags (to be ; consistant with wmgr. ; rwh Port to Modern Victorian ; DAF Fixed CallControl to SystemError if CDEF not loaded by LoadResource. This ; is because Juggler can gracefully terminate the app without killing all. ; ;---------------------------------------------------------------------------------------------------- ; Modification History for ControlMgr2.a ;---------------------------------------------------------------------------------------------------- ; ; 1.1 CCH 11/10/1988 Fixed Header. ; 1.0 CCH 11/ 9/1988 Adding to EASE. ; 1.0 BBM 2/11/88 Adding file for the first time into EASEÉ ; ; 20-Sep-82 AJH Fixed "thePort" trash bug in FindWindow ; 28-Sep-82 AJH Made FindWindow use CallWindow to save code ; 10-Oct-82 AJH Converted for QuickDraw Trap Interface ; 01-Nov-82 AJH Removed FindWindow, added FindControl ; 28-Dec-82 AJH Removed control defProcs from control manager ; 11-Feb-83 AJH Made FindControl return last one for overlapping controls ; 07-Mar-83 AJH Fixed bug in FindControl with 255-hiliting ; LOAD 'StandardEqu.d' INCLUDE 'ControlPriv.a' ; <3> INCLUDE 'LayerEqu.a' ; <3> INCLUDE 'SysEqu.a' ; fau MACHINE MC68020 ; needed for cache flush fau CMGR PROC EXPORT ; Macintosh Control Manager External Definitions EXPORT NewControl EXPORT DisposeControl EXPORT KillControls EXPORT MoveControl EXPORT SizeControl EXPORT DragControl EXPORT ShowControl EXPORT HideControl EXPORT SetCTitle EXPORT GetCTitle EXPORT HiliteControl EXPORT SetCRefCon EXPORT GetCRefCon EXPORT GetCtlValue EXPORT GetCtlMin EXPORT GetCtlMax EXPORT SetCtlValue EXPORT SetCtlMin EXPORT SetCtlMax EXPORT GetCtlAction EXPORT SetCtlAction EXPORT TestControl EXPORT TrackControl EXPORT FindControl EXPORT DrawControls EXPORT UpdtControls EXPORT DrawOneControl EXPORT GetCVariant ; DAF EXPORT cmgrend ; ; External Routines used by Control Manager ; IMPORT GetNewRgn IMPORT FlushCRange ; ; FUNCTION NewControl( window: windowPtr; ; boundsRect: Rect; ; Title: String255; ; VisFlag: Boolean; ; Value: INTEGER; ; minValue: INTEGER; ; maxValue: INTEGER; ; ctlProcID INTEGER; ; refCon: LongInt): ControlHandle; ; ; NewControl allocates and initializes a new control data structure. The ctlProc ; parameter determines the type of control (button, scrollBar, etc.) ; ; Parameter definition equates ; NCRefCon EQU 8 NCCDefID EQU 12 NCMaxValue EQU 14 NCMinValue EQU 16 NCValue EQU 18 NCVisFlag EQU 20 NCTitle EQU 22 NCBoundsRect EQU 26 NCWindow EQU 30 NCFResult EQU 34 ; NewControl LINK A6,#0 ;make a stack frame MOVEM.L D1/A2-A4,-(SP) ;save work registers DAF LEA NCFResult(A6),A4 ;use A4 to get at parameters ; ; allocate memory for the control data structure ; MOVEQ #ContrlSize+1,D0 ;get size of control data structure MOVEQ #0,D1 ;clear out high part MOVE.L NCTitle(A6),A0 ;get pointer to title string MOVE.B (A0),D1 ;get length of title ADD.L D1,D0 ;compute length of control block _NEWHANDLE ;allocate some memory ; MOVE.L A0,A3 ;keep control handle in A3 MOVE.L A0,(A4) ;also, its the function result MOVE.L (A3),A2 ;handle -> pointer SF.B contrlVis(A2) ; set this temporarily, so SetCtlColor won't try to draw DAF MOVE.L A3,-(SP) ; push controlHandle DAF MOVE.L #-1,-(SP) ; push -1 to make a new rec with default CTab DAF ; begin roll-in FixNewControl32Bit patch <3> move.l 30(a6),contrlOwner(a2) ; copy the owner into the field <3> _SetCtlColor ; make one DAF move.l (a3),a2 ; re-dereference the control handle <3> ; end roll-in FixNewControl32Bit patch <3> @1 ; ; insert it into the controlList of the owning window ; MOVE.L -(A4),A1 ;get owning window pointer MOVE.L A1,ContrlOwner(A2) ;initialize owner field MOVE.L WControlList(A1),NextControl(A2) ;link old 1st one MOVE.L A3,WControlList(A1) ;make new one first ; ; initialize the bounding rectangle ; LEA ContrlRect(A2),A1 ;get destination MOVE.L -(A4),A0 ;get ptr to bounding rectangle MOVE.L (A0)+,(A1)+ ;move in the topLeft MOVE.L (A0),(A1) ;move in the bottomRight ; ; initialize the control title. Use the standard SetCTitle call to save code. ; CLR.B ContrlVis(A2) ;pretend its hidden MOVE.L A3,-(SP) ;push control handle MOVE.L -(A4),-(SP) ;push pointer to new title _SetCTitle ;initialize the title field ; ; copy parameters into control data structure ; MOVE.L (A3),A2 ;better rebuild pointer from handle LEA ContrlVis(A2),A0 ;point to visible flag byte SUBQ #2,A4 ;point A4 at visFlag boolean TST.B (A4) ;check out the parameter SNE (A0)+ ;set the visFlag byte accordingly CLR.B (A0)+ ;initial hilite state is 0 ; MOVE.W -(A4),(A0)+ ;init value MOVE.W -(A4),(A0)+ ;init minimum value MOVE.W -(A4),(A0)+ ;init max value ; ; initialize definition proc ; MOVE.W -(A4),D0 ;get the resource ID LSR #4,D0 ;divide by 16 GetCDefProc SUBQ #4,SP ;make room for function result MOVE.L #('CDEF'),-(SP) ;push resource type CDef MOVE.W D0,-(SP) ;push mapped resource ID MOVE.W #MapTRUE,ROMMapInsert ; set flag to load from ROM <8 july 85> _GetResource ;get the CDef handle MOVEQ #0,D0 ;assume we couldnÕt get it MOVE.L (A3),A0 ;get the control ptr LEA ContrlDefHandle(A0),A0 ;point to defHandle MOVE.L (SP)+,(A0) ;move it in BEQ.S GetCDefProc ;if we couldnt find it, try 0 MOVE.W (A4),D0 ;get resource ID AND #$000F,D0 ;use only low 4 bits MOVE.L A0,-(SP) ; save A0 DAF MOVE.L D0,-(SP) ; save D0 too DAF SUBQ #6,SP ; get placeholder for auxCtlHndl, and boolean result DAF MOVE.L A3,-(SP) ; push controlhandle DAF PEA 6(SP) ; point to longword placeholder DAF _GetAuxCtl ; get this windowÕs auxRec DAF ADDQ #2,SP ; flush boolean DAF MOVE.L (SP)+,A0 ; get auxCtlHndl DAF MOVE.L (A0),A0 ; get auxCtlPtr DAF MOVE.L (SP)+,D0 ; restore D0 (with variant) DAF MOVE.B D0,acReserved(A0) ; put variant in auxRec DAF<1.6> MOVE.L (SP)+,A0 ; restore A0 DAF ADDQ #4,A0 ;bump to next field CLR.L (A0)+ ;init dataHandle CLR.L (A0)+ ;clear actionProc MOVE.L -(A4),(A0)+ ;init reference constant ; ; all the fields of the data structure are now initialized. Send the controlProc ; the "init" message ; MOVEQ #NewCtlMsg,D0 ;message is "new" BSR.S CallControl ;tell the controlProc to init ; ; tell the control to draw itself if its visible ; TST.B NCVisFlag(A6) ;is it visible BEQ.S NCDone ;if not, weÕre done ; MOVEQ #0,D1 ;tell it to draw everything BSR.S CallDControl ;tell the control to draw itself ; ; all done with NewControl -- restore registers and return to caller ; NCDone MOVEM.L (SP)+,D1/A2-A4 ;restore work registers DAF UNLK A6 ;unbuild stack frame MOVE.L (SP)+,A0 ;get return address ADD #26,SP ;strip parameters JMP (A0) ;return to caller ; ; CallControl is a utility used to send a message to a controlÕs definitions ; procedure. On entry, the controlHandle is in A3, the message number is in ; D0 while D1 contains an optional parameter (used for hit & calc messages). ; CallControl makes sure that the controlÕs window is the current grafPort at ; the time the control definition procedure is invoked. On return, D0 contains ; the result from the definition procedure. The entry point CallDControl ; is used for draw messages to save code; it preloads D0 with the draw message, ; tests to see if the control should be drawn, and if so falls through to CallControl ; CallDControl MOVEQ #DrawCtlMsg,D0 ;get the draw message MOVE.L (A3),A0 ;get control pointer TST.B ContrlVis(A0) ;is it visible? BEQ.S NoDControl ;donÕt draw invisible ones ; only draw the control if itÕs in the portrect ; Removed 14Jan86 because it didnÕt work with MacExpress ; MOVEM.L D0-D1,-(SP) ; save message, param ; SUBA.L #10,SP ; make room for rect, result ; PEA ContrlRect(A0) ; push address of controlÕs rect ; MOVE.L ContrlOwner(A0),A1 ; get pointer to owning window ; PEA PortRect(A1) ; push address of windowÕs portRect ; PEA 10(SP) ; point to temp rect ; _SectRect ; should we draw it? ; TST.B (SP)+ ; NE if we should ; ADDA.L #8,SP ; strip the rect ; MOVEM.L (SP)+,D0-D1 ; restore message, param ; BEQ.S NoDControl ; => donÕt draw remote ones ; CallControl ; ; set the grafPort to be the owning window ; BSR OwnerPort ;save old one, too ; ; push parameters and invoke the control definition routine ; CLR.L -(SP) ;make room for function result CLR.W -(SP) ;make room for variant code DAF MOVE.L A3,-(SP) ;push control handle MOVE.W D0,-(SP) ;push message index MOVE.L D1,-(SP) ;push parameter SUBQ #2,SP ; make room for GetCVariant return DAF MOVE.L A3,-(SP) ; get variation code DAF _GetCVariant ; leave word result on stack DAF MOVE.W (SP)+,10(SP) ; move from top of stack to placeholder DAF MOVE.L (A3),A0 ;get pointer to control structure MOVE.L ContrlDefHandle(A0),A0 ;get handle of controlProc DAF TST.L (A0) ;needs reloading? BNE.S SkipCLoad ;if not,skip MOVE.L A0,-(SP) ;push control handle MOVE.W #MapTrue,ROMMapInsert ; get it from ROM if possible <10 Jul 85> _LoadResource ;load it in again TST.L (A0) ;did we get it this time? DAF BNE.S SkipCLoad ;yup, keep going DAF MOVE.W #CDEFnFnd,D0 ;get error code DAF _SysError ;and croak DAF SkipCLoad ; Some programmers are pretty slimy and load a CDEF that is empty. They then fau ; stuff some code into it. However, since HLOCK does not flush the cache anymore, fau ; the code that they stuff into it might not get written back to memory. To solve this, fau ; we check here whether the CDEF resource size is less than, say, 32 bytes. If so, we chp ; assume that they have already loaded the CDEF and modified it, so we flush the cache fau ; for them. _GetHandleSize ; How big is our CDEF Handle fau cmp.l #32,D0 ; Is it "small" chp bhi.s @RealCDEF ; no, don't flush the cache fau move.l A0,-(SP) move.l (A0),A0 move.l D0,A1 bsr.l FlushCRange ; else, flush the caches. fau move.l (SP)+,A0 @RealCDEF ; fau _HLock ; lock it down MOVE.L (A0),A0 ;get cDefProc ptr JSR (A0) ;call it MOVE.L (A3),A0 ;get pointer back MOVE.L ContrlDefHandle(A0),A0 ;get defProc handle back _HUnlock ;unlock it DAF MOVE.L (SP)+,D0 ;get function result ; ; restore original grafPort and return to caller ; RPortExit _SetPort ;restore original grafPort NoDControl RTS ;return to caller ; ; function GetCVariant ( whichControl : controlHandle ) : integer; ; ; GetCVariant returns the control variant code of the control whose ; handle is whichControl. Variant codes are 4-bit values returned ; right-justified in the word result. In case you are wondering ; the result is word rather than byte because itÕs less complicated ; for this stack-based routine, and the variant is passed to the ; defprocs as a word. GetCVariant ; DAF MOVE.L 4(SP),A0 ; get ctl handle SUBQ #6,SP ; leave room for result and boolean DAF MOVE.L A0,-(SP) ; push the controlHandle DAF PEA 6(SP) ; point to result placeholder DAF _GetAuxCtl ; get the controlÕs auxRec DAF ADDQ #2,SP ; flush the boolean DAF MOVE.L (SP)+,A0 ; get the auxCtlHndl DAF MOVE.L (A0),A0 ; get the auxRecPtr DAF CLR.W D0 ; clear top byte DAF MOVE.B acReserved(A0),D0 ; get variant code DAF<1.6> MOVE.W D0,8(SP) ; return result MOVE.L (SP)+,A0 ; get return addr ADDQ #4,SP ; flush parameters JMP (A0) ; and return to caller ; ; Utility EraseControl -- utility for erasing a control from its window. The ; control handle is passed in A3 ; EraseControl ; get into the window that owns this control BSR OwnerPort ;save port on stack, get into this on MOVEM.L A1-A4,-(SP) ;save work registers ; ; allocate a temporary region and ask the control definition procedure for the ; controlÕs bounding region. The above move multiple pushed an extra register ; to make room for the NewRgn function result ; _NewRgn ;allocate a new region MOVE.L (SP),A4 ;keep the region in A4, keep on stack MOVEQ #CalcWholeCtlMsg,D0 ;message is calculate whole regions <1.2> MOVE.L A4,D1 ;the region is the parameter <1.2> BSR CallControl ;send it the message <1.2> ; ; paint white to erase control and add it to the windowÕs update region ; _EraseRgn ;erase it from the window ; MOVE.L A4,-(SP) ;push region _InvalRgn ;add to update region ; ; dispose of the temporary region ; MOVE.L A4,-(SP) ;push region _DisposRgn ;return it to the free list ; set the vis field false. This was moved up from HideControl so that DisposeControl ; (who also uses this utility) will do the right thing when de-allocating an auxWinRec ; on nuMac. This is in support of the ruler in Microsoft Word (1.05/3.0) DAF MOVE.L (A3),A0 ;better rebuild pointer from handle CLR.B ContrlVis(A0) ;mark it hidden ; ; restore original grafPort and weÕre done! ; MOVEM.L (SP)+,A2-A4 ;restore work registers BRA.S RPortExit ;use common code ; ; PROCEDURE DisposeControl(theControl: controlHandle); ; ; This routine disposes of a control. It deallocates its storage, removes it from the ; windowÕs controlList and removes it from the screen. ; DisposeControl MOVEM.L A2/A3,-(SP) ;preserve a work register <1.5> MOVE.L 12(SP),A3 ;get the control handle <1.5> ; begin roll-in PatchDisposeControlForCorrectLayer patch <3> tst.l 12(sp) ; is there a control handle ? rb beq DisposeNilControl ;if handle is NIL, exit <3> move.l (a3), a0 ; get pointer <3> subq.l #4, sp ; room for result <3> subq.l #4, sp ; room for result for _SwapCurLayer <3> move.l contrlOwner(a0), -(sp) ; setup for _GetParent <3> _GetParent ; <3> _SwapCurLayer ; swap for parent, leaves original layer on stack <3> ; end roll-in PatchDisposeControlForCorrectLayer patch <3> ; begin roll-in PatchDisposeControlForInvisibleControlsIIci patch <3> move.l (a3),a0 ;get the control pointer <3> tst.b contrlVis(A0) ;is the control visible? <3> beq.s DontEraseControl ;no, skip erasing <3> BSR.S EraseControl ;erase it from the screen DontEraseControl ; <3> ; end roll-in PatchDisposeControlForInvisibleControlsIIci patch <3> ; dispose of auxCtlRec, if present. To do this, do a SetCtlColor with the request being the ; default control colortable (which deletes the auxCtlRec). MOVE.L A3,-(SP) ; push handle for SetCtlColor later CLR.L -(SP) ; return the default cTabHndl here CLR.B -(SP) ; make room for a function return from GetAuxCtl CLR.L -(SP) ; push the control Handle PEA 6(SP) ; push a pointer to the cTabHndl placeholder _GetAuxCtl ; get the default cTabHndl ADDQ #2,SP ; dump the function result MOVE.L (SP)+,A0 ; get the auxCtlRec handle MOVE.L (A0),A0 ; get auxCtlRec ptr MOVE.L acCTable(A0),-(SP) ; push default colors hndl <1.6> LEA AuxCtlHead,A1 ; get the head of the auxCtlList (offset is zero so this works!) @10 MOVE.L (A1),A2 ; get the handle to the auxCtlRec MOVE.L (A2),A0 ; get the pointer to the auxCtlRec CMP.L acOwner(A0),A3 ; is this the one? BEQ.S @20 ; yes, so remove it LEA acNext(A0),A1 ; get the next one BRA.S @10 @20 MOVE.L acNext(A0),(A1) ; link around the closing control MOVE.L A2,A1 ; copy the dead auxCtlRec handle MOVE.L (A1),A1 ; get a pointer to it MOVE.L acCTable(A1),D0 ; get the doomed color table handle CMP.L (SP)+,D0 ; does this doomed record have the same color table as the default? BEQ.S @30 ; if so, then donÕt delete it MOVE.L D0,A0 ; get the doomed ctab handle in A0 _HGetState ; get the tag bits of this color table BTST #resource,D0 ; is the resource bit set? BNE.S @30 ; if so, donÕt delete it (it the appÕs responsibility) _DisposHandle ; kill the color table @30 MOVE.L A2,A0 ; release the auxCtlRec _DisposHandle ; ADDQ #4,SP ; get rid of the extra window pointer pushed above ; ; delete it from the windowÕs controlList ; MOVE.L A3,A0 ;DeleteList needs handle in A0 MOVE.L (A3),A1 ;get control pointer MOVE.L ContrlOwner(A1),A1 ;get windowPtr of owning window LEA WControlList(A1),A1 ;A1 points to list header BSR DeleteList ;delete it ; ; deallocate the data handle by sending a message to the definition proc ; NoString1 MOVEQ #DispCtlMsg,D0 ;send the dispose message BSR CallControl ;tell it to dispose its dataHandle ; ; deallocate the data structure itself, and weÕre done ; MOVE.L A3,A0 _DisposHandle ;dispose of the control data structure ; begin roll-in PatchDisposeControlForCorrectLayer patch <3> _SetCurLayer ; original layer should be on stack <3> ; waiting for us from _SwapCurLayer <3> DisposeNilControl ; <3> ; end roll-in PatchDisposeControlForCorrectLayer patch <3> MOVEM.L (SP)+,A2/A3 ; restore work registers <1.5> MOVE.L (SP)+,(SP) ; strip parameter <1.5> RTS ; <1.5> ; ; PROCEDURE KillControls(theWindow: WindowPtr); ; ; Dispose all controls associated with a given window ; KillControls MOVE.L A3,-(SP) ;save work register MOVE.L 8(SP),A3 ;get window pointer ; ; Here is the loop that disposes the controls. It simply disposes the first one ; in the list ; KillCLoop MOVE.L WControlList(A3),D0 ;get next one in list BEQ.S CShowDone ;if NIL, weÕre done ; MOVE.L D0,-(SP) ;push the control handle _DisposControl ;dispose of it BRA.S KillCLoop ;loop till done ; PROCEDURE ShowOneControl(theControl: controlHandle); ; ; ShowOneControl draws a single control. The control is only drawn if visible DrawOneControl MOVE.L A3,-(SP) ; save work register MOVE.L 8(SP),A3 ; get control handle MOVE.L (A3),A0 ; handle -> pointer TST.B contrlVis(A0) ; is the control visible? DAF BEQ.S CShowDone ; if FALSE, then quit using common code DAF BRA.S ShowCommon ; => use common code ; ; PROCEDURE ShowControl(theControl: controlHandle); ; ; ShowControl makes a control visible if it is currently hidden. It causes it to ; be redrawn on the screen. ; ShowControl MOVE.L A3,-(SP) ;save work register MOVE.L 8(SP),A3 ;get control handle MOVE.L (A3),A0 ;handle -> pointer ; ; is it already visible? ; TST.B ContrlVis(A0) ;already visible? BNE.S CShowDone ;if so, thereÕs nothing to do ; ; make it visible ; ST ContrlVis(A0) ;set the visible flag ShowCommon ; MOVEQ #0,D1 ;all it of! BSR CallDControl ;tell control to draw itself ; ; all done with ShowControl (code also shared with HideControl) ; CShowDone MOVE.L (SP)+,A3 ;restore work register MOVE.L (SP)+,(SP) ;strip parameter RTS ; ; PROCEDURE HideControl(theControl: controlHandle); ; ; HideControl makes a control hidden if it is currently visible. It causes it to ; be erased from the screen. ; HideControl MOVE.L A3,-(SP) ;save work register MOVE.L 8(SP),A3 ;get control handle MOVE.L (A3),A0 ;handle -> pointer ; ; is it already hidden? ; TST.B ContrlVis(A0) ;already hidden? BEQ.S CShowDone ;if so, thereÕs nothing to do ; ; hide the control ; BSR EraseControl ;erase it (controlHandle in A3) ; ;+++ MOVE.L (A3),A0 ;better rebuild pointer from handle DAF ;+++ CLR.B ContrlVis(A0) ;mark it hidden DAF BRA.S CShowDone ;all done! ; ; PROCEDURE MoveControl(theControl:controlHandle; h,v: INTEGER); ; ; MoveControl moves a control to the position specified by the (h,v) parameters. ; The (h,v) parameter is intepreted to be in the local coordinates of the controlÕs ; owning window and is the coordinate of the topLeft of the bounding rectangle ; MoveControl MOVEM.L D3/A3,-(SP) ;save work registers MOVE.L 16(SP),A3 ;get the control handle MOVE.L (A3),A0 ;get pointer to control MOVE.B ContrlVis(A0),D3 ;remember visible state ; MOVE.L A3,-(SP) ;push control handle _HideControl ;hide it if its visible ; ; compute the difference of old position and new position ; MOVE.L (A3),A0 ;get pointer to control data structure ADDQ #ContrlRect,A0 ;point it at the rectangle MOVE 12(SP),D0 ;get vertical coordinate SUB (A0),D0 ;compute delta vertical MOVE 14(SP),D1 ;get horizontal coordinate SUB Left(A0),D1 ;compute delta horizontal ; ; offset the bounding rectangle to its new position ; MOVE.L A0,-(SP) ;push pointer to old rectangle MOVE D1,-(SP) ;push horizontal offset MOVE D0,-(SP) ;push vertical offset _OffsetRect ;offset to new position ; ; show the control if used to be visible ; DoneMC0 TST.B D3 ;test the old visFlag BEQ.S DoneMC ;if not visible, weÕre done ; ; show the control again ; DoneMC1 MOVE.L A3,-(SP) ;push controlHandle _ShowControl ;show it ; DoneMC MOVEM.L (SP)+,D3/A3 ;restore work registers EightBytExit MOVE.L (SP)+,A0 ;get return address ADDQ #8,SP ;strip parameters JMP (A0) ;return to caller ; ; FUNCTION GetCRefCon(theControl: controlHandle): LongInt; ; ; get the reference constant of a control ; GetCRefCon MOVEQ #ContrlRfCon,D1 ;get offset to refCon GetCCommon MOVE.L (SP)+,A0 ;get return address MOVE.L (SP)+,A1 ;get controlHandle MOVE.L (A1),A1 ;handle -> pointer MOVE.L 0(A1,D1),(SP) ;return refCon as function result JMP (A0) ;return to caller ; ; PROCEDURE SetCRefCon(theControl: controlHandle; data: LongInt); ; ; set the reference constant of a control to a specified value ; SetCRefCon MOVEQ #ContrlRfCon,D1 ;get offset to refCon SetCCommon MOVE.L (SP)+,A0 ;get return address MOVE.L (SP)+,D0 ;get new refCon MOVE.L (SP)+,A1 ;get controlHandle MOVE.L (A1),A1 ;handle -> pointer MOVE.L D0,0(A1,D1) ;set the refCon JMP (A0) ;return to caller ; ; FUNCTION GetCtlAction(theControl: ControlHandle): ProcPtr ; ; access routine to find out the current local actionProc of a control ; GetCtlAction MOVEQ #ContrlAction,D1 BRA.S GetCCommon ; ; PROCEDURE SetCtlAction(theControl: ControlHandle; newProc: ProcPtr); ; ; access routine to set the actionProc of a control ; SetCtlAction MOVEQ #ContrlAction,D1 BRA.S SetCCommon ; ; ; PROCEDURE SizeControl(theControl: controlHandle; width,heigth: INTEGER); ; ; change the size of a controlÕs bounding box to the specified width and height ; SizeControl MOVEM.L D3/A3,-(SP) ;save work registers MOVE.L 16(SP),A3 ;get control handle MOVE.L (A3),A0 ;handle -> pointer MOVE.B ContrlVis(A0),D3 ;remember visible state ; MOVE.L A3,-(SP) ;push control handle _HideControl ;hide the control ; ; get the width and height parameters ; MOVE 12(SP),D0 ;get height parameter MOVE 14(SP),D1 ;get width parameter ; ; resize the controlÕs bounding rectangle ; @2 MOVE.L (A3),A0 ;get pointer to control ADDQ #ContrlRect,A0 ;get pointer to boundsRect ADD.W (A0)+,D0 ;bottom := top + height ADD.W (A0)+,D1 ;right := left + width MOVE D0,(A0)+ ;update bottom MOVE D1,(A0)+ ;update right ; ; if its used to be visible, we better show it again ; BRA.S DoneMC0 ;let common code do the work ; ; PROCEDURE HiliteControl(theControl: controlHandle; fHilite: INTEGER); ; ; HiliteControl will hilite a portion of a control according to the value of ; fHilite. fHilite is an integer between 0 and 255; 0 always means unhilited ; while other values hilite various parts of the control as defined by its definition ; procedure. Value 255 is special -- it means "obscure" the control and make it ; inactive and unselectable. ; HiliteControl MOVE.L A3,-(SP) ;save work register MOVE.L 10(SP),A3 ;get the control handle MOVE.L (A3),A0 ;get control pointer MOVEQ #0,D1 ;clear out D1 MOVEQ #0,D0 ;ditto for D0 ; ; get the value of hilite; if thatÕs the state the control is already in, we have ; nothing to do. ; MOVE.B 9(SP),D1 ;get low byte of fHilite MOVE.B ContrlHilite(A0),D0 ;remember old HiliteState CMP.B D0,D1 ;are they the same? BEQ.S DoneHiControl ;if they are, weÕre done ; ; the hilite state has changed so update the control data structure and redraw it ; MOVE.B D1,ContrlHilite(A0) ;update hilite state BNE.S @1 ;skip if non-zero MOVE.W D0,D1 ;unhilite old part code @1 BSR CallDControl ;tell control to draw itself ; DoneHiControl MOVE.L (SP)+,A3 ;restore work register SixBytExit MOVE.L (SP)+,A0 ;get return address ADDQ #6,SP ;strip parameters JMP (A0) ;return to caller ; ; PROCEDURE GetCTitle(theControl:ControlHandle; VAR theTitle: Str255); ; ; GetCTitle returns the current title of a control in the string passed in ; theTitle. ; GetCTitle MOVE.L (SP)+,D0 ;remember return address MOVE.L (SP)+,A1 ;get destination string pointer MOVE.L (SP)+,A0 ;get control handle MOVE.L D0,-(SP) ;replace return address ; ; point A0 at the title string ; MOVE.L (A0),A0 ;handle -> pointer LEA ContrlTitle(A0),A0 ;point to title handle ; ; at this point A0 points to the string. Figure out its length and call blockMove to ; move it into the result string ; MOVEQ #0,D0 ;clear high part MOVE.B (A0),D0 ;get length of string ADDQ.L #1,D0 ;include the length byte, too _BLOCKMOVEDATA ;move it in place RTS ;all done! ; ; PROCEDURE SetCTitle(theControl: controlHandle; theTitle: Str255); ; ; SetCTitle is used to set the title of a control. ; SetCTitle MOVEM.L D3/A3-A4,-(SP) ;save work register MOVE.L 20(SP),A3 ;get control handle MOVE.L (A3),A0 ;handle -> pointer MOVE.B ContrlVis(A0),D3 ;remember visible state ; ; hide the control first ; MOVE.L A3,-(SP) ;push control handle _HideControl ;hide it ; ; resize the control to its new size ; MOVE.L 16(SP),A4 ;get pointer to new title MOVEQ #0,D0 ;clear out high part of D0 MOVE.B (A4),D0 ;get length word MOVE.L D0,-(SP) ;remember it ADD #ContrlSize+1,D0 ;compute the new size MOVE.L A3,A0 ;get handle in A0 _SetHandleSize ;resize it ; begin roll-in CheckMemErrInSetCTitle patch <3> beq.s CopyCTitle ; if no error, continue <3> addq.w #4,sp ; otherwise, pop off the size <3> bra.s GoTstVis ; and forget the _BlockMove <3> CopyCTitle ; <3> ; end roll-in CheckMemErrInSetCTitle patch <3> MOVE.L (SP)+,D0 ;recall the size MOVE.L A4,A0 ;get pointer to source MOVE.L (A3),A1 ;get control pointer LEA ContrlTitle(A1),A1 ;point to title string ADDQ #1,D0 ;dont forget the length byte _BlockMoveData ;move it in ; ; make it visible if it used to be ; GoTstVis TST.B D3 ;was it visible? BEQ.S DoneSetCString ;if not, weÕre done MOVE.L A3,-(SP) ;push control handle _ShowControl ;make it visible ; ; restore registers and go home ; DoneSetCString MOVEM.L (SP)+,D3/A3-A4 ;restore work registers BRA EightBytExit ;standard exit saves code ; ; FUNCTION GetCtlValue(theControl: controlHandle): INTEGER; ; ; GetCtlValue returns the current value of the specified control. To save code, ; it shares code with GetCtlMin and GetCtlMax ; GetCtlValue MOVEQ #ContrlValue,D0 ;get value index into D0 ; ; Here is the common code for GetCtlValue, GetCtlMin and GetCtlMax ; GetCtlCommon MOVE.L (SP)+,A1 ;get return address MOVE.L (SP)+,A0 ;get control handle MOVE.L (A0),A0 ;get control pointer MOVE 0(A0,D0),(SP) ;move value into function result JMP (A1) ;all done -- return to caller ; ; FUNCTION GetCtlMin(theControl:controlHandle): INTEGER; ; ; Get the current minimum value of the control ; GetCtlMin MOVEQ #ContrlMin,D0 ;get min index into D0 BRA.S GetCtlCommon ;let common code do all the work ; ; FUNCTION GetCtlMax(theControl:controlHandle): INTEGER; ; ; Get the current maximum value of the control ; GetCtlMax MOVEQ #ContrlMax,D0 ;get max index into D0 BRA.S GetCtlCommon ;let common code do all the work ; ; PROCEDURE SetCtlValue(theControl:controlHandle; value: INTEGER); ; ; Change the current value of a control, redrawing it if necessary. To save code, ; it shares code with SetCtlMin and SetCtlMax. ; SetCtlValue MOVEQ #ContrlValue,D0 ;get value index in D0 ; ; Here is the common code shared by SetCtlValue, SetCtlMin and SetCtlMax ; SetCtlCommon MOVE.L A3,-(SP) ;save work register MOVE.L 10(SP),A3 ;get the controlHandle MOVE 8(SP),D1 ;get the value/min/max MOVE.L (A3),A0 ;get pointer to control ; ; if the new value is the same as the current one, we have nothing to do ; CMP.W 0(A0,D0),D1 ;has it changed? BEQ.S ValSetDone ;if not, weÕre done ; update the new value MOVE.W D1,0(A0,D0) ;update the new value/min/max MOVE.W ContrlValue(A0),D1 ;get the value ; make sure its in range CMP ContrlMin(A0),D1 ;compare with min BGE.S @1 ;if > min, go check other bounds MOVE ContrlMin(A0),D1 ;use the min if its less than min ; @1 CMP ContrlMax(A0),D1 ;compare with max BLE.S @2 ;if in range, set it MOVE ContrlMax(A0),D1 ;use the max ; move in the range-checked value and redraw the control @2 MOVE.W D1,ContrlValue(A0) ;move in the new value MOVE #inThumb,D1 ;tell defProc weÕre changing thumb BSR CallDControl ;tell control to redraw itself ; ; all done -- restore A3, strip parameters and return ; ValSetDone MOVE.L (SP)+,A3 ;restore work register BRA SixBytExit ;standard exit saves code ; ; PROCEDURE SetCtlMin(theControl:controlHandle; minVal: INTEGER); ; ; Change the current minimum of a control, redrawing it if necessary. ; SetCtlMin MOVEQ #ContrlMin,D0 ;get value index in D0 BRA.S SetCtlCommon ;let common code do the work ; ; PROCEDURE SetCtlMax(theControl:controlHandle; maxVal: INTEGER); ; ; Change the current maximum of a control, redrawing it if necessary. ; SetCtlMax MOVEQ #ContrlMax,D0 ;get value index in D0 BRA.S SetCtlCommon ;let common code do the work ; ; FUNCTION TestControl(theControl: controlHandle; thePt: Point): INTEGER; ; ; TestControl tests to see if a given point is inside a given control. The point ; is assumed to be in the local coordinates of the controlÕs owning window. It ; returns an integer which is 0 if the point is not in the control at all or some ; small integer indicating what part of the control the button is in. ; TestControl MOVE.L A3,-(SP) ;preserve work register MOVE.L 12(SP),A3 ;get control handle MOVE.L (A3),A0 ;get control pointer ; ; if the control isnÕt visible, return 0 ; CLR.W 16(SP) ;assume its not in the control MOVE.B ContrlVis(A0),D1 ;is it visible? BEQ.S DoneTControl ;if not visible, weÕre done ; ; if its hilite state is 255, pretend its invisible ; CMP.B #$FF,ContrlHilite(A0) ;is it selectable? BEQ.S DoneTControl ;if not, donÕt really check it ; ; test the control by sending the control definition routine the "hit-test" message ; MOVE.L 8(SP),D1 ;get point parameter in D1 MOVEQ #HitCtlMsg,D0 ;the message is hit-test BSR CallControl ;invoke the definition routine ; ; the result is in D0; return this as the function result ; MOVE D0,16(SP) ;return hit test result ; DoneTControl MOVE.L (SP)+,A3 ;restore work register BRA EightBytExit ;standard exit saves code ; ; PROCEDURE DragControl(theControl:controlHandle; startPt: Point; ; boundRect: Rect; slopRect: Rect; axis: INTEGER); ; ; drag a flickering outline of control until the mouse button goes up. Make ; sure it stays within the bounding rectangle. The axis parameter is a constaint ; on the visual picture; if 0, no constraint, 1 = horizontal only, 2 = vertical only ; The slopRect is a rectangle for some hysterisis when dragging -- things pin to ; the bounding rect but are acceptable if the mouse goes up in the slopRect (which ; always contains the boundsRect) ; DragControl CLR.W DragFlag ;flag where weÕre coming from ; DragCon1 LINK A6,#0 ;estblish stack frame MOVEM.L D3-D4/A3-A4,-(SP) ;save work registers MOVEM.L 14(A6),D3-D4/A3 ;suck up the parameters ; ; save current grafPort and get into the control ownerÕs port ; BSR OwnerPort ; ; issue the "custom drag" message -- if the control definition proc "accepts" it ; by returning a non-zero result, thereÕs nothing more to do ; MOVE DragFlag,D1 ;get indicator boolean as parameter MOVEQ #DragCtlMsg,D0 ;its a drag, man... BSR CallControl ;tell the defProc about it TST D0 ;did the defProc implement it? BNE.S DoneDC1 ;if so, weÕre done (clear offset) ; ; ; allocate a region and ask the control definition procedure to update it ; JSR GetNewRgn ;allocate a new region MOVEQ #CalcWholeCtlMsg,D0 ;message is calculate whole regions <1.2> TST.W DragFlag ;if weÕre called as real MoveControl, <1.2> BEQ.S @0 ;then we picked the right message <1.2> MOVEQ #CalcThumbCtlMsg,D0 ;else message is calculate thumb regions <1.2> @0 ; <1.2> MOVE.L (SP),D1 ;the region is the parameter <1.2> BSR.S CallControl ;send it the message <1.2> MOVE.L (SP)+,A4 ;keep it in A4 ; ; set up the parameters for dragging the region around (careful -- extra reg ; in MOVEM reserves space for function result) ; MOVEM.L D3-D4/A4-A5,-(SP) ;push the parameters MOVE.L 10(A6),-(SP) ;push the slopRect MOVE.W 8(A6),-(SP) ;push axis parameter MOVE.L ExpandMem,a0 move.l a3,ExpandMemRec.emControlHandle(a0) ; ; set up the actionProc parameter ; MOVE.L CurDragAction,-(SP) ;push the action proc TST.W DragFlag ;are we tracking an indicator? BNE.S @1 ;if so, weÕre cool CLR.L (SP) ;no actionProc for DragControl @1 _DragTheRgn ;use window manager drag routine MOVE.L ExpandMem,a0 ; Now, clear the parameter we passed to Clr.l ExpandMemRec.emControlHandle(a0) ; DragTheRgn ; ; dispose of the region -- we donÕt need it anymore ; MOVE.L A4,-(SP) ;push the region _DisposRgn ;dispose it ; ; get the motion offset and, if its non-zero, send a message to the control ; MOVE.L (SP)+,D3 ;get the delta it was moved BEQ.S DoneDrgControl ;if zero, donÕt move it CMP.W #$8000,D3 ;was it aborted? BNE.S DCMoveIt ;if not, skip DoneDC1 MOVEQ #0,D3 ;pretend it was 0 BRA.S DoneDrgControl ;and weÕre done DCMoveIt TST.W DragFlag ;called from real MoveControl? BNE.S DoneDrgControl ;if not, donÕt move ; ; call MoveControl to move it to its new position ; MOVE.L (A3),A0 ;get control pointer MOVE.L ContrlRect(A0),D0 ;get current topLeft ADD D3,D0 ;compute new x position SWAP D0 ;get y in low part SWAP D3 ;ditto for curPosition ADD D3,D0 ;compute new y position SWAP D0 ;get x in low part ; ; call MoveControl ; MOVE.L A3,-(SP) ;push control handle MOVE.L D0,-(SP) ;push new position _MoveControl ;move it ; ; all done -- restore port, restore registers and go home ; DoneDrgControl _SetPort ;restore old port ; MOVE.L D3,D1 ;remember delta in D1 MOVEM.L (SP)+,D3-D4/A3-A4 ;restore work registers UNLK A6 ;deallocate stack frame MOVE.L (SP)+,A0 ;get return address ADD #18,SP ;strip parameters JMP (A0) ;return to caller ; ; Utility OwnerPort -- a utility used to save code. It saves the current grafPort ; on the stack and then enters the owning port of the control in A3 ; WARNING: CallControl depends on D0, D1 not being trashed. ; OwnerPort MOVE.L (SP)+,D2 ;get the return address SUBQ #4,SP ;allocate space on stack for result <16 Jul 85> MOVE.L D2,-(SP) ;replace the return address <16 Jul 85> MOVEM.L D0-D1,-(SP) ;we rely on D0 and D1 <16 Jul 85> PEA 12(SP) ;point to space on stack <16 Jul 85> _GetPort ;remember the port on the stack MOVE.L (A3),A0 ;get pointer to control data structure MOVE.L ContrlOwner(A0),-(SP) ;push owning windowPtr _SetPort ;make that the current port MOVEM.L (SP)+,D0-D1 ;restore the regs <16 Jul 85> RTS ;and return w/result on stack ; ; FUNCTION TrackControl(theControl: controlHandle; mousePt: Point; ; actionProc: ProcPtr): INTEGER; ; ; TrackControl is called when the mouse button goes down inside a control. It ; hilites the appropriate section of the control and retains control until the mouse ; button goes up. While looping, it calls the actionProc to allow the application ; to perform some action while the control is active (like smooth scrolling, or beeping, ; etc.). It returns a position code indicating where the mouse was in the control when ; the button when up (useful for momentary buttons). ; ; If the actionProc parameter is NIL, it wonÕt call any actionProc. If its -1 (actually, ; any odd number) it will use the local actionProc that is part of the control data ; structure. If the local actionProc is odd, donÕt use it... instead, send a message ; to the defProc. ; ; If the classification code of the part of the control weÕre in is > 128, then ; weÕre in an indicator part of a dial. If so, case out and drag the indicator ; around. ; TrackControl LINK A6,#-28 ;get space for locals MOVEM.L D3/A3,-(SP) ;save a work register MOVE.L 16(A6),A3 ;keep the controlHandle in A3 MOVE.L 12(A6),-8(A6) ;initialize mouse position ; begin roll-in ThrottleScrollingSpeed patch <3> ; set up startTicks for UseGAction below, even though we may not need it <3> SUBQ.L #4, SP ; <3> _TickCount ; Get a time stamp. <3> move.l ExpandMem,a0 ; <3> move.l ExpandMemRec.emScrollSpeedGlobals(a0),a0 ; <3> MOVE.L (SP)+,ScrollSpeedGlobals.startTicks(A0) ; And save it. <3> ; end roll-in ThrottleScrollingSpeed patch <3> ; ; preserve the current grafPort and enter the window that owns the control ; BSR.S OwnerPort MOVEQ #0,D3 ;mark initial code ; ; here is the main loop of trackControl. It reads the mouse position, tests the control, ; hilites the control based on the results of test control, calls the actionProc and ; repeats all this until the mouse button goes up. ; TrkCtlLoop MOVE.L A3,-(SP) ;push control handle for later hilite CLR.W -(SP) ;make room for TestControl result MOVE.L A3,-(SP) ;push control handle MOVE.L -8(A6),-(SP) ;push the mouse point _TestControl ;test the control ; ; make sure we only track the first section of a multi-part object (like a dial) ; that we go into ; NoAction TST D3 ;got anything yet? BNE.S CheckCPart ;if so, make sure its the right part MOVE (SP),D3 ;get this part as the one TST.B D3 ;indicator part? BPL.S CheckAction ;if not indicator, go handle it BRA DoTheThumb ;go handle dragging the thumb ; ; only hilite parts that match the code in D3 ; CheckCPart CMP (SP),D3 ;do they match BEQ.S CheckAction ;if so, its cool CLR (SP) ;pretend its out of range ; ; call the actionProc with the test result as the parameter, after hiliting ; the control ; CheckAction MOVE.W (SP),20(A6) ;save as result _HiliteControl ;hilite it MOVE.L 8(A6),D0 ;is there an actionProc? BEQ.S TCNextMouse ;"ThereÕs no action..." (E. Costello) ; ; is it odd? if so, use the local one ; BTST #0,D0 ;is it odd? BEQ.S UseGAction ;if not, use global actionProc ; ; the actionProc is odd so use the local one (if any) ; MOVE.L (A3),A0 ;get control pointer MOVE.L ContrlAction(A0),D0 ;get local action proc BEQ.S TCNextMouse ;if none, skip it BTST #0,D0 ;is the built in one odd? BEQ.S UseGAction ;is not, use it MOVEQ #TrackCtlMsg,D0 ;invoke actionProc in defProc MOVE 20(A6),D1 ;get part code as parameter BSR CallControl ;ask the control to do it BRA.S TCNextMouse ;now go hilite it ; UseGAction Move.l D0,-(SP) ; Save our action proc 'cause TickCount trashes it ; begin roll-in ThrottleScrollingSpeed patch <3> ; set up actionTicks for _ScrollDelay, even though we may not need it <3> SUBQ.L #4, SP ; <3> _TickCount ; Get a time stamp. <3> move.l ExpandMem,a0 ; <3> move.l ExpandMemRec.emScrollSpeedGlobals(a0),a0 ; <3> MOVE.L (SP)+,ScrollSpeedGlobals.actionTicks(A0) ; Save it <3> Move.l (SP)+,D0 ; get back our action proc ; call action proc that was passed in <3> MOVE.L A3,-(SP) ;pass control handle MOVE.W 20(A6),-(SP) ;duplicate test result MOVE.L D0,A0 ;get actionProc ptr JSR (A0) ;call it ; see if we need to delay <3> MOVE.W 20(A6), D0 ; get part code <3> CMP.W #inUpButton, D0 ; < up button? <3> BLT.S @noDelay ; Skip if so. <3> CMP.W #inPageDown, D0 ; > page down? <3> BGT.S @noDelay ; Skip if so. <3> ; we need a delay <3> SUBQ.L #2, SP ; Room for result. <3> move.l ExpandMem,a0 ; <3> move.l ExpandMemRec.emScrollSpeedGlobals(a0),a0 ; <3> MOVE.L ScrollSpeedGlobals.startTicks(a0), -(SP) ; <3> MOVE.L ScrollSpeedGlobals.actionTicks(a0), -(SP) ; <3> CLR.W -(SP) ; itemsVisible is unknown. <3> _ScrollDelay ADDQ.L #2, SP ; Toss result. <3> @noDelay ; end roll-in ThrottleScrollingSpeed patch <3> ; ; read next mouse position and loop while the mouse button is still down ; TCNextMouse PEA -8(A6) ;push mousePt buffer location _GetMouse ;read the mouse in local coordinates ; CLR.W -(SP) ;make room for function result _WaitMouseUp ;is mouse button still down? TST.B (SP)+ ;examine result BNE.S TrkCtlLoop ;if so, continue to loop ; ; unhilite the control ; MOVE.L A3,-(SP) ;push the control handle CLR.W -(SP) ;0 means unhilite _HiliteControl ;unhilite it ; ; restore grafPort, registers and return to caller ; TrackDone _SetPort ;restore original grafPort ; MOVEM.L (SP)+,D3/A3 ;restore work registers UNLK A6 ;de-allocate stack frame MOVE.L (SP)+,A0 ;get return address ADD #12,SP ;strip parameters JMP (A0) ;return to caller ; ; DoTheThumb handles the case when the FindWindow code is greater than 127. It drags ; the indicator by issuing a "ThumbDrag" message to get the rectangles and then calling ; DragControl with the implicit dragFlag parameter set. Finally, issue the move command ; to actually update the dial ; DoTheThumb MOVE (SP)+,20(A6) ;return code as result ADDQ #4,SP ;pop off control handle LEA -28(A6),A0 ;get address of parameter block MOVE.L 12(A6),(A0) ;set it up with the mousePt MOVE.L A0,D1 ;thatÕs the parameter block MOVEQ #ThumbCtlMsg,D0 ;calculate the boxes BSR CallControl ;ask the control to do it ; Move.w #$FFFF,DragFlag ;mark it as a call from thumb-drag MOVE.L 8(A6),D0 ;get the actionProc BTST #0,D0 ;is it odd? BEQ.S @1 ;if not, we got it MOVE.L (A3),A0 ;get the control pointer MOVE.L ContrlAction(A0),D0 ;get the builtin one BTST #0,D0 ;is the built-in one odd? BEQ.S @1 ;if not, use it MOVEQ #0,D0 ;otherwise, donÕt use it @1 MOVE.L D0,CurDragAction ;set up implicit actionProc param SUBQ #2,SP ;make room for return value CSS MOVE.L A3,-(SP) ;push the control handle CSS _GetCtlValue ;get the current control value (leave on stack) CSS MOVE.L A3,-(SP) ;push the control handle MOVE.L 12(A6),-(SP) ;push the mouse point LEA -28(A6),A0 ;get thumb parameter block MOVE.L A0,-(SP) ;push pointer to boundsRect PEA 8(A0) ;push pointer to slopRect MOVE.W 16(A0),-(SP) ;push axis parameter BSR DragCon1 ;drag the outline around CLR.W DragFlag ;clear the drag flag CSS ; TST.L D1 ;did it move at all? BEQ.S ReturnZero ;if not, weÕre done ADD #2,SP ;remove saved value of control as DragControl CSS ;told us the truth. ; ; OK, now we have the delta to move by in D1. Issue the pos message to actually ; set the dial to its new value. ; MOVEQ #PosCtlMsg,D0 ;position message BSR CallControl ;tell it to position itself ; ; all done with the indicator ; BRA.S TrackDone ReturnZero ; CSS ; we may be here because a custom drag was done and drag control lied to us. We need to ; return the right thing to the caller of trackcontrol so if the control moved we don't ; clear the return value. SUBQ #2,SP ; make room for return value CSS MOVE.L A3,-(SP) ; get control handle CSS _GetCtlValue ; get new control value CSS MOVE.W (SP)+,D1 ; get new value of control CSS MOVE.W (SP)+,D0 ; get old value of control CSS CMP.W D1,D0 ; did a custom drag do something out from CSS ; under us? CSS BNE.S TrackDone ; yes - don't zero return value. CSS CLR.W 20(A6) ;return zero BRA.S TrackDone ;all done ; PROCEDURE UpdateControls(theWindow: windowPtr; update: RgnHandle); ; ; UpdateControls is used to draw all the controls of a given window ; that are in the specified update region. Most useful for scrolling ; windows that contain controls. DrawSW EQU 4 ; also # bytes of params for DrawC UpdateSW EQU 8 ; also # bytes of params for UpdateC UpdtControls LINK A6,#-24 ; set up stack frame MOVEM.L D7/A3,-(SP) ; save work registers MOVE.L 12(A6),A3 ; get the window pointer MOVEQ #updateSW,D7 ; signal update (#bytes of params too) BRA.S DCCommon ; and use common code ; PROCEDURE DrawControls(theWindow: windowPtr); ; ; DrawControls is used to draw all the controls of a given window ; DonÕt call the defProc for controls that arenÕt in the portRect DrawControls LINK A6,#-24 ; set up stack frame MOVEM.L D7/A3,-(SP) ; save work registers MOVE.L 8(A6),A3 ; get the window pointer MOVEQ #drawSW,D7 ; signal draw (#bytes of params too) DCCommon ; preserve the pen state and set the pen to normal SUBQ #4,SP ;get some space MOVE.L SP,-(SP) ;push ptr to it _GetPort MOVE.L A3,-(SP) ;push current window _SetPort ;make it the port ; PEA -24(A6) ;get address of penState buffer MOVE.L (SP),-(SP) ;save ptr for restore later _GetPenState ;save the current penState _PenNormal ;set the pen to normal ; MOVE.L WControlList(A3),D0 ;get 1st control in list BEQ.S DoneDrwCtls ;if NIL, weÕre done ; ; Here is the loop that issues the "draw yourself" message to each control in the list. ; If it is UpdateControls, it only issues message to controls in update region. ; DCLoop MOVE.L D0,A3 ;get controlHandle in A3 CMP.W #updateSW,D7 ; is it update? BNE.S DoDC ; => no, donÕt check region SUBQ #2,SP ; room for result MOVE.L (A3),A0 ; handle -> pointer PEA contrlRect(A0) ; push the controlÕs rect MOVE.L 8(A6),-(SP) ; push the region handle _RectInRgn ; does the item need to be updated? TST.B (SP)+ ; NE if update needed BEQ.S SkipDC ; => control not in update region DoDC MOVEQ #0,D1 ;draw all BSR CallDControl ;issue the draw message SkipDC MOVE.L (A3),A0 ;get control pointer MOVE.L NextControl(A0),D0 ;get next one in list BNE.S DCLoop ;loop till we get a NIL one ; DoneDrwCtls _SetPenState ;restore the pen state _SetPort ;restore grafPort ; MOVE.L D7,D0 ; get params to strip MOVEM.L (SP)+,D7/A3 ; restore work registers UNLK A6 ; unbuild stack frame MOVE.L (SP)+,A0 ; get return address ADDA.L D0,SP ; strip parameters JMP (A0) ; ; ; DELETELIST -- delete an element from a list. On entry, A0 contains the ; handle of the element to be deleted while A1 contains the address of the ; list header. On exit, D0 contains zero if the deletion was successful ; and -1 if the element to be deleted couldnÕt be found ; ; DeleteList MOVEM.L D1/A2-A3,-(SP) ;save some A-regs to play with MOVEQ #-1,D0 ;assume we canÕt find it TST.L (A1) ;is the list empty? BEQ.S DELDONE ;if so, weÕre done MOVE.L (A1),A2 ;get handle of 1st element MOVE.L A1,A3 ;header is "prev" element BRA.S DeleteNext ;dive right in ; ; here is the loop where we search for the element to be deleted ; DELETELOOP MOVE.L (A2),A3 ;get pointer to current element MOVE.L (A3),A2 ;get handle to next one MOVE.L A2,D1 ;is it NIL? BEQ.S DELDONE ;if so, weÕre done DeleteNext CMP.L A0,A2 ;is it the one we want? BNE.S DELETELOOP ;if at first you donÕt succeed... ; ; delete the element pointed to by A2. A3 points to itÕs predecessor ; MOVE.L (A2),A2 ;get pointer to one to be deleted MOVE.L (A2),(A3) ;delete it! MOVEQ #0,D0 ;flag the successful deletion ; ; all done so restore registers and return to caller ; DELDONE MOVEM.L (SP)+,D1/A2-A3 ;restore registers RTS ; ; FUNCTION FindControl( thePoint: Point; ; theWindow: WindowPtr; ; VAR theControl: ControlHandle): INTEGER; ; ; FindControl is the routine that correlates a mouse position with the logical ; data structure in that position. The mouse point is passed in the local coordinates ; of the window and it returns the control handle of the control the point is in, ; as well as a classification code further classifying the position. ; FindControl BLANKS ON STRING ASIS LINK A6,#-4 ;reserve space for locals MOVEM.L D2-D3/A3,-(SP) ;save work registers (one extra) ; ; assume classification code is zero (inDesk) and the controlHandle is NIL. ; LEA 8(A6),A0 ;point to control handle MOVE.L (A0)+,A1 ;get pointer to controlHandle CLR.L (A1) ;make it NIL MOVE.L (A0)+,A3 ;get the windowPtr MOVE.L (A0)+,D3 ;get the mouse point CLR.W (A0) ;set classification code to zero ; ; save the current grafPort and set the parameter window as the new one ; MOVE.L SP,-(SP) ;point to savePort buffer _GetPort ;save the port in it MOVE.L A3,-(SP) ;make the port the current window _SetPort ; ; first make sure the window is visible and the point is somewhere inside the window ; TST.B WVisible(A3) ;is this window visible? BEQ TrackDone ;if not, don't test it, return 0 ; ; check to see if its in the portRect of the window ; CLR.W -(SP) ;make room for function result MOVE.L D3,-(SP) ;push the point PEA PortRect(A3) ;push the portRect of the window _PtInRect ;is the point in the window? TST.B (SP)+ ;examine result BEQ TrackDone ;if its not, return 0 ; ; its in the content area of the window so waltz through the controlList to see ; if its in any of the controls. Start with the first item in the control list ; MOVE.L WControlList(A3),D0 ;get 1st control handle BEQ.S TrackDone ;if NIL, its not in any MOVE.L D0,A3 ;get control handle in A3 ; FControlLoop MOVE.L (A3),A0 ;handle -> pointer CMP.B #255,ContrlHilite(A0) ;is it 255-hilited? BEQ.S SkipControl ;is so, skip it CLR.W -(SP) ;make room for function result MOVE.L A3,-(SP) ;push control handle MOVE.L D3,-(SP) ;push the point _TestControl ;ask the control what's up MOVE.W (SP)+,D0 ;get the result of the test BNE.S GotFControl ;if non-zero, then we found something ; ; its not in this control, so try the next one in the list ; SkipControl MOVE.L (A3),A0 ;handle -> pointer MOVE.L NextControl(A0),A3 ;get the next one MOVE.L A3,D0 ;is it NIL BNE.S FControlLoop ;loop till we find one ; ; its not in any control, so just return ; BRA TrackDone ; ; at this point, we know we're in some control. A3 has the control handle while D0 has ; the classification code. Update the controlHandle result and let common code finish ; up the rest ; GotFControl MOVE.L 8(A6),A0 ;get pointer to control result MOVE.L A3,(A0) ;update with control handle MOVE D0,20(A6) ;update classification code result BRA.S SkipControl ;go see if its in any others cmgrEnd END