DIRECTORY
Atom, BiScrollers, CedarProcess, GGBasicTypes, GGBoundBox, GGCaret, GGError, GGGravity, GGInterfaceTypes, GGModelTypes, GGObjects, GGRefresh, GGSelect, GGSegmentTypes, GGSequence, GGShapes, GGStatistics, GGTouch, GGTraj, GGUtility, GGVector, Imager, ImagerBackdoor, ImagerOps, ImagerPixelMap, List, Process, Rope, Rosary, SlackProcess, TIPUser, Terminal, Interminal, ViewerClasses, ViewerOps;

GGRefreshImpl: CEDAR MONITOR
IMPORTS Atom, BiScrollers, CedarProcess, GGBoundBox, GGCaret, GGError, GGGravity, GGObjects, GGSelect, GGSequence, GGShapes, GGStatistics, GGTouch, GGTraj, GGUtility, GGVector, Imager, ImagerBackdoor, List, Process, Rope, SlackProcess, Terminal, Interminal, ViewerOps
EXPORTS GGRefresh = BEGIN

BitVector: TYPE = GGBasicTypes.BitVector;
BoundBox: TYPE = GGModelTypes.BoundBox;
BoundBoxGenerator: TYPE = GGObjects.BoundBoxGenerator;
CameraData: TYPE = GGModelTypes.CameraData;
Caret: TYPE = GGInterfaceTypes.Caret;
Color: TYPE = Imager.Color;
FeatureData: TYPE = GGGravity.FeatureData;
OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor;
Slice: TYPE = GGModelTypes.Slice;
SliceParts: TYPE = GGModelTypes.SliceParts;
SliceGenerator: TYPE = GGModelTypes.SliceGenerator;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator;
EntityGenerator: TYPE = GGModelTypes.EntityGenerator;
GargoyleData: TYPE = GGInterfaceTypes.GargoyleData;
Joint: TYPE = GGModelTypes.Joint;
JointGenerator: TYPE = GGModelTypes.JointGenerator;
Outline: TYPE = GGModelTypes.Outline;
Point: TYPE = GGBasicTypes.Point;
Scene: TYPE = GGModelTypes.Scene;
Segment: TYPE = GGSegmentTypes.Segment;
SegAndIndex: TYPE = GGSequence.SegAndIndex;
SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator;
Sequence: TYPE = GGModelTypes.Sequence;
SelectionClass: TYPE = GGInterfaceTypes.SelectionClass;
SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator;
Traj: TYPE = GGModelTypes.Traj;
Vector: TYPE = GGBasicTypes.Vector;

Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE;

KillData: TYPE = RECORD [process: UNSAFE PROCESS, gargoyleData: GargoyleData];
NilIt: PRIVATE ENTRY PROC [data: REF KillData] = TRUSTED {data.process _ NIL};
ActionAreaPaint: PUBLIC PROC [screen: Imager.Context, whatHasChanged: ATOM, gargoyleData: GargoyleData] = TRUSTED {
IF whatHasChanged=$ViewersPaintEntireScene THEN { -- need a special abort watcher
data: REF KillData _ NEW[KillData _ [Process.GetCurrent[], gargoyleData]];
[] _ CedarProcess.Fork[Killer, data, [excited, TRUE]];
DoActionAreaPaint[screen, whatHasChanged, gargoyleData ! UNWIND => NilIt[data]];
NilIt[data];
}
ELSE DoActionAreaPaint[screen, whatHasChanged, gargoyleData]; -- SlackProcess is watching for aborts
};

Killer: PROC [data: REF] RETURNS [results: REF _ NIL] = {
KillKeysDown: PROC RETURNS [kill: BOOL _ FALSE] = {
tsc: TIPUser.TIPScreenCoords ~ NEW[TIPUser.TIPScreenCoordsRec];
vt: Terminal.Virtual ~ Terminal.Current[];
keyBits: Terminal.KeyBits ~ Terminal.GetKeys[vt: vt];
IF (keyBits[LeftShift]=down OR keyBits[RightShift]=down) AND keyBits[Spare3]=down THEN {
mouse: Interminal.MousePosition ~ Interminal.GetMousePosition[];
viewer: ViewerClasses.Viewer;
tsc^ _ [
mouseX: mouse.mouseX,
mouseY: (IF mouse.color THEN vt.colorHeight ELSE vt.bwHeight) - mouse.mouseY,
color: mouse.color
];
viewer _ ViewerOps.MouseInViewer[tsc: tsc].viewer;
RETURN[viewer#NIL AND BiScrollers.ViewerIsABiScroller[viewer]] ;
};
};
MaybeKill: ENTRY PROC = {
IF killData.process # NIL AND KillKeysDown[] THEN {
gargoyleData: GargoyleData _ killData.gargoyleData;
TRUSTED {Process.Abort[killData.process];};
killData.process _ NIL;
SlackProcess.FlushQueue[gargoyleData.slackHandle]; -- you have to do this HERE!
gargoyleData.refresh.suppressRefresh _ FALSE; -- in case you killed FastPlayback
gargoyleData.aborted _ ALL[TRUE]; -- copies of aborted for all purposes
};
};
killData: REF KillData _ NARROW[data];
UNTIL killData.process = NIL DO
MaybeKill[];
Process.Pause[ticks: Process.SecondsToTicks[1]];
ENDLOOP;
};

DoActionAreaPaint: PROC [screen: Imager.Context, whatHasChanged: ATOM, gargoyleData: GargoyleData] = {
IF gargoyleData.aborted[refresh] THEN { -- last paint got killed => unknown bitmap cache states
gargoyleData.aborted[refresh] _ FALSE;
PaintEntireScene[screen, gargoyleData];
}
ELSE SELECT whatHasChanged FROM
$None => NULL;
$PaintEntireScene, $ViewersPaintEntireScene => PaintEntireScene[screen, gargoyleData];
$NewAlignmentsDeselected => PaintAllPlanes[screen, gargoyleData];
$NewAlignmentsSelected => PaintAllPlanes[screen, gargoyleData];
$SequencesMadeHot => PaintAllPlanes[screen, gargoyleData];
$SequencesMadeCold => PaintAllPlanes[screen, gargoyleData];
$Everything => PaintEntireScene[screen, gargoyleData];
$SelectionChanged => SelectionOrCaretChanged[screen, gargoyleData];
$FinishedAdding => FinishedAdding[screen, gargoyleData];
$FinishedDragging => FinishedDragging[screen, gargoyleData];
$CaretMoved => SelectionOrCaretChanged[screen, gargoyleData]; -- GGMouseEventImplA
$AnchorAdded => PaintAllPlanes[screen, gargoyleData]; -- GGEventImplB
$AnchorRemoved => PaintAllPlanes[screen, gargoyleData]; -- GGEventImplB
$DuringMotion => PaintDragOverlay[screen, gargoyleData, TRUE]; -- GGMouseEventImplA
$DuringCaretPos => PaintDragOverlay[screen, gargoyleData, FALSE]; -- GGMouseEventImplA
$DuringSelect => DuringSelect[screen, gargoyleData];
$ObjectChangedInPlace => ObjectChangedInPlace[screen, gargoyleData, normal];
$ObjectChangedBoundBoxProvided => ObjectChangedBoundBoxProvided[screen, gargoyleData];
$ObjectAdded => ObjectAdded[screen, gargoyleData];
$PaintSpot => PaintSpot[screen, gargoyleData];
$PaintHitLine => PaintHitLine[screen, gargoyleData];
$PaintOddHitLine => PaintOddHitLine[screen, gargoyleData];
$PaintTouchPoints => PaintTouchPoints[screen, gargoyleData];
$PaintAlign => PaintAlign[screen, gargoyleData];
$PaintBoundBoxes => PaintBoundBoxes[screen, gargoyleData];
$PaintTightBoxes => PaintTightBoxes[screen, gargoyleData];
$PaintOutlineBoxes => PaintOutlineBoxes[screen, gargoyleData];
$PaintSelectionBox => PaintSelectionBox[screen, gargoyleData];
$PaintMovingBox => PaintMovingBox[screen, gargoyleData];
ENDCASE => {
GGError.Append[gargoyleData.feedback, Rope.Cat["Gargoyle GGRefreshImpl doesn't know how to ", Atom.GetPName[whatHasChanged], "."], oneLiner];
GGError.Blink[gargoyleData.feedback];
};
};

DrawBackground: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = {
BackgroundBitsToDC: PROC = {
AdjustContextForDrawBits[dc, gargoyleData];
Imager.SetColor[dc, Imager.black];
ImagerBackdoor.DrawBits[dc, backgroundBitmap.base, backgroundBitmap.wordsPerLine, 0, 0, backgroundBitmap.height, backgroundBitmap.width, 0, backgroundBitmap.height];
};
backgroundBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.backgroundBitmap;
IF gargoyleData.refresh.showColors.state = off THEN {
IF NOT gargoyleData.refresh.backgndBitmapOK THEN {
PaintBackground: PROC = {
rect: Imager.Rectangle;
rect _ ImagerBackdoor.GetBounds[gargoyleData.refresh.backgroundContext];
Imager.SetColor[gargoyleData.refresh.backgroundContext, Imager.white];
Imager.MaskRectangle[gargoyleData.refresh.backgroundContext, rect];
DrawObjectsFiltered[screen: gargoyleData.refresh.backgroundContext, gargoyleData: gargoyleData, filter: GGBoundBox.BoundBoxFromRectangle[rect], excludeOverlay: FALSE, overObject: NIL]
};
Imager.DoSaveAll[gargoyleData.refresh.backgroundContext, PaintBackground];
gargoyleData.refresh.backgndBitmapOK _ TRUE;
};
Imager.DoSaveAll[dc, BackgroundBitsToDC];
}
ELSE {
rect: Imager.Rectangle;
rect _ BiScrollers.ViewportBox[gargoyleData.biScroller];
Imager.SetColor[dc, Imager.white];
Imager.MaskRectangle[dc, rect];
DrawObjectsFiltered[screen: dc, gargoyleData: gargoyleData, filter: GGBoundBox.BoundBoxFromRectangle[rect], excludeOverlay: FALSE, overObject: NIL]
};
};


DrawForeground: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = {
ForegroundBitsToDC: PROC = {
AdjustContextForDrawBits[dc, gargoyleData];
Imager.SetColor[dc, Imager.black];
Imager.MaskBits[dc, foregroundBitmap.base, foregroundBitmap.wordsPerLine, 0, 0, foregroundBitmap.height, foregroundBitmap.width, 0, foregroundBitmap.height];
};
foregroundBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.foregroundBitmap;
IF gargoyleData.refresh.showColors.state = off THEN {
IF NOT gargoyleData.refresh.foregndBitmapOK THEN {
PaintForeground: PROC = {
rect: Imager.Rectangle;
rect _ ImagerBackdoor.GetBounds[gargoyleData.refresh.foregroundContext];
Imager.SetColor[gargoyleData.refresh.foregroundContext, Imager.white];
Imager.MaskRectangle[gargoyleData.refresh.foregroundContext, rect];
GGGravity.DrawObjectBagRegardless[gargoyleData.refresh.foregroundContext, gargoyleData.hitTest.currentObjectBag, gargoyleData];
};
Imager.DoSaveAll[gargoyleData.refresh.foregroundContext, PaintForeground];
gargoyleData.refresh.foregndBitmapOK _ TRUE;
};
Imager.DoSaveAll[dc, ForegroundBitsToDC];
}
ELSE {
IF NOT gargoyleData.refresh.foregndBitmapOK THEN
GGGravity.DrawObjectBagRegardless[dc, gargoyleData.hitTest.currentObjectBag, gargoyleData];
};
};

