; tld_stuff.i   Version 1.00   10th February, 2002

*>>************************************************************************
*
*   Subroutines to draw boxes and areas
*   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*   TLDWindow   intialise wint to current window size
*   TLDBox      draw a bevelled box
*   TLDArea     draw an area
*   TLDButtons  draw a set of buttons (bevelled boxes with unicode)
*   TLDMouse    make mouse rel to wbox
*   TLDButmon   see if IntuiMessage is in a button
*   TLDShow     draw strings in a window, monitor its vertical scroller
*   TLDMakeback make a backup rastport
*   TLDBackup   backup from rastport
*   TLDRestore  restore to rastport
*   TLDFreeback free the rastport made by TLDMakeback
*   TLDBusy     make pointer busy
*   TLDUnbusy   make pointer unbusy
*   TLDInput    get text (not written yet)
*
***************************************************************************


 IFND TLD_Stuff


TLD_Stuff: SET 1


*>> initialise wint to current window interior

; a0 = window
; a1 = pointer to 8 bytes, to make into wint

; initilises (a1) to current window interior
;            (a2) to 0,0,10000,10000 (i.e. entire window)

TLDWindow:
 movem.l d0-d1,-(a7)       ;saves all

 moveq #0,d0
 move.b wd_BorderLeft(a0),d0
 move.w d0,(a1)
 add.b wd_BorderRight(a0),d0
 move.w wd_Width(a0),d1
 sub.w d0,d1
 move.w d1,4(a1)
 move.b wd_BorderTop(a0),d0
 move.w d0,2(a1)
 add.b wd_BorderBottom(a0),d0
 move.w wd_Height(a0),d1
 sub.w d0,d1
 move.w d1,6(a1)

 movem.l (a7)+,d0-d1
 rts


*>> draw a bevelled box

; d0-d3 = region
; d4    = dark pen    } swap for reverse bevel
; d5    = light pen   } both same for unbevelled box
; a0    = rastport
; a1    = wint
; a2    = wbox
; a6    = graphics.library base

TLDBox:
 movem.l d0-d7/a0-a6,-(a7)
 subq.l #8,a7

 move.l a7,a3              ;trim to the wint - a3 = clipping box
 bsr TLDTrim
 beq .done                 ;go if trimed right off

 move.l a0,a5              ;a5 = rastport
 move.l a3,a2              ;a2 = clipping box
 move.l d0,d6              ;cache d0,d1 in d6,d7
 move.l d1,d7

 cmp.b rp_FgPen(a5),d5     ;set fpen to light pen
 beq.s .mode
 move.l d5,d0
 move.l a5,a1
 jsr _LVOSetAPen(a6)
.mode:
 cmp.b #RP_JAM2,rp_DrawMode(a1) ;if drmode <> jam2, set drmode
 beq.s .draw
 move.l a5,a1
 moveq #RP_JAM2,d0
 jsr _LVOSetDrMd(a6)

.draw:                     ;top light
 tst.w 2(a2)
 bne.s .2                  ;not if top disp > 0
 move.l d6,d0
 move.l d7,d1
 move.l a5,a1
 jsr _LVOMove(a6)          ;from x1,y1
 move.l d6,d0
 add.w d2,d0
 subq.w #1,d0
 move.l d7,d1              ;to x2,y1 if rhs disp > 0
 tst.w 4(a2)
 bne.s .1b                 ;not if rhs disp = 0 and width = 1
 cmp.w #1,d2
 beq.s .2
 subq.w #1,d0              ;to x2-1,y1 if rhs disp = 0
.1b:
 move.l a5,a1
 jsr _LVODraw(a6)

.2:                        ;inner left light
 move.l d6,d0
 cmp.w #1,(a2)             ;not if left disp > 1
 bhi.s .4
 beq.s .2a                 ;not if left disp = 0 and width = 1
 cmp.w #1,d2
 beq.s .3                  ;xpos = x1 if left disp = 1
 addq.w #1,d0              ;xpos = x1+1 if left disp = 0
.2a:
 move.l d7,d1
 tst.w 2(a2)               ;from x1[+1], y1 if top disp > 0
 bne.s .2b
 cmp.w #1,d3               ;not if top disp = 0 and height = 1
 beq.s .3
 addq.w #1,d1              ;from x1[+1], y1+1 if top disp = 0
.2b:
 move.l a5,a1
 move.l d0,a4
 jsr _LVOMove(a6)
 move.l a4,d0              ;to x1[+1], y2 if bot disp > 0
 move.l d7,d1
 add.w d3,d1
 subq.w #1,d1
 tst.w 6(a2)               ;not if bot disp = 0 and height = 1
 bne.s .2c
 cmp.w #1,d3               ;to x1[+1], y2-1 if bot disp = 0
 beq.s .3
 subq.w #1,d1
.2c:
 move.l a5,a1
 jsr _LVODraw(a6)

.3:                        ;outer left light
 tst.w (a2)
 bne.s .4                  ;not if left disp > 0
 move.w d6,d0
 move.w d7,d1              ;from x1, x1
 move.l a5,a1
 jsr _LVOMove(a6)
 move.l d6,d0              ;to x1, y2
 move.l d7,d1
 add.w d3,d1
 subq.w #1,d1
 move.l a5,a1
 jsr _LVODraw(a6)

.4:                        ;to dark pen unless already set
 cmp.b rp_FgPen(a5),d4
 beq.s .5
 move.l d4,d0
 move.l a5,a1
 jsr _LVOSetAPen(a6)

.5:                        ;bottom dark
 tst.w 6(a2)
 bne.s .6                  ;not if bot disp > 0
 move.l d6,d0
 tst.w (a2)
 bne.s .5a
 cmp.w #1,d2               ;from x1, y2 if lhs disp > 0
 beq.s .6
 addq.w #1,d0              ;not if lhs disp = 0 and width = 1
.5a:
 move.l d7,d1
 add.w d3,d1
 subq.w #1,d1
 move.l a5,a1
 jsr _LVOMove(a6)
 move.l d6,d0              ;to x2, y2
 add.w d2,d0
 subq.w #1,d0
 move.l d7,d1
 add.w d3,d1
 subq.w #1,d1
 move.l a5,a1
 jsr _LVODraw(a6)

.6:                        ;inner right dark
 move.l d6,d0
 add.w d2,d0
 subq.w #1,d0              ;not if rhs disp > 1
 cmp.w #1,4(a2)
 bhi.s .done               ;not if rhs disp = 0 and width = 1
 beq.s .6a
 cmp.w #1,d2               ;xpos = x2 if rhs disp = 1
 beq.s .7
 subq.w #1,d0              ;xpos = x2-1 if rhs disp = 0
.6a:
 move.l d7,d1              ;from x2[-1], y1 if bot disp <> 0
 tst.w 2(a2)
 bne.s .6b                 ;not if top disp = 0 and height = 1
 cmp.w #1,d3
 beq.s .7                  ;from x2[-1], y1+1 if bot disp = 0
 addq.w #1,d1
.6b:
 move.l a5,a1
 move.l d0,a4
 jsr _LVOMove(a6)
 move.l a4,d0
 move.l d7,d1
 add.w d3,d1               ;to x2[-1], y2 if bot disp <> 0
 subq.w #1,d1
 tst.w 6(a2)               ;not if bot disp = 0 and height = 1
 bne.s .6c
 cmp.w #1,d3               ;from x2[-1], y2-1 if bot disp = 0
 beq.s .7
 subq.w #1,d1
.6c:
 move.l a5,a1
 jsr _LVODraw(a6)

