PUBLIC	SwitchWindow, ToggleNumWindows, SelectBuffer, BufToggle, InitWIndows

PUBLIC	WindowStart, WindowEnd, WindowStartLine		; for pure screens
PUBLIC	NumWinsScr,					; for fns like C-V
PUBLIC	ActiveBuffer, ActiveWindow			; for modeline
PUBLIC	Separatorline
PUBLIC	CBuffer1

EXTRN	$Buffer1:Word, $Buffer2:Word, $BufferNumber:Word
EXTRN	.Error0:Near, .Msg:Near, .Screen:Near, Sound:NEAR, .InCH:Near
EXTRN	.CLRMsg:NEAR
;---------------------------------------------------------------------------
	Page ,132
NAME Windows

TITLE Windows and Buffers

INCLUDE        FDEF.DEF


;---------------------------------------------------------------------------
Program        SEGMENT PARA    PUBLIC  'code'
       ASSUME  CS:Program, DS:Program, ES:Program, SS:Program

;...........................................................................

ActiveBuffer	dw	0	; buffer = [0,1...9]		; PUBLIC

Windowstart	dw	Line0		; [0 , 11*160]		; PUBLIC
Windowend	dw     TextLastLine*160	; [9*160 , 19*160]	; PUBLIC

WindowStartLine	dw	0	; used to position cursor	; PUBLIC
NumWinsScr	dw	0	; used to calculate C-V etc	; PUBLIC



ActiveWindow	db	0	; window = [0,1]	; PUBLIC

CBuffer1	dw	0
CBuffer2	dw	0
PBuffer1	dw	0
PBuffer2	dw	0
CBSeg1		dw	0	; just for easier access
CBSeg2		dw	0
PBSeg1		dw	0
PBSeg2		dw	0

OneBufMsg	db	'*** Only One Buffer ***'
UserAbortMsg	db	'*** User Abort ***'
ChooseBuffer	db	'Choose new Buffer: '
WelcomeMsg	db	'Available Buffers:', 0
BuffernumberMsg	db	'1)  ', 0
ByeMsg		db	'----------------------------------------', 0

CURSOR	MACRO	X, Y
	mov	AH, 2
	mov	BH, 0
	mov	DX, X*256+Y
	int	BIOS
ENDM

;---------------------------------------------------------------------------
InitWindows	PROC	NEAR

	mov	CS:ActiveWindow, Win1
	mov	CS:ActiveBuffer, 0

	mov	CS:CBuffer1, 0
	mov	CS:CBuffer2, 1
	mov	CS:PBuffer1, 1
	mov	CS:PBuffer2, 0

	mov	AX, CS:$Buffer1			; init windows
	mov	DS, AX
	mov	CS:CBSeg1, AX
	mov	CS:PBSeg2, AX

	mov	AX, CS:$Buffer2

	mov	CS:CBSeg2, AX
	mov	CS:PBSeg1, AX
	ret
InitWindows	ENDP
;---------------------------------------------------------------------------
; ToggleNumWindows
;
;	FN:	toggles the number of windows on the screen, leaves the
;		cursor in the active window.
;
;	OUT:	NumWinsScr:	New Value
;		WindowStart:	New Value
;		WindowEnd:	New Value
;		WindowStartLine:New Value

ToggleNumWindows	PROC	NEAR

	xor	CS:NumWinsScr, Toggle
	cmp	CS:NumWinsScr, OneWindow
	je	To1Window

To2Windows:
	call	SwitchWindow			; this will split up one
	call	.Screen				; display it
	call	SwitchWindow
	call	SeparatorLine
	ret

To1Window:
	mov	CS:WindowStart, Line0
	mov	CS:WindowStartLine, 0
	mov	CS:WindowEnd, Line0+FullScreen
	ret

ToggleNumWindows	ENDP

;---------------------------------------------------------------------------
; SwitchWindow:
;
;	FN:	switches to the other buffer, if both windows edit an
;		identical buffer, we need to arrange a few special things.
;
;	OUT:	ActiveWindow:	New Value
;		DS:		new Buffer Segment
;		Aux*:		to reflect concurrent editing
;
SwitchWindow	PROC	NEAR

	xor	CS:ActiveWindow, Toggle

	mov	AX, CS:CBuffer1
	cmp	AX, CS:CBuffer2
	jne	DifferentBuffers

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
IdenticalBuffers:			; if W1[Buffer]=W2[Buffer]
	mov	AX, DS:BCB.AuxScrStart	; xchg Screen Starts
	xchg	AX, DS:BCB.ScrStart
	mov	DS:BCB.AuxScrStart, AX

	mov	AX, DS:BCB.AuxCursor	; and xchg Cursors
	xchg	AX, DS:BCB.FCursor
	mov	DS:BCB.AuxCursor, AX

	mov	AX, DS:BCB.FCursor		; if we have edited the Window
	cmp	AX, DS:BCB.FEnd			; such that the cursor would
	ja	ResetCursor 			; be further than the end of
						; file...

	mov	BX, AX				; if we are on a LF, move back
	cmp	Byte Ptr DS:[BX], LF		; to the CR
	jne	SwitchScreen
	dec	DS:BCB.FCursor
	jmp	SwitchScreen			; and update screen

