DIRECTORY
AltoFileDefs: FROM "AltoFileDefs",
DiscoDefs: FROM "DiscoDefs" USING [SFD,ScanBuffer],
GraphicsDefs: FROM "GraphicsDefs",
IODefs: FROM "IODefs",
InlineDefs: FROM "InlineDefs",
MagicDefs: FROM "MagicDefs",
Mopcodes: FROM "MopCodes";

Magic: PROGRAM IMPORTS DiscoDefs, InlineDefs, GraphicsDefs EXPORTS MagicDefs =
BEGIN

RandomTable: ARRAY [ 0..16) OF CARDINAL ← [1,22222,30303,7345,5525,6666,7777,877,9999,1770,11111,12,1313,7714,15151,1776];
next: CARDINAL ← 1;
Random: PUBLIC PROCEDURE RETURNS [CARDINAL] =
BEGIN
this: CARDINAL ← next;
next ← (next+1) MOD 16;
RandomTable[this] ← RandomTable[this]+RandomTable[next];
RETURN[RandomTable[this]];
END;
Buttons: TYPE = MACHINE DEPENDENT RECORD
[ KeyPadAndGarbage: [0..10000B),
Red: [0..1],
Blue: [0..1],
Yellow: [0..1]
];
MouseButtons: POINTER TO Buttons = LOOPHOLE[177030B];
CursorX: POINTER TO CARDINAL = LOOPHOLE[426B];
CursorY: POINTER TO CARDINAL = LOOPHOLE[427B];
GetUserBox: PUBLIC PROCEDURE [xRatio,yRatio: CARDINAL] RETURNS [x,y: CARDINAL,dx,dy: INTEGER] =
BEGIN
calculatedX,calculatedY: LONG INTEGER;
UNTIL MouseButtons.Red = 0 DO ENDLOOP;
x ← CursorX↑;
y ← CursorY↑;
dx ← dy ← 0;
DO
WHILE MouseButtons.Red = 0 DO
GraphicsDefs.XorArea[x,y,x+dx,y];
GraphicsDefs.XorArea[x+dx,y,x+dx,y+dy];
GraphicsDefs.XorArea[x+dx,y+dy,x,y+dy];
GraphicsDefs.XorArea[x,y+dy,x,y];
dx ← CursorX↑ - x;
dy ← CursorY↑ - y;
calculatedX ← (LONG[dy-1]*LONG[xRatio])/LONG[yRatio];
calculatedY ← (LONG[dx+1]*LONG[yRatio])/LONG[xRatio];
IF ABS[ABS[calculatedX]-ABS[dx]] > ABS[ABS[calculatedY]-ABS[dy]]
THEN dy ← (IF dy<0 THEN -1 ELSE 1)*InlineDefs.LowHalf[ABS[calculatedY]]
ELSE dx ← (IF dx<0 THEN -1 ELSE 1)*InlineDefs.LowHalf[ABS[calculatedX]];
GraphicsDefs.XorArea[x,y,x+dx,y];
GraphicsDefs.XorArea[x+dx,y,x+dx,y+dy];
GraphicsDefs.XorArea[x+dx,y+dy,x,y+dy];
GraphicsDefs.XorArea[x,y+dy,x,y];
ENDLOOP;
IF dx < 0 THEN BEGIN x ← x+dx;dx ← ABS[dx];END;
IF dy < 0 THEN BEGIN y ← y+dy;dy ← ABS[dy];END;
WHILE MouseButtons.Yellow = 0 DO --move origin
GraphicsDefs.XorArea[x,y,x+dx,y];
GraphicsDefs.XorArea[x+dx,y,x+dx,y+dy];
GraphicsDefs.XorArea[x+dx,y+dy,x,y+dy];
GraphicsDefs.XorArea[x,y+dy,x,y];
x ← CursorX↑;
y ← CursorY↑;
GraphicsDefs.XorArea[x,y,x+dx,y];
GraphicsDefs.XorArea[x+dx,y,x+dx,y+dy];
GraphicsDefs.XorArea[x+dx,y+dy,x,y+dy];
GraphicsDefs.XorArea[x,y+dy,x,y];
ENDLOOP;
IF MouseButtons.Blue = 0 THEN RETURN[x,y,dx,dy];

ENDLOOP;
END;

