mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-28 13:52:37 +00:00
3047 lines
103 KiB
Plaintext
3047 lines
103 KiB
Plaintext
|
;
|
|||
|
; File: ListMgrPACK.a
|
|||
|
;
|
|||
|
; Contains: the List Manager
|
|||
|
;
|
|||
|
; Written by: Steve Capps and Ernie Beernik
|
|||
|
;
|
|||
|
; Copyright: © 1984-1993 by Apple Computer, Inc. All rights reserved.
|
|||
|
;
|
|||
|
; This file is used in these builds: Bigbang Sys606
|
|||
|
;
|
|||
|
; Change History (most recent first):
|
|||
|
;
|
|||
|
; <SM7> 9/9/93 SAM Changed ShiftDown to not assume the PtInRect will leave
|
|||
|
; thePoint.v in D1 (good lord!).
|
|||
|
; <SM6> 8/16/93 fau Moved <LW3,4,5> to happen in the GetTheListProc routine, instead
|
|||
|
; of where they were. This is where the check should be
|
|||
|
; performed. This was exposed by a PageMaker bug, after Ludwig
|
|||
|
; shipped.
|
|||
|
; <SM5> 6/14/93 kc Roll in Ludwig.
|
|||
|
; <LW5> 5/3/93 chp Flush the caches for LDEF 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)
|
|||
|
; <LW4> 3/8/93 fau Made the compare in previous checkin be 16 bytes, instead of 12,
|
|||
|
; and unsigned.
|
|||
|
; <LW3> 3/6/93 fau Fixed bug 1070072. Essentially, a slimy developer was using a
|
|||
|
; fake LDEF to stuff their own code and NOT flushing the cache
|
|||
|
; afterwards. They relied on the HLOCK in the initlist routine to
|
|||
|
; flush it for them. We "fixed" them by checking the size of the
|
|||
|
; LDEF handle to see if it's less than 12 bytes. If so, we will
|
|||
|
; flush the cache for them. This penalizes developers who use
|
|||
|
; this method and do flush the cache. All for compatibility.
|
|||
|
; <SM4> 1/27/93 PN Add emStartTicks extended memory global to use in ListMgrPack to
|
|||
|
; replace the 'startTicks'.
|
|||
|
; <3> 11/11/92 GMA Set RomMapInsert to mapTrue before getting LDEF resources. fixes
|
|||
|
; bug # 1052658.
|
|||
|
; <SM2> 11/5/92 SWC Changed PackMacs.a->Packages.a.
|
|||
|
; <13> 3/4/91 dba dty: get rid of SysVers conditionals
|
|||
|
; <12> 1/14/91 dba (stb) Restore the use of hilite value of 255 when there is no
|
|||
|
; scrolling possible.
|
|||
|
; <11> 1/14/91 dba (vl) Use the hilite value of 254 (feature added to the scroll
|
|||
|
; bar CDEF) for inactive scroll bars.
|
|||
|
; <10> 10/24/90 ngk <KSM>Fix AddColumn/AddRow to not trash heap if growing handle fails
|
|||
|
; <9> 9/17/90 BG Removed <6>. 040s are behaving more reliably now.
|
|||
|
; <8> 8/17/90 ngk Fix bug in last bug fix. changed BHS to BHI.
|
|||
|
; <7> 7/29/90 ngk Fix bug in LClick where is was testing the is_selected bit of a
|
|||
|
; cell out of range when clicking past bottom of item list.
|
|||
|
; <6> 7/19/90 BG Added EclipseNOPs for flakey 040s.
|
|||
|
; <5> 4/16/90 BBH fixed parameter passing to the ldefproc in LNew (was danger of
|
|||
|
; passing an odd address in the parameter designed lRect which
|
|||
|
; caused Pascal and C ldefproc's to crash occasionally on 68000
|
|||
|
; machines)
|
|||
|
; <4> 3/21/90 dba get rid of hiliting while auto-scrolling; fix bug in check for
|
|||
|
; double-click; assume that ScrollDelay is implemented on 7.0
|
|||
|
; systems; fix bug where horizontal auto-scrolling is tied to
|
|||
|
; vertical auto-scrolling
|
|||
|
; <3> 12/28/89 dba changed from PROC to MAIN to get dead code stripping
|
|||
|
; <2> 12/20/89 dba fix bug in JustRect routine that scrolls the list wrong; get
|
|||
|
; package handle from low memory to lock instead of using
|
|||
|
; RecoverHandle
|
|||
|
; <1.6> 12/10/89 EMT NEEDED FOR 6.0.5: Check for UserDelay trap before using
|
|||
|
; ScrollDelay.
|
|||
|
; <1.5> 12/7/89 dba added interface to SetHilite for use by Standard File who is
|
|||
|
; intimate with the List Manager; also fix some bugs from the last
|
|||
|
; version, including PinRect
|
|||
|
; <1.4> 12/7/89 dba got rid of MyRectInRgn and MyPinRect; merged the scroll bar
|
|||
|
; code; created the MyShowWindow and MyValidRect routines
|
|||
|
; <1.3> 11/21/89 EMT NEEDED FOR 6.0.5: Added humane scrolling.
|
|||
|
; <1.2> 11/17/89 dba fixed flashing arrow while scrolling; frame rectangle and call
|
|||
|
; ValidRect when hiding; the scroll bar to deactivate it (this
|
|||
|
; fixes a bug that was worked around in the Chooser and Control
|
|||
|
; Panel); get rid of code to handle 64K ROMs; fixed one or two
|
|||
|
; bugs with handles and registers
|
|||
|
; <1.1> 10/11/89 ngk bug fix to ListGetSelect, it used to not return that the last
|
|||
|
; item was selected
|
|||
|
; <1.0> 11/16/88 CCH Added to EASE.
|
|||
|
; <S412> 2/29/88 GP and EMT test for an empty handle (purged LDEF)
|
|||
|
; <S3> 12/21/86 JTC 32-bit cleaning, with care to get the conditionals correct
|
|||
|
; for old ROMs.
|
|||
|
; <S2> 12/17/86 EHB Fixed lock state problem in StdExit.
|
|||
|
; 12/2/86 GP Changed handling of LVBadFit in SetVisible due to conflicting
|
|||
|
; assignment of lDoHAutoscroll
|
|||
|
; 8/14/86 DLD Converted source to MPW.
|
|||
|
; 5/30/86 SAB Fixed HUnLock bug in UnlockLProc which was trying to test for
|
|||
|
; NIL LDEF Handle, but actually relied on the condition code left
|
|||
|
; by the LDEF
|
|||
|
; 12/16/85 EHB Bad exit in ListHilite (special StdExit for internal routines)
|
|||
|
; 12/11/85 EHB Added checking for defproc not found (just skips call to
|
|||
|
; defproc); Fixed DelRow/Col update bug when all rows/columns
|
|||
|
; deleted; Do update after justRect,moveRect in DelExit; Don’t
|
|||
|
; inval cells that aren’t visible (intersect with rview); SetHilite
|
|||
|
; was calling DrawControl when control invisible; Intensive
|
|||
|
; scramble testing done; Removed bogus size checking code in
|
|||
|
; setCell/addtocell; changed all #lock/#unlock to _Lock/_Unlock
|
|||
|
; 12/11/85 EHB Added flags that disable autoscrolling. Default is disabled if
|
|||
|
; there is not a scroll bar on that axis.
|
|||
|
; 11/18/85 EHB Fixed ListSize bugs (of unknown origin)
|
|||
|
; 11/15/85 EHB Fixed up RAM entry and RecoverHandle
|
|||
|
; 8/15/85 EHB ROMMapInsert for ROM version only (no longer used since not in
|
|||
|
; ROM)
|
|||
|
; 8/5/85 EHB Left some error checking hanging...
|
|||
|
; 8/5/85 EHB Fixed SectRect bug in DoDraw
|
|||
|
; 7/16/85 EHB Lock down RAM version of List Manager
|
|||
|
; 7/11/85 EHB Squished the dispatcher for small ROMs Optimized for routines
|
|||
|
; fixed in ROM (RectInRgn, PinRect)
|
|||
|
; 7/9/85 EHB added setup of ROMMapInsert for ROM resources
|
|||
|
; 5/22/85 EHB added slop to double clicking, disabled double clicks in scroll
|
|||
|
; bars moved noDraw testing to low level=> NO drawing if doDraw
|
|||
|
; FALSE!!
|
|||
|
;
|
|||
|
|
|||
|
print push,off
|
|||
|
load 'StandardEqu.d'
|
|||
|
include 'Packages.a'
|
|||
|
include 'ListMgrPriv.a'
|
|||
|
INCLUDE 'SysEqu.a' ; <LW3> fau
|
|||
|
|
|||
|
MACHINE MC68020 ; needed for cache flush <LW3> fau
|
|||
|
print pop
|
|||
|
|
|||
|
ListMgrPackage MAIN EXPORT
|
|||
|
|
|||
|
ListMgrHandle equ AppPacks + listMgr * 4 ; handle to List Manager package
|
|||
|
IntUtilHandle equ AppPacks + intUtil * 4 ; handle to International Utilities package
|
|||
|
|
|||
|
BRA.S @skipHeader
|
|||
|
DC.W 0 ; flags
|
|||
|
DC.L ('PACK') ; resource type
|
|||
|
DC.W 0 ; id = 0
|
|||
|
DC.W 7 ; version 7
|
|||
|
@skipHeader
|
|||
|
|
|||
|
MOVE.L (SP)+,a1 ; get return address
|
|||
|
|
|||
|
move.l ListMgrHandle,A0 ; get our handle <2>
|
|||
|
_HGetState ; D0 := current lock, etc. state <S3>
|
|||
|
MOVE.B D0,D1 ; D1 := ditto <S3>
|
|||
|
_HLock ; and lock ourselves down
|
|||
|
|
|||
|
MOVE.W (SP)+,D0 ; get the selector
|
|||
|
ASR.W #1,D0 ; table of offsets, not jumps
|
|||
|
LEA ListStart,A0 ; point to dispatch table
|
|||
|
ADD.W 0(A0,D0.W),A0 ; add offset to address
|
|||
|
jsr (A0) ; dispatch the call
|
|||
|
|
|||
|
move.l ListMgrHandle,A0 ; get our handle <2>
|
|||
|
MOVE.B D1,D0 ; D0 := saved lock state <S3>
|
|||
|
_HSetState ; restore to handle <S3>
|
|||
|
|
|||
|
jmp (a1) ; return to our caller
|
|||
|
|
|||
|
DC.W SetHilite-ListStart ; for internal use by Standard File only
|
|||
|
ListStart
|
|||
|
DC.W ListActivate-ListStart
|
|||
|
DC.W ListAddColumn-ListStart
|
|||
|
DC.W ListAddRow-ListStart
|
|||
|
DC.W ListAddToCell-ListStart
|
|||
|
DC.W ListAutoScroll-ListStart
|
|||
|
DC.W ListCellSize-ListStart
|
|||
|
DC.W ListClick-ListStart
|
|||
|
DC.W ListClrCell-ListStart
|
|||
|
DC.W ListDelColumn-ListStart
|
|||
|
DC.W ListDelRow-ListStart
|
|||
|
DC.W ListDispose-ListStart
|
|||
|
DC.W ListDoDraw-ListStart
|
|||
|
DC.W ListDraw-ListStart
|
|||
|
DC.W ListFind-ListStart
|
|||
|
DC.W ListGetCell-ListStart
|
|||
|
DC.W ListGetSelect-ListStart
|
|||
|
DC.W ListLastClick-ListStart
|
|||
|
DC.W ListNew-ListStart
|
|||
|
DC.W ListNextCell-ListStart
|
|||
|
DC.W ListRect-ListStart
|
|||
|
DC.W ListScroll-ListStart
|
|||
|
DC.W ListSearch-ListStart
|
|||
|
DC.W ListSetCell-ListStart
|
|||
|
DC.W ListSetSelect-ListStart
|
|||
|
DC.W ListSize-ListStart
|
|||
|
DC.W ListUpdate-ListStart
|
|||
|
|
|||
|
; All procs have the form of ...h: ListHandle ) or ...c: Point; h: ListHandle )
|
|||
|
; StdEntry takes advantage of this consistency and loads up some registers in a standard way.
|
|||
|
|
|||
|
; StdEntry locks down the handle, and saves it A4. The dereferenced handle is saved
|
|||
|
; in A3. It then puts 2nd param in D7 (which is usually a cell). Watch out for strange
|
|||
|
; references to D7 in routines that don’t have c passed to them. Finally it saves the
|
|||
|
; current port and gets into the list’s port.
|
|||
|
|
|||
|
; Stack Frame used by almost all routines. SavePort is set up by StdEntry. GoodCell thru
|
|||
|
; index are set up by MyFind. R is a temporary rect. VisBounds is set by the routine
|
|||
|
; GetVisBounds, and it is the equivalent of dataBounds, but it is adjusted if cells do not
|
|||
|
; fit exactly into the visBounds. Below the stack frame are the saved registers and then <S3>
|
|||
|
; the saved state of the input handle. This is unraveled in the exit procedure. <S3>
|
|||
|
|
|||
|
; This entry and exit preserves D1 and A1, because the package wrapper puts the real return
|
|||
|
; address in A1 and the handle state in D1.
|
|||
|
|
|||
|
goodCell EQU -4 ; state of next-to-last parameter
|
|||
|
offset EQU goodCell-4 ; offset of cell
|
|||
|
len EQU offset-4 ; length of cell
|
|||
|
index EQU len-4 ; index to current cell
|
|||
|
r EQU index-8 ; temp rect
|
|||
|
visBounds EQU r-8 ; bounds for scrolling
|
|||
|
stdFrame EQU visBounds ; size of std frame
|
|||
|
|
|||
|
ListMgrSavedRegisters REG A1-A4/D1-D7
|
|||
|
|
|||
|
StdEntry
|
|||
|
MOVE.L (SP)+,A0 ; get local RTS
|
|||
|
LINK A6,#stdFrame ; std frame for every routine
|
|||
|
MOVEM.L ListMgrSavedRegisters,-(SP)
|
|||
|
MOVE.L 8(A6),A4 ; save list handle in A4
|
|||
|
MOVE.L (A4),A3 ; save list pointer in A3
|
|||
|
MOVE.L 12(A6),D7 ; get next to last parameter in D7 (often cell)
|
|||
|
|
|||
|
move.l a0,a2 ; keep return address in A2 for a moment
|
|||
|
|
|||
|
StdEntryMidstream
|
|||
|
|
|||
|
MOVEA.L A4,A0 ; input handle <S3>
|
|||
|
_HGetState ; D0 := current lock, etc. state<S3>
|
|||
|
MOVE.B D0,-(SP) ; save across entire LM call <S3>
|
|||
|
_HLock ; lock handle across call <S3>
|
|||
|
subq #4,sp ; make room for saved port
|
|||
|
move.l sp,-(sp) ; save the port
|
|||
|
_GetPort
|
|||
|
MOVE.L port(A3),-(SP) ; set port to our port
|
|||
|
_SetPort
|
|||
|
|
|||
|
jmp (a2) ; return to our caller inside the List Mgr.
|
|||
|
|
|||
|
ListNewEntry ; entry point used by ListNew
|
|||
|
MOVE.L (SP)+,a2 ; get local RTS
|
|||
|
BRA.S StdEntryMidstream
|
|||
|
|
|||
|
StdExit
|
|||
|
MOVE.W D0,D3 ; amount of stack to kill <S3>
|
|||
|
|
|||
|
_SetPort ; restore port
|
|||
|
MOVE.B (SP)+,D0 ; saved handle state <S3>
|
|||
|
MOVEA.L A4,A0 ; extant handle (could be NIL)
|
|||
|
_HSetState ; restore handle state (works for NIL)
|
|||
|
@noHandle
|
|||
|
|
|||
|
MOVE.W D3,D0 ; D0 := amount of stack to kill <S3>
|
|||
|
MOVEM.L (SP)+,ListMgrSavedRegisters
|
|||
|
UNLK A6
|
|||
|
MOVE.L (SP)+,A0 ; get return address
|
|||
|
ADD.W D0,SP ; strip params
|
|||
|
JMP (a0) ; return
|
|||
|
|
|||
|
;------------
|
|||
|
; GetVisBounds is sort of a standard entry routine. It is called by all
|
|||
|
; routines that need to do scrolling and positioning of scroll bars. The upper left
|
|||
|
; visible boundary is always the same as the upper left data boundary. The lower right
|
|||
|
; must be set according to whether or not cells fit exactly into the window.
|
|||
|
|
|||
|
; The flags LHBadFit and LVBadFit are set up by ListCellSize when the size of the cells
|
|||
|
; are initially set.
|
|||
|
|
|||
|
GetVisBounds
|
|||
|
MOVE.L dataBounds(A3),visBounds(A6) ; assume that the visible
|
|||
|
MOVE.L dataBounds+4(A3),visBounds+4(A6) ; bounds is the same as data
|
|||
|
|
|||
|
BTST #LHBadFit,ListFlags(A3) ; if cells don’t fit exactly
|
|||
|
BEQ.S @1 ; then add one
|
|||
|
ADD.W #1,visBounds+right(A6) ; to right
|
|||
|
@1
|
|||
|
BTST #LVBadFit,ListFlags(A3) ; if cells don’t fit exactly
|
|||
|
BEQ.S @2 ; then add one
|
|||
|
ADD.W #1,visBounds+bottom(A6) ; to bottom
|
|||
|
@2
|
|||
|
RTS
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; FUNCTION ListLastClick (h: ListHandle): Cell;
|
|||
|
;
|
|||
|
; Returns the cell number of the last cell clicked.
|
|||
|
;
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
ListLastClick
|
|||
|
MOVE.L 4(SP),A0 ; get list handle
|
|||
|
MOVE.L (A0),A0 ; get list pointer
|
|||
|
MOVE.L lastClick(A0),8(SP) ; return result
|
|||
|
MOVE.L (SP)+,(SP) ; strip parameter
|
|||
|
RTS ; and return to restore handle lock state
|
|||
|
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE SetHilite(h: ListHandle );
|
|||
|
;
|
|||
|
; SetHilite is an internal routine used to update the scroll bars.
|
|||
|
;
|
|||
|
; There are two basic things that need to be done to scroll bars.
|
|||
|
; When the amount of data in the list changes, or the size of the
|
|||
|
; list changes, or the size of the cells change, or if the list is
|
|||
|
; scrolled, then the control values must be updated. When the list
|
|||
|
; is activated or deactivated, the hilite state of the list must be
|
|||
|
; adjusted.
|
|||
|
;
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
SetHilite ; called when data or window changes
|
|||
|
BSR.S StdEntry ; set things up
|
|||
|
|
|||
|
BTST #noDraw,ListFlags(A3) ; is drawing on?
|
|||
|
BNE.S @noDraw ; => nope, just exit
|
|||
|
|
|||
|
BSR.S GetVisBounds ; set scrolling bounds
|
|||
|
|
|||
|
MOVE.L hScroll(A3),A0 ; get horizontal scroll handle
|
|||
|
MOVE.W #h,D4 ; use left and right
|
|||
|
BSR.S SetAScroll ; set min, max, activate
|
|||
|
|
|||
|
MOVE.L vScroll(A3),A0 ; get vertical scroll handle
|
|||
|
MOVE.W #v,D4 ; use top and bottom
|
|||
|
BSR.S SetAScroll ; set min, max, activate
|
|||
|
@noDraw
|
|||
|
BRA Std4Exit ; and use routine exit
|
|||
|
|
|||
|
;----------------------------
|
|||
|
; SetAScroll is a code saving utility.
|
|||
|
; It is called with a control handle in A0, and
|
|||
|
; and offset (top or left) in D4.
|
|||
|
|
|||
|
SetAScroll
|
|||
|
MOVE.L A0,D7 ; test handle
|
|||
|
BEQ.S @done ; can’t get a handle on it
|
|||
|
|
|||
|
moveq #0,d6
|
|||
|
MOVE.W visBounds(A6,D4.W),D6 ; get min for later
|
|||
|
moveq #0,d5
|
|||
|
MOVE.W visBounds+botRight(A6,D4.W),D5 ; stuff and save max
|
|||
|
SUB.W visible+botRight(A3,D4.W),D5
|
|||
|
moveq #0,d3
|
|||
|
MOVE.W visible(A3,D4.W),D3 ; get visible
|
|||
|
ADD.W D3,D5 ; and use to set max
|
|||
|
|
|||
|
; figure out the right hilite for the control
|
|||
|
; 0 for normal circumstances
|
|||
|
; 255 if there is no scrolling to do
|
|||
|
; 254 if the list is not active (overrides 255)
|
|||
|
|
|||
|
moveq #0,d0 ; set up high byte of D0 <11>
|
|||
|
cmp.w d6,d5 ; is max > min? <12>
|
|||
|
sle.b d0 ; no, unhilite control (if not already so) <12>
|
|||
|
tst.b LActive(a3) ; are we active? <11>
|
|||
|
bne.s @active ; => yes, don’t use 254 hiliting <11>
|
|||
|
move.b #254,d0 ; => no, use 254 hiliting <11>
|
|||
|
@active
|
|||
|
|
|||
|
; set all of the values in the control
|
|||
|
|
|||
|
move.l (a0),a0 ; dereference the control handle
|
|||
|
|
|||
|
cmp.w contrlMin(a0),d6 ; is the minimum different?
|
|||
|
bne.s @doSetMinimum
|
|||
|
moveq #-1,d6 ; don’t set minimum
|
|||
|
@doSetMinimum
|
|||
|
|
|||
|
cmp.w contrlMax(a0),d5 ; is the maximum different?
|
|||
|
bne.s @doSetMaximum
|
|||
|
moveq #-1,d5 ; don’t set minimum
|
|||
|
@doSetMaximum
|
|||
|
|
|||
|
cmp.w contrlValue(a0),d3 ; is the value different?
|
|||
|
bne.s @doSetValue
|
|||
|
moveq #-1,d3 ; don’t set value
|
|||
|
@doSetValue
|
|||
|
|
|||
|
move.b contrlHilite(a0),d1 ; get the current hilite value
|
|||
|
bz.s @hilite ; if there is nothing hilited, we can do the hilite
|
|||
|
cmp.b #254,d1 ; is it a 254 or 255? <11>
|
|||
|
blo.s @noHilite ; no, don’t do hilite while scrolling
|
|||
|
@hilite
|
|||
|
cmp.b d0,d1 ; any change to hilite?
|
|||
|
beq.s @noHilite
|
|||
|
MOVE.L D7,-(SP) ; push handle
|
|||
|
MOVE.W D0,-(SP) ; make inactive with the magic 254, or make active with 0 <11>
|
|||
|
_HiliteControl ; and stuff hilite value
|
|||
|
@noHilite
|
|||
|
|
|||
|
tst.l d6 ; any change to min?
|
|||
|
bmi.s @noMin
|
|||
|
MOVE.L D7,-(SP) ; push handle
|
|||
|
MOVE.W D6,-(SP) ; push min
|
|||
|
_SetMinCtl
|
|||
|
@noMin
|
|||
|
|
|||
|
tst.l d5 ; any change to max?
|
|||
|
bmi.s @noMax
|
|||
|
MOVE.L D7,-(SP) ; push scroll handle
|
|||
|
MOVE.W D5,-(SP) ; and max value
|
|||
|
_SetMaxCtl
|
|||
|
@noMax
|
|||
|
|
|||
|
tst.l d3 ; any change to value?
|
|||
|
bmi.s @noValue
|
|||
|
MOVE.L D7,-(SP) ; push control handle
|
|||
|
MOVE.W D3,-(SP) ; and current value
|
|||
|
_SetCtlValue
|
|||
|
@noValue
|
|||
|
|
|||
|
MOVE.L D7,-(SP) ; show it just in case drawing
|
|||
|
bsr.s MyShowControl ; was just turned on
|
|||
|
@done
|
|||
|
RTS
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListActivate( act: BOOLEAN; h: ListHandle );
|
|||
|
;
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
ListActivate
|
|||
|
BSR StdEntry ; ho hum
|
|||
|
|
|||
|
BTST #noDraw,ListFlags(A3) ; is drawing on?
|
|||
|
BNE.S @done ; => nope, just exit
|
|||
|
|
|||
|
MOVE.B 12(A6),LActive(A3) ; record active state
|
|||
|
LEA DrawASel,A2 ; get routines that draws selections
|
|||
|
BSR DoSelLoop ; and call once for each selection
|
|||
|
|
|||
|
BSR.S DrawScrollBars
|
|||
|
@done
|
|||
|
|
|||
|
Std6Exit
|
|||
|
MOVEQ #6,D0 ; adios
|
|||
|
BRA StdExit
|
|||
|
|
|||
|
;-----------------------
|
|||
|
; DrawScrollBars draws both the horizontal and vertical scroll bars.
|
|||
|
;
|
|||
|
; In: A4 list handle
|
|||
|
|
|||
|
DrawScrollBars
|
|||
|
move.l a4,-(sp) ; set up the hiliting
|
|||
|
bsr.s SetHilite
|
|||
|
|
|||
|
MOVE.L hScroll(A3),D0 ; get handle to control
|
|||
|
BSR.S DrawScrollBar ; do horizontal
|
|||
|
MOVE.L vScroll(A3),D0 ; get handle to control
|
|||
|
|
|||
|
DrawScrollBar
|
|||
|
beq.s @done ; no handle, all done
|
|||
|
|
|||
|
MOVE.L d0,a2 ; get handle to control
|
|||
|
move.l (a2),a0 ; get pointer to control
|
|||
|
CLR.B contrlVis(a0) ; mark it invisible to force redraw
|
|||
|
MOVE.L D0,-(SP) ; push control handle
|
|||
|
bsr.s MyShowControl ; make the control visible
|
|||
|
@done
|
|||
|
|
|||
|
RTS
|
|||
|
|
|||
|
;-----------------------
|
|||
|
; MyShowControl is the same as ShowControl, except that it also validates the control’s
|
|||
|
; rectangle. It should only be called for rectangular controls (here used only for scroll bars).
|
|||
|
; A more advanced version could be written that uses the control’s region.
|
|||
|
|
|||
|
MyShowControl
|
|||
|
move.l 4(sp),a1 ; get the control handle
|
|||
|
move.l (a1),a0 ; dereference and point to the control record
|
|||
|
|
|||
|
lea contrlRect+8(a0),a0 ; point after the control’s rectangle
|
|||
|
move.l -(a0),-(sp) ; push the rectangle on the stack
|
|||
|
move.l -(a0),-(sp)
|
|||
|
|
|||
|
move.l a1,-(sp) ; push control handle for ShowControl
|
|||
|
_ShowControl
|
|||
|
|
|||
|
move.l sp,-(sp) ; push pointer to rectangle for ValidRect
|
|||
|
bsr.s MyValidRect
|
|||
|
|
|||
|
addq.l #8,sp ; remove the rectangle from the stack
|
|||
|
move.l (sp)+,(sp) ; remove the control handle from the stack
|
|||
|
rts
|
|||
|
|
|||
|
;-----------------------
|
|||
|
; MyValidRect is the same as ValidRect, except that it intersects the validate region with the
|
|||
|
; visRgn and clipRgn. This is useful so that we only validate the area that we just drew, without
|
|||
|
; marking areas that are still not drawn as valid.
|
|||
|
|
|||
|
MyValidRect
|
|||
|
move.l d3,-(sp) ; save register for region handle
|
|||
|
|
|||
|
subq.l #4,sp ; make room for region handle
|
|||
|
_NewRgn
|
|||
|
move.l (sp),d3 ; keep region handle around
|
|||
|
move.l 4+4+4(sp),-(sp) ; get rectangle from lower part of stack
|
|||
|
_RectRgn ; make the region
|
|||
|
|
|||
|
subq.l #4,sp ; make room for the port pointer
|
|||
|
move.l sp,-(sp) ; point where to put the port
|
|||
|
_GetPort
|
|||
|
move.l (sp)+,a0 ; get the port
|
|||
|
|
|||
|
move.l d3,-(sp)
|
|||
|
move.l clipRgn(a0),-(sp)
|
|||
|
move.l d3,-(sp)
|
|||
|
move.l d3,-(sp)
|
|||
|
move.l visRgn(a0),-(sp)
|
|||
|
move.l d3,-(sp)
|
|||
|
_SectRgn ; intersect with both regions
|
|||
|
_SectRgn
|
|||
|
|
|||
|
move.l d3,-(sp)
|
|||
|
_ValidRgn ; do the invalidate
|
|||
|
|
|||
|
move.l d3,-(sp)
|
|||
|
_DisposRgn ; get rid of the region now
|
|||
|
|
|||
|
move.l (sp)+,d3 ; restore register
|
|||
|
move.l (sp)+,(sp) ; remove the rectangle pointer from the stack
|
|||
|
rts
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListAutoScroll( h: ListHandle );
|
|||
|
; 8
|
|||
|
; Scroll the topmost selection to the top left of the screen iff it isn’t
|
|||
|
; visible. If no selections, or that selection is visible, do nothing.
|
|||
|
;
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
ListAutoScroll
|
|||
|
BSR StdEntry ; hoe humb
|
|||
|
|
|||
|
; get first selection
|
|||
|
|
|||
|
SUBQ #2,SP ; make room for result
|
|||
|
MOVE.B #1,-(SP) ; get the next selection
|
|||
|
PEA r(A6) ; temp storage for c
|
|||
|
MOVE.L dataBounds+topLeft(A3),r(A6) ; start search at first cell
|
|||
|
MOVE.L A4,-(SP) ; pass the handle
|
|||
|
_LGetSelect ; get the next selection
|
|||
|
MOVE.B (SP)+,D0 ; test the result
|
|||
|
BEQ.S @done ; => sorry, no selections
|
|||
|
|
|||
|
MOVE.L r(A6),D7 ; get the returned cell
|
|||
|
|
|||
|
; is it visible?
|
|||
|
|
|||
|
BSR.S IsCellVisible ; is cell visible? <10Dec85>
|
|||
|
BNE.S @done ; => yes, don’t scroll
|
|||
|
|
|||
|
; else scroll the selected cell to the upper left of the visible
|
|||
|
|
|||
|
SUB.W visible+left(A3),D7 ; get horizontal delta
|
|||
|
SWAP D7
|
|||
|
SUB.W visible+top(A3),D7 ; get vertical delta
|
|||
|
SWAP D7
|
|||
|
MOVE.L D7,-(SP) ; push dh,dv
|
|||
|
MOVE.L A4,-(SP) ; and list handle
|
|||
|
_LScroll ; and update the screen
|
|||
|
@done
|
|||
|
|
|||
|
Std4Exit
|
|||
|
MOVEQ #4,D0
|
|||
|
BRA StdExit ; and scurry back home
|
|||
|
|
|||
|
|
|||
|
;------------------------------
|
|||
|
;
|
|||
|
; IsCellVisible tests to see if the cell in D7 is visible.
|
|||
|
; If so, it returns NE.
|
|||
|
|
|||
|
IsCellVisible
|
|||
|
SUBQ #2,SP ; make room for result
|
|||
|
MOVE.L D7,-(SP) ; pass point
|
|||
|
PEA visible(A3) ; and the visible rect
|
|||
|
_PtInRect ; is it visible
|
|||
|
TST.B (SP)+
|
|||
|
RTS ; NE if visible
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; FUNCTION ListClick( pt: Point; modifiers: INTEGER; h: ListHandle ):BOOLEAN;
|
|||
|
; 14 12 8 18
|
|||
|
; Call this routine when there is a mouse down in the list area. Pt is the
|
|||
|
; mouse coordinates (local). Modifiers is the integer returned in the event record.
|
|||
|
; This routine handles all scrolling (clicks within the scroll bars
|
|||
|
; and autoscrolling) and selection of items in the list.
|
|||
|
;
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
ListClick
|
|||
|
BSR StdEntry ; ho hum
|
|||
|
BSR GetVisBounds ; get visible boundaries
|
|||
|
|
|||
|
CLR.B 18(A6) ; assume no double click
|
|||
|
BSET #7,12(A6) ; flag first time through
|
|||
|
MOVE.L #$80008000,D7 ; set up bogus last point
|
|||
|
SUBQ #8,SP ; save space for a rect
|
|||
|
|
|||
|
MOVE.L 14(A6),D5 ; get click point into D5
|
|||
|
MOVE.B selFlags(A3),14(A6) ; save current selFlags in Frame
|
|||
|
|
|||
|
; code:=FindControl( pt, port, ctl );
|
|||
|
|
|||
|
SUBQ #2,SP ; result of find control
|
|||
|
MOVE.L D5,-(SP) ; pass point
|
|||
|
MOVE.L port(A3),-(SP)
|
|||
|
PEA r(A6) ; get control handle into r(A6)
|
|||
|
_FindControl
|
|||
|
MOVE (SP)+,D6 ; get code into D6
|
|||
|
BNE clickCont ; if <> 0 then hit control
|
|||
|
|
|||
|
ClickArea
|
|||
|
; Immediately discard if the initial point isn’t in the view rect
|
|||
|
; IF PtInRect( pt, rView ) THEN BEGIN
|
|||
|
|
|||
|
SUBQ #2,SP
|
|||
|
MOVE.L D5,-(SP) ; pass point
|
|||
|
PEA rView(A3)
|
|||
|
_PtInRect
|
|||
|
TST.B (SP)+
|
|||
|
BEQ ClickExit ; escape if not inside
|
|||
|
|
|||
|
clickWait
|
|||
|
|
|||
|
; Register conventions in this loop are: D7 used for last click
|
|||
|
; D6 used for anchor for shift-selection
|
|||
|
; D5 used for new point
|
|||
|
; D3 used for new cell
|
|||
|
; A4,A3 used for list handle,pointer
|
|||
|
; A2 used for routine to call repeatedly
|
|||
|
|
|||
|
; call the clikProc if there is one (current mouse point is in mouseLoc)
|
|||
|
|
|||
|
MOVE.L lClikLoop(A3),D0 ; get the click proc
|
|||
|
BEQ.S @noClickProc ; => there isn’t one
|
|||
|
MOVE.L D0,A0 ; get the proc
|
|||
|
JSR (A0) ; and call it
|
|||
|
BEQ clickExit ; => user said to abort!
|
|||
|
@noClickProc
|
|||
|
|
|||
|
; now do any autoscrolling that is required
|
|||
|
|
|||
|
MOVE.L D5,D0 ; get working copy of point (h coordinate first)
|
|||
|
|
|||
|
MOVEQ #0,D2 ; horizontal delta := 0
|
|||
|
BTST #lDoHAutoscroll,listFlags(A3) ; horizontal auto-scrolling?
|
|||
|
BEQ @noHAutoScroll ; no, don’t do any horizontal auto-scrolling
|
|||
|
|
|||
|
CMP.W rView+left(A3),D0 ; is pt.h <= rView.left
|
|||
|
BGT.S @4 ; and
|
|||
|
MOVE.W visBounds+left(A6),D3 ; visible.left > databounds.left
|
|||
|
CMP.W visible+left(A3),D3
|
|||
|
BGE.S @4
|
|||
|
MOVEQ #-1,D2 ; delta fields:=-1
|
|||
|
@4
|
|||
|
ADDQ #1,D0
|
|||
|
CMP.W rView+right(A3),D0 ; is pt.h >= rView.right
|
|||
|
BLT.S @5 ; and
|
|||
|
MOVE.W visBounds+right(A6),D3 ; visible.right < databounds.right
|
|||
|
CMP.W visible+right(A3),D3
|
|||
|
BLE.S @5
|
|||
|
MOVEQ #1,D2 ; delta fields:=1
|
|||
|
@5
|
|||
|
|
|||
|
@noHAutoScroll
|
|||
|
|
|||
|
SWAP D0 ; get v coordinate now
|
|||
|
|
|||
|
MOVEQ #0,D1 ; vertical delta := 0
|
|||
|
BTST #lDoVAutoscroll,listFlags(A3) ; vertical auto-scrolling?
|
|||
|
BEQ @noVAutoScroll ; no, don’t do any vertical auto-scrolling
|
|||
|
|
|||
|
CMP.W rView+top(A3),D0 ; is pt.v <= rView.top
|
|||
|
BGT.S @6 ; and
|
|||
|
MOVE.W visBounds+top(A6),D3 ; visible.top > databounds.top
|
|||
|
CMP.W visible+top(A3),D3
|
|||
|
BGE.S @6
|
|||
|
MOVEQ #-1,D1 ; delta fields:=-1
|
|||
|
@6
|
|||
|
ADDQ #1,D0
|
|||
|
CMP rView+bottom(A3),D0 ; is pt.v >= rView.bottom
|
|||
|
BLT.S @7 ; and
|
|||
|
MOVE visBounds+bottom(A6),D3 ; visible.bottom < databounds.bottom
|
|||
|
CMP visible+bottom(A3),D3
|
|||
|
BLE.S @7
|
|||
|
MOVEQ #1,D1 ; delta fields:=1
|
|||
|
@7
|
|||
|
|
|||
|
@noVAutoScroll
|
|||
|
|
|||
|
MOVE.B D1,D3 ; is any auto-scrolling desired?
|
|||
|
OR.B D2,D3
|
|||
|
BEQ.S @noAutoScroll ; no, get out of here
|
|||
|
|
|||
|
LEA -10(SP), SP ; Reserve space for call to ScrollDelay
|
|||
|
|
|||
|
; calculate the number of items to pass to ScrollDelay
|
|||
|
|
|||
|
MOVE.L visBounds+botRight(A6), D0
|
|||
|
|
|||
|
TST.W D2 ; Scrolling horizontally?
|
|||
|
BEQ.S @tryV ; Skip if not.
|
|||
|
SUB.W visBounds+left(A6), D0 ; Number of horizontal items visible
|
|||
|
|
|||
|
@tryV
|
|||
|
TST.W D1 ; Scrolling vertically?
|
|||
|
BEQ.S @notV ; Skip if not.
|
|||
|
SWAP D0 ; Get visible.bottom
|
|||
|
SUB.W visBounds+top(A6), D0 ; Number of vertical items visible
|
|||
|
|
|||
|
@notV
|
|||
|
MOVE.W D0, -(SP) ; itemsVisible
|
|||
|
|
|||
|
MOVE D2,-(SP) ; dh
|
|||
|
MOVE D1,-(SP) ; dv push params for ListScroll
|
|||
|
MOVE.L A4,-(SP) ; list handle
|
|||
|
|
|||
|
SUBQ.L #4, SP
|
|||
|
_TickCount ; Get a time stamp.
|
|||
|
MOVE.L (SP)+, D1 ; Copy it into D1.
|
|||
|
MOVE.L D1, 10(SP) ; And put it on the stack for ScrollDelay.
|
|||
|
|
|||
|
move.l ExpandMem,A0 ; A0 -> ExpandedMem <SM4>
|
|||
|
move.l ExpandMemRec.emStartTicks(A0),D0 ; See if we need to set this. <SM4>
|
|||
|
BNE.S @startTicksOK ; Skip if not.
|
|||
|
MOVE.L D1, D0 ; Use TickCount value.
|
|||
|
MOVE.L D0,ExpandMemRec.emStartTicks(A0) ; Put it in startTicks. <SM4>
|
|||
|
|
|||
|
@startTicksOK
|
|||
|
MOVE.L D0,14(SP) ; copy startTicks to stack for ScrollDelay.
|
|||
|
|
|||
|
_LScroll
|
|||
|
|
|||
|
_ScrollDelay
|
|||
|
ADDQ.L #2, SP ; Toss the result
|
|||
|
@noSD
|
|||
|
BRA.S @doneAutoScroll
|
|||
|
|
|||
|
@noAutoScroll
|
|||
|
move.l ExpandMem,A0 ; A0 -> ExpandedMem <SM4>
|
|||
|
move.l #0,ExpandMemRec.emStartTicks(A0) ; Clear out startTicks we're not scrolling anymore <SM4>
|
|||
|
|
|||
|
@doneAutoScroll
|
|||
|
|
|||
|
; pin point to the visible rect and then do auto-scroll
|
|||
|
|
|||
|
SUBQ #4,SP ; pin point to view rect
|
|||
|
PEA rView(A3)
|
|||
|
MOVE.L D5,-(SP) ; pass point
|
|||
|
_PinRect
|
|||
|
MOVE.L (SP)+,D5 ; pinned point
|
|||
|
|
|||
|
; Turn mouse point into a cell coordinate
|
|||
|
; i.v:=visible.top + (pt.v-rView.top) DIV cellSize.v;
|
|||
|
; i.h:=visible.left + (pt.h-rView.left) DIV cellSize.h;
|
|||
|
|
|||
|
MOVE.L D5,-(SP) ; subract from this point
|
|||
|
MOVE.L rView+topLeft(A3),-(SP) ; subtract this point
|
|||
|
PEA 4(SP) ; act on point
|
|||
|
_SubPt
|
|||
|
MOVEQ #0,D3
|
|||
|
MOVE (SP)+,D3 ; get v
|
|||
|
DIVU cellSize+v(A3),D3
|
|||
|
ADD visible+top(A3),D3
|
|||
|
SWAP D3 ; put v in lower half of D3
|
|||
|
MOVEQ #0,D0
|
|||
|
MOVE (SP)+,D0 ; get h
|
|||
|
DIVU cellSize+h(A3),D0
|
|||
|
ADD visible+left(A3),D0
|
|||
|
MOVE.W D0,D3 ; put h in lower half of D3
|
|||
|
|
|||
|
; If the current click in same location, skip the selection
|
|||
|
|
|||
|
CMP.L D3,D7
|
|||
|
BEQ clickScan
|
|||
|
|
|||
|
; if first time through, then set up our state. Check for shift, command, or
|
|||
|
; nothing in modifier byte. Initialize according to which it is
|
|||
|
|
|||
|
ChkKeys
|
|||
|
BCLR #7,12(A6) ; test and say it’s not the first time
|
|||
|
BEQ CallRtn ; => doesn’t feel like the first time
|
|||
|
|
|||
|
CMP.L lastClick(A3),D3 ; are we in the same cell as before?
|
|||
|
SEQ 18(A6) ; assume double click if so
|
|||
|
MOVE.L D3,lastClick(A3) ; save new click
|
|||
|
|
|||
|
; set low modifier byte to $FF if cell not selected, $00 if selected. This is later
|
|||
|
; used if whatever we’re doing is affected by state of first cell.
|
|||
|
|
|||
|
MOVEM.L D3/D7,-(SP) ; save new and old cells
|
|||
|
MOVE.L D3,D7 ; get new cell in D7
|
|||
|
BSR CellToIndex ; and index in D3
|
|||
|
st d4 ; default d4 to $FF <ngk 29July90>
|
|||
|
cmp.w maxIndex(a3),d3 ; is d3 out of range (clicked on nothing below last item)? <ngk 29July90>
|
|||
|
bhi.s @1 ; if so, then clicked "cell" was not selected <ngk 29July90> <ngk 17Aug90>
|
|||
|
TST.B cellArray(A3,D3) ; if selected, turn cells off
|
|||
|
SPL D4 ; get into D4
|
|||
|
@1 MOVE.B D4,13(A6) ; and save in low modifier byte (not used)
|
|||
|
MOVEM.L (SP)+,D3/D7 ; restore new and old cells
|
|||
|
|
|||
|
; test for double click. If the mouse is in the same cell as the last click, the elapsed interval
|
|||
|
; is within doubleTime and the mouse is within a few pixels of clikLoc, then return true.
|
|||
|
; If an app doesn’t want to get two double clicks from a triple click, then it must tweek clikTime
|
|||
|
; upon receiving a double click.
|
|||
|
|
|||
|
SUBQ #4,SP ; make room for result
|
|||
|
_TickCount ; get ticks into D0
|
|||
|
; *** this should use the time of the event instead!!!
|
|||
|
MOVE.L (SP),D0 ; and leave on stack
|
|||
|
SUB.L clikTime(A3),D0 ; see if double click
|
|||
|
MOVE.L (SP)+,clikTime(A3) ; but first save new time
|
|||
|
CMP.L doubleTime,D0 ; compare with lowMem doubleTime
|
|||
|
SLE D1 ; set a flag
|
|||
|
NOT.B D4 ; make D4=1 if cell selected
|
|||
|
AND.B D4,D1 ; dclick if cell selected
|
|||
|
AND.B D1,18(A6) ; doubleTime
|
|||
|
|
|||
|
MOVE.L clikLoc(A3),-(SP) ; make a slop rect
|
|||
|
MOVE.L (SP),-(SP) ; out of the last click location
|
|||
|
MOVE.L SP,-(SP) ; push a pointer to the rect
|
|||
|
MOVE.L #$FFFDFFFD,-(SP) ; make the slop -3,-3
|
|||
|
_InsetRect ; make last point a rect
|
|||
|
|
|||
|
SUBQ #2,SP ; room for boolean result
|
|||
|
MOVE.L D5,-(SP) ; push current mouse point
|
|||
|
PEA 6(SP) ; push pointer to rect
|
|||
|
_PtInRect ; is the point in the slop?
|
|||
|
MOVE.B (SP)+,D1 ; get result
|
|||
|
AND.B D1,18(A6) ; and it into our mondo result
|
|||
|
ADDQ #8,SP ; strip off the rect
|
|||
|
|
|||
|
MOVE.L D5,clikLoc(A3) ; update click location
|
|||
|
|
|||
|
; This horrendous bit of code figures out how selections will be done based on the
|
|||
|
; selection flags and the modifier keys.
|
|||
|
|
|||
|
DoSelect
|
|||
|
BTST #LOnlyOne,14(A6) ; Are multiple selections allowed?
|
|||
|
BNE OneClick ; => no, allow only one at a time
|
|||
|
|
|||
|
BTST #CmdKey,12(A6) ; is it command?
|
|||
|
BEQ.S TryShft ; => nope, try for shift
|
|||
|
|
|||
|
CmdClick
|
|||
|
BSET #LUseSense,14(A6) ; use sense flag we just set up
|
|||
|
Cmd2Click
|
|||
|
BSET #LNoExtend,14(A6) ; don’t extend current selection
|
|||
|
BSET #LNoRect,14(A6) ; don’t drag out a rect
|
|||
|
MOVE.L D3,D6 ; set anchor to new cell
|
|||
|
BRA TryDisJoint ; => use ShiftDown, check for deselect all
|
|||
|
|
|||
|
; If shift, use the upper left selection and the lower right selection as the old selection
|
|||
|
; rect. If no cells are selected, the new cell is used instead. Future changes to the
|
|||
|
; selection will be based on this rect, which is saved on the stack. The anchor is the
|
|||
|
; point from which the rectangle will grow. If you click above the current rect, then the
|
|||
|
; botright of the rect becomes the anchor, if below, the topleft becomes anchor.
|
|||
|
|
|||
|
TryShft
|
|||
|
BTST #ShiftKey,12(A6) ; is it shift?
|
|||
|
BEQ.S GotNoMods ; => no modifiers to speak of
|
|||
|
|
|||
|
ShiftClick
|
|||
|
MOVE.L D3,-(SP) ; save current click
|
|||
|
MOVE.L #$7FFF7FFF,D0 ; choose largest possible topleft
|
|||
|
MOVE.L D0,D1 ; get D1 = #$80008000
|
|||
|
NOT.L D1 ; and smallest possible botRight
|
|||
|
|
|||
|
LEA GetBounds,A2 ; get upper left and lower right of selections
|
|||
|
BSR DoSelLoop ; into D0 and D1
|
|||
|
|
|||
|
MOVE.L (SP)+,D3 ; restore cell
|
|||
|
CMP.L #$80008000,D1 ; any selections?
|
|||
|
BEQ.S GetTopLeft ; => no, use cell
|
|||
|
|
|||
|
BTST #LNoExtend,14(A6) ; do we need to anchor?
|
|||
|
BEQ.S GetAnchor ; => yes, use bounds
|
|||
|
|
|||
|
GetTopLeft
|
|||
|
MOVE.L D3,D7 ; where cellToIndex can get it
|
|||
|
MOVE.L D3,D0 ; use as default topleft
|
|||
|
MOVE.L D3,D1 ; and default botright
|
|||
|
|
|||
|
GetAnchor
|
|||
|
MOVE.L D0,(SP) ; save topLeft of rect
|
|||
|
MOVE.L D1,4(SP) ; save botRight of rect
|
|||
|
|
|||
|
; anchor is topleft unless click.v<top or click.h<left or click=topleft
|
|||
|
|
|||
|
MOVE.L D3,D2 ; save new click in D2
|
|||
|
MOVE.L D0,D6 ; assume anchor is topleft
|
|||
|
CMP.L D0,D3 ; special case if click on topleft
|
|||
|
BEQ.S BRAnchor ; => anchor is botRight
|
|||
|
CMP.W D0,D3 ; check left first
|
|||
|
BLT.S BRAnchor ; => click.h<left
|
|||
|
SWAP D3
|
|||
|
SWAP D0
|
|||
|
CMP.W D0,D3 ; check top
|
|||
|
BGE.S TLAnchor ; => click.v<top
|
|||
|
|
|||
|
BRAnchor
|
|||
|
MOVE.L D1,D6 ; else anchor is botright
|
|||
|
|
|||
|
TLAnchor
|
|||
|
MOVE.L D2,D3 ; restore new click
|
|||
|
BRA.S TryDisJoint ; =>check for deselect all
|
|||
|
|
|||
|
; It goes here if no modifier keys are held down...
|
|||
|
; If LExtendDrag is set, then we want to select cells as we drag over them
|
|||
|
|
|||
|
GotNoMods
|
|||
|
BTST #LExtendDrag,14(A6) ; should we select as we go?
|
|||
|
BNE.S DoExtend ; => yes, extend selections
|
|||
|
|
|||
|
OneClick
|
|||
|
LEA NoMods,A2 ; a simple click on a selected cell does nothing
|
|||
|
TST.B 13(A6) ; was it already selected?
|
|||
|
BEQ.S CallRtn ; => yes, it’s a no-op for double clicking
|
|||
|
MOVE.L A2,-(SP) ; use NoMods as routine
|
|||
|
BRA.S ClearAll ; => and deselect everything
|
|||
|
|
|||
|
DoExtend
|
|||
|
BSET #LNoExtend,14(A6) ; don’t want to extend current rect
|
|||
|
BTST #LNoRect,14(A6) ; should we drag out a rect?
|
|||
|
BEQ.S ShiftClick ; => yes, use shift code
|
|||
|
BCLR #LUseSense,14(A6) ; else use command code
|
|||
|
BSET #LNoDisjoint,14(A6) ; but without disjoint selections
|
|||
|
BRA.S Cmd2Click ; and without sense
|
|||
|
|
|||
|
TryDisJoint
|
|||
|
LEA ShiftDown,A2 ; use shiftDown routine
|
|||
|
MOVE.L A2,-(SP) ; save routine
|
|||
|
BTST #LNoDisJoint,14(A6) ; should we deselect?
|
|||
|
BEQ.S UseStkRtn ; => no, disjoint ok
|
|||
|
|
|||
|
ClearAll
|
|||
|
LEA clrSel,A2 ; else no keys down
|
|||
|
BSR DoSelLoop ; clear all selections
|
|||
|
|
|||
|
UseStkRtn
|
|||
|
MOVE.L (SP)+,A2 ; get the routine to use
|
|||
|
|
|||
|
CallRtn
|
|||
|
JSR (A2) ; call the proper routine
|
|||
|
|
|||
|
clickScan
|
|||
|
SUBQ #4,SP ; get current mouse
|
|||
|
MOVE.L SP,-(SP)
|
|||
|
_GetMouse
|
|||
|
MOVE.L (SP)+,D5 ; and save in var
|
|||
|
MOVE.L D5,mouseLoc(A3) ; save for defProc
|
|||
|
|
|||
|
SUBQ #2,SP ; is mouse still down
|
|||
|
_StillDown
|
|||
|
TST.B (SP)+
|
|||
|
BEQ clickExit ; escape on mouseUp
|
|||
|
|
|||
|
BRA clickWait
|
|||
|
|
|||
|
; It hit in a control, look for our two
|
|||
|
|
|||
|
clickCont
|
|||
|
MOVE.L r(A6),D7 ; get control handle
|
|||
|
|
|||
|
CMP.L hScroll(A3),D7 ; skip if not ours
|
|||
|
BEQ.S @0
|
|||
|
CMP.L vScroll(A3),D7
|
|||
|
BNE ClickArea ; used to be "bne.s clickExit" <10>
|
|||
|
|
|||
|
@0
|
|||
|
CMP.W #128,D6 ; indicators are 129-253
|
|||
|
BLE.S @2
|
|||
|
CMP.W #254,D6
|
|||
|
BGE.S @2
|
|||
|
|
|||
|
; it’s an indicator!
|
|||
|
|
|||
|
SUBQ #2,SP
|
|||
|
MOVE.L D7,-(SP)
|
|||
|
_GetCtlValue ; leave on stack
|
|||
|
|
|||
|
SUBQ #2,SP
|
|||
|
MOVE.L D7,-(SP) ; pass ctl Handle
|
|||
|
MOVE.L D5,-(SP) ; pass point
|
|||
|
MOVE.L minusOne,-(SP)
|
|||
|
_TrackControl ; leave junk on stack
|
|||
|
|
|||
|
MOVE.L D7,-(SP) ; pass point
|
|||
|
_GetCtlValue
|
|||
|
|
|||
|
MOVEQ #0,D0 ; zero other dimension
|
|||
|
MOVE (SP)+,D0 ; get new value
|
|||
|
SUB (SP)+,D0 ; subtract old value
|
|||
|
BEQ.S clickExit
|
|||
|
|
|||
|
CMP.L hScroll(A3),D7 ; is this horizontal scroll?
|
|||
|
BEQ.S @1
|
|||
|
SWAP D0
|
|||
|
@1
|
|||
|
MOVE.L D0,-(SP) ; push both deltas
|
|||
|
MOVE.L A4,-(SP)
|
|||
|
_LScroll
|
|||
|
BRA.S clickExit
|
|||
|
|
|||
|
; For all other parts, just track incrementally with proc
|
|||
|
@2
|
|||
|
MOVE.L D7,-(SP) ; pass ctl
|
|||
|
MOVE.L A4,-(SP) ; handle is refcon-to-be
|
|||
|
_SetCRefCon
|
|||
|
|
|||
|
SUBQ.L #4, SP
|
|||
|
_TickCount ; Get a time stamp.
|
|||
|
|
|||
|
move.l ExpandMem,A0 ; A0 -> ExpandedMem <SM4>
|
|||
|
move.l (SP)+,ExpandMemRec.emStartTicks(A0) ; Put it in startTicks. <SM4>
|
|||
|
|
|||
|
SUBQ #2,SP
|
|||
|
MOVE.L D7,-(SP) ; pass ctl Handle
|
|||
|
MOVE.L D5,-(SP) ; pass point
|
|||
|
PEA ClickTrack ; track proc
|
|||
|
_TrackControl
|
|||
|
ADDQ #2,SP
|
|||
|
clickExit
|
|||
|
move.l ExpandMem,A0 ; A0 -> ExpandedMem <SM4>
|
|||
|
move.l #0,ExpandMemRec.emStartTicks(A0) ; Clear out startTicks <SM4>
|
|||
|
|
|||
|
ADDQ #8,SP ; strip off the rect
|
|||
|
Std10Exit
|
|||
|
MOVEQ #10,D0
|
|||
|
BRA StdExit
|
|||
|
|
|||
|
;------------
|
|||
|
; NoMods
|
|||
|
; This routine is called repeatedly if neither shift nor command is held down
|
|||
|
; The last click is in D7, the new one is in D3. First time through, last click
|
|||
|
; is invalid, but ListSetSelect just ignores it.
|
|||
|
|
|||
|
NoMods
|
|||
|
MOVEQ #0,D6 ; deselect old click
|
|||
|
BSR.S CmdD1 ; (in D7)
|
|||
|
MOVEQ #-1,D6 ; select new click
|
|||
|
MOVE.L D3,D7
|
|||
|
CmdD1
|
|||
|
MOVE.B D6,-(SP) ; on or off?
|
|||
|
MOVE.L D7,-(SP) ; push cell
|
|||
|
MOVE.L A4,-(SP) ; and list handle
|
|||
|
_LSetSelect ; select/deselect it
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; GetBounds
|
|||
|
; This routine is called repeatedly by DoSelLoop. It calculates the
|
|||
|
; smallest rect that contains all the selections, and puts the topleft
|
|||
|
; cell in D0 and the botRight cell in D1
|
|||
|
|
|||
|
|
|||
|
GetBounds
|
|||
|
BSR IndexToCell ; index in D3 -> cell in D7
|
|||
|
MOVEQ #1,D2 ; go through this code twice
|
|||
|
@1
|
|||
|
CMP.W D0,D7 ; check top/left
|
|||
|
BGE.S @2 ; => not less
|
|||
|
MOVE.W D7,D0 ; else get new top/left
|
|||
|
@2
|
|||
|
CMP.W D1,D7 ; check bottom/right
|
|||
|
BLE.S @3 ; => not greater
|
|||
|
MOVE.W D7,D1 ; else get new bot/right
|
|||
|
@3
|
|||
|
SWAP D7
|
|||
|
SWAP D0
|
|||
|
SWAP D1
|
|||
|
DBRA D2,@1 ; loop once
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; ShiftDown
|
|||
|
; This routine is called repeatedly while the shift key is held down.
|
|||
|
; Its goal is to form a selection rectangle on the screen. The last
|
|||
|
; rect selected is on the stack. Select everything in the current rect
|
|||
|
; and deselect things in the old rect but not in the new one.
|
|||
|
; The new cell position is in D3. The "anchored position" is in D6.
|
|||
|
; Note: D3 (new click) saved, and D7 (old click) restored.
|
|||
|
|
|||
|
; if LExtendDrag then anchor was set to newclick (D6=D3)
|
|||
|
; if LUseSense then use 13(A6) to determine select on/off
|
|||
|
; if LNoRect then set new anchor point each time through the loop
|
|||
|
; and we don’t want to deselect behind us, so ignore old rect
|
|||
|
|
|||
|
ShiftDown
|
|||
|
MOVEM.L D3/A2,-(SP) ; self preservation
|
|||
|
MOVE.L D6,-(SP) ; pass anchor
|
|||
|
MOVE.L D3,-(SP) ; and new position
|
|||
|
PEA r(A6) ; save new rect
|
|||
|
_Pt2Rect ; make it a rect
|
|||
|
ADDQ #1,r+bottom(A6)
|
|||
|
ADDQ #1,r+right(A6)
|
|||
|
|
|||
|
LEA 12(SP),A2 ; assume we want to use old rect
|
|||
|
BTST #LNoRect,14(A6) ; do we?
|
|||
|
BEQ.S @0 ; => yes
|
|||
|
MOVE.L D3,D6 ; else next anchor is current point
|
|||
|
LEA r(A6),A2 ; and use new rect instead of old rect
|
|||
|
@0
|
|||
|
MOVE.L A2,-(SP) ; get the union of the
|
|||
|
PEA r(A6) ; last rect and the new rect
|
|||
|
MOVE.L A2,-(SP) ; and save as union (jack)
|
|||
|
_UnionRect
|
|||
|
|
|||
|
MOVE.W (A2)+,D5 ; get top into D5
|
|||
|
MOVE.L (A2)+,D2 ; get bottom into D2
|
|||
|
MOVE.W (A2),D4 ; get right into D4
|
|||
|
MOVE.L -(A2),D3 ; point at left for D3
|
|||
|
@1
|
|||
|
MOVE.W (A2),D3 ; need to load left each time through
|
|||
|
@2
|
|||
|
SUBQ #2,SP ; make room for boolean result
|
|||
|
MOVE.W D3,-(SP) ; pass the cell h=low word
|
|||
|
MOVE.W D5,-(SP) ; v=high word
|
|||
|
PEA r(A6) ; if the cell in the rect
|
|||
|
_PtInRect ; then select, else deselect
|
|||
|
|
|||
|
MOVE.B (SP)+,D0 ; get result
|
|||
|
BNE.S @11 ; => always do points in rect
|
|||
|
BTST #LNoRect,14(A6) ; if this bit set, don’t off outsiders
|
|||
|
BNE.S @12 ; => skip the selection
|
|||
|
BTST #LNoExtend,14(A6) ; like it says above
|
|||
|
BNE.S @12
|
|||
|
@11
|
|||
|
BTST #LUseSense,14(A6) ; use sense?
|
|||
|
BEQ.S @3 ; => not today
|
|||
|
AND.B 13(A6),D0 ; get selection sense
|
|||
|
@3
|
|||
|
MOVE.B D0,-(SP) ; only on if in rect and turn on
|
|||
|
MOVE.W D3,-(SP) ; push the cell again
|
|||
|
MOVE.W D5,-(SP) ; push point.v (dont assume PtInRect will leave it in D1! SHeesh!) <SM7> SAM
|
|||
|
MOVE.L A4,-(SP) ; and the handle
|
|||
|
_LSetSelect ; and select/deselect the cell
|
|||
|
@12
|
|||
|
ADDQ #1,D3 ; check next horizontal
|
|||
|
CMP.W D3,D4 ; hit right yet?
|
|||
|
BGE.S @2 ; => nope, go that way --->
|
|||
|
ADDQ #1,D5 ; check next vertical
|
|||
|
CMP.W D5,D2 ; hit bottom yet?
|
|||
|
BGE.S @1 ; => no spanks to you!
|
|||
|
|
|||
|
MOVE.L r(A6),12(SP) ; save new rect as old rect
|
|||
|
MOVE.L r+4(A6),16(SP)
|
|||
|
|
|||
|
MOVEM.L (SP)+,D7/A2 ; get old click, our address
|
|||
|
RTS
|
|||
|
|
|||
|
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
; PROCEDURE ClickTrack( ctl: ControlHandle; part: INTEGER );
|
|||
|
; 10 8
|
|||
|
|
|||
|
ClickTrack
|
|||
|
LINK A6,#0 ; hum de dum...
|
|||
|
MOVE.L D3,-(SP) ; save this one
|
|||
|
|
|||
|
MOVE.L 10(A6),A0 ; get control handle
|
|||
|
MOVE.L A0,D3 ; save in D3
|
|||
|
MOVE.L (A0),A0
|
|||
|
MOVE.L contrlRfCon(A0),A0 ; get list handle
|
|||
|
MOVE.L A0,D2 ; save list Handle in D2
|
|||
|
MOVE.L (A0),A0 ; and dereference
|
|||
|
|
|||
|
LEA visible(A0),A1 ; point to rect
|
|||
|
CMP.L hScroll(A0),D3 ; hScroll
|
|||
|
BEQ.S @3
|
|||
|
SUBQ #2,A1 ; point to high order words
|
|||
|
@3
|
|||
|
MOVEQ #1,D1 ; assume change
|
|||
|
MOVEQ #-20,D0 ; offset constant
|
|||
|
ADD.W 8(A6),D0 ; get the part (zero based)
|
|||
|
BMI.S @noScroll ; => part too small
|
|||
|
SUB.W #2,D0
|
|||
|
BMI.S @0 ; line at a time
|
|||
|
CMP #1,D0
|
|||
|
BGT.S @noScroll ; => part too big
|
|||
|
MOVE.L (A1)+,D1 ; get negative delta from visible
|
|||
|
SUB.L (A1)+,D1 ; in low order
|
|||
|
NOT.W D1 ; get delta -1
|
|||
|
BNE.S @0 ; => special case for one cell wide
|
|||
|
ADDQ #1,D1
|
|||
|
@0
|
|||
|
BTST #0,D0 ; see if odd therefore down
|
|||
|
BNE.S @1
|
|||
|
NEG D1 ; flip sense
|
|||
|
@1
|
|||
|
SWAP D1 ; put in high order
|
|||
|
CLR D1 ; low order = o
|
|||
|
|
|||
|
; Calculate the number of visible items for ScrollDelay. Assume vertical unless told otherwise.
|
|||
|
|
|||
|
MOVE.W visible+bottom(A0), D0
|
|||
|
SUB.W visible+top(A0), D0
|
|||
|
|
|||
|
CMP.L hScroll(A0),D3 ; hScroll
|
|||
|
BNE.S @2
|
|||
|
SWAP D1
|
|||
|
|
|||
|
; It was horizontal - correct our assumption.
|
|||
|
|
|||
|
MOVE.W visible+right(A0), D0
|
|||
|
SUB.W visible+left(A0), D0
|
|||
|
@2
|
|||
|
|
|||
|
SUBQ.L #2, SP ; Make room for ScrollDelay return
|
|||
|
move.l ExpandMem,A0 ; A0 -> ExpandedMem <SM4>
|
|||
|
move.l ExpandMemRec.emStartTicks(A0),-(SP) ; startTicks for ScrollDelay <SM4>
|
|||
|
SUBQ.L #4, SP ; Reserve space for actionTicks
|
|||
|
MOVE.W D0, -(SP) ; itemsVisible for ScrollDelay
|
|||
|
|
|||
|
MOVE.L D1,-(SP) ; pass deltas
|
|||
|
MOVE.L D2,-(SP) ; pass list handle
|
|||
|
|
|||
|
SUBQ.L #4, SP
|
|||
|
_TickCount
|
|||
|
MOVE.L (SP)+, 10(SP)
|
|||
|
|
|||
|
_LScroll
|
|||
|
|
|||
|
_ScrollDelay
|
|||
|
ADDQ.L #2, SP ; Toss the result
|
|||
|
@noSD
|
|||
|
|
|||
|
@noScroll
|
|||
|
MOVE.L (SP)+,D3
|
|||
|
MOVE.W #6,D0
|
|||
|
|
|||
|
NonStd3
|
|||
|
UNLK A6
|
|||
|
MOVE.L (SP)+,A0 ; get RTS
|
|||
|
ADD.W D0,SP ; strip params
|
|||
|
JMP (A0) ; and return
|
|||
|
|
|||
|
;------------
|
|||
|
; Routine ListHilite is called by ListSetSelect instead of ListDraw
|
|||
|
; This is because the routine is only called if the cell is already
|
|||
|
; drawn and the sense needs to be reversed. Draw procs can simply
|
|||
|
; call draw when they get the hilite command, or they can do something
|
|||
|
; faster. Only do if list is active.
|
|||
|
|
|||
|
ListHilite
|
|||
|
BSR StdEntry ; set things up
|
|||
|
TST.B LActive(A3) ; are we active?
|
|||
|
BEQ.S @notActive ; => no, skip it <16Dec85>
|
|||
|
BSR.S DoHilite ; invert the cell
|
|||
|
@notActive
|
|||
|
bra.s Std8Exit ; strip 8 bytes of params
|
|||
|
|
|||
|
DoHilite
|
|||
|
MOVE.L D6,-(SP) ; save D6
|
|||
|
MOVE.W #LHiliteMsg,D6 ; and set with hilite command
|
|||
|
BRA.S DDraw1
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListDraw( c: Point; h: ListHandle );
|
|||
|
; 12 8
|
|||
|
; Draws the given cell from the given list
|
|||
|
; DoDraw is split off to be used internally
|
|||
|
;
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
ListDraw
|
|||
|
BSR StdEntry ; ho hum again
|
|||
|
BSR.S DoDraw ; do the actual drawing
|
|||
|
Std8Exit
|
|||
|
MOVEQ #8,D0
|
|||
|
BRA StdExit
|
|||
|
|
|||
|
;------------
|
|||
|
; DoDraw -- This is the drawing stuff that must be done for
|
|||
|
; each cell drawn. It is called by ListDraw and ListUpdate.
|
|||
|
; It assumes that StdEntry has been called (cell in D7 etc.).
|
|||
|
|
|||
|
DoDraw
|
|||
|
MOVE.L D6,-(SP) ; save D6
|
|||
|
MOVE.W #LDrawMsg,D6 ; code = Draw
|
|||
|
DDraw1
|
|||
|
BTST #noDraw,ListFlags(A3) ; is drawing on?
|
|||
|
BNE.S DoDrExit ; => nope, just exit
|
|||
|
|
|||
|
BSR MyFind ; validate the cell
|
|||
|
BEQ.S DoDrExit ; skip if bad cell
|
|||
|
|
|||
|
SUBQ #4,SP ; save the current clip’n reg’n
|
|||
|
_NewRgn ; get a new region
|
|||
|
MOVE.L (SP),-(SP) ; and save it on the stack
|
|||
|
_GetClip ; set it to the current clip
|
|||
|
|
|||
|
PEA r(A6) ; get the cell’s rect into r
|
|||
|
MOVE.L D7,-(SP) ; pass the cell
|
|||
|
MOVE.L A4,-(SP)
|
|||
|
_LRect ; get the cell’s rect
|
|||
|
|
|||
|
SUBQ #2,SP ; room for result
|
|||
|
PEA rView(A3) ; get intersection of rView
|
|||
|
PEA r(A6) ; and current cell
|
|||
|
MOVE.L (SP),-(SP) ; and save into r
|
|||
|
_SectRect
|
|||
|
TST.B (SP)+ ; is cell visible?
|
|||
|
BEQ.S DoneDraw ; => no, get clip off stack & exit
|
|||
|
|
|||
|
PEA r(A6) ; push rect for our view
|
|||
|
_ClipRect ; and set clip to it
|
|||
|
|
|||
|
MOVE.L (SP),-(SP) ; get original clip
|
|||
|
MOVE.L port(A3),A2
|
|||
|
MOVE.L clipRgn(A2),-(SP) ; intersect with our new rect
|
|||
|
MOVE.L (SP),-(SP) ; and save in clip rgn
|
|||
|
_SectRgn
|
|||
|
|
|||
|
; call the defproc’s routine to draw/hilite the cell
|
|||
|
|
|||
|
BSR.S GetTheListProc ; what it says, but into A0
|
|||
|
BEQ.S DoneDraw ; => oh no! no defproc
|
|||
|
|
|||
|
MOVE.W D6,-(SP) ; push call
|
|||
|
|
|||
|
MOVE.W Index(A6),D0 ; get an index for this cell
|
|||
|
TST.B cellArray(A3,D0.W) ; and check it
|
|||
|
SMI D0 ; set D5 if selected
|
|||
|
AND.B LActive(A3),D0 ; and in active byte
|
|||
|
|
|||
|
MOVE.B D0,-(SP) ; pass select boolean
|
|||
|
PEA r(A6) ; and here is the cell’s rect
|
|||
|
MOVE.L D7,-(SP) ; here is the cell
|
|||
|
MOVE.W offset(A6),-(SP) ; this is the offset into the data
|
|||
|
MOVE.W len(A6),-(SP) ; and this is how long the data is
|
|||
|
MOVE.L A4,-(SP) ; and a handle to our record
|
|||
|
JSR (A0) ; call the defproc
|
|||
|
BSR.S UnlockLProc ; now unlock that poor defproc...
|
|||
|
DoneDraw
|
|||
|
MOVE.L (SP),-(SP) ; dup rgn on stack
|
|||
|
_SetClip ; restore it
|
|||
|
_DisposRgn ; and erase last traces
|
|||
|
DoDrExit
|
|||
|
MOVE.L (SP)+,D6 ; restore D6
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; GetTheListProc
|
|||
|
; This routine makes sure that the listproc stored in the list record
|
|||
|
; as ListDefHandle is loaded into memory and locked down.
|
|||
|
|
|||
|
GetTheListProc
|
|||
|
MOVE.L ListDefHandle(A3),D0 ; get the handle
|
|||
|
BEQ.S @done ; => didn’t get one
|
|||
|
|
|||
|
; Some programmers are pretty slimy and load an LDEF that is empty. They then <LW3> fau
|
|||
|
; stuff some code into it. However, since HLOCK does not flush the cache anymore, <LW3> fau
|
|||
|
; the code that they stuff into it might not get written back to memory. To solve this, <LW3> fau
|
|||
|
; we check here whether the LDEF resource size is less than, say, 32 bytes. If so, we <LW5> chp
|
|||
|
; assume that they have already loaded the LDEF and modified it, so we flush the cache <LW3> fau
|
|||
|
; for them.
|
|||
|
|
|||
|
MOVE.L ListDefHandle(A3),A0 ; get the handle <LW3> fau
|
|||
|
_GetHandleSize ; How big is our LDEF Handle <LW3> fau
|
|||
|
cmp.l #32,D0 ; Is it "small" <LW5> chp
|
|||
|
bhi.s @RealLDEF ; no, don't flush the cache <LW3> fau
|
|||
|
jsr ([jCacheFlush]) ; else, flush the caches. <LW3> fau
|
|||
|
@RealLDEF ; <LW3> fau
|
|||
|
MOVE.L ListDefHandle(A3),A0 ; get the handle <LW3> fau
|
|||
|
MOVE.L A0,-(SP) ; and load the defProc
|
|||
|
_LoadResource
|
|||
|
MOVE.L (A0),D0 ; Is the handle still empty? <S412 29Feb88>
|
|||
|
BEQ.S @done ; Yes, skip <S412 29Feb88>
|
|||
|
_HLock ; lock it down
|
|||
|
MOVE.L (A0),A0 ; and get its address
|
|||
|
MOVEQ #-1,D0 ; make sure NE
|
|||
|
@done
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; UnlockLProc
|
|||
|
; This routine unlocks the List defProc and leaves it floating around.
|
|||
|
|
|||
|
UnlockLProc
|
|||
|
MOVE.L ListDefHandle(A3),A0 ; get the handle
|
|||
|
_HUnlock ; and unlock it
|
|||
|
RTS
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; Procedure ListCellSize (cSize: Point; h: ListHandle );
|
|||
|
; 12 8
|
|||
|
; ListCellSize sets the cellSize field in the specified list and updates the
|
|||
|
; visible rect accordingly.
|
|||
|
;
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
ListCellSize
|
|||
|
BSR StdEntry ; hum ho
|
|||
|
MOVE.L D7,cellSize(A3) ; set cellsize
|
|||
|
BSR.S SetVisible ; set visible and fit flags
|
|||
|
LCS1
|
|||
|
MOVE.L A4,-(SP) ; this is the handle
|
|||
|
BSR SetHilite ; check databounds and position thumb
|
|||
|
BRA Std8Exit ; use standard exit
|
|||
|
|
|||
|
;------------
|
|||
|
; SetVisible is a utility used to set the visible rect based on the
|
|||
|
; cellsize and the list’s window (rView). It also sets flags that
|
|||
|
; indicate whether the cells fit exactly into the window.
|
|||
|
|
|||
|
; A trick is used to index into ListFlags using D3. The bit positions
|
|||
|
; of the flags used to indicate exact fit (LHBadFit and LVBadFit) were
|
|||
|
; chosen to be equal to h and v.
|
|||
|
;
|
|||
|
; **** Note, we now clobber D4 in this routine
|
|||
|
; The trick above did not work out so well. lDoHAutoscroll was assigned the same position in the
|
|||
|
; flags byte as LVBadFit. the gp 12/2/86 fix was done to solve that problem as the lDoHAutoscroll
|
|||
|
; EQU had already been published and LVBadFit has not been published.
|
|||
|
SetVisible
|
|||
|
MOVEQ #v,D3 ; do vertical half first
|
|||
|
MOVEQ #LVBadFit,D4 ; will need this to set/clear the right bit - gp 12/2/86
|
|||
|
BSR.S CellCommon
|
|||
|
MOVEQ #h,D3 ; then do horizontal
|
|||
|
MOVEQ #LHBadFit,D4 ; will need this to set/clear the right bit - gp 12/2/86
|
|||
|
CellCommon
|
|||
|
MOVEQ #0,D0 ; division needs a long
|
|||
|
ADD.W rView+bottom(A3,D3),D0 ; add bottom/left
|
|||
|
SUB.W rView+top(A3,D3),D0 ; subtract top/right
|
|||
|
ADD.W cellsize(A3,D3),D0 ; add cellsize.v/h
|
|||
|
SUBQ #1,D0 ; and subtract 1
|
|||
|
DIVU cellsize(A3,D3),D0 ; divide by cellsize.v/h
|
|||
|
ADD.W visible+top(A3,D3),D0 ; add visible top/left
|
|||
|
MOVE.W D0,visible+bottom(A3,D3) ; and update visible bottom/right
|
|||
|
BCLR D4,ListFlags(A3) ; assume cells fit exactly - gp 12/2/86 {was using D3}
|
|||
|
SWAP D0 ; get remainder
|
|||
|
ADD.W #1,D0 ; compensate for rounding
|
|||
|
CMP.W cellSize(A3,D3),D0 ; hit a cell boundary?
|
|||
|
BEQ.S @1 ; => Hey boss, they do fit!
|
|||
|
BSET D4,ListFlags(A3) ; else need we say more room - gp 12/2/86 {was using D3}
|
|||
|
@1
|
|||
|
RTS
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; Procedure ListSize (w,h:Integer; h: ListHandle );
|
|||
|
; 14,12 8
|
|||
|
; ListSize is called by the user to resize his list. It should be called
|
|||
|
; immediately after the call to sizeWindow. w and h are the width and height
|
|||
|
; of the list, not including the scroll bars.
|
|||
|
;
|
|||
|
; ListSize sets the viewRect to the specified rect, and sets flags that
|
|||
|
; determine whether or not cells fit exactly into the view. If not, then
|
|||
|
; a flag is set that indicates that scrolling must be extended by one cell
|
|||
|
; in the direction(s) that doesn’t fit. It also updates the scroll bars
|
|||
|
; to fit within their new confines.
|
|||
|
;
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
ListSize
|
|||
|
BSR StdEntry ; hum ho (get h,w into D7)
|
|||
|
BSR.S InvalStuff ; invalidate scroll bars + grow
|
|||
|
@12
|
|||
|
; save original RView so we can validate the part that was scrollRected
|
|||
|
|
|||
|
MOVE.L rView+4(A3),-(SP) ; except for the part scrolled
|
|||
|
MOVE.L rView(A3),-(SP) ; push rect
|
|||
|
|
|||
|
MOVE.L rView(A3),D0 ; get current topLeft
|
|||
|
ADD.W D7,D0 ; add width to left
|
|||
|
SWAP D0
|
|||
|
SWAP D7
|
|||
|
ADD.W D7,D0 ; add height to right
|
|||
|
SWAP D0 ; get botRight
|
|||
|
MOVE.L D0,rView+botRight(A3) ; and update viewRect
|
|||
|
BSR.S SetVisible ; set visible and flags
|
|||
|
MOVE.L hScroll(A3),D4 ; horizontal scroll bar?
|
|||
|
MOVEQ #top,D0 ; indicate which scroller
|
|||
|
BSR SetScRect ; set scroll rect
|
|||
|
|
|||
|
MOVE.L vScroll(A3),D4 ; vertical scroll bar?
|
|||
|
MOVEQ #left,D0 ; indicate which bar
|
|||
|
BSR.S SetScRect
|
|||
|
|
|||
|
MOVE.L visible(A3),r(A6) ; make a copy of visible
|
|||
|
MOVE.L visible+4(A3),r+4(A6)
|
|||
|
BSR JustRect ; align rect for optimal display
|
|||
|
BNE.S @3 ; => no change, no update
|
|||
|
|
|||
|
PEA rView(A3) ; else invalidate entire view
|
|||
|
_InvalRect
|
|||
|
|
|||
|
; now slide original rView to it’s JustRected position for validation
|
|||
|
|
|||
|
BSR GetOffset ; get offset between r and visible
|
|||
|
MOVE.L SP,-(SP) ; push pointer to old rView (saved on stack)
|
|||
|
MOVE.L D0,-(SP) ; push offset returned by GetOffset
|
|||
|
_OffsetRect ; and get new rect
|
|||
|
|
|||
|
SUBQ #2,SP ; make room for result
|
|||
|
PEA rView(A3) ; get intersection between view
|
|||
|
PEA 6(SP) ; and new rect
|
|||
|
MOVE.L (SP),-(SP) ; and save in new rect
|
|||
|
_SectRect ; get intersection
|
|||
|
TST.B (SP)+ ; ignore result
|
|||
|
|
|||
|
MOVE.L SP,-(SP) ; point to rect
|
|||
|
bsr.s MyValidRect ; and validate it
|
|||
|
|
|||
|
CLR.W D0 ; move, but no update
|
|||
|
BSR MoveRect ; now go move the thing
|
|||
|
@3
|
|||
|
ADDQ #8,SP ; strip rView off stack
|
|||
|
BRA LCS1 ; recalc scroll settings, redraw
|
|||
|
|
|||
|
;------------
|
|||
|
; InvalStuff is by ListSize to save a little code
|
|||
|
; D0 indexes to the side of the rect that needs to grow to include
|
|||
|
; the grow box. The scrollHandle is in D1.
|
|||
|
|
|||
|
InvalStuff
|
|||
|
BTST #LHasGrow,ListFlags(A3) ; is there one?
|
|||
|
BEQ.S @2 ; => no, nothing to do
|
|||
|
MOVE.L SP,A2 ; and point to it
|
|||
|
|
|||
|
MOVEQ #top,D0 ; do vertical bar first
|
|||
|
BSR.S @1 ; invalidate it
|
|||
|
MOVEQ #left,D0 ; fall into routine for horizontal
|
|||
|
@1
|
|||
|
MOVE.L D0,D4 ; save index here
|
|||
|
MOVE.L rView+4(A3),-(SP) ; default rect is the view
|
|||
|
MOVE.L rView(A3),-(SP) ; get temp copy on stack
|
|||
|
MOVE.L SP,A2 ; and point to it with A2
|
|||
|
BSR GetScSize ; get scroll bar size in A2
|
|||
|
NEG.W D4 ; need to index the other way...
|
|||
|
ADD.W #16,6(A2,D4.W) ; stretch scroll bar for grow box
|
|||
|
MOVE.L A2,-(SP) ; push for invalidate
|
|||
|
_EraseRect
|
|||
|
MOVE.L A2,-(SP) ; and for erase
|
|||
|
_InvalRect
|
|||
|
ADDQ #8,SP ; strip the rect
|
|||
|
@2
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; SetScRect is used by ListSize to move and resize the scroll bars when the
|
|||
|
; window is grown. D0 flags which scroll bar is being set.
|
|||
|
|
|||
|
SetScRect
|
|||
|
MOVE.L rView+4(A3),-(SP) ; push botRight of r
|
|||
|
MOVE.L rView(A3),-(SP) ; and topLeft too
|
|||
|
MOVE.L SP,A2 ; pass pointer to rect in A2
|
|||
|
BSR GetScSize ; get scroll’s rect (uses D0) into A2
|
|||
|
TST.L D4 ; is control valid?
|
|||
|
BNE.S @haveControl ; => yes, move the control
|
|||
|
|
|||
|
; the control’s not valid. Erase the rect if there is a grow box
|
|||
|
|
|||
|
@noControl
|
|||
|
BTST #LHasGrow,ListFlags(A3) ; is there a grow box?
|
|||
|
BEQ.S @done ; => no, just exit
|
|||
|
MOVE.L A2,-(SP) ; else erase the rect
|
|||
|
_EraseRect
|
|||
|
BRA.S @done ; and return
|
|||
|
|
|||
|
@haveControl
|
|||
|
MOVE.L D4,-(SP) ; hide the control
|
|||
|
_HideControl
|
|||
|
MOVE.L D4,-(SP) ; push control handle
|
|||
|
MOVE.L topLeft(A2),-(SP) ; push topLeft of control
|
|||
|
_MoveControl ; and move it to new spot
|
|||
|
MOVE.L D4,-(SP) ; now make it the new size
|
|||
|
MOVE.L botRight(A2),D0 ; get width
|
|||
|
SUB.W left(A2),D0
|
|||
|
MOVE.W D0,-(SP) ; and push it
|
|||
|
SWAP D0 ; get height
|
|||
|
SUB.W top(A2),D0
|
|||
|
MOVE.W D0,-(SP) ; and push it
|
|||
|
_SizeControl
|
|||
|
MOVE.L D4,-(SP) ; now show the control again
|
|||
|
bsr.s MyShowControl
|
|||
|
@done
|
|||
|
|
|||
|
MOVE.L A2,-(SP) ; validate the rect
|
|||
|
bsr.s MyValidRect ; so it doesn’t get drawn again
|
|||
|
ADDQ #8,SP ; and strip the rect
|
|||
|
RTS
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; Procedure ListDoDraw (drawIt: BOOLEAN; h: ListHandle);
|
|||
|
;
|
|||
|
; Sets the flag that indicates whether or not drawing occurs as a
|
|||
|
; result of List Add/Del Row/column calls and set/addto/clr cell calls.
|
|||
|
;
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
ListDoDraw
|
|||
|
BSR StdEntry
|
|||
|
BSET #noDraw,ListFlags(A3) ; assume noDraw = TRUE
|
|||
|
TST.B 12(A6) ; check the boolean
|
|||
|
BEQ.S @1 ; => noDraw = TRUE
|
|||
|
BCLR #noDraw,ListFlags(A3) ; noDraw = FALSE
|
|||
|
MOVE.L A4,-(SP) ; push the list handle
|
|||
|
BSR SetHilite ; and set the control values
|
|||
|
@1
|
|||
|
BRA Std6Exit
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; Procedure ListNew (view,dBounds: Rect; CSize: cell; theProc:INTEGER; theWindow: WindowPtr;
|
|||
|
; drawIt,hasGrow,scrollHoriz,scrollVert: BOOLEAN): ListHandle;
|
|||
|
;
|
|||
|
; Create a new list.
|
|||
|
;
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NLsVert EQU 8
|
|||
|
NLsHoriz EQU NLsVert+2
|
|||
|
NLhasGrow EQU NLsHoriz+2
|
|||
|
NLdrawIt EQU NLhasGrow+2
|
|||
|
NLWindow EQU NLdrawIt+2
|
|||
|
NLProc EQU NLWindow+4
|
|||
|
NLcSize EQU NLProc+2
|
|||
|
NLBounds EQU NLcSize+4
|
|||
|
NLview EQU NLBounds+4
|
|||
|
NLResult EQU NLview+4
|
|||
|
|
|||
|
ListNew ; don’t use StdEntry because no handles yet
|
|||
|
LINK A6,#stdFrame ; standard frame
|
|||
|
MOVEM.L ListMgrSavedRegisters,-(SP)
|
|||
|
CLR.L NLResult(A6) ; assume some error
|
|||
|
|
|||
|
; First allocate memory for the data structure + the cellArray
|
|||
|
; the cellArray is initialized to 0s, indicating no data yet.
|
|||
|
|
|||
|
MOVE.L NLBounds(A6),A2 ; get pointer to bounds rect
|
|||
|
|
|||
|
MOVEQ #0,D7
|
|||
|
MOVEQ #0,D1
|
|||
|
MOVE.W right(A2),D7 ; l := (right-left)*(bottom-top)*3
|
|||
|
SUB.W left(A2),D7
|
|||
|
MOVE.W bottom(A2),D1
|
|||
|
SUB.W top(A2),D1
|
|||
|
MULU D1,D7 ; get number of cells
|
|||
|
LSL #1,D7 ; 2 bytes per cell
|
|||
|
|
|||
|
moveq #sizeList+2,D0 ; we need this mush room (said Alice)
|
|||
|
add.l d7,d0
|
|||
|
_NewHandle clear ; get handle in A0 (ignore result *** )
|
|||
|
|
|||
|
MOVE.L A0,A4 ; handle in A4 is our custom
|
|||
|
MOVE.L (A4),A3 ; and get list pointer in A3
|
|||
|
|
|||
|
MOVE.L NLWindow(A6),port(A3) ; make specified window our port
|
|||
|
BSR ListNewEntry ; get into our port, lock list
|
|||
|
|
|||
|
MOVE.L NLBounds(A6),a2 ; get pointer to bounds rect
|
|||
|
MOVE.L (a2)+,dataBounds+topLeft(A3) ; dataBounds:=bounds
|
|||
|
MOVE.L (a2),dataBounds+botRight(A3)
|
|||
|
|
|||
|
MOVE.W D7,maxIndex(A3) ; set max index for cellArray
|
|||
|
|
|||
|
; set up the default list fields
|
|||
|
; the user can replace any of these settings after doing the ListNew, or by
|
|||
|
; letting the defProc’s Init function do it.
|
|||
|
|
|||
|
; Set viewRect, in global coordinates, to the values passed in r.
|
|||
|
|
|||
|
LEA rView(A3),A2 ; use A2 to index through record
|
|||
|
MOVE.L NLview(A6),A1 ; get our view rect
|
|||
|
|
|||
|
MOVE.L (A1)+,(A2)+ ; set our viewRect to r
|
|||
|
MOVE.L (A1),(A2)+
|
|||
|
|
|||
|
MOVEQ #0,D7 ; save cellSize.v in D7
|
|||
|
MOVEQ #0,D6 ; save cellSize.h in D6
|
|||
|
MOVE.W NLcSize+v(A6),D7 ; set specified cellSize
|
|||
|
MOVE.W NLcSize+h(A6),D6
|
|||
|
|
|||
|
MOVE.L #0,indent(A3) ; default indent = 0
|
|||
|
|
|||
|
; visible := (right-left)/cellsize.h,(bottom-top)/cellsize.v)
|
|||
|
; if cellsize := 0, then assign a size that is wide enough to fit all columns
|
|||
|
; on the screen and tall enough for text in the current font.
|
|||
|
|
|||
|
SUBQ #8,SP ; make room for GetFontInfo record
|
|||
|
MOVE.L SP,-(SP) ; point to it
|
|||
|
_GetFontInfo ; and go get info
|
|||
|
|
|||
|
MOVE.L NLBounds(A6),A1 ; get boundsrect into A1
|
|||
|
|
|||
|
TST.W D7 ; cellSize.v = 0 ?
|
|||
|
BNE.S @1 ; => no
|
|||
|
MOVE.W (SP),D7 ; else cellSize.v := ascent+descent+leading
|
|||
|
ADD.W 2(SP),D7 ; add descent
|
|||
|
ADD.W 6(SP),D7 ; add leading
|
|||
|
@1
|
|||
|
TST.W D6 ; cellSize.h = 0 ?
|
|||
|
BNE.S @2 ; => no
|
|||
|
MOVE.L NLview(A6),A0 ; get r
|
|||
|
MOVE.W right(A0),D6 ; else cellSize := r.right-r.left
|
|||
|
SUB.W left(A0),D6
|
|||
|
|
|||
|
MOVE.W right(A1),D0 ; if bounds.right-bounds.left <> 0
|
|||
|
SUB.W left(A1),D0
|
|||
|
BEQ.S @2
|
|||
|
DIVU D0,D6 ; then divide size.h by # of columns
|
|||
|
@2
|
|||
|
ADDQ #8,SP ; all done with font info
|
|||
|
MOVE.L topLeft(A1),visible(A3) ; visible.topLeft := bounds.topLeft
|
|||
|
|
|||
|
MOVE.W D6,-(SP) ; push cellSize.h
|
|||
|
MOVE.W D7,-(SP) ; push cellSize.v
|
|||
|
MOVE.L A4,-(SP) ; push list handle
|
|||
|
_LCellSize ; and set visible bottom, right
|
|||
|
|
|||
|
MOVE.B #1,LActive(A3) ; active = 1
|
|||
|
|
|||
|
MOVE.B NLdrawIt(A6),-(SP) ; push drawIt flag
|
|||
|
MOVE.L A4,-(SP) ; and our handle
|
|||
|
_LDoDraw ; and set our internal flag
|
|||
|
|
|||
|
; Set up the flag that says whether or not there is a grow box
|
|||
|
|
|||
|
TST.B NLhasGrow(A6) ; is there a grow box?
|
|||
|
BEQ.S @0 ; => no
|
|||
|
BSET #LHasGrow,ListFlags(A3) ; else say there is one
|
|||
|
@0
|
|||
|
TST.B NLsHoriz(A6) ; scrollHoriz?
|
|||
|
BEQ.S @4 ; => no thanks, not today
|
|||
|
MOVEQ #top,D0 ; use top index
|
|||
|
SUBQ #4,SP ; make room for result
|
|||
|
BSR ScrollNew ; get new control (trashes A2)
|
|||
|
MOVE.L (SP)+,hScroll(A3) ; save control handle
|
|||
|
BSET #lDoHAutoScroll,listFlags(A3) ; and allow autoscrolling
|
|||
|
@4
|
|||
|
TST.B NLsVert(A6) ; scrollVert?
|
|||
|
BEQ.S @5 ; => thanks, but no
|
|||
|
MOVEQ #left,D0 ; use left index
|
|||
|
SUBQ #4,SP ; make room for result
|
|||
|
BSR ScrollNew
|
|||
|
MOVE.L (SP)+,vScroll(A3) ; save control handle
|
|||
|
BSET #lDoVAutoScroll,listFlags(A3) ; and allow autoscrolling
|
|||
|
@5
|
|||
|
MOVE.L A4,-(SP) ; set control min, max
|
|||
|
BSR SetHilite ; if necessary
|
|||
|
|
|||
|
NOT.L lastClick(A3) ; set invalid click of all ones
|
|||
|
|
|||
|
; set up a handle for the data
|
|||
|
|
|||
|
MOVEQ #0,D0 ; get a handle for data
|
|||
|
_NewHandle clear ; make sure they’re 0 length
|
|||
|
MOVE.L A0,D0 ; test result
|
|||
|
BEQ.S NewExit ; => couldn’t get memory
|
|||
|
MOVE.L A0,cells(A3) ; save handle
|
|||
|
|
|||
|
; initialize the list defProc handle
|
|||
|
|
|||
|
MOVE.W #MapTrue, RomMapInsert ; insert ROM map <SM3>
|
|||
|
|
|||
|
MOVE.W NLProc(A6),D3 ; get the defProc ID
|
|||
|
|
|||
|
SUBQ #4,SP ; make room for function result
|
|||
|
MOVE.L #'LDEF',-(SP) ; push LDEF resource type
|
|||
|
MOVE.W D3,-(SP) ; push defProc ID1
|
|||
|
_GetResource ; get it
|
|||
|
MOVE.L (SP)+,ListDefHandle(A3) ; save list def handle
|
|||
|
|
|||
|
; Now call the defProc to let it do Init if it so desires.
|
|||
|
; Do it last so it can muck with all our other Init defaults.
|
|||
|
|
|||
|
BSR GetTheListProc ; get listproc and lock down
|
|||
|
BEQ.S @noLDEF ; => oops, we didn’t get it
|
|||
|
MOVE.W #LInitMsg,-(SP) ; do init call to defproc
|
|||
|
|
|||
|
MOVE.L #0,-(SP) ; this results in an EVEN address
|
|||
|
MOVE.L #0,-(SP) ; for the lRect ALWAYS
|
|||
|
MOVE.L #0,-(SP)
|
|||
|
MOVE.W #0,-(SP) ; CLR's are twice as slow
|
|||
|
|
|||
|
MOVE.L A4,-(SP) ; push handle
|
|||
|
JSR (A0) ; init it
|
|||
|
BSR UnlockLProc ; then unlock it
|
|||
|
@noLDEF
|
|||
|
MOVE.L A4,NLResult(A6) ; return result
|
|||
|
NewExit
|
|||
|
MOVE.W #26,D0 ; strip 26 bytes of parameters
|
|||
|
BRA StdExit ; unlock list, restore port, strip params...
|
|||
|
|
|||
|
;-------------------------
|
|||
|
; ScrollNew -- gets a new scroll bar; returns the handle on the stack
|
|||
|
;
|
|||
|
; A2 points to the temp rect used here. D0 indexes to top or left. The result of this
|
|||
|
; routine should be placed on the stack (below the RTS). A3 points to window list record.
|
|||
|
|
|||
|
ScrollNew
|
|||
|
MOVE.L NLview(A6),A2 ; get new view
|
|||
|
MOVE.L 4(A2),-(SP) ; push low word of r
|
|||
|
MOVE.L (A2),-(SP) ; and high word too
|
|||
|
MOVE.L SP,A2 ; pass pointer to rect in A2
|
|||
|
|
|||
|
BSR.S GetScSize ; calculate the size
|
|||
|
|
|||
|
SUBQ #4,SP ; room for horizontal handle
|
|||
|
MOVE.L port(A3),-(SP) ; push port address
|
|||
|
MOVE.L A2,-(SP) ; point to rect
|
|||
|
CLR.W len(A6) ; use len as a null string
|
|||
|
PEA len(A6) ; point to null string
|
|||
|
MOVE.B NLdrawIt(A6),-(SP) ; push visible flag
|
|||
|
CLR.L -(SP) ; 0,0: int
|
|||
|
CLR.W -(SP) ; 0: int
|
|||
|
MOVE.W #scrollBarProc,-(SP) ; proc ID: integer
|
|||
|
CLR.L -(SP) ; 0
|
|||
|
_NewControl
|
|||
|
MOVE.L (SP)+,12(SP) ; put result below rect and RTS
|
|||
|
ADDQ #8,SP ; strip off rect
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; GetScSize is a utility that is used
|
|||
|
; by ScrollNew and ListSize to calculate the size of the scroll bar
|
|||
|
; based on the list’s rect.
|
|||
|
; A pointer to a temp rect containing the current rView is in A2.
|
|||
|
; The index D0 is used to access either vertical (D0=0) or
|
|||
|
; horizontal elements (D0=2).
|
|||
|
|
|||
|
GetScSize
|
|||
|
MOVE.W 4(A2,D0),D1 ; top/left := bottom/right + 1
|
|||
|
ADD.W #1,D1
|
|||
|
MOVE.W D1,topLeft(A2,D0.W)
|
|||
|
ADD.W #14,D1 ; bottom/right := bottom/right + 15
|
|||
|
MOVE.W D1,botRight(A2,D0.W)
|
|||
|
MOVE.L A2,-(SP) ; point to rect
|
|||
|
MOVE.L MinusOne,-(SP) ; -1,-1
|
|||
|
_InsetRect ; make it a bit bigger
|
|||
|
RTS
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListDispose( h: ListHandle );
|
|||
|
;
|
|||
|
; Disposes of the given list.
|
|||
|
;
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
ListDispose
|
|||
|
BSR StdEntry ; ho hum again
|
|||
|
|
|||
|
BSR GetTheListProc ; get listproc and lock down
|
|||
|
BEQ.S @noDefProc ; => no defproc found
|
|||
|
MOVE.W #LcloseMsg,-(SP) ; do close call to defproc
|
|||
|
CLR.L -(SP) ; no select, rect or data
|
|||
|
CLR.L -(SP)
|
|||
|
CLR.L -(SP)
|
|||
|
CLR.W -(SP)
|
|||
|
MOVE.L A4,-(SP) ; push handle
|
|||
|
JSR (A0) ; init it
|
|||
|
BSR UnlockLProc ; then unlock it
|
|||
|
@noDefProc
|
|||
|
|
|||
|
MOVE.L cells(A3),A0 ; dump the data
|
|||
|
_DisposHandle
|
|||
|
|
|||
|
MOVE.L hScroll(A3),D0 ; is there a horizontal guy?
|
|||
|
BEQ.S @noHScroll ; => nope
|
|||
|
MOVE.L D0,-(SP) ; else push the control handle
|
|||
|
_DisposControl ; and down the dumper
|
|||
|
@noHScroll
|
|||
|
MOVE.L vScroll(A3),D0 ; is there a vertical guy?
|
|||
|
BEQ.S @noVScroll ; => nope
|
|||
|
MOVE.L D0,-(SP) ; else push the control handle
|
|||
|
_DisposControl ; and down the dumper
|
|||
|
@noVScroll
|
|||
|
|
|||
|
MOVE.L A4,A0 ; crumple up the list
|
|||
|
_DisposHandle ; and file it away
|
|||
|
move.l #0,a4 ; put a NIL in the handle so we don’t crash on unlock
|
|||
|
|
|||
|
BRA Std4Exit
|
|||
|
|
|||
|
;--------------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; Function ListAddColumn ( count, colNum: INTEGER; h: ListHandle ): INTEGER;
|
|||
|
; 14 12 8 16
|
|||
|
; ListAddColumn inserts count columns at colNum. If colNum is not within dataBounds, it
|
|||
|
; adds new last columns. The new cells added are all empty (have 0 length). The column
|
|||
|
; number of the first column added is returned. DataBounds is updated. If there are no cells
|
|||
|
; (because dataBounds.top=dataBounds.bottom), no cells are added, but dataBounds is still
|
|||
|
; extended.
|
|||
|
;
|
|||
|
; A new cell is added by inserting a new offset into the cellArray. This is accomplished
|
|||
|
; by shifting the array, from the insertion point to the end, two bytes to the right. This
|
|||
|
; leaves the offset of the new cell the same as the offset of the next cell, hence its
|
|||
|
; length is 0.
|
|||
|
;
|
|||
|
; A4 is the list handle. A3 is the list pointer. D7 is used for the cell.
|
|||
|
; D6 is used to make this routine work for ListAddRow too. This routine is
|
|||
|
; written to work to add columns (D6=D5=0). To make it work with rows, we must
|
|||
|
; add 2 to vertical references (D6=2) and subtract 2 from horizontal references
|
|||
|
; (D5 = -2). Got that?
|
|||
|
;
|
|||
|
; For listAddRow, interchange references to c.h and c.v, rows and columns,
|
|||
|
; right and bottom, and left and top.
|
|||
|
;
|
|||
|
;--------------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListAddRow
|
|||
|
BSR StdEntry ; set up standard stuff
|
|||
|
MOVEQ #h,D6 ; do rows
|
|||
|
BRA.S LAC1 ; => use common code
|
|||
|
|
|||
|
ListAddColumn
|
|||
|
BSR StdEntry ; set up standard stuff
|
|||
|
MOVEQ #v,D6 ; do columns
|
|||
|
LAC1
|
|||
|
MOVE.L D6,D5 ; use a negative copy for
|
|||
|
NEG.W D5 ; vertical references
|
|||
|
|
|||
|
; if colNum is out of bounds, set it to dataBounds.right
|
|||
|
|
|||
|
SWAP D7 ; get c.h into low word
|
|||
|
MOVE.W dataBounds+right(A3,D5),D0 ; get right for below
|
|||
|
CMP.W dataBounds+left(A3,D5),D7 ; is it too small?
|
|||
|
BLT.S @1 ; => yes, add new right column
|
|||
|
CMP.W D0,D7 ; is it too big?
|
|||
|
BLE.S @2 ; => no, use specified column
|
|||
|
@1
|
|||
|
MOVE.W D0,D7 ; else return new column
|
|||
|
@2
|
|||
|
MOVE.W D7,16(A6) ; return final column
|
|||
|
SWAP D7 ; set up c.v
|
|||
|
MOVE.W dataBounds+bottom(A3,D6),D4 ; set final index
|
|||
|
MOVE.W dataBounds+top(A3,D6),D7 ; for c.v:= top to bottom-1
|
|||
|
|
|||
|
; allocate enough extra memory for bottom-top new cells
|
|||
|
|
|||
|
MOVE.W D4,D3 ; get number of cells to add in D3
|
|||
|
SUB.W D7,D3 ; bottom-top := new cells
|
|||
|
EXT.L D3 ; make it a long
|
|||
|
MULU 14(A6),D3 ; multiply by number of columns
|
|||
|
BSR.S GrowRecord ; make the record bigger
|
|||
|
tst.w d0 ; did grow fail? <10>
|
|||
|
bne Std8Exit ; if so bail out, note: there is no way to tell the caller we failed <10>
|
|||
|
|
|||
|
; increase our bounds in the proper direction
|
|||
|
|
|||
|
MOVE.W 14(A6),D0 ; get number of columns
|
|||
|
ADD.W D0,dataBounds+right(A3,D5) ; bump right by count
|
|||
|
BRA.S @7 ; check bounds and go
|
|||
|
@4
|
|||
|
TST.W D6 ; if columns, then get c.h
|
|||
|
BNE.S @5 ; => it’s rows, have c.h
|
|||
|
SWAP D7
|
|||
|
@5
|
|||
|
BSR CellToIndex ; cell in D7 -> index in D3
|
|||
|
LEA cellArray(A3,D3),A0 ; get source address
|
|||
|
MOVE.L A0,A1 ; and destination address
|
|||
|
MOVE.W 14(A6),D1 ; get count
|
|||
|
EXT.L D1 ; as a long
|
|||
|
ASL.L #1,D1 ; 2*count is amount of shift
|
|||
|
ADD.L D1,A1 ; form destination address
|
|||
|
MOVE.W maxIndex(A3),D0 ; # of bytes to move =
|
|||
|
ADD.W #2,D0 ; maxindex + 2 - D3
|
|||
|
SUB.W D3,D0
|
|||
|
EXT.L D0 ; make it long
|
|||
|
ADD.W D1,maxIndex(A3) ; update maxIndex by amount of shift
|
|||
|
_BlockMove ; and slide the bytes over
|
|||
|
|
|||
|
; set the new offsets to the first pre-existing offset to the right (-> 0 length)
|
|||
|
|
|||
|
MOVE.L A3,A0 ; make sure new cells aren’t selected
|
|||
|
EXT.L D3
|
|||
|
ADD.L D3,A0 ; get pointer to first new cell
|
|||
|
MOVE.W 14(A6),D0 ; get count
|
|||
|
ASL.W #1,D0 ; *2
|
|||
|
MOVE.W cellArray(A0,D0),D1 ; get index for next pre-existing cell
|
|||
|
BCLR #15,D1 ; de-select it
|
|||
|
BRA.S @8 ; need to subtract 2 for 0 based
|
|||
|
@3
|
|||
|
MOVE.W D1,cellArray(A0,D0) ; stuff the new value
|
|||
|
@8
|
|||
|
SUBQ #2,D0 ; do next cell
|
|||
|
BPL.S @3
|
|||
|
|
|||
|
TST.W D6 ; if columns, then get c.v
|
|||
|
BNE.S @6 ; => it’s rows, use c.h
|
|||
|
SWAP D7 ; do next c.v
|
|||
|
@6
|
|||
|
ADD.W #1,D7
|
|||
|
@7
|
|||
|
CMP.W D4,D7 ; hit bottom yet
|
|||
|
BLT.S @4 ; => no, keep looping
|
|||
|
|
|||
|
BRA DelExit ; redraw scroll bars and exit
|
|||
|
|
|||
|
;------------
|
|||
|
; GrowRecord -- extend the record by the number
|
|||
|
; of cells in D3. Trashes A0, updates A3, D0 = error code <10>
|
|||
|
|
|||
|
GrowRecord
|
|||
|
MOVE.L A4,A0 ; first get current handle
|
|||
|
_HUnlock ; unlock the handle
|
|||
|
_GetHandleSize ; get size into D0
|
|||
|
ADD.W D3,D0 ; convert cells to bytes
|
|||
|
ADD.W D3,D0 ; get new size
|
|||
|
EXT.L D0 ; and make it long
|
|||
|
_SetHandleSize ; resize it
|
|||
|
move.w d0,-(sp) ; save SetHandleSize error <10>
|
|||
|
_HLock ; lock the handle
|
|||
|
move.w (sp)+,d0 ; restore SetHandleSize error <10>
|
|||
|
MOVE.L (A4),A3 ; get the pointer
|
|||
|
RTS ; and return
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;------------
|
|||
|
; HomeVisible -- move the visible rect to the upper left of the
|
|||
|
; bounds rect.
|
|||
|
|
|||
|
HomeVisible
|
|||
|
MOVE.L dataBounds(A3),D0 ; get the databounds
|
|||
|
SUB.W visible+left(A3),D0 ; get databounds.left - visible.left
|
|||
|
SWAP D0
|
|||
|
SUB.W visible+top(A3),D0 ; get databounds.top - visible.top
|
|||
|
SWAP D0 ; get offset
|
|||
|
PEA visible(A3) ; adjust visible rectangle
|
|||
|
MOVE.L D0,-(SP) ; push the offset
|
|||
|
_OffsetRect
|
|||
|
RTS
|
|||
|
|
|||
|
|
|||
|
;--------------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; Function ListDelColumn ( count, colNum: INTEGER; h: ListHandle );
|
|||
|
; 14 12 8
|
|||
|
; ListDelColumn deletes count columns, starting at colNum. If colNum is not within
|
|||
|
; dataBounds, it does nothing. If there aren’t the specified number of columns to the
|
|||
|
; right of colnum, then only existing columns are deleted. DataBounds is updated.
|
|||
|
; See comments for ListAddColumn
|
|||
|
;
|
|||
|
; A4 is the list handle. A3 is the list pointer. D7 is used for the cell. D6 for the colNum
|
|||
|
;
|
|||
|
;--------------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListDelRow
|
|||
|
BSR StdEntry ; save standard stuff
|
|||
|
MOVEQ #h,D6 ; say we’re doing rows
|
|||
|
BRA.S LDC1 ; and use (un)common code
|
|||
|
|
|||
|
ListDelColumn
|
|||
|
BSR StdEntry ; save standard stuff
|
|||
|
MOVEQ #v,D6
|
|||
|
LDC1
|
|||
|
MOVE.L D6,D5
|
|||
|
NEG D5 ; get negative for horizontal refs
|
|||
|
MOVE.W D7,D0 ; get count into D0
|
|||
|
BMI Del2Exit ; negative counts are verboten!
|
|||
|
BNE.S @0 ; => not special case of 0
|
|||
|
|
|||
|
MOVEQ #0,D7 ; set colNum to 0
|
|||
|
BRA.S DelAll ; and flush out the record
|
|||
|
|
|||
|
; If (colNum = dataBounds.left AND count >= # of columns) then flushRecord
|
|||
|
|
|||
|
@0 SWAP D7 ; c.h := colNum
|
|||
|
MOVE.W dataBounds+right(A3,D5),D1 ; get right
|
|||
|
MOVE.W dataBounds+left(A3,D5),D2 ; get left
|
|||
|
CMP.W D7,D2 ; colNum = databounds.left?
|
|||
|
BNE.S DelSome ; => no, do the usual
|
|||
|
MOVE.W D1,D3 ; if right - left <= count
|
|||
|
SUB.W D2,D3 ; then clear everything out
|
|||
|
CMP.W D3,D0
|
|||
|
BLT.S DelSome ; => count < width
|
|||
|
|
|||
|
DelAll BSR FlushRecord ; clear out data and bounds
|
|||
|
BSR.S HomeVisible ; move visible to topLeft of bounds
|
|||
|
|
|||
|
SWAP D7 ; fix up D7
|
|||
|
BRA DelExit ; => use common code to redraw
|
|||
|
|
|||
|
DelSome CMP.W D2,D7 ; if (colNum >= left) AND (colNum < right)
|
|||
|
BLT Del2Exit ; => oops, colNum < left
|
|||
|
CMP.W D1,D7
|
|||
|
BGE Del2Exit ; => oops, colNum >= right
|
|||
|
|
|||
|
; now make sure that the requested number of columns can be deleted. If not, get the
|
|||
|
; maximum number that can be deleted.
|
|||
|
|
|||
|
MOVE.W D7,D3 ; get first column to delete
|
|||
|
ADD.W D0,D3 ; get proposed right column
|
|||
|
CMP.W D1,D3 ; how does it compare to databounds.right?
|
|||
|
BLE.S @0 ; it’s just fine
|
|||
|
SUB.W D7,D1 ; else calculate number of columns to our right
|
|||
|
MOVE.W D1,14(A6) ; and save new value in frame
|
|||
|
|
|||
|
; save state of doDraw, and turn drawing off while clearing cells
|
|||
|
|
|||
|
@0 MOVE.B ListFlags(A3),-(SP) ; save flags
|
|||
|
BSET #noDraw,ListFlags(A3) ; turn drawing off
|
|||
|
|
|||
|
SWAP D7 ; set up c.v
|
|||
|
MOVE.W dataBounds+bottom(A3,D6),D7 ; for i := bottom-1 downto top do
|
|||
|
MOVE.W dataBounds+top(A3,D6),D4
|
|||
|
|
|||
|
BRA.S EndClrEm ; pre-decrement i
|
|||
|
|
|||
|
ClrLoop
|
|||
|
; repeat count times (next cell to be deleted will slide back into current position)
|
|||
|
|
|||
|
MOVE.W 14(A6),A2 ; get number of cells in row
|
|||
|
|
|||
|
TST.W D6 ; is it columns
|
|||
|
BNE.S DelNext ; => no, got c.h
|
|||
|
SWAP D7 ; get c.h into low word
|
|||
|
|
|||
|
; first get rid of the cell’s data
|
|||
|
|
|||
|
DelNext MOVE.L D7,-(SP) ; this is the cell
|
|||
|
MOVE.L A4,-(SP) ; and this is the list
|
|||
|
_LClrCell ; go zero out the data
|
|||
|
|
|||
|
; now get rid of the cell itself
|
|||
|
|
|||
|
BSR CellToIndex ; cell in D7 -> index in D3
|
|||
|
LEA cellArray(A3,D3),A1 ; get destination address
|
|||
|
MOVE.L A1,A0 ; source address is two beyond it
|
|||
|
ADDQ.L #2,A0 ; to delete current cell
|
|||
|
MOVE.W maxIndex(A3),D0 ; get maxIndex for the array
|
|||
|
SUB.W #2,maxIndex(A3) ; and shrink for next time
|
|||
|
SUB.W D3,D0 ; get number of bytes to move
|
|||
|
EXT.L D0 ; make it long
|
|||
|
_BlockMove ; and slide the bytes over
|
|||
|
|
|||
|
SUBA #1,A2 ; do next count
|
|||
|
MOVE.W A2,D0 ; test count
|
|||
|
BNE.S DelNext ; => delete "same cell" again
|
|||
|
|
|||
|
TST.W D6 ; is it columns?
|
|||
|
BNE.S EndClrEm ; => no, use c.h
|
|||
|
SWAP D7 ; do next c.v
|
|||
|
|
|||
|
EndClrEm SUB.W #1,D7
|
|||
|
CMP.W D4,D7 ; hit top yet?
|
|||
|
BGE.S ClrLoop ; => no, keep looping
|
|||
|
|
|||
|
MOVE.B (SP)+,ListFlags(A3) ; restore flags
|
|||
|
|
|||
|
MOVE.W 14(A6),D0 ; get count
|
|||
|
SUB.W D0,dataBounds+right(A3,D5) ; make right smaller by count
|
|||
|
|
|||
|
; release the extra memory that we just threw away
|
|||
|
|
|||
|
MOVE.W D4,D3 ; get number of cells to subtract in D3
|
|||
|
SUB.W dataBounds+bottom(A3,D6),D3 ; top-bottom := new cells (negative)
|
|||
|
EXT.L D3 ; make it long and negative
|
|||
|
MULS D0,D3 ; multiply by count
|
|||
|
BSR.S GrowRecord ; make the record smaller
|
|||
|
|
|||
|
DelExit
|
|||
|
|
|||
|
; This hunk of code is shared by add/delete row/column. On entry, the databounds have
|
|||
|
; been adjusted to account for the change in structure. This routine first calls JustRect
|
|||
|
; to adjust (and redraw) the visible rect if necessary. Then it calls ListUpdate to
|
|||
|
; redraw any portions of the array that have changed. Finally it calls SetHilite to
|
|||
|
; update the scroll bars.
|
|||
|
|
|||
|
; If the flag noDraw is set then don’t do this stuff
|
|||
|
|
|||
|
BTST #noDraw,ListFlags(A3) ; should we do update?
|
|||
|
BNE.S Del2Exit ; => no
|
|||
|
|
|||
|
LEA r(A6),A2 ; use our temp rect
|
|||
|
MOVE.L visible(A3),(A2) ; get the visible rect
|
|||
|
MOVE.L visible+4(A3),4(A2)
|
|||
|
BSR JustRect ; and adjust it
|
|||
|
BNE.S @1 ; => no change do normal update
|
|||
|
ST D0 ; we want an update
|
|||
|
BSR MoveRect ; move and update if necessary
|
|||
|
|
|||
|
; The rect we want to update is basically the visible rect, except with our
|
|||
|
; row/column replacing its left/top. Get the local coordinates of the upper left
|
|||
|
; cell to be updated, and update down to lower right of rView.
|
|||
|
; At this point our row/column is in the high word of D7, and its index is in D5
|
|||
|
@1
|
|||
|
MOVE.L visible(A3),(A2) ; get the visible topLeft
|
|||
|
SWAP D7 ; and the top/Left imposed by new row, column
|
|||
|
CMP.W left(A2,D5),D7 ; use whichever is greater
|
|||
|
BLE.S @2 ; ours is less or equal to visible, use visible
|
|||
|
MOVE.W D7,left(A2,D5) ; new row/column
|
|||
|
@2
|
|||
|
MOVE.L A2,-(SP) ; get coordinates into r
|
|||
|
MOVE.L (A2),-(SP) ; and cell to update
|
|||
|
MOVE.L A4,-(SP) ; and list handle
|
|||
|
_LRect ; get local coordinates of topleft (no bounds check)
|
|||
|
MOVE.L rView+botRight(A3),botRight(A2) ; and of botRight into r
|
|||
|
|
|||
|
; ListUpdate needs a region. Create one equal to the rect in r.
|
|||
|
|
|||
|
SUBQ #4,SP ; make room for handle
|
|||
|
_NewRgn ; get handle for DisposRgn
|
|||
|
MOVE.L (SP),-(SP) ; make copy for ListUpdate
|
|||
|
MOVE.L (SP),-(SP) ; and one for EraseRgn
|
|||
|
MOVE.L (SP),-(SP) ; and one for RectRgn
|
|||
|
MOVE.L A2,-(SP) ; push the rect
|
|||
|
_RectRgn ; make the rect a region (leave on stack)
|
|||
|
|
|||
|
; If there aren’t enough rows/columns to fill the screen, then we need to erase the
|
|||
|
; rightmost/bottom row/column. It is more general to erase update region within ListUpdate,
|
|||
|
; but then erases get done twice for everything (eraseRect done in drawProc too).
|
|||
|
|
|||
|
_EraseRgn
|
|||
|
MOVE.L A4,-(SP) ; pass the list handle
|
|||
|
_LUpdate ; go update the whole mess
|
|||
|
|
|||
|
_DisposRgn ; and dispose the region
|
|||
|
skipUpdate
|
|||
|
MOVE.L A4,-(SP) ; push handle
|
|||
|
BSR SetHilite ; update scroll bars, hiliting
|
|||
|
Del2Exit
|
|||
|
BRA Std8Exit ; do the standard ausgang spiel
|
|||
|
|
|||
|
;------------
|
|||
|
; FlushRecord is a little utility that throws out all the current data, and
|
|||
|
; resets everything relevant to 0. The list record is locked, but its not growing.
|
|||
|
|
|||
|
FlushRecord
|
|||
|
MOVE.L A4,A0 ; get handle to list
|
|||
|
MOVEQ #sizeList+2,D0 ; list record plus 2 for maxindex
|
|||
|
_SetHandleSize ; re-size the list record (which is locked)
|
|||
|
MOVE.W dataBounds+left(A3,D5),D0 ; say 0 columns by setting right=left
|
|||
|
MOVE.W D0,dataBounds+right(A3,D5) ; (this keeps users left the same)
|
|||
|
MOVE.L cells(A3),A0 ; get handle to cell data
|
|||
|
MOVEQ #0,D0 ; set size to 0
|
|||
|
_SetHandleSize ; no more data!
|
|||
|
CLR.L maxIndex(A3) ; clear maxIndex and first cell of array
|
|||
|
RTS
|
|||
|
|
|||
|
;-------------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; Procedure ListRect ( VAR r: Rect; c: Cell; h:ListHandle );
|
|||
|
; 16 12 8
|
|||
|
; ListRect returns in r the local coordinates of the cell c in the window. If c.h <0
|
|||
|
; the coordinates of the entire row identified by c.v are returned.
|
|||
|
;
|
|||
|
; StdEntry puts c in D7; list pointer in A3; list handle in A4
|
|||
|
; NOTE: don’t bounds check c because delExit, above, wants coordinates of out of bounds cells.
|
|||
|
;-------------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListRect
|
|||
|
BSR StdEntry ; *** what if c out of bounds??
|
|||
|
MOVE.L 16(A6),A1 ; get r into A1
|
|||
|
MOVE.L rView(A3),(A1) ; get topLeft of list’s rect
|
|||
|
|
|||
|
SWAP D7 ; get c.v in low word
|
|||
|
MOVE.W D7,D0 ; r.top := r.top+(c.v-visible.top)*cellsize.v
|
|||
|
SUB.W visible+top(A3),D0
|
|||
|
MULU cellsize+v(A3),D0
|
|||
|
ADD.W D0,top(A1)
|
|||
|
|
|||
|
MOVE.W top(A1),D0
|
|||
|
ADD.W cellSize+v(A3),D0 ; r.bottom := r.top+cellSize.v
|
|||
|
MOVE.W D0,bottom(A1)
|
|||
|
|
|||
|
SWAP D7 ; get c.h in low word
|
|||
|
MOVE.W D7,D0 ; if c.h < 0 then
|
|||
|
BLT.S @wholeRow ; return whole row
|
|||
|
|
|||
|
SUB.W visible+left(A3),D0 ; r.left := r.left+(c.h-visible.left)*cellsize.h
|
|||
|
MULU cellSize+h(A3),D0
|
|||
|
ADD.W D0,left(A1)
|
|||
|
|
|||
|
MOVE.W left(A1),D0
|
|||
|
ADD.W cellSize+h(A3),D0 ; r.right := r.left+cellSize.v
|
|||
|
MOVE.W D0,right(A1)
|
|||
|
@wholeRow
|
|||
|
|
|||
|
Std12Exit
|
|||
|
MOVEQ #12,D0 ; strip 12 bytes of parameters
|
|||
|
BRA StdExit ; and exit
|
|||
|
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListScroll ( dCols, dRows: INTEGER; h: ListHandle );
|
|||
|
; 14 12 8
|
|||
|
; ListScroll scrolls the list dCols horizontally and dRows vertically, bounded
|
|||
|
; by the visBounds. Does all necessary updating of the screen.
|
|||
|
;
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListScroll
|
|||
|
BSR StdEntry ; ho humm
|
|||
|
|
|||
|
MOVE.L visible(A3),r(A6) ; make a copy of visible rect
|
|||
|
MOVE.L visible+4(A3),r+4(A6)
|
|||
|
|
|||
|
; first offset the visible rect by the requested amount
|
|||
|
|
|||
|
PEA r(A6) ; OffsetRect(rNew,dCols,dRows)
|
|||
|
MOVE.L D7,-(SP) ; push rows, cols
|
|||
|
_OffsetRect
|
|||
|
|
|||
|
BSR.S JustRect ; align the rect for optimal display
|
|||
|
BNE.S @3 ; => no movement. Don’t flicker
|
|||
|
ST D0 ; we want an update
|
|||
|
BSR.S MoveRect ; else update display
|
|||
|
|
|||
|
MOVE.L A4,-(SP) ; and update the scroll bars
|
|||
|
BSR SetHilite
|
|||
|
@3
|
|||
|
BRA Std8Exit ; strip 8 bytes of parameters
|
|||
|
|
|||
|
;------------
|
|||
|
; JustRect
|
|||
|
; This routine is used by ListScroll and Add/Delete Row/Column. Given a rect in r,
|
|||
|
; (the proposed visible rect), it makes sure that the bottom right of the rect are
|
|||
|
; within the current visBounds. If not, it tries to move r up and to the left
|
|||
|
; so that all visible cells contain something. It returns BNE if no visible change.
|
|||
|
|
|||
|
JustRect
|
|||
|
BSR GetVisBounds ; get visible boundaries
|
|||
|
|
|||
|
moveq #v,d2 ; do the vertical sliding
|
|||
|
bsr.s JustifyOneDimension
|
|||
|
|
|||
|
moveq #h,d2 ; do the horizontal sliding
|
|||
|
bsr.s JustifyOneDimension
|
|||
|
|
|||
|
SUBQ #2,SP ; if rNew <> visible then
|
|||
|
PEA r(A6)
|
|||
|
PEA visible(A3)
|
|||
|
_EqualRect
|
|||
|
TST.B (SP)+
|
|||
|
RTS ; BNE if no change
|
|||
|
|
|||
|
;------------
|
|||
|
; JustifyOneDimension slides one dimension (horizontal or vertical) of the rectangle, r,
|
|||
|
; into view. The parameters are:
|
|||
|
;
|
|||
|
; r(a6) rectangle to slide
|
|||
|
; visBounds(a6) area defining what is visible
|
|||
|
; d2.w h or v to define which dimension to slide
|
|||
|
;
|
|||
|
; uses d0 and d1
|
|||
|
|
|||
|
JustifyOneDimension
|
|||
|
|
|||
|
move.w r+botRight(a6,d2.w),d0
|
|||
|
sub.w visBounds+botRight(a6,d2.w),d0
|
|||
|
ble.s @tryTopLeft ; if bottom/right needs to be slid into place, do it
|
|||
|
bsr.s @slide
|
|||
|
@tryTopLeft
|
|||
|
move.w r+topLeft(a6,d2.w),d0
|
|||
|
sub.w visBounds+topLeft(a6,d2.w),d0
|
|||
|
bge.s @noSlide ; if top/left needs to be slid into place, do it
|
|||
|
@slide
|
|||
|
sub.w d0,r+topLeft(a6,d2.w) ; slide so that it is visible
|
|||
|
sub.w d0,r+botRight(a6,d2.w)
|
|||
|
@noSlide
|
|||
|
rts
|
|||
|
|
|||
|
;------------
|
|||
|
; MoveRect scrolls and updates the list so that the rect in r becomes the visible rect.
|
|||
|
|
|||
|
MoveRect
|
|||
|
movem.l d7/a2,-(sp) ; save registers
|
|||
|
|
|||
|
move.b d0,d7 ; save update flag
|
|||
|
|
|||
|
SUBQ #4,SP ; go get a new region
|
|||
|
_NewRgn
|
|||
|
move.l (sp),a2 ; get region handle (keep around for dispose)
|
|||
|
|
|||
|
BTST #noDraw,ListFlags(A3) ; is drawing on?
|
|||
|
BNE.S @noScroll ; => nope, just exit
|
|||
|
PEA rView(A3) ; scroll by our x and y deltas
|
|||
|
BSR.S GetOffset ; get offset into D0
|
|||
|
MOVE.L D0,-(SP)
|
|||
|
MOVE.L A2,-(SP) ; pass the region handle
|
|||
|
_ScrollRect
|
|||
|
@noScroll
|
|||
|
|
|||
|
MOVE.L r(A6),visible(A3) ; visible := rNew
|
|||
|
MOVE.L r+4(A6),visible+4(A3)
|
|||
|
|
|||
|
TST.B d7 ; update?
|
|||
|
BEQ.S @noUpdate ; => no
|
|||
|
MOVE.L A2,-(SP) ; pass the region handle
|
|||
|
MOVE.L A4,-(SP) ; and the handle to our list
|
|||
|
_LUpdate ; and update region
|
|||
|
@noUpdate
|
|||
|
|
|||
|
_DisposRgn ; dispose of region
|
|||
|
|
|||
|
movem.l (sp)+,d7/a2 ; restore registers
|
|||
|
rts
|
|||
|
|
|||
|
GetOffset
|
|||
|
MOVEQ #0,D0 ; prepare for long multiply
|
|||
|
MOVE.W visible+left(A3),D0 ; dx = (visible.left-r.left)*cellsize.h
|
|||
|
SUB.W r+left(A6),D0
|
|||
|
MULU cellSize+h(A3),D0
|
|||
|
MOVE.W D0,-(SP)
|
|||
|
MOVEQ #0,D0 ; prepare for long multiply
|
|||
|
MOVE.W visible+top(A3),D0 ; dy = (visible.top-r.top)*cellSize.v
|
|||
|
SUB.W r+top(A6),D0
|
|||
|
MULU cellSize+v(A3),D0
|
|||
|
MOVE.W D0,-(SP)
|
|||
|
MOVE.L (SP)+,D0
|
|||
|
RTS
|
|||
|
|
|||
|
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListUpdate ( r: RgnHandle; h: ListHandle );
|
|||
|
; 12 8
|
|||
|
; ListUpdate redraws any of the visible cells which intersect with r. Also
|
|||
|
; draws the scroll bar controls if they intersect with r.
|
|||
|
;
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListUpdate
|
|||
|
BSR StdEntry ; ho hum
|
|||
|
|
|||
|
BTST #noDraw,ListFlags(A3) ; is drawing on?
|
|||
|
BNE.S @done ; => nope, just exit
|
|||
|
|
|||
|
MOVE.W visible+top(A3),D6 ; D6 := visible.top
|
|||
|
MOVE.W visible+bottom(A3),D4 ; D4 := visible.bottom
|
|||
|
MOVE.W visible+right(A3),D5 ; D5 := visible.right
|
|||
|
BRA.S @5 ; for i := top to bottom-1
|
|||
|
@1
|
|||
|
MOVE.W visible+left(A3),D3 ; for j := left to right-1
|
|||
|
BRA.S @4
|
|||
|
@2
|
|||
|
MOVE.W D6,D7 ; get current cell into D7 for DoDraw
|
|||
|
SWAP D7 ; c.v into high word
|
|||
|
MOVE.W D3,D7 ; and c.h into low word
|
|||
|
|
|||
|
PEA r(A6) ; ListRect (r,c,h)
|
|||
|
MOVE.L D7,-(SP) ; push c
|
|||
|
MOVE.L A4,-(SP) ; push h
|
|||
|
_LRect ; find rect containing c
|
|||
|
|
|||
|
; is the cell in the update region?
|
|||
|
|
|||
|
SUBQ #2,SP ; make room for boolean result
|
|||
|
PEA r(A6) ; push our rect
|
|||
|
MOVE.L 12(A6),-(SP) ; and update Region
|
|||
|
_RectInRgn ; is the rect in the region?
|
|||
|
TST.B (SP)+ ; check el resulto
|
|||
|
BEQ.S @3 ; => no, don’t draw
|
|||
|
|
|||
|
BSR DoDraw ; go draw the cell
|
|||
|
@3
|
|||
|
ADDQ #1,D3 ; j:=j+1
|
|||
|
@4
|
|||
|
CMP.W D5,D3 ; until left = right
|
|||
|
BLT.S @2
|
|||
|
ADDQ #1,D6 ; i:=i+1
|
|||
|
@5
|
|||
|
CMP.W D4,D6 ; until top = bottom
|
|||
|
BLT.S @1
|
|||
|
|
|||
|
BSR DrawScrollBars
|
|||
|
@done
|
|||
|
BRA Std8Exit ; and exit using commoner’s code
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
; Selection handling routines
|
|||
|
; Register conventions: A4 = List handle
|
|||
|
; A3 = List pointer
|
|||
|
; D3 = used as cell index
|
|||
|
; D4 = set to end of selection array
|
|||
|
; D6 = actual cell, if needed
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
;------------
|
|||
|
; DoSelLoop
|
|||
|
; This routine calls the routine in A2 once for each selected cell.
|
|||
|
|
|||
|
DoSelLoop
|
|||
|
MOVEM.L D3-D4/D7,-(SP) ; save work registers
|
|||
|
MOVEQ #0,D3 ; get starting index
|
|||
|
MOVE.W maxIndex(A3),D4 ; get maximum index
|
|||
|
BRA.S @3 ; do initial check
|
|||
|
@1
|
|||
|
TST.B cellArray(A3,D3) ; test next cell
|
|||
|
BPL.S @2
|
|||
|
|
|||
|
JSR (A2) ; call for each selection
|
|||
|
@2
|
|||
|
ADDQ #2,D3 ; go to next element
|
|||
|
@3
|
|||
|
CMP.W D4,D3 ; done yet?
|
|||
|
BLE.S @1 ; => noop, lope on
|
|||
|
MOVEM.L (SP)+,D3-D4/D7
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; DrawASel -- draws a selected cell called by listactivate (must draw)
|
|||
|
;
|
|||
|
; This routine is passed to DoSelLoop, and called once for each selected cell.
|
|||
|
|
|||
|
DrawASel
|
|||
|
BSR.S DrawIndex ; get cell, draw it
|
|||
|
|
|||
|
PEA r(A6) ; get rect into r
|
|||
|
MOVE.L D7,-(SP) ; get rect we just drew
|
|||
|
MOVE.L A4,-(SP)
|
|||
|
_LRect ; get cell’s rect into r
|
|||
|
|
|||
|
SUBQ #2,SP ; room for result
|
|||
|
PEA rView(A3) ; get intersection of rView
|
|||
|
PEA r(A6) ; and current cell
|
|||
|
MOVE.L (SP),-(SP) ; and save into r
|
|||
|
_SectRect
|
|||
|
TST.B (SP)+ ; is cell in view
|
|||
|
BEQ.S @nothingDrawn ; => no, nothing to validate
|
|||
|
|
|||
|
PEA r(A6) ; get rect into r
|
|||
|
bsr.s MyValidRect ; validate rectangle so we don’t draw twice
|
|||
|
@nothingDrawn
|
|||
|
|
|||
|
RTS ; and return
|
|||
|
|
|||
|
;------------
|
|||
|
; DrawSel -- draws the cell in D7
|
|||
|
|
|||
|
DrawIndex
|
|||
|
BSR IndexToCell ; index in D3 -> cell in D7
|
|||
|
DrawSel
|
|||
|
MOVE.L D7,-(SP) ; pass selected cell
|
|||
|
MOVE.L A4,-(SP) ; and handle
|
|||
|
_LDraw ; draw the cell
|
|||
|
RTS ; and return
|
|||
|
|
|||
|
;------------
|
|||
|
; ClrSel
|
|||
|
; This utility deselects the cell whose index is in D3 and redraws it.
|
|||
|
; On entry, the list pointer is in A3.
|
|||
|
|
|||
|
ClrSel
|
|||
|
BCLR #7,cellArray(A3,D3) ; test and clear selection
|
|||
|
HiliteIndex
|
|||
|
BSR IndexToCell ; index in D3 -> cell in D7
|
|||
|
HiliteSel
|
|||
|
MOVE.L D7,-(SP) ; pass selected cell
|
|||
|
MOVE.L A4,-(SP) ; and handle
|
|||
|
BSR ListHilite ; draw the cell
|
|||
|
RTS ; and return
|
|||
|
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListSetSelect ( SetIt: BOOLEAN; c: Cell; h: ListHandle );
|
|||
|
; 16 12 8
|
|||
|
; If SetIt is true, then select the cell and redraw if necessary.
|
|||
|
; If SetIt is false,then deselect the cell and redraw if necessary.
|
|||
|
; If the noDraw bit in ListFlags is set, then don’t draw.
|
|||
|
;
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListSetSelect
|
|||
|
BSR StdEntry ; ha ha
|
|||
|
BSR MyFind ; validate cell
|
|||
|
BEQ.S @3 ; bogus cell, exit post haste
|
|||
|
|
|||
|
BTST #LNoNilHilite,selFlags(A3) ; should we select empty cells?
|
|||
|
BEQ.S @0 ; => yes, select anything
|
|||
|
TST.W len(A6) ; is it empty?
|
|||
|
BEQ.S @3 ; => yes, don’t select
|
|||
|
@0
|
|||
|
BSR CellToIndex ; get index into D3 (cell in D7)
|
|||
|
TST.B 16(A6) ; select or deselect cell?
|
|||
|
BNE.S @1 ; => select the cell
|
|||
|
BCLR #7,cellArray(A3,D3) ; test and deselect
|
|||
|
BEQ.S @3 ; => don’t need to draw
|
|||
|
BRA.S @2 ; => else redraw the cell
|
|||
|
@1
|
|||
|
BSET #7,cellArray(A3,D3) ; test and select
|
|||
|
BNE.S @3 ; => don’t need to redraw
|
|||
|
@2
|
|||
|
BTST #noDraw,ListFlags(A3) ; is drawing on?
|
|||
|
BNE.S @3 ; => no, don’t invert
|
|||
|
BSR.S HiliteSel ; else hilite the cell
|
|||
|
@3
|
|||
|
BRA Std10Exit ; strip off 10 bytes and go
|
|||
|
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; ListGetSelect ( getNext:boolean; VAR c: cell; h: ListHandle): boolean
|
|||
|
; 16 12 8 18
|
|||
|
; If getNext is FALSE, returns whether the cell c is selected.
|
|||
|
; If getNext is TRUE, returns in c the next selected cell (including c).
|
|||
|
; If there is no next cell, FALSE is returned.
|
|||
|
;
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListGetSelect
|
|||
|
BSR StdEntry ; hee hee
|
|||
|
CLR.W 18(A6) ; assume result false
|
|||
|
MOVE.L D7,A2 ; get cell pointer
|
|||
|
MOVE.L (A2),D7 ; get cell
|
|||
|
BSR MyFind ; validate cell (A2 preserved)
|
|||
|
BEQ.S LGSExit ; => exit if bad
|
|||
|
|
|||
|
MOVE.W index(A6),D3 ; get index to cell
|
|||
|
|
|||
|
TST.B 16(A6) ; get the next one?
|
|||
|
BNE.S @1 ; => yes
|
|||
|
|
|||
|
; simply set the result according to the selection bit of the indicated cell
|
|||
|
|
|||
|
TST.B cellArray(A3,D3) ; test selection bit
|
|||
|
BPL.S LGSExit ; if plus, return false
|
|||
|
@0
|
|||
|
MOVE.W #$0100,18(A6) ; else return true
|
|||
|
BRA.S LGSExit
|
|||
|
|
|||
|
; starting at the indicated cell, find the next selected cell.
|
|||
|
|
|||
|
@1
|
|||
|
MOVE.W maxIndex(A3),D4 ; get last one for quick checking
|
|||
|
@2
|
|||
|
TST.B cellArray(A3,D3) ; test selection bit
|
|||
|
BPL.S @3 ; => not selected, keep looking
|
|||
|
BSR IndexToCell
|
|||
|
MOVE.L D7,(A2) ; set new cell
|
|||
|
BRA.S @0 ; => and return true
|
|||
|
@3
|
|||
|
ADDQ #2,D3 ; point to next cell
|
|||
|
CMP.W D3,D4 ; done yet?
|
|||
|
BGE.S @2 ; <NGK 11-OCT-89> changed from BNE.S, missed last one
|
|||
|
LGSExit
|
|||
|
BRA Std10Exit
|
|||
|
|
|||
|
;---------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; FUNCTION ListNextCell (hNext,vNext: BOOLEAN; VAR c: Cell,h: ListHandle): BOOLEAN
|
|||
|
; 18 16 12 8 20
|
|||
|
; If HNext and VNext, then advance c to the next cell in the list.
|
|||
|
; If just hNext or just vNext, then advance c within the row or column.
|
|||
|
; If no next cell, return FALSE.
|
|||
|
|
|||
|
ListNextCell
|
|||
|
BSR StdEntry ; set up standard stuff
|
|||
|
MOVE.L D7,A2 ; get VAR pointer
|
|||
|
MOVE.L (A2),D7 ; get c in D7
|
|||
|
BSR MyFind ; check bounds on c
|
|||
|
BEQ.S @0 ; => out of bounds, return false
|
|||
|
TST.B 18(A6) ; hNext?
|
|||
|
BEQ.S @2 ; => no, just increment column
|
|||
|
ADDQ #1,D7 ; c.h = c.h + 1
|
|||
|
CMP.W databounds+right(A3),D7 ; still within dataBounds?
|
|||
|
BLT.S @1 ; => yes, return true
|
|||
|
MOVE.W databounds+left(A3),D7 ; else move to left of next row
|
|||
|
@2
|
|||
|
TST.B 16(A6) ; vNext?
|
|||
|
BEQ.S @0 ; => no, return false (note, c.h may be 0)
|
|||
|
SWAP D7 ; get c.v
|
|||
|
ADDQ #1,D7 ; go to next row
|
|||
|
CMP.W databounds+bottom(A3),D7 ; still within databounds?
|
|||
|
BLT.S @4 ; => yes
|
|||
|
SWAP D7 ; get D7 where it belongs
|
|||
|
@0
|
|||
|
CLR.W 20(A6) ; return false
|
|||
|
BRA @5 ; and current D7 as c
|
|||
|
@4
|
|||
|
SWAP D7
|
|||
|
@1
|
|||
|
MOVE.W #$0100,20(A6) ; return TRUE
|
|||
|
@5
|
|||
|
MOVE.L D7,(A2) ; return c
|
|||
|
BRA Std12Exit
|
|||
|
|
|||
|
|
|||
|
;------------------------------ Data Structure Routines --------------------------
|
|||
|
|
|||
|
; These are the routines that directly manipulate the data.
|
|||
|
|
|||
|
; A few comments and conventions:
|
|||
|
|
|||
|
; ListFind, called by every relevant routine, places the index into cellArray of
|
|||
|
; the current cell into index(A6). The data structure contains a value maxIndex
|
|||
|
; that is the index to the last element of cellArray, for convenient bounds checking.
|
|||
|
; This last element does not indicate a data element, it is used to calculate the
|
|||
|
; length of the last element as well as to detect the end of the array.
|
|||
|
|
|||
|
; For each element in the list, there is a 2 byte field in the cellArray. The high bit
|
|||
|
; of the field indicates whether or not the cell is selected. The remaining 15 bits are
|
|||
|
; the offset into the cell data structure of the beginning of that element. The length
|
|||
|
; of an element is calculated by subtracting the offset to the next element in the array
|
|||
|
; from the offset of the current element.
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListFind( VAR offset, len: Integer; c: Cell; h: ListHandle );
|
|||
|
; 20 16 12 8
|
|||
|
; Given a cell coordinate, returns the offset to the data part of that cell (just
|
|||
|
; past the length for that cell), and the length for that cell. If the cell c is
|
|||
|
; not within bounds, offset and len are set to -1.
|
|||
|
|
|||
|
ListFind
|
|||
|
BSR StdEntry ; set up standard stuff
|
|||
|
BSR.S LFind2 ; call shared listFind code
|
|||
|
TST.B D4 ; was the cell valid?
|
|||
|
BNE.S @1 ; => yes, return our data
|
|||
|
MOVEQ #-1,D6 ; else len = -1
|
|||
|
MOVEQ #-1,D5 ; and offset = -1
|
|||
|
@1
|
|||
|
MOVE.L 16(A6),A1 ; set VAR len
|
|||
|
MOVE.W D6,(A1)
|
|||
|
MOVE.L 20(A6),A1 ; set VAR offset
|
|||
|
MOVE.W D5,(A1)
|
|||
|
Std16Exit
|
|||
|
MOVEQ #16,D0
|
|||
|
BRA StdExit ; restore regs, unlink, strip params...
|
|||
|
|
|||
|
;------------
|
|||
|
; MyFind -- This routine is used internally to validate the cell that is in D7.
|
|||
|
; It assumes that StdEntry has already been called to set things up.
|
|||
|
; GoodCell indicates the cell’s validity; len, offset and index are set.
|
|||
|
|
|||
|
MyFind
|
|||
|
MOVEM.L D1-D7/A1-A4,-(SP) ; save em all
|
|||
|
BSR LFind2 ; call ListFind
|
|||
|
MOVE.W D6,len(A6) ; return length of chosen cell
|
|||
|
MOVE.W D5,offset(A6) ; return offset to chosen cell
|
|||
|
MOVE.W D3,index(A6) ; set index of cell
|
|||
|
MOVE.B D4,goodCell(A6) ; set cc’s
|
|||
|
MOVEM.L (SP)+,D1-D7/A1-A4 ; and fix ’em up
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; LFind2 is used by ListFind and MyFind
|
|||
|
|
|||
|
LFind2
|
|||
|
|
|||
|
; Len is left in D6 and offset in D5. D4 is 0 if the cell was invalid.
|
|||
|
|
|||
|
MOVEQ #0,D5 ; save offset in D5
|
|||
|
MOVEQ #0,D6 ; save len in D6
|
|||
|
|
|||
|
; set D4 true if the cell is a valid, otherwise false
|
|||
|
|
|||
|
SUBQ #2,SP ; check if c param ok
|
|||
|
MOVE.L D7,-(SP)
|
|||
|
PEA dataBounds(A3)
|
|||
|
_PtInRect
|
|||
|
MOVE.B (SP)+,D4 ; remember result in D4
|
|||
|
BEQ.S findExit
|
|||
|
|
|||
|
; find the correct cell
|
|||
|
|
|||
|
BSR.S CellToIndex ; cell in D7 -> index in D3
|
|||
|
MiniFind ; used by search
|
|||
|
LEA cellArray(A3,D3),A0 ; get pointer to offset
|
|||
|
MOVE.W (A0)+,D5 ; get offset to current cell
|
|||
|
AND.W #$7FFF,D5 ; minus the select bit
|
|||
|
MOVE.W (A0),D6 ; get offset to next cell
|
|||
|
AND.W #$7FFF,D6 ; minus the select bit
|
|||
|
SUB.W D5,D6 ; get the length
|
|||
|
findExit ; index is in D3
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; CellToIndex
|
|||
|
; Given a cell number in D7, this routine returns in D0 the offset
|
|||
|
; into cellArray of that cell. Leaves D7 intact.
|
|||
|
|
|||
|
CellToIndex
|
|||
|
SWAP D7 ; c.v in low word
|
|||
|
MOVE.W dataBounds+right(A3),D3 ; index := c.v * rowLen + c.h
|
|||
|
SUB.W dataBounds+left(A3),D3
|
|||
|
MULU D7,D3
|
|||
|
SWAP D7
|
|||
|
ADD.W D7,D3 ; got cell number
|
|||
|
LSL.W #1,D3 ; get index into D3
|
|||
|
RTS
|
|||
|
|
|||
|
;------------
|
|||
|
; IndexToCell
|
|||
|
; Given an offset into the cellArray in D3, this routine returns in D7
|
|||
|
; the cell that has that index. Leaves D3 intact.
|
|||
|
|
|||
|
IndexToCell
|
|||
|
MOVE.L D1,-(SP) ; save D1
|
|||
|
MOVE.W D3,D7
|
|||
|
EXT.L D7 ; make it a long
|
|||
|
BEQ.S @1 ; offset is 0 => cell is 0
|
|||
|
LSR.L #1,D7 ; make it a simple index
|
|||
|
MOVE.W dataBounds+right(A3),D1 ; get right
|
|||
|
SUB.W dataBounds+left(A3),D1 ; get row width
|
|||
|
DIVU D1,D7 ; get number of columns
|
|||
|
SWAP D7 ; high, remainder is rows
|
|||
|
@1
|
|||
|
MOVE.L (SP)+,D1 ; restore D1
|
|||
|
RTS
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListClrCell( c: Cell; h: ListHandle );
|
|||
|
;
|
|||
|
; Deletes the given cell from the given list
|
|||
|
; Sets up stack to make a ListSetCell call with NIL string.
|
|||
|
;
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
ListClrCell
|
|||
|
|
|||
|
; pull off return address, our params, push on p and l for SetCell, put ours back
|
|||
|
; note: lock state of pack is in D1, don’t use D1
|
|||
|
|
|||
|
MOVEM.L (SP)+,D0/D2/A0 ; get RTS, handle, cell
|
|||
|
CLR.L -(SP) ; push p = NIL
|
|||
|
CLR.W -(SP) ; push l = 0
|
|||
|
MOVEM.L A0/D2/D0,-(SP) ; restore cell, handle, RTS
|
|||
|
|
|||
|
; and fall into a more macho routine...
|
|||
|
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListSetCell ( p: Ptr; l: INTEGER; c: Cell; h: ListHandle );
|
|||
|
; 18 16 12 8
|
|||
|
; ListSetCell Replaces the current contents of the cell c with the l bytes
|
|||
|
; of data pointed to by p. If p is NIL and l is 0, this is the same as
|
|||
|
; ListClrCell.
|
|||
|
;
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListSetCell
|
|||
|
BSR StdEntry ; ho hum again
|
|||
|
BSR MyFind ; validate cell, set things up
|
|||
|
BEQ std14Exit ; skip if bad cell
|
|||
|
|
|||
|
MOVE.W len(A6),D6 ; get the current length
|
|||
|
MOVE.W 16(A6),D5 ; get the new length
|
|||
|
|
|||
|
; *** need to verify that data will fit?
|
|||
|
|
|||
|
SUBQ #4,SP ; munge out the field
|
|||
|
MOVE.L cells(A3),-(SP) ; here’s the data handle
|
|||
|
MOVE.W offset(A6),-(SP) ; pass offset
|
|||
|
CLR.W -(SP) ; which must be long
|
|||
|
CLR.L -(SP)
|
|||
|
MOVE.W D6,-(SP) ; pass length
|
|||
|
CLR.W -(SP) ; which must be long
|
|||
|
MOVE.L 18(A6),-(SP) ; pass in this string
|
|||
|
MOVE.W D5,-(SP) ; with this length
|
|||
|
CLR.W -(SP) ; which must be long
|
|||
|
_Munger
|
|||
|
; *** test result of Munger here (in D0.W)
|
|||
|
ADDQ #4,SP ; dump result
|
|||
|
|
|||
|
SUB.W D6,D5 ; get delta for subsequent elements
|
|||
|
BRA.S CellShare ; share common exit
|
|||
|
|
|||
|
;----------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListAddtoCell( p: Ptr; l: INTEGER; c: Point; h: ListHandle );
|
|||
|
; 18 16 12 8
|
|||
|
; Appends l bytes of data starting at p to the cell c in list h.
|
|||
|
;----------------------------------------------------------------------
|
|||
|
|
|||
|
ListAddtoCell
|
|||
|
BSR StdEntry ; ho hum
|
|||
|
BSR MyFind ; validate the cell
|
|||
|
BEQ.S std14Exit ; skip if bad cell
|
|||
|
MOVE.W 16(A6),D5 ; get new length into D5
|
|||
|
BEQ.S std14Exit ; => nothing to add
|
|||
|
|
|||
|
; *** need to verify that data will fit?
|
|||
|
|
|||
|
SUBQ #4,SP ; go munge it in
|
|||
|
MOVE.L cells(A3),-(SP) ; pass the data handle
|
|||
|
MOVEQ #0,D0 ; Munger needs a long offset
|
|||
|
MOVE.W offset(A6),D0 ; add offset + length
|
|||
|
ADD.W len(A6),D0
|
|||
|
MOVE.L D0,-(SP) ; insert at the end
|
|||
|
CLR.L -(SP) ; NIL for p1
|
|||
|
CLR.L -(SP) ; zero length1
|
|||
|
MOVE.L 18(A6),-(SP) ; pass pointer
|
|||
|
MOVE.W D5,-(SP) ; low length word
|
|||
|
CLR.W -(SP) ; high length word
|
|||
|
_Munger
|
|||
|
ADDQ #4,SP ; ignore reply
|
|||
|
cellShare
|
|||
|
MOVE.W D5,D0 ; get length into D0
|
|||
|
BSR.S FixOffsets ; and adjust other cells
|
|||
|
|
|||
|
BSR DoDraw ; and draw cell in D7
|
|||
|
|
|||
|
Std14Exit
|
|||
|
MOVEQ #14,D0
|
|||
|
BRA StdExit
|
|||
|
|
|||
|
RTS ; and exit
|
|||
|
|
|||
|
;------------
|
|||
|
; FixOffsets
|
|||
|
; This is a register based routine that takes a word length offset in D0.
|
|||
|
; D0 is added to each element in the cellArray from index+1 to the end.
|
|||
|
; Trashes D1, A0, and A1
|
|||
|
|
|||
|
FixOffsets
|
|||
|
TST.W D0 ; if 0, nothing to do
|
|||
|
BEQ.S @2 ; => yippee! saved us some work
|
|||
|
|
|||
|
MOVE.W maxIndex(A3),D1 ; get pointer past end of array in A1
|
|||
|
LEA cellArray(A3,D1),A1 ; stop after updating this one
|
|||
|
|
|||
|
MOVE.W index(A6),D1 ; get index into D2
|
|||
|
LEA cellArray+2(A3,D1),A0 ; index+1 is the first one to do
|
|||
|
@1
|
|||
|
ADD.W D0,(A0)+ ; add offset to it
|
|||
|
CMP.L A1,A0 ; done yet?
|
|||
|
BLE.S @1
|
|||
|
@2
|
|||
|
RTS
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE ListGetCell ( p: Ptr; VAR l: INTEGER; c: Cell; h: ListHandle );
|
|||
|
; 20 16 12 8
|
|||
|
; ListGetCell returns in p the data associated with the cell c. If the data
|
|||
|
; is longer than l, only l bytes are returned. If the data is shorter than l,
|
|||
|
; l is set to the new length.
|
|||
|
;
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
ListGetCell
|
|||
|
BSR StdEntry ; oh muh!
|
|||
|
BSR MyFind ; validate cell
|
|||
|
BEQ.S @2 ; => cell no good, just return
|
|||
|
|
|||
|
MOVE.L 16(A6),A0 ; get pointer to length
|
|||
|
MOVE.W len(A6),D0
|
|||
|
CMP.W (A0),D0 ; is len < l?
|
|||
|
BGE.S @1
|
|||
|
MOVE.W D0,(A0) ; yes, return new length
|
|||
|
@1
|
|||
|
MOVE.W (A0),D0 ; get count in D0
|
|||
|
BEQ.S @2 ; => no data to move
|
|||
|
SUBQ #2,SP ; make room for result
|
|||
|
EXT.L D0 ; make it long
|
|||
|
MOVE.L cells(A3),A0 ; get data handle
|
|||
|
MOVE.L (A0),A0 ; get data pointer
|
|||
|
ADD.W offset(A6),A0 ; bump it to our cell
|
|||
|
MOVE.L 20(A6),A1 ; get destination pointer
|
|||
|
_BlockMove
|
|||
|
ADDQ #2,SP ; ignore result ***
|
|||
|
@2
|
|||
|
BRA Std16Exit
|
|||
|
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; FUNCTION ListSearch ( p: Ptr; l: INTEGER; MyProc: Ptr; VAR c: Cell; h: ListHandle): BOOLEAN;
|
|||
|
; 22 20 16 12 8 26
|
|||
|
; ListSearch searches through the data, one cell at a time, beginning with cell c, for a
|
|||
|
; cell that contains data that matches the data in p with length l (according to the
|
|||
|
; definition of matching kindly provided by IUMagIDString). If a matching cell is found,
|
|||
|
; TRUE is returned, and c is set to that cell. If no matching cell is found, or the
|
|||
|
; supplied starting cell is out of bounds, the result is set to FALSE, and the returned
|
|||
|
; cell is invalid.
|
|||
|
;
|
|||
|
; If MyProc is non-zero, it is called in place of IUMagIDString, with the same parameters:
|
|||
|
; MyProc(aPtr,bPtr: Pointer; aLen,bLen: INTEGER): INTEGER;
|
|||
|
; We depend on the user to preserve registers D3-D7 and A2-A7!!.
|
|||
|
;-------------------------------------------------------------------------------
|
|||
|
|
|||
|
ListSearch
|
|||
|
BSR StdEntry
|
|||
|
MOVE.W #$0100,26(A6) ; assume cell is found
|
|||
|
MOVE.L D7,A2 ; get address of cell
|
|||
|
MOVE.L (A2),D7 ; get cell, save address in A2
|
|||
|
|
|||
|
MOVE.L IntUtilHandle,A0 ; get the handle into A0
|
|||
|
_HGetState ; D0 := current lock, etc. state<S3>
|
|||
|
MOVE.B D0,-(SP) ; save status on stack <S3>
|
|||
|
_HLock ; lock down the package
|
|||
|
|
|||
|
MOVE.L cells(A3),A0 ; get handle to data
|
|||
|
_HGetState ; D0 := current lock, etc. state<S3>
|
|||
|
MOVE.B D0,-(SP) ; save status on stack <S3>
|
|||
|
_HLock ; and lock down the data
|
|||
|
|
|||
|
MOVE.W maxIndex(A3),D4 ; get terminator in D4
|
|||
|
BSR CellToIndex ; cell in D7 -> index in D3
|
|||
|
|
|||
|
BSR MyFind ; bounds-check cell in D7
|
|||
|
BEQ.S NoMatch ; => cell not valid, pattern not found
|
|||
|
LookAtNext
|
|||
|
BSR MiniFind ; index in D3 -> D5 = offset, D6 = len
|
|||
|
|
|||
|
MOVE.L D3,-(SP) ; because Jerome doesn’t want to save it
|
|||
|
SUBQ #2,SP ; make room for integer result
|
|||
|
MOVE.L cells(A3),A0 ; get handle to data
|
|||
|
MOVE.L (A0),A0 ; get pointer to data
|
|||
|
ADD.W D5,A0 ; get pointer to current cell
|
|||
|
MOVE.L A0,-(SP) ; push pointer to cell data
|
|||
|
MOVE.L 22(A6),-(SP) ; this is the data to find
|
|||
|
MOVE.W D6,-(SP) ; and cell length
|
|||
|
MOVE.W 20(A6),-(SP) ; and pass the data length
|
|||
|
|
|||
|
MOVE.L 16(A6),D2 ; get routine and test
|
|||
|
BEQ.S @1 ; => no routine
|
|||
|
MOVE.L D2,A0 ; call user’s routine
|
|||
|
JSR (A0) ; with same params as IUMagIDString
|
|||
|
|
|||
|
; NOTE: We count on the user’s preserving the standard registers (D3-D7,A2-A7) !
|
|||
|
|
|||
|
BRA.S @2
|
|||
|
@1
|
|||
|
_IUMagIDString
|
|||
|
@2
|
|||
|
MOVE.W (SP)+,D0 ; get result
|
|||
|
MOVE.L (SP)+,D3 ; harrumph
|
|||
|
TST.W D0
|
|||
|
BEQ.S GotAMatch ; => we found it
|
|||
|
|
|||
|
ADDQ.W #2,D3 ; spin that odometer
|
|||
|
CMP.W D4,D3 ; done scanning yet?
|
|||
|
BLT.S LookAtNext ; => nope, do next string
|
|||
|
NoMatch
|
|||
|
CLR.W 26(A6) ; no match -> return false
|
|||
|
GotAMatch
|
|||
|
|
|||
|
; get cell to return. If no match, cell is invalid
|
|||
|
|
|||
|
BSR IndexToCell ; index in D3 -> cell in D7
|
|||
|
MOVE.L D7,(A2) ; return "new" cell
|
|||
|
|
|||
|
MOVE.L cells(A3),A0 ; get handle to data
|
|||
|
MOVE.B (SP)+,D0 ; saved lock state <S3>
|
|||
|
_HSetState ; restore to handle <S3>
|
|||
|
|
|||
|
MOVE.L IntUtilHandle,A0 ; get handle to package
|
|||
|
MOVE.B (SP)+,D0 ; saved lock state <S3>
|
|||
|
_HSetState ; restore to handle <S3>
|
|||
|
|
|||
|
MOVEQ #18,D0
|
|||
|
BRA StdExit ; strip of 18 bytes of parameters
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|
|||
|
END
|