.7:                        ;outer right dark
 tst.w 4(a2)
 bne.s .done               ;not if rhs disp > 0
 move.l d6,d0
 add.w d2,d0
 subq.w #1,d0
 move.l d7,d1              ;from x2, y1
 move.l a5,a1
 jsr _LVOMove(a6)          ;to x2,y2
 move.l d6,d0
 add.w d2,d0
 subq.w #1,d0
 move.l d7,d1
 add.w d3,d1
 subq.w #1,d1
 move.l a5,a1
 jsr _LVODraw(a6)

.done:
 addq.l #8,a7
 movem.l (a7)+,d0-d7/a0-a6
 rts


*>> draw an area

; d0-d3 = rectangle
; d4    = pen
; a0    = rastport
; a1    = wint
; a2    = wbox
; a6    = graphics.library base

TLDArea:
 movem.l d0-d3/a0-a3,-(a7) ;save all
 subq.l #8,a7              ;room for clipping rect

 move.l a7,a3              ;clip d0-d3 to wint
 bsr TLDTrim
 beq.s .done               ;go if rect entirely off wint

 move.l a0,a1
 movem.l d0-d1/a1,-(a7)

 cmp.b rp_FgPen(a1),d4     ;if fpen <> d4, set fpen
 beq.s .mode
 move.l d4,d0
 jsr _LVOSetAPen(a6)
 move.l 8(a7),a1
.mode:
 cmp.b #RP_JAM2,rp_DrawMode(a1) ;if drmodw <> jam2, set drmode
 beq.s .draw
 moveq #RP_JAM2,d0
 jsr _LVOSetDrMd(a6)

.draw:
 movem.l (a7)+,d0-d1/a1

 add.w d0,d2               ;set d2,d3 = xmax,ymax
 subq.w #1,d2
 add.w d1,d3
 subq.w #1,d3
 jsr _LVORectFill(a6)      ;blit the rectangle

.done:
 addq.l #8,a7
 movem.l (a7)+,d0-d3/a0-a3
 rts



*>> draw a matrix of "buttons" (i.e. bevelled boxes with text)

; d0-d3 = area where buttons drawn
; d4    = box dark pen
; d5    = box light pen
; d6    = bits 0-7   text fgpen
;         bits 8-15  0, or if 1+ box to hilight
;         bits 16-23 text bgpen
;         bits 24-31 hilight pen
; d7    = bits 0-7   rows
;              16-23 columns
; a0    = rastport
; a1    = wint
; a2    = wbox
; a3    = strings: as many null delimited strings as rows * cols, col by col
;         in TLUstring ASCII + &...; format
;         null strings ($00 only) drawn inactive ($20,$00 for blank active)
; a5    = ucode_path
; a6    = ucode.library base

; Caution: if a string is too high/wide for one of the buttons, it will
; lap the bottom/right of the box (but it will not lap the wbox/wint)

TLDButtons:
 movem.l d0-d7/a0-a6,-(a7) ;saves all

 tst.w d7                  ;quit if d7 has illegal values
 ble .done
 swap d7
 tst.w d7
 ble .done
 swap d7

 moveq #0,d6               ;set d6 lsw = column width
 move.w d2,d6              ;       msw = column width remainder
 moveq #0,d4
 swap d7
 move.b d7,d4
 swap d7
 divu d4,d6

.col:                      ;draw next column

 move.w d6,d2              ;d2 = column width
 swap d6
 tst.w d6
 beq.s .cry1
 addq.w #1,d2              ;bump d2 if reminder not yet exhausted
 subq.w #1,d6
.cry1:
 swap d6
 move.w 4+2(a7),d1         ;d1 = ypos of 1st box in column
 move.b 28+3(a7),d7        ;d7 lsw = boxes in column

 moveq #0,d5               ;set d5 lsw = row height
 move.w 12+2(a7),d5        ;       msw = row height remainder
 moveq #0,d4
 move.w d7,d4
 divu d4,d5

.box:                      ;draw next box

 move.w d5,d3              ;d3 = box height
 swap d5
 tst.w d5
 beq.s .cry2
 addq.w #1,d3              ;bump d3 if remainder not yet exhausted
 subq.w #1,d5
.cry2:
 swap d5

 move.l xxp_gfxp(a5),a6
 move.b 24+1(a7),d4        ;draw box background
 bsr TLDArea
 move.l d5,-(a7)           ;draw box
 move.b 4+16+3(a7),d4
 move.b 4+20+3(a7),d5
 bsr TLDBox
 move.l (a7)+,d5

 movem.l d0-d7/a0-a6,-(a7) ;draw strings

 move.l 60+56(a7),a6       ;a6 = input a6 = ucode.library base
 move.l a2,d2              ;d2 = wbox
 move.l a1,d3              ;d3 = wint
 move.l a0,a1              ;a1 = rastport
 move.l a5,a0              ;a0 = ucode_path
 move.l a3,a2              ;a2 = string
 moveq #0,d4
 bset #31,d4               ;flags for ASCII + &...; + preview
 bset #30,d4
 bset #15,d4
 moveq #2,d7               ;cspace = 2
 jsr _LVOTLUstring(a6)     ;preview the string
 move.w d0,d5              ;d5 = width
 beq.s .pop                ;go if null
 move.l (a7),d0            ;d0 = xpos
 neg.w d5
 add.w 8+2(a7),d5          ;d5 = box width - string width
 bmi.s .cry3               ;go if -ve
 lsr.w #1,d5
 add.w d5,d0               ;else centre string horizontally
.cry3:
 move.w 12+2(a7),d5        ;d5 = box height - actual glyph height
 sub.w xxp_uasl(a0),d5
 bmi.s .cry4               ;go if -ve
 lsr.w #1,d5               ;else centre string vertically
 add.w d5,d1
.cry4:
 bclr #15,d4               ;TLUstring not to be preview this time
 move.b 60+24+3(a7),d5     ;d5 = input d6 bits 0-7 = fgpen
 move.b 60+24+1(a7),d6     ;d6 = input d6 bits 16-23 = bgpen
 subq.b #1,60+24+2(a7)     ;d5 = hilight pen if hilight box (if any) reached
 bne.s .cry5
 move.b 60+24+0(a7),d5
.cry5:
 jsr _LVOTLUstring(a6)     ;print the string

.pop:
 movem.l (a7)+,d0-d7/a0-a6

.skip:                     ;to next string
 tst.b (a3)+
 bne .skip

 add.w d3,d1               ;bump ypos
 subq.b #1,d7
 bne .box                  ;until column finished

 add.w d2,d0               ;bump xpos
 swap d7
 subq.b #1,d7              ;until all comumns finished
 beq.s .done
 swap d7
 bra .col

.done:
 movem.l (a7)+,d0-d7/a0-a6
 rts



*>> get mouse posn rel to wint

; A0 = IntuiMessage
; A1 = wint

; Returns  NE if LMB, mouse in wint, else EQ

; Sets im_MouseX, im_MouseY rel to wint
; (If not in wint, sets im_MouseX -ve)


TLDMouse:
 movem.l d0-d1,-(a7)       ;saves all

 move.l im_MouseX(a0),d0   ;d0 = MouseX, MouseY
 sub.w 2(a1),d0
 bmi.s .ifno               ;go if MouseY above wint
 cmp.w 6(a1),d0
 bcc.s .ifno               ;go if MouseY below wint
 swap d0
 sub.w (a1),d0             ;go if MouseX left of wint
 bmi.s .ifno
 cmp.w 4(a1),d0            ;go if MouseX, MouseY ok
 bcs.s .ifsw

