<> <> <> <> <> <<>> DIRECTORY Basics, Feedback, GGAlign, GGBasicTypes, GGCaret, GGDescribe, GGInterfaceTypes, GGModelTypes, GGMouseEvent, GGMultiGravity, GGOutline, GGRefresh, GGScene, GGSegmentTypes, GGSelect, GGSequence, GGState, GGUtility, GGWindow, GList, ImagerTransformation, InputFocus, IO, Menus, Rope; GGMouseEventImplB: CEDAR PROGRAM IMPORTS Feedback, GGAlign, GGCaret, GGDescribe, GGMouseEvent, GGMultiGravity, GGScene, GGOutline, GGRefresh, GGSelect, GGSequence, GGState, GGWindow, ImagerTransformation, InputFocus, IO, Rope EXPORTS GGMouseEvent = BEGIN AlignmentPoint: TYPE = GGInterfaceTypes.AlignmentPoint; BoundBox: TYPE = GGModelTypes.BoundBox; Caret: TYPE = GGInterfaceTypes.Caret; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; FeatureData: TYPE = GGInterfaceTypes.FeatureData; GGData: TYPE = GGInterfaceTypes.GGData; Joint: TYPE = GGModelTypes.Joint; MouseButton: TYPE = Menus.MouseButton; MouseProc: TYPE = GGMouseEvent.MouseProc; AlignBag: TYPE = GGInterfaceTypes.AlignBag; Outline: TYPE = GGModelTypes.Outline; OutlineDescriptor: TYPE = REF OutlineDescriptorObj; OutlineDescriptorObj: TYPE = GGModelTypes.OutlineDescriptorObj; Point: TYPE = GGBasicTypes.Point; ResultFeatureType: TYPE = GGModelTypes.ResultFeatureType; Scene: TYPE = GGModelTypes.Scene; SelectMode: TYPE = GGModelTypes.SelectMode; Segment: TYPE = GGSegmentTypes.Segment; Sequence: TYPE = GGModelTypes.Sequence; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorObj: TYPE = GGModelTypes.SliceDescriptorObj; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceClass: TYPE = GGModelTypes.SliceClass; SliceParts: TYPE = GGModelTypes.SliceParts; StartProc: TYPE = GGMouseEvent.StartProc; TouchGroup: TYPE = GGSegmentTypes.TouchGroup; Traj: TYPE = GGModelTypes.Traj; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajGenerator: TYPE = GGModelTypes.TrajGenerator; Vector: TYPE = GGBasicTypes.Vector; Problem: SIGNAL [msg: Rope.ROPE] = Feedback.Problem; SaveSavedState: PROC [ggData: GGData] = { GGScene.SaveSelections[ggData.scene]; GGWindow.SaveCaretPos[ggData]; GGCaret.Copy[from: ggData.caret, to: ggData.drag.savedCaret]; }; DescribeSelectionAction: PUBLIC PROC [ggData: GGData, feature: FeatureData, hitData: REF ANY, selectMode: SelectMode, action: Rope.ROPE] = { Feedback.PutFHerald[ggData.feedback, oneLiner, "%g %g", [rope[action]], [rope[GGDescribe.DescribeFeature[feature, hitData, ggData]]]]; }; SetCaretAttractorEndpoint: PUBLIC PROC [ggData: GGData, mapPoint: Point, feature: FeatureData, hitData: REF ANY] = { IF feature=NIL THEN GGCaret.SetAttractor[ggData.caret, mapPoint, NIL] ELSE { shape: REF ANY _ feature.shape; SELECT feature.type FROM outline => { pos: Point; sliceD: OutlineDescriptor _ NARROW[shape]; jointD: OutlineDescriptor; [jointD, pos] _ sliceD.slice.class.closestJointToHitData[sliceD, mapPoint, hitData]; GGCaret.SetAttractor[ggData.caret, pos, jointD]; }; slice => { pos: Point; sliceD: SliceDescriptor _ NARROW[shape]; jointD: SliceDescriptor; [jointD, pos] _ sliceD.slice.class.closestJointToHitData[sliceD, mapPoint, hitData]; GGCaret.SetAttractor[ggData.caret, pos, jointD]; }; ENDCASE => GGCaret.SetAttractor[ggData.caret, mapPoint, NIL]; }; }; <> StartSelectJoint: PUBLIC StartProc = { ggData.drag.selectState _ joint; StartSelectAux[ggData, worldPt]; DuringSelect[NIL, ggData, worldPt]; }; StartSelectSegment: PUBLIC StartProc = { ggData.drag.selectState _ segment; StartSelectAux[ggData, worldPt]; DuringSelect[NIL, ggData, worldPt]; }; StartSelectTrajectory: PUBLIC StartProc = { ggData.drag.selectState _ traj; StartSelectAux[ggData, worldPt]; DuringSelect[NIL, ggData, worldPt]; }; StartSelectTopLevel: PUBLIC StartProc = { ggData.drag.selectState _ topLevel; StartSelectAux[ggData, worldPt]; DuringSelect[NIL, ggData, worldPt]; }; StartSelectAux: PROC [ggData: GGData, worldPt: Point] = { IF NOT GGRefresh.EmptyOverlay[ggData] THEN ERROR; SaveSavedState[ggData]; }; DuringSelect: PUBLIC MouseProc = { <> opRope: Rope.ROPE = "Selecting "; resultPoint: Point; feature: FeatureData; hitData: REF ANY; IF GGState.GetSelectMode[ggData] = joint THEN [resultPoint, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.criticalR, ggData.hitTest.innerR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE] ELSE [resultPoint, feature, hitData] _ GGMultiGravity.StrictDistance[worldPt, ggData.hitTest.criticalR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; GGMouseEvent.SetCaretAttractorEndpoint[ggData, resultPoint, feature, hitData]; GGSelect.DeselectAll[ggData.scene, normal]; IF feature#NIL THEN SelectAndDescribeSlicePart[feature, hitData, ggData, ggData.drag.selectState, opRope] ELSE DescribeOperationOnNothing[ggData, opRope]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end DuringSelect EndSelect: PUBLIC MouseProc = { resultPoint: Point; feature: FeatureData; hitData: REF ANY; <> IF ggData.drag.selectState = joint THEN [resultPoint, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.criticalR, ggData.hitTest.innerR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE] ELSE [resultPoint, feature, hitData] _ GGMultiGravity.StrictDistance[worldPt, ggData.hitTest.criticalR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; <> GGMouseEvent.SetCaretAttractorEndpoint[ggData, resultPoint, feature, hitData]; <> <> GGWindow.NewCaretPos[ggData]; <> GGSelect.DeselectAll[ggData.scene, normal]; <> SELECT ggData.drag.selectState FROM joint => EndSelectAux[ggData, resultPoint, feature, hitData, joint, "joint"]; segment => EndSelectAux[ggData, resultPoint, feature, hitData, segment, "segment"]; traj => EndSelectAux[ggData, resultPoint, feature, hitData, traj, "trajectory"]; topLevel => EndSelectAux[ggData, resultPoint, feature, hitData, topLevel, "object"]; ENDCASE => ERROR; ggData.drag.selectState _ none; -- added to help DescribeFeature work. KAP. }; -- end EndSelect EndSelectAux: PROC [ggData: GGData, resultPoint: Point, feature: FeatureData, hitData: REF ANY, mode: SelectMode, opName: Rope.ROPE] = { <> IF feature = NIL THEN { GGCaret.SitOn[ggData.caret, NIL]; Feedback.PutFHerald[ggData.feedback, oneLiner, "No near %g found.", [rope[opName]]]; } ELSE { <> SELECT mode FROM joint => ggData.drag.extendMode _ joint; segment => ggData.drag.extendMode _ segmentRange; traj => ggData.drag.extendMode _ traj; topLevel => ggData.drag.extendMode _ topLevel; ENDCASE => ERROR; SELECT feature.type FROM outline => { outlineD: OutlineDescriptor _ NARROW[SelectSlicePart[feature, hitData, ggData, mode]]; SitTheCaret[ggData.caret, outlineD, hitData, mode]; IF mode = topLevel THEN Feedback.AppendHerald[ggData.feedback, "Top level outline selected.", oneLiner] ELSE Feedback.AppendHerald[ggData.feedback, Rope.Concat[outlineD.slice.class.describe[outlineD], " selected"], oneLiner]; ggData.drag.outlineToExtend _ outlineD; ggData.drag.sliceToExtend _ NIL; }; slice => { sliceD: SliceDescriptor _ NARROW[SelectSlicePart[feature, hitData, ggData, mode]]; IF sliceD.slice.class.type = $Outline THEN { ERROR Problem[msg: "Outlines must be Slices now."]; } ELSE { IF mode = traj OR mode = topLevel THEN GGCaret.SitOn[ggData.caret, NIL] ELSE GGCaret.SitOn[ggData.caret, sliceD]; }; Feedback.AppendHerald[ggData.feedback, Rope.Concat[sliceD.slice.class.describe[sliceD], " selected"], oneLiner]; ggData.drag.outlineToExtend _ NIL; ggData.drag.sliceToExtend _ sliceD; }; ENDCASE => ERROR Problem[msg: "Unexpected feature type"]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndSelectAux SelectAndDescribeSlicePart: PUBLIC PROC [feature: FeatureData, hitData: REF ANY, ggData: GGData, mode: SelectMode, opRope: Rope.ROPE] = { selectedD: REF ANY _ SelectSlicePart[feature, hitData, ggData, mode]; description: Rope.ROPE _ WITH selectedD SELECT FROM outlineD: OutlineDescriptor => outlineD.slice.class.describe[outlineD], sliceD: SliceDescriptor => sliceD.slice.class.describe[sliceD], ENDCASE => GGDescribe.DescribeFeature[feature, hitData, ggData]; Feedback.PutFHerald[ggData.feedback, oneLiner, "%g %g", [rope[opRope]], [rope[description]] ]; }; SelectSlicePart: PUBLIC PROC [feature: FeatureData, hitData: REF ANY, ggData: GGData, mode: SelectMode] RETURNS [selectedD: REF ANY] = { <> SELECT feature.type FROM outline => { outline: Outline _ NARROW[feature.shape, OutlineDescriptor].slice; selectedOutlineD: OutlineDescriptor; selectedOutlineD _ outline.class.newParts[outline, hitData, mode]; GGSelect.SelectOutline[selectedOutlineD, ggData.scene, normal]; selectedD _ selectedOutlineD; }; slice => { slice: Slice _ NARROW[feature.shape, SliceDescriptor].slice; selectedSliceD: SliceDescriptor; selectedSliceD _ slice.class.newParts[slice, hitData, mode]; GGSelect.SelectSlice[selectedSliceD, ggData.scene, normal]; selectedD _ selectedSliceD; }; slopeLine, angleLine, distanceLine, intersectionPoint, radiiCircle, midpoint => ERROR; ENDCASE => ERROR Problem[msg: "unimplemented result type"]; }; DescribeOperationOnNothing: PUBLIC PROC [ggData: GGData, opRope: Rope.ROPE] = { Feedback.PutFHerald[ggData.feedback, oneLiner, "%g %g", [rope[opRope]], [rope["nothing"]] ]; }; SitTheCaret: PROC [caret: Caret, outlineD: OutlineDescriptor, hitData: REF ANY, mode: SelectMode] = { SELECT mode FROM joint => GGCaret.SitOn[caret, outlineD]; segment, traj, topLevel => { jointParts: SliceParts; jointSeq: Sequence; jointD: OutlineDescriptor; jointNum: NAT; traj: Traj; IF outlineD.slice.class.type = $Outline THEN { [jointNum, traj] _ GGOutline.NearestJointToHitData[hitData]; jointSeq _ GGSequence.CreateFromJoint[traj, jointNum]; jointParts _ GGOutline.PartsFromSequence[outlineD.slice, jointSeq]; jointD _ GGOutline.DescriptorFromParts[outlineD.slice, jointParts]; GGCaret.SitOn[caret, jointD]; } ELSE GGCaret.SitOn[caret, NIL]; }; ENDCASE => ERROR; }; <<>> <> StartDeselectJoint: PUBLIC StartProc = { ggData.drag.selectState _ joint; StartDeselectAux[ggData, worldPt, NIL]; DuringDeselect[NIL, ggData, worldPt]; }; StartDeselectSegment: PUBLIC StartProc = { ggData.drag.selectState _ segment; StartDeselectAux[ggData, worldPt, NIL]; DuringDeselect[NIL, ggData, worldPt]; }; StartDeselectTrajectory: PUBLIC StartProc = { ggData.drag.selectState _ traj; StartDeselectAux[ggData, worldPt, NIL]; DuringDeselect[NIL, ggData, worldPt]; }; StartDeselectTopLevel: PUBLIC StartProc = { ggData.drag.selectState _ topLevel; StartDeselectAux[ggData, worldPt, NIL]; DuringDeselect[NIL, ggData, worldPt]; }; StartDeselectAux: PROC [ggData: GGData, worldPt: Point, startBox: BoundBox] = { <> IF NOT GGRefresh.EmptyOverlay[ggData] THEN ERROR; -- nothing on overlay [] _ InputFocus.SetInputFocus[ggData.actionArea]; <> SaveSavedState[ggData]; ggData.drag.currentPoint _ worldPt; -- this line moved from individual Start code ggData.drag.transform _ ImagerTransformation.Scale[1.0]; -- needed for DuringDeselect to work properly }; DuringDeselect: PUBLIC MouseProc = { <> opRope: Rope.ROPE = "Deselecting "; resultPoint: Point; feature: FeatureData; hitData: REF ANY; <> ggData.drag.currentPoint _ worldPt; IF ggData.drag.selectState = joint THEN [resultPoint, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.criticalR, ggData.hitTest.innerR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE] ELSE [resultPoint, feature, hitData] _ GGMultiGravity.StrictDistance[worldPt, ggData.hitTest.criticalR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; <> GGScene.RestoreSelections[ggData.scene]; IF feature#NIL THEN DuringDeselectAux[feature, hitData, resultPoint, ggData, ggData.drag.selectState] ELSE DescribeOperationOnNothing[ggData, opRope]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end DuringDeselect DuringDeselectAux: PROC [feature: FeatureData, hitData: REF ANY, caretPt: Point, ggData: GGData, mode: GGModelTypes.SelectMode] = { description: Rope.ROPE; opRope: Rope.ROPE = "Deselecting "; SELECT feature.type FROM outline => { deselectedD: OutlineDescriptor _ OutlineDeselectAux[feature, hitData, mode, ggData.scene]; description _ IF deselectedD=NIL THEN "" ELSE deselectedD.slice.class.describe[deselectedD]; Feedback.PutFHerald[ggData.feedback, oneLiner, "%g %g", [rope[opRope]], [rope[description]] ]; }; slice => { deselectedD: SliceDescriptor _ SliceDeselectAux[feature, hitData, mode, ggData.scene]; description _ IF deselectedD=NIL THEN "" ELSE deselectedD.slice.class.describe[deselectedD]; Feedback.PutFHerald[ggData.feedback, oneLiner, "%g %g", [rope[opRope]], [rope[description]] ]; }; slopeLine, angleLine, distanceLine, intersectionPoint, radiiCircle, midpoint => ERROR; ENDCASE => ERROR; }; SliceDeselectAux: PROC [feature: FeatureData, hitData: REF ANY, mode: GGModelTypes.SelectMode, scene: Scene] RETURNS [deselectedD: SliceDescriptor] = { sliceD: SliceDescriptor _ GGSelect.FindSelectedSlice[NARROW[feature.shape, SliceDescriptor].slice, scene, normal]; IF sliceD#NIL THEN { class: SliceClass _ sliceD.slice.class; newD: SliceDescriptor _ class.newParts[sliceD.slice, hitData, mode]; diffD: SliceDescriptor _ class.differenceParts[sliceD, newD]; GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, scene, normal]; IF NOT class.emptyParts[diffD] THEN GGSelect.SelectSlice[diffD, scene, normal]; deselectedD _ newD; }; }; OutlineDeselectAux: PROC [feature: FeatureData, hitData: REF ANY, mode: GGModelTypes.SelectMode, scene: Scene] RETURNS [deselectedD: OutlineDescriptor] = { sliceD: OutlineDescriptor _ GGSelect.FindSelectedOutline[NARROW[feature.shape, OutlineDescriptor].slice, scene, normal]; IF sliceD#NIL THEN { class: GGModelTypes.OutlineClass _ sliceD.slice.class; newD: OutlineDescriptor _ class.newParts[sliceD.slice, hitData, mode]; diffD: OutlineDescriptor _ class.differenceParts[sliceD, newD]; GGSelect.DeselectOutline[sliceD.slice, sliceD.parts, scene, normal]; IF NOT class.emptyParts[diffD] THEN GGSelect.SelectOutline[diffD, scene, normal]; deselectedD _ newD; }; }; EndDeselect: PUBLIC MouseProc = { resultPoint: Point; feature: FeatureData; hitData: REF ANY; IF ggData.drag.selectState = joint THEN [resultPoint, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.criticalR, ggData.hitTest.innerR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE] ELSE [resultPoint, feature, hitData] _ GGMultiGravity.StrictDistance[worldPt, ggData.hitTest.criticalR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; <> <> <> <> GGRefresh.MoveOverlayToBackground[ggData]; <> SELECT ggData.drag.selectState FROM joint => EndDeselectAux[ggData, resultPoint, feature, hitData, joint, "joint"]; segment => EndDeselectAux[ggData, resultPoint, feature, hitData, segment, "segment"]; traj => EndDeselectAux[ggData, resultPoint, feature, hitData, traj, "trajectory"]; topLevel => EndDeselectAux[ggData, resultPoint, feature, hitData, topLevel, "top level object"]; ENDCASE => ERROR; ggData.drag.selectState _ none; -- added to help DescribeFeature work. KAP. }; EndDeselectAux: PROC [ggData: GGData, resultPoint: Point, feature: FeatureData, hitData: REF ANY, mode: SelectMode, selectRope: Rope.ROPE] = { GGCaret.SitOn[ggData.caret, NIL]; IF feature = NIL THEN { Feedback.PutFHerald[ggData.feedback, oneLiner, "No near %g found.", [rope[selectRope]]]; } ELSE { SELECT feature.type FROM outline => { gone: OutlineDescriptor _ OutlineDeselectAux[feature, hitData, mode, ggData.scene]; sliceD: OutlineDescriptor _ NARROW[feature.shape]; IF gone#NIL AND gone.parts#NIL THEN Feedback.PutFHerald[ggData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[gone]]], [rope[" deselected"]]]; }; slice => { gone: SliceDescriptor _ SliceDeselectAux[feature, hitData, mode, ggData.scene]; sliceD: SliceDescriptor _ NARROW[feature.shape]; IF gone#NIL AND gone.parts#NIL THEN Feedback.PutFHerald[ggData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[gone]]], [rope[" deselected"]]]; }; ENDCASE => SIGNAL Problem [msg: IO.PutFR["Unexpected feature type for deselect %g.", [rope[selectRope]]]]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndDeselectJoint <<>> <> StartExtendSelectJoint: PUBLIC StartProc = { ggData.drag.extendMode _ joint; RETURN[StartExtendSelection[input, ggData, worldPt]]; }; StartExtendSelectSegment: PUBLIC StartProc = { ggData.drag.extendMode _ segment; RETURN[StartExtendSelection[input, ggData, worldPt]]; }; StartExtendSelectTraj: PUBLIC StartProc = { ggData.drag.extendMode _ traj; RETURN[StartExtendSelection[input, ggData, worldPt]]; }; StartExtendSelectTopLevel: PUBLIC StartProc = { ggData.drag.extendMode _ topLevel; RETURN[StartExtendSelection[input, ggData, worldPt]]; }; StartExtendSelection: PUBLIC StartProc = { IF NOT GGRefresh.EmptyOverlay[ggData] THEN ERROR; SaveSavedState[ggData]; -- must do this before any possible aborts occur ggData.drag.currentPoint _ worldPt; ggData.drag.transform _ ImagerTransformation.Scale[1.0]; DuringExtendSelection[NIL, ggData, worldPt]; }; DuringExtendSelection: PUBLIC MouseProc= { opRope: Rope.ROPE = "Extending to "; resultPoint: Point; feature: FeatureData; hitData: REF ANY; scene: Scene _ ggData.scene; IF GGState.GetExtendMode[ggData] = joint THEN [resultPoint, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.criticalR, ggData.hitTest.innerR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE] ELSE [resultPoint, feature, hitData] _ GGMultiGravity.StrictDistance[worldPt, ggData.hitTest.criticalR, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; <> SetCaretAttractorEndpoint[ggData, resultPoint, feature, hitData]; <> GGSelect.DeselectAll[scene, normal]; GGScene.RestoreSelections[scene]; IF feature#NIL THEN { SELECT ggData.drag.extendMode FROM joint, segment, segmentRange, traj, topLevel => DuringExtendSelectionFeedback[feature, hitData, resultPoint, ggData]; slice, none => NULL; -- NoOp ENDCASE => ERROR; } ELSE DescribeOperationOnNothing[ggData, opRope]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end DuringExtendSelection DuringExtendSelectionFeedback: PROC [feature: FeatureData, hitData: REF ANY, caretPt: Point, ggData: GGData] = { <> opRope: Rope.ROPE _ "Extending to "; SELECT ggData.drag.extendMode FROM joint, segment, traj, topLevel => [] _ SelectAndDescribeSlicePart[feature, hitData, ggData, ggData.drag.extendMode, opRope]; segmentRange => { IF feature.type = outline THEN { traj, trajToExtend: Traj; hitType: GGModelTypes.TrajPartType; segNum, cpNum, jointNum, segToExtendNum: INT; hitPoint: Point; [traj, hitType, segNum, cpNum, jointNum, hitPoint] _ GGOutline.UnpackHitData[hitData]; IF (hitType = segment OR hitType = controlPoint) THEN { [trajToExtend, segToExtendNum] _ GGOutline.UnpackOneSegmentDescriptorOld[ggData.drag.outlineToExtend]; IF trajToExtend = traj THEN { -- we're extending segments in the same trajectory seq: Sequence _ GGSequence.CreateFromSegments[traj, segToExtendNum, segNum]; [] _ GGSelect.SelectSequence[seq, ggData.scene, normal]; -- select current hit Feedback.PutFHerald[ggData.feedback, oneLiner, "%g %g", [rope[opRope]], [rope[GGDescribe.DescribeSegment[traj, segNum] ]] ]; } ELSE GOTO RegularSelectMechanism; } ELSE GOTO RegularSelectMechanism; } ELSE GOTO RegularSelectMechanism; EXITS RegularSelectMechanism => [] _ SelectAndDescribeSlicePart[feature, hitData, ggData, segment, opRope]; }; ENDCASE => ERROR; -- should have been weeded about before calling this Proc }; EndExtendSelection: PUBLIC MouseProc = { <> <> GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndExtendSelection END.