-- Compiler Refresh/n
-- m.stone January 29, 1981 4:45 PM
-- Last Edited by: Stone, February 14, 1983 3:16 pm

DIRECTORY
 GriffinDefs: FROM "GriffinDefs",
 ObjectDefs: FROM "ObjectDefs",
 ScreenDefs: FROM "ScreenDefs",
 PointDefs: FROM "PointDefs",
 RefreshDefs: FROM "RefreshDefs",
 XFormDefs: FROM "XFormDefs",
 MergeDefs: FROM "MergeDefs",
 GriffinViewer USING [PaintProc, DoPaint],
 GriffinMemoryDefs USING [CZone];

Refresh: PROGRAM
IMPORTS ObjectDefs,ScreenDefs,GriffinMemoryDefs, MergeDefs, GriffinViewer
EXPORTS RefreshDefs =
BEGIN OPEN ObjectDefs,PointDefs,GriffinMemoryDefs;
Frame: TYPE = REF FrameType;
FrameType: TYPE = RECORD
 [next: Frame,
 back: Frame,
 tl,br: ScrPt,
 obj: ObjectHandle,
 useNext: BOOLEAN];
newFrameH,newFrameT,bFrameH,bFrameT,tFrameH,tFrameT: Frame ← NIL;

EraseAndSave: PUBLIC PROCEDURE[obj: ObjectHandle]=
BEGIN
tl,br: ScrPt;
IF obj=NIL THEN RETURN;
tl ← obj.tl;
br ← obj.br;
IF obj.objectType#token AND obj.objectType#menu THEN BEGIN
 tl ← [tl[X]-selW,tl[Y]-selW];
 br ← [br[X]+selW,br[Y]+selW];
END;
EraseAndSaveBox[tl,br];
END;

EraseAndSaveBox: PUBLIC PROCEDURE[tl,br: ScrPt]=
BEGIN
ScreenDefs.EraseBox[tl,br, NIL];
[tl,br] ← ScreenDefs.ClipToScreen[tl,br];
IF br[X]>=tl[X] AND br[Y]>=tl[Y] THEN AddFrame[tl,br,newFrameT];
END;

PlotAndMark: PUBLIC PROCEDURE[obj: ObjectHandle]=
BEGIN
newframe: Frame ← NIL;
IF obj=NIL THEN RETURN;
IF ~obj.validEncoding THEN ObjectDefs.PlotOneObject[obj,write];
newframe ← MakeBox[obj.tl,obj.br,obj];
newframe.useNext ← TRUE;
newframe.obj ← obj;
END;

MarkBox: PUBLIC PROCEDURE[tl,br: ScrPt, obj: ObjectHandle]=
BEGIN
newframe: Frame ← NIL;
IF obj=NIL THEN RETURN;
newframe ← MakeBox[tl,br,obj];
newframe.obj ← obj;
END;

MakeBox: PROCEDURE[tl,br: ScrPt, obj: ObjectHandle] RETURNS[newFrame: Frame]=
BEGIN
IF obj=NIL THEN RETURN[NIL];
--space for select token
IF obj.objectType=shape OR obj.objectType=caption THEN BEGIN
 tl ← [tl[X]-selW,tl[Y]-selW];
 br ← [br[X]+selW,br[Y]+selW];
END;
[tl,br] ← ScreenDefs.ClipToScreen[tl,br];
IF br[X]>=tl[X] AND br[Y]>=tl[Y] THEN AddFrame[tl,br,newFrameT];
RETURN[newFrameT.back];
END;

EraseAndSaveAllCPs: PUBLIC PROCEDURE=
BEGIN
EraseCPs: ObjectDefs.ObjectProc = BEGIN
WITH token: obj SELECT FROM
 token=> IF token.tokenType=CP OR token.tokenType=open THEN EraseAndSave[obj];
ENDCASE;
END;
ObjectDefs.ForAllVisibleObjects[EraseCPs];
END;

RestoreScreen: PUBLIC PROCEDURE=
BEGIN
frame,tptr: Frame;
area: MergeDefs.AreaDescriptor ← MergeDefs.AreaCreate[];
paint: GriffinViewer.PaintProc = {
 FOR frame← bFrameH.next, frame𡤏rame.next UNTIL frame=bFrameT DO
  IF frame.obj=NIL THEN ReplotBox[frame.tl,frame.br, dc]
  ELSE ReplotBoxFromObject[frame.tl,frame.br,frame.obj, dc];
  ENDLOOP;
 };
saveBox: PROC [tl,br: ScrPt, z: INTEGER] = {
-- ScreenDefs.EraseBox[tl,br];
 AddFrame[tl,br,bFrameT];
 };
frame ← newFrameH.next;
UNTIL frame=newFrameT DO
IF frame.obj=NIL THEN {
  MergeDefs.AreaNewBox[area,frame.tl,frame.br,0];
  frame ← DeleteFrame[frame]}
ELSE frame ← frame.next;
ENDLOOP;
MergeDefs.AreaGenerate[area,saveBox];
MergeDefs.AreaDestroy[area];
--now have non-intersecting set of erase frames
--clip the overlapping areas and add outside pieces to eraseFrames
frame ← newFrameH.next;
UNTIL frame=newFrameT DO
 tptr ← frame.next; --ClipAndAdd deletes
 ClipAndAdd[frame];
 frame ← tptr;
