GGRefreshImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Contents: All painting actions in Gargoyle are called thru this interface.
Last edited by Bier on April 16, 1987 12:02:52 pm PDT
Pier, May 14, 1987 4:06:11 pm PDT
Kurlander August 28, 1986 7:11:40 pm PDT
DIRECTORY
Atom, BiScrollers, BufferedRefresh, CodeTimer, Feedback, FunctionCache, GGBasicTypes, GGBoundBox, GGCaret, GGGravity, GGInterfaceTypes, GGModelTypes, GGScene, GGRefresh, GGSegmentTypes, GGSelect, GGSequence, GGShapes, GGTraj, GGUtility, Imager, ImagerBackdoor, ImagerTransformation, Rope, Rosary, SlackProcess, TIPUser, Vectors2d, ViewerAbort, ViewerClasses;
GGRefreshImpl: CEDAR MONITOR
IMPORTS Atom, BiScrollers, BufferedRefresh, CodeTimer, Feedback, FunctionCache, GGBoundBox, GGCaret, GGGravity, GGScene, GGSelect, GGSequence, GGShapes, GGTraj, GGUtility, Imager, ImagerBackdoor, Rope, SlackProcess, Vectors2d, ViewerAbort
EXPORTS GGRefresh = BEGIN
BitVector: TYPE = GGBasicTypes.BitVector;
BoundBox: TYPE = GGModelTypes.BoundBox;
BoundBoxGenerator: TYPE = GGScene.BoundBoxGenerator;
CameraData: TYPE = GGModelTypes.CameraData;
Caret: TYPE = GGInterfaceTypes.Caret;
Color: TYPE = Imager.Color;
FeatureData: TYPE = GGGravity.FeatureData;
OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor;
Rectangle: TYPE = Imager.Rectangle;
Sandwich: TYPE = BufferedRefresh.Sandwich;
Slice: TYPE = GGModelTypes.Slice;
SliceParts: TYPE = GGModelTypes.SliceParts;
SliceGenerator: TYPE = GGModelTypes.SliceGenerator;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator;
EntityGenerator: TYPE = GGModelTypes.EntityGenerator;
GGData: TYPE = GGInterfaceTypes.GGData;
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;
ActionAreaPaint: PUBLIC PROC [screen: Imager.Context, whatHasChanged: ATOM, ggData: GGData] = TRUSTED {
PaintWithAbort: PROC = TRUSTED {
DoActionAreaPaint[screen, whatHasChanged, ggData ! UNWIND => {
Feedback.Append[ggData.feedback, "Refresh Aborted", oneLiner];
SlackProcess.FlushQueue[ggData.slackHandle]; -- you have to do this HERE!
ggData.refresh.suppressRefresh ← FALSE; -- in case you killed FastPlayback
ggData.aborted ← ALL[TRUE]; -- copies of aborted for all purposes
};
];
};
IF whatHasChanged=$ViewersPaintEntireScene THEN ViewerAbort.CallWithAbortEnabled[ggData.actionArea, PaintWithAbort]
ELSE DoActionAreaPaint[screen, whatHasChanged, ggData]; -- SlackProcess is watching for aborts
};
DoActionAreaPaint: PROC [screen: Imager.Context, whatHasChanged: ATOM, ggData: GGData] = {
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 ggData 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 ggData.
showColors: BOOL ← ggData.refresh.showColors.state = on;
IF ggData.aborted[refresh] THEN { -- last paint got killed => unknown bitmap cache states
ggData.aborted[refresh] ← FALSE;
PaintEntireScene[screen, ggData, showColors];
}
ELSE SELECT whatHasChanged FROM
$None => NULL;
The Sixteen Types of Scene Change:
$PaintEntireScene, $ViewersPaintEntireScene => PaintEntireScene[screen, ggData, showColors];
$ViewersPaintAllPlanes => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
$NewAlignmentsDeselected => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
$NewAlignmentsSelected => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
$SequencesMadeHot => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
$SequencesMadeCold => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
$Everything => PaintEntireScene[screen, ggData, showColors];
$SelectionChanged => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
$FinishedAdding => FinishedAdding[screen, ggData, showColors];
$FinishedDragging => FinishedDragging[screen, ggData, showColors];
$CaretMoved => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE]; -- GGMouseEventImplA
$AnchorAdded => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE]; -- GGEventImplB
$AnchorRemoved => PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE]; -- GGEventImplB
Dragging
$DuringMotion => PaintDragOverlay[screen, ggData, TRUE, showColors]; -- GGMouseEventImplA
$DuringCaretPos => PaintDragOverlay[screen, ggData, FALSE, showColors]; -- GGMouseEventImplA
$DuringSelect => DuringSelect[screen, ggData, showColors];
$ObjectChangedInPlace => ObjectChangedInPlace[screen, ggData, normal, showColors];
$ObjectChangedBoundBoxProvided => ObjectChangedBoundBoxProvided[screen, ggData, showColors];
$ObjectAdded => ObjectAdded[screen, ggData, showColors];
Debugging
$PaintSpot => PaintSpot[screen, ggData];
$PaintHitLine => PaintHitLine[screen, ggData];
$PaintOddHitLine => PaintOddHitLine[screen, ggData];
$PaintAlign => PaintAlign[screen, ggData];
$PaintBoundBoxes => PaintBoundBoxes[screen, ggData];
$PaintTightBoxes => PaintTightBoxes[screen, ggData];
$PaintOutlineBoxes => PaintOutlineBoxes[screen, ggData];
$PaintSelectionBox => PaintSelectionBox[screen, ggData];
$DrawBackgroundBox, $DrawOverlayBox, $DrawRubberBox, $DrawDragBox => DrawMovingBox[screen, ggData, whatHasChanged];
ENDCASE => {
Feedback.Append[ggData.feedback, Rope.Cat["Gargoyle GGRefreshImpl doesn't know how to ", Atom.GetPName[whatHasChanged], "."], oneLiner];
Feedback.Blink[ggData.feedback];
};
};
[Artwork node; type 'ArtworkInterpress on' to command tool]
CreateSandwich: PUBLIC PROC [] RETURNS [sandwich: Sandwich] = {
sandwich ← BufferedRefresh.CreateSandwich[LIST[
[$Background, TRUE, RefreshBackground], -- back ...
[$Overlay, FALSE, RefreshOverlay],
[$CPFeedback, FALSE, RefreshCPFeedback],
[$Foreground, TRUE, RefreshForeground],
[$CaretPlane, FALSE, RefreshCaretPlane]]]; -- ... to front
};
PaintEntireScene: PUBLIC PROC [screen: Imager.Context, ggData: GGData, showColors: BOOL] = {
sandwich: Sandwich ← ggData.refresh.sandwich;
CodeTimer.StartInt[$PaintEntireScene, $Gargoyle];
BufferedRefresh.SetLayerOK[sandwich, $Foreground, FALSE];
BufferedRefresh.SetLayerOK[sandwich, $Background, FALSE];
PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
CodeTimer.StopInt[$PaintEntireScene, $Gargoyle];
};
PaintAllPlanes: PROC [screen: Imager.Context, ggData: GGData, showColors: BOOL, caretIsMoving: BOOL, dragInProgress: BOOL] = {
sandwich: Sandwich ← ggData.refresh.sandwich;
clientToViewer, viewerToClient: Imager.Transformation;
ignoreBackingMap: BOOL;
IF ggData.refresh.suppressRefresh THEN RETURN;
ggData.refresh.caretIsMoving ← caretIsMoving;
ggData.refresh.dragInProgress ← dragInProgress;
[clientToViewer, viewerToClient] ← BiScrollers.GetStyle[].GetTransforms[BiScrollers.QuaBiScroller[ggData.actionArea]];
clientToViewer ← ImagerTransformation.Invert[viewerToClient];
ignoreBackingMap ← showColors;
BufferedRefresh.DrawSandwich[sandwich, screen, clientToViewer, viewerToClient, ggData, ignoreBackingMap];
};
Single-Plane Commands
RefreshBackground: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ggData.refresh.suppressRefresh THEN RETURN;
DrawObjectsFiltered[dc: dc, ggData: ggData, filter: GGBoundBox.BoundBoxFromRectangle[boundRect], excludeOverlay: FALSE, overObject: NIL];
};
RefreshOverlay: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
This could use some optimizing.
ggData: GGData ← NARROW[clientData];
DrawDragOverlayAux: PROC = {
IF ggData.refresh.orderedOverlayList=NIL THEN ggData.refresh.orderedOverlayList ← OrderOverlayList[ggData]; -- update ordered list
FOR oList: LIST OF SliceDescriptor ← ggData.refresh.orderedOverlayList, oList.rest UNTIL oList = NIL DO
oList.first.slice.class.drawTransform[oList.first, dc, ggData.camera, ggData.drag.transform];
ENDLOOP;
};
IF ggData.refresh.suppressRefresh THEN RETURN;
Imager.DoSaveAll[dc, DrawDragOverlayAux];
};
RefreshCPFeedback: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
ggData: GGData ← NARROW[clientData];
caretIsMoving: BOOL ← ggData.refresh.caretIsMoving;
dragInProgress: BOOL ← ggData.refresh.dragInProgress;
IF ggData.refresh.suppressRefresh THEN RETURN;
IF ggData.camera.quality#quality THEN {
DrawAttractorFeedback[dc, ggData, dragInProgress, caretIsMoving];
DrawCpsOfSelectedOutlines[dc, ggData.scene, ggData.camera, dragInProgress, caretIsMoving];
DrawCpsOfSelectedSlices[dc, ggData.scene, ggData.camera, dragInProgress, caretIsMoving];
};
};
RefreshForeground: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ggData.refresh.suppressRefresh THEN RETURN;
FunctionCache.Flush[ggData.refresh.lineCache];
GGGravity.DrawAlignBagRegardless[dc, ggData.hitTest.alignBag, ggData];
};
RefreshCaretPlane: PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] = {
No Imager.DoSaveAll is used. This procedure sets the color to black.
ggData: GGData ← NARROW[clientData];
IF ggData.refresh.suppressRefresh THEN RETURN;
DrawCaret[dc, ggData.caret, Imager.black];
DrawAnchor[dc, ggData.anchor, Imager.black];
};
NoteNewForeground: PUBLIC PROC [alignObjects: LIST OF FeatureData, ggData: GGData] = {
Add these new features to the foreground context.
PaintForeground: PROC = {
GGGravity.DrawFeatureList[foregroundContext, alignObjects, ggData];
};
foregroundContext: Imager.Context ← BufferedRefresh.GetLayerContext[ggData.refresh.sandwich, $Foreground];
Imager.DoSaveAll[foregroundContext, PaintForeground];
BufferedRefresh.SetLayerOK[ggData.refresh.sandwich, $Foreground, TRUE];
};
UpdateForegroundForMotion: PUBLIC PROC [ggData: GGData] = {
Repaint all of the alignment lines. Use the FunctionCache to avoid drawing what has already been drawn.
PaintForeground: PROC = {
GGGravity.DrawAlignBagRegardless[foregroundContext, ggData.hitTest.alignBag, ggData];
};
foregroundContext: Imager.Context ← BufferedRefresh.GetLayerContext[ggData.refresh.sandwich, $Foreground];
Imager.DoSaveAll[foregroundContext, PaintForeground];
BufferedRefresh.SetLayerOK[ggData.refresh.sandwich, $Foreground, TRUE];
};
Drawing Utilities
DrawAttractorFeedback: PROC [dc: Imager.Context, ggData: GGData, dragInProgress, caretIsMoving: BOOL] = {
Draws control points on slices which are the caret attractor
attractor: SliceDescriptor ← GGCaret.GetAttractor[ggData.caret];
IF attractor#NIL THEN {
selectedD: SliceDescriptor ← GGSelect.FindSelectedSlice[attractor.slice, ggData.scene, normal];
selectedParts: SliceParts ← IF selectedD = NIL THEN NIL ELSE selectedD.parts;
attractor.slice.class.drawAttractorFeedback[attractor, selectedParts, dragInProgress, dc, ggData.camera];
};
};
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] = {
Puts all the selected (hot & normal) outlines in a list, and returns them
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] = {
Puts all the selected (hot & normal) slices in a list, and returns them
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;
};
WhoCaresIfChairIsAttractor: PROC [ggData: GGData] 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[ggData.caret];
WITH attractor SELECT FROM
oSliceD: OutlineDescriptor => {};
aSliceD: SliceDescriptor => {};
ENDCASE => attOn ← nothing;
};
ChairIsNotAttractor: PROC [ggData: GGData] 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[ggData.caret];
[chair: chair, on: chairOn, jointNum: chairJointNum, segNum: chairSegNum, seg: chairSeg] ← GGCaret.GetChair[ggData.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;
};
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];
};
Repairing Various Planes
ObjectChangedInPlace: PROC [screen: Imager.Context, ggData: GGData, selectClass: GGInterfaceTypes.SelectionClass ← normal, showColors: BOOL] = {
The selected objects have changed in some small way (e.g. line width or color). Repair the background plane and refresh the screen.
bBox: BoundBox ← GGBoundBox.BoundBoxOfSelected[ggData.scene, selectClass];
RepairBackgroundInBoundBox[ggData, bBox, TRUE, NIL];
PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
};
ObjectChangedBoundBoxProvided: PROC [screen: Imager.Context, ggData: GGData, showColors: BOOL] = {
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 ggData.refresh.startBoundBox. Repair the background plane and refresh the screen.
RepairBackgroundInBoundBox[ggData, ggData.refresh.startBoundBox, TRUE, NIL];
PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
};
ObjectAdded: PROC [screen: Imager.Context, ggData: GGData, showColors: BOOL] = {
An object has been added to the scene. All of the changes are confined to the box ggData.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).
RepairBackgroundInBoundBox[ggData, ggData.refresh.startBoundBox, FALSE, ggData.refresh.addedObject];
PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
};
RepairBackgroundInBoundBox: PROC [ggData: GGData, bBox: BoundBox, eraseFirst: BOOLFALSE, overObject: Slice] = {
backgroundContext: Imager.Context ← BufferedRefresh.GetLayerContext[ggData.refresh.sandwich, $Background];
IF ggData.refresh.suppressRefresh THEN RETURN;
IF ggData.refresh.showColors.state = off THEN {
PaintObjectsInBox: PROC = {
IF eraseFirst THEN GGBoundBox.EraseWithinBoundBox[backgroundContext, bBox];
DrawObjectsFiltered[dc: backgroundContext, ggData: ggData, filter: bBox, overObject: overObject];
};
Imager.DoSaveAll[backgroundContext, PaintObjectsInBox];
BufferedRefresh.SetLayerOK[ggData.refresh.sandwich, $Background, TRUE];
};
};
Dynamic
DuringSelect: PROC [screen: Imager.Context, ggData: GGData, showColors: BOOL] = {
IF ggData.refresh.suppressRefresh THEN RETURN;
IF NOT showColors THEN {
clientToViewer, viewerToClient: Imager.Transformation;
[clientToViewer, viewerToClient] ← BiScrollers.GetStyle[].GetTransforms[BiScrollers.QuaBiScroller[ggData.actionArea]];
BufferedRefresh.DrawSandwich[ggData.refresh.sandwich, screen, clientToViewer, viewerToClient, ggData, showColors];
}
ELSE {}; -- no feedback in SlowPaint mode
};
SplitBackgroundAndOverlay: PUBLIC PROC [ggData: GGData, restoreBox: BoundBox] = {
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.
PaintAllButOverlayed: PROC = {
GGBoundBox.EraseWithinBoundBox[backgroundContext, restoreBox];
DrawObjectsFiltered[dc: backgroundContext, ggData: ggData, filter: restoreBox, excludeOverlay: TRUE, overObject: NIL];
};
backgroundContext: Imager.Context;
IF ggData.refresh.suppressRefresh THEN RETURN;
backgroundContext ← BufferedRefresh.GetLayerContext[ggData.refresh.sandwich, $Background];
Imager.DoSaveAll[backgroundContext, PaintAllButOverlayed];
}; -- end StoreBackground
PaintDragOverlay: PROC [screen: Imager.Context, ggData: GGData, dragInProgress: BOOL, showColors: BOOL] = {
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.
clientToViewer, viewerToClient: Imager.Transformation;
ggData.refresh.dragInProgress ← dragInProgress;
ggData.refresh.caretIsMoving ← TRUE;
[clientToViewer, viewerToClient] ← BiScrollers.GetStyle[].GetTransforms[BiScrollers.QuaBiScroller[ggData.actionArea]];
BufferedRefresh.DrawSandwich[ggData.refresh.sandwich, screen, clientToViewer, viewerToClient, ggData, showColors];
};
FinishedAdding: PROC [screen: Imager.Context, ggData: GGData, showColors: BOOL] = {
The boundBox describes the region of the background which must be updated from the overlay.
MergeBackgroundAndOverlay[ggData, ggData.refresh.startBoundBox, FALSE, ggData.refresh.addedObject, showColors];
PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
};
BackmostSelectedSlice: PROC [scene: Scene] RETURNS [backmost: Slice] = {
sliceGen: SliceGenerator ← GGScene.TopLevelEntitiesInScene[scene];
FOR slice: Slice ← GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO
sliceD: SliceDescriptor ← GGSelect.FindSelectedSlice[slice, scene, normal];
IF sliceD#NIL THEN RETURN[sliceD.slice];
ENDLOOP;
RETURN[NIL];
};
FinishedDragging: PROC [screen: Imager.Context, ggData: GGData, showColors: BOOL] = {
overObject: Slice ← BackmostSelectedSlice[ggData.scene];
GGBoundBox.EnlargeByBox[ggData.refresh.startBoundBox, GGBoundBox.BoundBoxOfMoving[ggData.scene]];
MergeBackgroundAndOverlay[ggData, ggData.refresh.startBoundBox, FALSE, overObject, showColors];
PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE];
};
MergeBackgroundAndOverlay: PROC [ggData: GGData, bBox: BoundBox, eraseFirst: BOOLFALSE, overObject: Slice, showColors: BOOL] = {
The background and overlay planes are about to be recombined into the background plane, after dragging.
backgroundContext: Imager.Context ← BufferedRefresh.GetLayerContext[ggData.refresh.sandwich, $Background];
MergeBackgroundAndOverlayAux: PROC = {
IF eraseFirst THEN GGBoundBox.EraseWithinBoundBox[backgroundContext, bBox];
DrawObjectsFiltered[dc: backgroundContext, ggData: ggData, filter: bBox, overObject: overObject];
};
IF ggData.refresh.suppressRefresh THEN RETURN;
IF NOT showColors THEN {
Imager.DoSaveAll[backgroundContext, MergeBackgroundAndOverlayAux];
BufferedRefresh.SetLayerOK[ggData.refresh.sandwich, $Background, TRUE];
};
};
Drawing Routines which are independent of refresh strategy.
DrawObjects: PROC [screen: Imager.Context, ggData: GGData] = {
The common core of PaintEntireScene and InterpressEntireScene.
scene: Scene ← ggData.scene;
camera: CameraData ← ggData.camera;
sliceGen: SliceGenerator ← GGScene.TopLevelSlicesInScene[ggData.scene];
Imager.SetColor[screen, Imager.black];
FOR slice: Slice ← GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO
slice.class.drawParts[slice, NIL, screen, camera, FALSE];
ENDLOOP;
};
DrawObjectsFiltered: PROC [dc: Imager.Context, ggData: GGData, filter: GGBoundBox.BoundBox, excludeOverlay: BOOLFALSE, overObject: Slice] = {
Paints those objects in the scene within the filter bounding box, and in front of (and including) overObject (in PriorityOrder) into the display context.
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
sliceGen: SliceGenerator ← GGScene.TopLevelEntitiesInScene[scene];
thisSlice: Slice ← GGScene.NextSlice[sliceGen];
IF overObject # NIL THEN {
UNTIL thisSlice = overObject OR thisSlice = NIL DO
thisSlice ← GGScene.NextSlice[sliceGen];
ENDLOOP;
IF thisSlice = NIL THEN RETURN;
};
Imager.SetColor[dc, Imager.black];
GGBoundBox.Clip[dc: dc, bBox: filter];
FOR slice: Slice ← thisSlice, GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO
IF excludeOverlay AND slice.onOverlay THEN LOOP;
IF NOT OutsideOf[slice.class.getBoundBox[slice, NIL], filter] THEN slice.class.drawParts[slice, NIL, dc, camera, FALSE];
ENDLOOP;
};
scene: Scene ← ggData.scene;
camera: CameraData ← ggData.camera;
IF filter=NIL OR filter.null THEN RETURN;
Imager.DoSaveAll[dc, DrawObjectsFilteredAux];
};
DrawCaret: PROC [dc: Imager.Context, caret: Caret, color: Imager.Color] = {
caretPos: Point ← GGCaret.GetPoint[caret];
IF NOT GGCaret.Exists[caret] THEN RETURN;
Imager.SetColor[dc, color];
GGShapes.DrawCaret[dc, caretPos];
};
DrawAnchor: PROC [dc: Imager.Context, caret: Caret, color: Imager.Color] = {
caretPos: Point ← GGCaret.GetPoint[caret];
IF NOT GGCaret.Exists[caret] THEN RETURN;
Imager.SetColor[dc, color];
GGShapes.DrawAnchor[dc, caretPos];
};
Debugging
DrawNewAnchor: PROC [dc: Imager.Context, ggData: GGData] = {
anchorPos: Point ← GGCaret.GetPoint[ggData.anchor];
Imager.SetColor[dc, Imager.black];
GGShapes.DrawAnchor[dc, anchorPos];
};
PaintSpot: PROC [dc: Imager.Context, ggData: GGData] = {
IF ggData.refresh.suppressRefresh THEN RETURN;
Imager.SetColor[dc, Imager.black];
GGShapes.DrawSpot[dc, ggData.refresh.spotPoint];
};
PaintHitLine: PROC [dc: Imager.Context, ggData: GGData] = {
IF ggData.refresh.suppressRefresh THEN RETURN;
Imager.SetColor[dc, Imager.black];
Imager.SetStrokeEnd[dc, round];
Imager.MaskVector[dc, [ggData.refresh.spotPoint.x, ggData.refresh.spotPoint.y], [ggData.refresh.hitPoint.x, ggData.refresh.hitPoint.y]];
GGShapes.DrawFilledRect[dc, ggData.refresh.spotPoint, 3.0];
};
PaintOddHitLine: PROC [dc: Imager.Context, ggData: GGData] = {
IF ggData.refresh.suppressRefresh THEN RETURN;
Imager.SetColor[dc, Imager.black];
Imager.SetStrokeEnd[dc, round];
Imager.MaskVector[dc, [ggData.refresh.spotPoint.x, ggData.refresh.spotPoint.y], [ggData.refresh.hitPoint.x, ggData.refresh.hitPoint.y]];
GGShapes.DrawCP[dc, ggData.refresh.spotPoint];
};
PaintAlign: PROC [dc: Imager.Context, ggData: GGData] = {
Imager.SetColor[dc, ImagerColor.ColorFromGray[0.5]];
IF ggData.refresh.suppressRefresh THEN RETURN;
GGGravity.DrawAlignBagRegardless[dc, NARROW[ggData.hitTest.alignBag], ggData];
};
PaintBoundBoxes: PROC [dc: Imager.Context, ggData: GGData] = {
bBoxGen: BoundBoxGenerator;
PaintBoundBoxesAux: PROC = {
Draw the boxes.
bBoxGen ← GGScene.BoundBoxesInScene[ggData.scene];
FOR box: BoundBox ← GGScene.NextBox[bBoxGen], GGScene.NextBox[bBoxGen] UNTIL box = NIL DO
GGBoundBox.DrawBoundBox[dc, box];
ENDLOOP;
};
IF ggData.refresh.suppressRefresh THEN RETURN;
Imager.DoSaveAll[dc, PaintBoundBoxesAux];
};
PaintTightBoxes: PROC [dc: Imager.Context, ggData: GGData] = {
box: BoundBox;
PaintTightBoxesAux: PROC = {
Draw the boxes.
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
FOR sliceD: SliceDescriptor ← GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO
box ← sliceD.slice.class.getTightBox[sliceD.slice, sliceD.parts];
GGBoundBox.DrawBoundBox[dc, box];
ENDLOOP;
};
IF ggData.refresh.suppressRefresh THEN RETURN;
Imager.DoSaveAll[dc, PaintTightBoxesAux];
};
PaintOutlineBoxes: PROC [dc: Imager.Context, ggData: GGData] = {
PaintBoundBoxesAux: PROC = {
Draw the boxes.
outSeqGen: GGSelect.OutlineSequenceGenerator;
bBox: BoundBox;
outSeqGen ← GGSelect.SelectedOutlineSequences[ggData.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[dc, bBox];
};
FOR holeSeq: Sequence ← GGSequence.NextSequence[outSeq.holeSeqs], GGSequence.NextSequence[outSeq.holeSeqs] UNTIL holeSeq = NIL DO
bBox ← GGTraj.GetBoundBox[holeSeq.traj];
GGBoundBox.DrawBoundBox[dc, bBox];
ENDLOOP;
ENDLOOP;
};
IF ggData.refresh.suppressRefresh THEN RETURN;
Imager.DoSaveAll[dc, PaintBoundBoxesAux];
};
PaintSelectionBox: PUBLIC PROC [dc: Imager.Context, ggData: GGData] = {
box: BoundBox ← NIL;
PaintSelectionBoxAux: PROC = {
Draw the box.
box ← GGBoundBox.BoundBoxOfSelected[ggData.scene];
IF NOT box.null THEN GGBoundBox.DrawBoundBox[dc, box];
};
IF ggData.refresh.suppressRefresh THEN RETURN;
Imager.DoSaveAll[dc, PaintSelectionBoxAux];
};
GetOutlineParts: PROC [sliceD: OutlineDescriptor, atom: ATOM] RETURNS [parts: OutlineDescriptor] = {
parts ← SELECT atom FROM
$DrawBackgroundBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].background,
$DrawOverlayBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].overlay,
$DrawRubberBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].rubber,
$DrawDragBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].drag,
ENDCASE => ERROR;
};
GetSliceParts: PROC [sliceD: SliceDescriptor, atom: ATOM] RETURNS [parts: SliceDescriptor] = {
parts ← SELECT atom FROM
$DrawBackgroundBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].background,
$DrawOverlayBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].overlay,
$DrawRubberBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].rubber,
$DrawDragBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].drag,
ENDCASE => ERROR;
};
DrawMovingBox: PUBLIC PROC [dc: Imager.Context, ggData: GGData, atom: ATOM] = {
OutlineEnlargeBox: PROC [outlineD: OutlineDescriptor] = {
thisBox: BoundBox;
theseParts: OutlineDescriptor;
theseParts ← GetOutlineParts[outlineD, atom];
IF theseParts.parts = NIL THEN thisBox ← GGBoundBox.NullBoundBox[]
ELSE thisBox ← outlineD.slice.class.getBoundBox[outlineD.slice, theseParts.parts];
GGBoundBox.EnlargeByBox[bBox: box, by: thisBox];
};
SliceEnlargeBox: PROC [sliceD: SliceDescriptor] = {
thisBox: BoundBox;
theseParts: SliceDescriptor;
theseParts ← GetSliceParts[sliceD, atom];
IF theseParts.parts = NIL THEN thisBox ← GGBoundBox.NullBoundBox[]
ELSE thisBox ← sliceD.slice.class.getBoundBox[sliceD.slice, theseParts.parts];
GGBoundBox.EnlargeByBox[bBox: box, by: thisBox];
};
box: BoundBox ← GGBoundBox.NullBoundBox[];
IF ggData.refresh.suppressRefresh THEN RETURN;
GGSelect.DoForEachSelectedOutline[ggData.scene, normal, OutlineEnlargeBox];
GGSelect.DoForEachSelectedSlice[ggData.scene, normal, SliceEnlargeBox];
IF NOT box.null THEN GGBoundBox.DrawBoundBox[dc, box];
};
EraseAll: PROC [dc: Imager.Context] = {
rect: Imager.Rectangle;
rect ← ImagerBackdoor.GetBounds[dc];
Imager.SetColor[dc, Imager.white];
Imager.MaskRectangle[dc, rect];
};
Drawing Arrows
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 Vectors2d;
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 ← Vectors2d.Normalize[Vectors2d.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 ← Vectors2d.Normalize[Vectors2d.Sub[tip, base]];
perp ← [axis.y, -axis.x];
Imager.Clip[dc, ClipPath, FALSE, TRUE];
};
};
DrawArrows: PROC [dc: Imager.Context, traj: Traj, ggData: GGData] = {
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];
};
Drawing Feedback
DrawJoints: PROC [dc: Imager.Context, traj: Traj, ggData: GGData] = {
Let Q be a logical variable corresponding to (ggData.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.
IF ggData.camera.quality = quality OR traj.parent.onOverlay THEN RETURN;
IF NOT traj.visibleJoints THEN RETURN;
Suppress joints for an interpress master and for dragging.
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, ggData: GGData, selectClass: SelectionClass ← normal] = {
jointGen: JointGenerator;
Suppress joints for an interpress master.
IF ggData.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;
};
For Interpress Masters
SnapShot: PUBLIC PROC [dc: Imager.Context, ggData: GGData] = {
Called by GGMouseEvent.IPSnapShot to get a picture of Gargoyle dragging in action.
boundRect: Rectangle ← ImagerBackdoor.GetBounds[dc]; -- Not IMPLEMENTED for IP contexts
boundRect: Rectangle ← [x: 0.0, y: 0.0, w: 8.5*72.0, h: 11.0*72.0]; -- kludge
SnapshotBackground[dc, ggData];
RefreshOverlay[dc, boundRect, ggData]; -- fortunately, RefreshOverlay doesn't user boundRect
};
SnapshotBackground: PROC [dc: Imager.Context, ggData: GGData] = {
Draw all but the overlay objects into a bitmap. Auxiliary for SnapShot.
scene: Scene ← ggData.scene;
camera: CameraData ← ggData.camera;
sliceGen: SliceGenerator;
Draw most of the scene.
Imager.SetColor[dc, Imager.black];
Worry about scene objects.
sliceGen ← GGScene.TopLevelEntitiesInScene[ggData.scene];
FOR slice: Slice ← GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO
IF OnOverlay[slice, ggData] THEN LOOP
IF slice.onOverlay THEN LOOP
ELSE slice.class.drawParts[slice, NIL, dc, camera, FALSE];
ENDLOOP;
Worry about the caret.
IF NOT OnOverlay[ggData.caret, ggData] THEN DrawCaret[dc, ggData.caret, Imager.black];
DrawCaret[dc, ggData.caret, Imager.black];
DrawAnchor[dc, ggData.anchor, Imager.black];
Worry about alignment lines.
GGGravity.DrawAlignBagRegardless[dc, NARROW[ggData.hitTest.alignBag], ggData];
};
InterpressEntireScene: PUBLIC PROC [dc: Imager.Context, ggData: GGData] = {
DrawObjects[dc, ggData];
};
The Overlay Plane
MoveToOverlay: PUBLIC PROC [sliceD: SliceDescriptor, ggData: GGData] = {
IF OnOverlay[sliceD, ggData] THEN ERROR;
sliceD.slice.onOverlay ← TRUE;
ggData.refresh.overlayList ← GGUtility.AppendSliceDescriptorList[LIST[sliceD], ggData.refresh.overlayList];
ggData.refresh.orderedOverlayList ← NIL;
};
MoveAllSelectedToOverlay: PUBLIC PROC [ggData: GGData, selectClass: SelectionClass] = {
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, selectClass];
FOR sliceD: SliceDescriptor ← GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO
MoveToOverlay[sliceD, ggData];
ENDLOOP;
};
MoveToBackground: PUBLIC PROC [sliceD: SliceDescriptor, ggData: GGData] = {
IF NOT OnOverlay[sliceD, ggData] THEN RETURN;
ggData.refresh.overlayList ← GGUtility.DeleteSliceDescriptorFromList[sliceD, ggData.refresh.overlayList];
sliceD.slice.onOverlay ← FALSE;
ggData.refresh.orderedOverlayList ← NIL;
};
MoveOverlayToBackground: PUBLIC PROC [ggData: GGData] = {
FOR overlayList: LIST OF SliceDescriptor ← ggData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO
overlayList.first.slice.onOverlay ← FALSE;
ENDLOOP;
ggData.refresh.overlayList ← NIL;
ggData.refresh.orderedOverlayList ← NIL;
};
EmptyOverlay: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = {
RETURN[ggData.refresh.overlayList = NIL];
};
OnOverlay: PROC [sliceD: SliceDescriptor, ggData: GGData] RETURNS [BOOL] = {
RETURN[sliceD.slice.onOverlay];
};
OrderOverlayList: PROC [ggData: GGData] RETURNS [orderedList: LIST OF SliceDescriptor] = {
traverse the scene.entities from back to end front.
FindOverlayedD: PROC [slice: Slice] RETURNS [sliceD: SliceDescriptor] = {
FOR ov: LIST OF SliceDescriptor ← ggData.refresh.overlayList, ov.rest UNTIL ov=NIL DO
IF ov.first.slice=slice THEN RETURN[ov.first];
ENDLOOP;
RETURN[NIL];
};
sliceD: SliceDescriptor;
sliceGen: SliceGenerator;
finger: LIST OF SliceDescriptor;
[orderedList, finger] ← GGUtility.StartSliceDescriptorList[];
sliceGen ← GGScene.TopLevelSlicesInScene[ggData.scene];
FOR slice: Slice ← GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO
IF slice.onOverlay THEN {
sliceD ← FindOverlayedD[slice];
IF sliceD = NIL THEN sliceD ← slice.class.newParts[slice, NIL, topLevel];
[orderedList, finger] ← GGUtility.AddSliceDescriptor[sliceD, orderedList, finger];
};
ENDLOOP;
IF OnOverlay[ggData.caret, ggData] THEN [orderedList, finger] ← GGUtility.AddEntity[ggData.caret, orderedList, finger];
};
Utility
AdjustContextForDrawBits: PROC [dc: Imager.Context, ggData: GGData] = {
this procedure is needed to map the chunking and background bitmaps onto the actual viewer area before DrawBits is called.
viewerToClient: Imager.Transformation ← BiScrollers.GetStyle[].GetTransforms[BiScrollers.QuaBiScroller[ggData.actionArea]].viewerToClient;
Imager.ConcatT[dc, viewerToClient];
};
InitStats: PROC [] = {
interval: CodeTimer.Interval;
interval ← CodeTimer.CreateInterval[$PaintEntireScene];
CodeTimer.AddInt[interval, $Gargoyle];
};
InitStats[];
END.
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.