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] = { 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; $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 $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]; $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]; }; }; 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]]; ignoreBackingMap _ showColors; BufferedRefresh.DrawSandwich[sandwich, screen, clientToViewer, viewerToClient, ggData, ignoreBackingMap]; }; 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] = { 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]; 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] = { 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] = { 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] = { 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]; }; DrawAttractorFeedback: PROC [dc: Imager.Context, ggData: GGData, dragInProgress, caretIsMoving: BOOL] = { 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]; }; 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; }; 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]; }; ObjectChangedInPlace: PROC [screen: Imager.Context, ggData: GGData, selectClass: GGInterfaceTypes.SelectionClass _ normal, showColors: BOOL] = { 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] = { RepairBackgroundInBoundBox[ggData, ggData.refresh.startBoundBox, TRUE, NIL]; PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE]; }; ObjectAdded: PROC [screen: Imager.Context, ggData: GGData, showColors: BOOL] = { RepairBackgroundInBoundBox[ggData, ggData.refresh.startBoundBox, FALSE, ggData.refresh.addedObject]; PaintAllPlanes[screen, ggData, showColors, FALSE, FALSE]; }; RepairBackgroundInBoundBox: PROC [ggData: GGData, bBox: BoundBox, eraseFirst: BOOL _ FALSE, 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]; }; }; 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] = { 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] = { 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] = { 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: BOOL _ FALSE, overObject: Slice, showColors: BOOL] = { 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]; }; }; DrawObjects: PROC [screen: Imager.Context, ggData: GGData] = { 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: BOOL _ FALSE, overObject: Slice] = { 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]; }; 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] = { 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 = { 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 = { 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 = { 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 = { box _ GGBoundBox.BoundBoxOfSelected[ggData.scene]; IF NOT box.null THEN GGBoundBox.DrawBoundBox[dc, box]; }; IF ggData.refresh.suppressRefresh THEN RETURN; Imager.DoSaveAll[dc, PaintSelectionBoxAux]; }; 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] = { 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.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]; }; 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]; }; DrawJoints: PROC [dc: Imager.Context, traj: Traj, ggData: GGData] = { IF ggData.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, ggData: GGData, selectClass: SelectionClass _ normal] = { jointGen: JointGenerator; 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; }; SnapShot: PUBLIC PROC [dc: Imager.Context, ggData: GGData] = { 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] = { scene: Scene _ ggData.scene; camera: CameraData _ ggData.camera; sliceGen: SliceGenerator; Imager.SetColor[dc, Imager.black]; sliceGen _ GGScene.TopLevelEntitiesInScene[ggData.scene]; FOR slice: Slice _ GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO IF slice.onOverlay THEN LOOP ELSE slice.class.drawParts[slice, NIL, dc, camera, FALSE]; ENDLOOP; DrawCaret[dc, ggData.caret, Imager.black]; DrawAnchor[dc, ggData.anchor, Imager.black]; GGGravity.DrawAlignBagRegardless[dc, NARROW[ggData.hitTest.alignBag], ggData]; }; InterpressEntireScene: PUBLIC PROC [dc: Imager.Context, ggData: GGData] = { DrawObjects[dc, ggData]; }; 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] = { 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; }; AdjustContextForDrawBits: PROC [dc: Imager.Context, ggData: GGData] = { 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. (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 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 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. The Sixteen Types of Scene Change: Dragging Debugging [Artwork node; type 'ArtworkInterpress on' to command tool] clientToViewer _ ImagerTransformation.Invert[viewerToClient]; Single-Plane Commands This could use some optimizing. DrawCpsOfSelectedOutlines[dc, ggData.scene, ggData.camera, dragInProgress, caretIsMoving]; No Imager.DoSaveAll is used. This procedure sets the color to black. Add these new features to the foreground context. Repaint all of the alignment lines. Use the FunctionCache to avoid drawing what has already been drawn. Drawing Utilities Draws control points on slices which are the caret attractor 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; }; Puts all the selected (hot & normal) slices in a list, and returns them 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; }; 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; }; Repairing Various Planes 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 ggData.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 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). Dynamic 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. Drawing Routines which are independent of refresh strategy. 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[dc, ImagerColor.ColorFromGray[0.5]]; Draw the boxes. Draw the boxes. Draw the boxes. Draw the box. 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; }; 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]; }; GGSelect.DoForEachSelectedOutline[ggData.scene, normal, OutlineEnlargeBox]; Drawing Arrows Drawing Feedback 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. 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. boundRect: Rectangle _ ImagerBackdoor.GetBounds[dc]; -- Not IMPLEMENTED for IP contexts Draw all but the overlay objects into a bitmap. Auxiliary for SnapShot. Draw most of the scene. Worry about scene objects. IF OnOverlay[slice, ggData] THEN LOOP Worry about the caret. IF NOT OnOverlay[ggData.caret, ggData] THEN DrawCaret[dc, ggData.caret, Imager.black]; Worry about alignment lines. The Overlay Plane traverse the scene.entities from back to end front. IF OnOverlay[ggData.caret, ggData] THEN [orderedList, finger] _ GGUtility.AddEntity[ggData.caret, orderedList, finger]; 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. Ê04˜code™Kšœ Ïmœ1™<—K™Kšœ5™5Kšœ!™!K™(—K™šÏk ˜ Jšœæ˜æK˜—šÏn œžœž˜Jšžœç˜îKšžœ ž˜—˜Kšœ žœ˜)Kšœ žœ˜'Kšœžœ˜4Kšœ žœ˜+Kšœžœ˜%Kšœžœ˜Kšœ žœ˜*Kšœžœ"˜9Kšœ žœ˜#Kšœ žœ˜*Kšœžœ˜!Kšœ žœ˜+Kšœžœ˜3Kšœžœ ˜5Kšœžœ)˜GKšœžœ ˜5Kšœžœ˜'Kšœžœ˜!Kšœžœ˜3Kšœ žœ˜%Kšœžœ˜!Kšœžœ˜!Kšœ žœ˜'Kšœ žœ˜+Kšœžœ!˜7Kšœ žœ˜'Kšœžœ#˜7Kšœžœ"˜9Kšœžœ˜Kšœžœ˜#K˜Kš Ÿœžœžœ žœžœ˜/—š Ÿœžœžœ*žœžœ˜gšŸœžœžœ˜ šœ3žœ˜>Kšœ>˜>Kšœ-Ïc˜IKšœ!žœ "˜JKšœžœžœ %˜AKšœ˜Kšœ˜—K˜—Kšžœ)žœÏb œ#˜sKšžœ4 &˜^K˜K˜—šŸœžœ*žœ˜ZKšœ‘™‘KšœÍ™ÍK™Kšœ žœ(˜8šžœžœ 7˜YKšœžœ˜ Kšœ-˜-K˜—šžœžœž˜Kšœ žœ˜Kš¡"™"Kšœ\˜\KšœEžœžœ˜SKšœGžœžœ˜UKšœEžœžœ˜SKšœ@žœžœ˜NKšœAžœžœ˜OKšœ<˜˜>KšœB˜BKšœ:žœžœ˜]Kšœ;žœžœ ˜Yšœ=žœžœ ˜[Kš¡™—Kšœ2žœ ˜YKšœ4žœ ˜\Kšœ:˜:KšœR˜RKšœ\˜\šœ8˜8Kš¡ ™ —Kšœ(˜(Kšœ.˜.Kšœ4˜4Kšœ*˜*Kšœ4˜4Kšœ4˜4Kšœ8˜8Kšœ8˜8Kšœs˜sšžœ˜ Kšœˆ˜ˆKšœ ˜ 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 ¤ ¨  ÄnHÄSùD¡£ r jÄÔºsÄÛM ¢ ¨¡¡¨ r jÄð¹ ¤ÄScVž ¢ ¥ ¨Å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 é¢¯“¡¡¨¢·“¢°“ÄboLIJôG™ÄfEOÄc )—˜¢¯“¡¡¨¢·“¢°“ľ“Ĩm™Ä]åIÄ›ËD—˜ k é k gšŸ=™=—K˜šŸœžœžœžœ˜?procšœ*žœ˜/Mšœžœ!˜3Mšœ žœ˜"Mšœžœ˜(Mšœžœ˜'Mšœžœ'˜:—˜J˜——šŸœž œ6žœ˜\Kšœ-˜-Kšœ1˜1Kšœ2žœ˜9Kšœ2žœ˜9Kšœ+žœžœ˜9Kšœ0˜0K˜K˜—š Ÿœžœ6žœžœžœ˜~Kšœ-˜-Kšœ6˜6Kšœžœ˜Kšžœ žœžœ˜.Kšœ-˜-Kšœ/˜/Kšœv˜vKšœ=™=Kšœ˜Kšœi˜iK˜K˜—K™K™K™šŸœžœ8žœžœ˜[K•StartOfExpansion¡[screen: Imager.Context, gargoyleData: GGInterfaceTypes.GargoyleData, filter: GGBasicTypes.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY]šœžœ ˜$Kšžœ žœžœ˜.K–¡[screen: Imager.Context, gargoyleData: GGInterfaceTypes.GargoyleData, filter: GGBasicTypes.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY]šœqžœžœ˜‰K˜K˜—šŸœžœ8žœžœ˜XK™K–¡[screen: Imager.Context, gargoyleData: GGInterfaceTypes.GargoyleData, filter: GGBasicTypes.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY]šœžœ ˜$šŸœžœ˜Kšžœ#žœžœ? ˜‚š žœžœžœAžœ žœž˜gKšœ]˜]Kšžœ˜—K˜—Kšžœ žœžœ˜.Kšœ)˜)K˜K˜—šŸœžœ8žœžœ˜[K–¡[screen: Imager.Context, gargoyleData: GGInterfaceTypes.GargoyleData, filter: GGBasicTypes.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY]šœžœ ˜$Kšœžœ ˜3Kšœžœ˜5Kšžœ žœžœ˜.šžœžœ˜'KšœA˜AJšœZ™ZJšœX˜XK˜—K˜K˜—šŸœžœ8žœžœ˜[K–¡[screen: Imager.Context, gargoyleData: GGInterfaceTypes.GargoyleData, filter: GGBasicTypes.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY]šœžœ ˜$Kšžœ žœžœ˜.Kšœ.˜.KšœF˜FK˜K˜—šŸœžœ8žœžœ˜[K™EK–¡[screen: Imager.Context, gargoyleData: GGInterfaceTypes.GargoyleData, filter: GGBasicTypes.BoundBox, excludeOverlay: BOOL _ FALSE, overObject: REF ANY]šœžœ ˜$Kšžœ žœžœ˜.Kš¡ œ!˜*Kš¡ œ"˜,K˜K˜—š Ÿœžœžœžœžœ!˜VJš¡œ.™1šŸÐbn œžœ˜KšœC˜CK˜—Kšœj˜jKšœ5˜5KšœAžœ˜GJ˜J˜—šŸœžœžœ˜;K™hšŸ¢ œžœ˜KšœU˜UK˜—Kšœj˜jKšœ5˜5KšœAžœ˜GJ˜J˜—K˜K™K˜šŸœžœEžœ˜iK™˜>Kšœ_žœžœ˜vK˜—Kšœ"˜"Kšžœ žœžœ˜.KšœZ˜ZKšœ:˜:Kšœ ˜—K˜šŸœžœ:žœžœ˜kK™ÝKšœ6˜6Kšœ/˜/Kšœžœ˜$Kšœv˜vKšœr˜rK˜K˜—šŸœžœ6žœ˜SKšœ[™[Kšœ@žœ*˜oKšœ+žœžœ˜9K˜K˜—šŸœžœžœ˜HJšœB˜BšžœIžœ žœž˜`JšœK˜KJšžœžœžœžœ˜(Jšžœ˜—Jšžœžœ˜ K˜K˜—šŸœžœ6žœ˜UKšœ8˜8Kšœa˜aKšœ@žœ˜_Kšœ+žœžœ˜9˜K˜——š Ÿœžœ.žœžœ!žœ˜ƒK™gKšœj˜jšŸœžœ˜&Kšžœ žœ9˜KKšœa˜aK˜—Kšžœ žœžœ˜.šžœžœ žœ˜KšœB˜BKšœAžœ˜GK˜—K˜—K˜K™;K™šŸ œžœ-˜>KšœŸœ™>Kšœ˜Kšœ#˜#KšœG˜GKšœ&˜&šžœIžœ ž˜`Kšœžœžœ˜9Kšžœ˜—K˜K˜—šŸœžœSžœžœ˜Kšœ™™™šŸ œžœ$žœžœ˜EKš žœžœžœžœ &˜ŽK˜—šŸœžœ %˜FKšœB˜BKšœ/˜/šžœžœžœ˜šžœžœ žœž˜2Kšœ(˜(Kšžœ˜—Kšžœ žœžœžœ˜K˜—Kšœ"˜"K˜&šžœ7žœ žœž˜NKšžœžœžœžœ˜0Kš žœžœ*žœ žœžœžœ˜xKšžœ˜—K˜—Kšœ˜Kšœ#˜#Kš žœžœžœ žœžœ˜)Kšœ-˜-K˜K˜—šŸ œžœ<˜KKšœ*˜*Kšžœžœžœžœ˜)Kšœ˜Kšœ!˜!K˜K˜—šŸ œžœ<˜LKšœ*˜*Kšžœžœžœžœ˜)Kšœ˜Kšœ"˜"K˜K˜—K™K™ K˜šŸ œžœ)˜Kšžœ žœžœ˜.Kšœ"˜"Kšœ˜Kšœˆ˜ˆKšœ.˜.K˜K˜K˜—šŸ œžœ)˜9Kšœ4™4Kšžœ žœžœ˜.Kšœ%žœ#˜NK˜K˜—šŸœžœ)˜>K˜šŸœžœ˜K™Kšœ2˜2šžœDžœžœž˜YKšœ!˜!—Kšžœ˜K˜—Kšžœ žœžœ˜.Kšœ)˜)K˜K˜—šŸœžœ)˜>Kšœ˜šŸœžœ˜K™JšœW˜Wšžœržœ žœž˜ŠJšœA˜AKšœ!˜!Jšžœ˜—J˜—Kšžœ žœžœ˜.Kšœ)˜)K˜K˜—šŸœžœ)˜@šŸœžœ˜K™Kšœ-˜-K˜KšœD˜Dšžœwžœ žœž˜šžœžœžœ˜Kšœ0˜0Kšœ"˜"K˜—šžœhžœ žœž˜Kšœ(˜(Kšœ"˜"Kšžœ˜—Kšžœ˜—K˜—Kšžœ žœžœ˜.Kšœ)˜)K˜K˜—šŸœžœžœ)˜GKšœžœ˜šŸœžœ˜K™ Kšœ2˜2Kšžœžœ žœ"˜6K˜—Kšžœ žœžœ˜.Kšœ+˜+K˜K˜—šŸœžœ#žœžœ™dšœž œž™Kšœ\™\KšœV™VKšœT™TKšœP™PKšžœžœ™—K™K™—šŸ œžœ!žœžœ˜^šœž œž˜Kšœ\˜\KšœV˜VKšœT˜TKšœP˜PKšžœžœ˜—K˜K˜K˜—šŸ œžœžœ,žœ˜OšŸœžœ"™9Kšœ™Kšœ™Kšœ-™-Kšžœžœžœ$™BKšžœN™RKšœ0™0K™—šŸœžœ˜3Kšœ˜Kšœ˜Kšœ)˜)Kšžœžœžœ$˜BKšžœJ˜NKšœ0˜0K˜—Kšœ*˜*Kšžœ žœžœ˜.KšœK™KKšœG˜GKšžœžœ žœ"˜6K˜K˜—šŸœžœ˜'Kšœ˜Kšœ$˜$Kšœ"˜"Kšœ˜K˜K˜—K™™K˜—šŸ œžœžœWžœ˜ˆK˜ Kšœ žœ˜ Kšœ#˜#Kšœ˜Kšœ˜Mšœ+˜+šžœ žœ˜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šœ5˜5Kšœ˜Kšœžœžœ˜'K˜—šžœžœ˜Kšœ˜Kšœ4˜4Kšœ˜Kšœ˜Kšœ5˜5Kšœ˜Kšœžœžœ˜'K˜—K˜K˜K˜—šŸ œžœ5˜EK˜=Kšœžœ˜Kš žœžœžœžœžœžœ˜5Kšœe˜eMšžœžœ=˜QMšžœžœA˜UK˜K˜—K˜K™K˜šŸ œžœ6˜FKšœO™OK™*K™3K™6K™(K™$Kšžœ!žœžœžœ˜Hšžœžœžœžœ˜&K™:—K˜"šžœžœžœž˜*Kšœ6˜6—Kšžœ˜K˜K˜—šŸœžœ_˜˜Kš¡)™)—Kšžœ!žœžœ˜/K˜"Kšœ,˜,šžœžœBžœž˜[KšœO˜O—Kšžœ˜K˜K˜—K™K™šŸœžœžœ)˜>KšœR™RKšœW™WKšœD  ˜MKšœ˜Kšœ' 5˜\K˜K˜—šŸœžœ)˜AKšœH™HKšœ˜Kšœ#˜#šœ˜K™—šœ"˜"K™—Kšœ9˜9šžœIžœ žœž˜`Kšžœžœž™%Kšžœžœž˜Kšžœžœžœ˜:Kšžœ˜K™—Kšžœžœ!žœ+™VKšœ*˜*šœ,˜,K™—Kšœ%žœ#˜NK˜K˜—šŸœžœžœ)˜KKšœ˜K˜K˜—K™™K™—šŸ œžœžœ.˜HKšžœžœžœ˜(Kšœžœ˜KšœŸ#œžœ&˜kKšœ$žœ˜(K˜K˜—šŸœžœžœ2˜WKšœ\˜\šžœržœžœž˜ˆKšœ˜Kšžœ˜—K˜K˜—šŸœžœžœ.˜KKšžœžœžœžœ˜-KšœŸ'œ%˜iKšœžœ˜Kšœ$žœ˜(K˜K˜—šŸœžœžœ˜9š žœžœžœ@žœžœž˜rKšœ$žœ˜*Kšžœ˜—Kšœžœ˜!Kšœ$žœ˜(˜K˜——š Ÿ œžœžœžœžœ˜=Kšžœžœ˜)K˜K˜—šŸ œžœ+žœžœ˜LKšžœ˜K˜K˜—š Ÿœžœžœžœžœ˜ZK™3šŸœžœžœ˜Iš žœžœžœ7žœžœž˜UKšžœžœžœ ˜.Kšžœ˜—Kšžœžœ˜ K˜—Kšœ˜J˜Kšœžœžœ˜ Kšœ"Ÿœ˜=Kšœ7˜7šžœIžœ žœž˜`šžœžœ˜Kšœ˜Kšžœ žœžœ&žœ ˜IKšœ"Ÿœ˜RK˜—Kšžœ˜—Kšžœ!žœP™wK˜K˜—K™K™šŸœžœ)˜GK™zKšœŠ˜ŠKšœ#˜#K˜K˜—šŸ œžœ˜Kšœ˜Kšœ7˜7Kšœ&˜&K˜K˜—K˜ K˜šžœ˜Kšœ²™²K™——…—vÔÏ"