-- Straw0.mesa
-- Written by Joe Maleson
-- Last changed by Doug Wyatt, April 8, 1981 5:52 PM

DIRECTORY
AltoFileDefs,
DiscoDefs USING [Lookup, LookupList, TransferBytes],
DisplayListDefs,
GraphicsDefs,
ImageDefs,
InlineDefs USING [COPY],
IODefs USING [WriteLine, WriteString, ReadID, Rubout],
MagicDefs,
MiscDefs,
Mopcodes,
PressDefs USING [PressPage, ReleasePressPage, PressFileDescriptor,
InitPressFileDescriptor, PutPressPage, ClosePressFile, PressObject,
PressFilePointers, PressFont, ELShowDots, ELShowDotsOpaque,
OpenPressFileFromFP, ReadPressPage, ReleasePressFilePointers],
Real USING [InitReals],
SegmentDefs,
StrawDefs,
StreamDefs,
StringDefs,
SystemDefs,
XMAllocDefs;
Straw0: PROGRAM
IMPORTS DiscoDefs
,DisplayListDefs,GraphicsDefs,MagicDefs,PressDefs,Real,
StrawDefs,XMAllocDefs,ImageDefs,InlineDefs,IODefs,MiscDefs,
StringDefs,SegmentDefs,SystemDefs
EXPORTS StrawDefs =
BEGIN
OPEN DiscoDefs,InlineDefs, IODefs, StrawDefs;
Buttons: TYPE = MACHINE DEPENDENT RECORD
[ KeyPadAndGarbage: [0..10000B),
Red: [0..1],
Blue: [0..1],
Yellow: [0..1]
];
triState: TYPE = {empty,singleFile,multiFile};
MouseButtons: POINTER TO Buttons = LOOPHOLE[177030B];
CursorX: POINTER TO CARDINAL = LOOPHOLE[426B];
CursorY: POINTER TO CARDINAL = LOOPHOLE[427B];
CursorBits: POINTER TO ARRAY [0..15] OF CARDINAL = LOOPHOLE[431B];
Cursor: GraphicsDefs.Bitmap ← [bank: 0,nWords: 1,nBits:16,nLines:16, bits:LOOPHOLE[CursorBits],nBitsPerPixel:1,portraitMode:TRUE,scaleFactor:10];
ArrowCursor: GraphicsDefs.Bitmap ← [bank: 0,nWords: 1,nBits: 16,nLines: 16, bits:,nBitsPerPixel:1,portraitMode:TRUE,scaleFactor:10];
HourGlassCursor: GraphicsDefs.Bitmap ← [bank: 0,nWords: 1,nBits: 16,nLines: 16,bits:,nBitsPerPixel:1,portraitMode:TRUE,scaleFactor:10];

Screen: POINTER TO GraphicsDefs.Bitmap;
bitsPerInch: CARDINAL ← 72;
micasPerInch: CARDINAL = 2540;
dispXOff: CARDINAL ← 0;
dispYOff: CARDINAL ← 0;
GridSize: CARDINAL ← 0;
DCBHead: POINTER TO CARDINAL = LOOPHOLE[420B];
nextDCB: POINTER TO ARRAY[0..3] OF UNSPECIFIED ← LOOPHOLE[DCBHead↑];
nScanLines: CARDINAL ← 808;
DCBtop: POINTER TO ARRAY[0..3] OF CARDINAL ← nextDCB;

pfp: PressDefs.PressFilePointers;
needRelease: BOOLEAN ← FALSE;
pressNames: POINTER TO ARRAY [0..0) OF STRING;
nFiles: CARDINAL ← 0;
pressFiles: POINTER TO DiscoDefs.LookupList ← DiscoDefs.Lookup["*.press"];
font: POINTER TO GraphicsDefs.StrikeFont ← GraphicsDefs.GetStrikeHandle["SysFont"];
nPages: CARDINAL;
displayPage: CARDINAL;
pressPage: PressDefs.PressPage;
ScreenState: triState ← empty;