DrawCaretPlane: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
DrawCaret[screen, gargoyleData.caret, Imager.black];
DrawAnchor[screen, gargoyleData.anchor, Imager.black];
};

NoteNewForeground: PUBLIC PROC [alignObjects: LIST OF FeatureData, gargoyleData: GargoyleData] = {
PaintForeground: PROC = {
GGGravity.DrawFeatureList[gargoyleData.refresh.foregroundContext, alignObjects, gargoyleData];
};
Imager.DoSaveAll[gargoyleData.refresh.foregroundContext, PaintForeground];
gargoyleData.refresh.foregndBitmapOK _ TRUE;
};


DrawCPFeedback: PROC [dc: Imager.Context, gargoyleData: GargoyleData, caretIsMoving, dragInProgress: BOOL] = {
IF gargoyleData.camera.quality#quality THEN {
DrawAttractorFeedback[dc, gargoyleData, dragInProgress, caretIsMoving];
DrawCpsOfSelectedOutlines[dc, gargoyleData.scene, gargoyleData.camera, dragInProgress, caretIsMoving];
DrawCpsOfSelectedSlices[dc, gargoyleData.scene, gargoyleData.camera, dragInProgress, caretIsMoving];
};
};

DrawAttractorFeedback: PROC [dc: Imager.Context, gargoyleData: GargoyleData, dragInProgress, caretIsMoving: BOOL] = {
attractor: REF ANY;
selectedParts: SliceParts;
attractor _ GGCaret.GetAttractor[gargoyleData.caret];
IF attractor = NIL THEN RETURN;
WITH attractor SELECT FROM
sliceD: SliceDescriptor => {
selectedD: SliceDescriptor _ GGSelect.FindSelectedSlice[slice: sliceD.slice, scene: gargoyleData.scene, selectClass: normal];
selectedParts _ IF selectedD = NIL THEN NIL ELSE selectedD.parts; 
sliceD.slice.class.drawAttractorFeedback[sliceD, selectedParts, dragInProgress, dc, gargoyleData.camera];
};
outlineD: OutlineDescriptor => {
selectedD: OutlineDescriptor _ GGSelect.FindSelectedOutline[outlineD.slice, gargoyleData.scene, normal];
selectedParts _ IF selectedD = NIL THEN NIL ELSE selectedD.parts; 
outlineD.slice.class.drawAttractorFeedback[outlineD, selectedParts, dragInProgress, dc, gargoyleData.camera];
};
ENDCASE => ERROR;
};


MemberTraj: PROC [ref: Traj, list: LIST OF Traj] RETURNS [BOOL] = {
FOR tl: LIST OF Traj _ list, tl.rest UNTIL tl = NIL DO
IF tl.first = ref THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};

AllSelectedOutlines: PROC [scene: Scene] RETURNS [selectedList: LIST OF Outline _ NIL] = {
ptr: LIST OF Outline;
outDGen: GGModelTypes.OutlineDescriptorGenerator;
outDGen _  GGSelect.SelectedOutlines[scene, hot];
[selectedList, ptr] _ GGUtility.StartOutlineList[];
FOR outD: OutlineDescriptor _ GGSelect.NextOutlineDescriptor[outDGen], GGSelect.NextOutlineDescriptor[outDGen] UNTIL outD = NIL DO
[selectedList, ptr] _ GGUtility.AddOutline[outD.slice, selectedList, ptr];
ENDLOOP;
outDGen _  GGSelect.SelectedOutlines[scene, normal];
FOR outD: OutlineDescriptor _ GGSelect.NextOutlineDescriptor[outDGen], GGSelect.NextOutlineDescriptor[outDGen] UNTIL outD = NIL DO
IF NOT GGSelect.IsSelectedInPart[outD.slice, scene, hot] THEN [selectedList, ptr] _ GGUtility.AddOutline[outD.slice, selectedList, ptr];
ENDLOOP;
};

AllSelectedSlices: PROC [scene: Scene] RETURNS [selectedList: LIST OF Slice _ NIL] = {
ptr: LIST OF Slice;
sGen: SliceDescriptorGenerator _  GGSelect.SelectedSlices[scene, hot];
[selectedList, ptr] _ GGUtility.StartSliceList[];
FOR sd: SliceDescriptor _ GGSelect.NextSliceDescriptor[sGen], GGSelect.NextSliceDescriptor[sGen] UNTIL sd = NIL DO
[selectedList, ptr] _ GGUtility.AddSlice[sd.slice, selectedList, ptr];
ENDLOOP;
sGen _ GGSelect.SelectedSlices[scene, normal];
FOR sd: SliceDescriptor _ GGSelect.NextSliceDescriptor[sGen], GGSelect.NextSliceDescriptor[sGen] UNTIL sd = NIL DO
IF NOT GGSelect.IsSelectedInPart[sd.slice, scene, hot] THEN [selectedList, ptr] _ GGUtility.AddSlice[sd.slice, selectedList, ptr];
ENDLOOP;
};

DrawCpsOfSelectedOutlines: PROC [dc: Imager.Context, scene: Scene, camera: CameraData, dragInProgress, caretIsMoving: BOOL] = {
normalD, hotD: OutlineDescriptor;
normalParts, hotParts: SliceParts;
outline: Outline;
IF caretIsMoving OR dragInProgress THEN RETURN;
FOR oList: LIST OF Outline _ AllSelectedOutlines[scene], oList.rest UNTIL oList=NIL DO
outline _ oList.first;
normalD _ GGSelect.FindSelectedOutline[outline, scene, normal];
hotD _ GGSelect.FindSelectedOutline[outline, scene, hot];
normalParts _ IF normalD # NIL THEN normalD.parts ELSE NIL;
hotParts _ IF hotD # NIL THEN hotD.parts ELSE NIL;
outline.class.drawSelectionFeedback[outline, normalParts, hotParts, dc, camera, dragInProgress, caretIsMoving, FALSE, caretIsMoving];
ENDLOOP;
};


DrawCpsOfSelectedSlices: PROC [dc: Imager.Context, scene: Scene, camera: CameraData, dragInProgress, caretIsMoving: BOOL] = {
normalSliceD, hotSliceD: SliceDescriptor;
normalParts, hotParts: SliceParts;
slice: Slice;
IF caretIsMoving OR dragInProgress THEN RETURN;
FOR sList: LIST OF Slice _ AllSelectedSlices[scene], sList.rest UNTIL sList=NIL DO
slice _ sList.first;
normalSliceD _ GGSelect.FindSelectedSlice[slice, scene, normal];
hotSliceD _ GGSelect.FindSelectedSlice[slice, scene, hot];
normalParts _ IF normalSliceD # NIL THEN normalSliceD.parts ELSE NIL;
hotParts _ IF hotSliceD # NIL THEN hotSliceD.parts ELSE NIL;
slice.class.drawSelectionFeedback[slice, normalParts, hotParts, dc, camera, dragInProgress, caretIsMoving, FALSE, caretIsMoving];
ENDLOOP;
};


MemberSlice: PROC [ref: SliceDescriptor, list: LIST OF SliceDescriptor] RETURNS [BOOL] = {
FOR tl: LIST OF SliceDescriptor _ list, tl.rest UNTIL tl = NIL DO
IF tl.first = ref THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};

PaintEntireScene: PUBLIC PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
GGStatistics.StartInterval[$PaintEntireScene, GGStatistics.GlobalTable[]];
gargoyleData.refresh.foregndBitmapOK _ FALSE;
gargoyleData.refresh.backgndBitmapOK _ FALSE;
PaintAllPlanes[screen, gargoyleData];
GGStatistics.StopInterval[$PaintEntireScene, GGStatistics.GlobalTable[]];
};

PaintAllPlanes: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
IF gargoyleData.refresh.suppressRefresh THEN RETURN;
IF gargoyleData.refresh.showColors.state = off THEN {
BackgroundToChunking[gargoyleData];
CPFeedbackToChunking[gargoyleData, FALSE, FALSE];
ForegroundToChunking[gargoyleData];
CaretPlaneToChunking[gargoyleData];
ChunkingToScreen[screen, gargoyleData];
}
ELSE {
DrawBackground[screen, gargoyleData];
DrawCPFeedback[screen, gargoyleData, FALSE, FALSE];
DrawForeground[screen, gargoyleData];
DrawCaretPlane[screen, gargoyleData];
};
};

ObjectChangedInPlace: PROC [screen: Imager.Context, gargoyleData: GargoyleData, selectClass: GGInterfaceTypes.SelectionClass _ normal] = {
bBox: BoundBox _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, selectClass];
RepairBackgroundInBoundBox[gargoyleData, bBox, TRUE, NIL];
PaintAllPlanes[screen, gargoyleData];
};

ObjectChangedBoundBoxProvided: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
RepairBackgroundInBoundBox[gargoyleData, gargoyleData.refresh.startBoundBox, TRUE, NIL];
PaintAllPlanes[screen, gargoyleData];
};

ObjectAdded: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
RepairBackgroundInBoundBox[gargoyleData, gargoyleData.refresh.startBoundBox, FALSE, gargoyleData.refresh.addedObject];
PaintAllPlanes[screen, gargoyleData];
};

RepairBackgroundInBoundBox: PROC [gargoyleData: GargoyleData, bBox: BoundBox, eraseFirst: BOOL _ FALSE, overObject: REF ANY] = {
backgroundContext: Imager.Context _ gargoyleData.refresh.backgroundContext;
backgroundBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.backgroundBitmap;
IF gargoyleData.refresh.suppressRefresh THEN RETURN;
IF gargoyleData.refresh.showColors.state = off THEN {
PaintObjectsInBox: PROC = {
IF eraseFirst THEN GGBoundBox.EraseWithinBoundBox[backgroundContext, bBox];
DrawObjectsFiltered[screen: backgroundContext, gargoyleData: gargoyleData, filter: bBox, overObject: overObject];
};
Imager.DoSaveAll[backgroundContext, PaintObjectsInBox];
gargoyleData.refresh.backgndBitmapOK _ TRUE;
};
};

SelectionOrCaretChanged: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
PaintAllPlanes[screen, gargoyleData];
};

DuringSelect: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext;
chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap;
IF gargoyleData.refresh.suppressRefresh THEN RETURN;
IF gargoyleData.refresh.showColors.state = off THEN {
BackgroundBitsToChunking[gargoyleData];
CPFeedbackToChunking[gargoyleData, FALSE, FALSE];
ForegroundToChunking[gargoyleData];
CaretPlaneToChunking[gargoyleData];
ChunkingToScreen[screen: screen, gargoyleData: gargoyleData];
}
ELSE {}; -- no feedback in SlowPaint mode
};


