<> <> <> <> <> <<>> DIRECTORY Atom, Basics, GGAlign, GGBasicTypes, GGBoundBox, GGButtons, GGSlice, GGCaret, GGDescribe, GGMouseEvent, GGEvent, GGError, GGGravity, GGInterfaceTypes, GGModelTypes, GGObjects, GGOutline, GGRefresh, GGSegment, GGSegmentTypes, GGSelect, GGSequence, GGStatistics, GGTouch, GGTraj, GGTransform, GGVector, GGWindow, GList, Imager, ImagerTransformation, InputFocus, Menus, RealFns, Rope; GGMouseEventImplA: CEDAR PROGRAM IMPORTS Atom, Basics, GGAlign, GGBoundBox, GGButtons, GGSlice, GGCaret, GGDescribe, GGError, GGEvent, GGGravity, GGMouseEvent, GGObjects, GGOutline, GGRefresh, GGSegment, GGSelect, GGSequence, GGStatistics, GGTouch, GGTraj, GGTransform, GGVector, GGWindow, GList, Imager, ImagerTransformation, InputFocus, RealFns, Rope EXPORTS GGMouseEvent = BEGIN AlignmentPoint: TYPE = GGInterfaceTypes.AlignmentPoint; BoundBox: TYPE = GGModelTypes.BoundBox; Caret: TYPE = GGInterfaceTypes.Caret; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; FeatureData: TYPE = GGModelTypes.FeatureData; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Joint: TYPE = GGModelTypes.Joint; MouseButton: TYPE = Menus.MouseButton; ObjectBag: TYPE = GGGravity.ObjectBag; Outline: TYPE = GGModelTypes.Outline; OutlineDescriptor: TYPE = REF OutlineDescriptorObj; OutlineDescriptorObj: TYPE = GGModelTypes.OutlineDescriptorObj; Point: TYPE = GGBasicTypes.Point; ResultFeatureType: TYPE = GGModelTypes.ResultFeatureType; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; Sequence: TYPE = GGModelTypes.Sequence; Slice: TYPE = GGModelTypes.Slice; SliceParts: TYPE = GGModelTypes.SliceParts; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorObj: TYPE = GGModelTypes.SliceDescriptorObj; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; TouchGroup: TYPE = GGSegmentTypes.TouchGroup; TouchItem: TYPE = GGSegmentTypes.TouchItem; TouchItemGenerator: TYPE = GGTouch.TouchItemGenerator; Traj: TYPE = GGModelTypes.Traj; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajGenerator: TYPE = GGObjects.TrajGenerator; TrajPartType: TYPE = GGModelTypes.TrajPartType; TriggerBag: TYPE = GGAlign.TriggerBag; Vector: TYPE = GGBasicTypes.Vector; MouseProc: TYPE = GGMouseEvent.MouseProc; <> StartProc: TYPE = GGMouseEvent.StartProc; <> NotYetImplemented: PUBLIC SIGNAL = CODE; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = GGError.Problem; EasyAbort: PROC [input: LIST OF REF ANY, gargoyleData: GargoyleData, worldPt: Point] = { <> scene: Scene _ gargoyleData.scene; GGObjects.RestoreSelections[scene]; GGCaret.Copy[from: gargoyleData.drag.savedCaret, to: gargoyleData.caret]; --restore original caret FinishAbort[gargoyleData]; }; AbortAdd: PROC [input: LIST OF REF ANY, gargoyleData: GargoyleData, worldPt: Point] = { GGEvent.DeleteCaretSegment[NIL, gargoyleData]; FinishAbort[gargoyleData]; }; AbortBox: PROC [input: LIST OF REF ANY, gargoyleData: GargoyleData, worldPt: Point] = { FixupAbortedBox[gargoyleData]; FinishAbort[gargoyleData]; }; FinishAbort: PROC [gargoyleData: GargoyleData] = { GGRefresh.MoveOverlayToBackground[gargoyleData]; GGError.AppendHerald[gargoyleData.feedback, ". . . Aborted.", end]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: FALSE]; }; ResetMouseMachinery: PUBLIC PROC [gargoyleData: GargoyleData] = { gargoyleData.mouseMode _ $None; gargoyleData.state _ $None; GGRefresh.MoveOverlayToBackground[gargoyleData]; }; SaveSavedState: PROC [gargoyleData: GargoyleData] = { GGObjects.SaveSelections[gargoyleData.scene]; GGWindow.SaveCaretPos[gargoyleData]; GGCaret.Copy[from: gargoyleData.caret, to: gargoyleData.drag.savedCaret]; }; <<>> <> HandleMouseless: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> HandleMouse[event, [0.0, 0.0], clientData]; }; HandleMouse: PUBLIC PROC [event: LIST OF REF ANY, point: Point, clientData: REF ANY] = { atom: ATOM; gargoyleData: GargoyleData _ NARROW[clientData]; SELECT gargoyleData.mouseMode FROM $CaretPos => HandleGuarded[StartCaretPos, DuringCaretPos, EndCaretPos, EasyAbort, NIL, event, gargoyleData, point]; $Add => HandleGuarded[StartAdd, DuringAdd, EndAdd, AbortAdd, ContinueAdd, event, gargoyleData, point]; $Box => HandleGuarded[StartBox, DuringAdd, EndBox, AbortBox, NIL, event, gargoyleData, point]; <<$Circle => HandleGuarded[StartCircle, DuringAdd, EndCircle, AbortCircle, NIL, event, gargoyleData, point];>> $Drag => HandleGuarded[StartDrag, DuringDrag, EndMotion, EasyAbort, NIL, event, gargoyleData, point]; $CopyAndDrag => HandleGuarded[CopySelected, DuringDrag, EndMotion, EasyAbort, NIL, event, gargoyleData, point]; $Rotate => HandleGuarded[StartRotate, DuringRotate, EndMotion, EasyAbort, NIL, event, gargoyleData, point]; $Scale => HandleGuarded[StartScale, DuringScale, EndMotion, EasyAbort, NIL, event, gargoyleData, point]; $SixPoint => HandleGuarded[StartSixPoint, DuringSixPoint, EndMotion, EasyAbort, NIL, event, gargoyleData, point]; $SelectWithBox => HandleUnGuarded[StartBox, DuringAdd, EndSelectWithBox, AbortBox, event, gargoyleData, point]; $SelectJoint => HandleUnGuarded[StartSelectJoint, DuringSelect, EndSelect, EasyAbort, event, gargoyleData, point]; $ExtSelectJoint => HandleGuarded[GGMouseEvent.StartExtendSelectJoint, GGMouseEvent.DuringExtendSelection, GGMouseEvent.EndExtendSelection, EasyAbort, NIL, event, gargoyleData, point]; $SelectSegment => HandleUnGuarded[StartSelectSegment, DuringSelect, EndSelect, EasyAbort, event, gargoyleData, point]; $ExtSelectSegment => HandleGuarded[GGMouseEvent.StartExtendSelectSegment, GGMouseEvent.DuringExtendSelection, GGMouseEvent.EndExtendSelection, EasyAbort, NIL, event, gargoyleData, point]; $SelectTrajectory => HandleUnGuarded[StartSelectTrajectory, DuringSelect, EndSelect, EasyAbort, event, gargoyleData, point]; $ExtSelectTrajectory => HandleGuarded[GGMouseEvent.StartExtendSelectTraj, GGMouseEvent.DuringExtendSelection, GGMouseEvent.EndExtendSelection, EasyAbort, NIL, event, gargoyleData, point]; $SelectTopLevel => HandleUnGuarded[StartSelectTopLevel, DuringSelect, EndSelect, EasyAbort, event, gargoyleData, point]; $ExtSelectTopLevel => HandleGuarded[GGMouseEvent.StartExtendSelectTopLevel, GGMouseEvent.DuringExtendSelection, GGMouseEvent.EndExtendSelection, EasyAbort, NIL, event, gargoyleData, point]; $Extend => HandleUnGuarded[GGMouseEvent.StartExtendSelection, GGMouseEvent.DuringExtendSelection, GGMouseEvent.EndExtendSelection, EasyAbort, event, gargoyleData, point]; $DeselectJoint => HandleGuarded[GGMouseEvent.StartDeselectJoint, GGMouseEvent.DuringDeselect, GGMouseEvent.EndDeselect, EasyAbort, NIL, event, gargoyleData, point]; $DeselectSegment => HandleGuarded[GGMouseEvent.StartDeselectSegment, GGMouseEvent.DuringDeselect, GGMouseEvent.EndDeselect, EasyAbort, NIL, event, gargoyleData, point]; $DeselectTrajectory => HandleGuarded[GGMouseEvent.StartDeselectTrajectory, GGMouseEvent.DuringDeselect, GGMouseEvent.EndDeselect, EasyAbort, NIL, event, gargoyleData, point]; $DeselectTopLevel => HandleGuarded[GGMouseEvent.StartDeselectTopLevel, GGMouseEvent.DuringDeselect, GGMouseEvent.EndDeselect, EasyAbort, NIL, event, gargoyleData, point]; $None => { atom _ NARROW[event.first]; SELECT atom FROM $StartCaretPos => { gargoyleData.mouseMode _ $CaretPos; HandleMouse[event, point, gargoyleData]; }; $StartAdd => { gargoyleData.mouseMode _ $Add; HandleMouse[event, point, gargoyleData]; }; $StartBox => { gargoyleData.mouseMode _ $Box; HandleMouse[event, point, gargoyleData]; }; $StartSelectWithBox => { gargoyleData.mouseMode _ $SelectWithBox; HandleMouse[event, point, gargoyleData]; }; $StartDrag => { gargoyleData.mouseMode _ $Drag; HandleMouse[event, point, gargoyleData]; }; $StartCopyAndDrag => { gargoyleData.mouseMode _ $CopyAndDrag; HandleMouse[event, point, gargoyleData]; }; $StartRotate => { gargoyleData.mouseMode _ $Rotate; HandleMouse[event, point, gargoyleData]; }; $StartScale => { gargoyleData.mouseMode _ $Scale; HandleMouse[event, point, gargoyleData]; }; $StartSixPoint => { gargoyleData.mouseMode _ $SixPoint; HandleMouse[event, point, gargoyleData]; }; $StartSelectJoint => { gargoyleData.mouseMode _ $SelectJoint; HandleMouse[event, point, gargoyleData]; }; $StartExtSelectJoint => { gargoyleData.mouseMode _ $ExtSelectJoint; HandleMouse[event, point, gargoyleData]; }; $StartSelectSegment => { gargoyleData.mouseMode _ $SelectSegment; HandleMouse[event, point, gargoyleData]; }; $StartExtSelectSegment => { gargoyleData.mouseMode _ $ExtSelectSegment; HandleMouse[event, point, gargoyleData]; }; $StartSelectTrajectory => { gargoyleData.mouseMode _ $SelectTrajectory; HandleMouse[event, point, gargoyleData]; }; $StartExtSelectTrajectory => { gargoyleData.mouseMode _ $ExtSelectTrajectory; HandleMouse[event, point, gargoyleData]; }; $StartSelectTopLevel => { gargoyleData.mouseMode _ $SelectTopLevel; HandleMouse[event, point, gargoyleData]; }; $StartExtSelectTopLevel => { gargoyleData.mouseMode _ $ExtSelectTopLevel; HandleMouse[event, point, gargoyleData]; }; $StartExtendSelection => { gargoyleData.mouseMode _ $Extend; HandleMouse[event, point, gargoyleData]; }; $StartDeselectJoint => { gargoyleData.mouseMode _ $DeselectJoint; HandleMouse[event, point, gargoyleData]; }; $StartDeselectSegment => { gargoyleData.mouseMode _ $DeselectSegment; HandleMouse[event, point, gargoyleData]; }; $StartDeselectTrajectory => { gargoyleData.mouseMode _ $DeselectTrajectory; HandleMouse[event, point, gargoyleData]; }; $StartDeselectTopLevel => { gargoyleData.mouseMode _ $DeselectTopLevel; HandleMouse[event, point, gargoyleData]; }; ENDCASE; -- ignore other actions }; ENDCASE => SIGNAL Problem[msg: "Unimplemented Mode"]; }; <<>> HandleGuarded: PROC [startProc: StartProc, duringProc, endProc, abortProc: MouseProc, continueProc: StartProc, input: LIST OF REF ANY, gargoyleData: GargoyleData, worldPt: Point] = { genericAction, atom: ATOM; atomName: Rope.ROPE; GGStatistics.StartInterval[$HandleGuarded, GGStatistics.GlobalTable[]]; WITH input.first SELECT FROM refChar: REF CHAR => RETURN; -- ignore characters during mouse actions ENDCASE; atom _ NARROW[input.first]; atomName _ Atom.GetPName[atom]; genericAction _ IF Rope.Equal[Rope.Substr[atomName, 0, 5], "Start", TRUE] THEN $Start ELSE atom; HandleGuardedAux[startProc, duringProc, endProc, abortProc, continueProc, genericAction, input, gargoyleData, worldPt]; GGStatistics.StopInterval[$HandleGuarded, GGStatistics.GlobalTable[]]; }; Restart: PROC [input: LIST OF REF ANY, gargoyleData: GargoyleData] RETURNS [BOOL] = { mouseMode: ATOM _ gargoyleData.mouseMode; state: ATOM _ NARROW[input.first]; RETURN[ (mouseMode = $CaretPos AND state = $StartCaretPos) OR (mouseMode = $Add AND state = $StartAdd) OR (mouseMode = $Box AND state = $StartBox) OR <<(mouseMode = $Circle AND state = $StartCircle) OR>> (mouseMode = $Drag AND state = $StartDrag) OR (mouseMode = $CopyAndDrag AND state = $StartCopyAndDrag) OR (mouseMode = $Rotate AND state = $StartRotate) OR (mouseMode = $Scale AND state = $StartScale) OR (mouseMode = $SelectJoint AND state = $StartSelectJoint) OR (mouseMode = $SelectSegment AND state = $StartSelectSegment) OR (mouseMode = $SelectTrajectory AND state = $StartSelectTrajectory) OR (mouseMode = $SelectTopLevel AND state = $StartSelectTopLevel) OR (mouseMode = $ExtendSelection AND state = $StartExtendSelection) OR (mouseMode = $DeselectJoint AND state = $StartDeselectJoint) OR (mouseMode = $DeselectSegment AND state = $StartDeselectSegment) OR (mouseMode = $DeselectTrajectory AND state = $StartDeselectTrajectory) OR (mouseMode = $DeselectTopLevel AND state = $StartDeselectTopLevel)]; }; HandleGuardedAux: PROC [startProc: StartProc, duringProc, endProc, abortProc: MouseProc, continueProc: StartProc, genericAction: ATOM, input: LIST OF REF ANY, gargoyleData: GargoyleData, worldPt: Point] = { SELECT gargoyleData.state FROM $None => { SELECT genericAction FROM $Start => { gargoyleData.drag.currentPoint _ worldPt; [] _ InputFocus.SetInputFocus[gargoyleData.actionArea]; IF startProc[input, gargoyleData, worldPt] THEN gargoyleData.state _ $Main ELSE {abortProc[input, gargoyleData, worldPt]; gargoyleData.state _ $Aborted;}; }; ENDCASE; }; $Main => { SELECT genericAction FROM $During => { duringProc[input, gargoyleData, worldPt]; gargoyleData.drag.currentPoint _ worldPt; }; $Abort => {abortProc[input, gargoyleData, worldPt]; gargoyleData.state _ $Aborted}; $GuardUp => gargoyleData.state _ $GuardUp; $MouseUp => gargoyleData.state _ $MouseUp; $Start => { -- the mouse must have gone out of the window while the mouse button was done. Abort the current action and start a new one. abortProc[input, gargoyleData, worldPt]; gargoyleData.state _ $None; gargoyleData.mouseMode _ $None; HandleMouse[input, worldPt, gargoyleData]; }; ENDCASE; }; $GuardUp => { SELECT genericAction FROM $AllUp => { endProc[input, gargoyleData, gargoyleData.drag.currentPoint]; gargoyleData.mouseMode _ $None; gargoyleData.state _ $None; }; $Abort => {abortProc[input, gargoyleData, worldPt]; gargoyleData.state _ $Aborted}; ENDCASE; }; $MouseUp => { SELECT genericAction FROM $AllUp => { endProc[input, gargoyleData, gargoyleData.drag.currentPoint]; gargoyleData.mouseMode _ $None; gargoyleData.state _ $None; }; $Abort => {abortProc[input, gargoyleData, worldPt]; gargoyleData.state _ $Aborted}; $Start => { -- we may be starting another action of this mode or some other mode. IF Restart[input, gargoyleData] AND continueProc # NIL THEN { IF continueProc[input, gargoyleData, worldPt] THEN { gargoyleData.state _ $Main; gargoyleData.drag.currentPoint _ worldPt; } ELSE {abortProc[input, gargoyleData, worldPt]; gargoyleData.state _ $Aborted;}; } ELSE { gargoyleData.mouseMode _ $None; endProc[input, gargoyleData, gargoyleData.drag.currentPoint]; gargoyleData.state _ $None; HandleMouse[input, worldPt, gargoyleData]; }; }; ENDCASE; }; $Aborted => { SELECT genericAction FROM $AllUp => {gargoyleData.state _ $None; gargoyleData.mouseMode _ $None}; ENDCASE; }; ENDCASE => SIGNAL Problem[msg: "Unknown generic state"]; }; HandleUnGuarded: PROC [startProc: StartProc, duringProc, endProc, abortProc: MouseProc, input: LIST OF REF ANY, gargoyleData: GargoyleData, worldPt: Point] = { genericAction, atom: ATOM; atomName: Rope.ROPE; WITH input.first SELECT FROM refChar: REF CHAR => RETURN; -- ignore characters during mouse actions ENDCASE; atom _ NARROW[input.first]; atomName _ Atom.GetPName[atom]; genericAction _ IF Rope.Equal[Rope.Substr[atomName, 0, 5], "Start", TRUE] THEN $Start ELSE atom; <> parts: SliceParts _ SelectTrajInternal[feature, resultPoint, gargoyleData]; gargoyleData.drag.extendMode _ traj; SELECT feature.type FROM outline => { jointParts: SliceParts; jointSeq: Sequence; jointD: OutlineDescriptor; traj: Traj; jointNum: NAT; outlineD: OutlineDescriptor _ NEW[OutlineDescriptorObj _ [slice: NARROW[feature.shape, OutlineDescriptor].slice, parts: parts]]; IF outlineD.slice.class.type = $Outline THEN { [jointNum, traj] _ GGOutline.NearestJointToHitData[feature.hitPart]; jointSeq _ GGSequence.CreateFromJoint[traj, jointNum]; jointParts _ GGOutline.PartsFromSequence[outlineD.slice, jointSeq]; jointD _ NEW[OutlineDescriptorObj _ [outlineD.slice, jointParts]]; GGCaret.SitOn[gargoyleData.caret, jointD]; } ELSE GGCaret.SitOn[gargoyleData.caret, NIL]; GGError.AppendHerald[gargoyleData.feedback, Rope.Concat[outlineD.slice.class.describe[outlineD.slice, outlineD.parts], " selected"], oneLiner]; gargoyleData.drag.outlineToExtend _ outlineD; }; slice => { sliceD: SliceDescriptor _ NEW[SliceDescriptorObj _ [slice: NARROW[feature.shape, SliceDescriptor].slice, parts: parts] ]; IF sliceD.slice.class.type = $Outline THEN { ERROR Problem[msg: "Outlines must be Slices now."]; <<[jointNum, traj] _ GGOutline.NearestJointToHitData[feature.hitPart];>> <> <> <> <> } ELSE GGCaret.SitOn[gargoyleData.caret, NIL]; GGError.AppendHerald[gargoyleData.feedback, Rope.Concat[sliceD.slice.class.describe[sliceD.slice, sliceD.parts], " selected"], oneLiner]; gargoyleData.drag.sliceToExtend _ sliceD; }; ENDCASE => SIGNAL Problem[msg: "Unexpected feature type"]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end SelectTrajectory EndSelectTopLevel: PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = { IF feature = NIL THEN { -- no selection GGCaret.SitOn[gargoyleData.caret, NIL]; GGError.AppendHerald[gargoyleData.feedback, "No near object found.", oneLiner]; } ELSE { <> parts: SliceParts _ SelectTopLevelInternal[feature, resultPoint, gargoyleData]; gargoyleData.drag.extendMode _ topLevel; SELECT feature.resultType FROM outline => { jointParts: SliceParts; jointSeq: Sequence; jointD: OutlineDescriptor; traj: Traj; jointNum: NAT; outlineD: OutlineDescriptor _ NEW[OutlineDescriptorObj _ [slice: NARROW[feature.shape, OutlineDescriptor].slice, parts: parts]]; IF outlineD.slice.class.type = $Outline THEN { [jointNum, traj] _ GGOutline.NearestJointToHitData[feature.hitPart]; jointSeq _ GGSequence.CreateFromJoint[traj, jointNum]; jointParts _ GGOutline.PartsFromSequence[outlineD.slice, jointSeq]; jointD _ NEW[OutlineDescriptorObj _ [outlineD.slice, jointParts]]; GGCaret.SitOn[gargoyleData.caret, jointD]; } ELSE GGCaret.SitOn[gargoyleData.caret, NIL]; GGError.AppendHerald[gargoyleData.feedback, "Top level outline selected.", oneLiner]; gargoyleData.drag.outlineToExtend _ outlineD; }; slice => { sliceD: SliceDescriptor _ NEW[SliceDescriptorObj _ [slice: NARROW[feature.shape, SliceDescriptor].slice, parts: parts]]; IF sliceD.slice.class.type = $Outline THEN { ERROR Problem[msg: "Outlines must be Slices now."]; <<[jointNum, traj] _ GGOutline.NearestJointToHitData[feature.hitPart];>> <> <> <> <> } ELSE GGCaret.SitOn[gargoyleData.caret, NIL]; GGError.AppendHerald[gargoyleData.feedback, Rope.Concat[sliceD.slice.class.describe[sliceD.slice, sliceD.parts], " selected"], oneLiner]; gargoyleData.drag.sliceToExtend _ sliceD; }; ENDCASE => ERROR; -- nothing else should be in the object bag }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end SelectTopLevel TransformObjectsAfterMove: PROC [gargoyleData: GargoyleData] = { entityGen: EntityGenerator; GGTouch.InitializeTouching[gargoyleData]; entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM outlineD: OutlineDescriptor => { outlineD.slice.class.transform[outlineD.slice, outlineD.parts, gargoyleData.drag.transform]; }; sliceD: SliceDescriptor => { sliceD.slice.class.transform[sliceD.slice, sliceD.parts, gargoyleData.drag.transform]; }; ENDCASE => ERROR NotYetImplemented; ENDLOOP; }; <> StartCaretPos: PUBLIC StartProc = { <> GGStatistics.StartInterval[$StartCaretPos, GGStatistics.GlobalTable[]]; StartSelectAux[gargoyleData, worldPt]; DuringCaretPos[NIL, gargoyleData, worldPt]; GGStatistics.StopInterval[$StartCaretPos, GGStatistics.GlobalTable[]]; }; DuringCaretPos: PUBLIC MouseProc = { <> resultPoint: Point; feature: FeatureData; GGStatistics.StartInterval[$DuringCaretPos, GGStatistics.GlobalTable[]]; [resultPoint, feature] _ GGGravity.Map[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.currentObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, TRUE]; SetCaretAttractor[gargoyleData, resultPoint, feature]; -- move caret to feature point GGWindow.RestoreScreenAndInvariants[paintAction: $DuringCaretPos, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; -- show caret in new position GGStatistics.StopInterval[$DuringCaretPos, GGStatistics.GlobalTable[]]; }; -- end of DuringCaretPos EndCaretPos: PUBLIC MouseProc = { resultPoint: Point; feature: FeatureData; currentObjects: ObjectBag _ NARROW[gargoyleData.hitTest.currentObjectBag]; sceneObjects: TriggerBag _ NARROW[gargoyleData.hitTest.sceneTriggerBag]; GGStatistics.StartInterval[$EndCaretPos, GGStatistics.GlobalTable[]]; [resultPoint, feature] _ GGGravity.Map[worldPt, gargoyleData.hitTest.criticalR, currentObjects, sceneObjects, gargoyleData, TRUE]; <> SetCaretAttractor[gargoyleData, resultPoint, feature, "Final"]; -- move caret to feature point GGWindow.NewCaretPos[gargoyleData]; GGCaret.SitOn[gargoyleData.caret, NIL]; -- subsequent Add operations will start a NEW trajectory. GGWindow.RestoreScreenAndInvariants[paintAction: $CaretMoved, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; GGStatistics.StopInterval[$EndCaretPos, GGStatistics.GlobalTable[]]; }; -- end EndCaretPos SitOnFeature: PROC [caret: Caret, feature: FeatureData] = { IF feature = NIL THEN GGCaret.SitOn[caret, NIL] ELSE { -- feature.shape type is OutlineD or SliceD WITH feature.shape SELECT FROM outlineD: OutlineDescriptor => GGCaret.SitOn[caret, outlineD]; sliceD: SliceDescriptor => GGCaret.SitOn[caret, sliceD]; ENDCASE => GGCaret.SitOn[caret, NIL]; }; }; SetCaretAttractor: PROC [gargoyleData: GargoyleData, mapPoint: Point, feature: FeatureData, action: Rope.ROPE _ ""] = { <> IF feature = NIL THEN GGCaret.SetAttractor[gargoyleData.caret, mapPoint, NIL] ELSE { SELECT feature.resultType FROM outline => { traj: Traj; hitType: GGModelTypes.TrajPartType; segNum, cpNum, jointNum: INT; seq: Sequence; parts: SliceParts; partsD: OutlineDescriptor; outlineD: OutlineDescriptor _ NARROW[feature.shape]; [traj, hitType, segNum, cpNum, jointNum] _ GGOutline.UnpackHitData[feature.hitPart]; SELECT hitType FROM joint => { seq _ GGSequence.CreateFromJoint[traj, jointNum]; }; controlPoint => { seq _ GGSequence.CreateFromControlPoint[traj, segNum, cpNum]; }; segment => { seq _ GGSequence.CreateSimpleFromSegment[traj, segNum]; }; ENDCASE => ERROR; parts _ GGOutline.PartsFromSequence[outlineD.slice, seq]; partsD _ NEW[OutlineDescriptorObj _ [outlineD.slice, parts]]; GGCaret.SetAttractor[gargoyleData.caret, mapPoint, partsD]; }; slice => { GGCaret.SetAttractor[gargoyleData.caret, mapPoint, feature.shape]; }; ENDCASE => GGCaret.SetAttractor[gargoyleData.caret, mapPoint, NIL]; }; GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g Caret on %g at [%g, %g]", [rope[action]], [rope[GGDescribe.DescribeFeature[feature, gargoyleData]]], [real[mapPoint.x]], [real[mapPoint.y]] ]; }; <<>> <> <<>> StartMotionAux: PROC [gargoyleData: GargoyleData, opName: Rope.ROPE, bagType: ATOM, worldPt: Point, needAnchor: BOOL _ FALSE] RETURNS [BOOL] = { restoreBox: BoundBox; repaintNeeded: BOOL; IF NOT GGRefresh.EmptyOverlay[gargoyleData] THEN ERROR; -- nothing on overlay SaveSavedState[gargoyleData]; -- must do this before any possible aborts occur IF GGSelect.NoSelections[gargoyleData.scene, normal] THEN { GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Select some objects to %g", [rope[opName]]]; GGError.Blink[gargoyleData.feedback]; RETURN[FALSE]; }; IF needAnchor AND NOT GGCaret.Exists[gargoyleData.anchor] THEN { GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Anchor needed to %g", [rope[opName]]]; GGError.Blink[gargoyleData.feedback]; RETURN[FALSE]; }; GGRefresh.MoveAllSelectedToOverlay[gargoyleData, normal]; gargoyleData.drag.startPoint _ GGCaret.GetPoint[gargoyleData.caret]; GGCaret.SetAttractor[gargoyleData.caret, gargoyleData.drag.startPoint, NIL]; -- move caret to start point gargoyleData.drag.transform _ ImagerTransformation.Scale[1.0]; restoreBox _ GGBoundBox.BoundBoxOfMoving[gargoyleData.scene]; gargoyleData.refresh.startBoundBox^ _ restoreBox^; GGRefresh.SplitBackgroundAndOverlay[gargoyleData, restoreBox]; repaintNeeded _ GGAlign.UpdateBagsForAction[gargoyleData, bagType]; IF repaintNeeded THEN GGWindow.RestoreScreenAndInvariants[paintAction: $None, gargoyleData: gargoyleData, remake: bitMap, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE] ELSE GGWindow.RestoreScreenAndInvariants[paintAction: $None, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; RETURN[TRUE]; }; StartDrag: PUBLIC StartProc = { startSuccess: BOOL _ StartMotionAux[gargoyleData, "drag", $Drag, worldPt]; IF NOT startSuccess THEN RETURN[FALSE]; DuringDrag[NIL, gargoyleData, worldPt]; }; StartRotate: PUBLIC StartProc = { startSuccess: BOOL _ StartMotionAux[gargoyleData, "rotate", $Drag, worldPt, TRUE]; IF NOT startSuccess THEN RETURN[FALSE]; DuringRotate[NIL, gargoyleData, worldPt]; }; StartScale: PUBLIC StartProc = { anchorPoint: Point; originalVector: Vector; startSuccess: BOOL _ StartMotionAux[gargoyleData, "scale", $Drag, worldPt, TRUE]; IF NOT startSuccess THEN RETURN[FALSE]; anchorPoint _ GGCaret.GetPoint[gargoyleData.anchor]; originalVector _ GGVector.Sub[gargoyleData.drag.startPoint, anchorPoint]; IF originalVector = [0.0, 0.0] THEN { GGError.AppendHerald[gargoyleData.feedback, "Move caret away from anchor before scaling.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN[FALSE]; }; DuringScale[NIL, gargoyleData, worldPt]; }; DuringDrag: PUBLIC MouseProc = { <> totalDragVector: Vector; mapPoint: Point; feature: FeatureData; [mapPoint, feature] _ GGGravity.Map[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.currentObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, TRUE]; SetCaretAttractor[gargoyleData, mapPoint, feature, "Dragging:"]; totalDragVector _ GGVector.Sub[mapPoint, gargoyleData.drag.startPoint]; gargoyleData.drag.transform _ ImagerTransformation.Translate[[totalDragVector.x, totalDragVector.y]]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringMotion, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end DuringDrag DuringRotate: PUBLIC MouseProc = { originalVector, newVector: Vector; mapPoint: Point; feature: FeatureData; degrees: REAL; anchorPoint: Point _ GGCaret.GetPoint[gargoyleData.anchor]; [mapPoint, feature] _ GGGravity.Map[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.currentObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, TRUE]; SetCaretAttractor[gargoyleData, mapPoint, feature, "Rotating:"]; originalVector _ GGVector.Sub[gargoyleData.drag.startPoint, anchorPoint]; newVector _ GGVector.Sub[mapPoint, anchorPoint]; degrees _ GGVector.AngleCCWBetweenVectors[originalVector, newVector]; gargoyleData.drag.transform _ GGTransform.RotateAboutPoint[anchorPoint, degrees]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringMotion, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; DuringScale: PUBLIC MouseProc = { epsilon: REAL = 1.0e-3; originalVector, newVector: Vector; mapPoint: Point; feature: FeatureData; ratio: REAL; anchorPoint: Point _ GGCaret.GetPoint[gargoyleData.anchor]; [mapPoint, feature] _ GGGravity.Map[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.currentObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, TRUE]; SetCaretAttractor[gargoyleData, mapPoint, feature, "Scaling:"]; originalVector _ GGVector.Sub[gargoyleData.drag.startPoint, anchorPoint]; newVector _ GGVector.Sub[mapPoint, anchorPoint]; IF RealFns.AlmostZero[newVector.x, -10] AND RealFns.AlmostZero[newVector.y, -10] THEN RETURN; -- can't scale to zero ratio _ GGVector.Magnitude[newVector]/GGVector.Magnitude[originalVector]; gargoyleData.drag.transform _ GGTransform.ScaleAboutPoint[anchorPoint, ratio]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringMotion, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; DuringSixPoint: PUBLIC MouseProc = { OPEN GGVector; epsilon: REAL = 1.0e-3; pts: ARRAY [0..5] OF Point; crossProduct: REAL; mapPoint: Point; feature: FeatureData; pts[0] _ pts[3] _ GGCaret.GetPoint[gargoyleData.anchor]; pts[2] _ gargoyleData.drag.startPoint; pts[1] _ pts[4] _ Add[pts[0], VectorPlusAngle[Sub[pts[2], pts[0]], 90.0]]; [mapPoint, feature] _ GGGravity.Map[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.currentObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, TRUE]; SetCaretAttractor[gargoyleData, mapPoint, feature, "Six Point Transform:"]; pts[5] _ mapPoint; crossProduct _ CrossProductScalar[Sub[pts[4],pts[3]], Sub[pts[5],pts[3]]]; IF ABS[crossProduct] < epsilon THEN RETURN; -- illegal six point transform gargoyleData.drag.transform _ GGTransform.SixPoints[pts]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringMotion, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; StartSixPoint: PUBLIC StartProc = { OPEN GGVector; epsilon: REAL = 1.0e-3; p0, p1, p2: Point; crossProduct: REAL; startSuccess: BOOL _ StartMotionAux[gargoyleData, "six point", $Drag, worldPt, TRUE]; IF NOT startSuccess THEN RETURN[FALSE]; p0 _ GGCaret.GetPoint[gargoyleData.anchor]; p2 _ gargoyleData.drag.startPoint; p1 _ Add[p0, VectorPlusAngle[Sub[p2, p0], 90.0]]; crossProduct _ CrossProductScalar[Sub[p1,p0], Sub[p2, p0]]; IF ABS[crossProduct] < epsilon THEN { GGError.AppendHerald[gargoyleData.feedback, "Move caret away from anchor before six point.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN[FALSE]; }; DuringSixPoint[NIL, gargoyleData, worldPt]; }; EndMotion: PUBLIC MouseProc = { <> GGStatistics.StartInterval[$EndMotion, GGStatistics.GlobalTable[]]; TransformObjectsAfterMove[gargoyleData]; GGRefresh.MoveOverlayToBackground[gargoyleData]; GGWindow.NewCaretPos[gargoyleData]; GGWindow.RestoreScreenAndInvariants[paintAction: $FinishedDragging, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; GGStatistics.StopInterval[$EndMotion, GGStatistics.GlobalTable[]]; }; <> ExtendTrajToMouse: PRIVATE PROC [scene: Scene, worldPt: Point, gargoyleData: GargoyleData] RETURNS [traj: Traj, movingJointSeq: Sequence, success: BOOL] = { caret: Caret _ gargoyleData.caret; chair: REF ANY; caretPoint: Point; jointNum: NAT; newLine: Segment; jointParts: SliceParts; jointD: OutlineDescriptor; partType: TrajPartType; caretPoint _ GGCaret.GetPoint[caret]; IF GGCaret.SittingOnEnd[caret] THEN { -- extend the existing trajectory outlineD: OutlineDescriptor; chair _ GGCaret.GetChair[caret]; -- better be a traj !! IF ISTYPE[chair, SliceDescriptor] THEN ERROR Problem[msg: "Slices are Outlines now."]; outlineD _ NARROW[chair]; [success, partType, traj, ----, jointNum] _ GGOutline.UnpackSimpleDescriptorOld[outlineD]; IF NOT success OR partType # joint THEN ERROR; IF jointNum = 0 THEN { -- add to the low end of the trajectory newLine _ GGSegment.MakeLine[worldPt, caretPoint, NIL]; success _ GGTraj.AddSegment[traj, lo, newLine, hi]; IF NOT success THEN RETURN; <> GGSelect.ReselectTraj[traj, lo, gargoyleData.scene, TRUE]; GGCaret.SetAttractor[gargoyleData.caret, worldPt, NIL]; movingJointSeq _ GGSequence.CreateFromJoint[traj, 0]; jointParts _ GGOutline.PartsFromSequence[outlineD.slice, movingJointSeq]; jointD _ NEW[OutlineDescriptorObj _ [outlineD.slice, jointParts]]; GGCaret.SitOn[gargoyleData.caret, jointD]; } ELSE IF jointNum = GGTraj.HiJoint[traj] THEN { -- add to the high end of the trajectory newLine _ GGSegment.MakeLine[caretPoint, worldPt, NIL]; success _ GGTraj.AddSegment[traj, hi, newLine, lo]; IF NOT success THEN RETURN; GGSelect.ReselectTraj[traj, hi, gargoyleData.scene, TRUE]; <> GGCaret.SetAttractor[gargoyleData.caret, worldPt, NIL]; movingJointSeq _ GGSequence.CreateFromJoint[traj, GGTraj.HiJoint[traj]]; jointParts _ GGOutline.PartsFromSequence[outlineD.slice, movingJointSeq]; jointD _ NEW[OutlineDescriptorObj _ [outlineD.slice, jointParts]]; GGCaret.SitOn[gargoyleData.caret, jointD]; } ELSE ERROR; } ELSE { -- Create a new trajectory starting at the caret (making touching constraints, if any). newOutline: Outline; newLine _ GGSegment.MakeLine[caretPoint, worldPt, NIL]; traj _ GGTraj.CreateTraj[caretPoint]; success _ GGTraj.AddSegment[traj, hi, newLine, lo]; IF NOT success THEN RETURN; newOutline _ GGOutline.CreateOutline[traj]; GGObjects.AddOutline[scene, newOutline, -1]; GGCaret.SetAttractor[gargoyleData.caret, worldPt, NIL]; movingJointSeq _ GGSequence.CreateFromJoint[traj, 1]; jointParts _ GGOutline.PartsFromSequence[newOutline, movingJointSeq]; jointD _ NEW[OutlineDescriptorObj _ [newOutline, jointParts]]; GGCaret.SitOn[gargoyleData.caret, jointD]; }; GGSelect.DeselectAll[gargoyleData.scene, normal]; GGSelect.SelectSequence[movingJointSeq, gargoyleData.scene, normal]; }; ContinueAdd: PUBLIC StartProc = { <> selSeq: Sequence _ gargoyleData.drag.seqInProgress; GGTraj.TransformSequence[selSeq, gargoyleData.drag.transform]; GGWindow.NewCaretPos[gargoyleData]; GGRefresh.MoveOverlayToBackground[gargoyleData]; success _ StartAdd[LIST[$ContinueAdd], gargoyleData, worldPt]; }; StartAdd: PUBLIC StartProc = { continue, repaintNeeded: BOOL; newOutline: Outline; GGStatistics.StartInterval[$StartAdd, GGStatistics.GlobalTable[]]; continue _ NARROW[input.first, ATOM] = $ContinueAdd; [newOutline, success] _ StartAddAux[gargoyleData, worldPt]; IF NOT success THEN RETURN; <> GGRefresh.SplitBackgroundAndOverlay[gargoyleData, GGBoundBox.emptyBoundBox]; repaintNeeded _ GGAlign.UpdateBagsForAction[gargoyleData, $Drag]; IF NOT repaintNeeded OR (continue AND GGButtons.GetButtonState[gargoyleData.hitTest.heuristicsButton] = off) THEN { GGWindow.RestoreScreenAndInvariants[paintAction: $None, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; } ELSE { GGWindow.RestoreScreenAndInvariants[paintAction: $None, gargoyleData: gargoyleData, remake: bitMap, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; DuringAdd[NIL, gargoyleData, worldPt]; GGStatistics.StopInterval[$StartAdd, GGStatistics.GlobalTable[]]; }; -- end StartAdd StartAddAux: PROC [gargoyleData: GargoyleData, worldPt: Point] RETURNS [newOutline: Outline, success: BOOL] = { jointSeq: Sequence; trajUnderCaret: Traj; jointNum: NAT; chair: REF ANY; movingJointSeq: Sequence; oldOutline: Outline; outlineD: OutlineDescriptor; outlineParts: SliceParts; SaveSavedState[gargoyleData]; -- must do this before any possible aborts occur IF NOT GGRefresh.EmptyOverlay[gargoyleData] THEN ERROR; -- nothing on overlay <> [trajUnderCaret, movingJointSeq, success] _ ExtendTrajToMouse[gargoyleData.scene, worldPt, gargoyleData]; IF NOT success THEN RETURN[NIL, FALSE]; oldOutline _ GGOutline.OutlineOfTraj[trajUnderCaret]; newOutline _ GGOutline.OutlineOfTraj[movingJointSeq.traj]; GGAlign.ReplaceObsoleteOutlineTrigger[gargoyleData, oldOutline, newOutline]; <> chair _ GGCaret.GetChair[gargoyleData.caret]; outlineD _ NARROW[chair]; [jointNum: jointNum] _ GGOutline.UnpackSimpleDescriptorOld[outlineD]; jointSeq _ GGSequence.CreateJointToJoint[trajUnderCaret, jointNum, jointNum]; gargoyleData.drag.seqInProgress _ jointSeq; -- remember this sequence outlineParts _ GGOutline.PartsFromSequence[newOutline, jointSeq]; outlineD _ NEW[OutlineDescriptorObj _ [newOutline, outlineParts]]; GGRefresh.MoveToOverlay[outlineD, gargoyleData]; <> gargoyleData.drag.startPoint _ worldPt; -- used in DuringAddMotion gargoyleData.drag.transform _ ImagerTransformation.Scale[1.0]; }; -- end StartAddAux DuringAdd: PUBLIC MouseProc = { DuringAddMotion[gargoyleData, worldPt]; GGStatistics.StartInterval[$AddPaint, GGStatistics.GlobalTable[]]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringMotion, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; GGStatistics.StopInterval[$AddPaint, GGStatistics.GlobalTable[]]; }; -- end During Add DuringAddMotion: PROC [gargoyleData: GargoyleData, worldPt: Point] = { <> totalDragVector: Vector; mapPoint: Point; feature: FeatureData; currentObjects: ObjectBag _ NARROW[gargoyleData.hitTest.currentObjectBag]; sceneObjects: TriggerBag _ NARROW[gargoyleData.hitTest.sceneTriggerBag]; [mapPoint, feature] _ GGGravity.Map[worldPt, gargoyleData.hitTest.criticalR, currentObjects, sceneObjects, gargoyleData, TRUE]; SetCaretAttractor[gargoyleData, mapPoint, feature, "Adding:"]; totalDragVector _ GGVector.Sub[mapPoint, gargoyleData.drag.startPoint]; gargoyleData.drag.transform _ ImagerTransformation.Translate[[totalDragVector.x, totalDragVector.y]]; }; -- end DuringAddMotion EndAdd: PUBLIC MouseProc = { <> selSeq: Sequence; GGStatistics.StartInterval[$EndAdd, GGStatistics.GlobalTable[]]; DuringAddMotion[gargoyleData, worldPt]; selSeq _ gargoyleData.drag.seqInProgress; GGTraj.TransformSequence[selSeq, gargoyleData.drag.transform]; GGWindow.NewCaretPos[gargoyleData]; GGRefresh.MoveOverlayToBackground[gargoyleData]; gargoyleData.refresh.startBoundBox^ _ selSeq.traj.boundBox^; gargoyleData.refresh.addedObject _ GGOutline.OutlineOfTraj[selSeq.traj]; GGWindow.RestoreScreenAndInvariants[paintAction: $FinishedAdding, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; GGStatistics.StopInterval[$EndAdd, GGStatistics.GlobalTable[]]; }; AddNewBoxSlice: PROC [from, to: Point, gargoyleData: GargoyleData] RETURNS [sliceD: SliceDescriptor] = { box: BoundBox; corner: GGSlice.Corner _ none; loX: REAL _ MIN[from.x, to.x ]; loY: REAL _ MIN[from.y, to.y ]; hiX: REAL _ MAX[from.x, to.x ]; hiY: REAL _ MAX[from.y, to.y ]; IF to.x=loX THEN IF to.y=loY THEN corner _ ll ELSE corner _ ul; IF to.x=hiX THEN IF to.y=loY THEN corner _ lr ELSE corner _ ur; box _ GGBoundBox.CreateBoundBox[loX, loY, hiX, hiY]; gargoyleData.drag.boxInProgress _ sliceD _ GGSlice.MakeBoxSlice[box, corner, GGTransform.Identity[]]; GGObjects.AddSlice[gargoyleData.scene, sliceD.slice, -1]; <> }; StartBox: PUBLIC StartProc = { sliceD: SliceDescriptor; caretPos: Point; GGStatistics.StartInterval[$StartBox, GGStatistics.GlobalTable[]]; caretPos _ GGCaret.GetPoint[gargoyleData.caret]; SaveSavedState[gargoyleData]; -- must do this before any possible aborts occur IF NOT GGRefresh.EmptyOverlay[gargoyleData] THEN ERROR; -- nothing on overlay sliceD _ AddNewBoxSlice[caretPos, worldPt, gargoyleData]; GGSelect.DeselectAll[gargoyleData.scene, normal]; GGSelect.SelectSlice[slice: sliceD.slice, parts: sliceD.parts, scene: gargoyleData.scene, selectClass: normal]; <> GGRefresh.MoveToOverlay[sliceD, gargoyleData]; -- slice on overlay to be rubberbanded <> gargoyleData.drag.startPoint _ worldPt; gargoyleData.drag.transform _ ImagerTransformation.Scale[1.0]; GGRefresh.SplitBackgroundAndOverlay[gargoyleData, GGBoundBox.emptyBoundBox]; GGWindow.RestoreScreenAndInvariants[paintAction: $None, gargoyleData: gargoyleData, remake: bitMap, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; DuringAdd[NIL, gargoyleData, worldPt]; GGStatistics.StopInterval[$StartBox, GGStatistics.GlobalTable[]]; }; EndBox: PUBLIC MouseProc = { <> sliceD: SliceDescriptor _ NARROW[gargoyleData.drag.boxInProgress]; slice: Slice _ sliceD.slice; slice.class.transform[slice, sliceD.parts, gargoyleData.drag.transform]; -- update the slice GGRefresh.MoveOverlayToBackground[gargoyleData]; gargoyleData.refresh.startBoundBox^ _ slice.boundBox^; --newly updated by slice.class.transform gargoyleData.refresh.addedObject _ slice; GGWindow.RestoreScreenAndInvariants[paintAction: $FinishedAdding, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; }; EndSelectWithBox: PUBLIC MouseProc = { <> sliceD: SliceDescriptor _ NARROW[gargoyleData.drag.boxInProgress]; slice: Slice _ sliceD.slice; slice.class.transform[slice, sliceD.parts, gargoyleData.drag.transform]; -- update the slice GGRefresh.MoveOverlayToBackground[gargoyleData]; GGSelect.SelectSlice[slice: slice, parts: slice.class.newParts[slice, NIL, topLevel], scene: gargoyleData.scene, selectClass: normal]; GGEvent.AreaSelectNewAndDelete[NIL, gargoyleData]; gargoyleData.refresh.startBoundBox^ _ slice.boundBox^; --newly updated by slice.class.transform GGWindow.RestoreScreenAndInvariants[paintAction: $FinishedAdding, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: FALSE]; }; FixupAbortedBox: PROC [gargoyleData: GargoyleData] = { <> sliceD: SliceDescriptor _ NARROW[gargoyleData.drag.boxInProgress]; slice: Slice _ sliceD.slice; repaintBox: BoundBox _ GGCaret.BoundBoxOfCaret[gargoyleData.caret, gargoyleData]; -- start with caret GGBoundBox.EnlargeByBox[repaintBox, slice.boundBox]; -- repaint deleted box slice GGSelect.DeselectEntityAllClasses[slice, gargoyleData.scene]; GGSlice.DeleteSlice[gargoyleData.scene, slice]; gargoyleData.refresh.startBoundBox^ _ repaintBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: FALSE]; }; InitStats: PROC [] = { interval: GGStatistics.Interval; bags, paint, background: GGStatistics.Interval; bags _ GGStatistics.CreateInterval[$SetBags]; paint _ GGStatistics.CreateInterval[$AddPaint]; background _ GGStatistics.CreateInterval[$StoreBackground]; interval _ GGStatistics.CreateInterval[$StartAdd, LIST[bags, paint, background]]; GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]]; interval _ GGStatistics.CreateInterval[$EndAdd]; GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]]; interval _ GGStatistics.CreateInterval[$StartCaretPos]; GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]]; interval _ GGStatistics.CreateInterval[$DuringCaretPos]; GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]]; interval _ GGStatistics.CreateInterval[$EndCaretPos]; GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]]; interval _ GGStatistics.CreateInterval[$EndMotion]; GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]]; interval _ GGStatistics.CreateInterval[$StartBox]; GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]]; interval _ GGStatistics.CreateInterval[$HandleGuarded]; GGStatistics.AddInterval[interval, GGStatistics.GlobalTable[]]; }; InitStats[]; END.