.ifno:
 moveq #-1,d0              ;here if MouseX &/or MouseY bad

.ifsw:
 swap d0

.iffx:
 move.l d0,im_MouseX(a0)   ;set MouseX+MouseY
 bmi.s .done               ;go if bad

.if:
 cmp.l #IDCMP_MOUSEBUTTONS,im_Class(a0)  ;go if not LMB down
 bne.s .done
 cmp.w #$0068,im_Code(a0)

.done:
 eori.w #-1,CCR            ;EQ if not LMB down, or MouseX/MouseY not in wint
 movem.l (a7)+,d0-d1
 rts



*>> see if an IntuiMessage is in a set of buttons

; D0-D3 = area covered by buttons
; D7 = bits 0-15 rows
;      bits 16-31 columns
; A0 = IntuiMessage  (TLDMouse has been called, and has returned NE)
; A2 = wbox

; returns  D0 = 0 if none
;          1+ = button pressed

TLDButmon:
 movem.l d0/d5-d6,-(a7)    ;save all except result in D0

 clr.l (a7)                ;stack D0 = 0 pro-tem

 move.w im_MouseX(a0),d5   ;d5 = pointer xpos
 sub.w (a2),d5             ;rel to wbox
 bmi.s .done               ;no if off wbox lhs
 cmp.w 4(a2),d5
 bcc.s .done               ;no if off wbox rhs
 sub.w d0,d5               ;rel to buttons
 bmi.s .done               ;no if off buttons lhs
 cmp.w d2,d5
 bcc.s .done               ;no if off buttons rhs

 move.w im_MouseY(a0),d6   ;d6 = pointer ypos
 sub.w 2(a2),d6            ;rel to wbox
 bmi.s .done               ;no if off wbox top
 cmp.w 6(a2),d6
 bcc.s .done               ;no if off wbox bot
 sub.w d1,d6               ;rel to buttons
 bmi.s .done               ;no if off buttons top
 cmp.w d3,d6
 bcc.s .done               ;no if off buttons bot

 swap d7
 mulu d7,d5                ;calculate which box
 divu d2,d5
 swap d7
 mulu d7,d5
 mulu d7,d6
 divu d3,d6
 add.w d6,d5

 addq.w #1,d5              ;box number = 1+
 move.w d5,2(a7)           ;result to stack D0

.done:
 movem.l (a7)+,d0/d5-d6
 rts


*>> draw strings to a window, monitor its scroller

; On call:   d0 = number of strings
;            d1 = line height in pixels (must be > 0)
;            d2 = wint
;            d3 = wbox
;            d4 = bits 0-7   = fgpen  } Of these, TLDShow only uses bgpen.
;                      8-15  = bgpen  } It passes the cspace and pens to
;                      24-31 = cspace } (a2) for use if required.
;            d5 = address to copy messages (im_SIZEOF bytes)
;            d6 = intuition.library base
;            d7 = gadtools.library base
;            a0 = window
;            a1 = window's xxp_scro
;            a2 = addr of subroutine to draw lines
;            a3 = pointer to data needed by (a2)
;            a5 = 0, or pointer to pop-up data (see below)
;            a6 = graphics.library base
;
; On return: d0 bits 16-31 = number of lines shown on wbox
;               bits 0-15  = top line shown on wbox

; n.b. calls TLScroll, TLSupdate, TLDArea

; TLDShow puts as many lines as will fit onto the window's wbox, and gets
; IDCMPs from the window, which it replies to and copies to (d7). If (d7)
; is a scroller movement or up or down arrow, it scrolls the lines as needed.
; If (d7) = ACTIVEWINDOW or INACTIVEWINDOW or SIZEVERIFY or IDCMPUPDATE
; other than scrollers, it continues.
; It also ignores INTUITICKS, except if a5<>0 (see below).
; If (d7) is any other message, TLDShow returns.

; When TLDShow wants to draw a line, it calls the subroutine at (a2) with
; the following data in its registers:
;
;            d0 = string number to be printed
;            d1 = ypos (rel to wbox) to print it
;            d2 = wint
;            d3 = wbox
;            d4 = fgpen
;            d5 = bgpen
;            d6 = cspace
;            a1 = rastport
;            a3 = a3 as passed to TLDShow
;
; TLDShow does not look at the data in (a3), but simply passes a3 to (a2)
; when it calls it. The caller of TLDShow can thus pass data to (a2)
; depending on what (a2) needs to draw line d0. e.g. it might be a structure
; being the address returned by TLLstart, and the string number therein of
; the first of a number of consecutive strings to be displayed. TLDShow does
; not scroll strings horizontally, so it is the caller's responsibility to
; ensure that the strings fit horizontally (if (a2) uses TLUstring to draw
; the strings, it clips them to the wint and wbox). (a2) can trash the
; values in all registers before it returns.

; Normally, TLDShow is called with A5 = 0. But A5 can instead point to a
; set of data like this, which can be used to manage a pop up, &c.
;
;           bytes 0-1 0 to ignore intuiticks, 1+ to call a5+2 if the
;                     mouse pointer is still for that many intuiticks
;                 2-5 address of subroutine to call. If 0, then no further
;                     calls take place.
;                 6   0 to ignore LMB clicks to window, -1 to call a5+2 if
;                     LMB down
;                 7   0 to ignore RMB clicks to window, -1 to call a5+2 if
;                     RMB down
;
; TLDshow first fills the window with all lines to be displayed. It then
; calls a5+2 if:
;
;             TLDShow is about to render to the window (when it sets D7=-1)
;             TLDShow is about to exit (when it sets D7=+1)
;             The window is clicked with LMB down or RMB down, if a5+6 or
;                 a5+7 are non-zero.
;             The cursor has not moved for a5+0 intuiticks. If a5+0 is
;                 0, then intuiticks are ignored.
;
; If a5+0 is non-zero, TLDShow temorarily adjusts IDCMP to get intuiticks if
; required. If a5+7 is non-zero, then TLDShow temporarily sets the RMB trap
; if required.
;
; When TLDShow calls a5+2, it sets registers as follows
;
;             d0 = line number at top of window
;             d1 = number of lines on window
;             d2 = wint
;             d3 = wbox
;             d4 = fgpen
;             d5 = bgpen
;             d6 = cspace
;             d7 = reason for calling
;                  0  = cursor was still for a5+0 ticks  (and A5+0 <> 0)
;                  1  = TLDShow is about to render to the window
;                  2  = TLDShow is about to return
;                  3  = LMB down  (and A5+6 <> 0)
;                  4  = RMB down  (and A5+7 <> 0)
;             a1 = rastport
;             a3 = a3 as passed to TLDShow
;             a5 = a5 as passed to TLDShow
;
; When a5+2 is called, it can change the things in (a5), a5 being passed to
; to it. e.g. you can switch a5+6 on and off, or set a5+2 to 0 to stop
; further calls.
;
; If a5+0 = 1, then TLDShow calls a5+2 as soon as it gets an intuitick; or,
; If a5+0 was already called where the mouse is, as soon as the mouse is at
; a different position. (i.e. for popup info, set a5+2 > 1 to pop on,
; a5+2 = 1 to pop off).


TLDShow:

.ytop: EQU 0               ;2 line num displayed at top of wbox
.visi: EQU 2               ;2 lines that will fit on window
.idms: EQU 4               ;4 IDCMP at start (will restore if changes)
.flgs: EQU 8               ;4 WFLG at start (will restore if changed)
.tick: EQU 12              ;8 intuitick: xpos,ypos,steps,- here

