; Doug's Programming Language  -- DPL, Version 2.22
; Copyright (c) 1988 Douglas S. Cody, All rights reserved.
;-----------------------------------------
; S H A D E  -- Open a shade on the screen
;
; Entry Conditions:
;	AX points to the control block
;
; Exit Conditions:
;	AL contains the choosen option number
;	AH contains the last key typed
;	Assume all working registers modified
;
; Screen Control Block:
;		DW	Starting row
;		DW	Starting column
;		DW	Ending column
;		DW	Number of entries in the table
;		DW	Video buffer backup buffer
;		DW	Border display attribute
;		DW	Box display Attribute
;		DW	Last option choosen
;		DW	Shade is opened
;		DW	1st string
;		:
;		DW	Xth string
;
SUBPGM	SHADE
;
; SHADE CONTROL BLOCK OFFSETS
;
SROW		EQU	0	; STARTING ROW
SCOL		EQU	2	; STARTING COLUMN
ECOL		EQU	4	; ENDING COLUMN
NUMENT		EQU	6	; NUMBER OF ENTRIES IN STRING LIST
VBOFF		EQU	8	; VIDEO BUFFER OFFSET
BDATT		EQU	10	; VIDEO BOARDER ATTRIBUTE
BXATT		EQU	12	; VIDEO BOX ATTRIBUTE
LSTOP		EQU	14	; LAST OPTION CHOOSEN BY OPERATOR
SHDFLG		EQU	16	; SHADE-IS-OPENED FLAG (0FFH=YES,00=NO)
STROFF		EQU	18	; START OF STRING LIST
;
; BOARDER CHARACTERS
;
LTC		EQU	218	; LEFT TOP CORNER
TPL		EQU	196	; TOP LINE
RTC		EQU	183	; RIGHT TOP CORNER
LVB		EQU	179	; LEFT VERTICAL BAR
RVB		EQU	186	; RIGHT VERITCAL BAR
LBC		EQU	212	; LEFT BOTTOM CORNER
BTL		EQU	205	; BOTTOM LINE
RBC		EQU	188	; RIGHT BOTTOM CORNER
;
; KEYBOARD SCAN CODES & MAIN KEY CODES
;
KEY_U		EQU	048H	; UPWARD ARROW KEY
KEY_L		EQU	04BH	; LEFT ARROW KEY
KEY_R		EQU	04DH	; RIGHT ARROW KEY
KEY_D		EQU	050H	; DOWNWARD ARROW KEY
KEY_ESC		EQU	01BH	; ESCAPE KEY
KEY_SP		EQU	020H	; SPACE KEY
KEY_CR		EQU	00DH	; CARRIAGE RETURN
;
;-----------------------------====< EXECUTION >====----------------------------
;
BEGIN	SHADE
	PUBLIC	SHADE, OPSHD, CLSHD
	EXTRN	VIDOFF:NEAR, VIDON:NEAR
;
	PUSH	DS			; SAVE THE CRITICALS
	PUSH	ES
	PUSH	SI
	PUSH	DI
;
	CALL	OPSHD			; OPEN THE SHADE ON THE SCREEN
;
	PUSH	AX
	CALL	SHDREG
;
	PUSH	ES			; SWAP SEGMENTS & POINTERS
	PUSH	DS
	POP	ES
	POP	DS
	XCHG	SI,DI			; ES:DI POINTS TO THE VIDEO BUFFER
;
	MOV	SI,AX			; SI POINTS TO THE CONTROL BLOCK
	ADD	DI,2			; MOVE PAST THE BOARDER
	SUB	CX,2			; DO NOT COUNT THE BOARDERS
	SUB	DX,2			; DITTO, SO...
	ADD	BX,4			; WE MUST ADJUST THE DISTANCE COUNT
	PUSH	DI			; BP+10 SAVE THE STARTING ADDRESS
	PUSH	CX			; BP+8  SAVE COLUMN WIDTH
	PUSH	DX			; BP+6  SAVE LINE COUNT
	PUSH	BX			; BP+4  SAVE DISTANCE TO NEXT LINE
	XOR	AX,AX
	PUSH	AX			; BP+2  SAVE CURRENT LINE #
	PUSH	BP			;   +0
	MOV	BP,SP
;
SHD_05:
	INKEY	,WAIT			; WAIT FOR TO CLOSE
	OR	AL,AL			; IS IT JUST A SCAN CODE?
	JNZ	SHD_06			; NO, USE THE MAIN BYTE
	MOV	AL,AH			; YES, SO WE WILL CHECK THE SCAN AS WELL