Menu: PUBLIC PROCEDURE [nItems: CARDINAL,itemList: POINTER TO ARRAY [0..0) OF STRING,font: POINTER TO GraphicsDefs.StrikeFont] RETURNS [index: CARDINAL] =
BEGIN
stringLen: PUBLIC PROCEDURE [s: STRING] RETURNS [CARDINAL] =
BEGIN
i: CARDINAL;
widthList: POINTER TO ARRAY [0..0) OF CARDINAL ← font.xInSegment;
len: CARDINAL ← 0;
FOR i IN [0..s.length) DO
BEGIN ix: CARDINAL ← LOOPHOLE[s[i],CARDINAL];
len ← len + widthList[ix+1] - widthList[ix];
END;
ENDLOOP;
RETURN[len];
END;
menuWidth: CARDINAL ← 0;
fontHeight: CARDINAL ← font.ascent + font.descent;
menuHeight: CARDINAL ← nItems * fontHeight;
menuBox: GraphicsDefs.Box;
b: POINTER TO GraphicsDefs.Box ← @menuBox;
menuBitmap: POINTER TO GraphicsDefs.Bitmap ← @menuBox.boxBitmap;
Select: PUBLIC PROCEDURE [index: CARDINAL] =
BEGIN
GraphicsDefs.XorArea[0,index*fontHeight,
stringLen[itemList[index]],(index+1)*fontHeight,menuBitmap];
GraphicsDefs.PaintBox[@menuBox];
END;
i: CARDINAL;
Screen: POINTER TO GraphicsDefs.Bitmap ← GraphicsDefs.GetDefaultBitmapHandle[];
DCB: TYPE = MACHINE DEPENDENT RECORD
[ link: POINTER TO DCB,
lowResolution: BOOLEAN,
inverseVideo: BOOLEAN,
offset: [0..77B],
width: [0..377B],
bits: POINTER,
height: CARDINAL
];
DCBHead: POINTER TO POINTER TO DCB = LOOPHOLE[420B];
currentDCB: POINTER TO DCB ← DCBHead↑;
XOffset,YOffset: CARDINAL ← 0;
UNTIL currentDCB = NIL DO
IF currentDCB.bits = Screen.bits THEN EXIT;
YOffset ← YOffset + currentDCB.height*2;
currentDCB ← currentDCB.link;
ENDLOOP;

IF currentDCB = NIL THEN YOffset ← 0 ELSE XOffset ← currentDCB.offset*16;

index ← 177777B;
FOR i IN [0..nItems) DO
BEGIN sLen: CARDINAL ← stringLen[itemList[i]];
IF sLen > menuWidth THEN menuWidth ← sLen;
END;
ENDLOOP;

GraphicsDefs.CreateBox[@menuBox,menuWidth,menuHeight];
GraphicsDefs.PutArea[0,0,0,menuBitmap.nLines-1,menuBitmap];
GraphicsDefs.PutArea[0,menuBitmap.nLines-1,
menuBitmap.nBits-1,menuBitmap.nLines-1,menuBitmap];
GraphicsDefs.PutArea[menuBitmap.nBits-1,menuBitmap.nLines-1,
menuBitmap.nBits-1,0,menuBitmap];
GraphicsDefs.PutArea[menuBitmap.nBits-1,0,0,0,menuBitmap];
GraphicsDefs.DisplayBox[@menuBox,CursorX↑-XOffset,CursorY↑-YOffset];

FOR i IN [0..nItems) DO
[]←GraphicsDefs.PutText[itemList[i],0,font.ascent+i*fontHeight,font,0,
menuBitmap];
ENDLOOP;
GraphicsDefs.PaintBox[@menuBox];

WHILE CursorX↑-XOffset IN [MAX[20,b.displayX]-20..b.displayX+b.boxBitmap.nBits+20)
AND
CursorY↑-YOffset IN [MAX[20,b.displayY]-20..b.displayY+b.boxBitmap.nLines+20) DO
WHILE MouseButtons.Yellow = 0 DO
GraphicsDefs.MoveBox[@menuBox,CursorX↑-XOffset,CursorY↑-YOffset];
ENDLOOP;
IF MouseButtons.Red = 0 THEN --selection
BEGIN
newIndex: CARDINAL ←
MIN[nItems-1,(CursorY↑-YOffset-menuBox.displayY)/fontHeight];
IF newIndex = index THEN LOOP;
IF index IN [0..nItems) THEN Select[index];
index ← newIndex;
Select[index];
END;
ENDLOOP;

GraphicsDefs.DestroyBox[@menuBox,TRUE];
RETURN[index];
END;

lastBuffer: POINTER TO UNSPECIFIED ← NIL;
wordsLeft: CARDINAL ← 0;
InitReadBlock
: PUBLIC PROCEDURE =
BEGIN
wordsLeft ← 0;
END;

ReadBlock: PUBLIC PROCEDURE[sfd: POINTER,p: POINTER TO UNSPECIFIED,nwords: CARDINAL] RETURNS [POINTER TO UNSPECIFIED] =
BEGIN
dsfd: POINTER TO DiscoDefs.SFD ← sfd;
fa: AltoFileDefs.FA;
wordsTransferred: CARDINAL ← 0;
thisTransfer: CARDINAL;

--IF nwords <= wordsLeft THEN
--
BEGIN
--
wordsLeft ← wordsLeft - nwords;
--
RETURN[lastBuffer+(256-(wordsLeft+nwords))];
--
END;
UNTIL nwords = 0 DO
thisTransfer ← MIN[wordsLeft,nwords];
InlineDefs.COPY[to: p+wordsTransferred,from: lastBuffer + 256 - wordsLeft,nwords:thisTransfer];
nwords ← nwords - thisTransfer;
wordsLeft ← wordsLeft - thisTransfer;
wordsTransferred ← wordsTransferred + thisTransfer;
IF wordsLeft = 0 THEN
BEGIN
lastBuffer ← DiscoDefs.ScanBuffer[dsfd,@fa];
wordsLeft ← 256;
END;
ENDLOOP;
wordsTransferred ← wordsTransferred + thisTransfer;
RETURN[p];
END;

END.