$NOLIST

NAME  WindowBlockCopyRtns

$INCLUDE (WinCnsts~Inc~)

CGROUP GROUP CODE


PUBLIC WinScrollRectangle, WinCopyRectangle, WinCopyCursorRectangle

EXTRN  drawWindow: WORD

EXTRN  WinClipRectangle: NEAR
EXTRN  CsrMaybeTurnCursorOff: NEAR, CsrTurnCursorOn: NEAR

EXTRN  GfxCopyRectangle: FAR


CODE SEGMENT  PUBLIC 'CODE'
	ASSUME CS:CGROUP
$EJECT

;***********************************************************
;*                                                         *
;* PROCEDURE WinScrollRectangle	                         *
;*  (VAR r: Rectangle; dir: Direction;	distance: Integer);	*
;*                                                         *
;***********************************************************

params  STRUC
  r1_tpl_x   DW ?	; local r1: Rectangle
  r1_tpl_y   DW ?
  r1_ext_x   DW ?
  r1_ext_y   DW ?
;--------------
  oldBP      DW ?	; stack stuff
  oldDS      DW ?
  nearReturn DW ?
;--------------
  distance   DW ?	; param distance: Integer
  dir        DW ?	; param dir: Direction
  pRect      DD ?	; param VAR r: Rectangle
params  ENDS

loc        EQU [BP]
localBytes EQU 8H

WinScrollRectangle PROC NEAR
	PUSH	DS
	PUSH	BP

	MOV	BX, localBytes
	SUB	SP, BX
	MOV	BP, SP

	LDS	SI, loc.pRect
	MOV	CX, loc.distance
	PUSH	CX	; CX <- distance

; Compute rectangle to be scrolled

	MOV	AX, loc.dir	; dir
	TEST	AL, 2H	; left/right bit
	JNZ	ScrollAcross

; Subtract dist from extent.y  

	SUB	DS:[SI].rectExtentY, CX
	TEST	AL, 1H	; down bit
	JNZ	SetLocalR1

	ADD	DS:[SI].rectTopLeftY, CX
	JMP	SHORT SetLocalR1

; Subtract dist from extent.x

ScrollAcross:
	SUB	DS:[SI].rectExtentX, CX
	TEST	AL, 1H	; right bit
	JNZ	SetLocalR1
	ADD	DS:[SI].rectTopLeftX, CX

; Local r1 gets r (DS and SI already set up)

SetLocalR1:
	PUSH	SS	; segment of local
	POP	ES
	MOV	DI, BP	; offset of local r1
	MOV	CX, BX
	CLD
	REP MOVSB	; copy the rect

  ;*********************************
  ;*  AL = dir                     *
  ;*  BX = scratch register (8H)   *
  ;*  CX = +distance               *
  ;*  DX = dx                      *
  ;*  DI = dy                      *
  ;*  ES = +/- distance            *
  ;*  DS:[SI] -> VAR r parameter   *
  ;*********************************

	SUB	SI, BX	; undo MOVSB
	POP	CX	; CX = distance
	XOR	DX, DX	; DX = dx
	XOR	DI, DI	; DI = dy
	MOV	ES, CX
	TEST	AL, 1H
	JNZ	NoNeg	; distance = - distance..

	NEG	CX	;   ..for left and down
	MOV	ES, CX
	NEG	CX

NoNeg:
	TEST	AL, 2H	; left/right bit
	JNZ	MoveAcross

	MOV	DI, ES	; dy gets +/- distance
	TEST	AL, 1H
	JNZ	SetRectExtentY

; Scrolling UP: reset topLeft.y of rect

	MOV	AX, DS:[SI].rectExtentY
	SUB	AX, CX
	ADD	DS:[SI].rectTopLeftY, AX

SetRectExtentY:
	MOV	DS:[SI].rectExtentY, CX	; extent.y gets distance
	JMP	SHORT CopyTheRect

; Scrolling left/right:

MoveAcross:
	MOV	DX, ES	; dx gets +/- distance
	TEST	AL, 1H
	JNZ	SetRectExtentX