;
SHD_06:
	CMP	AL,KEY_SP		; SPACE BAR?
	JZ	SHD_15			; YES, ADVANCE THE PROMPT BAR
	CMP	AL,KEY_D		; DOWNWARD ARROW?
	JZ	SHD_15			; YES, ADVANCE THE PROMPT BAR
	CMP	AL,KEY_CR		; CARRIAGE RETURN?
	JZ	SHD_10			; NO, GO RE-ENTER THE KEY
	CMP	AL,KEY_U		; UPWARD ARROW KEY?
	JZ	SHD_20			; YES, MOVE THE BAR UPWARD
	CMP	AL,KEY_ESC		; ESCAPE?
	JZ	SHD_07			; YES, EXIT
	CMP	AL,KEY_L		; LEFT ARROW KEY?
	JZ	SHD_07			; YES, EXIT
	CMP	AL,KEY_R		; RIGHT ARROW KEY?
	JNZ	SHD_05			; NO, GO RE-ENTER THE KEY
;
SHD_07:
	MOV	WORD PTR [BP+2],00	; FLUSH THE LINE #
;
SHD_10:
	MOV	CX,[BP+2]		; GET THE LINE SELECTED
	POP	BP			; RESTORE THE CRITICAL
	ADD	SP,10			; TOSS OUT THE VARIABLES ON THE STACK
;
	POP	BX			; GET THE CONTROL BLOCK
;
	PUSH	AX			; SAVE THE LAST KEY
	MOV	[BX+LSTOP],CX		; SAVE IT
	MOV	AX,BX			; CLOSE THE SHADE NOW
	CALL	CLSHD
	POP	AX			; GET THE LAST KEY TYPED
;
	POP	DI
	POP	SI
	POP	ES
	POP	DS
	RETURN
;
SHD_15:
	CALL	REST_BAR		; REMOVE THE CURRENT BAR
	CALL	DOWN_BAR		; CREATE THE NEW BAR
	JMP	SHORT SHD_05		; & CONTINUE THE SELECTION
;
SHD_20:
	CALL	REST_BAR		; REMOVE THE CURRENT BAR
	CALL	UP_BAR			; MOVE THE BAR UPWARD
	JMP	SHORT SHD_05		; & CONTINUE WITH THE SELECTION
;
;
;=====================
;   ROUTINE SECTION
;	LEVEL 1
;=====================
;
;
;----------------------------------------
; C L S H D  --  Close the shade
;
; ENTRY CONDITIONS:
;	BP POINTS TO THE SCREEN CONTROL BLOCK IN THE STACK SEGMENT
;	EXTERNAL DS:CRTFLAG:BYTE
;		0 = MONOCHROME DISPLAY ADAPTER
;		1 = COLOR GRAPHICS ADAPTER
;
; EXIT CONDITIONS:
;	ES,DS,BP INDEX REGISTER UNMODIFIED
;	ASSUME ALL WORK REGISTERS MODIFIED
;
	PUBLIC	CLSHD
CLSHD	PROC
	PUSH	SI
	PUSH	DI
	PUSH	DS
	PUSH	ES
	PUSH	AX
;
; SETUP THE REGISTERS
;
	CALL	SHDREG
	PUSH	DS			; SWAP SEGMENTS
	PUSH	ES
	POP	DS
	POP	ES
	XCHG	SI,DI			; SWAP THE OFFSETS
;
; TURN OFF THE VIDEO
;
	CALL	VIDOFF
;
CLSHD_05:
	PUSH	CX			; SAVE THE COLUMN WIDTH
	REP	MOVSW			; MOVE ONE LINE
	ADD	DI,BX			; MOVE TO THE NEXT VIDEO RAM LOCATION
	POP	CX 
	DEC	DX			; HAVE WE MOVED IT ALL?
	JNZ	CLSHD_05		; NOT YET...
;
; TURN ON THE VIDEO
;
	CALL	VIDON
;
; RESTORE & EXIT
;
	POP	AX
	POP	ES
	POP	DS
;
; CLEAR THE OPENED FLAG
;
	MOV	SI,AX
	MOV	BYTE PTR [SI+SHDFLG],00	; CLEAR THE FLAG...
;
	POP	DI
	POP	SI
	RETURN

CLSHD ENDP
;
;
;----------------------------------------
; O P S H D  --  Open the video shade
;
; Entry conditions:
;	AX holds the control block offset
;
; Exit conditions:
;	ES,DS,BP,SI,DI registers unchanged
;	Assume all other registers trashed
;
	PUBLIC	OPSHD
OPSHD	PROC	NEAR
	PUSH	BP			; DO NOT DISTURB THE CRITICALS
	PUSH	SI
	PUSH	DI