SplitBackgroundAndOverlay: PUBLIC PROC [gargoyleData: GargoyleData, restoreBox: BoundBox] = {
PaintAllButOverlayed: PROC = {
GGBoundBox.EraseWithinBoundBox[backgroundContext, restoreBox];
DrawObjectsFiltered[screen: backgroundContext, gargoyleData: gargoyleData, filter: restoreBox, excludeOverlay: TRUE, overObject: NIL];
};
backgroundContext: Imager.Context _ gargoyleData.refresh.backgroundContext;
IF gargoyleData.refresh.suppressRefresh THEN RETURN;
Imager.DoSaveAll[gargoyleData.refresh.backgroundContext, PaintAllButOverlayed];
}; -- end StoreBackground

PaintDragOverlay: PROC [screen: Imager.Context, gargoyleData: GargoyleData, dragInProgress: BOOL] = {
chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap;
IF gargoyleData.refresh.suppressRefresh THEN RETURN;
IF gargoyleData.refresh.showColors.state = off THEN {
BackgroundBitsToChunking[gargoyleData];
OverlayToChunking[gargoyleData];
CPFeedbackToChunking[gargoyleData: gargoyleData, duringMotion: TRUE, dragInProgress: dragInProgress];
ForegroundToChunking[gargoyleData];
CaretPlaneToChunking[gargoyleData];
ChunkingToScreen[screen, gargoyleData];
}
ELSE {
DrawCPFeedback[screen, gargoyleData, TRUE, dragInProgress];
DrawForeground[screen, gargoyleData];
DrawCaretPlane[screen, gargoyleData];
};
};

FinishedAdding: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
MergeBackgroundAndOverlay[gargoyleData, gargoyleData.refresh.startBoundBox, FALSE, gargoyleData.refresh.addedObject];
PaintAllPlanes[screen, gargoyleData];
};

FinishedDragging: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
GGBoundBox.EnlargeByBox[gargoyleData.refresh.startBoundBox, GGBoundBox.BoundBoxOfMoving[gargoyleData.scene]];
MergeBackgroundAndOverlay[gargoyleData, gargoyleData.refresh.startBoundBox, TRUE, NIL];
PaintAllPlanes[screen, gargoyleData];
};

MergeBackgroundAndOverlay: PROC [gargoyleData: GargoyleData, bBox: BoundBox, eraseFirst: BOOL _ FALSE, overObject: REF ANY] = {
backgroundContext: Imager.Context _ gargoyleData.refresh.backgroundContext;
backgroundBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.backgroundBitmap;
MergeBackgroundAndOverlayAux: PROC = {
IF eraseFirst THEN GGBoundBox.EraseWithinBoundBox[backgroundContext, bBox];
DrawObjectsFiltered[screen: backgroundContext, gargoyleData: gargoyleData, filter: bBox, overObject: overObject];
};
IF gargoyleData.refresh.suppressRefresh THEN RETURN;
IF gargoyleData.refresh.showColors.state = off THEN {
Imager.DoSaveAll[backgroundContext, MergeBackgroundAndOverlayAux];
gargoyleData.refresh.backgndBitmapOK _ TRUE;
};
};

BackgroundBitsToChunking: PROC [gargoyleData: GargoyleData] = {
background: ImagerBackdoor.Bitmap _ gargoyleData.refresh.backgroundBitmap;
chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext;
BackgroundBitsToChunkingAux: PROC [] = {
AdjustContextForDrawBits[chunkingContext, gargoyleData];
IF gargoyleData.refresh.showColors.state = off THEN ImagerBackdoor.DrawBits[chunkingContext, background.base, background.wordsPerLine, 0, 0, background.height, background.width, 0, background.height]
ELSE DrawPixels[chunkingContext, gargoyleData.refresh.backgroundPixelMap, gargoyleData];
};
IF gargoyleData.refresh.suppressRefresh THEN RETURN;
Imager.DoSaveAll[chunkingContext, BackgroundBitsToChunkingAux];
};

OverlayToChunking: PROC [gargoyleData: GargoyleData] = {
OverlayToChunkingAux: PROC [] = {
DrawDragOverlay[chunkingContext, gargoyleData];
};
chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext;
Imager.DoSaveAll[chunkingContext, OverlayToChunkingAux];
};

BackgroundToChunking: PROC [gargoyleData: GargoyleData] = {
chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext;
DrawBackground[chunkingContext, gargoyleData];
};

ForegroundToChunking: PROC [gargoyleData: GargoyleData] = {
chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext;
DrawForeground[chunkingContext, gargoyleData];
};

CPFeedbackToChunking: PROC [gargoyleData: GargoyleData, duringMotion, dragInProgress: BOOL] = {
chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext;
DrawCPFeedback[chunkingContext, gargoyleData, duringMotion, dragInProgress];
};

CaretPlaneToChunking: PROC [gargoyleData: GargoyleData] = {
chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext;
DrawCaretPlane[chunkingContext, gargoyleData];
};

ChunkingToScreen: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
ChunkingToScreenAux: PROC = {
AdjustContextForDrawBits[screen, gargoyleData];
ImagerBackdoor.DrawBits[screen, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height];
};
chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap;
Imager.DoSaveAll[screen, ChunkingToScreenAux];
};



DrawDragOverlay: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
DrawDragOverlayAux: PROC = {
IF gargoyleData.refresh.orderedOverlayList=NIL THEN gargoyleData.refresh.orderedOverlayList _ OrderOverlayList[gargoyleData]; -- update ordered list
FOR oList: LIST OF REF ANY _ gargoyleData.refresh.orderedOverlayList, oList.rest UNTIL oList = NIL DO
WITH oList.first SELECT FROM
sliceD: SliceDescriptor => {
sliceD.slice.class.drawTransform[sliceD.slice, sliceD.parts, screen, gargoyleData.camera, gargoyleData.drag.transform];
};
outlineD: OutlineDescriptor => {
outlineD.slice.class.drawTransform[outlineD.slice, outlineD.parts, screen, gargoyleData.camera, gargoyleData.drag.transform];
};
traj: Traj => ERROR;
caret: Caret => {
caret _ NARROW[oList.first];
DrawCaret[screen, caret, Imager.black];
};
ENDCASE => ERROR;
ENDLOOP;
IF GGCaret.Exists[gargoyleData.anchor] THEN DrawAnchor[screen, gargoyleData.anchor, Imager.black]; -- a kludge for now, June 25, 1986, Bier
};
Imager.DoSaveAll[screen, DrawDragOverlayAux];
};

DrawObjects: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
scene: Scene _ gargoyleData.scene;
entityGen: EntityGenerator;
Imager.SetColor[screen, Imager.black];
entityGen _ GGObjects.TopLevelEntitiesInScene[scene];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
WITH entity SELECT FROM
outline: Outline => outline.class.drawParts[outline, NIL, screen, gargoyleData.camera, FALSE];
slice: Slice => slice.class.drawParts[slice, NIL, screen, gargoyleData.camera, FALSE];
ENDCASE => ERROR;
ENDLOOP;
};

DrawObjectsFiltered: PROC [screen: Imager.Context, gargoyleData: GargoyleData, filter: GGBoundBox.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY] = {
OutsideOf: PROC [test, bound: GGBoundBox.BoundBox] RETURNS [BOOL] = {
RETURN[ test.hiX < bound.loX OR test.loX > bound.hiX OR test.hiY < bound.loY OR test.loY > bound.hiY ]; -- these tests may have to be <= or >=
};
DrawObjectsFilteredAux: PROC = { -- need to clip to filter, then image
entityGen: EntityGenerator _ GGObjects.TopLevelEntitiesInScene[scene];
thisEntity: REF ANY _ GGObjects.NextEntity[entityGen];
IF overObject # NIL THEN {
UNTIL thisEntity = overObject OR thisEntity = NIL DO thisEntity _ GGObjects.NextEntity[entityGen] ENDLOOP;
IF thisEntity = NIL THEN RETURN;
};
Imager.SetColor[screen, Imager.black];
GGBoundBox.Clip[dc: screen, bBox: filter];
FOR entity: REF ANY _ thisEntity, GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
WITH entity SELECT FROM
outline: Outline => {
IF excludeOverlay AND outline.onOverlay THEN LOOP;
IF NOT OutsideOf[outline.class.getBoundBox[outline, NIL], filter] THEN outline.class.drawParts[outline, NIL, screen, gargoyleData.camera, FALSE];
};
slice: Slice => {
IF excludeOverlay AND slice.onOverlay THEN LOOP;
IF NOT OutsideOf[slice.class.getBoundBox[slice, NIL], filter] THEN slice.class.drawParts[slice, NIL, screen, gargoyleData.camera, FALSE];
};
ENDCASE => ERROR;
ENDLOOP;
};
scene: Scene _ gargoyleData.scene;
IF filter=NIL OR filter.null THEN RETURN;
Imager.DoSaveAll[screen, DrawObjectsFilteredAux];
};

DrawCaret: PROC [screen: Imager.Context, caret: Caret, color: Imager.Color] = {
caretPos: Point _ GGCaret.GetPoint[caret];
IF NOT GGCaret.Exists[caret] THEN RETURN;
Imager.SetColor[screen, color];
GGShapes.DrawCaret[screen, caretPos];
};

DrawAnchor: PROC [screen: Imager.Context, caret: Caret, color: Imager.Color] = {
caretPos: Point _ GGCaret.GetPoint[caret];
IF NOT GGCaret.Exists[caret] THEN RETURN;
Imager.SetColor[screen, color];
GGShapes.DrawAnchor[screen, caretPos];
};

DrawPixels: PROC [screen: Imager.Context, pm: ImagerPixelMap.PixelMap, gargoyleData: GargoyleData] = {};

DrawNewAnchor: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
anchorPos: Point _ GGCaret.GetPoint[gargoyleData.anchor];
Imager.SetColor[screen, Imager.black];
GGShapes.DrawAnchor[screen, anchorPos];
};

PaintSpot: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
Imager.SetColor[screen, Imager.black];
GGShapes.DrawSpot[screen, gargoyleData.refresh.spotPoint];
};

PaintHitLine: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
Imager.SetColor[screen, Imager.black];
Imager.SetStrokeEnd[screen, round];
Imager.MaskVector[screen, [gargoyleData.refresh.spotPoint.x, gargoyleData.refresh.spotPoint.y], [gargoyleData.refresh.hitPoint.x, gargoyleData.refresh.hitPoint.y]];
GGShapes.DrawFilledRect[screen, gargoyleData.refresh.spotPoint, 3.0];
};

PaintOddHitLine: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
Imager.SetColor[screen, Imager.black];
Imager.SetStrokeEnd[screen, round];
Imager.MaskVector[screen, [gargoyleData.refresh.spotPoint.x, gargoyleData.refresh.spotPoint.y], [gargoyleData.refresh.hitPoint.x, gargoyleData.refresh.hitPoint.y]];
GGShapes.DrawCP[screen, gargoyleData.refresh.spotPoint];
};


PaintAlign: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
GGGravity.DrawObjectBagRegardless[screen, NARROW[gargoyleData.hitTest.currentObjectBag], gargoyleData];
};

