-- File CIFDevicesControl.mesa
-- Written by Martin Newell, March 1980
-- Last updated: March 27, 1981 5:33 PM

-- Provides multiple implementations of Trapezoid for different devices

DIRECTORY

CIFDevicesDefs: FROM "CIFDevicesDefs" USING [DeviceDescriptor,
DeviceDescriptorRecord, MaxLENGTHLayerArray],
CIFOutDevice: FROM "CIFOutDevice" USING [MakeCIFOutDevice, SetCurrentDevice],
CIFScreenDefs: FROM "CIFScreenDefs" USING [CIFScreen],
CIFUtilitiesDefs: FROM "CIFUtilitiesDefs" USING [Rectangle],
Graphics USING [DeviceContext],
IODefs: FROM "IODefs" USING [SP, WriteString, WriteLine],
OpaqueDevice: FROM "OpaqueDevice" USING [DeviceContext],
ParserErrorDefs: FROM "ParserErrorDefs" USING [ErrorType, Report],
StringDefs: FROM "StringDefs" USING [EqualString],
SystemDefs: FROM "SystemDefs" USING [AllocateHeapNode, FreeHeapNode];

CIFDevicesControl: PROGRAM
IMPORTS CIFOutDevice, CIFScreenDefs, IODefs, ParserErrorDefs, StringDefs, SystemDefs
EXPORTS CIFDevicesDefs =

BEGIN OPEN CIFDevicesDefs, CIFOutDevice, CIFScreenDefs, CIFUtilitiesDefs, IODefs, OpaqueDevice, ParserErrorDefs, StringDefs, SystemDefs;

SelectDevice: PUBLIC PROCEDURE [deviceName: STRING] RETURNS[ok: BOOLEAN] =
BEGIN
device: DeviceDescriptor ← LookupDevice[deviceName];
IF device=NIL THEN
BEGIN
WriteString["Unknown device in SelectDevice: "];
WriteLine[deviceName];
RETURN[FALSE];
END;
IF (ok←device.deviceSelect[]) THEN SelectedDevice ← device;
END;

DrawFrame: PUBLIC PROCEDURE =
BEGIN
SelectedDevice.deviceDrawFrame[];
END;

SetScale: PUBLIC PROCEDURE [factor: REAL] =
BEGIN
SelectedDevice.deviceSetScale[factor];
END;

SetClipRegion: PUBLIC PROCEDURE [rt: Rectangle] =
BEGIN
SelectedDevice.deviceSetClipRegion[rt];
END;

OutputDevice: PUBLIC PROCEDURE =
BEGIN
CurrentDevice ← SelectedDevice;
SetCurrentDevice[CurrentDevice];
LayerString ← [SP,SP,SP,SP];
CurrentDevice.deviceOutput[];

CurrentDevice ← ScreenDevice;
END;

Draw: PUBLIC PROCEDURE =
BEGIN
ScreenDevice.deviceOutput[];
SelectedDevice.deviceDrawFrame[];
END;

LookupLayer: PUBLIC PROCEDURE [s: PACKED ARRAY [0..4) OF CHARACTER]
RETURNS[CARDINAL] =
-- Looks up layer number - makes new entry if necessary
BEGIN
i: CARDINAL;
IF s=LayerString THEN RETURN[LayerIndex];

FOR i IN [0..LENGTHLayerArray) DO
IF s=LayerArray[i] THEN
BEGIN
LayerString ← s;
LayerIndex ← i;
RETURN[LayerIndex];
END;
ENDLOOP;
--
No such layer - make one
--
Report["New Layer",Advisory];
IF LENGTHLayerArray=MaxLENGTHLayerArray THEN
BEGIN
Report["Too many layers",Fatal];
RETURN[0];
END;
LayerString ← s;
LayerIndex ← LENGTHLayerArray;
LayerArray[LayerIndex] ← s;
LENGTHLayerArray ← LENGTHLayerArray + 1;
RETURN[LayerIndex];
END;