;
	PUSH	DS
	PUSH	ES
;
	PUSH	AX			; + 16 SAVE THE BLOCK ADDRESS
;
; SETUP THE VIDEO-TO-BUFFER REGISTERS
;
	CALL	SHDREG			; SETUP THE REGISTERS
;
	PUSH	ES			; + 14 SAVE THE DATA SEGMENT
	PUSH	DS			; + 12  SAVE THE VIDEO SEGMENT
	PUSH	SI			; + 10  SAVE THE VIDEO RAM POINTER
	PUSH	DI			; + 8  SAVE THE VIDEO BACKUP BUFFER
	PUSH	BX			; + 6  SAVE THE DISTANCE COUNT
	PUSH	CX			; + 4  SAVE THE COLUMN COUNT
	PUSH	DX			; + 2  SAVE THE LINE COUNT
	PUSH	BP			; + 0  SAVE BP...
	MOV	BP,SP
;
; TURN OFF THE VIDEO
;
	CALL	VIDOFF			; NO REGISTERS ARE DISTURBED
;
OPSHD_05:
	REP	MOVSW			; MOVE THE ENTIRE LINE TO THE BUFFER
	MOV	CX,[BP+4]		; GET THE COLUMN COUNT
	ADD	SI,BX			; MOVE TO THE NEXT VIDEO POSITION
	DEC	DX			; ARE WE DONE?
	JNZ	OPSHD_05		; NO, CONTINUE THE BLOCK MOVE
;
	MOV	DI,[BP+10]		; POINT TO THE VIDEO BUFFER
	MOV	ES,[BP+12]		; & VIDEO SEGMENT
	MOV	DS,[BP+14]		; RESTORE THE DATA SEGMENT
	MOV	BX,[BP+16]		; GET THE CONTROL BLOCK ADDRESS
;
	MOV	DH,[BX+BDATT]		; FETCH THE BOARDER ATTRIBUTE (& CHEAT)
	MOV	AH,DH			; DH WILL HOLD THE BOARDER ATTRIBUTE
	MOV	AL,LTC			; LEFT TOP CORNER
	STOSW				; SAVE IT IN RAM
	SUB	WORD PTR [BP+4],2	; WE DON'T NEED THE BOARDER COUNT
	MOV	CX,[BP+4]		; GET THE COLUMN WIDTH
	JCXZ	OPSHD_10
	MOV	AL,TPL
	REP	STOSW			; GIVE THE ENTIRE LINE
;
OPSHD_10:
	MOV	AL,RTC
	STOSW				; STORE RIGHT TOP CORNER
;
	SUB	WORD PTR [BP+2],2	; WE DON'T NEED TO KNOW ABOUT THE BOARDER
	MOV	DL,[BX+BXATT]		; DL HOLDS THE BOX ATTRIBUTE (& CHEAT)
	ADD	BX,STROFF		; POINT TO THE STRING LIST
;
	CMP	WORD PTR [BP+2],00	; ANY LINES FOR THE BOX?
	JZ	OPSHD_32		; NO, GO CLOSE THE BOX
;
OPSHD_15:
	ADD	DI,[BP+6]		; MOVE TO THE NEXT LINE
	MOV	AH,DH			; FETCH THE BOARDER ATTRIBUTE
	MOV	AL,LVB
	STOSW				; PLACE THE VERTICAL BAR
	MOV	SI,[BX]			; GET THE NEXT LINE ADDRESS
	ADD	BX,2			; ADVANCE THE BLOCK POINTER
	MOV	AH,DL			; GET THE BOX ATTRIBUTE
	MOV	CX,[BP+4]		; FETCH THE COLUMN WIDTH
	JCXZ	OPSHD_30		; DON'T DO NULL WIDTH
	TEST	BYTE PTR [SI],80H	; IS IT 8 BIT ASCII?
	JZ	OPSHD_20		; NO, SKIP IT
	LODSB				; FETCH THE CHARACTER AS THE ATTRIBUTE
	MOV	AH,7FH			; TRIM THE 8TH BIT
	AND	AH,AL
;
OPSHD_20:
	LODSB				; FETCH THE NEXT CHARACTER
	OR	AL,AL			; END OF STRING?
	JZ	OPSHD_25		; YES, CONTINUE ON...
	STOSW				; NO, SAVE THE CHAR & ATTR
	LOOP	OPSHD_20		; DO UNTIL STRING IS DONE
	JMP	SHORT OPSHD_30		; GO DO THE NEXT STRING
;
OPSHD_25:
	REP	STOSW			; DO THE REST OF THE STRING
