IMPLEMENTATION MODULE CursorMouse; (*J. Gutknecht, 14.11.84*)

FROM SYSTEM IMPORT WORD;
FROM DisplayDriver IMPORT ScreenWidth, MapHeight, BMDescriptor, BMD;
FROM Programs IMPORT CurrentLevel, TermProcedure;
CONST maxLev = 7;
unit = 32; offset = unit*2;
msW = 1024 DIV unit; msH = 1024 DIV unit (*mouse range*);

VAR scW, scH, W, H, W0, H0, u, v, top, cur: CARDINAL;
done: BOOLEAN;

tab: ARRAY [0..maxLev] OF RECORD
lev: CARDINAL; read: ReadProc
END;
TYPE Pattern1 = RECORD
height: CARDINAL;
raster: ARRAY [0..15] OF BITSET
END;


PROCEDURE GET(chan: CARDINAL; VAR val: WORD);
CODE 126B
END GET;

PROCEDURE PUT(chan: CARDINAL; val: WORD);
CODE 126B
END PUT;

PROCEDURE SetMouse(x, y: CARDINAL);
BEGIN u := x; v := y; PUT(6, 0)
END SetMouse;

PROCEDURE GetMouse(VAR s: BITSET; VAR x, y: CARDINAL);
VAR keys: CARDINAL;
BEGIN GET(6, x); GET(7, y); GET(3, keys);
x := (x * W0 DIV msW + u) MOD W;
y := (y * H0 DIV msH + v) MOD H;
IF x > scW + offset THEN x := 0
ELSIF x > scW THEN x := scW
END;
IF y > scH + offset THEN y := 0
ELSIF y > scH THEN y := scH
END;
s := BITSET(keys)
END GetMouse;

PROCEDURE ReadMouse(VAR s: BITSET; VAR x, y: CARDINAL);
BEGIN
IF cur = 0 THEN GetMouse (s, x, y)
ELSE cur := cur-1; tab[cur].read(s, x, y); cur := cur+1
END
END ReadMouse;

PROCEDURE Assign(p: ReadProc);
VAR curLev: CARDINAL;
BEGIN
IF cur = top THEN curLev := CurrentLevel();
IF (top = 0) OR (tab[top-1].lev < curLev) THEN
IF top <= maxLev THEN
tab[top].read := p; tab[top].lev := curLev;
top := top+1; cur := top
END
ELSE tab[top-1].read := p
END
END
END Assign;

PROCEDURE Cleanup;
VAR curLev: CARDINAL;
BEGIN
curLev := CurrentLevel();
WHILE (top > 0) & (tab[top-1].lev >= curLev) DO
top := top - 1
END
END Cleanup;


CONST lu = 0; ld = 1; ru = 2; rd = 3;
TYPE Block = RECORD x,y,w,h: CARDINAL END;
Direction = [lu..rd];

VAR standard: BOOLEAN;
i, prevX, prevY: CARDINAL;
cursor: Pattern; curBlk: Block;
test: Pattern1;

curOn: BOOLEAN;
arrow: ARRAY Direction OF Pattern;
privPat: Pattern;

PROCEDURE REPL(m: CARDINAL; bmd: BMDescriptor; pat: Pattern; blk: Block);
CODE 126B
END REPL;

PROCEDURE PaintCursor(X, Y: CARDINAL);
VAR d: Direction;
BEGIN
WITH curBlk DO
IF X + 16 <= scW THEN x := X;
IF Y >= 16 THEN y := Y - 16; d := lu ELSE y := Y; d := ld END
ELSE x := X - 16;
IF Y >= 16 THEN y := Y - 16; d := ru ELSE y := Y; d := rd END
END
END;
IF standard THEN cursor := arrow[d]
ELSE cursor := privPat
END;
REPL(2, BMD, cursor, curBlk)
END PaintCursor;

PROCEDURE MoveCursor(x, y: CARDINAL);
BEGIN
IF curOn THEN
IF (x # prevX) OR (y # prevY) THEN
REPL(2, BMD, cursor, curBlk);
prevX := x; prevY := y;
PaintCursor(x, y)
END
ELSE curOn := TRUE; prevX := x; prevY := y;
PaintCursor(x, y)
END
END MoveCursor;

PROCEDURE EraseCursor;
BEGIN
IF curOn THEN curOn := FALSE;
REPL(2, BMD, cursor, curBlk)
END
END EraseCursor;

PROCEDURE SetPattern(VAR p: Pattern);
BEGIN privPat := p; standard := FALSE
END SetPattern;

PROCEDURE ResetPattern;
BEGIN standard := TRUE
END ResetPattern;

BEGIN
top := 0; cur := 0;
scW := ScreenWidth(); scH := MapHeight();
W := (scW + unit - 1) DIV unit * unit + offset*2;
H := (scH + unit - 1) DIV unit * unit + offset*2;
W0 := W DIV unit; H0 := H DIV unit;
SetMouse(scW DIV 2, scH DIV 2);
TermProcedure(Cleanup, done);

scW := ScreenWidth(); scH := MapHeight();
WITH arrow[lu] DO
raster[ 0] := {0..7}; raster[ 1] := {0..6};
raster[ 2] := {0..5}; raster[ 3] := {0..6};
raster[ 4] := {0..7}; raster[ 5] := {0..8};
raster[ 6] := {0..1,3..9}; raster[ 7] := {0,4..10};
raster[ 8] := {5..11}; raster[ 9] := {6..12};
raster[10] := {7..13}; raster[11] := {8..14};
raster[12] := {9..15}; raster[13] := {10..14};
raster[14] := {11..13}; raster[15] := {12};
height := 16
END;
WITH arrow[ld] DO height := 16;
FOR i := 0 TO 15 DO
raster[i] := arrow[lu].raster[15-i]
END
END;
WITH test DO
raster[ 0] := {0..7}; raster[ 1] := {0..6};
raster[ 2] := {0..5}; raster[ 3] := {0..6};
raster[ 4] := {0..7}; raster[ 5] := {0..8};
raster[ 6] := {0..1,3..9}; raster[ 7] := {0,4..10};
raster[ 8] := {5..11}; raster[ 9] := {6..12};
raster[10] := {7..13}; raster[11] := {8..14};
raster[12] := {9..15}; raster[13] := {10..14};
raster[14] := {11..13}; raster[15] := {12};
height := 16
END;
WITH test DO height := 16;
FOR i := 0 TO 15 DO
raster[i] := arrow[lu].raster[15-i]
END

END;
WITH arrow[ru] DO height := 16;
raster[ 0] := {8..15}; raster[ 1] := {9..15};
raster[ 2] := {10..15}; raster[ 3] := {9..15};
raster[ 4] := {8..15}; raster[ 5] := {7..15};
raster[ 6] := {6..12,14..15}; raster[ 7] := {5..11,15};
raster[ 8] := {4..10}; raster[ 9] := {3..9};
raster[10] := {2..8}; raster[11] := {1..7};
raster[12] := {0..6}; raster[13] := {1..5};
raster[14] := {2..4}; raster[15] := {3}
END;
WITH arrow[rd] DO height := 16;
FOR i := 0 TO 15 DO
raster[i] := arrow[ru].raster[15-i]
END
END;
WITH curBlk DO w := 16; h := 16 END;
curOn := FALSE; standard := TRUE
END CursorMouse.