; Scrolling Left: reset topLeft.x of rect

	MOV	AX, DS:[SI].rectExtentX
	SUB	AX, CX
	ADD	DS:[SI].rectTopLeftX, AX

SetRectExtentX:
	MOV	DS:[SI].rectExtentX, CX	; extent.x gets distance

; Push lv r1, [r1.topLeft] + [dx, dy] onto stack

CopyTheRect:
	PUSH	CS:drawWindow	; Both the source and dest window are the
	PUSH	CS:drawWindow	; draw window for scroll rectangle
	PUSH	SS
	PUSH	BP	; still points to r1
	ADD	DX, loc.r1_tpl_x
	PUSH	DX	; newTopLeft.x
	ADD	DI, loc.r1_tpl_y
	PUSH	DI	; newTopLeft.y
	CALL	WinCopyRectangle

	ADD	SP, localBytes
	POP	BP
	POP	DS
	RET	8H
WinScrollRectangle ENDP

PURGE params, loc, localBytes
PURGE r1_tpl_x, r1_tpl_y, r1_ext_x, r1_ext_y
PURGE oldBP, oldDS, nearReturn
PURGE dir, distance, pRect
$EJECT

;**************************************************
;*                                                *
;* PROCEDURE WinCopyRectangle	                *
;*  (srcWindowID, dstWindowID: Word;              *
;*   VAR r: Rectangle;                            *
;*   newTopLeftX, newTopLeftY: Point);            *
;*                                                *
;**************************************************

; WinCopyCursorRectangle differs from WinCopyRectangle in that it just does
; the copy without checking to see if the cursor needs to be turned off
; before copying the rectangle.  It is ONLY used by the cursor routines.

params STRUC
  r1_tpl_x     DW ?	; local r1: Rectangle
  r1_tpl_y     DW ?
  r1_ext_x     DW ?
  r1_ext_y     DW ?

  r2_tpl_x     DW ?	; local r2: Rectangle
  r2_tpl_y     DW ?
  r2_ext_x     DW ?
  r2_ext_y     DW ?

  crsrIsCaller DW ?
;----------------
  oldBP        DW ?	; stack stuff
  oldDS        DW ?
  nearReturn   DW ?
;----------------
  ntl_y        DW ?
  ntl_x        DW ?
  pRect        DD ?
  dstWindow    DW ?
  srcWindow    DW ?
params ENDS

localBytes EQU 18
loc        EQU [BP-localBytes]
paramBytes EQU 12

WinCopyRectangle PROC NEAR
	XOR	AL, AL	; Entrypoint for non-cursor routines
	JMP	SHORT WinCopyRectangleRoutine

WinCopyCursorRectangle LABEL NEAR
	MOV	AL, 1	; Cursor routines are making the call

WinCopyRectangleRoutine:
	PUSH	DS
	PUSH	BP
	MOV	BP, SP
	SUB	SP, localBytes

	MOV	loc.crsrIsCaller, AX

	MOV	AX, CS:drawWindow	; AX has the current draw window
	XOR	BX, BX	; BX = 0 = "use draw window" window ID

	CMP	loc.srcWindow, BX	; If source window <> "use draw window"
	JNE	WinCopyRectSourceWinSet	; then use the source window specified

	MOV	loc.srcWindow, AX	; Use draw window as the source window

WinCopyRectSourceWinSet:
	CMP	loc.dstWindow, BX	; If dest window <> "use draw window"
	JNE	WinCopyRectDestWinSet	; then use the dest window specified

	MOV	loc.dstWindow, AX	; Use draw window as the dest window