.dsiz: EQU 20              ;size of stack data area


 movem.l d0-d7/a0-a6,-(a7) ;save all except result in d0
 sub.w #.dsiz,a7

; set intuiticks, rmb trap if a5 <> 0

 move.l wd_IDCMPFlags(a0),.idms(a7)  ;cache input idcmp, flags
 move.l wd_Flags(a0),.flgs(a7)

 move.l a5,d0              ;go if a5 = 0
 beq.s .visc
 move.l #-1,.tick(a7)      ;restart intuitick count next tick

 move.l d6,a6              ;set rmb trap
 move.l .flgs(a7),d0
 or.l #WFLG_RMBTRAP,d0
 move.l d0,wd_Flags(a0)
 move.l .idms(a7),d0       ;set intuiticks
 or.l #IDCMP_INTUITICKS,d0
 jsr _LVOModifyIDCMP(a6)

; calculate .visi, set .ytop

.visc:
 move.l d3,a2              ;set .visi = lines that will fit
 moveq #0,d7               ;    .ytop = 0
 move.w 6(a2),d7
 divu .dsiz+4+2(a7),d7     ;wbox hght / lspace
 tst.w d7
 bne.s .some
 moveq #1,d7               ;(.visi at least 1)
.some:
 move.w d7,.visi(a7)
 clr.w .ytop(a7)

; clear wbox

.draw:
 move.l .dsiz+32(a7),a0    ;a0 = window
 move.l .dsiz+8(a7),a1     ;a1 = wint
 move.l .dsiz+12(a7),a2    ;a2 = wbox
 moveq #0,d0
 moveq #0,d1
 move.w 4(a2),d2
 move.w 6(a2),d3
 move.b .dsiz+16+2(a7),d4  ;d4 = bgpen
 move.l wd_RPort(a0),a0    ;a0 = rastport
 move.l .dsiz+32+24(a7),a6 ;a6 = graphics.library base
 bsr TLDArea

; draw lines

 move.w .ytop(a7),d0       ;d0 = ytop
 moveq #0,d1               ;d1 = ypos
 move.l a1,d2              ;d2 = wint
 move.l a2,d3              ;d3 = wbox
 move.b .dsiz+16+3(a7),d4  ;d4 = fgpen
 move.b .dsiz+16+2(a7),d5  ;d5 = bgpen
 move.b .dsiz+16(a7),d6    ;d6 = cspace
 move.l a0,a1              ;a1 = rastport
 move.l .dsiz+32+8(a7),a0  ;a0 = input a2 = address to call
 move.l .dsiz+32+12(a7),a3 ;a3 = input a3
 move.w .dsiz+2(a7),d7     ;d7 = lessor of (lines - ytop), visible lines
 sub.w d0,d7
 cmp.w .visi(a7),d7
 bls.s .drwl
 move.w .visi(a7),d7
.drwl:
 movem.l d0-d7/a0-a6,-(a7) ;call subroutine
 jsr (a0)
 movem.l (a7)+,d0-d7/a0-a6
 addq.w #1,d0              ;bump lines number
 add.w .dsiz+4+2(a7),d1    ;bump ypos
 subq.w #1,d7
 bne .drwl                 ;until all lines that will fit are drawn

; set the scroller

 moveq #0,d0               ;d0 = total lines
 move.w .dsiz+0+2(a7),d0
 moveq #0,d1
 move.w .visi(a7),d1       ;d1 = visible lines
 cmp.w d1,d0
 bcc.s .sscr
 move.w d1,d0              ;d0 = d1 if total < visible (i.e annul scroller)

.sscr:
 move.l .dsiz+24(a7),a6    ;a6 = intbase
 move.l .dsiz+32+4(a7),a0  ;a0 = xxp_scro
 move.l .dsiz+32(a7),a5    ;a5 = window

 clr.l xxp_hztp(a0)        ;horz scroller inoperative
 move.l #256,xxp_hzvs(a0)
 move.l #256,xxp_hztt(a0)
 move.l #1,xxp_hstp(a0)
 clr.l xxp_vttp(a0)        ;vert top     = ytop
 move.w .ytop(a7),xxp_vttp+2(a0)
 move.l d1,xxp_vtvs(a0)    ;vert visible = visible lines
 move.l d0,xxp_vttt(a0)    ;vert total   = total lines
 move.l #1,xxp_vstp(a0)    ;vert step    = 1 line
 moveq #0,d0               ;d0 = 0 = set
 moveq #0,d1               ;d1 = 0 = both
 bsr TLScroll              ;initialise the scrollers

 bra .wait                 ;go wait for messages

; here if scroller moves or up/down arrow

.scro:
 move.l .dsiz+32+4(a7),a3  ;a3 = window's xxp_scro
 move.w xxp_vttp+2(a3),d7  ;d7 = new ytop
 move.w .ytop(a7),d6       ;d6 = old ytop
 move.w d7,.ytop(a7)       ;set new ytop
 move.w d7,d0
 sub.w d6,d0               ;d0 = |change in ytop|  (go if no change)
 beq .wait
 bpl.s .lim
 neg.w d0
.lim:

; about to render - call a5+2 if applicable

 move.l .dsiz+32+20(a7),d4 ;go if a5 was 0
 beq.s .npop
 move.l d4,a0
 tst.l 2(a0)
 beq.s .npop

 movem.l d0-d7/a0-a6,-(a7)

 move.w d6,d0              ;d0 = topline on window
 move.w 60+.visi(a7),d1    ;d1 = lesser of total,.visi = lines on window
 cmp.w 60+.dsiz+0+2(a7),d1
 bls.s .cnc0
 move.w 60+.dsiz+0+2(a7),d1
.cnc0:
 move.l 60+.dsiz+8(a7),d2     ;d2 = wint
 move.l 60+.dsiz+12(a7),d3    ;d3 = wbox
 move.b 60+.dsiz+16+3(a7),d4  ;d4 = fgpen
 move.b 60+.dsiz+16+2(a7),d5  ;d5 = bgpen
 move.b 60+.dsiz+16+0(a7),d6  ;d6 = cspace
 moveq #1,d7                  ;d7 = 1 = code for about to render
 move.l 60+.dsiz+32(a7),a2
 move.l wd_RPort(a2),a1       ;a1 = rastport
 move.l 60+.dsiz+32+12(a7),a3 ;a3 = a3 at call
 move.l 60+.dsiz+32+20(a7),a5 ;a5 = a5 at call
 move.l 2(a0),a2
 jsr (a2)

 movem.l (a7)+,d0-d7/a0-a6

.npop:
 cmp.w xxp_vtvs+2(a3),d0   ;re-draw entirely if >= vtvs
 bcc .draw

 move.l .dsiz+32+24(a7),a6 ;a6 = graphics.library base
 move.l .dsiz+32(a7),a0
 move.l wd_RPort(a0),a2    ;a2 = window's rastport
 moveq #0,d0
 move.b .dsiz+16+2(a7),d0  ;d0 = bgpen
 cmp.b rp_BgPen(a2),d0
 beq.s .bg                 ;go if bgpen already set
 move.l a2,a1              ;else, set bgpen
 jsr _LVOSetBPen(a6)

.bg:
 move.l .dsiz+8(a7),a0     ;a0 = wint
 move.l .dsiz+12(a7),a1    ;a1 = wbox

 moveq #0,d4               ;d4 = wbox width
 move.w 4(a1),d4
 moveq #0,d2
 move.w (a1),d2            ;d2 = wbox xpos in wint
 bpl.s .cry1
 add.w d2,d4               ;clip to wint lhs
 ble.s .scld               ;go if rhs off wint lhs
 moveq #0,d2