Main: PROCEDURE =
BEGIN
p: POINTER TO LookupList;
--mem defs
TotalPagesForXMem: CARDINAL = 400;
nXMemBlocks: CARDINAL = 4;
PagesPerXMemBlock: CARDINAL = TotalPagesForXMem/nXMemBlocks;

ArrowBits: ARRAY [0..15] OF CARDINAL;
HourGlassBits: ARRAY [0..15] OF CARDINAL ←
[
177777B, 100001B, 040002B, 034034B,
017170B, 007660B, 003740B, 001700B,
001100B, 002440B, 004220B, 010610B,
021704B, 047762B, 177777B, 177777B
];

IF pressFiles=NIL THEN RETURN; -- DKW

COPY[from: Cursor.bits,nwords: 16,to: @ArrowBits];
ArrowCursor.bits ← LOOPHOLE[@ArrowBits];
HourGlassCursor.bits ← LOOPHOLE[@HourGlassBits];

UNTIL nextDCB[0] = 0 DO
nScanLines ← nScanLines - nextDCB[3]*2;
nextDCB ← LOOPHOLE[nextDCB[0]];
ENDLOOP;
nScanLines ← nScanLines - nextDCB[3]*2;

pressPage.leftX ← pressPage.bottomY ← 77777B;
pressPage.rightX ← pressPage.topY ← 0;
pressPage.ObjectList ← NIL;
pressPage.FontDir ← ALL[NIL];

p←pressFiles;
UNTIL p = NIL DO nFiles ← nFiles + 1;p ← p.link;ENDLOOP;
pressNames ← SystemDefs.AllocateHeapNode[nFiles];
p←pressFiles;nFiles ← 0;
UNTIL p = NIL DO
pressNames[nFiles] ← p.name;
nFiles ← nFiles + 1;
p ← p.link;
ENDLOOP;

--now, initialize mem
--LongDefs.InitMachineType[];
//needed for Alto compatible XMAlloc stuff
--
AltoMicrocodeDefs.LoadRam[]; //ditto
THROUGH [1..nXMemBlocks] DO
OPEN SegmentDefs;
ENABLE InsufficientVM => EXIT;
XMAllocDefs.AddToXMZone[LongDataSegmentAddress[NewDataSegment[
DefaultXMBase,PagesPerXMemBlock]],PagesPerXMemBlock*256];
ENDLOOP;
GraphicsDefs.SetXMAlloc[XMAllocDefs.Allocate,XMAllocDefs.Free];

Screen ← GraphicsDefs.TurnOnGraphics[];
nextDCB ← LOOPHOLE[DCBHead↑];

SelectFile[];
AddFile[];

--menu-less edit
IODefs.WriteLine["Straw of October 20, 1980"];
StrawDefs.EditDisplayList[];
ImageDefs.StopMesa[];

DO --edit loop
BEGIN
commandIndex: CARDINAL;
newFile: CARDINAL = 0;
addFile: CARDINAL = newFile+1;
writeFile: CARDINAL = addFile+1;
edit: CARDINAL = writeFile+1;
quit: CARDINAL = edit+1;
nextPage: CARDINAL = quit+1;
commandNames: ARRAY [0..nextPage] OF STRING ←
["New File","Add File","Write File","Edit","Quit","Next Page"];
nCommands: CARDINAL ← nextPage;
IF (nPages > displayPage) AND (ScreenState = singleFile) THEN nCommands ← nCommands+1;

DO --get user command
commandIndex ← MagicDefs.Menu[nCommands,LOOPHOLE[@commandNames],font];
IF commandIndex IN [0..nCommands) THEN EXIT;
ENDLOOP;

SELECT commandIndex FROM
newFile,nextPage =>
BEGIN
NewPage[];
IF commandIndex = newFile THEN
BEGIN
Refresh[];
SelectFile[];
END
ELSE displayPage ← displayPage+1;
AddFile[];
END;
addFile =>
BEGIN
SelectFile[];
AddFile[];
END;
edit => StrawDefs.EditDisplayList[];
writeFile => WriteFile[];
quit => ImageDefs.StopMesa[];
ENDCASE;
END;
ENDLOOP; --edit loop

