home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
modula2
/
library
/
fst
/
qvideo
/
qvideo.mod
< prev
Wrap
Text File
|
1987-11-20
|
27KB
|
840 lines
IMPLEMENTATION MODULE QVideo;
(*
Screen routines supporting windows for Fitted Software Tools Modula-2.
In the public domain - MS/PC-DOS CGA, mono, Hercules (TM) compat.
For ease of use, everything's a CARDINAL (if it's not an ARRAY OF CHAR)
and no pointers need be used.
All columns and rows in procedure calls are in 1-80, 1-25 format
in col, row order. Col and row are always the last parameters in a call
that includes them.
A number of procedures have defaults which are employed when the
parameter(s) passed = 0.
*)
FROM SYSTEM IMPORT ASSEMBLER, OFS, SEG, ADDRESS, ADR;
FROM Strings IMPORT Length;
(*
C O N T E N T S
ClrScr, ClrEOL, SetAttrib, GetAttrib
GotoXY, GetXY, QWrite, QWriteString
KeyScan, ScreenBuffer, WriteBuffer
CursorOn, CursorOff, Frame
ScrollUp, ScrollDn
plus a prototype window at the end of the file
*)
(****************************** ClrScr ********************************)
PROCEDURE ClrScr (attrib : CARDINAL);
(* clear the whole screen, home cursor *)
(* if attrib is 0, it uses normal white on black *)
(* usage:
;
; ClrScr (0);
; WriteString ("I'm at the top left of a new, otherwise empty screen.");
*)
CONST norm = 7;
VAR atr : CARDINAL;
BEGIN
IF (attrib = 0) THEN (* if 0, use default attribute *)
attrib := norm;
END;
SetAttrib (attrib, 1, 1); (* see procedure below *)
ScrollUp (0, 80, 25, 1, 1); (* see " " *)
GotoXY (1, 1); (* see " " *)
END ClrScr;
(****************************** ClrEOL *******************************)
PROCEDURE ClrEOL;
(* clear line from cursor to end, using attribute at cursor x,y *)
(* cursor stays at starting position *)
(* usage:
;
; GotoXY (1, 10); (* 10 rows down the screen at left of screen *)
; WriteString ("This is a sentence about frogs.");
; GotoXY (26, 10); (* same row at column 26 - the beginning of "frogs." *)
; ClrEOL; (* cursor is still at 26, 10 *)
; WriteString ("bogs.");
; (* results in: This is a sentence about bogs. *)
*)
VAR
col, row, atr : CARDINAL;
BEGIN
GetXY (col, row);
GetAttrib (atr, col, row);
DEC (col);
DEC (row); (* adjust to 0-79, 0-24 format *)
ASM (* BEGIN *)
MOV AL,32 (* put space char in AL *)
MOV BL,atr (* put returned attribute into BL *)
MOV DL,col (* put row and column in DX *)
MOV DH,row
MOV CX,80 (* default number of columns *)
SUB CL,DL (* adjust by subtracting columns up to cursor position *)
MOV AH,9 (* func 9 = write at cursor for CX spaces *)
INT 10H (* call video handler *)
END; (* ASM *)
INC (col); (* back to 1-80, 1-25 format *)
INC (row);
GotoXY (col, row);
END ClrEOL;
(************************* SetAttrib *******************************)
PROCEDURE SetAttrib (attrib, col, row : CARDINAL);
(* set the attribute for the character at specified column, row *)
(* cursor will still be where it was before call *)
(* usage:
;
; CONST ReverseVideo = 112;
; NormalVideo = 7;
;
; ClrScr (0); (* homes cursor *)
; WriteString ("This x is in reverse video.");
; SetAttrib (ReverseVideo, 6, 1);
*)
VAR CurrentCol, CurrentRow : CARDINAL;
BEGIN
GetXY (CurrentCol, CurrentRow);
GotoXY (col, row);
ASM (* BEGIN *)
MOV AH,8 (* func 8 = get char, etc. at current position *)
MOV BH,0 (* page *)
INT 10H (* call video handler *)
MOV AH,9 (* func 9 = write char and attrib *)
(* current char is already in AL *)
MOV BL,attrib
MOV BH,0 (* page *)
MOV CX,1 (* write CX times *)
INT 10H (* call video handler *)
END; (* ASM *)
GotoXY (CurrentCol, CurrentRow);
END SetAttrib;
(************************* GetAttrib *******************************)
PROCEDURE GetAttrib (VAR attrib : CARDINAL; col, row : CARDINAL);
(* get the attribute for the char at specified column, row *)
(* cursor will still be where it was before call *)
(* usage:
;
; VAR attribute, row, column, I : CARDINAL;
; BEGIN
; ..... (* write to line 1 *)
; row := 1;
; FOR I := 1 TO 80 DO
; GetAttrib (attribute, I, row);
; IF attribute = 112 THEN (* 112 is reverse video *)
; SetAttrib (7, I, row) (* 7 is normal video *)
; END;
; END;
; GotoXY (1, 2);
; WriteString ("There are now no reverse characters on line one!");
;
*)
VAR LocalAttrib, CurrentCol, CurrentRow : CARDINAL;
BEGIN
GetXY (CurrentCol, CurrentRow);
GotoXY (col, row);
ASM (* BEGIN *)
MOV BH,0 (* page *)
MOV AH,8 (* func 8 = get current attribute, etc. *)
INT 10H (* call video handler *)
XOR BX,BX (* clear BX for byte to int conversion *)
MOV BL,AH (* put returned attribute into attrib *)
MOV LocalAttrib,BX
END; (* ASM *)
attrib := LocalAttrib;
GotoXY (CurrentCol, CurrentRow);
END GetAttrib;
(**************************** GotoXY *********************************)
PROCEDURE GotoXY (col, row : CARDINAL);
(* locate cursor - column and row start at 1, not 0 *)
(* usage:
;
; GotoXY (1, 1);
; WriteString ("x marks column 1, row 1 - the top left of the screen.");
; GotoXY (1, 12);
; WriteString ("z marks column 1, row 12 - half way down the screen at left");
*)
VAR
BEGIN
DEC (col); (* adjust to 0-79, 0-24 format *)
DEC (row);
ASM (* BEGIN *)
MOV AH,2 (* func 2 = set cursor position *)
MOV BH,0 (* page *)
MOV DH,row (* put row and col in DX *)
MOV DL,col
INT 10H (* call video handler *)
END; (* ASM *)
END GotoXY;
(******************************* GetXY *******************************)
PROCEDURE GetXY (VAR col, row : CARDINAL);
(* get current cursor location *)
(* usage:
;
; VAR CurrentColumn, CurrentRow : CARDINAL;
; BEGIN
; ClrScr (0);
; WriteString ("123456789");
; GetXY (CurrentColumn, CurrentRow);
; WriteLn;
; WriteString ("After printing the numbers, the cursor was at column ");
; WriteCard (CurrentColumn, 2);
; WriteString (" and row ");
; WriteCard (CurrentRow, 2);
; GotoXY (CurrentColumn, CurrentRow);
; WriteString ("x marks the spot.");
; GotoXY (CurrentColumn, CurrentRow);
; ....
*)
VAR LocalCol, LocalRow : CARDINAL;
BEGIN
ASM (* BEGIN *)
MOV AH,3 (* func 3 = read cursor position *)
MOV BH,0 (* page *)
INT 10H (* call video handler *)
XOR AX,AX (* clear HIGH bits *)
MOV AL,DL (* put col byte in low part of AX *)
MOV LocalCol,AX
(* now col is getting an integer *)
MOV AL,DH (* do the same with the row byte *)
MOV LocalRow,AX
(* row also gets an integer *)
END; (* ASM *)
col := LocalCol + 1; (* adjust to 1-80, 1-25 format *)
row := LocalRow + 1;
END GetXY;
(****************************** QWrite *******************************)
PROCEDURE QWrite (ch : CHAR; attrib, col, row : CARDINAL);
(* Write a CHAR - does NOT advance cursor *)
(* if attrib is 0 it uses current attribute at cursor position *)
(* attribute can be pre-set with SetAttrib using the same col,row *)
VAR atr : CARDINAL;
BEGIN
DEC (col); (* convert to 0-79, 0-24 format *)
DEC (row);
ASM (* BEGIN *)
MOV AH,2 (* func 2 = set cursor position *)
MOV BH,0 (* page *)
MOV DL,col (* set to desired column *)
MOV DH,row (* and desired row *)
INT 10H (* call video handler *)
MOV BH,0 (* page *)
MOV AH,8 (* func 8 = get current attribute, etc. *)
INT 10H
XOR BX,BX
MOV BL,AH
MOV atr,BX
END; (* ASM *)
IF (attrib <> 0) THEN
atr := attrib;
END;
ASM (* BEGIN *)
MOV BL,atr (* returned or passed attribute *)
MOV AL,ch (* char *)
MOV AH,9 (* func 9 = write at cursor position *)
MOV BH,0 (* page *)
MOV CX,1 (* write CX times *)
INT 10H (* call video handler *)
END; (* ASM *)
END QWrite;
(************************* QWriteString ******************************)
PROCEDURE QWriteString(String : ARRAY OF CHAR);
(* fast string writing (mono, CGA) does NOT move cursor *)
(* position cursor with GotoXY or WriteLn to begin writing *)
(* uses attribute at cursor for the whole string *)
(* usage:
;
; VAR I : CARDINAL;
; BEGIN
; ClrScr (0);
; FOR I := 2 TO 22 BY 2 DO
; GotoXY (I + 1, I);
; QWriteString ("All these lines in the blink of an eye!");
; END;
; ...
*)
VAR
row, col, offset : CARDINAL;
Ofs, Seg, StringLen : CARDINAL;
TextAdr : ADDRESS;
BEGIN
(* do it this way as an example of using ADDRESS *)
GetXY (col, row);
StringLen := Length(String);
TextAdr := ADR (String); (* get whole address *)
Ofs := TextAdr.OFS; (* address's offset field for SI *)
Seg := TextAdr.SEG; (* and data segment for DS *)
(* can't use record fields in ASM *)
DEC (col); DEC(row); (* adjust to 0-79, 0-24 format *)
offset := (row * 160) + (col * 2); (* total offset into screen memory *)
ASM (* BEGIN *)
MOV AH,8 (* func 8 = get current attribute, etc. *)
MOV BH,0 (* page *)
INT 10H (* call video handler *)
MOV CX,AX (* save returned info in CX until needed *)
MONO:
MOV AH,15 (* func 15 = check video adapter *)
INT 10H (* call video handler *)
MOV BX,0B000H (* assume mono screen address *)
MOV DX,03BAH (* check here for skipping retrace (snow) check *)
CMP AL,7 (* if mono, jump to SETUP *)
JZ SETUP
CGA:
MOV BX,0B800H (* CGA screen memory start *)
MOV DX,03DAH (* check here for retrace (snow) check *)
SETUP:
MOV AX,offset (* offset for screen memory into DI via AX *)
MOV DI,AX
MOV ES,BX (* mono or CGA base for screen memory *)
MOV SI,Ofs (* data offset for index *)
MOV DS,Seg (* data segment *)
MOV AH,CH (* we previously saved attribute in CX *)
MOV CX,StringLen (* write CX times *)
CLD (* the string move direction is up *)
CONTINUE:
CMP DL,0 (* if not CGA, jump over retrace check *)
JZ WRITE
SNOW1:
IN AL,DX (* test CGA port for beginning of retrace *)
TEST AL,1
JNZ SNOW1
CLI (* disable interrupts *)
SNOW2:
IN AL,DX (* test for retrace ongoing *)
TEST AL,1
JZ SNOW2
WRITE:
LODSB (* only get a byte, we have attribute in AH *)
STOSW (* stow char and attribute on the screen *)
STI (* enable interrupts *)
LOOP CONTINUE
END; (* ASM *)
END QWriteString;
(**************************** KeyScan ********************************)
PROCEDURE KeyScan (VAR KeyValue : CARDINAL) : CARDINAL;
(* get extended key code (F keys, arrow keys, etc.) or normal char *)
(* usage:
; VAR TestScanKey, Value : CARDINAL;
; ....
; TestScanKey := KeyScan (Value);
; IF TestScanKey = 1 THEN
; WriteString ("It's a scan key: ");
; WriteCard (Value);
; ELSE
; WriteString ("It's a normal character key: ");
; Write (CHR (Value));
; END;
;
*)
VAR
LocalValue, ARegLow : CARDINAL;
BEGIN
ARegLow := 0; (* clear HIGH bits *)
ASM (* BEGIN *)
KEYPRESS: (* loop until key pressed *)
MOV AH,1 (* try to get a keypress *)
INT 16H (* call keyboard handler *)
JZ KEYPRESS (* IF KEYPRESSED = 0 THEN GOTO KEYPRESS *)
MOV AH,0 (* get the key value *)
INT 16H (* call keyboard handler *)
MOV ARegLow,AL (* we need AL for RETURN *)
CMP AL,0 (* if 0, it's a scan key *)
JNE FINISHED (* IF ARegLow <> 0 THEN GOTO FINISHED *)
MOV AL,AH (* since it's a scan key, get it into CARDINAL order *)
FINISHED:
MOV AH,0 (* we know it's only a byte *)
MOV LocalValue,AX (* get value from AL *)
END; (* ASM *)
KeyValue := LocalValue;
IF ARegLow = 0 THEN
RETURN 1;
ELSE
RETURN 0;
END;
END KeyScan;
(************************** ScreenBuffer **************************)
PROCEDURE ScreenBuffer (VAR ScreenArray : ARRAY OF CHAR;
direction : CARDINAL);
(* save and restore a whole screen *)
(* usage:
;
; MODULE MyProg;
;
; FROM QVideo IMPORT QWriteString, GotoXY, ScreenBuffer, ClrScr, KeyScan;
;
; VAR scan, val : CARDINAL;
; FirstScreen, SecondScreen : ARRAY[0..4000] OF CHAR;
;
; BEGIN
; ClrScr (0);
; GotoXY (2, 2);
; QWriteString ("This happens so fast you hardly saw me before I came back!");
; GotoXY (3, 3);
; QWriteString (" Hit any key to see what you missed...");
; ScreenBuffer (FirstScreen, 0); (* save the screen *)
; ClrScr (0);
; GotoXY (3, 3);
; QWriteString (" You didn't see me, but I was here before!");
; ScreenBuffer (SecondScreen, 0);
; ScreenBuffer (FirstScreen, 1); (* restore the saved screen *)
; scan := KeyScan (val);
; ScreenBuffer (SecondScreen, 1);
;
; END MyProg.
*)
(* direction = 1 if restoring, 0 if saving - think of 0 as empty array *)
(* ScreenArray is a 4000 or > byte string since we need attributes AND chars *)
VAR
Ofs, Seg, ScreenLen : CARDINAL;
ScreenAdr : ADDRESS;
BEGIN
ScreenAdr := ADR (ScreenArray);
Ofs := ScreenAdr.OFS; (* address's offset field for SI or DI *)
Seg := ScreenAdr.SEG; (* and data segment for DS or ES *)
ScreenLen := 2000; (* words (two bytes each) *)
ASM (* BEGIN *)
MONO:
MOV AH,15 (* func 15 = check video adapter *)
INT 10H (* call video handler *)
MOV BX,0B000H (* assume mono screen address *)
MOV DX,03BAH (* check here for skipping retrace (snow) check *)
CMP AL,7 (* if mono, jump to SETUP *)
JZ SETUP
CGA:
MOV BX,0B800H (* CGA screen memory start *)
MOV DX,03DAH (* check here for retrace (snow) check *)
SETUP:
MOV AX,direction
CMP AX,1 (* if it's 1, then restore the array to screen *)
JNE GETSCR (* else put screen into the array *)
PUTSCR:
MOV ES,BX (* mono or CGA screen memory to fill with array *)
MOV DI,0 (* no offset - start at top left *)
MOV SI,Ofs (* array's memory offset in data seg *)
MOV DS,Seg (* array's data seg *)
JMP READY
GETSCR:
MOV DS,BX (* mono or CGA base from which to load array *)
MOV SI,0 (* no offset into screen *)
MOV DI,Ofs (* memory offset to beginning of array *)
MOV ES,Seg (* data seg where array lives *)
READY:
MOV CX,ScreenLen (* write CX times *)
CONTINUE:
CMP DL,0 (* if not CGA, jump over retrace check *)
JZ WRITE
SNOW1:
IN AL,DX (* test CGA port for beginning of retrace *)
TEST AL,1
JNZ SNOW1
CLI (* disable interrupts *)
SNOW2:
IN AL,DX (* test for retrace ongoing *)
TEST AL,1
JZ SNOW2
WRITE:
MOVSW (* move all the words ( attributes and chars ) *)
STI (* enable interrupts *)
LOOP CONTINUE
END; (* ASM *)
END ScreenBuffer;
(*************************** WriteBuffer ******************************)
PROCEDURE WriteBuffer (String : ARRAY OF CHAR;
VAR Buffer : ARRAY OF CHAR;
Col, Row : CARDINAL);
(*
Write to the array used in ScreenBuffer instead of the screen,so that when
the array is placed on the screen by ScreenBuffer (FirstScreen, Restore),
the effect will be very nearly instantaneous.
-
Initialize the array by first calling ClrScr with the desired attribute
as in ClrScr (Reverse) and then saving it to the array with ScreenBuffer:
ScreenBuffer (FirstScreen, Save). In other words, all the attributes will
be in place and you need only add the chars with WriteBuffer. It is easier
to code if you work it out on the screen first, then simply translate your
calls from:
ClrScr (Normal);
GotoXY (10, 12);
QWriteString ("x is at column 10 on row 12.");
...etc.
to:
ClrScr (Normal);
ScreenBuffer (FirstScreen, Save);
WriteBuffer ("x is at column 10 on row 12.", FirstScreen, 10, 12);
...etc.
ScreenBuffer (FirstScreen, Restore);
*)
VAR I, J, Pos : CARDINAL;
BEGIN
DEC (Col); (* we start with BufferChar[0] = col 1, row 1 *)
DEC (Row);
Col := Col * 2; (* we count the attributes too: atr, char, atr, char *)
Row := Row * 160; (* a row = 80 chars + 80 attributes and is sequential *)
Pos := Col + Row; (* buffer is straight line, just as screen RAM is ..*)
(* .. instead of being made up of columns and rows *)
J := 0;
FOR I := Pos TO (Pos + (2 * Length (String) - 2)) BY 2 DO (* skip over atr *)
Buffer[I] := String[J]; (* first buffer char is string[0] *)
INC (J);
END;
END WriteBuffer;
(**************************** ScrollUp *******************************)
PROCEDURE ScrollUp (NumLines, Width, Height, ULC, ULR : CARDINAL);
(* scroll up area defined by upper left corner and total width and height *)
(* scrolls each line NumLines times - clears window if NumLines = 0 *)
VAR LRC, LRR : CARDINAL; (* define lower right corner co-ordinates *)
BEGIN
GotoXY (ULC, ULR); (* we'll need to get the attribute *)
DEC (ULC); DEC (ULR); (* adjust to 0-79, 0-24 format *)
LRC := ULC + Width - 1;
LRR := ULR + Height - 1;
ASM (* BEGIN *)
MOV BH,0 (* page *)
MOV AH,8 (* func 8 = get attribute at cursor, etc. *)
INT 10H (* call video handler *)
MOV BH,AH (* use returned attribute for the scroll *)
MOV AL,NumLines (* scroll each line up or down NumLines *)
MOV AH,6 (* func 6 = scroll up *)
MOV CL,ULC (* upper left col *)
MOV CH,ULR (* upper left row *)
MOV DL,LRC (* lower right col *)
MOV DH,LRR (* lower right row *)
INT 10H (* call video handler *)
END; (* ASM *)
END ScrollUp;
(**************************** ScrollDn *******************************)
PROCEDURE ScrollDn (NumLines, Width, Height, ULC, ULR : CARDINAL);
(* scroll down area defined by upper left corner and total width and height *)
(* scrolls each line NumLines times - clears window if NumLines = 0 *)
VAR LRC, LRR : CARDINAL; (* define lower right corner co-ordinates *)
BEGIN
GotoXY (ULC, ULR); (* to get the attribute *)
DEC (ULC); DEC (ULR); (* adjust to 0-79, 0-24 format *)
LRC := ULC + Width - 1;
LRR := ULR + Height - 1;
ASM (* BEGIN *)
MOV BH,0 (* page *)
MOV AH,8 (* func 8 = get attribute at cursor, etc. *)
INT 10H (* call video handler *)
MOV BH,AH (* use returned attribute for the scroll *)
MOV AL,NumLines (* scroll each line up or down NumLines *)
MOV AH,7 (* func 7 = scroll down *)
MOV CL,ULC (* upper left col *)
MOV CH,ULR (* upper left row *)
MOV DL,LRC (* lower right col *)
MOV DH,LRR (* lower right row *)
INT 10H (* call video handler *)
END; (* ASM *)
END ScrollDn;
(***************************** CursorOn ******************************)
PROCEDURE CursorOn (startline, endline : CARDINAL);
(* turn cursor on and set the shape *)
(* if you call with startline and endline as 0, the default shape
for video adapter is used *)
(* usage:
; ...
; GotoXY (20, 12);
; WriteString (" The cursor won't blink until you hit a key.");
; CursorOff;
; scan := KeyScan(val);
; CursorOn (0, 0); (* normal mono or CGA shape is used *)
; WriteString (" But now it will!");
;
*)
CONST cga = 1;
mono = 2;
VAR mode : CARDINAL;
BEGIN
ASM (* BEGIN *)
MOV AH,15 (* func 15 = get video adapter *)
INT 10H (* call video handler *)
CMP AL,7 (* if AL = 7, it's mono *)
JZ MONO (* so go there *)
CGA:
MOV BX,cga (* nope, it's CGA *)
MOV mode,BX
JMP DONE
MONO:
MOV BX,mono (* yep, it's mono *)
MOV mode,BX
DONE:
END; (* ASM *)
IF (startline = 0) AND (endline = 0) THEN
IF (mode = cga) THEN
startline := 6;
endline := 7;
ELSE (* mono *)
startline := 11;
endline := 12;
END;
END;
ASM (* BEGIN *)
MOV AH,1 (* func 1 = set cursor shape *)
MOV CL, endline
MOV CH, startline
INT 10H (* call video handler *)
END; (* ASM *)
END CursorOn;
(**************************** CursorOff *******************************)
PROCEDURE CursorOff;
(* turn the cursor off (for Frame, etc. *)
(* see CursorOn for usage *)
BEGIN
ASM (* BEGIN *)
MOV AH,1 (* func 1 = set cursor shape *)
MOV CH,32 (* set bit 5 *)
INT 10H (* call video handler *)
END; (* ASM *)
END CursorOff;
(******************************* Frame *******************************)
PROCEDURE Frame (Method, Width, Height, ULC, ULR : CARDINAL);
(* draw frame from upper left column,row - width across and height down *)
(* Method = 1 for single line frame - window not cleared
= 10 for single line frame - window cleared
= 2 for double line frame - window not cleared
= 20 for double line frame - window cleared
= 3 for featureless frame - window not cleared
= 30 for featureless frame - window cleared
Set the attribute for the window frame with SetAttrib at same x,y as Frame.
Set the attribute for inside the window (if cleared) with x+1,y+1.
Cursor will be at top left of window after call, so you can WriteString.
*)
(* usage:
;
; CursorOff; (* don't want to see moving cursor *)
;
; SetAttrib ( 7, 1, 2); (* attribute 7 (normal) for frame sides *)
; (* note the ^ ^ column, row of each call *)
;
; SetAttrib (112, 2, 3); (* attribute 112 (reverse) for inside box *)
; (* ^ ^ *)
;
; Frame(20, 80, 12, 1, 2); (* window fills top half of screen *)
; (* ^ ^ except for the top line *)
;
; CursorOn (0, 0); (* turn cursor on with default shape *)
; GetXY (col, row); (* returns col = 2, row = 3 *)
; WriteString("I'm inside a double line, cleared, reverse video window.");
; GotoXY (col, row + 1);
; WriteString("It extends from column 1 on row 2 to column 80, row 12");
;
*)
VAR I, atr : CARDINAL;
ulCor, urCor, llCor, lrCor, vBar, hBar : CHAR;
BEGIN
IF (Method = 1) OR (Method = 10) THEN (* if single line *)
ulCor := "┌"; urCor := "┐";
llCor := "└"; lrCor := "┘";
vBar := "│"; hBar := "─";
ELSIF (Method = 2) OR (Method = 20) THEN (* if double line *)
ulCor := "╔"; urCor := "╗";
llCor := "╚"; lrCor := "╝";
vBar := "║"; hBar := "═";
ELSE (* assume blank line *)
ulCor := " "; urCor := " ";
llCor := " "; lrCor := " ";
vBar := " "; hBar := " ";
END;
GetAttrib (atr, ULC, ULR); (* get attribute for frame *)
IF (Method > 3) THEN
ScrollUp (0, Width - 2, Height - 2, ULC + 1, ULR + 1); (* clear inside *)
END;
DEC (Width);
DEC (Height);
QWrite (ulCor, atr, ULC, ULR);
FOR I := (ULC + 1) TO (ULC + Width - 1) DO
QWrite (hBar, atr, I, ULR);
END;
QWrite (urCor, atr, ULC + Width, ULR);
FOR I := (ULR + 1) TO (ULR + Height - 1) DO
QWrite (vBar, atr, ULC, I);
QWrite (vBar, atr, ULC + Width, I);
END;
QWrite (llCor, atr, ULC, ULR + Height);
FOR I := (ULC + 1) TO (ULC + Width - 1) DO
QWrite (hBar, atr, I, ULR + Height);
END;
QWrite (lrCor, atr, ULC + Width, ULR + Height);
GotoXY (ULC + 1, ULR + 1); (* position to top left inside *)
END Frame;
(************ Window PROTOTYPE only - NOT implemented **************)
(*
This simply sets the frame and window attributes and draws a window on top
of the current screen, optionally clearing the window. Row and Column are
updated as VAR parameters so that column, row will be the top left inside.
-
Save screen first via ScreenBuffer (Screen0, Save) so it can be restored.
*)
(* PROCEDURE Window (Method, FrameAttrib, WindowAttrib : CARDINAL;
* Width, Height : CARDINAL;
* VAR StartCol, StartRow : CARDINAL);
*BEGIN
* CursorOff; (* cursor would spoil effect of framing *)
* (* set screen attributes *)
* SetAttrib (FrameAttrib, StartCol, StartRow); (* for outside *)
* SetAttrib (WindowAttrib, StartCol + 1, StartRow + 1); (* for the inside *)
*
* Frame (Method, Width, Height, StartCol, StartRow); (* draw it, *
* * maybe clear it *)
* GetXY (StartCol, StartRow); (* find position *
* * for writing *)
*END Window;
*)
(*****************************************************************************
Placed in the public domain November, 1987 by author : Alan Steed
RD2, Safe Harbor Road
Conestoga, PA 17516
******************************************************************************)
END QVideo.