.cry1:
 add.w d2,d4               ;clip to wint rhs
 cmp.w 4(a0),d4
 bls.s .cry2
 move.w 4(a0),d4
.cry2:
 sub.w d2,d4
 ble.s .scld               ;go if lhs off wint rhs

 moveq #0,d5               ;d5 = line ht * visible lines
 move.w .dsiz+4+2(a7),d5
 move.w d5,d1              ;d1 = line ht
 mulu .visi(a7),d5
 moveq #0,d3
 move.w 2(a1),d3           ;d3 = wbox ypos in wint
 bpl.s .cry3
 add.w d3,d5               ;clip to wint top
 ble.s .scld               ;go if bot off wint top
 moveq #0,d3
.cry3:
 add.w d3,d5               ;clip to wint bot
 cmp.w 6(a0),d5
 bls.s .cry4
 move.w 6(a0),d5
.cry4:
 sub.w d3,d5
 ble.s .scld               ;go if top off wint bot

 add.w (a0),d2             ;d2,d3 rel to wint
 add.w 2(a0),d3
 add.w d2,d4
 subq.w #1,d4              ;d4 = rhs
 add.w d3,d5
 subq.w #1,d5              ;d5 = bot
 move.w d7,d0
 sub.w d6,d0               ;d1 = (new ytop - old ytop) * line ht
 bpl.s .plus               ;   = vert displacement
 neg.w d0
 mulu d0,d1
 neg.l d1
 bra.s .scrd
.plus:
 mulu d0,d1
.scrd:
 moveq #0,d0               ;horz displacement = 0
 move.l a2,a1
 jsr _LVOScrollRaster(a6)  ;scroll the raster

.scld:
 sub.w d6,d7               ;d7 = number of lines to draw at top/bottom
 bpl.s .bot
 neg.w d7                  ;here if fill in lines at top...
 moveq #0,d0               ;from line d0 rel to ytop
 moveq #0,d1               ;ypos = 0
 bra.s .pick
.bot:                      ;here if fill in lines at bot...
 move.w .visi(a7),d0
 sub.w d7,d0               ;from line .visi - d7 rel to .ytop
 move.w d0,d1
 mulu .dsiz+4+2(a7),d1     ;d1 = line rel to ytop * line ht = ypos
.pick:
 subq.w #1,d7              ;d7 counts lines
 add.w .ytop(a7),d0        ;d0 = actual line num,d1 = ypos rel to wbox
 move.l .dsiz+8(a7),d2     ;d2 = wint
 move.l .dsiz+12(a7),d3    ;d3 = wbox
 move.b .dsiz+16+3(a7),d4  ;d4 = fgpen
 move.b .dsiz+16+2(a7),d5  ;d5 = bgpen
 move.b .dsiz+16+0(a7),d6  ;d6 = cspace
 move.l a2,a1              ;a1 = rastport
 move.l .dsiz+32+12(a7),a3 ;a3 = (a2) data
 move.l .dsiz+32+8(a7),a0  ;a0 = addr to call
.line:
 movem.l d0-d7/a0-a6,-(a7)
 jsr (a0)                  ;print line
 movem.l (a7)+,d0-d7/a0-a6
 addq.w #1,d0              ;bump line num
 add.w .dsiz+4+2(a7),d1    ;bump ypos
 dbra d7,.line             ;until all lines done

; wait for messages