WinCopyRectDestWinSet:
	PUSH	AX	; Save the current draw window

	LDS	SI, loc.pRect	; Move the VAR parameter rectangle to
	PUSH	SS	; a local on the stack.  Copy it twice.
	POP	ES
	LEA	DI, loc.r1_tpl_x
	CLD
	MOVSW
	MOVSW
	MOVSW
	MOVSW	; Copy rect to loc rect 1
	MOV	AX, loc.ntl_x
	STOSW
	MOV	AX, loc.ntl_y
	STOSW
	SUB	SI, 4	; Back up to extent pt of rect
	MOVSW
	MOVSW	; Copy rect's extent to loc rect 1

	MOV	AX, loc.srcWindow
	MOV	CS:drawWindow, AX
	LEA	AX, loc.r1_tpl_x
	PUSH	SS
	PUSH	AX
	CALL	WinClipRectangle	; Clip local copy of the source rectangle

	LDS	SI, loc.pRect	; DS:SI => original source rectangle

CheckLeftClippingSrc:
	MOV	AX, loc.r1_tpl_x
	SUB	AX, DS:[SI].rectTopLeftX
	JZ	CheckTopClippingSrc

	ADD	loc.ntl_x, AX
	ADD	loc.r2_tpl_x, AX
	SUB	loc.r2_ext_x, AX

CheckTopClippingSrc:
	MOV	AX, loc.r1_tpl_y
	SUB	AX, DS:[SI].rectTopLeftY
	JZ	CheckRightClippingSrc

	ADD	loc.ntl_y, AX
	ADD	loc.r2_tpl_y, AX
	SUB	loc.r2_ext_y, AX

CheckRightClippingSrc:
	MOV	AX, loc.r1_ext_x
	MOV	BX, DS:[SI].rectExtentX
	CMP	AX, BX
	JE	CheckBottomClippingSrc
	JL	ChkRtClipSrcGreater

	XCHG	AX, BX

ChkRtClipSrcGreater:
	MOV	loc.r1_ext_x, AX
	MOV	DS:[SI].rectExtentX, AX

CheckBottomClippingSrc:
	MOV	AX, loc.r1_ext_y
	MOV	BX, DS:[SI].rectExtentY
	CMP	AX, BX
	JE	EndClippingSrc
	JL	ChkBtClipSrcGreater

	XCHG	AX, BX

ChkBtClipSrcGreater:
	MOV	loc.r1_ext_y, AX
	MOV	DS:[SI].rectExtentY, AX

EndClippingSrc:
	MOV	AX, loc.dstWindow
	MOV	CS:drawWindow, AX
	LEA	AX, loc.r2_tpl_x
	PUSH	SS
	PUSH	AX
	CALL	WinClipRectangle	; Clip local copy of the dest rectangle

CheckLeftClippingDst:
	MOV	AX, loc.r2_tpl_x
	SUB	AX, loc.ntl_x
	JZ	CheckTopClippingDst

	ADD	loc.r1_tpl_x, AX
	SUB	loc.r1_ext_x, AX

CheckTopClippingDst:
	MOV	AX, loc.r2_tpl_y
	SUB	AX, loc.ntl_y
	JZ	CheckRightClippingDst

	ADD	loc.r1_tpl_y, AX
	SUB	loc.r1_ext_y, AX

CheckRightClippingDst:
	MOV	AX, loc.r1_ext_x
	MOV	CX, loc.r2_ext_x
	CMP	CX, AX
	JLE	CheckBottomClippingDst

	XCHG	CX, AX

CheckBottomClippingDst:
	MOV	AX, loc.r1_ext_y
	MOV	BX, loc.r2_ext_y
	CMP	BX, AX
	JLE	EndClippingDst

	XCHG	BX, AX

EndClippingDst:
	MOV	loc.r2_ext_x, CX	; Save clipped ext x for return rect
	MOV	loc.r2_ext_y, BX	; Save clipped ext y for return rect

	OR	CX, CX	; If extent x is zero or negative
	JLE	DontCopyTheRectangles	; then don't copy the rectangles

	OR	BX, BX	; If extent y is greater than zero
	JG	CopyTheRectangles	; then copy the rectangles

DontCopyTheRectangles:
	JMP	WinCopyRectExit	; Don't copy the rectangles