ResetCursor:
	mov	AX, DS:BCB.FEnd
	mov	DS:BCB.FCursor, AX
	jmp	SwitchScreen


;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
DifferentBuffers:

	cmp	CS:ActiveWindow, Win1		; which window is active ?
	je	Switchto1

Switchto2:
	mov	DS, CS:CBSeg2
	mov	AX, CS:CBuffer2
	mov	CS:ActiveBuffer, AX
	jmp	SwitchScreen

Switchto1:
	mov	DS, CS:CBSeg1
	mov	AX, CS:CBuffer1
	mov	CS:ActiveBuffer, AX
	jmp	SwitchScreen

;...........................................................................
SwitchScreen:
	cmp	CS:NumWinsScr, OneWindow	; if we presently have only
	jne	SS2				; one Window,

SS1:	mov	CS:WindowStart, Line0		; there is just one window
	mov	CS:WindowStartLine, 0		; displayed
	mov	CS:WindowEnd, Line0+FullScreen
	ret

SS2:	mov	CS:WindowStart, Line0		; there are two windows displ.
	mov	CS:WindowStartLine, 0

	cmp	CS:ActiveWindow, Win2		; find out the start of the
	jne	SS2C				; Window ( either l0 or l10 )
	mov	CS:WindowStart, Line10		; bottom window
	mov	CS:WindowStartLine, 10

SS2C:	mov	AX, CS:WindowStart		; top window
	add	AX, HalfScreen
	mov	CS:WindowEnd, AX
	ret

SwitchWindow	ENDP

;---------------------------------------------------------------------------
; SelectBuffer:
;
;	FN:	switches the active buffer in window n to be the previous
;		buffer, and assigns a new one
;
;		Note that at exit time I always draw a Separatorline: if
;		there should be none, the screen update will erase it
;		quickly!
;
SelectBuffer	PROC	NEAR

	call	TellBuffers

	call	.CLRMsg
	mov	SI, Offset ChooseBuffer
	mov	CX, 19
	call	.Msg

Wait:	call	.Inch
	jz	Wait

	cmp	AL, CTL_G
	je	UserAbort

	cmp	AL, CR
	je	Userequal

	sub	AL, '1'
	sub	AH, AH

	cmp	AX, CS:$BufferNumber
	jb	Foundnewbuffer
	call	Sound
	jmp	Wait
UserAbort:
	call	Separatorline			; without check for double !
	mov	SI, Offset USERABORTMSG
	mov	CX, 18
	jmp	.Error0
Userequal:
	call	Separatorline			; without check for double !
	ret

FoundNewBuffer:
	mov	CX, AX				; this will be the new number
	cmp	CX, CS:ActiveBuffer
	jne	FNB1
	call	Separatorline			; without check for double !
	jmp	.CLRMsg

FNB1:	add	AX, AX
	add	AX, Offset $Buffer1		; this will be the new segment
	mov	BX, AX				; to convince the assembler
	mov	DX, CS:[BX]

	cmp	CS:ActiveWindow, Win1		; and it goes into window n
	je	WithWindow1

WithWindow2:
	push	cx
	call	Separatorline
	pop	cx
	mov	AX, CS:CBuffer2
	mov	CS:PBuffer2, AX

	mov	AX, CS:CBSeg2
	mov	CS:PBSeg2, AX

	mov	CS:CBuffer2, CX
	mov	CS:ActiveBuffer, CX
	mov	CS:CBSeg2, DX
	mov	DS, DX
	jmp	.CLRMsg

WithWindow1:
	push	cx
	call	Separatorline
	pop	cx
	mov	AX, CS:CBuffer1
	mov	CS:PBuffer1, AX

	mov	AX, CS:CBSeg1
	mov	CS:PBSeg1, AX

	mov	CS:CBuffer1, CX
	mov	CS:ActiveBuffer, CX

	mov	CS:CBSeg1, DX
	mov	DS, DX
	jmp	.CLRMsg
SelectBuffer	ENDP

;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
; simply exchanges the previous and the current buffer
;
BufToggle	PROC	Near

	cmp	CS:$Buffernumber, 1
	jbe	BTError

	mov	AL, CS:ActiveWindow		; now check which Window
	cmp	AL, Win1			; we are currently in
	je	UpdateWin1

UpdateWin2:
	mov	AX, CS:CBSeg2			; exchange the buffer segment
	xchg	AX, CS:PBSeg2
	mov	CS:CBSeg2, AX
	mov	DS, AX

	mov	AX, CS:CBuffer2			; exchange the buffer name
	xchg	AX, CS:PBuffer2
	mov	CS:CBuffer2, AX
	mov	CS:ActiveBuffer, AX
	ret


UpdateWin1:
	mov	AX, CS:CBSeg1			; exchange the buffer segment
	xchg	AX, CS:PBSeg1
	mov	CS:CBSeg1, AX
	mov	DS, AX

	mov	AX, CS:CBuffer1			; exchange the buffer name
	xchg	AX, CS:PBuffer1
	mov	CS:CBuffer1, AX
	mov	CS:ActiveBuffer, AX
	ret