.wait:
 move.l _AbsExecBase,a6    ;wait for message
 move.l .dsiz+32(a7),a2
 move.l wd_UserPort(a2),a0
 jsr _LVOWaitPort(a6)
 move.l wd_UserPort(a2),a0 ;get message
 move.l .dsiz+28(a7),a6
 jsr _LVOGT_GetIMsg(a6)
 tst.l d0                  ;retry if null (can't happen?)
 beq .wait
 move.l d0,a0              ;copy of message in input (d5), a2
 move.l .dsiz+20(a7),a1
 move.l a1,a2
 move.w #im_SIZEOF-1,d1
.mesg:
 move.b (a0)+,(a1)+
 dbra d1,.mesg
 move.l d0,a1
 jsr _LVOGT_ReplyIMsg(a6)  ;reply to message

 cmp.l #IDCMP_SIZEVERIFY,im_Class(a2) ;wait for NEWSIZE after SIZEVERIFY
 beq .wait

; if a5 <> 0 and a5+2 <> 0, trim mouse posn to wbox

 move.l .dsiz+32+20(a7),d2 ;go if a5 was 0
 beq .ifsc
 move.l d2,a0
 tst.l 2(a0)               ;go if call address null
 beq .ifsc

; go if not trapping this message

 move.l d2,a0              ;go if not processing intuiticks
 tst.w (a0)
 beq .ifsc

 cmp.l #IDCMP_INTUITICKS,im_Class(a2)
 bne .ifsc                 ;go if not an intuitick

; message trapped - make mouse posn rel to wbox

.rela:
 move.l .dsiz+8(a7),a0     ;trim mouse posn to wbox
 move.l .dsiz+12(a7),a1
 move.w im_MouseX(a2),d0   ;  a0,a1 = wint,wbox
 move.w im_MouseY(a2),d1   ;  d0,d1 = mousex,mousey
 move.l #-1,im_MouseX(a2)
 sub.w (a0),d0             ;d0 rel to wint
 bmi.s .tkow               ;go if d0 off wint
 cmp.w 4(a0),d0
 bcc.s .tkow
 sub.w (a1),d0             ;d0 rel to wbox
 bmi.s .tkow               ;go if d0 off wbox
 cmp.w 4(a1),d0
 bcc.s .tkow
 sub.w 2(a0),d1            ;d1 rel to wint
 bmi.s .tkow               ;go if d1 off wint
 cmp.w 6(a0),d1
 bcc.s .tkow
 sub.w 2(a1),d1            ;d1 rel to wbox
 bmi.s .tkow               ;go if d1 off wint
 cmp.w 6(a1),d1
 bcc.s .tkow
 swap d0                   ;d0 = mousex : mousey
 move.w d1,d0

; process whichever sort of thing trapped

.tkow:
 move.l .dsiz+32+20(a7),a0 ;a0 = input a5

 move.w (a0),d2            ;go with d2 = tick limit if we trapped intuitick
 beq.s .tkw2
 cmp.l #IDCMP_INTUITICKS,im_Class(a2)
 beq.s .tict

; trap LMB/RMB if pointer within wbox

.tkw2:
 tst.l d0                  ;do not trap other things if mouset no on wbox
 bmi .ifsc
 move.l d0,im_MouseX(a2)   ;update MouseX,MouseY rel to wbox

                           ;(#### not yet implemented)

 bra .wait

; intuitick trapped (trapped even if pointer not on wbox)

.tict:
 move.l d0,im_MouseX(a2)   ;MouseX, MouseY rel to wbox

 move.l .tick(a7),d1       ;d1 = old posn
 move.l d0,.tick(a7)       ;put new posn
 bmi .wait                 ;go if new posn not on wbox

 cmp.l d0,d1               ;restart count if new posn <> old posn
 beq.s .same
 clr.w .tick+4(a7)
.same:
 cmp.w .tick+4(a7),d2      ;go if still where already called a5+2
 bls .wait
 addq.w #1,.tick+4(a7)     ;bump count
 cmp.w .tick+4(a7),d2
 bne .wait                 ;go unless count reached

; call if intuitick count reached

 move.w .ytop(a7),d0       ;d0 = topline on window
 move.w .visi(a7),d1       ;d1 = lesser of total,.visi = lines on window
 cmp.w .dsiz+0+2(a7),d1
 bls.s .conc
 move.w .dsiz+0+2(a7),d1
.conc:
 move.l .dsiz+8(a7),d2     ;d2 = wint
 move.l .dsiz+12(a7),d3    ;d3 = wbox
 move.b .dsiz+16+3(a7),d4  ;d4 = fgpen
 move.b .dsiz+16+2(a7),d5  ;d5 = bgpen
 move.b .dsiz+16+0(a7),d6  ;d6 = cspace
 moveq #0,d7               ;d7 = 0 = code for intuitick count reached
 move.l .dsiz+32(a7),a2
 move.l wd_RPort(a2),a1    ;a1 = rastport
 move.l .dsiz+32+12(a7),a3 ;a3 = a3 at call
 move.l .dsiz+32+20(a7),a5 ;a5 = a5 at call
 move.l 2(a0),a2
 jsr (a2)
 bra .wait                 ;get next message after calling

; see if scroller message

.ifsc:
 move.l .dsiz+24(a7),a6    ;a6 = intbase
 move.l .dsiz+32+4(a7),a0  ;a0 = xxp_scro
 move.l .dsiz+32(a7),a5    ;a5 = window
 bsr TLSupdate
 bne .scro                 ;if yes, go scroll

; see if up arrow or down arrow

 cmp.l #IDCMP_RAWKEY,im_Class(a2)  ;to .else if not up arrow or down arrow
 bne.s .else
 cmp.w #$004C,im_Code(a2)
 beq.s .upar
 cmp.w #$004D,im_Code(a2)
 beq.s .dnar
 bra.s .else

.upar:                     ;up arrow pressed
 move.l .dsiz+24(a7),a6    ;a6 = intbase
 move.l .dsiz+32+4(a7),a0  ;a0 = xxp_scro
 move.l .dsiz+32(a7),a5    ;a5 = window
 tst.w xxp_vttp+2(a0)      ;ignore if vert top = 0
 beq .wait
 subq.w #1,xxp_vttp+2(a0)  ;dec vert top
 moveq #0,d0               ;d0 = 0 = set
 moveq #-1,d1              ;d1 = -1 = vert
 bsr TLScroll              ;set the scroller
 bra .scro                 ;go update window contents

.dnar:                     ;down arrow pressed
 move.l .dsiz+24(a7),a6    ;a6 = intbase
 move.l .dsiz+32+4(a7),a0  ;a0 = xxp_scro
 move.l .dsiz+32(a7),a5    ;a5 = window
 move.w xxp_vttt+2(a0),d0
 sub.w xxp_vtvs+2(a0),d0
 cmp.w xxp_vttp+2(a0),d0   ;ignore if vert top = vert total - vert visible
 beq .wait
 addq.w #1,xxp_vttp+2(a0)  ;bump vert top
 moveq #0,d0               ;d0 = 0 = set
 moveq #-1,d1              ;d1 = -1 = vert
 bsr TLScroll              ;set the scroller
 bra .scro                 ;go update window contents

.else:
 move.l im_Class(a2),d0

 cmp.l #IDCMP_MOUSEBUTTONS,d0   ;ignore mousebuttone up
 bne .els2
 cmp.w #$0080,im_Code(a2)
 bcc .wait

.els2:
 cmp.l #IDCMP_IDCMPUPDATE,d0    ;ignore discarded IDCMPUPDATEs.
 beq .wait
 cmp.l #ACTIVEWINDOW,d0         ;ignore activewindow
 beq .wait
 cmp.l #IDCMP_INACTIVEWINDOW,d0 ;ignore inactivewindow
 beq .wait
 cmp.l #IDCMP_INTUITICKS,d0     ;ignore discarded intuiticks
 beq .wait

; set result in stack D0 ready to exit

.done:
 move.w .visi(a7),d0           ;d0 = lesser of total,.visi
 cmp.w .dsiz+0+2(a7),d0
 bls.s .donc
 move.w .dsiz+0+2(a7),d0
.donc:
 move.w d0,.dsiz+0(a7)         ;stack d0 bits 16-31 = lesser of totl,.visi
 move.w .ytop(a7),.dsiz+2(a7)  ;              0-15  = .ytop

; call a5+2, restore idcmp, rmb trap if a5 was <> 0

 move.l .dsiz+32+20(a7),d0 ;go if a5 was 0
 beq.s .quit
 move.l d0,a5
 tst.l 2(a5)               ;go if a5+2 null
 beq.s .ffix

 movem.l d0-d7/a0-a6,-(a7)    ;call a5+2 with code 2

 move.w 60+.dsiz+2(a7),d0     ;d0 = topline on window } as set for
 move.w 60+.dsiz+0(a7),d1     ;d1 = lines on window   } return
 move.l 60+.dsiz+8(a7),d2     ;d2 = wint
 move.l 60+.dsiz+12(a7),d3    ;d3 = wbox
 move.b 60+.dsiz+16+3(a7),d4  ;d4 = fgpen
 move.b 60+.dsiz+16+2(a7),d5  ;d5 = bgpen
 move.b 60+.dsiz+16+0(a7),d6  ;d6 = cspace
 moveq #2,d7                  ;d7 = 2 = code for about to return
 move.l 60+.dsiz+32(a7),a2
 move.l wd_RPort(a2),a1       ;a1 = rastport
 move.l 60+.dsiz+32+12(a7),a3 ;a3 = a3 at call
 move.l 60+.dsiz+32+20(a7),a5 ;a5 = a5 at call
 move.l 2(a5),a2
 jsr (a2)

 movem.l (a7)+,d0-d7/a0-a6

.ffix:
 move.l .dsiz+24(a7),a6    ;a6 = intuition.library base
 move.l .dsiz+32(a7),a0    ;a0 = window
 move.l .flgs(a7),wd_Flags(a0)   ;restore flags as at start
 move.l .idms(a7),d0
 cmp.l wd_IDCMPFlags(a0),d0      ;restore idcmp as at start
 beq.s .quit
 jsr _LVOModifyIDCMP(a6)

; exit from TLDShow

.quit:
 add.w #.dsiz,a7
 movem.l (a7)+,d0-d7/a0-a6
 rts


*>> trim an area (internal routine called by other TLD routines)

; On call:   d0-d3 = area
;            a1    = wint
;            a2    = wbox
;            a3    = trim (8 bytes)(undefined on call)

; On return: d0-d3 trimmed to fit wbox (d2 = 0 if out of wbox/wint)
;
;            trim  +0 = amt trimmed at lhs  }
;                  +2 = amt trimmed at top  } undef if d2 = 0
;                  +4 = amt trimmed at rhs  }
;                  +6 = amt trimmed at bot  }


TLDTrim:
 clr.l (a3)                ;all regs saved except results in d0-d3
 clr.l 4(a3)

 tst.w d0                  ;trim xpos at left if -ve
 bpl.s .t1
 add.w d0,d2
 ble .null
 sub.w d0,(a3)
 moveq #0,d0

.t1:
 tst.w d1                  ;trim ypos at top if -ve
 bpl.s .t2
 add.w d1,d3
 ble .null
 sub.w d1,2(a3)
 moveq #0,d3

.t2:
 cmp.w 4(a2),d0            ;go if xpos >= rhs of wbox
 bcc .null
 add.w d0,d2               ;trim to rhs of wbox
 cmp.w 4(a2),d2
 bls.s .t3
 sub.w 4(a3),d2
 move.w d2,4(a3)
 move.w 4(a2),d2
