NetBoot/BootPicker.a
2021-02-08 16:02:04 +08:00

340 lines
8.4 KiB
Plaintext

; Input appended to this code:
; [4 arbitrary bytes] [byte-prefixed pstring] [padding to even byte] ... [4 bytes] [zero byte]
; Outputs: D0 = index of selected string, Ao = pointer to selected string
_BoundaryLabelAtStartOfBootPicker_
; Aesthetic parameters
.kMinWid equ 70 ; min width to leave for button label
.kBtnHt equ 20 ; should always be 20 because text won't move
.kBtnGap equ 13
.kPadX equ 5+26 ; due to border, padding=6 would leave 1 white pixel
.kPadY equ 5+13
; Save all the stuff that we whack
movem.l A1-A5/D1-D7,-(SP)
move.l $3F8,-(SP) ; Save DSAlertRect
move.l $3F8+4,-(SP)
move.l $9CE,-(SP) ; Save ToolScratch
move.l $9CE+4,-(SP)
move.l $2BA,-(SP) ; Save DSAlertTab
move.l $A8C,-(SP) ; Save RestProc
move.l $120,-(SP) ; Save MacJmp
move.b $BFF,-(SP) ; Save MacJmpFlag (32-bit only)
link.w A6,#0 ; We use a lot of stack
; Head-patch _PtInRect to account for our unusual window placement
move.w #$A8AD,D0 ; _PtInRect
dc.w $A146 ; _GetTrapAddress
move.l A0,$9CE+4 ; Save in ToolScratch+4 to enable head-patch
move.w #$A8AD,D0 ; _PtInRect
lea .MyPtInRect,A0
dc.w $A047 ; _SetTrapAddress
; Do the usual "QuickDraw outside of application" setup
clr.l -(SP)
move.l SP,A5 ; tiny A5 world with QD globals ptr
lea -206(SP),SP ; push the QD globals
pea 202(SP)
dc.w $A86E ; _InitGraf
dc.w $A8FE ; _InitFonts (because we use _StringWidth)
lea -108(SP),SP
pea (SP)
dc.w $A86F ; _OpenPort (don't save, we have our own globs)
; Copy a stub alert table to the stack
move.l #.MyDSAlertTabEnd-.MyDSAlertTabStart,D0
sub.l D0,SP
move.l SP,A1
lea .MyDSAlertTabStart,A0
dc.w $A22E ; _BlockMoveData
; First pass: calculate box width, putting shortest string width into D5
moveq.l #.kMinWid,D5
bsr .GetA0 ; A0 = current pstring ptr
.dswLoop
tst.b (A0)
beq.s .dswDone
move.l A0,-(SP)
clr.w -(SP)
move.l A0,-(SP)
dc.w $A88C ; _StringWidth
move.w (SP)+,D0
addq.w #8,D0
cmp.w D0,D5
bgt.s .notlargest
move.w D0,D5
.notlargest
move.l (SP)+,A0
bsr .AdvanceA0
bra.s .dswLoop
.dswDone
; Second pass: create a button list object in the DS alert table
move.w (SP)+,D7 ; pop NumEntries from DS table
move.l #((.kPadY)<<16)|(.kPadX),D2 ; D2 = current button's topleft
move.l #((.kPadY+.kBtnHt)<<16)|(.kPadX+4+4),D3; D3 = current button's botright
add.w D5,D3 ; ...including width of the text
moveq.l #0,D6 ; D6 = button counter
bsr .GetA0 ; A0 = current pstring ptr
.dsbLoop
tst.b (A0)
beq.s .dsbDone
move.w D6,-(SP) ; push procedure object ID (base $8000)
add.w #$8000,(SP)
move.l D3,-(SP) ; push botright
move.l D2,-(SP) ; push topleft
move.w D6,-(SP) ; push string object ID (base $C000)
add.w #$C000,(SP)
; increment...
add.l #(.kBtnHt+.kBtnGap)<<16,D2 ; the button's top edge
add.l #(.kBtnHt+.kBtnGap)<<16,D3 ; the button's bottom edge
addq.w #1,D6 ; the button counter
bsr .AdvanceA0
bra.s .dsbLoop
.dsbDone ; done looping, push a header for this object...
move.w D6,-(SP) ; the number of buttons
mulu #12,D6 ; the size in bytes = 12n+2
add.w #2,D6
move.w D6,-(SP)
move.w #$1993,-(SP) ; the unique ID for this button list
addq.w #1,D7
move.w D7,-(SP) ; increment and re-push NumEntries
; Third pass: calculate box height
lea $3F8,A1 ; A0 = DSAlertRect
move.l (A5),A0 ; From QD globals
move.l -122+6+4(A0),D0 ; D0 = screenBits.bounds.botRight, so D0.W = screen width
add.w #.kPadX,D3 ; D3 = box width
sub.w D3,D0
bgt.s .nottoowide
clr.w D0
.nottoowide
asr.w #1,D0
move.w D0,2(A1) ; set DSAlertRect left
move.w D0,$9CE+2 ; & stash in ToolScratch for .MyPtInRect
add.w D3,D0
move.w D0,6(A1) ; set DSAlertRect right
swap D0 ; D0 = screen height
swap D2 ; D2 = box height ("top" of next button)
add.w #.kPadY-.kBtnGap,D2 ; adjust box height
sub.w D2,D0
bgt.s .nottoohigh
clr.w D0
.nottoohigh
asr.w #1,D0
move.w D0,(A1) ; set DSAlertRect top
move.w D0,$9CE ; & stash in ToolScratch for .MyPtInRect
add.w D2,D0
move.w D0,4(A1) ; set DSAlertRect bottom
; Fourth pass: create a string offset for each button
moveq.l #0,D6 ; D6 = button counter
bsr .GetA0 ; A0 = current pstring ptr
.dssLoop
tst.b (A0)
beq.s .dssDone
move.w (SP)+,D7 ; pop NumEntries from DS table
; push the struct fields...
bsr .PushPaddedString ; even-length string with 2-byte length
move.w D6,-(SP) ; the unique ID (C000+n)
add.w #$C000,(SP)
addq.w #1,D7
move.w D7,-(SP) ; increment and re-push NumEntries
; increment...
addq.w #1,D6 ; the button counter
bsr .AdvanceA0
bra.s .dssLoop
.dssDone
; Fifth pass: generate code for each button
moveq.l #0,D6 ; D6 = button counter
bsr .GetA0 ; A0 = current pstring ptr
.dspLoop
tst.b (A0)
beq.s .dspDone
move.w (SP)+,D7 ; pop NumEntries from DS table
pea .ReturnToCaller ; craft the code for this button...
move.w #$4EF9,-(SP) ; jmp .ReturnToCaller (absolute addr)
move.l A6,-(SP)
move.w #$2C7C,-(SP) ; move.l #CorrectA6,A6 ; frame ptr
move.l A0,-(SP)
move.w #$207C,-(SP) ; move.l #CorrectA0,A0 ; return string ptr
move.l D6,-(SP)
move.w #$203C,-(SP) ; move.l #CorrectD0,D0 ; return string idx
; push a header...
move.w #24,-(SP) ; the size in bytes of the above code
move.w D6,-(SP) ; the unique ID (8000+n)
add.w #$8000,(SP)
addq.w #1,D7
move.w D7,-(SP) ; increment and re-push NumEntries
; increment...
addq.w #1,D6 ; the button counter
bsr .AdvanceA0
bra.s .dspLoop
.dspDone ; Must clear the instruction cache on 030/040
move.l A6,D0
sub.l SP,D0
move.l SP,A0
move.l SP,A1
dc.w $A02E ; using non-Data _BlockMove
; Put up the DeepShit alert
move.l SP,$2BA ; Set DSAlertTab
clr.l $A8C ; Clear RestProc or our buttons get jumbled
move.w #$2012,D0 ; Our error object number
dc.w $A9C9 ; _SysError!
bra.s * ; Should never return
; The selected procedure will jump to here after setting A6,A0,D0
.ReturnToCaller
movem.l A0/D0,-(SP) ; save/restore our return values
move.l (A5),A0 ; Open a new whole-screen port
move.l (A0),-(SP)
dc.w $A86F ; _OpenPort
pea $3F8 ; DSAlertRect
move.l (A5),A0 ;
pea -24(A0) ; qd.gray
dc.w $A8A5 ; _FillRect
move.w #$A8AD,D0 ; Unpatch _PtInRect
move.l $9CE+4,A0 ; We saved it in ToolScratch
dc.w $A047 ; _SetTrapAddress
movem.l (SP)+,A0/D0
unlk A6 ; See the saving code for details
move.b (SP)+,$BFF
move.l (SP)+,$120
move.l (SP)+,$A8C
move.l (SP)+,$2BA
move.l (SP)+,$9CE+4
move.l (SP)+,$9CE
move.l (SP)+,$3F8+4
move.l (SP)+,$3F8
move.l #-1,$14A
movem.l (SP)+,A1-A5/D1-D7
rts
.PushPaddedString ; trashes A1-A2,D0-D2, but must preserve A0
move.l (SP)+,A2
move.l A0,-(SP) ; backup
moveq.l #0,D0
clr.w -(SP)
move.l A0,-(SP)
dc.w $A88C ; _StringWidth
move.w D5,D0
sub.w (SP)+,D0
bgt.s .notzero
moveq.l #0,D0
.notzero
asr.w #3,D0 ; divide the leftover by twice a Chicago space
move.l (SP)+,A0 ; restore backup
clr.w D1
move.b D0,D1
add.b (A0),D1
addq.b #1,D1
bclr #0,D1 ; this is the spaced-out length in memory
clr.w D2
.spaceloop
cmp.w D2,D1
beq.s .spacedone
move.w #$2020,-(SP)
addq.w #2,D2
bra.s .spaceloop
.spacedone
move.w D1,-(SP)
lea 2(SP),A1 ; bm dest
add.w D0,A1
clr.l D0
move.b (A0),D0
move.l A0,-(SP)
addq.l #1,A0 ; bm src
dc.w $A22E ; _BlockMoveData
move.l (SP)+,A0
jmp (A2)
.MyPtInRect
move.l $9CE,D0
sub.w D0,10(SP)
swap D0
sub.w D0,8(SP)
move.l $9CE+4,A0
jmp (A0)
.GetA0
lea .TrailingList+4,A0
rts
.AdvanceA0
moveq.l #1,D0
add.b (A0),D0
add.l D0,A0
and.l #1,D0 ; align to 2-byte boundary
add.l D0,A0
lea 4(A0),A0 ; skip the 4-byte header
rts
.MyDSAlertTabStart
dc.w 1 ; NumEntries
; Our only alert definition
dc.w $2012 ; ID of this error
dc.w 10 ; length of remaining items
dc.w 0 ; primary text definition ID
dc.w 0 ; secondary text definition ID
dc.w 0 ; icon definition ID
dc.w 0 ; procedure definition ID
dc.w $1993 ; button definition ID
.MyDSAlertTabEnd
.TrailingList
_BoundaryLabelAtEndOfBootPicker_