PaintTouchPoints: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
GGTouch.DrawAllTouchPoints[screen, gargoyleData];
};

PaintBoundBoxes: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
bBoxGen: BoundBoxGenerator;
PaintBoundBoxesAux: PROC = {
bBoxGen _ GGObjects.BoundBoxesInScene[gargoyleData.scene];
FOR box: BoundBox _ GGObjects.NextBox[bBoxGen], GGObjects.NextBox[bBoxGen] UNTIL box = NIL DO
GGBoundBox.DrawBoundBox[screen, box];
ENDLOOP;
};
Imager.DoSaveAll[screen, PaintBoundBoxesAux];
};

PaintTightBoxes: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
box: BoundBox;
PaintTightBoxesAux: PROC = {
entityGen: GGModelTypes.EntityGenerator;
entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, normal];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
WITH entity SELECT FROM
sliceD: SliceDescriptor => {
box _ sliceD.slice.class.getTightBox[sliceD.slice, sliceD.parts];
};
outlineD: OutlineDescriptor => {
box _ outlineD.slice.class.getTightBox[outlineD.slice, outlineD.parts];
};
ENDCASE => ERROR;
GGBoundBox.DrawBoundBox[screen, box];
ENDLOOP;
};
Imager.DoSaveAll[screen, PaintTightBoxesAux];
};

PaintOutlineBoxes: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
PaintBoundBoxesAux: PROC = {
outSeqGen: GGSelect.OutlineSequenceGenerator;
bBox: BoundBox;
outSeqGen _ GGSelect.SelectedOutlineSequences[gargoyleData.scene, normal];
FOR outSeq: GGSelect.OutlineSequence _ GGSelect.NextOutlineSequences[outSeqGen], GGSelect.NextOutlineSequences[outSeqGen] UNTIL outSeq = NIL DO
IF outSeq.fenceSeq # NIL THEN {
bBox _ GGTraj.GetBoundBox[outSeq.fenceSeq.traj];
GGBoundBox.DrawBoundBox[screen, bBox];
};
FOR holeSeq: Sequence _ GGSequence.NextSequence[outSeq.holeSeqs], GGSequence.NextSequence[outSeq.holeSeqs] UNTIL holeSeq = NIL DO
bBox _ GGTraj.GetBoundBox[holeSeq.traj];
GGBoundBox.DrawBoundBox[screen, bBox];
ENDLOOP;
ENDLOOP;
};
Imager.DoSaveAll[screen, PaintBoundBoxesAux];
};

PaintSelectionBox: PUBLIC PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
box: BoundBox _ NIL;
PaintSelectionBoxAux: PROC = {
box _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene];
IF NOT box.null THEN GGBoundBox.DrawBoundBox[screen, box];
};
Imager.DoSaveAll[screen, PaintSelectionBoxAux];
};

PaintMovingBox: PUBLIC PROC [screen: Imager.Context, gargoyleData: GargoyleData] = {
box: BoundBox _ NIL;
PaintMovingBoxAux: PROC = {
box _ GGBoundBox.BoundBoxOfMoving[gargoyleData.scene];
IF NOT box.null THEN GGBoundBox.DrawBoundBox[screen, box];
};
Imager.DoSaveAll[screen, PaintMovingBoxAux];
};

EraseAll: PROC [screen: Imager.Context] = {
rect: Imager.Rectangle;
rect _ ImagerBackdoor.GetBounds[screen];
Imager.SetColor[screen, Imager.white];
Imager.MaskRectangle[screen, rect];
};


EndFourPoints: PROC [traj: Traj] RETURNS [firstPoint, secondPoint, secondToLastPoint, lastPoint: Point, firstWidth, lastWidth: REAL] = {
seg: Segment;
cpCount: NAT;
seg _ GGTraj.FetchSegment[traj, 0];
firstWidth _ seg.strokeWidth;
firstPoint _ seg.lo;
cpCount _ seg.class.controlPointCount[seg];
IF cpCount > 0 THEN {
secondPoint _ seg.class.controlPointGet[seg, 0];
}
ELSE {
secondPoint _ seg.hi;
};
seg _ GGTraj.FetchSegment[traj, GGTraj.HiSegment[traj]];
lastWidth _ seg.strokeWidth;
lastPoint _ seg.hi;
cpCount _ seg.class.controlPointCount[seg];
IF cpCount > 0 THEN {
secondToLastPoint _ seg.class.controlPointGet[seg, cpCount-1];
}
ELSE {
secondToLastPoint _ seg.lo;
};
};

ExcludeArrows: PROC [dc: Imager.Context, traj: Traj] = {
OPEN GGVector;
ClipPath: Imager.PathProc = {
moveTo[Add[Add[tip, Scale[perp, -halfWidth]], Scale[axis, thisWidth/2.0]]];
lineTo[Add[Add[tip, Scale[perp, halfWidth]], Scale[axis, thisWidth/2.0]]];
lineTo[Sub[tip, Add[Scale[axis, height], Scale[perp, halfWidth]]]];
lineTo[Sub[tip, Add[Scale[axis, height], Scale[perp, -halfWidth]]]];
lineTo[Add[tip, Scale[perp, -halfWidth]]];
};
firstPoint, secondPoint, secondToLastPoint, lastPoint, tip, base: Point;
firstWidth, lastWidth, thisWidth, height, halfWidth: REAL;
axis, perp: Vector;

IF NOT traj.loArrow AND NOT traj.hiArrow THEN RETURN;
[firstPoint, secondPoint, secondToLastPoint, lastPoint, firstWidth, lastWidth] _ EndFourPoints[traj];
IF traj.loArrow THEN {
thisWidth _ firstWidth;
[height, halfWidth] _ GGShapes.ArrowSize[thisWidth];
tip _ firstPoint;
base _ secondPoint;
axis _ GGVector.Normalize[GGVector.Sub[tip, base]];
perp _ [axis.y, -axis.x];
Imager.Clip[dc, ClipPath, FALSE, TRUE];
};
IF traj.hiArrow THEN {
thisWidth _ lastWidth;
[height, halfWidth] _ GGShapes.ArrowSize[thisWidth];
tip _ lastPoint;
base _ secondToLastPoint;
axis _ GGVector.Normalize[GGVector.Sub[tip, base]];
perp _ [axis.y, -axis.x];
Imager.Clip[dc, ClipPath, FALSE, TRUE];
};
};


DrawArrows: PROC [dc: Imager.Context, traj: Traj, gargoyleData: GargoyleData] = {
firstPoint, secondPoint, secondToLastPoint, lastPoint: Point;
firstWidth, lastWidth: REAL;
IF NOT traj.loArrow AND NOT traj.hiArrow THEN RETURN;
[firstPoint, secondPoint, secondToLastPoint, lastPoint, firstWidth, lastWidth] _ EndFourPoints[traj];
IF traj.loArrow THEN GGShapes.DrawArrow[dc, firstPoint, secondPoint, firstWidth];
IF traj.hiArrow THEN GGShapes.DrawArrow[dc, lastPoint, secondToLastPoint, lastWidth];
};


MaskStroke: PROC [dc: Imager.Context, seg: Segment] = {
MaskPath: Imager.PathProc = {
moveTo[seg.lo];
seg.class.buildPath[seg, lineTo, curveTo, conicTo, arcTo];
};
Imager.MaskStroke[dc, MaskPath, FALSE];
};


DrawJoints: PROC [dc: Imager.Context, traj: Traj, gargoyleData: GargoyleData]  = {
IF gargoyleData.camera.quality = quality OR traj.parent.onOverlay THEN RETURN;
IF NOT traj.visibleJoints THEN RETURN;
Imager.SetColor[dc, Imager.black];
FOR i: INT IN [0..GGTraj.HiJoint[traj]] DO
GGShapes.DrawJoint[dc, GGTraj.FetchJointPos[traj, i]];
ENDLOOP;
};

DrawJointsInSequenceFeedback: PROC [dc: Imager.Context, seq: Sequence, gargoyleData: GargoyleData, selectClass: SelectionClass _ normal]  = {
jointGen: JointGenerator;
IF gargoyleData.camera.quality = quality THEN RETURN;
Imager.SetColor[dc, Imager.black];
jointGen _ GGSequence.JointsInSequence[seq];
FOR i: INT _ GGSequence.NextJoint[jointGen], GGSequence.NextJoint[jointGen] UNTIL i = -1 DO
GGShapes.DrawSelectedJoint[dc, GGTraj.FetchJointPos[seq.traj, i], selectClass];
ENDLOOP;
};

SnapShot: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = {
SnapshotBackground[dc, gargoyleData];
DrawDragOverlay[dc, gargoyleData];
};

SnapshotBackground: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = {
scene: Scene _ gargoyleData.scene;
entityGen: EntityGenerator;
Imager.SetColor[dc, Imager.black];
entityGen _ GGObjects.TopLevelEntitiesInScene[gargoyleData.scene];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
WITH entity SELECT FROM
outline: Outline => {
IF OnOverlay[outline, gargoyleData] THEN LOOP
ELSE outline.class.drawParts[outline, NIL, dc, gargoyleData.camera, FALSE];
};
slice: Slice => {
IF OnOverlay[slice, gargoyleData] THEN LOOP
ELSE slice.class.drawParts[slice, NIL, dc, gargoyleData.camera, FALSE];
};
ENDCASE => ERROR;
ENDLOOP;
IF NOT OnOverlay[gargoyleData.caret, gargoyleData] THEN DrawCaret[dc, gargoyleData.caret, Imager.black];
DrawAnchor[dc, gargoyleData.anchor, Imager.black];
GGGravity.DrawObjectBagRegardless[dc, NARROW[gargoyleData.hitTest.currentObjectBag], gargoyleData];
};

InterpressEntireScene: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = {
DrawObjects[dc, gargoyleData];
};

MoveToOverlay: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData] = {
WITH entity SELECT FROM
caret: Caret => {
IF OnOverlay[caret, gargoyleData] THEN ERROR;
GGCaret.TellOnOverlay[caret, TRUE];
gargoyleData.refresh.overlayList _ List.Nconc[LIST[caret], gargoyleData.refresh.overlayList];
};
outlineD: OutlineDescriptor => {
IF OnOverlay[outlineD, gargoyleData] THEN ERROR;
outlineD.slice.onOverlay _ TRUE;
gargoyleData.refresh.overlayList _ List.Nconc[LIST[outlineD], gargoyleData.refresh.overlayList];
};
sliceD: SliceDescriptor => {
IF OnOverlay[sliceD, gargoyleData] THEN ERROR;
sliceD.slice.onOverlay _ TRUE;
gargoyleData.refresh.overlayList _ List.Nconc[LIST[sliceD], gargoyleData.refresh.overlayList];
};
ENDCASE => ERROR;
gargoyleData.refresh.orderedOverlayList _ NIL;
};

MoveAllSelectedToOverlay: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] = {
entityGen: EntityGenerator _ GGSelect.SelectedStuff[gargoyleData.scene, selectClass];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
MoveToOverlay[entity, gargoyleData];
ENDLOOP;
};

