; 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_