-- StrawSil.mesa
-- Written by Joe Maleson
-- Last changed by Doug Wyatt, October 27, 1980 4:40 PM

DIRECTORY
DisplayListDefs: FROM "DisplayListDefs",
GraphicsDefs: FROM "GraphicsDefs",
InlineDefs,
IODefs: FROM "IODefs" USING [GetInputStream],
MagicDefs: FROM "MagicDefs" USING [Menu],
PressDefs: FROM "PressDefs" USING [PressObject,SignedMulDiv,MulDiv,
ELShowRectangle,ELShowObject,ELShowCharacters,ELShowDots,
ELShowDotsOpaque,PressDotsData],
ProcessDefs: FROM "ProcessDefs" USING [Yield],
StrawDefs: FROM "StrawDefs",
StreamDefs: FROM "StreamDefs" USING [StreamHandle],
SystemDefs: FROM "SystemDefs" USING
[AllocateHeapNode,FreeHeapNode];

StrawSil: PROGRAM IMPORTS DisplayListDefs,GraphicsDefs,InlineDefs,IODefs,MagicDefs, PressDefs,ProcessDefs,StrawDefs,SystemDefs
EXPORTS StrawDefs =
BEGIN
Buttons: TYPE = MACHINE DEPENDENT RECORD
[ KeyPadAndGarbage: [0..10000B),
Mark: BOOLEAN, --TRUE means button up
Select: BOOLEAN,
Draw: BOOLEAN
];
KeyWord2: TYPE = MACHINE DEPENDENT RECORD
[ One,Esc,Tab,F,Ctrl,C,J,B,Z,LShift,Period,Semi,Return,LArrow,Del,xxx: BOOLEAN
];
MouseButtons: POINTER TO Buttons = LOOPHOLE[177030B];
KeyWord: POINTER TO KeyWord2 = LOOPHOLE[177036B];
MouseX: POINTER TO INTEGER = LOOPHOLE[424B];
MouseY: POINTER TO INTEGER = LOOPHOLE[425B];
CursorX: POINTER TO INTEGER = LOOPHOLE[426B];
CursorY: POINTER TO INTEGER = LOOPHOLE[427B];
bitsPerInch: CARDINAL ← 72;
micasPerInch: CARDINAL = 2540;
keys: StreamDefs.StreamHandle ← IODefs.GetInputStream[];
displayList: POINTER TO ARRAY [0..0) OF POINTER TO GraphicsDefs.Box;
selectionIndex: CARDINAL;
selectGray: CARDINAL ← 15;
waitCount: CARDINAL ← 40;
UnDeleteRecord: TYPE = RECORD
[
count: CARDINAL,
item: ARRAY [0..0) OF POINTER TO GraphicsDefs.Box
];
RealUnDeleteMax: CARDINAL = 6;
UnDeleteStack: ARRAY [1..RealUnDeleteMax] OF POINTER TO UnDeleteRecord;
UnDeleteStackPointer: CARDINAL ← 0;
UnDeleteStackMax: CARDINAL ← RealUnDeleteMax-1;
Ctrl: ARRAY CHARACTER [’A..’Z] OF CHARACTER =
[1C,2C,3C,4C,5C,6C,7C,10C,11C,12C,13C,
14C,15C,16C,17C,20C,21C,22C,23C,24C,25C,26C,27C,30C,31C,32C];
ScreenHeight: CARDINAL ← GraphicsDefs.GetDefaultBitmapHandle[].nLines;

Mica: TYPE = INTEGER;
OriginX: Mica ← 0;
OriginY: Mica ← 0;
MarkX: Mica ← 0;
MarkY: Mica ← 0;
ButtonX: Mica ← 0;
ButtonY: Mica ← 0;

dc: PROCEDURE [m: Mica] RETURNS [INTEGER] = INLINE
BEGIN
RETURN[PressDefs.SignedMulDiv[m,bitsPerInch,micasPerInch]];
END;

mc: PROCEDURE [c: CARDINAL] RETURNS [Mica] = INLINE
BEGIN
RETURN[PressDefs.MulDiv[c,micasPerInch,bitsPerInch]];
END;