.t3:
 sub.w d0,d2

 cmp.w 6(a2),d1            ;go if ypos >= bot of wbox
 bcc.s .null
 add.w d1,d3               ;trim to bot of wbox
 cmp.w 6(a2),d3
 bls.s .t4
 sub.w 6(a2),d3
 move.w d3,6(a3)
 move.w 6(a2),d3
.t4:
 sub.w d1,d3

 add.w (a2),d0             ;make d0 rel to wbox
 bpl.s .t5
 add.w d0,d2
 ble.s .null
 sub.w d0,(a3)             ;trim left if -ve
 moveq #0,d0

.t5:
 add.w 2(a2),d1            ;make d1 rel to wbox
 bpl.s .t6
 add.w d1,d3
 ble.s .null
 sub.w d1,2(a3)            ;trip top if -ve
 moveq #0,d1

.t6:
 cmp.w 4(a1),d0            ;go if lhs >= wint rhs
 bcc.s .null
 add.w d0,d2
 cmp.w 4(a1),d2            ;else trim rhs to wint bot
 bls.s .t7
 sub.w 4(a1),d2
 add.w d2,4(a3)
 move.w 4(a1),d2
.t7:
 sub.w d0,d2

 cmp.w 6(a1),d1            ;go if top >= wint bot
 bcc.s .null
 add.w d1,d3
 cmp.w 6(a1),d3            ;else trim bot to wint bot
 bls.s .t8
 sub.w 6(a1),d3
 add.w d3,6(a3)
 move.w 6(a1),d3
.t8:
 sub.w d1,d3

 add.w (a1),d0             ;make d0,d1 rel to wint
 add.w 2(a1),d1
 bra.s .done               ;done ok

.null:
 moveq #0,d2               ;here if trimmed completely off wint

.done:
 tst.w d2                  ;EQ if null
 rts


*>> make a backup rastport

; D0 = bytes per bitplane (must be divisible by 16, minimum 128)
; D1 = bitplanes          (must be 2 to 8, usually 8)
; A6 = graphics.library base

; on return, D0 = address of backup rastport (0 if out of mem)

; makes public memory as follows:
;
; mem+0                    rastport
;    +rp_SIZEOF            bitmap
;    +rp_SIZEOF+bm_SISEOF  40 bytes for D0-D6/A0-A1/A6 of TLDBackup ClipBlit

TLDMakeback:
 movem.l d0-d7/a0-a6,-(a7) ;save all except result in D0

 move.l d0,d7              ;d7 = bytes per bitplane
 move.l d1,d2              ;d2 =bitplanes

 clr.l (a7)                ;stack d0 = 0 pro-tem

 move.l _AbsExecBase,a6    ;d6 = chip memory (d0*d1 bytes)
 mulu d1,d0
 moveq #MEMF_CHIP,d1
 jsr _LVOAllocVec(a6)
 move.l d0,d6
 beq.s .done               ;go if out of mem

 move.l #rp_SIZEOF+bm_SIZEOF+40,d0  ;d5 = public memory for rastport, bitmap
 moveq #MEMF_PUBLIC,d1
 jsr _LVOAllocVec(a6)
 move.l d0,d5
 bne.s .good               ;go if memory ok

 move.l d6,a1              ;else free chip memory, return out of mem
 jsr _LVOFreeVec(a6)
 bra.s .done

.good:
 move.l d5,(a7)            ;stack d0 = address of rastport

 move.l 32+24(a7),a6       ;a6 = graphics.library base
 move.l d5,a1
 jsr _LVOInitRastPort(a6)

 moveq #16,d0              ;(dummy bitmap size 16 X 16)
 moveq #16,d1              ;d2 already = planes
 move.l d5,a2              ;a2 = rastport
 move.l d5,a0              ;a0 = bitmap
 add.w #rp_SIZEOF,a0
 move.l a0,rp_BitMap(a2)   ;attach bitmap to rastport
 jsr _LVOInitBitMap(a6)    ;initialise bitmap

 move.l d5,a0
 clr.w bm_Rows(a0)         ;bm_Rows = 0 = no backup has happened

 add.w #rp_SIZEOF+bm_Planes,a0  ;a0 scans bitplanes
 subq.w #1,d2              ;d2 counts bitplanes
.plan:
 move.l d6,(a0)+           ;put next bitplane
 add.l d7,d6
 dbra d2,.plan             ;until all bitplanes put

.done:
 movem.l (a7)+,d0-d7/a0-a6 ;result 0/rastport in D0
 rts


*>> backup from a rastport

; D0-D3 = region in wbox
; A0 = rastport to backup from
; A1 = rastport made by TLDMakeback
; A2 = wint
; A3 = wbox
; A6 = graphics.library base


TLDBackup:
 movem.l d0-d7/a0-a6,-(a7) ;save all

 move.l rp_BitMap(a1),a5   ;a5 = backup bitmap
 clr.w bm_Rows(a5)         ;bm_Rows will be 0 if no blit takes place

 ext.l d2
 ble .done
 ext.l d3
 ble .done

 ext.l d0                  ;clip d0,d2 to rastport
 bpl.s .cry1
 add.w d0,d2
 ble .done
 moveq #0,d2
.cry1:
 add.w d0,d2
 cmp.w 4(a3),d2
 bls.s .cry2
 move.w 4(a3),d2
.cry2:
 sub.w d0,d2
 ble .done
 add.w (a3),d0
 bpl.s .cry3
 add.w d0,d2
 ble .done
 moveq #0,d0
.cry3:
 add.w d0,d2
 cmp.w 4(a2),d2
 bls.s .cry4
 move.w 4(a2),d2
.cry4:
 sub.w d0,d2
 ble .done
 add.w (a2),d0

 ext.l d1                  ;clip d1,d3 to rastport
 bpl.s .cry5
 add.w d1,d3
 ble .done
 moveq #0,d1
.cry5:
 add.w d1,d3
 cmp.w 6(a3),d3
 bls.s .cry6
 move.w 6(a3),d3
.cry6:
 sub.w d1,d3
 ble .done
 add.w 2(a3),d1
 bpl.s .cry7
 add.w d1,d3
 ble .done
 moveq #0,d1
.cry7:
 add.w d1,d3
 cmp.w 6(a2),d3
 bls.s .cry8
 move.w 6(a2),d3