END;

SelectFile: PUBLIC PROCEDURE =
BEGIN
pressIndex: CARDINAL ← 177777B;
p: POINTER TO LookupList;

IF needRelease THEN
BEGIN
PressDefs.ReleasePressFilePointers[@pfp];
END;
needRelease ← TRUE;

DO
pressIndex ← MagicDefs.Menu[nFiles,LOOPHOLE[pressNames],font];
IF pressIndex IN [0..nFiles) THEN EXIT;
ENDLOOP;

WaitCursor[];
p ← pressFiles;
THROUGH [1..pressIndex] DO p ← p.link;ENDLOOP;

nPages ← PressDefs.OpenPressFileFromFP[@p.fp,@pfp];
NormalCursor[];

--get page number from user, and display it

IF nPages > 99 THEN MiscDefs.CallDebugger["too many pages"];
IF nPages = 1 THEN displayPage ← 1
ELSE
BEGIN
i: CARDINAL;
numbers: ARRAY [0..100) OF STRING;
FOR i IN [0..nPages) DO
numbers[i] ← SystemDefs.AllocateHeapString[2];
StringDefs.AppendDecimal[numbers[i],i+1];
ENDLOOP;
DO
displayPage←MagicDefs.Menu[nPages,LOOPHOLE[@numbers],font]+1;
IF displayPage IN [1..nPages] THEN EXIT;
ENDLOOP;
FOR i IN [0..nPages) DO
SystemDefs.FreeHeapString[numbers[i]];
ENDLOOP;
END; --select displayPage
END;

AddFile: PUBLIC PROCEDURE =
BEGIN
obj,savedObj: POINTER TO PressDefs.PressObject;

WaitCursor[];
--add new page to pressPage
savedObj ← pressPage.ObjectList;
pressPage.ObjectList ← NIL;

PressDefs.ReadPressPage[@pfp,displayPage,@pressPage];
DisplayPressPage[@pressPage];

obj ← pressPage.ObjectList;
UNTIL obj.link = NIL DO obj ← obj.link; ENDLOOP;
obj.link ← savedObj;

IF ScreenState = empty THEN ScreenState ← singleFile
ELSE ScreenState ← multiFile;

NormalCursor[];
END;

NewPage: PUBLIC PROCEDURE =
BEGIN
i: CARDINAL;
displayList: POINTER TO ARRAY [0..0) OF POINTER TO StrawDefs.EntityBox ←
LOOPHOLE[DisplayListDefs.GetDisplayListHandle[]];

ReLinkPressPage[@pressPage];
--free storage allocated by ReadDirs
FOR i DECREASING IN [0..DisplayListDefs.GetDisplayCount[]) DO
ReleaseEntityBox[displayList[i],FALSE];
ENDLOOP;
DisplayListDefs.ResetDisplayCount[];

PressDefs.ReleasePressPage[@pressPage];
pressPage.leftX ← pressPage.bottomY ← 77777B;
pressPage.rightX ← pressPage.topY ← 0;
pressPage.ObjectList ← NIL;
pressPage.FontDir ← ALL[NIL];

--and grab them heap pages
WHILE SystemDefs.PruneHeap[] DO ENDLOOP;

ScreenState ← empty;
END;

WriteFile: PUBLIC PROCEDURE =
BEGIN
pfp: PressDefs.PressFileDescriptor;
pressStr: STRING ← [40];

GetString[pressStr,"Press file name: "];
IF pressStr.length # 0 THEN
BEGIN
WaitCursor[];
ReLinkPressPage[@pressPage];
PressDefs.InitPressFileDescriptor[@pfp,pressStr];
PressDefs.PutPressPage[@pfp,@pressPage];
PressDefs.ClosePressFile[@pfp];
DiscoDefs.TransferBytes[dp:NIL,nBytes:0,data:NIL,free:TRUE];--invalidate cache
NormalCursor[];
END;
END;