;
OPSHD_30:
	MOV	AH,DH			; FETCH THE BOARDER ATTRIBUTE
	MOV	AL,RVB			; RIGHT VERTICAL BAR
	STOSW				; PLACE THE VERTICAL BAR
;
	DEC	WORD PTR [BP+2]		; DECREMENT THE LINE COUNT
	JNZ	OPSHD_15		; DO THE REST OF THE STRINGS
;
OPSHD_32:
	ADD	DI,[BP+6]		; MOVE TO THE LAST LINE
	MOV	AH,DH			; FETCH THE BOARDER ATTRIBUTE
	MOV	AL,LBC			; LEFT BOTTOM CORNER
	STOSW				; SAVE IT IN RAM
	MOV	CX,[BP+4]		; GET THE COLUMN WIDTH
	JCXZ	OPSHD_35
	MOV	AL,BTL			; BOTTOM LINE
	REP	STOSW			; GIVE THE ENTIRE LINE
;
OPSHD_35:
	MOV	AL,RBC			; RIGHT BOTTOM CORNER
	STOSW				; WRITE	THE LAST CHARACTER
;
; TURN ON THE VIDEO
;
	CALL	VIDON 
;
; RETURN TO CALLING PROGRAM
;
	ADD	SP,16			; DEFRAME THE STACK

	POP	AX			; SAVE THE CONTROL BLOCK POINTER
	POP	ES
	POP	DS
;
; SET THE OPENED FLAG
;
	MOV	SI,AX
	MOV	BYTE PTR [SI+SHDFLG],0FFH	; SET THE FLAG...
;
	POP	DI
	POP	SI
	POP	BP
	RET

OPSHD	ENDP
;
;
;----------------------------------------
; DOWN_BAR  --  MOVE THE OPTION BAR DOWNWARD
;
DOWN_BAR PROC	NEAR
	INC	WORD PTR [BP+2]		; INCREMENT THE CURRENT LINE #
	MOV	AX,[BP+2]		; GET THE CURRENT LINE
	MOV	CX,[BP+8]		; GET THE COLUMN COUNT
	ADD	DI,CX			; MOVE TO THE END OF THE LINE
	ADD	DI,CX			; (ACCOUNT FOR ATTRIBUTES)
	ADD	DI,[BP+4]		; MOVE TO THE NEXT LINE DOWN
	CMP	AX,[BP+6]		; ARE WE AT THE END?
	JLE	DNBR_05			; NO, CONTINUE ON...
	MOV	WORD PTR [BP+2],00	; YES, CLEAR OUT THE CURRENT LINE
	MOV	DI,[BP+10]		; AND POINT TO THE START...
	RETURN
;
DNBR_05:
	CMP	BYTE PTR ES:[DI],00	; IS THE 1ST CHARACTER A NULL?
	JZ	DOWN_BAR		; YES, SKIP THIS LINE...
	MOV	AL,[SI+BXATT]		; GET THE BOX ATTRIBUTE
	CMP	ES:[DI+1],AL		; IS THE ATTRIBUTE THE SAME?
	JNZ	DOWN_BAR		; NO, SKIP THIS LINE
	PUSH	DI			; DO NOT DISTURB THE STARTING ADDR
;
DNBR_10:
	INC	DI			; MOVE PAST THE CHARACTER
	XOR	BYTE PTR ES:[DI],0FFH	; REVERSE THE ATTRIBUTE
	INC	DI
	LOOP	DNBR_10			; CONTINUE TILL DONE...
	POP	DI
	RETURN

DOWN_BAR	ENDP
;
;
;---------------------------------------
; R E S T _ B A R  --  RESTORE THE BAR ON THE SCREEN
;
;
REST_BAR PROC	NEAR
	MOV	AX,[BP+2]		; GET THE CURRENT LINE #
	OR	AX,AX			; IS IT THE NULL LINE?
	JZ	RSTBR_10		; YES, EXIT
	PUSH	DI			; SAVE THE CURRENT RAM PTR
	MOV	CX,[BP+8]		; GET THE COLUMN COUNT
;
RSTBR_05:
	INC	DI			; MOVE PAST THE CHARACTER
	XOR	BYTE PTR ES:[DI],0FFH	; RESTORE THE ATTRIBUTE
	INC	DI			; MOVE PAST THE ATTRIBUTE
	LOOP	RSTBR_05		; DO THE WHOLE LINE
	POP	DI
;
RSTBR_10:
	RETURN