.cry8:
 sub.w d1,d3
 ble.s .done
 add.w 2(a2),d1

 move.l d2,d4              ;ready regs for ClipBlit
 move.l d3,d5
 moveq #0,d2
 moveq #0,d3

 move.l bm_Planes+4(a5),d7 ;d7 = bytes per blitplane
 sub.l bm_Planes(a5),d7
 move.l d4,d6
 add.w #15,d6
 lsr.w #4,d6               ;d6 = bytes per row needed for width d4
 lsl.w #1,d6
 move.w d6,bm_BytesPerRow(a5)
 beq.s .done               ;bad if 0 (can't happen?)
 move.w d5,bm_Rows(a5)     ;set rows needes for height d5
 mulu d5,d6
 cmp.l d6,d7               ;ok if biplanes big enough
 bcc.s .redi

 clr.w bm_Rows(a5)         ;set Rows = 0 pro-tem
 moveq #0,d6
 move.w bm_BytesPerRow(a5),d6  ;determine number of rows that will fit
 divu d6,d7
 bvs.s .done                   ;go if can't
 move.w d7,bm_Rows(a5)         ;else truncate number of rows
 beq.s .done

.redi:
 move.w #$00C0,d6          ;minterm = vanilla copy

 move.l a1,a2
 add.w #rp_SIZEOF+bm_SIZEOF,a2 ;save data for TLDRestore
 move.l d0,(a2)
 move.l d1,4(a2)
 move.l d2,8(a2)
 move.l d3,12(a2)
 move.l d4,16(a2)
 move.l d5,20(a2)
 move.l d6,24(a2)
 move.l a0,28(a2)
 move.l a1,32(a2)
 move.l a6,36(a2)

 jsr _LVOClipBlit(a6)

.done:
 movem.l (a7)+,d0-d7/a0-a6
 rts


*>> restore from rastport

; A0 = rastport where TLDBackup took place

TLDRestore:
 movem.l d0-d6/a0-a6,-(a7) ;save all

 move.l rp_BitMap(a0),a5   ;a5 = backup bitmap
 tst.w bm_Rows(a5)
 beq.s .done               ;go if TLDBackup not validly called

 move.l a0,a2
 add.w #rp_SIZEOF+bm_SIZEOF,a2  ;retrieve registers from TLDBackup's blit

 move.l 8(a2),d0           ;swap d0,d1 <> d2,d3
 move.l 12(a2),d1
 move.l (a2),d2
 move.l 4(a2),d3
 move.l 16(a2),d4
 move.l 20(a2),d5
 move.l 24(a2),d6
 move.l 28(a2),a1          ;swap a0 <> a1
 move.l 32(a2),a0
 move.l 36(a2),a6

 jsr _LVOClipBlit(a6)      ;reverse TLDBackup's blit

.done:
 clr.w bm_Rows(a5)         ;forbid further restore without backup

 movem.l (a7)+,d0-d7/a0-a6
 rts



*>> free a backup rastport

; D0 = result returned by by TLDMakeback

; (ok if D0 = 0, when nothing happens)

TLDFreeback:
 tst.l d0                  ;quit if d0 = 0
 beq.s .done

 movem.l d0-d1/a0-a2/a6,-(a7)  ;save all

 move.l _AbsExecBase,a6    ;free chip mem
 move.l d0,a2
 move.l rp_BitMap(a2),a0
 move.l bm_Planes(a0),a1
 jsr _LVOFreeVec(a6)
 move.l a2,a1              ;free public mem
 jsr _LVOFreeVec(a6)

 movem.l (a7)+,d0-d1/a0-a2/a6

.done:
 rts


*>> put busy pointer in window

; A0 = window
; A6 = intuition.library base

TLDBusy:
 movem.l d0-d1/a0-a1,-(a7)
 cmp.w #39,LIB_VERSION(a6)     ;not if lib version < 39
 bcs.s .quit
 lea .tags,a1
 jsr _LVOSetWindowPointerA(a6)
.quit:
 movem.l (a7)+,d0-d1/a0-a1
 rts

.tags:                    ;tags for busy pointer (v39+ method)
 dc.l WA_BusyPointer,1    ;this uses the prefs busy pointer
 dc.l WA_PointerDelay,1   ;this stops the change if the delay is very short
 dc.l TAG_DONE


*>> put unbusy pointer in window

; A0 = window
; A6 = intuition.library base


TLDUnbusy:
 movem.l d0-d1/a0-a1,-(a7)
 cmp.w #39,LIB_VERSION(a6)     ;not if lib version < 39
 bcs.s .quit
 lea .tags,a1
 jsr _LVOSetWindowPointerA(a6)
.quit:
 movem.l (a7)+,d0-d1/a0-a1
 rts

.tags:
   dc.l  WA_Pointer,0    ;tag for normal pointer
   dc.l  TAG_DONE


*>> get a string

*
*    This routine not yet written
*

; d0 =
; d1 =
; d2 =
; d3 = wbox (tablet will be posn 0,0, ht = clone ht, width = wbox width)
; d4 = max chrs (1-80)
; d5 = flags
;      0-7  = init crsr
;      8-15 = tablet offset / 16 on return - FFFE if eol, FFFF if show crsr
;      31 = hex   } At most, one of these three set
;      30 = dec   } if none, ASCII
;      29 = float }
;      28 = allow break
;      27 = return immediately
; d6 = cspc lspc bpen fpen
; d7 = max line width (may exceed if < 1 chr will fit)(no max if 0)
; a0 = ucode_path
; a1 = window
; a2 = room to copy messages
; a3 = null delimited input buffer (size must be at least d4+2)
; a5 = gadtools.library base
; a6 = ucode.library base


; returns:
;
; 1. null delimited string in a1, plus,if d5 bit 28 set, a 2nd null
;    delimited string which is cf to next line
; 2. message causing return in a2
; 3. d0   bits 0 -  7  chrs in 1st buffer string
;              8 - 15  chrs in 2nd buffer string, if d5 bit 28
;             16 - 23  offset / 16
;             31       set if output <> input


TLDInput:

 STRUCTURE .offs,0
 APTR  .clone         ;ucode_path (clone)
 APTR  .ibase         ;intuition.library base
 APTR  .dbase         ;dos.library base
 APTR  .gbase         ;graphics.library base
 APTR  .uport         ;window's message port
 APTR  .rport         ;window's rastport
 STRUCT .wint,8       ;wint
 STRUCT .prev,172     ;posn of characters
 LABEL .ofsz

.osiz:  EQU (((.ofsz+3)/4)*4)   ;offsets rounded up longwords

.wbox:  EQU .osiz+12  ;D3 = wbox
.maxc:  EQU .osiz+16  ;D4 = maxc
.flag:  EQU .osiz+20  ;D5 = flags
.clbf:  EQU .osiz+24  ;D6 = cspc lspc bpen fpen
.maxw:  EQU .osiz+28  ;D7 = maxwidth
.upath: EQU .osiz+32  ;A0 = ucode_path
.wndow: EQU .osiz+36  ;A1 = window
.mesag: EQU .osiz+40  ;A2 = copy of message
.ibuf:  EQU .osiz+44  ;A3 = input buffer
.tbase: EQU .osiz+52  ;A5 = gadtools.library base
.ubase: EQU .osiz+56  ;A6 = ucode.library base

 movem.l d0-d7/a0-a6,-(a7)     ;save all
 sub.w #.osiz,a7

 move.l xxp_clon(a0),.clone(a7)
 move.l xxp_intp(a0),.ibase(a7)
 move.l xxp_dosp(a0),.dbase(a7)
 move.l xxp_gfxp(a0),.gbase(a7)
 move.l wd_RPort(a0),.rport(a7)
 move.l wd_UserPort(a0),.uport(a7)

; here to redraw completely

.rdrw:
 move.l .wndow(a7),a0 ;a0 = window
 lea .wint(a7),a1     ;a1 = wint
 move.l .wbox(a7),a2  ;a2 = wbox
 bsr TLDWindow

; clear tablet

 move.l .clone(a7),a3 ;d0-d3 = region
 moveq #0,d0
 moveq #0,d1
 move.w 4(a2),d2
 move.w xxp_uasl(a3),d3 ;ht = actual glyph ht
 move.b .clbf+2(a7),d4  ;d4 = bpen
 move.l .rport(a7),a0   ;a0 = rastport
 move.l .gbase(a7),a6   ;a6 = graphics.library base
 bsr TLDArea

; preview text




 movem.l (a7)+,d0-d7/a0-a6
 add.w #.osiz,a7

 rts


 ENDC                      ;end of TLD_Stuff
