DIRECTORY Basics, Feedback, GGAlign, GGBasicTypes, GGCaret, GGDescribe, GGInterfaceTypes, GGModelTypes, GGMouseEvent, GGMultiGravity, GGOutline, GGRefresh, GGScene, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGState, GGUtility, GGWindow, GList, ImagerTransformation, InputFocus, IO, Menus, Rope; GGMouseEventImplB: CEDAR PROGRAM IMPORTS Feedback, GGAlign, GGCaret, GGDescribe, GGMouseEvent, GGMultiGravity, GGScene, GGOutline, GGRefresh, GGSelect, GGSequence, GGSlice, 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, 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 { sliceD: SliceDescriptor; 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; sliceD _ SelectSlicePart[feature, hitData, ggData, mode]; IF sliceD.slice.class.type=$Outline THEN SitTheCaret[ggData.caret, sliceD, hitData, mode] ELSE GGCaret.SitOn[ggData.caret, sliceD]; Feedback.AppendHerald[ggData.feedback, Rope.Concat[sliceD.slice.class.describe[sliceD], " selected"], oneLiner]; ggData.drag.sliceToExtend _ sliceD; }; 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: SliceDescriptor] = { SELECT feature.type FROM outline, 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, sliceD: SliceDescriptor, hitData: REF ANY, mode: SelectMode] = { SELECT mode FROM joint => GGCaret.SitOn[caret, sliceD]; segment, traj, topLevel => { IF sliceD.slice.class.type = $Outline THEN { jointParts: SliceParts; jointSeq: Sequence; jointD: SliceDescriptor; jointNum: NAT; traj: Traj; [jointNum, traj] _ GGOutline.NearestJointToHitData[hitData]; jointSeq _ GGSequence.CreateFromJoint[traj, jointNum]; jointParts _ GGOutline.PartsFromSequence[sliceD.slice, jointSeq]; jointD _ GGSlice.DescriptorFromParts[sliceD.slice, jointParts]; GGCaret.SitOn[caret, jointD]; } ELSE IF mode = traj OR mode = topLevel THEN GGCaret.SitOn[caret, NIL] ELSE GGCaret.SitOn[caret, sliceD]; -- is this needed ?? }; 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, 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.isEmptyParts[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.FindSelectedSlice[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.DeselectSlice[sliceD.slice, sliceD.parts, scene, normal]; IF NOT class.isEmptyParts[diffD] THEN GGSelect.SelectSlice[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, 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.UnpackOneSegmentDescriptor[ggData.drag.sliceToExtend]; 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. GGMouseEventImplB.mesa Last edited by Pier on May 14, 1987 4:17:01 pm PDT Contents: Once a mouse event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module. Bier, April 16, 1987 11:23:36 am PDT Kurlander July 17, 1986 2:40:45 pm PDT outline => { pos: Point; sliceD: OutlineDescriptor _ NARROW[shape]; jointD: OutlineDescriptor; [jointD, pos] _ sliceD.slice.class.closestJointToHitData[sliceD, mapPoint, hitData]; GGCaret.SetAttractor[ggData.caret, pos, jointD]; }; Selection Procs While a joint, segment, traj, or top level object is being selected, gravity is forced to be StrictDistance. The object bag should consist only of trajectories and slices. The caret is moved to the segment endpoint of the nearest segment or traj as appropriate or tracks the cursor if none are nearby. Feedback is in the form of highlighted joints. Use StrictDistance gravity except for SelectJoint. Put Caret on a joint (if any). Use the commented code for more explicit messages. GGMouseEvent.DescribeSelectionAction[ggData, feature, ggData.drag.selectState, "Selected"]; Deselect all. Dispatch to the proper EndSelect handler for final selection. EndSelectAuxOLDD: PROC [ggData: GGData, resultPoint: Point, feature: FeatureData, hitData: REF ANY, mode: SelectMode, opName: Rope.ROPE] = { Prepare for a subsequent Add operation and for Extend. IF feature = NIL THEN { GGCaret.SitOn[ggData.caret, NIL]; Feedback.PutFHerald[ggData.feedback, oneLiner, "No near %g found.", [rope[opName]]]; } ELSE { Make Selection and Prepare for Extend. 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 Prepare for a subsequent Add operation and for Extend. Make Selection and Prepare for Extend. Find out which point is being selected and highlight it. 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; }; SitTheCaretOLDD: 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; }; Deselection Procs Check overlay invariant and grab input focus. Measure caret coordinates. While a joint, cp, segment, traj, or top level object is being deselected, gravity is forced to be StrictDistance. The object bag should consist only of trajectories and slices. The caret is moved to the segment endpoint of the nearest segment or traj as appropriate or tracks the cursor if none are nearby. Feedback is in the form of removing highlighted joints or cps. Use StrictDistance gravity except for DeselectJoint. Reselect all. 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]] ]; }; Put Caret on a joint (if any). SetCaretAttractorEndpoint[ggData, resultPoint, feature]; GGWindow.NewCaretPos[ggData]; -- why not leave the caret alone for deselect? Bier, March 31, 1987 Clear the overlay plane. And Dispatch to the proper EndDeselect handler. 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"]]]; }; Extend selection procs. Put Caret on a joint (if any). Reselect all. depending on extend mode, check if feature is in that mode, then select the new feature. [trajToExtend, segToExtendNum] _ GGOutline.UnpackOneSegmentDescriptorOld[ggData.drag.outlineToExtend]; GGCaret.DoNotSit[ggData.caret]; -- simple but not always correct thing to do simply paint new selections directly Κ ˜Icode™Kšœ2™2™…Kšœ$™$K™&—K™šΟk ˜ Jšœ‘˜‘K˜K˜—šΟnœœ˜ JšœΒ˜ΙKšœ˜—˜Kšœœ#˜7Kšœ œ˜'Kšœœ˜%Kšœœ ˜5Kšœ œ ˜1Kšœœ˜'Kšœœ˜!Kšœ œ˜&Kšœ œ˜)Kšœ œ˜+Kšœ œœ˜%Kšœœœ˜3Kšœœ%˜?Kšœœ˜!Kšœœ"˜9Kšœœ˜!Kšœ œ˜+Kšœ œ˜'Kšœ œ˜'Kšœœ˜!Kšœœ ˜5Kšœœ#˜;Kšœœ˜3Kšœ œ˜+Kšœ œ˜+Kšœ œ˜)Kšœ œ˜-Kšœœ˜Kšœ œ˜%Kšœœ˜1Kšœœ˜#—K˜Kšžœœ œ˜4K˜šžœœ˜)Kšœ%˜%Kšœ˜K˜=K˜K˜—š žœœœ1œœ'œ˜ŒKšœ†˜†K˜K˜—š žœœœBœœ˜tš œ œœ.œœ˜LKšœœœ˜šœ˜™ Kšœ ™ Kšœœ™*Kšœ™KšœT™TKšœ0™0K™—šœ˜Kšœ ˜ Kšœœ˜(Kšœ˜KšœT˜TKšœ0˜0K˜—Kšœ1œ˜=—K˜—K˜K˜—K˜K™šžœœ˜&Kšœ ˜ Kšœ ˜ Kšœ œ˜#K˜K˜—šžœœ˜(Kšœ"˜"Kšœ ˜ Kšœ œ˜#K˜K˜—šžœœ˜+Kšœ˜Kšœ ˜ Kšœ œ˜#K˜K˜—šžœœ˜)Kšœ#˜#Kšœ ˜ Kšœ œ˜#K˜K˜—šžœœ%˜9Kšœœ œœ˜1K˜K˜K˜—šž œœ˜"K™ίKšœ œ˜!Kšœ˜Kšœ˜Kšœ œœ˜K˜šœ'˜-Kšœ³œ˜Ή—Kšœœ˜ Kšœ žœ(˜NKšœ Οb œ˜+Kšœ œœWœ,˜šKšœiœ œœ˜˜Kšœ˜K˜—šž œœ˜Kšœ˜Kšœ˜Kšœ œœ˜˜KšŸ2™2—šœ!˜'Kšœ³œ˜Ή—šœœ˜ KšŸ™—Kšœ žœ(˜NK™2Kšœ žœ7™[šœ˜KšŸ ™ —šœ+˜+KšŸ=™=—šœ˜#KšœM˜MKšœS˜SKšœP˜PKšœT˜TKšœœ˜—Kšœ Οc+˜KKšœ ˜K˜—š žœœEœœ!œ™ŒKšŸ6™6šœ œœ™Kšœœ™!KšœT™TK™—šœ™KšŸ&™&šœ™Kšœ(™(Kšœ1™1Kšœ&™&Kšœ.™.Kšœœ™—šœ™šœ ™ Kšœœ2™VKšœ3™3KšœœP™gKšœu™yKšœ'™'Kšœœ™ Kšœ™—™ Kšœœ2™Ršœ$œ™,Kšœ.™3K™—šœ™Kšœ œœœ™GKšœ%™)K™—Kšœp™pKšœœ™"Kšœ#™#K™—Kšœœ)™9—K™—Kšœmœ œœ™œKšœ ™K™—š ž œœEœœ!œ˜ˆKšŸ6™6šœ œœ˜Kšœœ˜!KšœT˜TK˜—šœ˜KšœŸ˜KšŸ&™&šœ˜Kšœ(˜(Kšœ1˜1Kšœ&˜&Kšœ.˜.Kšœœ˜—Kšœ9˜9Kšœ"œ1˜YKšœ%˜)Kšœp˜pKšœ#˜#K˜—Kšœmœ œœ˜œKšœ ˜K˜—š žœœœ!œœ1œ˜‰Kšœ œœ3˜Ešœœœ œ˜3K˜GK˜?Kšœ9˜@—Kšœ^˜^K˜—K˜š žœœœ!œœ$œ!˜K™8šœ˜™ Kšœœ)™BKšœ$™$KšœB™BKšœ?™?Kšœ™K™—šœ˜Kšœœ'˜