LookupLayerString: PUBLIC PROCEDURE[layerName: STRING] RETURNS[CARDINAL] =
BEGIN
sa: PACKED ARRAY [0..4) OF CHARACTER ← [SP,SP,SP,SP];
i: CARDINAL;
FOR i IN [0..MIN[4,layerName.length]) DO sa[i] ← layerName[i]; ENDLOOP;
RETURN[LookupLayer[sa]];
END;

SetLayer: PUBLIC PROCEDURE [layer: CARDINAL] =
BEGIN
CurrentDevice.deviceLayer[layer];
END;

LoadLayer: PUBLIC PROCEDURE[layer: CARDINAL, v0,v1,v2,v3: CARDINAL] =
BEGIN
SelectedDevice.deviceLoadLayer[layer, v0,v1,v2,v3];
END;

SetLayerVisible: PUBLIC PROCEDURE[layer: CARDINAL, visible: BOOLEAN] =
BEGIN
VisibleArray[layer] ← visible;
END;

LayerVisible: PUBLIC PROCEDURE[layer: CARDINAL] RETURNS[visible: BOOLEAN] =
BEGIN
RETURN[VisibleArray[layer]];
END;

OutputText: PUBLIC PROCEDURE[text: STRING, x,y: REAL] =
BEGIN
CurrentDevice.deviceText[text,x,y];
END;

RegisterDevice: PUBLIC PROCEDURE[device: DeviceDescriptor] =
BEGIN
dev: DeviceDescriptor ← AllocateHeapNode[SIZE[DeviceDescriptorRecord]];
dev↑ ← device↑;
dev.next ← DeviceList;
DeviceList ← dev;
END;

UnRegisterDevice: PUBLIC PROCEDURE[deviceName: STRING] =
BEGIN
deviceptr: POINTER TO DeviceDescriptor;
FOR deviceptr ← @DeviceList, @deviceptr.next UNTIL deviceptr↑=NIL DO
IF EqualString[deviceName,deviceptr.name] THEN
BEGIN
dev: DeviceDescriptor ← deviceptr↑;
deviceptr↑ ← deviceptr.next;
FreeHeapNode[dev];
RETURN;
END;
ENDLOOP;
END;

GetCIFOutDevice: PUBLIC PROCEDURE RETURNS[device: Graphics.DeviceContext] =
BEGIN
RETURN[DC];
END;

--Private procedures--

LookupDevice: PROCEDURE[deviceName: STRING] RETURNS[device: DeviceDescriptor] =
BEGIN
FOR device ← DeviceList, device.next UNTIL device=NIL DO
IF EqualString[deviceName,device.name] THEN RETURN;
ENDLOOP;
END;

DeviceList: DeviceDescriptor ← NIL;
SelectedDevice: DeviceDescriptor;
CurrentDevice: DeviceDescriptor;
ScreenDevice: DeviceDescriptor;

--Make the CedarGraphics CIFOutDevice for all devices other than the Screen
DC: OpaqueDevice.DeviceContext ← MakeCIFOutDevice[];

-- Data for LookupLayer

LayerIndex: CARDINAL ← 0;
LayerString: PACKED ARRAY [0..4) OF CHARACTER ← [SP,SP,SP,SP];
LENGTHLayerArray: PUBLIC CARDINAL ← 8;

LayerArray: ARRAY [0..MaxLENGTHLayerArray) OF PACKED ARRAY [0..4) OF CHARACTER;
VisibleArray: ARRAY [0..MaxLENGTHLayerArray) OF BOOLEAN ← ALL[TRUE];

--Set up default layer names
LayerArray[0] ← [’N,’I,SP,SP];
LayerArray[1] ← [’N,’D,SP,SP];
LayerArray[2] ← [’N,’P,SP,SP];
LayerArray[3] ← [’N,’C,SP,SP];
LayerArray[4] ← [’N,’M,SP,SP];
LayerArray[5] ← [’N,’B,SP,SP];
LayerArray[6] ← [’N,’G,SP,SP];
LayerArray[7] ← [’N,’X,SP,SP];

--Always have Screen device
START CIFScreen;
[] ← SelectDevice["screen"];
ScreenDevice ← SelectedDevice;
CurrentDevice ← SelectedDevice;

END.