EditDisplayList: PUBLIC PROCEDURE =
BEGIN OPEN DisplayListDefs;
i: CARDINAL;
ButtonState: Buttons;
MagnifyOn: BOOLEAN ← FALSE;
FlashMarks: PROCEDURE =
BEGIN
GraphicsDefs.XorArea[dc[OriginX],dc[OriginY],dc[OriginX]+3,dc[OriginY]+1];
GraphicsDefs.XorArea[dc[MarkX],dc[MarkY],dc[MarkX]+1,dc[MarkY]+6];
FOR i IN [0..waitCount] DO ProcessDefs.Yield[];ENDLOOP;
GraphicsDefs.XorArea[dc[OriginX],dc[OriginY],dc[OriginX]+3,dc[OriginY]+1];
GraphicsDefs.XorArea[dc[MarkX],dc[MarkY],dc[MarkX]+1,dc[MarkY]+6];
END;

displayList ← DisplayListDefs.GetDisplayListHandle[];
selectionIndex ← DisplayListDefs.GetDisplayCount[];
OriginX ← 0;
OriginY ← 0;

DO --edit loop
DO --wait for all buttons to be released
ButtonState ← MouseButtons↑;
IF (ButtonState.Mark AND ButtonState.Select AND ButtonState.Draw) OR
(NOT keys.endof[keys])
THEN EXIT;
FlashMarks[];
ENDLOOP;
DO --wait for a button to go down
count,i: CARDINAL;
ButtonState ← MouseButtons↑;
IF (NOT (ButtonState.Mark AND ButtonState.Select AND ButtonState.Draw)) OR
(NOT keys.endof[keys])
THEN EXIT;
--check for cursor inside top selected image
count ← DisplayListDefs.GetDisplayCount[];
IF count>0 AND (NOT MagnifyOn) AND (i←count-1)>=selectionIndex
AND DisplayListDefs.Inside[CursorX↑,CursorY↑,displayList[i]] THEN {
OPEN PressDefs;
d: POINTER TO StrawDefs.DotObject ← LOOPHOLE[displayList[i]];
IF d.Object.command IN [ELShowDots..ELShowDotsOpaque] AND
d.DotsData.nBitsPerPixel = 8 THEN StrawDefs.EditGrayImage[d];
};
FlashMarks[];
ENDLOOP;

IF NOT keys.endof[keys] THEN
BEGIN
ch: CHARACTER ← keys.get[keys];
IF MagnifyOn THEN StrawDefs.StopMagnifier[];
SELECT ch FROM
Ctrl[’C] =>
BEGIN
Copy[MarkX-OriginX,MarkY-OriginY];
OriginX ← MarkX;OriginY ← MarkY;
END;
Ctrl[’D] => Delete[];
Ctrl[’I] =>
BEGIN
haveSelection: BOOLEAN ←
selectionIndex<DisplayListDefs.GetDisplayCount[];
IF KeyWord.Ctrl THEN LOOP; --was <TAB>
StrawDefs.SelectFile[];
IF haveSelection THEN
BEGIN UnDeleteStackMax ← UnDeleteStackMax+1;Delete[];
END;
StrawDefs.AddFile[];
selectionIndex ← DisplayListDefs.GetDisplayCount[];
IF haveSelection THEN
BEGIN UnDelete[];UnDeleteStackMax ← UnDeleteStackMax-1;
END;
END;
Ctrl[’K] =>
BEGIN
ClearUnDeleteStack[];
StrawDefs.NewPage[];
StrawDefs.Refresh[];
selectionIndex ← 0;
END;
Ctrl[’M] =>
BEGIN
IF KeyWord.Ctrl THEN LOOP; --was <CR>
MagnifyOn ← NOT MagnifyOn;
IF MagnifyOn THEN
BEGIN
StrawDefs.SetMagnifierPosition[MarkX,MarkY];
END;
END;
Ctrl[’O] => StrawDefs.WriteFile[];
Ctrl[’Q] => EXIT;
Ctrl[’T] =>
BEGIN nItems: CARDINAL ← DisplayListDefs.GetDisplayCount[];
RemoveSelections[];ResetDisplayCount[selectionIndex];
StrawDefs.SetGrid[];
ResetDisplayCount[nItems];ShowSelections[];
END;
Ctrl[’U] => BEGIN NewSelection[];UnDelete[];END;
Ctrl[’X] =>
BEGIN
temp: INTEGER;
Move[MarkX-OriginX,MarkY-OriginY];
temp ← MarkX;MarkX ← OriginX;OriginX ← temp;
temp ← MarkY;MarkY ← OriginY;OriginY ← temp;
END;
ENDCASE;
IF MagnifyOn THEN StrawDefs.StartMagnifier[selectionIndex,selectGray];
LOOP;
END;