MoveToBackground: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData] = {
IF NOT OnOverlay[entity, gargoyleData] THEN RETURN;
gargoyleData.refresh.overlayList _ List.DRemove[entity, gargoyleData.refresh.overlayList];
WITH entity SELECT FROM
sliceD: SliceDescriptor => sliceD.slice.onOverlay _ FALSE;
outline: Outline => outline.onOverlay _ FALSE;
caret: Caret => GGCaret.TellOnOverlay[caret, FALSE];
ENDCASE => ERROR;
gargoyleData.refresh.orderedOverlayList _ NIL;
};

MoveOverlayToBackground: PUBLIC PROC [gargoyleData: GargoyleData] = {
FOR overlayList: LIST OF REF ANY _ gargoyleData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO
WITH overlayList.first SELECT FROM
sliceD: SliceDescriptor => sliceD.slice.onOverlay _ FALSE;
outlineD: OutlineDescriptor => outlineD.slice.onOverlay _ FALSE;
caret: Caret => GGCaret.TellOnOverlay[caret, FALSE];
ENDCASE => ERROR;
ENDLOOP;
gargoyleData.refresh.overlayList _ NIL;
gargoyleData.refresh.orderedOverlayList _ NIL;
};

EmptyOverlay: PUBLIC PROC [gargoyleData: GargoyleData] RETURNS [BOOL] = {
RETURN[gargoyleData.refresh.overlayList = NIL];
};

OnOverlay: PROC [entity: REF ANY, gargoyleData: GargoyleData] RETURNS [BOOL] = {
WITH entity SELECT FROM
caret: Caret => RETURN[GGCaret.IsOnOverlay[caret]];
outline: Outline => RETURN[outline.onOverlay];
slice: Slice => RETURN[slice.onOverlay];
sliceD: SliceDescriptor => RETURN[sliceD.slice.onOverlay];
outlineD: OutlineDescriptor => RETURN[outlineD.slice.onOverlay];
ENDCASE => ERROR;
};

OrderOverlayList: PROC [gargoyleData: GargoyleData] RETURNS [orderedList: LIST OF REF ANY _ NIL] = {
FindOverlayedD: PROC [slice: REF ANY] RETURNS [sliceD: REF ANY _ NIL] = {
FOR ov: LIST OF REF ANY _ gargoyleData.refresh.overlayList, ov.rest UNTIL ov=NIL DO
WITH ov.first SELECT FROM
sliceD: SliceDescriptor => IF sliceD.slice=slice THEN RETURN[ov.first];
outlineD: OutlineDescriptor => IF outlineD.slice=slice THEN RETURN[ov.first];
ENDCASE => ERROR;
ENDLOOP;
RETURN[NIL];
};
sliceD: REF ANY;
finger: LIST OF REF ANY;
entityGen: EntityGenerator;
[orderedList, finger] _ GGUtility.StartList[];
entityGen _ GGObjects.TopLevelEntitiesInScene[gargoyleData.scene];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
IF OnOverlay[entity, gargoyleData] THEN {
WITH entity SELECT FROM
outline: Outline => { -- scene entity is identical to overlay entity
sliceD _ FindOverlayedD[entity];
IF sliceD = NIL THEN sliceD _ outline.class.newParts[outline, NIL, topLevel];
[orderedList, finger] _ GGUtility.AddEntity[sliceD, orderedList, finger];
};
slice: Slice => {
sliceD _ FindOverlayedD[entity];
IF sliceD = NIL THEN sliceD _ slice.class.newParts[slice, NIL, topLevel];
[orderedList, finger] _ GGUtility.AddEntity[sliceD, orderedList, finger];
};
caret: Caret => {}; -- fix up later
ENDCASE => ERROR;
};
ENDLOOP;
IF OnOverlay[gargoyleData.caret, gargoyleData] THEN [orderedList, finger] _ GGUtility.AddEntity[gargoyleData.caret, orderedList, finger];
};

AdjustContextForDrawBits: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = {
viewerToClient: Imager.Transformation _ BiScrollers.GetStyle[].GetTransforms[BiScrollers.QuaBiScroller[gargoyleData.actionArea]].viewerToClient;
Imager.ConcatT[dc, viewerToClient];
};

InitStats: PROC [] = {
interval: GGStatistics.Interval;
interval _ GGStatistics.CreateInterval[$PaintEntireScene];
GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]];
};

InitStats[];

END.
���)��GGRefreshImpl.mesa 
Copyright c 1985 by Xerox Corporation.  All rights reserved.
Contents:  All painting actions in Gargoyle are called thru this interface.
Last edited by Bier on January 15, 1987 1:38:40 am PST
Pier, December 11, 1986 3:43:05 pm PST
Kurlander August 28, 1986 7:11:40 pm PDT

 [Artwork node; type 'ArtworkInterpress on' to command tool] 
Fork a process that looks to see if SHIFT-SWAT is down and aborts refresh if it is.
whatHasChanged will be an atom describing some change which has occurred to the viewable scene state, such as $CaretMoved, $OverlayMoved, $ObjectAdded, $SelectionChanged, or $Everything.  A pointer to the particular objects to be repainted will be stored in gargoyleData for now.
We envision a scheme where Dispatch may actually queue up painting jobs and attempt optimizations on the queue.  In this case, the objects to be repainted will have to be stored separately from the gargoyleData.

The Sixteen Types of Scene Change:
Dragging
Debugging

Single-Plane Commands

DrawFeedback: PROC [screen: Imager.Context, gargoyleData: GargoyleData, duringMotion: BOOL, quick: BOOL] = {
DrawFeedbackAux: PROC = {
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
WITH entity SELECT FROM
sliceD: SliceDescriptor => {
IF selectClass = hot THEN
sliceD.slice.class.drawSelectionFeedback[sliceD.slice, NIL, sliceD.parts, NIL, screen, gargoyleData.camera, duringMotion, FALSE, quick]
ELSE
sliceD.slice.class.drawSelectionFeedback[sliceD.slice, sliceD.parts, NIL, NIL, screen, gargoyleData.camera, duringMotion, FALSE, quick];
};
outlineD: OutlineDescriptor => {
IF selectClass = hot THEN
outlineD.slice.class.drawSelectionFeedback[outlineD.slice, NIL, outlineD.parts, NIL, screen, gargoyleData.camera, duringMotion, FALSE, quick]
ELSE
outlineD.slice.class.drawSelectionFeedback[outlineD.slice, outlineD.parts, NIL, NIL, screen, gargoyleData.camera, duringMotion, FALSE, quick];
};
ENDCASE => ERROR;
ENDLOOP;
};
entityGen: EntityGenerator;
selectClass: SelectionClass;
entityCount: NAT;
IF NOT gargoyleData.camera.hideHot THEN {
entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, hot];
entityCount _ GGObjects.EntityCount[entityGen];
quick _ entityCount > 10 OR quick;
selectClass _ hot;
Imager.DoSaveAll[screen, DrawFeedbackAux];
};
entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, normal];
entityCount _ GGObjects.EntityCount[entityGen];
quick _ entityCount > 10 OR quick;
selectClass _ normal;
Imager.DoSaveAll[screen, DrawFeedbackAux];
};
Update the foreground bitmap, if necessary, and send it to the screen.
Draw the alignment objects directly to dc.
The caret plane has no backing bitmap, so it is always made up fresh.
No Imager.DoSaveAll is used.  This procedure sets the color to black.
Add these new features to the foreground context.
Draws control points on slices which are the caret attractor
Puts all the selected (hot & normal) outlines in a list, and returns them
Puts all the selected (hot & normal) slices in a list, and returns them
WhoCaresIfChairIsAttractor: PROC [gargoyleData: GargoyleData] RETURNS [attOn: GGInterfaceTypes.CaretOn, attractor: REF ANY, attJointNum: NAT, attSeg: Segment] = {
For now, I'm going to allow highlighting of moving objects.  You only live once.  Eric.  Note:  this procedure fixes a bug with ChairIsNotAttractor.  Namely, highlighting does not occur with ChairIsNotAttractor when the caret is positioned on a selected segment.
[attractor: attractor, on: attOn, jointNum: attJointNum, seg: attSeg] _ GGCaret.GetAttractor[gargoyleData.caret];
WITH attractor SELECT FROM
oSliceD: OutlineDescriptor => {};
aSliceD: SliceDescriptor => {};
ENDCASE => attOn _ nothing; 
};

