<> <> <> <<>> DIRECTORY Atom, GGBoundBox, GGCaret, GGError, GGGravity, GGInterfaceTypes, GGModelTypes, GGObjects, GGRefresh, GGSelect, GGShapes, GGTouch, GGTransform, GGUtility, Imager, ImagerBackdoor, ImagerColor, ImagerOps, ImagerPath, ImagerTransformation, Rosary, Rope; GGRefreshImpl: CEDAR PROGRAM IMPORTS Atom, GGBoundBox, GGCaret, GGError, GGGravity, GGObjects, GGSelect, GGShapes, GGTouch, GGTransform, GGUtility, Imager, ImagerBackdoor, ImagerColor, Rope, Rosary EXPORTS GGRefresh = BEGIN BoundBox: TYPE = GGModelTypes.BoundBox; BoundBoxGenerator: TYPE = GGObjects.BoundBoxGenerator; Camera: TYPE = GGModelTypes.Camera; Caret: TYPE = GGInterfaceTypes.Caret; Cluster: TYPE = GGModelTypes.Cluster; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Joint: TYPE = GGModelTypes.Joint; JointPair: TYPE = GGModelTypes.JointPair; JointGenerator: TYPE = GGObjects.JointGenerator; Outline: TYPE = GGModelTypes.Outline; Point: TYPE = GGModelTypes.Point; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGModelTypes.Segment; SegmentGenerator: TYPE = GGObjects.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SelectionClass: TYPE = GGInterfaceTypes.SelectionClass; Traj: TYPE = GGModelTypes.Traj; ActionAreaPaint: PUBLIC PROC [dc: Imager.Context, whatToDo: ATOM, gargoyleData: GargoyleData] = { <> <> SELECT whatToDo FROM $PaintEntireScene => PaintEntireScene[dc, gargoyleData]; $PaintSelectedRegion => PaintEntireScene[dc, gargoyleData]; <> $PickUpEntity => {}; $EraseOverlay => EraseOverlay[dc, gargoyleData]; $PaintDragOverlay => PaintDragOverlay[dc, gargoyleData]; $PaintNewAnchor => PaintNewAnchor[dc, gargoyleData]; <> $PaintSpot => PaintSpot[dc, gargoyleData]; $PaintHitLine => PaintHitLine[dc, gargoyleData]; $PaintTouchPoints => PaintTouchPoints[dc, gargoyleData]; $PaintAlign => PaintAlign[dc, gargoyleData]; $PaintBoundBoxes => PaintBoundBoxes[dc, gargoyleData]; $PaintSelectionBox => PaintSelectionBox[dc, gargoyleData]; ENDCASE => { GGError.Append[ Rope.Cat["Gargoyle GGRefreshImpl doesn't know how to ", Atom.GetPName[whatToDo], "."], oneLiner]; }; }; WorldCoordsContext: PROC [dc: Imager.Context, camera: Camera] = { Imager.TranslateT[dc, [camera.cameraScreen[1], camera.cameraScreen[2]]]; }; <> DrawCluster: PUBLIC PROC [dc: Imager.Context, cluster: Cluster, gargoyleData: GargoyleData] = { }; DrawOutline: PUBLIC PROC [dc: Imager.Context, outline: Outline, gargoyleData: GargoyleData] = { fence: Traj; fence _ outline.children.first; IF fence.role = fence THEN { FillTraj[dc, fence, outline.fillColor]; }; DrawTraj[dc, fence, gargoyleData]; }; DrawTraj: PUBLIC PROC [dc: Imager.Context, traj: Traj, gargoyleData: GargoyleData] = { seg: Segment; FOR i: INT IN [0..GGObjects.HiSegment[traj]] DO seg _ GGObjects.FetchSegment[traj, i]; Imager.SetStrokeWidth[dc, seg.strokeWidth]; Imager.SetColor[dc, seg.color]; seg.class.maskStroke[dc, seg]; ENDLOOP; Imager.SetStrokeWidth[dc, 1.0]; DrawJoints[dc, traj, gargoyleData]; }; DrawSequence: PUBLIC PROC [dc: Imager.Context, seq: Sequence, gargoyleData: GargoyleData] = { segGen: SegmentGenerator; segGen _ GGObjects.SegmentsInSequence[seq]; FOR seg: Segment _ GGObjects.NextSegment[segGen], GGObjects.NextSegment[segGen] UNTIL seg = NIL DO Imager.SetStrokeWidth[dc, seg.strokeWidth]; Imager.SetColor[dc, seg.color]; seg.class.maskStroke[dc, seg]; ENDLOOP; Imager.SetStrokeWidth[dc, 1.0]; DrawJointsInSequence[dc, seq, gargoyleData]; }; DrawJoints: PROC [dc: Imager.Context, traj: Traj, gargoyleData: GargoyleData] = { visible: BOOL; joint: Joint; IF GGSelect.IsSelected[traj, gargoyleData, normal] THEN { FOR i: INT IN [0..GGObjects.HiJoint[traj]] DO GGShapes.DrawSelectedJoint[dc, GGObjects.FetchJointPos[traj, i]]; ENDLOOP; RETURN; }; visible _ traj.visibleJoints OR traj.outline.onOverlay; FOR i: INT IN [0..GGObjects.HiJoint[traj]] DO joint _ NARROW[Rosary.Fetch[traj.joints, i]]; IF GGSelect.IsSelected[joint, gargoyleData, normal] THEN GGShapes.DrawSelectedJoint[dc, GGObjects.FetchJointPos[traj, i]] ELSE IF visible THEN GGShapes.DrawJoint[dc, GGObjects.FetchJointPos[traj, i]]; ENDLOOP; }; DrawJointsInSequence: PROC [dc: Imager.Context, seq: Sequence, gargoyleData: GargoyleData] = { visible: BOOL; joint: Joint; jointGen: JointGenerator; jointGen _ GGObjects.JointsInSequence[seq]; IF GGSelect.IsSelected[seq.traj, gargoyleData, normal] THEN { FOR i: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL i = -1 DO GGShapes.DrawSelectedJoint[dc, GGObjects.FetchJointPos[seq.traj, i]]; ENDLOOP; RETURN; }; visible _ seq.traj.visibleJoints OR seq.traj.outline.onOverlay; FOR i: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL i = -1 DO joint _ NARROW[Rosary.Fetch[seq.traj.joints, i]]; IF GGSelect.IsSelected[joint, gargoyleData, normal] THEN GGShapes.DrawSelectedJoint[dc, GGObjects.FetchJointPos[seq.traj, i]] ELSE IF visible THEN GGShapes.DrawJoint[dc, GGObjects.FetchJointPos[seq.traj, i]]; ENDLOOP; }; FillTraj: PUBLIC PROC [dc: Imager.Context, traj: Traj, fillColor: Imager.Color] = { BuildPath: Imager.PathProc = { seg: Segment; firstPoint: Point _ GGObjects.FetchJointPos[traj, 0]; moveTo[ [firstPoint[1], firstPoint[2]] ]; FOR i: INT IN [0..GGObjects.HiSegment[traj]] DO seg _ GGObjects.FetchSegment[traj, i]; seg.class.buildPath[seg, lineTo, curveTo, conicTo, arcTo]; ENDLOOP; }; Imager.SetColor[dc, fillColor]; Imager.MaskFill[dc, BuildPath]; }; NotYetImplemented: PUBLIC SIGNAL = CODE; DrawOutlineTransformSeq: PROC [dc: Imager.Context, outline: Outline, selSeq: Sequence, transform: ImagerTransformation.Transformation, gargoyleData: GargoyleData] = { <> fence: Traj; fence _ outline.children.first; IF fence.role = fence THEN FillTrajTransformSeq[dc, outline.fillColor, selSeq, transform]; <> FOR trajs: LIST OF Traj _ outline.children, trajs.rest UNTIL trajs = NIL DO IF trajs.first = selSeq.traj THEN DrawTrajTransformSeq[dc, selSeq, transform] ELSE DrawTraj[dc, trajs.first, gargoyleData]; ENDLOOP; }; MaxSegments: NAT = GGModelTypes.MaxSegments; DrawSegArray: TYPE = REF DrawSegArrayObj; DrawSegArrayObj: TYPE = RECORD [ entire: ARRAY [0..MaxSegments-1] OF BOOL, lo: ARRAY [0..MaxSegments-1] OF BOOL, hi: ARRAY [0..MaxSegments-1] OF BOOL ]; arrayPool: ARRAY [0..PoolSize-1] OF DrawSegArray; arrayPoolIndex: NAT; PoolSize: NAT = 3; Init: PROC [] = { FOR i: NAT IN [0..PoolSize) DO arrayPool[i] _ NEW[DrawSegArrayObj]; ENDLOOP; arrayPoolIndex _ 0; }; AllocateDrawSegArray: PROC [] RETURNS [array: DrawSegArray] = { IF arrayPoolIndex = PoolSize THEN ERROR; array _ arrayPool[arrayPoolIndex]; arrayPoolIndex _ arrayPoolIndex + 1; }; ReturnDrawSegArray: PROC [array: DrawSegArray] = { IF arrayPoolIndex = 0 THEN ERROR; arrayPoolIndex _ arrayPoolIndex - 1; arrayPool[arrayPoolIndex] _ array; }; SegAndIndex: TYPE = GGObjects.SegAndIndex; StoreTruthInArrayAboutSequence: PROC [segData: DrawSegArray, selSeq: Sequence] = { <> start, end, prevSegNum, followSegNum: NAT; segGen: SegmentGenerator; IF selSeq.all THEN ERROR; FOR i: NAT IN [0..GGObjects.HiSegment[selSeq.traj]] DO segData.entire[i] _ FALSE; segData.lo[i] _ FALSE; segData.hi[i] _ FALSE; ENDLOOP; FOR partList: LIST OF JointPair _ selSeq.parts, partList.rest UNTIL partList = NIL DO start _ partList.first.start; end _ partList.first.end; IF NOT(selSeq.traj.role = open AND start = 0) THEN { prevSegNum _ GGObjects.PreviousSegmentNum[selSeq.traj, start]; segData.hi[prevSegNum] _ TRUE; }; segGen _ GGObjects.SegmentsInJointPair[selSeq.traj, start, end]; FOR midSeg: SegAndIndex _ GGObjects.NextSegmentAndIndex[segGen], GGObjects.NextSegmentAndIndex[segGen] UNTIL midSeg.seg = NIL DO segData.entire[midSeg.index] _ TRUE; ENDLOOP; IF NOT(selSeq.traj.role = open AND end = GGObjects.HiJoint[selSeq.traj]) THEN { followSegNum _ end; segData.lo[followSegNum] _ TRUE; }; ENDLOOP; }; <> <> <> <> <> <> <> <> <> <> <<};>> <<>> DrawTrajTransformSeq: PROC [dc: Imager.Context, selSeq: Sequence, transform: ImagerTransformation.Transformation] = { <> <<1) Unselected. (entire = FALSE, lo = FALSE, hi = FALSE)>> <<2) One endpoint selected. (entire = FALSE, lo = TRUE, hi = FALSE) or vice-versa.>> <<3) Both endpoints selected. (entire = FALSE, lo = TRUE, hi = TRUE)>> <<4) Selected in entirety. (entire = TRUE, lo = X, hi = X).>> segData: DrawSegArray _ AllocateDrawSegArray[]; seg: Segment; entire, lo, hi: BOOL; StoreTruthInArrayAboutSequence[segData, selSeq]; FOR i: INT IN [0..GGObjects.HiSegment[selSeq.traj]] DO entire _ segData.entire[i]; lo _ segData.lo[i]; hi _ segData.hi[i]; seg _ GGObjects.FetchSegment[selSeq.traj, i]; Imager.SetStrokeWidth[dc, seg.strokeWidth]; seg.class.maskStrokeTransform[dc, seg, transform, entire, lo, hi]; ENDLOOP; ReturnDrawSegArray[segData]; }; FillTrajTransformSeq: PROC [dc: Imager.Context, fillColor: Imager.Color, selSeq: Sequence, transform: ImagerTransformation.Transformation] = { oldColor: Imager.Color _ ImagerBackdoor.GetColor[dc]; segData: DrawSegArray _ AllocateDrawSegArray[]; seg: Segment; BuildPath: Imager.PathProc = { firstPoint: Point; entire, lo, hi: BOOL; lo _ segData.lo[0]; entire _ segData.entire[0]; firstPoint _ GGObjects.FetchJointPos[selSeq.traj, 0]; IF lo OR entire THEN firstPoint _ GGTransform.Transform[transform, firstPoint]; moveTo[ [firstPoint[1], firstPoint[2]] ]; FOR i: INT IN [0..GGObjects.HiSegment[selSeq.traj]] DO entire _ segData.entire[i]; lo _ segData.lo[i]; hi _ segData.hi[i]; seg _ GGObjects.FetchSegment[selSeq.traj, i]; seg.class.buildPathTransform[seg, lineTo, curveTo, conicTo, arcTo, transform, entire, lo, hi]; ENDLOOP; }; StoreTruthInArrayAboutSequence[segData, selSeq]; Imager.SetColor[dc, fillColor]; Imager.MaskFill[dc, BuildPath]; Imager.SetColor[dc, oldColor]; ReturnDrawSegArray[segData]; }; <> MoveJointsToOverlay: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData] = { gargoyleData.refresh.overlayList _ CONS[traj, gargoyleData.refresh.overlayList]; }; RemoveJointsFromOverlay: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData] = { gargoyleData.refresh.overlayList _ GGUtility.DeleteEntityFromList[traj, gargoyleData.refresh.overlayList]; }; MoveToOverlay: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData] = { parentOutline: Outline; WITH entity SELECT FROM outline: Outline => { IF OnOverlay[outline] THEN ERROR; outline.onOverlay _ TRUE; outline.whyOnOverlay _ outline; gargoyleData.refresh.overlayList _ CONS[outline, gargoyleData.refresh.overlayList]; }; traj: Traj => { parentOutline _ GGObjects.OutlineOfTraj[traj]; IF OnOverlay[parentOutline] THEN ERROR; parentOutline.onOverlay _ TRUE; parentOutline.whyOnOverlay _ traj; gargoyleData.refresh.overlayList _ CONS[parentOutline, gargoyleData.refresh.overlayList]; }; seq: Sequence => { parentOutline _ GGObjects.OutlineOfTraj[seq.traj]; IF OnOverlay[parentOutline] THEN ERROR; parentOutline.onOverlay _ TRUE; parentOutline.whyOnOverlay _ seq; gargoyleData.refresh.overlayList _ CONS[parentOutline, gargoyleData.refresh.overlayList]; }; caret: Caret => { IF OnOverlay[caret] THEN ERROR; GGCaret.TellOnOverlay[caret, TRUE]; gargoyleData.refresh.overlayList _ CONS[caret, gargoyleData.refresh.overlayList]; }; ENDCASE => ERROR NotYetImplemented; }; MoveToBackground: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData] = { IF NOT OnOverlay[entity] THEN RETURN; gargoyleData.refresh.overlayList _ GGUtility.DeleteEntityFromList[entity, gargoyleData.refresh.overlayList]; WITH entity SELECT FROM outline: Outline => outline.onOverlay _ FALSE; caret: Caret => GGCaret.TellOnOverlay[caret, FALSE]; ENDCASE => ERROR NotYetImplemented; }; MoveAllSelectedToOverlay: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] = { entityGen: EntityGenerator; entityGen _ GGSelect.SelectedEntities[gargoyleData, selectClass]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO MoveToOverlay[entity, gargoyleData]; ENDLOOP; }; 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 outline: Outline => outline.onOverlay _ FALSE; caret: Caret => GGCaret.TellOnOverlay[caret, FALSE]; traj: Traj => {}; -- can only happen if Gargoyle is confused. Normally, trajectories are only added and removed by MoveJointsToOverlay[] and RemoveJointsFromOverlay[], above. ENDCASE => ERROR NotYetImplemented; ENDLOOP; gargoyleData.refresh.overlayList _ NIL; }; EmptyOverlay: PUBLIC PROC [gargoyleData: GargoyleData] RETURNS [BOOL] = { RETURN[gargoyleData.refresh.overlayList = NIL]; }; OnOverlay: PROC [entity: REF ANY] RETURNS [BOOL] = { WITH entity SELECT FROM outline: Outline => RETURN[outline.onOverlay]; caret: Caret => RETURN[GGCaret.IsOnOverlay[caret]]; ENDCASE => ERROR; }; <> <<>> EraseOverlay: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { <> camera: Camera _ gargoyleData.camera; background: ImagerBackdoor.Bitmap _ gargoyleData.refresh.backgroundBitmap; chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; IF gargoyleData.refresh.suppressRefresh THEN RETURN; ImagerBackdoor.DrawBits[chunkingContext, background.base, background.wordsPerLine, 0, 0, background.height, background.width, 0, background.height]; }; PaintEntireScene: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap; camera: Camera _ gargoyleData.camera; rect: Imager.Rectangle; PaintEntireSceneAux: PROC = { <> rect _ ImagerBackdoor.GetBounds[chunkingContext]; Imager.SetColor[chunkingContext, Imager.white]; Imager.MaskRectangle[chunkingContext, rect]; <> WorldCoordsContext[chunkingContext, camera]; DrawObjects[chunkingContext, gargoyleData]; DrawCaret[chunkingContext, gargoyleData.caret, Imager.black]; DrawAnchor[chunkingContext, gargoyleData.anchor, Imager.black]; }; IF gargoyleData.refresh.suppressRefresh THEN RETURN; IF gargoyleData.refresh.doubleBuffer.state = on THEN { Imager.DoSaveAll[chunkingContext, PaintEntireSceneAux]; <> ImagerBackdoor.DrawBits[dc, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height]; } ELSE { <> rect _ ImagerBackdoor.GetBounds[dc]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, rect]; <> WorldCoordsContext[dc, camera]; DrawObjects[dc, gargoyleData]; DrawCaret[dc, gargoyleData.caret, Imager.black]; DrawAnchor[dc, gargoyleData.anchor, Imager.black]; }; }; PaintSelectedRegion: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap; background: ImagerBackdoor.Bitmap _ gargoyleData.refresh.backgroundBitmap; camera: Camera _ gargoyleData.camera; boundBox: BoundBox; rect: Imager.Rectangle; PaintSelectedRegionAux: PROC = { <> ImagerBackdoor.DrawBits[chunkingContext, background.base, background.wordsPerLine, 0, 0, background.height, background.width, 0, background.height]; <> WorldCoordsContext[chunkingContext, camera]; GGBoundBox.Clip[chunkingContext, boundBox]; <> rect _ ImagerBackdoor.GetBounds[chunkingContext]; Imager.SetColor[chunkingContext, Imager.white]; Imager.MaskRectangle[chunkingContext, rect]; <> DrawObjects[chunkingContext, gargoyleData]; DrawCaret[chunkingContext, gargoyleData.caret, Imager.black]; DrawAnchor[chunkingContext, gargoyleData.anchor, Imager.black]; }; IF gargoyleData.refresh.suppressRefresh THEN RETURN; boundBox _ GGBoundBox.BoundBoxOfSelected[gargoyleData]; IF gargoyleData.refresh.doubleBuffer.state = on THEN { Imager.DoSaveAll[chunkingContext, PaintSelectedRegionAux]; <> ImagerBackdoor.DrawBits[dc, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height]; } ELSE { ImagerBackdoor.DrawBits[dc, background.base, background.wordsPerLine, 0, 0, background.height, background.width, 0, background.height]; <> WorldCoordsContext[dc, camera]; GGBoundBox.Clip[dc, boundBox]; <> rect _ ImagerBackdoor.GetBounds[dc]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, rect]; <> DrawObjects[dc, gargoyleData]; DrawCaret[dc, gargoyleData.caret, Imager.black]; DrawAnchor[dc, gargoyleData.anchor, Imager.black]; }; }; InterpressEntireScene: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; WorldCoordsContext[dc, camera]; DrawObjects[dc, gargoyleData]; }; StoreBackground: PUBLIC PROC [gargoyleData: GargoyleData] = { <> PaintAllButSelected: PROC = { camera: Camera _ gargoyleData.camera; scene: Scene _ gargoyleData.scene; rect: Imager.Rectangle; <> rect _ ImagerBackdoor.GetBounds[gargoyleData.refresh.backgroundContext]; Imager.SetColor[gargoyleData.refresh.backgroundContext, Imager.white]; Imager.MaskRectangle[gargoyleData.refresh.backgroundContext, rect]; <> Imager.SetColor[gargoyleData.refresh.backgroundContext, Imager.black]; Imager.TranslateT[gargoyleData.refresh.backgroundContext, [camera.cameraScreen[1], camera.cameraScreen[2]]]; <> FOR entities: LIST OF REF ANY _ gargoyleData.scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM outline: Outline => { IF OnOverlay[outline] THEN LOOP ELSE DrawOutline[gargoyleData.refresh.backgroundContext, outline, gargoyleData]; }; cluster: Cluster => StoreCluster[gargoyleData.refresh.backgroundContext, cluster, gargoyleData]; ENDCASE => ERROR; ENDLOOP; <> IF NOT OnOverlay[gargoyleData.caret] THEN DrawCaret[gargoyleData.refresh.backgroundContext, gargoyleData.caret, Imager.black]; DrawAnchor[gargoyleData.refresh.backgroundContext, gargoyleData.anchor, Imager.black]; <> IF gargoyleData.hitTest.linesAlwaysOn.state = on THEN GGGravity.DrawObjectBagRegardless[gargoyleData.refresh.backgroundContext, NARROW[gargoyleData.hitTest.environ], camera, gargoyleData]; }; IF gargoyleData.refresh.suppressRefresh THEN RETURN; Imager.DoSaveAll[gargoyleData.refresh.backgroundContext, PaintAllButSelected]; }; StoreCluster: PRIVATE PROC [backgroundContext: Imager.Context, cluster: Cluster, gargoyleData: GargoyleData] = { FOR children: LIST OF REF ANY _ cluster.children, children.rest UNTIL children = NIL DO WITH children.first SELECT FROM outline: Outline => { IF OnOverlay[outline] THEN LOOP ELSE DrawOutline[backgroundContext, outline, gargoyleData]; }; cluster: Cluster => StoreCluster[backgroundContext, cluster, gargoyleData]; ENDCASE => ERROR; ENDLOOP; }; <<>> <> <> <> <> <> <> <> <> <<};>> <> <> <> <<};>> <<>> PaintDragOverlay: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { <> chunkingBitmap: ImagerBackdoor.Bitmap _ gargoyleData.refresh.chunkingBitmap; camera: Camera _ gargoyleData.camera; chunkingContext: Imager.Context _ gargoyleData.refresh.chunkingContext; PaintDragEntitiesAux: PROC = { WorldCoordsContext[chunkingContext, camera]; DrawDragOverlay[chunkingContext, gargoyleData]; }; IF gargoyleData.refresh.suppressRefresh THEN RETURN; Imager.DoSaveAll[chunkingContext, PaintDragEntitiesAux]; <> ImagerBackdoor.DrawBits[dc, chunkingBitmap.base, chunkingBitmap.wordsPerLine, 0, 0, chunkingBitmap.height, chunkingBitmap.width, 0, chunkingBitmap.height]; }; <> <> <> <> < {};>> < DrawJoints[dc, traj];>> < DrawOutline[dc, outline];>> < DrawCluster[dc, cluster];>> < DrawCaret[dc, caret, Imager.black];>> < ERROR;>> <> <> <> <> <<};>> <<>> DrawDragOverlay: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { <> outline: Outline; <> IF gargoyleData.hitTest.linesAlwaysOn.state = off THEN GGGravity.DrawObjectBag[dc, NARROW[gargoyleData.hitTest.environ], gargoyleData.camera, gargoyleData]; <> FOR overlayList: LIST OF REF ANY _ gargoyleData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO WITH overlayList.first SELECT FROM outline: Outline => { WITH outline.whyOnOverlay SELECT FROM seq: Sequence => { <> IF seq.all THEN LOOP; DrawOutlineTransformSeq[dc, outline, seq, gargoyleData.drag.transform, gargoyleData]; }; ENDCASE => {}; }; traj: Traj => DrawJoints[dc, traj, gargoyleData]; caret: Caret => { caret _ NARROW[overlayList.first]; DrawCaret[dc, caret, Imager.black]; }; ENDCASE => ERROR; ENDLOOP; <> Imager.ConcatT[dc, gargoyleData.drag.transform]; FOR overlayList: LIST OF REF ANY _ gargoyleData.refresh.overlayList, overlayList.rest UNTIL overlayList = NIL DO IF ISTYPE[overlayList.first, Outline] THEN { outline _ NARROW[overlayList.first]; WITH outline.whyOnOverlay SELECT FROM seq: Sequence => { IF seq.all THEN DrawOutline[dc, outline, gargoyleData]; }; traj: Traj => ERROR; outline: Outline => DrawOutline[dc, outline, gargoyleData]; cluster: Cluster => DrawCluster[dc, cluster, gargoyleData]; ENDCASE => ERROR; }; ENDLOOP; }; DrawObjects: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { <> scene: Scene _ gargoyleData.scene; Imager.SetColor[dc, Imager.black]; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM outline: Outline => DrawOutline[dc, outline, gargoyleData]; cluster: Cluster => ERROR; ENDCASE => ERROR; ENDLOOP; }; <<>> 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]; }; <<>> <> PaintNewAnchor: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; anchorPos: Point _ GGCaret.GetPoint[gargoyleData.anchor]; Imager.SetColor[dc, Imager.black]; WorldCoordsContext[dc, camera]; GGShapes.DrawAnchor[dc, anchorPos]; }; PaintSpot: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; Imager.SetColor[dc, Imager.black]; WorldCoordsContext[dc, camera]; GGShapes.DrawSpot[dc, gargoyleData.refresh.spotPoint]; }; PaintHitLine: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; Imager.SetColor[dc, Imager.black]; WorldCoordsContext[dc, camera]; Imager.MaskVector[dc, [gargoyleData.refresh.spotPoint[1], gargoyleData.refresh.spotPoint[2]], [gargoyleData.refresh.hitPoint[1], gargoyleData.refresh.hitPoint[2]]]; GGShapes.DrawFilledRect[dc, gargoyleData.refresh.spotPoint, 3.0]; }; PaintAlign: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; Imager.SetColor[dc, ImagerColor.ColorFromGray[0.5]]; WorldCoordsContext[dc, camera]; GGGravity.DrawObjectBagRegardless[dc, NARROW[gargoyleData.hitTest.environ], camera, gargoyleData]; }; PaintTouchPoints: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { WorldCoordsContext[dc, gargoyleData.camera]; GGTouch.DrawAllTouchPoints[dc, gargoyleData]; }; PaintBoundBoxes: PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { bBoxGen: BoundBoxGenerator; camera: Camera _ gargoyleData.camera; PaintBoundBoxesAux: PROC = { <> WorldCoordsContext[dc, camera]; bBoxGen _ GGObjects.BoundBoxesInScene[gargoyleData.scene]; FOR box: BoundBox _ GGObjects.NextBox[bBoxGen], GGObjects.NextBox[bBoxGen] UNTIL box = NIL DO GGBoundBox.DrawBoundBox[dc, box]; ENDLOOP; }; Imager.DoSaveAll[dc, PaintBoundBoxesAux]; }; PaintSelectionBox: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { camera: Camera _ gargoyleData.camera; box: BoundBox; PaintSelectionBoxAux: PROC = { <> WorldCoordsContext[dc, camera]; box _ GGBoundBox.BoundBoxOfSelected[gargoyleData]; GGBoundBox.DrawBoundBox[dc, box]; }; Imager.DoSaveAll[dc, PaintSelectionBoxAux]; }; <<>> EraseAll: PROC [dc: Imager.Context] = { rect: Imager.Rectangle; rect _ ImagerBackdoor.GetBounds[dc]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, rect]; }; Init[]; END.