IF MagnifyOn THEN [ButtonX,ButtonY] ←
StrawDefs.MagToMicaCoords[CursorX↑,CursorY↑]
ELSE BEGIN ButtonX ← mc[CursorX↑];ButtonY ← mc[CursorY↑];END;

IF NOT ButtonState.Select THEN
BEGIN
IF MagnifyOn THEN StrawDefs.StopMagnifier[];
IF NOT (KeyWord.Ctrl OR KeyWord.LShift) THEN --"DeSelect"
BEGIN
DeSelect[];
END
ELSE IF NOT KeyWord.Ctrl THEN --"AddSelect"
BEGIN
Select[];
END
ELSE IF NOT KeyWord.LShift THEN --"AreaSelect"
BEGIN
OriginX ← ButtonX;
OriginY ← ButtonY;
NewSelection[];
SelectArea[];
END
ELSE
BEGIN
--"Select"
NewSelection[];
Select[];
END;
IF MagnifyOn THEN StrawDefs.StartMagnifier[selectionIndex,selectGray];
LOOP;
END;

IF NOT ButtonState.Draw THEN
BEGIN
IF MagnifyOn THEN StrawDefs.StopMagnifier[];
IF NOT (KeyWord.Ctrl OR KeyWord.LShift) THEN --"UnDelete"
BEGIN
NewSelection[];
UnDelete[];
END
ELSE IF NOT KeyWord.Ctrl THEN --"Copy"
BEGIN
dx: INTEGER ← ButtonX - OriginX;
dy: INTEGER ← ButtonY - OriginY;
Copy[dx,dy];
MarkX ← OriginX ← OriginX + dx;
MarkY ← OriginY ← OriginY + dy;
END
ELSE IF NOT KeyWord.LShift THEN --"Delete"
BEGIN
NewSelection[];
Select[];
Delete[];
END
ELSE
BEGIN
--"Help"
Help[];
END;
IF MagnifyOn THEN StrawDefs.StartMagnifier[selectionIndex,selectGray];
LOOP;
END;

IF NOT ButtonState.Mark THEN
BEGIN
IF NOT (KeyWord.Ctrl OR KeyWord.LShift) THEN --"Move Magnifier"
BEGIN
IF NOT MagnifyOn THEN
BEGIN
MagnifyOn ← TRUE;
StrawDefs.SetMagnifierPosition[ButtonX,ButtonY];
StrawDefs.StartMagnifier[selectionIndex,selectGray];
END;
WHILE NOT (KeyWord.Ctrl OR KeyWord.LShift OR MouseButtons.Mark)
DO
[ButtonX,ButtonY] ←
StrawDefs.MagToMicaCoords[CursorX↑,CursorY↑];
StrawDefs.SetMagnifierPosition[ButtonX,ButtonY];
StrawDefs.ShowMagnifier[];
ENDLOOP;
END
ELSE
BEGIN
IF MagnifyOn THEN
IF StrawDefs.ModifyMagnifier[dc[ButtonX],dc[ButtonY]] THEN
BEGIN
WHILE (NOT MouseButtons.Mark) AND
StrawDefs.ModifyMagnifier[CursorX↑,CursorY↑] DO ENDLOOP;
LOOP;
END
ELSE StrawDefs.StopMagnifier[];
IF NOT KeyWord.Ctrl THEN --Move
BEGIN
dx: INTEGER ← ButtonX - OriginX;
dy: INTEGER ← ButtonY - OriginY;
Move[dx,dy];
MarkX ← OriginX;
MarkY ← OriginY;
OriginX ← OriginX + dx;
OriginY ← OriginY + dy;
END
ELSE IF NOT KeyWord.LShift THEN --"MoveOrigin"
BEGIN
OriginX ← ButtonX;
OriginY ← ButtonY;
END
ELSE
BEGIN
--"Mark"
MarkX ← ButtonX;
MarkY ← ButtonY;
END;
IF MagnifyOn THEN StrawDefs.StartMagnifier[selectionIndex,selectGray];
END; --non-magnify stuff
LOOP;
END;