ChairIsNotAttractor: PROC [gargoyleData: GargoyleData] RETURNS [attOn: GGInterfaceTypes.CaretOn, attractor: REF ANY, attJointNum: NAT, attSeg: Segment] = {
This code figures out if the chair and the attractor are "identical" in a bunch of weird cases. It returns on=nothing if they are "identical" and returns the attractor data if not "identical".
This is the wrong question to ask.  The right thing to do is to take those objects that the caret is attracted to, and subtract away any parts that are moving.  -- Bier, December 16, 1986.
chair: REF ANY;
chairOn: GGInterfaceTypes.CaretOn;
attSegNum, chairJointNum, chairSegNum: NAT;
chairSeg: Segment;
[attractor: attractor, on: attOn, jointNum: attJointNum, seg: attSeg, segNum: attSegNum] _ GGCaret.GetAttractor[gargoyleData.caret];
[chair: chair, on: chairOn, jointNum: chairJointNum, segNum: chairSegNum, seg: chairSeg] _ GGCaret.GetChair[gargoyleData.caret];
WITH attractor SELECT FROM
aTraj: Traj => {
attSeg1, attSeg2, chairSeg1, chairSeg2: NAT;
IF chair#attractor THEN RETURN; -- return attractor information
attractor and chair are the same traj
IF attOn=joint THEN {
IF GGTraj.IsEndJoint[aTraj, attJointNum] THEN attSeg2 _ attSeg1 _ IF attJointNum=0 THEN 0 ELSE attJointNum-1 -- open traj, end joint
ELSE { -- closed traj or not end joint
attSeg1 _ attJointNum;
attSeg2 _ GGTraj.PreviousSegmentNum[aTraj, attJointNum];
};
}
ELSE IF attOn=seg OR attOn=cp THEN attSeg2 _ attSeg1 _ attSegNum;
IF chairOn=joint THEN {
IF GGTraj.IsEndJoint[aTraj, chairJointNum] THEN chairSeg2 _ chairSeg1 _ IF chairJointNum=0 THEN 0 ELSE chairJointNum-1 -- open traj, end joint
ELSE { -- closed traj or not end joint
chairSeg1 _ chairJointNum;
chairSeg2 _ GGTraj.PreviousSegmentNum[aTraj, chairJointNum];
};
}
ELSE IF chairOn=seg OR chairOn=cp THEN chairSeg2 _ chairSeg1 _ chairSegNum;
IF attSeg1=chairSeg1 OR attSeg2=chairSeg1 OR attSeg1=chairSeg2 OR attSeg2=chairSeg2  THEN attOn _ nothing;
};
aSliceD: SliceDescriptor => { -- if slices are the same (don't user parts) then chair=attractor
WITH chair SELECT FROM
chairSliceD: SliceDescriptor => IF aSliceD.slice=chairSliceD.slice THEN attOn _ nothing;
ENDCASE;
};
ENDCASE => attOn _ nothing; 
};


Static

Make no assumptions about the scene.
FeedbackToChunking[gargoyleData, FALSE, FALSE];
DrawFeedback[screen, gargoyleData, FALSE, FALSE];

The selected objects have changed in some small way (e.g. line width or color).  Repair the background plane and refresh the screen.
An object has been added to the scene, or has changed size or shape in a simple way.  All of the changes are confined to the box gargoyleData.refresh.startBoundBox.  Repair the background plane and refresh the screen.
An object has been added to the scene.  All of the changes are confined to the box gargoyleData.refresh.startBoundBox.  Repair the background plane and refresh the screen.  Since this is an addition, we only need to draw the objects which are over (in overlap order) the new shape (usually there aren't any).
The selection plane or the caret plane is obsolete.  Since these planes have no backing bitmaps, no repairs are needed.  Simply redraw the planes.

Dynamic

  Selection
This routine is called DuringSelect. The chunking bitmap has the correct bkgnd. Write the selection feedback and the foreground shapes onto the chunking bitmap and then dump the chunking bitmap onto the screen for double-buffered motion.
FeedbackToChunking[gargoyleData, FALSE, TRUE];
  Adding and Dragging
The background has split into two parts: background and overlay.  Remove any overlay objects from the background plane.  Also, a dragging operation is about to start, so mark the foregroundBitmap as obsolete.
This routine is called DuringDrag. Write the overlay shapes, selection feedback, and the foreground shapes onto the chunking bitmap and then dump the chunking bitmap onto the screen.  The result is double-buffered motion.
The boundBox describes the region of the background which must be updated from the overlay.
The background and overlay planes are about to be recombined into the background plane, after dragging.
Dynamic Utility Routines

Do no actual drawing.  Send the background bits to the chunking bitmap.
DrawPixels is a dummy routine for now until Imager implements it.
Do no actual drawing.  Send the overlay objects to the chunking bitmap.
FeedbackToChunking: PROC [gargoyleData: GargoyleData, duringMotion: BOOL, quick: BOOL] = {
chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext;
DrawFeedback[chunkingContext, gargoyleData, duringMotion, quick];
};


Drawing Routines which are independent of refresh strategy.

This could use some optimizing.
The common core of PaintEntireScene and InterpressEntireScene.
Paints those objects in the scene within the filter bounding box, and in front of (and including) overObject (in PriorityOrder) into the display context.

Debugging
Imager.SetColor[screen, ImagerColor.ColorFromGray[0.5]];
Draw the boxes.
Draw the boxes.
Draw the boxes.
Draw the box.
Draw the box.

Drawing Arrows
Drawing Feedback
Let Q be a logical variable corresponding to (gargoyleData.camera.quality = quality).
Let S correspond to (joint J is selected).
Let V correspond to (joint J is marked as visible).
Let O correspond to (joint J is on the overlay plane).
Then joint J is drawn filled when:  qSo.
Joint J is drawn unfilled when qsVo.
Suppress joints for an interpress master and for dragging.
Suppress joints for an interpress master.

For Interpress Masters
Called by GGMouseEvent.IPSnapShot to get a picture of Gargoyle dragging in action.
Draw all but the overlay objects into a bitmap.  Auxiliary for SnapShot.
Draw most of the scene.
Worry about scene objects.
Worry about the caret.
Worry about alignment lines.

The Overlay Plane

seq: Sequence => {
parentOutline: Outline _ GGOutline.OutlineOfTraj[seq.traj];
newParts: SliceParts _ GGOutline.PartsFromSequence[parentOutline, seq];
IF OnOverlay[parentOutline, gargoyleData] THEN {
parentOutline.movingParts _ parentOutline.class.unionParts[parentOutline, parentOutline.movingParts, newParts];
}
};
traverse the scene.entities from back to end front.
Scene may have: outline, slice
Overlay may have: OutlineDescriptor, SliceDescriptor, caret

Utility
this procedure is needed to map the chunking and background bitmaps onto the actual viewer area before DrawBits is called.
Changed the names of some of the procedures and wrote down some conventions which may help us think about them (See comments in ActionAreaPaint). Added atom $DrawCaret for the special case $PaintSelectedRegion would be wasteful because nothing in that region has changed (see GGMouseEventImpl.EndCaretPos).
Bier, April 30, 1986 6:15:58 pm PDT:  Deleted some commented out code.  Thanks, Ken, for getting rid of the DrawSegArray stuff.
Ê7S��˜�code™Kšœ
Ïmœ1™<—K™Kšœ6™6Kšœ&™&K™(—K™�šÏk	˜	Kšœˆ˜ˆK˜�—šÏn
œžœž˜Kšžœ„˜‹Kšžœ
ž˜—˜�Kšœžœ˜)Kšœ
žœ˜'Kšœžœ˜6Kšœžœ˜+Kšœžœ˜%Kšœžœ˜Kšœ
žœ˜*Kšœžœ"˜9Kšœžœ˜!Kšœžœ˜+Kšœžœ˜3Kšœžœ ˜5Kšœžœ)˜GKšœžœ ˜5Kšœžœ!˜3Kšœžœ˜!Kšœžœ˜3Kšœ	žœ˜%Kšœžœ˜!Kšœžœ˜!Kšœ	žœ˜'Kšœ
žœ˜+Kšœžœ!˜7Kšœ
žœ˜'Kšœžœ#˜7Kšœžœ"˜9Kšœžœ˜Kšœžœ˜#K˜�Kš
Ÿœžœžœžœžœ˜/—˜�I
artworkFigure–G114.3466 mm topLeading 114.3466 mm topIndent 1.411111 mm bottomLeading •Bounds:0.0 mm xmin 0.0 mm ymin 138.6662 mm xmax 111.5244 mm ymax •Artwork
Interpress•
Interpress‹Interpress/Xerox/3.0  f j k j¡¥“Ä��WB ¤ ¨  Än�HÄSù�D¡£ r jÄÔº�sÄÛM� ¢ ¨¡¡¨ r jÄð¹ ¤ÄSc�Vž ¢ ¥ ¨ÅXeroxÅ
PressFontsÅ
Laurel-mrr£¡ “ª ¤ ” •  —¡¡¨  ŠÁ1–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jčù ¤Ä^]�JÄ>�ö ¢ ¥ ¨ÅXeroxÅ
PressFontsÅ
Laurel-mrr£¡ “ª ¤ ” •  —¡¡¨  ŠÁ1–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jÄFµ ¤Ä�úä��ÕÄ+� ¢ ¥ ¨ÅXeroxÅ
PressFontsÅ
Helvetica-mrr£¡ “ª ¤ ” •  —¡¡¨  ŠÁCaret Plane–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jÄFµ ¤Ä�Ðm��»Ä�®
��I ¢ ¥ ¨ÅXeroxÅ
PressFontsÅ
Helvetica-mrr£¡ “ª ¤ ” •  —¡¡¨  ŠÁForeground Plane–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jÄFµ ¤ÄJw�[Ä�¦£��P ¢ ¥ ¨ÅXeroxÅ
PressFontsÅ
Helvetica-mrr£¡ “ª ¤ ” •  —¡¡¨  ŠÁSelection Feedback Plane–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jÄFµ ¤Ä�Ðm��»Äfã�5 ¢ ¥ ¨ÅXeroxÅ
PressFontsÅ
Helvetica-mrr£¡ “ª ¤ ” •  —¡¡¨  ŠÁBackground Plane–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jÄFµ ¤Ä4¤�%Ä�¥��O ¢ ¥ ¨ÅXeroxÅ
PressFontsÅ
Helvetica-mrr£¡ “ª ¤ ” •  —¡¡¨  ŠÁ
Overlay Plane–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é¢¯“¡¡¨¢·“¢°“Ä-k��èÄ�¦‡��K™ÄD´�7ÄdH�/—˜¢¯“¡¡¨¢·“¢°“Ä-k��èÄ�¦‡��K™Ä4¥��ÅĬß��Ë—˜¢¯“¡¡¨¢·“¢°“ÄD´�7Ä�Ÿº��M™Ä�Ŷ��c˜¢¯“¡¡¨¢·“¢°“Ä� ��fÄ�ܯ��j™ÄD´�7Ä�Ŷ��c—˜ r jčù ¤ÄT?�ÚÄ�‰��N ¢ ¥ ¨ÅXeroxÅ
PressFontsÅTimesRoman-mrr£¡ “° ¤ ” •  —¡¡¨  ŠÁ*Caret Plane:  Anchor, Caret, moving Caret.–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jčù ¤Ä�¸÷�ÞÄ�£
��a ¢ ¥ ¨ÅXeroxÅ
PressFontsÅTimesRoman-mrr£¡ “° ¤ ” •  —¡¡¨  ŠÁ"Foreground Plane:  Alignment lines–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jčù ¤Ä+¡�pÄ1Æ� ¢ ¥ ¨ÅXeroxÅ
PressFontsÅTimesRoman-mrr£¡ “° ¤ ” •  —¡¡¨  ŠÁ=ControlPointFeedback Plane:  control point and joint feedback–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jčù ¤ÄFÀ�¹Ä`—�? ¢ ¥ ¨ÅXeroxÅ
PressFontsÅTimesRoman-mrr£¡ “° ¤ ” •  —¡¡¨  ŠÁ>Selection Feedback Plane:  Selected segment and slice feedback–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jčù ¤Ä�‰û�bÄ�åe��ž ¢ ¥ ¨ÅXeroxÅ
PressFontsÅTimesRoman-mrr£¡ “° ¤ ” •  —¡¡¨  ŠÁ*Overlay Plane:  Moving outlines and slices–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jčù ¤Ä<%�+Ä�™š��o ¢ ¥ ¨ÅXeroxÅ
PressFontsÅTimesRoman-mrr£¡ “° ¤ ” •  —¡¡¨  ŠÁ1Background Plane:  Stationary outlines and slices–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é r jÄ¡ ¤ÄÍ�Ä�¨��K ¢ ¥ ¨ÅXeroxÅ
PressFontsÅ
Helvetica-mrr£¡ “ª ¤ ” •  —¡¡¨  ŠÁControlPoint Feedback Plane–¡¡¨ k é r j¢·“¡¯“¡¡¨ k é¢¯“¡¡¨¢·“¢°“Äbo�LÄ�²ô��G™ÄfE�OÄc
�)—˜¢¯“¡¡¨¢·“¢°“Ä�¾��“Ĩ��m™Ä]å�IÄ�›Ë��D—˜ k é k gšŸ=™=—Kš	œ
žœžœ
žœžœ˜NKšŸœžœžœžœžœ
žœžœ˜Nš
Ÿœžœžœ*žœ žœ˜sšžœ)žœÏc˜QKšœžœžœ2˜JK™SKšœ/žœ˜6KšŸœ(žœ˜PKšœ˜K˜—Kšžœ: &˜dKšœ˜K˜�—šŸœžœžœžœžœžœ˜9š
Ÿœžœžœžœžœ˜3Kšœžœ˜?K•StartOfExpansion[]˜*K˜5šžœžœžœžœ˜XK˜@K˜šœ˜K˜Kšœ	žœ
žœžœ˜MK˜Kšœ˜—K– [tsc: TIPUser.TIPScreenCoords]˜2K–[ViewerClasses.Viewer]šžœžœžœ+˜@Kšœ˜—K˜—šŸ	œÐbkÏb¡œ˜šžœžœžœžœ˜3Kšœ3˜3Kšžœ$˜+Kšœžœ˜Kšœ3 ˜OKšœ'žœ "˜PKšœžœžœ %˜GKšœ˜—Kšœ˜—Kšœ
žœžœ˜&šžœž˜KšŸ	œ˜K˜0Kšžœ˜—Kšœ˜—K˜�šŸœžœ*žœ!˜fKšœ—™—KšœÓ™ÓK™�šžœžœ 7˜_Kšœ žœ˜&Kšœ'˜'K˜—šžœžœž˜Kšœ	žœ˜Kš¢"™"KšœV˜VKšœA˜AKšœ?˜?Kšœ:˜:Kšœ;˜;Kšœ6˜6KšœC˜CKšœ8˜8Kšœ<˜<KšœR˜RKšœ6 ˜Ešœ8 ˜GKš¢™—Kšœ8žœ ˜SKšœ:žœ ˜VKšœ4˜4KšœL˜LKšœV˜Všœ2˜2Kš¢	™	—Kšœ.˜.Kšœ4˜4Kšœ:˜:Kšœ<˜<Kšœ0˜0Kšœ:˜:Kšœ:˜:Kšœ>˜>Kšœ>˜>Kšœ8˜8šžœ˜Kšœ˜Kšœ%˜%K˜——K˜K˜�—K™�K™K™�šŸœžœ5˜IšŸœžœ˜Kšœ+˜+K–;[context: Imager.Context, color: ImagerColorDefs.Color]šœ"˜"Kšœ¢œŽ˜¥K˜—KšœP˜Pšžœ-žœ˜5šžœžœ&žœ˜2šŸÐbn
œžœ˜Kšœ˜KšœH˜HKšœF˜FKšœC˜CK–¡[screen: Imager.Context, gargoyleData: GGInterfaceTypes.GargoyleData, filter: GGBasicTypes.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY]šœ žœžœ˜·K˜—KšœJ˜JKšœ'žœ˜,K˜—Kšœ)˜)K˜—šžœ˜Kšœ˜Kšœ8˜8Kšœ"˜"Kšœ˜K–¡[screen: Imager.Context, gargoyleData: GGInterfaceTypes.GargoyleData, filter: GGBasicTypes.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY]šœ|žœžœ˜“K˜—K˜K˜�—šŸœžœDžœ	žœ™lšŸœžœ™šžœ	žœžœDžœ
žœž™lKšžœžœž™šœ™šžœž™Kšœ7žœžœ-žœ™‡—šž™KšœEžœžœ-žœ	™ˆ—K™—šœ ™ šžœž™Kšœ;žœžœ-žœ™—šž™KšœKžœžœ-žœ	™Ž—K™—Kšžœžœ™—Kšžœ™K™—Kšœ™Kšœ™Kšœ
žœ™šžœžœžœ™)Kšœ7¢œ™<Kšœ/™/Kšœžœ™"Kšœ™Kšœ*™*K™—Kšœ7¢œ™?Kšœ/™/Kšœžœ™"Kšœ™Kšœ*™*K™—K˜�šŸœžœ5˜IšŸœžœ˜Kšœ+˜+K–;[context: Imager.Context, color: ImagerColorDefs.Color]šœ"˜"Kšœ¢œŽ˜K˜—KšœP˜Pšžœ-žœ˜5Kš¢F™Fšžœžœ&žœ˜2šŸ£
œžœ˜Kšœ˜KšœH˜HKšœF˜FKšœC˜CKšœ˜K˜—KšœJ˜JKšœ'žœ˜,K˜—Kšœ)˜)K˜—šžœ˜K™*šžœžœ&ž˜0Kšœ[˜[—K˜—K˜K˜�—šŸœžœ9˜MK™EK™EKš¢	œ+˜4Kš¢
œ,˜6K˜K˜�—š
Ÿœžœžœžœžœ-˜bJ™1šŸ£
œžœ˜Kšœ^˜^K˜—KšœJ˜JKšœ'žœ˜,J˜J˜�—K˜�šŸœžœQžœ˜nšžœ%žœ˜-KšœG˜GJšœf˜fJšœd˜dK˜—K˜K˜�—šŸœžœQžœ˜uK™<Jšœžœžœ˜Jšœ˜Jšœ5˜5Jšžœ
žœžœžœ˜šžœžœž˜˜J–h[slice: GGModelTypes.Slice, scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass]šœ}˜}Jšœžœ
žœžœžœžœ˜BJšœi˜iJ˜—˜ J–h[slice: GGModelTypes.Slice, scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass]šœh˜hJšœžœ
žœžœžœžœ˜BJšœm˜mJ˜—Jšžœžœ˜—J˜J˜�—K˜�šŸ
œžœžœžœžœžœ˜Cšžœžœžœžœžœž˜6Kšžœžœžœžœ˜$Kšžœ˜—Kšžœžœ˜Kšœ˜J˜�—šŸœžœžœžœžœžœ˜ZK™IKšœžœžœ	˜Kšœ1˜1Kšœ,¢œ˜1Kšœ3˜3šžœlžœžœž˜‚KšœJ˜JKšžœ˜—Kšœ,¢œ˜4šžœlžœžœž˜‚Kšžœžœ3žœK˜ˆKšžœ˜—K˜K˜�—šŸœžœžœžœžœ	žœ˜VK™GKšœžœžœ˜KšœA¢œ˜FKšœ1˜1šžœ^žœžœž˜rKšœF˜FKšžœ˜—Kšœ&¢œ˜.šžœ^žœžœž˜rKšžœžœ1žœ žœ&˜‚Kšžœ˜—K˜K˜�—šŸœžœWžœ˜Kšœ!˜!J˜"J˜Jšžœžœžœžœ˜/šžœžœžœ2žœžœž˜VKšœ˜Kšœ?˜?Kšœ9˜9Kšœžœžœžœžœžœ˜;Kšœžœžœžœžœžœ˜2Kšœožœ˜…Kšžœ˜—˜K˜�——K˜�šŸœžœWžœ˜}Kšœ)˜)J˜"K˜
Jšžœžœžœžœ˜/šžœžœžœ.žœžœž˜RKšœ˜Kšœ@˜@Kšœ:˜:Kšœžœžœžœžœžœ˜EKšœžœ
žœžœžœžœ˜<Kšœkžœ˜Kšžœ˜—K˜˜�K˜�——šŸœžœžœ.žœžœžœ™¢Kšœ†™†Kšœq™qšžœžœž™Kšœ!™!Kšœ™Kšžœ™—K™K™�—šŸœžœžœ.žœžœžœ™›K™ÀKš¢¼™¼Kšœžœžœ™Kšœ"™"Kšœ'žœ™+Kšœ™Kšœ„™„Kšœ€™€šžœžœž™šœ™Kšœ(žœ™,Kšžœžœžœ ™?Kšœ%™%šžœ
žœ™K–)[traj: GGModelTypes.Traj, index: NAT]šžœ'žœžœžœžœ ™„šžœ ™&Kšœ™Kšœ8™8Kšœ™—K™—Kšžœžœžœ
žœ™Ašžœžœ™K–)[traj: GGModelTypes.Traj, index: NAT]šžœ)žœžœžœžœ ™Žšžœ ™&Kšœ™Kšœ<™<Kšœ™—K™—Kšžœžœ
žœžœ%™KKš
žœžœžœžœžœ™jK™—šœ A™_šžœžœž™Kšœ žœ!žœ™XKšžœ™—K™—Kšžœ™—Kšœ™K™�—šŸœžœžœžœžœžœ˜Zšžœžœžœ!žœžœž˜AKšžœžœžœžœ˜$Kšžœ˜—Kšžœžœ˜Kšœ˜K˜�—K™�K™K™�šŸœžœžœ9˜VK™$KšœJ˜JKšœ'žœ˜-Kšœ'žœ˜-Kšœ%˜%KšœI˜IK˜K˜�—šŸœžœ9˜MKšžœ&žœžœ˜4šžœ-žœ˜5Kš¢œ˜#Kš¢œžœ™/Kš¢œžœžœ¢˜1Kš¢œ˜#Kš¢œ˜#Kš¢œ˜'K˜—šžœ˜Kšœ%˜%Kšœ#žœžœ™1Kšœ%žœ˜3Kšœ%˜%Kšœ%˜%K˜—˜K˜�——K™�šŸœžœp˜ŠK™„KšœP˜PKš¢œžœžœ˜:Kš¢œ˜%K˜K˜�—šŸœžœ9˜\KšœÙ™ÙKš¢œ3žœžœ˜XKš¢œ˜%K˜K˜�—šŸœžœ9˜JKšœ´™´Kš¢œ3žœ$˜vKš¢œ˜%K˜K˜�—šŸœžœ:žœžœžœžœ˜€KšœK˜KKšœP˜PKšžœ&žœžœ˜4šžœ-žœ˜5š£œžœ˜Kšžœžœ9˜KKšœq˜qK˜—Kšœ$¢œ˜7Kšœ'žœ˜,K˜—K˜K˜�—šŸœžœ9˜VK™’Kšœ%˜%K˜K˜�—K™�Kšœ™K™�K™šŸœžœ9˜KK™íKšœG˜GKšœL˜LKšžœ&žœžœ˜4šžœ-žœ˜5Kš¢œ˜'Kš¢œžœžœ™.Kš¢œžœžœ˜1Kš¢œ˜#Kš¢œ˜#Kšœ<¢˜=K˜—Kšžœ  ˜)K˜K˜�—K˜�K™šŸœžœžœ7˜]KšœÐ™ÐšŸœžœ˜Kšœ>˜>Kšœožœžœ˜†K˜—KšœK˜KKšžœ&žœžœ˜4Kšœ9¢œ˜OKšœ ˜—K˜�šŸœžœFžœ˜eK™ÝKšœL˜LKšžœ&žœžœ˜4šžœ-žœ˜5Kš¢œ˜'Kš¢œ˜ Kš¢œ+žœ!¢˜eKš¢œ˜#Kš¢œ˜#Kš¢œ˜'K˜—šžœ˜Kšœ%žœ˜;Kšœ%˜%Kšœ%˜%K˜—K˜K˜�—šŸœžœ9˜MKšœ[™[KšœLžœ$˜uKšœ%˜%K˜K˜�—šŸœžœ9˜OKšœm˜mKšœLžœžœ˜WKšœ%˜%˜K˜�——šŸœžœ:žœžœžœžœ˜K™gKšœK˜KKšœP˜PšŸœžœ˜&Kšžœžœ9˜KKšœq˜qK˜—Kšžœ&žœžœ˜4šžœ-žœ˜5KšœB˜BKšœ'žœ˜,K˜—K˜—K˜�K™K™�šŸœžœ!˜?KšœG™GKšœJ˜JKšœG˜GšŸ£œžœ˜(Kšœ8˜8Kšžœ-žœ¢œ|˜ÇšžœT˜XK™A—Kšœ˜—Kšžœ&žœžœ˜4Kšœ?˜?K˜K˜�—šŸœžœ!˜8KšœG™GšŸ£œžœ˜!Kšœ/˜/Kšœ˜—KšœG˜GKšœ8˜8K˜K˜�—šŸœžœ!˜;KšœG˜GKšœ.˜.K˜K˜�—šŸœžœ!˜;KšœG˜GKšœ.˜.˜K˜�——šŸœžœ<žœ˜_KšœG˜GKšœL˜LK˜K˜�—šŸœžœ,žœ	žœ™ZKšœG™GKšœA™A™K™�——šŸœžœ!˜;KšœG˜GKšœ.˜.K˜—K˜�šŸœžœ9˜OšŸœžœ˜Kšœ/˜/Kšœ¢œˆ˜ŸK˜—KšœL˜LKšœ.˜.K˜K˜�K˜�K˜�—K™�K™;K™�šŸœžœ9˜NK™šŸœžœ˜Kšžœ)žœžœK ˜”šžœžœžœžœžœ7žœ	žœž˜eKšžœ
žœž˜˜Kšœw˜wKšœ˜—šœ ˜ Kšœ}˜}K˜—Kšœžœ˜šœ˜Kšœžœ˜Kšœ'˜'K˜—Kšžœžœ˜—Kšžœ˜Kšžœ%žœ8 (˜‹K˜—Kšœ-˜-K˜K˜�—šŸœžœ9˜JKšœŸœ™>Kšœ"˜"Kšœ˜Kšœ&˜&Kšœ5˜5šžœ	žœžœDžœ
žœž˜lšžœžœž˜Kšœ5žœžœ˜^Kšœ-žœžœ˜VKšžœžœ˜—Kšžœ˜—K˜K˜�—šŸœžœcžœžœžœžœ˜¢Kšœ™™™šŸ	œžœ$žœžœ˜EKš	žœžœžœžœ &˜ŽK˜—šŸœžœ %˜FKšœF˜FKšœžœžœ#˜6šžœžœžœ˜Kš
žœžœžœžœ.žœ˜jKšžœžœžœžœ˜ K˜—Kšœ&˜&K˜*šžœ	žœžœ/žœ
žœž˜Wšžœžœž˜šœ˜Kšžœžœžœžœ˜2Kšžœžœ.žœžœ"žœžœ˜‘K˜—šœ˜Kšžœžœžœžœ˜0Kšžœžœ*žœžœžœžœ˜‰K˜—Kšžœžœ˜—Kšžœ˜—K˜—Kšœ"˜"Kš
žœžœžœ
žœžœ˜)Kšœ1˜1K˜K˜�—šŸ	œžœ@˜OKšœ*˜*Kšžœžœžœžœ˜)Kšœ˜Kšœ%˜%K˜K˜�—šŸ
œžœ@˜PKšœ*˜*Kšžœžœžœžœ˜)Kšœ˜Kšœ&˜&K˜K˜�—KšŸ
œžœX˜hK™�K™	K˜�šŸ
œžœ9˜LKšœ9˜9Kšœ&˜&Kšœ'˜'K˜K˜�—šŸ	œžœ9˜HKšœ&˜&Kšœ:˜:K˜K˜�—šŸœžœ9˜KKšœ&˜&Kšœ#˜#Kšœ¤˜¤KšœE˜EK˜K˜�—šŸœžœ9˜NKšœ&˜&Kšœ#˜#Kšœ¤˜¤Kšœ8˜8K˜K˜�K˜�—šŸ
œžœ9˜IKšœ8™8Kšœ*žœ7˜gK˜K˜�—šŸœžœ9˜OKšœ1˜1K˜K˜�—šŸœžœ9˜NK˜šŸœžœ˜K™Kšœ:˜:šžœHžœžœž˜]Kšœ%˜%—Kšžœ˜K˜—Kšœ-˜-K˜K˜�—šŸœžœ9˜NKšœ˜šŸœžœ˜K™Jšœ(˜(Jšœ?˜?šžœ	žœžœDžœ
žœž˜lšžœžœž˜šœ˜JšœA˜AJ˜—šœ ˜ JšœG˜GJ˜—Jšžœžœ˜—Kšœ%˜%Jšžœ˜—J˜—Kšœ-˜-K˜K˜�—šŸœžœ9˜PšŸœžœ˜K™Kšœ-˜-K˜KšœJ˜Jšžœwžœ
žœž˜šžœžœžœ˜Kšœ0˜0Kšœ&˜&K˜—šžœhžœžœž˜Kšœ(˜(Kšœ&˜&Kšžœ˜—Kšžœ˜—K˜—Kšœ-˜-K˜K˜�—šŸœžœžœ9˜WKšœžœ˜šŸœžœ˜K™
Kšœ8˜8Kšžœžœ
žœ&˜:K˜—Kšœ/˜/K˜K˜�—šŸœžœžœ9˜TKšœžœ˜šŸœžœ˜K™
Kšœ6˜6Kšžœžœ
žœ&˜:K˜—Kšœ,˜,K˜K˜�—šŸœžœ˜+Kšœ˜Kšœ(˜(Kšœ&˜&Kšœ#˜#K˜K˜�—K™�™K˜�—šŸ
œžœžœWžœ˜ˆK˜
Kšœ	žœ˜
Kšœ#˜#Kšœ˜Kšœ˜Iprocšœ+˜+šžœ
žœ˜Mšœ0˜0M˜—šžœ˜Mšœ˜M˜—Kšœ8˜8Kšœ˜Kšœ˜Mšœ+˜+šžœ
žœ˜Mšœ>˜>M˜—šžœ˜Mšœ˜M˜—M˜K˜�—šŸ
œžœ%˜8Kšžœ
˜šŸœ˜KšœK˜KKšœJ˜JKšœC˜CKšœD˜DKšœ*˜*K˜—KšœH˜HKšœ5žœ˜:Kšœ˜K˜�Kšžœžœžœžœžœžœ˜5Kšœe˜ešžœžœ˜Kšœ˜Kšœ4˜4Kšœ˜Kšœ˜Kšœ3˜3Kšœ˜Kšœžœžœ˜'K˜—šžœžœ˜Kšœ˜Kšœ4˜4Kšœ˜Kšœ˜Kšœ3˜3Kšœ˜Kšœžœžœ˜'K˜—K˜K˜�K˜�—šŸ
œžœA˜QK˜=Kšœžœ˜Kšžœžœžœžœžœžœ˜5Kšœe˜eMšžœžœ=˜QMšžœžœA˜UK˜K˜�—K˜�K™šŸ
œžœ'˜7–¡ -- [moveTo: ImagerPath.MoveToProc, lineTo: ImagerPath.LineToProc, curveTo: ImagerPath.CurveToProc, conicTo: ImagerPath.ConicToProc, arcTo: ImagerPath.ArcToProc]šŸœ˜Kšœ˜Kšœ:˜:K˜—Kšœ žœ˜'˜K˜�——K˜�šŸ
œžœB˜RKšœU™UK™*K™3K™6K™(K™$Kšžœ'žœžœžœ˜Nšžœžœžœžœ˜&K™:—K˜"šžœžœžœž˜*Kšœ6˜6—Kšžœ˜K˜K˜�—šŸœžœk˜˜Kš¢)™)—Kšžœ'žœžœ˜5K˜"Kšœ,˜,šžœžœBžœž˜[KšœO˜O—Kšžœ˜K˜K˜�—K™�K™šŸœžœžœ5˜JKšœR™RKšœ%˜%Kšœ"˜"K˜K˜�—šŸœžœ5˜MKšœH™HKšœ"˜"šœ˜K™—šœ"˜"K™—KšœB˜Bšžœ	žœžœDžœ
žœž˜lšžœžœž˜˜Kšžœ"žœž˜-Kšžœ"žœžœ˜KK˜—šœ˜Kšžœ žœž˜+Kšžœžœžœ˜GK˜—Kšžœžœ˜—Kšžœ˜K™—Kšžœžœ-žœ1˜hšœ2˜2K™—Kšœ&žœ7˜cK˜K˜�—šŸœžœžœ5˜WKšœ˜K˜K˜�—K™�™K™�—š
Ÿ
œžœžœ
žœžœ!˜Lšžœžœž˜šœ˜Kšžœ žœžœ˜-Kšœžœ˜#Kšœ#¢
œžœ+˜]K˜—™K™;KšœG™Gšžœ(žœ™0Kšœo™oK™—K™—˜ Kšžœ#žœžœ˜0Kšœžœ˜ Kšœ#¢
œžœ.˜`K˜—šœ˜Kšžœ!žœžœ˜.Kšœžœ˜Kšœ#¢
œžœ,˜^K˜—Kšžœžœ˜—Kšœ*žœ˜.K˜K˜�—šŸœžœžœ>˜cKšœU˜Ušžœ	žœžœDžœ
žœž˜lKšœ$˜$Kšžœ˜—K˜K˜�—š
Ÿœžœžœ
žœžœ!˜OKšžœžœ!žœžœ˜3KšœZ˜Zšžœžœž˜Kšœ4žœ˜:Kšœ(žœ˜.Kšœ-žœ˜4Kšžœžœ˜—Kšœ*žœ˜.K˜K˜�—šŸœžœžœ!˜Ešžœžœžœžœžœ6žœžœž˜pšžœžœž˜"Kšœ4žœ˜:Kšœ:žœ˜@Kšœ-žœ˜4Kšžœžœ˜—Kšžœ˜—Kšœ#žœ˜'Kšœ*žœ˜.˜K˜�——š
Ÿœžœžœžœžœ˜IKšžœ$žœ˜/K˜K˜�—šŸ	œžœ
žœžœžœžœ˜Pšžœžœž˜Kšœžœ˜3Kšœžœ˜.Kšœžœ˜(Kšœžœ˜:Kšœžœ˜@Kšžœžœ˜—K˜K˜�—šŸœžœžœžœžœžœžœžœ˜dK™3šŸœžœ	žœžœžœ
žœžœžœ˜Išžœžœžœžœžœ-žœžœž˜Sšžœ
žœž˜Kšœžœžœžœ˜GKšœžœžœžœ˜MKšžœžœ˜—Kšžœ˜—Kšžœžœ˜K˜—Kšœžœžœ˜Kš	œžœžœžœžœ˜J˜K˜.KšœB˜Bšžœ	žœžœDžœ
žœž˜lšžœ!žœ˜)Kš¢™Kš¢;™;šžœžœž˜šœ .˜DKšœ ˜ Kšžœ
žœžœ*žœ˜MKšœI˜IK˜—šœ˜Kšœ ˜ Kšžœ
žœžœ&žœ˜IKšœI˜IK˜—Kšœ ˜#Kšžœžœ˜—K˜—Kšžœ˜—Kšžœ-žœV˜‰K˜K˜�—K™�K™šŸœžœ5˜SK™zKšœ˜Kšœ#˜#K˜K˜�—šŸ	œžœ˜K˜ K˜:K˜?K˜K˜�—K˜K˜�šžœ˜Kšœ²™²K™——�…—����›��ûm��