<> <> <> <> <> <<>> DIRECTORY Atom, Basics, GGAlign, GGBasicTypes, GGBoundBox, AtomButtons, GGSlice, GGCaret, GGDescribe, GGMouseEvent, GGMultiGravity, 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, AtomButtons, GGSlice, GGCaret, GGDescribe, GGError, GGEvent, GGGravity, GGMouseEvent, GGMultiGravity, 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; HandleUnGuardedAux[startProc, duringProc, endProc, abortProc, genericAction, input, gargoyleData, worldPt]; }; HandleUnGuardedAux: PROC [startProc: StartProc, duringProc, endProc, abortProc: MouseProc, genericAction: ATOM, input: LIST OF REF ANY, gargoyleData: GargoyleData, worldPt: Point] = { SELECT gargoyleData.state FROM $None => { SELECT genericAction FROM $Start => { [] _ 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]; $MouseUp, $AllUp => { endProc[input, gargoyleData, worldPt]; gargoyleData.state _ $None; gargoyleData.mouseMode _ $None; }; $Abort => {abortProc[input, gargoyleData, worldPt]; gargoyleData.state _ $Aborted}; $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; }; $Aborted => { SELECT genericAction FROM $AllUp => {gargoyleData.state _ $None; gargoyleData.mouseMode _ $None}; $MouseUp => {gargoyleData.state _ $None; gargoyleData.mouseMode _ $None}; ENDCASE; }; ENDCASE => SIGNAL Problem[msg: "Unknown generic state"]; }; <<>> <> <<>> SortNewEntities: PROC [entityList: LIST OF REF ANY] RETURNS [sorted: LIST OF REF ANY] = { <> CompareProc: GList.CompareProc = { <<[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison]>> priority1, priority2: INT; WITH ref1 SELECT FROM slice: Slice => priority1 _ slice.priority; outline: Outline => priority1 _ outline.priority; ENDCASE; WITH ref2 SELECT FROM slice: Slice => priority2 _ slice.priority; outline: Outline => priority2 _ outline.priority; ENDCASE; RETURN[Basics.CompareINT[priority1, priority2]]; }; sorted _ NARROW[GList.Sort[entityList, CompareProc]]; }; ComputePriorities: PROC [scene: Scene] = { count: INT _ 0; entityGen: EntityGenerator _ GGObjects.TopLevelEntitiesInScene[scene]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM slice: Slice => slice.priority _ count; outline: Outline => outline.priority _ count; ENDCASE => ERROR; count _ count + 1; ENDLOOP; }; CopySelected: PUBLIC StartProc = { <> newTraj: Traj; newSlice: Slice; entityList: LIST OF REF ANY; allParts: SliceParts; newOutline, outline: Outline; outSeqGen: GGSelect.OutlineSequenceGenerator; sliceDGen: SliceDescriptorGenerator; scene: Scene _ gargoyleData.scene; SaveSavedState[gargoyleData]; -- must do this before any possible aborts occur ComputePriorities[gargoyleData.scene]; sliceDGen _ GGSelect.SelectedSlices[scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDGen], GGSelect.NextSliceDescriptor[sliceDGen] UNTIL sliceD = NIL DO newSlice _ GGSlice.CopySlice[sliceD.slice]; -- make the new one GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, scene, normal]; entityList _ CONS[newSlice, entityList]; newSlice.priority _ sliceD.slice.priority; ENDLOOP; outSeqGen _ GGSelect.SelectedOutlineSequences[scene, normal]; FOR outSeq: GGSelect.OutlineSequence _ GGSelect.NextOutlineSequences[outSeqGen], GGSelect.NextOutlineSequences[outSeqGen] UNTIL outSeq = NIL DO outline _ outSeq.outline; IF outSeq.fenceSeq # NIL THEN { IF GGSequence.NextSegment[GGSequence.SegmentsInSequence[outSeq.fenceSeq]]=NIL THEN { <<-- no segments, only joints selected>> GGError.AppendHerald[gargoyleData.feedback, ". . . Cannot Copy Joints or CPs", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN[FALSE]; }; <> IF GGSelect.IsSelectedInFull[outline, scene, normal] THEN { newOutline _ outline.class.copy[outline]; GGSelect.DeselectEntireOutline[outline, scene, normal]; -- deselect the old one entityList _ CONS[newOutline, entityList]; newOutline.priority _ outline.priority; LOOP; } <> ELSE { newTraj _ GGTraj.CopyTrajFromRun[outSeq.fenceSeq]; newOutline _ GGOutline.CreateOutline[newTraj, outline.lineEnds, outline.fillColor]; GGSelect.DeselectSequence[outSeq.fenceSeq, scene, normal]; entityList _ CONS[newOutline, entityList]; newOutline.priority _ outline.priority; }; }; FOR holeSeq: Sequence _ GGSequence.NextSequence[outSeq.holeSeqs], GGSequence.NextSequence[outSeq.holeSeqs] UNTIL holeSeq = NIL DO IF GGSequence.NextSegment[GGSequence.SegmentsInSequence[holeSeq]]=NIL THEN { <<-- no segments, only joints selected>> GGError.AppendHerald[gargoyleData.feedback, ". . . Cannot Copy Joints or CPs", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN[FALSE]; }; newTraj _ GGTraj.CopyTrajFromRun[holeSeq]; newOutline _ GGOutline.CreateOutline[newTraj, outline.lineEnds, outline.fillColor]; GGSelect.DeselectSequence[holeSeq, scene, normal]; entityList _ CONS[newOutline, entityList]; newOutline.priority _ outline.priority; ENDLOOP; ENDLOOP; <> entityList _ SortNewEntities[entityList]; <> FOR sliceList: LIST OF REF ANY _ entityList, sliceList.rest UNTIL sliceList = NIL DO WITH sliceList.first SELECT FROM newSlice: Slice => { GGObjects.AddSlice[gargoyleData.scene, newSlice, -1]; allParts _ newSlice.class.newParts[newSlice, NIL, slice]; GGSelect.SelectSlice[newSlice, allParts, scene, normal]; }; newOutline: Outline => { GGObjects.AddOutline[gargoyleData.scene, newOutline, -1]; allParts _ newOutline.class.newParts[newOutline, NIL, slice]; GGSelect.SelectOutline[newOutline, allParts, scene, normal]; }; ENDCASE => ERROR; ENDLOOP; [] _ StartDrag[NIL, gargoyleData, worldPt]; }; StartSelectJoint: PUBLIC StartProc = { gargoyleData.drag.selectState _ joint; StartSelectAux[gargoyleData, worldPt]; DuringSelect[NIL, gargoyleData, worldPt]; }; StartSelectSegment: PUBLIC StartProc = { gargoyleData.drag.selectState _ segment; StartSelectAux[gargoyleData, worldPt]; DuringSelect[NIL, gargoyleData, worldPt]; }; StartSelectTrajectory: PUBLIC StartProc = { gargoyleData.drag.selectState _ traj; StartSelectAux[gargoyleData, worldPt]; DuringSelect[NIL, gargoyleData, worldPt]; }; StartSelectTopLevel: PUBLIC StartProc = { gargoyleData.drag.selectState _ topLevel; StartSelectAux[gargoyleData, worldPt]; DuringSelect[NIL, gargoyleData, worldPt]; }; StartSelectAux: PROC [gargoyleData: GargoyleData, worldPt: Point] = { IF NOT GGRefresh.EmptyOverlay[gargoyleData] THEN ERROR; SaveSavedState[gargoyleData]; }; DuringSelect: PUBLIC MouseProc = { <> resultPoint: Point; feature: FeatureData; <> IF gargoyleData.drag.selectState = joint THEN [resultPoint, feature] _ GGMultiGravity.InnerCircle[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.innerR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, FALSE] ELSE [resultPoint, feature] _ GGMultiGravity.StrictDistance[worldPt, gargoyleData.hitTest.criticalR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData]; <> GGMouseEvent.SetCaretAttractorEndpoint[gargoyleData, resultPoint, feature]; GGMouseEvent.DescribeSelectionAction[gargoyleData, feature, gargoyleData.drag.selectState, "Selecting"]; <> GGSelect.DeselectAll[gargoyleData.scene, normal]; IF feature = NIL THEN { -- no near trajectories, caret in free space } ELSE { <> SELECT gargoyleData.drag.selectState FROM joint => SelectJointOrCP[feature: feature, caretPt: resultPoint, gargoyleData: gargoyleData]; segment => SelectSegment[feature: feature, caretPt: resultPoint, gargoyleData: gargoyleData]; traj => SelectTraj[feature: feature, caretPt: resultPoint, gargoyleData: gargoyleData]; topLevel => SelectTopLevel[feature: feature, caretPt: resultPoint, gargoyleData: gargoyleData]; ENDCASE => ERROR; }; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end DuringSelect SelectJointOrCP: PUBLIC PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] = { [----] _ SelectJointOrCPInternal[feature, caretPt, gargoyleData]; }; SelectJointOrCPInternal: PUBLIC PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] RETURNS [parts: SliceParts _ NIL]= { <> SELECT feature.resultType FROM slice => { sliceD: SliceDescriptor _ NARROW[feature.shape]; parts _ sliceD.slice.class.newParts[sliceD.slice, feature.hitPart, joint]; GGSelect.SelectSlice[sliceD.slice, parts, gargoyleData.scene, normal]; }; outline => { outlineD: OutlineDescriptor _ NARROW[feature.shape]; parts _ outlineD.slice.class.newParts[outlineD.slice, feature.hitPart, joint]; GGSelect.SelectOutline[outlineD.slice, parts, gargoyleData.scene, normal]; }; midpoint => NULL; -- temporarily ignore midpoints in bags. KAP. June 26, 1986 slopeLine, angleLine, distanceLine, intersectionPoint, radiiCircle, midpoint => ERROR; <> ENDCASE => ERROR NotYetImplemented; }; -- end SelectJointOrCPInternal SelectSegment: PUBLIC PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] = { [----] _ SelectSegmentInternal[feature, caretPt, gargoyleData]; }; SelectSegmentInternal: PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] RETURNS [parts: SliceParts _ NIL] = { <> SELECT feature.resultType FROM outline => { outline: Outline _ NARROW[feature.shape, OutlineDescriptor].slice; parts _ outline.class.newParts[outline, feature.hitPart, segment]; GGSelect.SelectOutline[outline, parts, gargoyleData.scene, normal]; }; slice => { slice: Slice _ NARROW[feature.shape, SliceDescriptor].slice; parts _ slice.class.newParts[slice, feature.hitPart, segment]; GGSelect.SelectSlice[slice, parts, gargoyleData.scene, normal]; }; midpoint => NULL; -- temporarily ignore midpoints in bags. KAP. June 26, 1986 slopeLine, angleLine, distanceLine, intersectionPoint, radiiCircle, midpoint => ERROR; <> ENDCASE => ERROR NotYetImplemented; }; -- end of SelectSegment SelectTraj: PUBLIC PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] = { [] _ SelectTrajInternal[feature, caretPt, gargoyleData]; }; SelectTrajInternal: PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] RETURNS [parts: SliceParts _ NIL] = { <> <> SELECT feature.type FROM outline => { outline: Outline _ NARROW[feature.shape, OutlineDescriptor].slice; parts _ outline.class.newParts[outline, feature.hitPart, traj]; GGSelect.SelectOutline[outline, parts, gargoyleData.scene, normal]; }; slice => { slice: Slice _ NARROW[feature.shape, SliceDescriptor].slice; parts _ slice.class.newParts[slice, feature.hitPart, traj]; GGSelect.SelectSlice[slice, parts, gargoyleData.scene, normal]; }; ENDCASE => SIGNAL Problem[msg: "Unexpected feature type"]; }; -- end SelectTraj SelectTopLevel: PUBLIC PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] = { [] _ SelectTopLevelInternal[feature, caretPt, gargoyleData]; }; SelectTopLevelInternal: PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] RETURNS [parts: SliceParts _ NIL] = { <> <> SELECT feature.resultType FROM outline => { outline: Outline _ NARROW[feature.shape, OutlineDescriptor].slice; parts _ outline.class.newParts[outline, feature.hitPart, topLevel]; GGSelect.SelectOutline[outline, parts, gargoyleData.scene, normal]; }; slice => { slice: Slice _ NARROW[feature.shape, SliceDescriptor].slice; parts _ slice.class.newParts[slice, feature.hitPart, topLevel]; GGSelect.SelectSlice[slice, parts, gargoyleData.scene, normal]; }; midpoint => NULL; -- temporarily ignore midpoints in bags. KAP. June 26, 1986 slopeLine, angleLine, distanceLine, intersectionPoint, radiiCircle, midpoint => ERROR; <> ENDCASE => ERROR NotYetImplemented; }; EndSelect: PUBLIC MouseProc = { resultPoint: Point; feature: FeatureData; <> IF gargoyleData.drag.selectState = joint THEN [resultPoint, feature] _ GGMultiGravity.InnerCircle[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.innerR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, FALSE] ELSE [resultPoint, feature] _ GGMultiGravity.StrictDistance[worldPt, gargoyleData.hitTest.criticalR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData]; <> GGMouseEvent.SetCaretAttractorEndpoint[gargoyleData, resultPoint, feature]; <> <> GGWindow.NewCaretPos[gargoyleData]; <> GGSelect.DeselectAll[gargoyleData.scene, normal]; <> SELECT gargoyleData.drag.selectState FROM joint => EndSelectJoint[gargoyleData, resultPoint, feature]; segment => EndSelectSegment[gargoyleData, resultPoint, feature]; traj => EndSelectTrajectory[gargoyleData, resultPoint, feature]; topLevel => EndSelectTopLevel[gargoyleData, resultPoint, feature]; ENDCASE => ERROR; gargoyleData.drag.selectState _ none; -- added to help DescribeFeature work. KAP. }; -- end EndSelect EndSelectJoint: PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = { <> IF feature = NIL THEN { -- no preparation needed GGCaret.SitOn[gargoyleData.caret, NIL]; GGError.AppendHerald[gargoyleData.feedback, "No near joint found.", oneLiner]; } ELSE { <> gargoyleData.drag.extendMode _ joint; SELECT feature.resultType FROM outline => { outlineD: OutlineDescriptor _ NEW[OutlineDescriptorObj _ [slice: NARROW[feature.shape, OutlineDescriptor].slice] ]; outlineD.parts _ SelectJointOrCPInternal[feature, resultPoint, gargoyleData]; GGCaret.SitOn[gargoyleData.caret, outlineD]; 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] ]; sliceD.parts _ SelectJointOrCPInternal[feature, resultPoint, gargoyleData]; GGCaret.SitOn[gargoyleData.caret, sliceD]; GGError.AppendHerald[gargoyleData.feedback, Rope.Concat[sliceD.slice.class.describe[sliceD.slice, sliceD.parts], " selected"], oneLiner]; gargoyleData.drag.sliceToExtend _ sliceD; }; ENDCASE => ERROR Problem[msg: "Unexpected feature type"]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndSelectJoint EndSelectSegment: PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = { <> IF feature = NIL THEN { GGCaret.SitOn[gargoyleData.caret, NIL]; GGError.AppendHerald[gargoyleData.feedback, "No near segment found.", oneLiner]; } ELSE { gargoyleData.drag.extendMode _ segmentRange; 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]]; outlineD.parts _ SelectSegmentInternal[feature, resultPoint, gargoyleData]; 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]]; sliceD.parts _ SelectSegmentInternal[feature, resultPoint, gargoyleData]; 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["Unexpected feature type"]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndSelectSegment EndSelectTrajectory: PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = { IF feature = NIL THEN { GGCaret.SitOn[gargoyleData.caret, NIL]; GGError.AppendHerald[gargoyleData.feedback, "No near trajectory found.", oneLiner]; } ELSE { <