WaitCursor: PUBLIC PROCEDURE =
BEGIN
GraphicsDefs.ReplaceBitmap[@HourGlassCursor,0,0,@Cursor];
END;

NormalCursor: PUBLIC PROCEDURE =
BEGIN
GraphicsDefs.ReplaceBitmap[@ArrowCursor,0,0,@Cursor];
END;

Refresh: PUBLIC PROCEDURE =
BEGIN
i,x,y: CARDINAL;
b: POINTER TO GraphicsDefs.Box;
displayList: POINTER TO ARRAY [0..0) OF POINTER TO GraphicsDefs.Box ←
DisplayListDefs.GetDisplayListHandle[];
GraphicsDefs.EraseArea[0,0,608,808];
IF GridSize # 0 THEN
BEGIN
dotLine: GraphicsDefs.Bitmap ← Screen↑;
dotLine.nLines ← 1;
FOR x ← 0,x+GridSize UNTIL x > dotLine.nBits
DO GraphicsDefs.PutPoint[x,0];ENDLOOP;
FOR y ← GridSize,y+GridSize UNTIL y > Screen.nLines
DO GraphicsDefs.PutBitmap[@dotLine,0,y,Screen];
ENDLOOP;
END;
FOR i IN [0..DisplayListDefs.GetDisplayCount[]) DO
b ← displayList[i];
GraphicsDefs.DisplayBox[b,b.displayX,b.displayY];
GraphicsDefs.ReleaseBox[b];
ENDLOOP;
END;

GetFont: PUBLIC PROCEDURE [n: CARDINAL] RETURNS [strike: POINTER TO GraphicsDefs.StrikeFont,mode: GraphicsDefs.textMode,width: POINTER TO ARRAY CHARACTER [0C..377C] OF INTEGER,index: CARDINAL] =
BEGIN
font: POINTER TO PressDefs.PressFont ← pressPage.FontDir[n];
fontName: STRING ← [40];
StringDefs.AppendString[fontName,font.Family];
StringDefs.AppendDecimal[fontName,font.PointSize];
strike ← GraphicsDefs.GetStrikeHandle[fontName];
IF strike = NIL THEN
strike ← GraphicsDefs.GetStrikeHandle["SysFont"];
RETURN[strike,font.Face,font.Widths,n];
END;

GetNum: PUBLIC PROCEDURE [prompt: STRING] RETURNS [CARDINAL] =
BEGIN ENABLE StringDefs.InvalidNumber => RETRY;
s: STRING ← [40];
GetString[s,prompt];
IF s.length = 0 THEN RETURN[0];
RETURN[StringDefs.StringToDecimal[s]];
END;

GetNumWithDefault: PUBLIC PROCEDURE [prompt: STRING,default: CARDINAL] RETURNS [CARDINAL]=
BEGIN ENABLE StringDefs.InvalidNumber => RETRY;
s: STRING ← [40];
defaultString: STRING ← [8];
StringDefs.AppendDecimal[defaultString,default];
GetStringWithDefault[s,prompt,defaultString];
RETURN[StringDefs.StringToDecimal[s]];
END;

GetStringWithDefault: PUBLIC PROCEDURE [s,prompt,default: STRING] =
BEGIN OPEN StringDefs;
newPrompt: STRING ← [80];
AppendString[to: newPrompt,from: prompt];
AppendString[to: newPrompt,from: "["];
AppendString[to: newPrompt,from: default];
AppendString[to: newPrompt,from: "]"];
GetString[s,newPrompt];
IF s.length = 0 THEN AppendString[to: s,from: default];
END;

GetString: PUBLIC PROCEDURE [s,prompt: STRING] =
BEGIN
heightDCB: TYPE = RECORD
[
longBit: BOOLEAN,
height: [0..100000B)
];
h: POINTER TO heightDCB ← @nextDCB[3];
normalLen: heightDCB ← nextDCB[3];
IF nextDCB # NIL THEN
BEGIN
h.height ← MIN[h.height,nScanLines/2];
nextDCB[0] ← DCBtop;
END;
BEGIN ENABLE Rubout => RETRY;
WriteLine[""];
WriteString[prompt];
ReadID[s];
END; --of ENABLE
IF nextDCB # NIL THEN
BEGIN
h↑ ← normalLen;
nextDCB[0] ← 0;
END;
END;

