mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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
|