REST_BAR	ENDP
;
;
;----------------------------------------
; UP_BAR  --  MOVE THE OPTION BAR UPWARD
;
UP_BAR	PROC	NEAR
	CMP	WORD PTR [BP+2],00	; ARE WE AT THE TOP?
	JNZ	UPBR_05			; NO, CONTINUE ON...
	MOV	AX,[BP+6]		; YES, MOVE TO THE BOTTOM
	INC	AX
	MOV	[BP+2],AX
;
; CALCULATE THE BOTTOM ROW
;
	MOV	CX,AX
;
UPBR_02:
	ADD	DI,[BP+4]		; MOVES TO THE NEXT LINE
	ADD	DI,[BP+8]		; ADD IN THE BOX WIDTH
	ADD	DI,[BP+8]
	LOOP	UPBR_02
;
UPBR_05:
	SUB	DI,[BP+4]		; MOVE BACK TO THE PREVIOUS LINE
	SUB	DI,[BP+8]
	SUB	DI,[BP+8]
	DEC	WORD PTR [BP+2]		; DECREMENT THE CURRENT LINE #
	JZ	UPBR_15			; EXIT IF AT 0
	MOV	CX,[BP+8]		; GET THE COLUMN COUNT
	CMP	BYTE PTR ES:[DI],00	; IS THE 1ST CHARACTER A NULL?
	JZ	UP_BAR			; YES, SKIP THIS LINE...
	MOV	AL,[SI+BXATT]		; GET THE BOX ATTRIBUTE
	CMP	ES:[DI+1],AL		; IS THE ATTRIBUTE THE SAME?
	JNZ	UP_BAR			; NO, SKIP THIS LINE
	PUSH	DI			; DO NOT DISTURB THE STARTING ADDR
;
UPBR_10:
	INC	DI			; MOVE PAST THE CHARACTER
	XOR	BYTE PTR ES:[DI],0FFH	; REVERSE THE ATTRIBUTE
	INC	DI
	LOOP	UPBR_10			; CONTINUE TILL DONE...
	POP	DI
;
UPBR_15:
	RETURN

UP_BAR	ENDP
;
;
;=====================
;   ROUTINE SECTION
;	LEVEL 2
;=====================
;
;
; S H D R E G  --  SETUP THE PROPER REGISTERS
;
; Entry conditions:
;	DS:AX holds the video control block
; Exit conditions:
;	ES points to data segment
;	DS points to video segment
;	SI points to start of video buffer
;	DI points to the buffer
;	CX holds the length
;	DX holds the # of lines to move
;	BX holds the count of (80-cx)*2
;	AX holds the video control block address
;
	PUBLIC	SHDREG
SHDREG	PROC	NEAR
	PUSH	AX
	MOV	AH,0FH
	INT	10H			; GET THE VIDEO PAGE
	MOV	CX,0B000H		; MONO SEGMENT
	TEST	[CRTFLAG],01		; MONO CARD?
	JZ	VBSU_05			; YES, CONTINUE ON...
	MOV	CX,0B800H		; NO, SETUP FOR CGA
;
VBSU_05:
	XCHG	BH,BL
	SUB	BH,BH			; BX HOLDS THE PAGE #
	MOV	AX,1000H		; AX HOLDS THE FULL PAGE SIZE
	MUL	BX			; AX HOLDS THE PAGE STARTING ADDR
	MOV	SI,AX
	POP	BX			; GET THE CONTROL BLOCK ADDRESS
	MOV	AX,[BX+SROW]
	MOV	DX,80*2
	MUL	DX			; AX = ROW * 80*2
	ADD	SI,AX
	ADD	SI,[BX+SCOL]		; ADD IN THE COLUMNS
	ADD	SI,[BX+SCOL]		; ..TWICE FOR DOUBLE BYTE STORAGE
	MOV	DX,[BX+NUMENT]		; GET THE NUMBER OF LINE OF TEXT
	ADD	DX,2			; ADJUST FOR BOX
	MOV	DI,[BX+VBOFF]		; GET THE BUFFER ADDRESS
	PUSH	DS
	POP	ES			; ES = DATA SEGMENT
	MOV	DS,CX			; DS = VIDEO SEGMENT
	MOV	CX,ES:[BX+ECOL]		; CALC THE NUMBER OF COLUMNS
	SUB	CX,ES:[BX+SCOL]
	INC	CX			; CX HOLDS THE TOTAL COLUMNS
	MOV	AX,BX			; MAKE SURE AX HOLDS THE BLOCK ADDRESS
	MOV	BX,80			; CALC THE DISTANCE TO THE START OF
	SUB	BX,CX			; THE NEXT LINE
	SHL	BX,1			; BX = BX * 2
	RETURN

SHDREG	ENDP
;
ENDPGM	SHADE
;