ReLinkPressPage: PROCEDURE[pressPage: POINTER TO PressDefs.PressPage] =
BEGIN
displayList: POINTER TO ARRAY [0..0) OF POINTER TO StrawDefs.EntityBox ←
LOOPHOLE[DisplayListDefs.GetDisplayListHandle[]];
nItems: CARDINAL ← DisplayListDefs.GetDisplayCount[];
d: POINTER TO StrawDefs.EntityBox;
i: CARDINAL;

--first, discard invisible items
FOR i DECREASING IN [0..nItems) DO
d ← displayList[i];
IF (INTEGER[d.Box.displayX] < 0) OR
(INTEGER[d.Box.displayY] < 0) OR
(d.Box.displayX > Screen.nBits) OR
(d.Box.displayY > Screen.nLines) THEN
ReleaseEntityBox[d,TRUE];
ENDLOOP;

nItems ← DisplayListDefs.GetDisplayCount[];
IF nItems = 0 THEN pressPage.ObjectList ← NIL
ELSE
BEGIN
pressPage.ObjectList ← displayList[0].Object;
FOR i IN [0..nItems-1) DO
displayList[i].Object.link ← displayList[i+1].Object;
ENDLOOP;
displayList[nItems-1].Object.link ← NIL;
END;
END;

ReleaseEntityBox: PUBLIC PROCEDURE [eBox: POINTER TO StrawDefs.EntityBox,erase: BOOLEAN] =
BEGIN
currentBox: POINTER TO GraphicsDefs.Box ← LOOPHOLE[eBox];
do: POINTER TO StrawDefs.DotObject ← LOOPHOLE[eBox];

GraphicsDefs.DestroyBox[currentBox,FALSE];
IF eBox.Object.command IN
[PressDefs.ELShowDots..PressDefs.ELShowDotsOpaque] THEN
BEGIN
IF do.DotsData.fileName # NIL THEN
SystemDefs.FreeHeapString[do.DotsData.fileName];
END;
--erase=FALSE implies that Object will be released by ReleasePressPage
IF erase THEN
BEGIN
SystemDefs.FreeHeapNode[eBox.Object];
DisplayListDefs.DeleteDisplayItem[currentBox];
RestoreGrid[currentBox];
END
ELSE
GraphicsDefs.ReleaseBox[currentBox];
SystemDefs.FreeHeapNode[currentBox];
END;

SetGrid: PUBLIC PROCEDURE =
BEGIN
GridSize ← GetNum["Dot spacing (72 = 1 inch): "];
Refresh[];
END;

RestoreGrid
: PUBLIC PROCEDURE [currentBox: POINTER TO GraphicsDefs.Box] =
BEGIN IF GridSize = 0 THEN RETURN;
BEGIN
x1: CARDINAL ← currentBox.displayX - (currentBox.displayX MOD GridSize);
x2: CARDINAL ← currentBox.displayX + currentBox.boxBitmap.nBits;
y1: CARDINAL ← currentBox.displayY;
y2: CARDINAL ← y1 + currentBox.boxBitmap.nLines;
x,y: CARDINAL;
IF INTEGER[x2] < 0 OR INTEGER[y2] < 0 THEN RETURN;
IF INTEGER[x1] < 0 THEN x1 ← 0;
IF INTEGER[y1] < 0 THEN y1 ← 0;
FOR y ← (y1-(y1 MOD GridSize)),y+GridSize UNTIL y > y2
DO FOR x ← x1,x+GridSize UNTIL x > x2
DO GraphicsDefs.PutPoint[x,y];ENDLOOP;
ENDLOOP;
END;
END;

MakeLongPointer: PROCEDURE [ptr: POINTER,bank: UNSPECIFIED] RETURNS [LONG POINTER] = MACHINE CODE BEGIN END;

Real.InitReals[];
Main[];
END.