CopyTheRectangles:
	XOR	AL, AL	; Cursor was not turned off
	TEST	loc.crsrIsCaller, 1	; If Cursor routines are the callers
	JNZ	CopyRectsAfterCursorChk	; then don't call the cursor routines

	MOV	DS, loc.srcWindow
	MOV	CX, loc.r1_tpl_x	; left
	MOV	DX, loc.r1_tpl_y	; top
	MOV	SI, CX
	ADD	SI, loc.r2_ext_x
	DEC	SI	; right
	MOV	DI, DX
	ADD	DI, loc.r2_ext_y
	DEC	DI	; bottom
	CALL	CsrMaybeTurnCursorOff	; Turn off cursor if it overlaps rect 1
	OR	AL, AL	; If it was just turned off
	JNZ	CopyRectsAfterCursorChk	; then don't check if it overlaps rect 2

	MOV	DS, loc.dstWindow
	MOV	CX, loc.r2_tpl_x	; left
	MOV	DX, loc.r2_tpl_y	; top
	MOV	SI, CX
	ADD	SI, loc.r2_ext_x
	DEC	SI	; right
	MOV	DI, DX
	ADD	DI, loc.r2_ext_y
	DEC	DI	; bottom
	CALL	CsrMaybeTurnCursorOff	; Turn off cursor if it overlaps rect 2

CopyRectsAfterCursorChk:
	PUSH	AX	; Save whether cursor was turned off or not

	MOV	DS, loc.srcWindow
	MOV	AX, DS:wiWindowFlags	; Bit 0 of window flags
	AND	AX, 1	; contains the screen format

	PUSH	DS:wiDisplayAddr	; source screen location
	PUSH	DS:wiDisplayWidth	; source window info
	PUSH	DS:wiDisplayHeight	; source window info
	PUSH	AX	; screen format

	MOV	ES, loc.dstWindow
	MOV	AX, ES:wiWindowFlags	; Bit 0 of window flags
	AND	AX, 1	; contains the screen format

	PUSH	ES:wiDisplayAddr	; dest screen location
	PUSH	ES:wiDisplayWidth	; dest window info
	PUSH	ES:wiDisplayHeight	; dest window info
	PUSH	AX	; screen format

	MOV	AX, loc.r1_tpl_x
	ADD	AX, DS:wiBoundsTopLeftX
	PUSH	AX

	MOV	AX, loc.r1_tpl_y
	ADD	AX, DS:wiBoundsTopLeftY
	PUSH	AX

	MOV	AX, loc.r2_tpl_x
	ADD	AX, ES:wiBoundsTopLeftX
	PUSH	AX

	MOV	AX, loc.r2_tpl_y
	ADD	AX, ES:wiBoundsTopLeftY
	PUSH	AX

	PUSH	loc.r2_ext_x
	PUSH	loc.r2_ext_y
	XOR	AX, AX
	PUSH	AX	; mode
	CALL	GfxCopyRectangle

	POP	AX	; State of whether cursor was turned off
	OR	AL, AL	; If cursor was not turned off
	JZ	WinCopyRectExit	; then return

	CALL	CsrTurnCursorOn	; Turn cursor back on

WinCopyRectExit:
	LES	DI, loc.pRect
	PUSH	SS
	POP	DS
	LEA	SI, loc.r2_tpl_x	; DS:[SI] -> r2
	CLD
	MOVSW
	MOVSW
	MOVSW
	MOVSW	; Return the clipped rectangle

	POP	CS:drawWindow	; Restore the current draw window

	MOV	SP, BP
	POP	BP
	POP	DS
	RET	paramBytes
WinCopyRectangle ENDP

PURGE params, loc, localBytes, paramBytes
PURGE r2_tpl_x, r2_tpl_y, r2_ext_x, r2_ext_y
PURGE r1_tpl_x, r1_tpl_y, r1_ext_x, r1_ext_y
PURGE crsrIsCaller
PURGE oldBP, oldDS, nearReturn
PURGE srcWindow, dstWindow, pRect, ntl_x, ntl_y


CODE ENDS

     END