ENDLOOP; --main loop
RemoveSelections[];
FOR i IN [selectionIndex..DisplayListDefs.GetDisplayCount[]) DO UnSelect[i]; ENDLOOP;
--and clear out the UnDeleteStack
ClearUnDeleteStack[];
END;
Help: PROCEDURE =
BEGIN
HelpMenu: ARRAY [0..7) OF STRING ←
[
" | Shift Ctrl CtlShft",
"-----------------------------------",
"Mark | MARK ORIGIN MOVE MAGNIFY",
"Draw | HELP DELETE COPY UNDELETE",
"Select| SEL AREA ADD DESELECT",
"-----------------------------------",
" keys| ↑C,↑D,↑I,↑K,↑M,↑O,↑Q,↑T,↑U,↑X"
];
font: POINTER TO GraphicsDefs.StrikeFont ← GraphicsDefs.GetStrikeHandle["Gacha10"];
[] ← MagicDefs.Menu[7,LOOPHOLE[@HelpMenu],font];
END;

Copy: PROCEDURE [dx,dy: Mica] =
BEGIN
i: CARDINAL;
newEBox,eBox: POINTER TO StrawDefs.EntityBox;
obj: POINTER TO PressDefs.PressObject;
nItems: CARDINAL ← DisplayListDefs.GetDisplayCount[];
objSize: CARDINAL;
RemoveSelections[];
FOR i IN [selectionIndex..nItems) DO
eBox ← LOOPHOLE[displayList[i]];
IF eBox.Object.command IN
[PressDefs.ELShowDots..PressDefs.ELShowDotsOpaque] THEN
BEGIN
do: POINTER TO StrawDefs.DotObject ←
SystemDefs.AllocateHeapNode[SIZE[StrawDefs.DotObject]];
newEBox ← LOOPHOLE[do];
objSize ← SIZE[PressDefs.PressObject]+SIZE[PressDefs.PressDotsData];
obj ← SystemDefs.AllocateHeapNode[objSize];
do.DotsData ← LOOPHOLE[obj+SIZE[PressDefs.PressObject]];
END
ELSE
BEGIN
newEBox ← SystemDefs.AllocateHeapNode[SIZE[StrawDefs.EntityBox]];
objSize ← SIZE[PressDefs.PressObject];
obj ← SystemDefs.AllocateHeapNode[objSize];
END;
GraphicsDefs.CreateBox[@newEBox.Box,eBox.Box.boxBitmap.nBits,
eBox.Box.boxBitmap.nLines];
InlineDefs.COPY[from:eBox.Object,nwords:objSize,to:obj];
newEBox.Object ← obj;
newEBox.Box.function ← eBox.Box.function;
newEBox.Box.type ← eBox.Box.type;
newEBox.Box.gray ← eBox.Box.gray;

newEBox.Object.micaX ← eBox.Object.micaX + dx;
newEBox.Object.micaY ← eBox.Object.micaY - dy;
GraphicsDefs.PutBitmap[@eBox.Box.boxBitmap,0,0,
@newEBox.Box.boxBitmap];
DisplayListDefs.AddDisplayItem[@newEBox.Box];
[newEBox.Box.displayX,newEBox.Box.displayY] ←
ScreenCoords[newEBox];
ENDLOOP;
FOR i IN [selectionIndex..nItems) DO UnSelect[i];ENDLOOP;
ShowSelections[];
END;

RemoveSelections: PROCEDURE =
BEGIN
i: CARDINAL;
FOR i DECREASING IN [selectionIndex..DisplayListDefs.GetDisplayCount[])
DO GraphicsDefs.RemoveBox[displayList[i]]; ENDLOOP;
END;

ShowSelections: PROCEDURE =
BEGIN
i: CARDINAL;
d: POINTER TO GraphicsDefs.Box;
FOR i IN [selectionIndex..DisplayListDefs.GetDisplayCount[]) DO
d ← displayList[i];
GraphicsDefs.DisplayBox[d,d.displayX,d.displayY];
ENDLOOP;
END;

ScreenCoords: PROCEDURE [e: POINTER TO StrawDefs.EntityBox] RETURNS [x,y: INTEGER] =
BEGIN OPEN PressDefs;
obj: POINTER TO PressObject ← e.Object;
--displayX,displayY refer to top left corner.
--different objects use different reference points, so be careful
SELECT e.Object.command FROM
ELShowObject =>
BEGIN
x ← dc[obj.micaX+obj.spaceX];
y ← ScreenHeight-dc[obj.micaY+obj.spaceY];
END;
ELShowRectangle,ELShowDots,ELShowDotsOpaque =>
BEGIN
x ← dc[obj.micaX];
y ← ScreenHeight-dc[obj.micaY+obj.spaceY];
END;
ELShowCharacters =>
BEGIN
strike: POINTER TO GraphicsDefs.StrikeFont;
[strike,,,] ← StrawDefs.GetFont[obj.font];
x ← dc[obj.micaX];
y ← ScreenHeight-(dc[obj.micaY]+strike.ascent);
END;
ENDCASE => ERROR; --can’t move guys with unknown reference points
END;