BTError:
	mov	CX, 23
	mov	SI, Offset OneBufMsg
	jmp	.Error0

BufToggle	ENDP
;---------------------------------------------------------------------------
SeparatorLine	PROC	NEAR
	mov	AX, ScreenSegment
	mov	ES, AX
	mov	DI, HalfScreen+2
	mov	AX, Modelinecolor*256+'-'
	mov	CX, 80
	rep	stosw
	ret
SeparatorLine	ENDP
;---------------------------------------------------------------------------
TellBuffers	PROC	NEAR

	mov	CS:StartofPrint, 0
	mov	CS:StartofPrintColumn, 0
	call	SwitchNormal

	push	DS

	mov	SI, Offset WelcomeMsg
	call	PRINTCS
	call	PRINTCR
	sub	DX, DX
	call	PRINTCR
	CURSOR	20, 19

	mov	BX, 0
	mov	CX, CS:$Buffernumber

TBLoop:	mov	DS, CS:[BX+Offset $Buffer1]
	shr	BX, 1
	mov	AX, BX
	add	BX, BX
	add	BX, 2
	push	AX
	cmp	AX, CS:ActiveBuffer
	je	SWI
	call	SwitchNormal
	jmp	TBL1
SWI:	call	SwitchInverse

TBL1:	pop	AX
	add	AL, '1'
	mov	CS:BuffernumberMsg, AL
	mov	SI, Offset BuffernumberMsg
	call	PRINTCS

	mov	AL, DS:BCB.Dirty
	cmp	AL, TRUE
	je	PNS
	mov	SI, Offset Saved
	jmp	TBL2
PNS:	mov	SI, Offset NotSaved
TBL2:	call	PrintCS

	mov	SI, Offset BCB.FIle
	call	PrintDS
	call	PrintCR
	loop	TBLoop
	pop	DS

	call	SwitchNormal
	mov	SI, Offset ByeMsg
	call	PRINTCS
	call	PRINTCR
	ret
TellBuffers	ENDP

;---------------------------------------------------------------------------
StartofPrint		dw	0
StartofPrintColumn	dw	0
PrintColor		db	0
Saved			db	' [Saved]::     ', 0
NotSaved		db	'*[Changed]::   ', 0

; IN:	SI -> ASCIZstring
;	CS:StartofPrint, 0
;	CS:PrintColumn, 0
PrintCS	PROC	NEAR

	push	AX
	push	DI
	push	SI
	push	DX
	push	CX

	mov	AX, ScreenSegment
	mov	ES, AX

	mov	DI, CS:StartofPrint
	mov	DX, CS:StartofPrintColumn

PLCS:	lods	Byte Ptr CS:[SI]
	cmp	AL, 0
	je	PrCS1
	mov	AH, CS:PrintColor
	stosw
	inc	DX
	jmp	PLCS

PrCS1:	mov	AL, ' '
	mov	AH, CS:Printcolor
	stosw
	stosw
	add	DX, 2
	mov	CS:StartOfPrint, DI
	mov	CS:StartOfPrintCOlumn, DX
	pop	CX
	pop	DX
	pop	SI
	pop	DI
	pop	AX
	ret

PrintCS	ENDP
;---------------------------------------------------------------------------

PrintDS	PROC	NEAR

	push	AX
	push	DI
	push	SI
	push	DX
	push	CX

	mov	AX, ScreenSegment
	mov	ES, AX

	mov	DI, CS:StartofPrint
	mov	DX, CS:StartofPrintColumn

PLDS:	lods	Byte Ptr DS:[SI]
	cmp	AL, 0
	je	PrDS1
	mov	AH, CS:PrintColor
	stosw
	inc	DX
	jmp	PLDS

PrDS1:	mov	AX, ' '+nocolor*256
	stosw
	stosw
	add	DX, 2
	mov	CS:StartOfPrint, DI
	mov	CS:StartOfPrintCOlumn, DX
	pop	CX
	pop	DX
	pop	SI
	pop	DI
	pop	AX
	ret

PrintDS	ENDP
;---------------------------------------------------------------------------
PRINTCR	PROC	NEAR

	mov	AX, ScreenSegment
	mov	ES, AX

	mov	AX, ' '+nocolor*256

	mov	DI, CS:StartofPrint
	mov	DX, CS:StartofPrintColumn

PRCRL:	stosw
	inc	DX
	cmp	DX, 80
	jne	PRCRL

	mov	CS:StartofPrintColumn, 0
	mov	CS:StartofPrint, DI
	ret
PRINTCR	ENDP
;---------------------------------------------------------------------------
SwitchInverse	PROC	NEAR
	mov	CS:PrintColor, Inverse
	ret
SwitchInverse	ENDP
SwitchNormal	PROC	NEAR
	mov	CS:Printcolor, Nocolor
	ret
SwitchNormal	ENDP



;---------------------------------------------------------------------------
	PROGRAM	ENDS
END