ENDLOOP;
--bFrameH is the head of all the areas to be cleaned up
YSort[bFrameH,bFrameT];
GriffinViewer.DoPaint[paint]; --do it in a paint proc
frame ← bFrameH.next;
UNTIL frame=bFrameT DO
 frame ← DeleteFrame[frame];
ENDLOOP;
END;

--take the new frame and compare it to the list headed by bFrameH
--take outside pieces and add them to bFrameH
ClipAndAdd: PROC [frame: Frame, start: Frame ← bFrameH.next] = {
 rover: Frame ← NIL;
FOR rover ← start, rover.next UNTIL rover=bFrameT DO
  SELECT TRUE FROM
  Inside[frame,rover] => {frame ← DeleteFrame[frame]; RETURN};
  Outside[frame,rover] => LOOP;
--now have to clip the frame against rover, then Clip and add all the pieces
  ENDCASE => {
   ClipBox[frame,rover]; --returns a list and Deletes frame
   FOR frame ← tFrameT.back, tFrameT.back UNTIL frame=tFrameH DO
    ClipAndAdd[frame,rover];
    ENDLOOP;
   RETURN;
   };
  ENDLOOP;
--if we get here, frame did not intersect anything. Add it to bFrameH
 AddFrameH[frame.tl,frame.br,bFrameH];
 frame ← DeleteFrame[frame];
RETURN;
 };

ClipBox: PROC[frame,clipper: Frame] = {
DO SELECT TRUE FROM
 Inside[frame,clipper] => {[] ← DeleteFrame[frame]; EXIT};
 frame.tl[Y]<clipper.tl[Y] => {
  AddFrameH[frame.tl,[frame.br[X],clipper.tl[Y]-1], tFrameH];
  frame.tl[Y] ← clipper.tl[Y];
  };
 frame.br[Y]>clipper.br[Y] => {
  AddFrameH[[frame.tl[X],clipper.br[Y]+1], frame.br, tFrameH];
  frame.br[Y] ← clipper.br[Y];
  };
ENDCASE => SELECT TRUE FROM
  frame.tl[X]<clipper.tl[X] => {
   AddFrameH[frame.tl,[clipper.tl[X]-1,frame.br[Y]], tFrameH];
   frame.tl[X] ← clipper.tl[X];
   };
  frame.br[X]>clipper.br[X] => {
   AddFrameH[[clipper.br[X]+1,frame.tl[Y]],frame.br, tFrameH];
   frame.br[X] ← clipper.br[X];
   };
  ENDCASE;
ENDLOOP;
 YSort[tFrameH,tFrameT];
 };

YSort: PROC[head,tail: Frame] = {
--sort in Y
 rover: Frame ← NIL;
 switches: INTEGER;
DO
  switches ← 0; rover ← head.next;
  UNTIL rover=tail DO
   IF rover.tl[Y]>rover.next.tl[Y] THEN {
    Switch[rover,rover.next];
    switches ← switches+1;}
   ELSE rover ← rover.next;
   ENDLOOP;
  IF switches=0 THEN EXIT;
  ENDLOOP;
 };

Inside: PROC[frame,clipper: Frame] RETURNS [BOOLEAN] = INLINE {
RETURN[PointInside[frame.tl,clipper.tl,clipper.br] AND
  PointInside[frame.br,clipper.tl,clipper.br]];
 };

PointInside: PROC[pt,tl,br: ScrPt] RETURNS [BOOLEAN] = INLINE {
RETURN[pt[X] IN [tl[X]..br[X]] AND pt[Y] IN [tl[Y]..br[Y]]];
 };

Outside: PROC[frame,clipper: Frame] RETURNS [BOOLEAN] = INLINE {
RETURN[frame.tl[Y]>clipper.br[Y] OR frame.br[Y]<clipper.tl[Y]
  OR frame.tl[X]>clipper.br[X] OR frame.br[X]<clipper.tl[X]];
   };

Switch: PROCEDURE[left,right: Frame]=
BEGIN
left.back.next ← right;
right.next.back ← left;
right.back ← left.back;
left.next ← right.next;
left.back ← right;
right.next ← left;
END;

AddFrameH: PROCEDURE[tl,br: ScrPt,head: Frame]=
BEGIN
newframe: Frame ← CZone.NEW[FrameType] ;
newframe^ ← [head.next,head,tl,br,NIL,FALSE];
newframe.next.back ← newframe;
head.next ← newframe;
END;

AddFrame: PROCEDURE[tl,br: ScrPt,tail: Frame]=
BEGIN
newframe: Frame ← CZone.NEW[FrameType];
newframe^ ← [tail,tail.back,tl,br,NIL,FALSE];
newframe.back.next ← newframe;
tail.back ← newframe;
END;

DeleteFrame: PROCEDURE[frame: Frame] RETURNS[next: Frame] =
BEGIN
frame.next.back ← frame.back;
frame.back.next ← frame.next;
next ← frame.next;
END;

InitHeadTail: PROCEDURE RETURNS [head,tail: Frame]=
BEGIN
head ← CZone.NEW[FrameType];
tail ← CZone.NEW[FrameType];
head^ ← [tail,NIL,[0,0],[0,0],NIL,FALSE];
tail^ ← [NIL,head,[808,808],[808,808],NIL,FALSE];
END;

[newFrameH,newFrameT] ← InitHeadTail[];
[bFrameH,bFrameT] ← InitHeadTail[];
[tFrameH,tFrameT] ← InitHeadTail[];
END.