Move: PROCEDURE [dx,dy: Mica] =
BEGIN
i: CARDINAL;
eBox: POINTER TO StrawDefs.EntityBox;
x,y: INTEGER;
IF dx = 0 AND dy = 0 THEN RETURN;

IF (DisplayListDefs.GetDisplayCount[]-selectionIndex) > 1 THEN
FOR i DECREASING IN [selectionIndex..DisplayListDefs.GetDisplayCount[])
DO GraphicsDefs.RemoveBox[displayList[i]]; ENDLOOP;

FOR i IN [selectionIndex..DisplayListDefs.GetDisplayCount[])
DO
eBox ← LOOPHOLE[displayList[i]];
eBox.Object.micaX ← eBox.Object.micaX + dx;
eBox.Object.micaY ← eBox.Object.micaY - dy;
[x,y] ← ScreenCoords[eBox];
GraphicsDefs.MoveBox[@eBox.Box,x,y];
ENDLOOP;
END;

Delete: PROCEDURE =
BEGIN
i: CARDINAL;
nItems: CARDINAL ← DisplayListDefs.GetDisplayCount[];
d: POINTER TO GraphicsDefs.Box;
eBox: POINTER TO StrawDefs.EntityBox;
u: POINTER TO UnDeleteRecord;

IF selectionIndex = nItems THEN RETURN; --no action
IF UnDeleteStackPointer = UnDeleteStackMax THEN --real delete
BEGIN
FOR i IN [0..UnDeleteStack[1].count) DO
d ← UnDeleteStack[1].item[i];
eBox ← LOOPHOLE[d];
GraphicsDefs.DestroyBox[d,FALSE];
SystemDefs.FreeHeapNode[eBox.Object];
SystemDefs.FreeHeapNode[d];
ENDLOOP;
SystemDefs.FreeHeapNode[UnDeleteStack[1]];
FOR i IN [1..UnDeleteStackMax) DO
UnDeleteStack[i] ← UnDeleteStack[i+1];
ENDLOOP;
END
ELSE UnDeleteStackPointer ← UnDeleteStackPointer+1;

u ← SystemDefs.AllocateHeapNode[(nItems-selectionIndex)+1];
u.count ← nItems-selectionIndex;
UnDeleteStack[UnDeleteStackPointer] ← u;

FOR i DECREASING IN [selectionIndex..nItems) DO
d ← displayList[i];
u.item[i-selectionIndex] ← d;
DisplayListDefs.DeleteDisplayItem[d];
StrawDefs.RestoreGrid[d];
ENDLOOP;
END;

UnDelete: PROCEDURE =
BEGIN
i: CARDINAL;
u: POINTER TO UnDeleteRecord;
IF UnDeleteStackPointer = 0 THEN RETURN; --nothing left

u ← UnDeleteStack[UnDeleteStackPointer];
UnDeleteStackPointer ← UnDeleteStackPointer-1;
FOR i IN [0..u.count) DO
DisplayListDefs.AddDisplayItem[u.item[i]];
ENDLOOP;
SystemDefs.FreeHeapNode[u];
ShowSelections[];
END;

ClearUnDeleteStack: PROCEDURE =
BEGIN
d: POINTER TO GraphicsDefs.Box;
eBox: POINTER TO StrawDefs.EntityBox;
i: CARDINAL;
UNTIL UnDeleteStackPointer = 0 DO
FOR i IN [0..UnDeleteStack[UnDeleteStackPointer].count) DO
d ← UnDeleteStack[UnDeleteStackPointer].item[i];
eBox ← LOOPHOLE[d];
GraphicsDefs.DestroyBox[d,FALSE];
SystemDefs.FreeHeapNode[eBox.Object];
SystemDefs.FreeHeapNode[d];
ENDLOOP;
SystemDefs.FreeHeapNode[UnDeleteStack[UnDeleteStackPointer]];
UnDeleteStackPointer ← UnDeleteStackPointer-1;
ENDLOOP;
END;

NewSelection: PROCEDURE =
BEGIN OPEN GraphicsDefs;
d: POINTER TO Box;
i: CARDINAL;
RemoveSelections[];
FOR i IN [selectionIndex..DisplayListDefs.GetDisplayCount[]) DO
d ← displayList[i];
SetGrayLevel[selectGray];
XorGray[0,0,d.boxBitmap.nBits,d.boxBitmap.nLines,@d.boxBitmap];
DisplayBox[d,d.displayX,d.displayY];
ReleaseBox[d];
ENDLOOP;
selectionIndex ← DisplayListDefs.GetDisplayCount[];
END;

Select: PROCEDURE =
BEGIN
i: CARDINAL;
x: INTEGER ← dc[ButtonX];
y: INTEGER ← dc[ButtonY];
FOR i DECREASING IN [0..selectionIndex) DO
IF DisplayListDefs.Inside[x,y,displayList[i]] THEN
BEGIN
d: POINTER TO GraphicsDefs.Box ← displayList[i];
RemoveSelections[];
MakeSelect[i];
ShowSelections[];
EXIT;
END;
ENDLOOP;
END;

SelectArea: PROCEDURE =
BEGIN
i: CARDINAL;
x1: INTEGER ← dc[MIN[OriginX,MarkX]];
y1: INTEGER ← dc[MIN[OriginY,MarkY]];
x2: INTEGER ← dc[MAX[OriginX,MarkX]];
y2: INTEGER ← dc[MAX[OriginY,MarkY]];
d: POINTER TO GraphicsDefs.Box;
nItems: CARDINAL ← DisplayListDefs.GetDisplayCount[];
lastItem: CARDINAL ← nItems-1;

FOR i DECREASING IN [0..selectionIndex) DO
d ← displayList[i];
IF INTEGER[d.displayX] >= x1 AND INTEGER[d.displayY] >= y1 AND
INTEGER[d.displayX+d.boxBitmap.nBits] <= x2 AND
INTEGER[d.displayY+d.boxBitmap.nLines] <= y2 THEN
BEGIN
MakeSelect[i];
END;
ENDLOOP;

--first, need to unscramble them
FOR i IN [0..(nItems-selectionIndex)/2) DO
d ← displayList[lastItem-i];
displayList[lastItem-i] ← displayList[selectionIndex+i];
displayList[selectionIndex+i] ← d;
ENDLOOP;

FOR i IN [selectionIndex..nItems) DO
d ← displayList[i];
GraphicsDefs.DisplayBox[d,d.displayX,d.displayY];
ENDLOOP;
OriginX ← MIN[OriginX,MarkX];
OriginY ← MIN[OriginY,MarkY];
END;

MakeSelect: PROCEDURE [i: CARDINAL] =
BEGIN
d: POINTER TO GraphicsDefs.Box ← displayList[i];
e: POINTER TO StrawDefs.EntityBox ← LOOPHOLE[d];
DisplayListDefs.DeleteDisplayItem[d];
StrawDefs.RestoreGrid[d];
DisplayListDefs.AddDisplayItem[d];
GraphicsDefs.SetGrayLevel[selectGray];
GraphicsDefs.XorGray[0,0,d.boxBitmap.nBits,d.boxBitmap.nLines,@d.boxBitmap];
OriginX ← mc[d.displayX];
OriginY ← mc[d.displayY];
selectionIndex ← selectionIndex-1;
END;

DeSelect: PROCEDURE =
BEGIN
i: CARDINAL;
x: INTEGER ← dc[ButtonX];
y: INTEGER ← dc[ButtonY];
FOR i DECREASING IN [selectionIndex..DisplayListDefs.GetDisplayCount[]) DO
IF DisplayListDefs.Inside[x,y,displayList[i]] THEN
BEGIN
RemoveSelections[];
UnSelect[i];
ShowSelections[];
EXIT;
END;
ENDLOOP;
END;

UnSelect: PROCEDURE [i: CARDINAL] =
BEGIN
j: CARDINAL;
d: POINTER TO GraphicsDefs.Box ← displayList[i];
GraphicsDefs.SetGrayLevel[selectGray];
GraphicsDefs.XorGray[0,0,d.boxBitmap.nBits,d.boxBitmap.nLines,@d.boxBitmap];
GraphicsDefs.DisplayBox[d,d.displayX,d.displayY];
GraphicsDefs.ReleaseBox[d];
FOR j DECREASING IN [selectionIndex..i) DO
displayList[j+1] ← displayList[j];
ENDLOOP;
displayList[selectionIndex] ← d;
selectionIndex ← selectionIndex+1;
END;


END.