<> <> <> <> <> <<>> DIRECTORY GGBasicTypes, GGCaret, GGDescribe, GGError, GGGravity, GGInterfaceTypes, GGModelTypes, GGMouseEvent, GGMultiGravity, GGObjects, GGOutline, GGRefresh, GGSegmentTypes, GGSelect, GGSequence, GGTraj, GGUtility, GGVector, GGWindow, ImagerTransformation, InputFocus, Menus, Rope; GGMouseEventImplB: CEDAR PROGRAM IMPORTS GGCaret, GGDescribe, GGError, GGGravity, GGMouseEvent, GGMultiGravity, GGObjects, GGOutline, GGRefresh, GGSelect, GGSequence, GGTraj, GGVector, GGWindow, ImagerTransformation, InputFocus EXPORTS GGMouseEvent = BEGIN AlignmentPoint: TYPE = GGInterfaceTypes.AlignmentPoint; BoundBox: TYPE = GGModelTypes.BoundBox; Caret: TYPE = GGInterfaceTypes.Caret; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; FeatureData: TYPE = GGInterfaceTypes.FeatureData; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Joint: TYPE = GGModelTypes.Joint; MouseButton: TYPE = Menus.MouseButton; MouseProc: TYPE = GGMouseEvent.MouseProc; ObjectBag: TYPE = GGInterfaceTypes.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; SelectMode: TYPE = GGModelTypes.SelectMode; Segment: TYPE = GGSegmentTypes.Segment; Sequence: TYPE = GGModelTypes.Sequence; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; 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] = GGError.Problem; SaveSavedState: PROC [gargoyleData: GargoyleData] = { GGObjects.SaveSelections[gargoyleData.scene]; GGWindow.SaveCaretPos[gargoyleData]; GGCaret.Copy[from: gargoyleData.caret, to: gargoyleData.drag.savedCaret]; }; DescribeSelectionAction: PUBLIC PROC [gargoyleData: GargoyleData, feature: FeatureData, selectMode: SelectMode, action: Rope.ROPE] = { GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[action]], [rope[GGDescribe.DescribeFeature[feature, gargoyleData]]]]; }; SetCaretAttractorEndpoint: PUBLIC PROC [gargoyleData: GargoyleData, mapPoint: Point, feature: FeatureData] = { IF feature=NIL THEN GGCaret.SetAttractor[gargoyleData.caret, mapPoint, NIL] ELSE { resultType: ResultFeatureType _ feature.resultType; shape: REF ANY _ feature.shape; SELECT resultType FROM outline => { traj: Traj; hitType: GGModelTypes.TrajPartType; segNum, cpNum, jointNum: INT; hitPoint, thisPoint: Point; jointSeq: Sequence; jointParts: SliceParts; jointD: OutlineDescriptor; outlineD: OutlineDescriptor _ NARROW[shape]; [traj, hitType, segNum, cpNum, jointNum, hitPoint] _ GGOutline.UnpackHitData[feature.hitPart]; SELECT hitType FROM joint => { jointSeq _ GGSequence.CreateFromJoint[traj, jointNum]; thisPoint _ mapPoint; }; controlPoint => { jointSeq _ GGSequence.CreateFromControlPoint[traj, segNum, cpNum]; thisPoint _ mapPoint; }; segment => { success: BOOL; jointPoint, cpPoint: Point; seg: Segment _ GGTraj.FetchSegment[traj, segNum]; [jointNum, ----] _ GGOutline.NearestJointToHitData[feature.hitPart]; jointPoint _ GGTraj.FetchJointPos[traj, jointNum]; [cpPoint, cpNum, success] _ seg.class.closestControlPoint[seg, mapPoint, GGUtility.plusInfinity]; IF NOT success THEN { -- its a joint for sure jointSeq _ GGSequence.CreateFromJoint[traj, jointNum]; thisPoint _ jointPoint; } ELSE { -- could be a cp instead of a joint cpDist: REAL _ GGVector.DistanceSquared[cpPoint, mapPoint]; jointDist: REAL _ GGVector.DistanceSquared[jointPoint, mapPoint]; tisAJoint: BOOL _ jointDist <= cpDist; IF tisAJoint THEN { jointSeq _ GGSequence.CreateFromJoint[traj, jointNum]; thisPoint _ jointPoint; } ELSE { jointSeq _ GGSequence.CreateFromControlPoint[traj, segNum, cpNum]; thisPoint _ cpPoint; }; }; }; ENDCASE => ERROR; jointParts _ GGOutline.PartsFromSequence[outlineD.slice, jointSeq]; jointD _ NEW[OutlineDescriptorObj _ [outlineD.slice, jointParts]]; GGCaret.SetAttractor[gargoyleData.caret, thisPoint, jointD]; }; slice => { pos: Point; sliceD: SliceDescriptor _ NARROW[shape]; IF sliceD.slice.class.type = $Outline THEN ERROR Problem[msg: "Outlines are Slices"]; [pos, ----, ----, ----] _ sliceD.slice.class.closestPoint[sliceD, mapPoint, GGUtility.plusInfinity]; GGCaret.SetAttractor[gargoyleData.caret, pos, sliceD]; }; ENDCASE => GGCaret.SetAttractor[gargoyleData.caret, mapPoint, NIL]; }; }; <> StartDeselectJoint: PUBLIC StartProc = { <> <> gargoyleData.drag.selectState _ joint; <> <> StartDeselectAux[gargoyleData, worldPt, NIL]; DuringDeselect[NIL, gargoyleData, worldPt]; }; StartDeselectSegment: PUBLIC StartProc = { <> <> gargoyleData.drag.selectState _ segment; <> StartDeselectAux[gargoyleData, worldPt, NIL]; DuringDeselect[NIL, gargoyleData, worldPt]; }; StartDeselectTrajectory: PUBLIC StartProc = { <> <> gargoyleData.drag.selectState _ traj; <> <> StartDeselectAux[gargoyleData, worldPt, NIL]; DuringDeselect[NIL, gargoyleData, worldPt]; }; StartDeselectTopLevel: PUBLIC StartProc = { gargoyleData.drag.selectState _ topLevel; <> <> StartDeselectAux[gargoyleData, worldPt, NIL]; DuringDeselect[NIL, gargoyleData, worldPt]; }; StartDeselectAux: PROC [gargoyleData: GargoyleData, worldPt: Point, startBox: BoundBox] = { <> IF NOT GGRefresh.EmptyOverlay[gargoyleData] THEN ERROR; -- nothing on overlay [] _ InputFocus.SetInputFocus[gargoyleData.actionArea]; <> SaveSavedState[gargoyleData]; gargoyleData.drag.currentPoint _ worldPt; -- this line moved from individual Start code gargoyleData.drag.transform _ ImagerTransformation.Scale[1.0]; -- needed for DuringDeselect to work properly }; DuringDeselect: PUBLIC MouseProc = { <> resultPoint: Point; feature: FeatureData; <> gargoyleData.drag.currentPoint _ worldPt; 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]; <> SetCaretAttractorEndpoint[gargoyleData, resultPoint, feature]; DescribeSelectionAction[gargoyleData, feature, gargoyleData.drag.selectState, "Deselecting"]; <> GGObjects.RestoreSelections[gargoyleData.scene]; IF feature = NIL THEN { -- no near trajectories, do nothing } ELSE { DuringDeselectAux[feature, resultPoint, gargoyleData.scene, gargoyleData.drag.selectState]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end DuringDeselect DuringDeselectAux: PROC [feature: FeatureData, caretPt: Point, scene: Scene, mode: GGModelTypes.SelectMode] = { SELECT feature.resultType FROM outline => { [] _ OutlineDeselectAux[feature, mode, scene]; }; slice => { [] _ SliceDeselectAux[feature, mode, scene]; }; midpoint => NULL; -- temporarily ignore midpoints in bags. KAP. June 26, 1986 slopeLine, angleLine, distanceLine, intersectionPoint, radiiCircle, midpoint => ERROR; ENDCASE => ERROR; }; SliceDeselectAux: PROC [feature: FeatureData, mode: GGModelTypes.SelectMode, scene: Scene] RETURNS [deselectedParts: SliceParts] = { sliceD: SliceDescriptor _ GGSelect.FindSelectedSlice[NARROW[feature.shape, SliceDescriptor].slice, scene, normal]; IF sliceD#NIL THEN { class: SliceClass _ sliceD.slice.class; newP: SliceParts _ class.newParts[sliceD.slice, feature.hitPart, mode]; diffP: SliceParts _ class.differenceParts[sliceD.slice, sliceD.parts, newP]; GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, scene, normal]; IF NOT class.emptyParts[sliceD.slice, diffP] THEN GGSelect.SelectSlice[sliceD.slice, diffP, scene, normal]; deselectedParts _ newP; }; }; OutlineDeselectAux: PROC [feature: FeatureData, mode: GGModelTypes.SelectMode, scene: Scene] RETURNS [deselectedParts: SliceParts] = { sliceD: OutlineDescriptor _ GGSelect.FindSelectedOutline[NARROW[feature.shape, OutlineDescriptor].slice, scene, normal]; IF sliceD#NIL THEN { class: GGModelTypes.OutlineClass _ sliceD.slice.class; newP: SliceParts _ class.newParts[sliceD.slice, feature.hitPart, mode]; diffP: SliceParts _ class.differenceParts[sliceD.slice, sliceD.parts, newP]; GGSelect.DeselectOutline[sliceD.slice, sliceD.parts, scene, normal]; IF NOT class.emptyParts[sliceD.slice, diffP] THEN GGSelect.SelectOutline[sliceD.slice, diffP, scene, normal]; deselectedParts _ newP; }; }; EndDeselect: 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]; <> SetCaretAttractorEndpoint[gargoyleData, resultPoint, feature]; GGWindow.NewCaretPos[gargoyleData]; <> GGRefresh.MoveOverlayToBackground[gargoyleData]; <> SELECT gargoyleData.drag.selectState FROM joint => EndDeselectJoint[gargoyleData, resultPoint, feature]; segment => EndDeselectSegment[gargoyleData, resultPoint, feature]; traj => EndDeselectTrajectory[gargoyleData, resultPoint, feature]; topLevel => EndDeselectTopLevel[gargoyleData, resultPoint, feature]; ENDCASE => ERROR; gargoyleData.drag.selectState _ none; -- added to help DescribeFeature work. KAP. }; EndDeselectJoint: PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = { GGCaret.SitOn[gargoyleData.caret, NIL]; IF feature = NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "No near joint found.", oneLiner]; } ELSE { SELECT feature.resultType FROM outline => { gone: SliceParts _ OutlineDeselectAux[feature, joint, gargoyleData.scene]; sliceD: OutlineDescriptor _ NARROW[feature.shape]; IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]]; }; slice => { gone: SliceParts _ SliceDeselectAux[feature, joint, gargoyleData.scene]; sliceD: SliceDescriptor _ NARROW[feature.shape]; IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]]; }; ENDCASE => SIGNAL Problem [msg: "Unexpected feature type for deselect joint."]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndDeselectJoint EndDeselectSegment: PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = { GGCaret.SitOn[gargoyleData.caret, NIL]; IF feature = NIL THEN { -- do nothing GGError.AppendHerald[gargoyleData.feedback, "No near segment found.", oneLiner]; } ELSE { SELECT feature.resultType FROM outline => { gone: SliceParts _ OutlineDeselectAux[feature, segment, gargoyleData.scene]; sliceD: OutlineDescriptor _ NARROW[feature.shape]; IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]]; }; slice => { gone: SliceParts _ SliceDeselectAux[feature, segment, gargoyleData.scene]; sliceD: SliceDescriptor _ NARROW[feature.shape]; IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]]; }; ENDCASE => SIGNAL Problem [msg: "Unexpected feature type for deselect segment."]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndDeselectSegment EndDeselectTrajectory: PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = { GGCaret.SitOn[gargoyleData.caret, NIL]; IF feature = NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "No near trajectory found.", oneLiner]; } ELSE { SELECT feature.type FROM outline => { gone: SliceParts _ OutlineDeselectAux[feature, traj, gargoyleData.scene]; sliceD: OutlineDescriptor _ NARROW[feature.shape]; IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]]; }; slice => { gone: SliceParts _ SliceDeselectAux[feature, traj, gargoyleData.scene]; sliceD: SliceDescriptor _ NARROW[feature.shape]; IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]]; }; ENDCASE => SIGNAL Problem [msg: "Unexpected feature type for deselect trajectory."]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndDeselectTrajectory EndDeselectTopLevel: PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = { GGCaret.SitOn[gargoyleData.caret, NIL]; IF feature = NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "No near object found.", oneLiner]; } ELSE { SELECT feature.resultType FROM outline => { gone: SliceParts _ OutlineDeselectAux[feature, topLevel, gargoyleData.scene]; sliceD: OutlineDescriptor _ NARROW[feature.shape]; IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]]; }; slice => { gone: SliceParts _ SliceDeselectAux[feature, topLevel, gargoyleData.scene]; sliceD: SliceDescriptor _ NARROW[feature.shape]; IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]]; }; ENDCASE => SIGNAL Problem [msg: "Unexpected feature type for deselect top level."]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; <<>> <> StartExtendSelectJoint: PUBLIC StartProc = { gargoyleData.drag.extendMode _ joint; RETURN[StartExtendSelection[input, gargoyleData, worldPt]]; }; StartExtendSelectSegment: PUBLIC StartProc = { gargoyleData.drag.extendMode _ segment; RETURN[StartExtendSelection[input, gargoyleData, worldPt]]; }; StartExtendSelectTraj: PUBLIC StartProc = { gargoyleData.drag.extendMode _ traj; RETURN[StartExtendSelection[input, gargoyleData, worldPt]]; }; StartExtendSelectTopLevel: PUBLIC StartProc = { gargoyleData.drag.extendMode _ topLevel; RETURN[StartExtendSelection[input, gargoyleData, worldPt]]; }; StartExtendSelection: PUBLIC StartProc = { IF NOT GGRefresh.EmptyOverlay[gargoyleData] THEN ERROR; [] _ InputFocus.SetInputFocus[gargoyleData.actionArea]; SaveSavedState[gargoyleData]; -- must do this before any possible aborts occur gargoyleData.drag.currentPoint _ worldPt; gargoyleData.drag.transform _ ImagerTransformation.Scale[1.0]; DuringExtendSelection[NIL, gargoyleData, worldPt]; }; DuringExtendSelection: PUBLIC MouseProc= { resultPoint: Point; feature: FeatureData; IF gargoyleData.drag.extendMode = 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]; <> SetCaretAttractorEndpoint[gargoyleData, resultPoint, feature]; DescribeSelectionAction[gargoyleData, feature, gargoyleData.drag.extendMode, "Extending to"]; <> GGSelect.DeselectAll[gargoyleData.scene, normal]; -- MUST CLEAR OUT TRANSIENT SELECTIONS! GGObjects.RestoreSelections[gargoyleData.scene]; IF feature = NIL THEN { -- no near trajectories, do nothing } ELSE { SELECT gargoyleData.drag.extendMode FROM joint, segment, segmentRange, traj, topLevel => DuringExtendSelectionFeedback[feature, resultPoint, gargoyleData]; outline, slice, none => NULL; -- NoOp ENDCASE => ERROR; }; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end DuringExtendSelection DuringExtendSelectionFeedback: PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] = { <> SELECT gargoyleData.drag.extendMode FROM joint => GGMouseEvent.SelectJointOrCP[feature, caretPt, gargoyleData]; segment => GGMouseEvent.SelectSegment[feature, caretPt, gargoyleData]; segmentRange => { IF feature.resultType = outline THEN { traj, trajToExtend: Traj; hitType: GGModelTypes.TrajPartType; segNum, cpNum, jointNum, segToExtendNum: INT; hitPoint: Point; [traj, hitType, segNum, cpNum, jointNum, hitPoint] _ GGOutline.UnpackHitData[feature.hitPart]; IF (hitType = segment OR hitType = controlPoint) THEN { [trajToExtend, segToExtendNum] _ GGOutline.UnpackOneSegmentDescriptorOld[gargoyleData.drag.outlineToExtend]; IF trajToExtend = traj THEN { -- we're extending segments in the same trajectory seq: Sequence _ GGSequence.CreateFromSegments[traj, segToExtendNum, segNum]; [] _ GGSelect.SelectSequence[seq, gargoyleData.scene, normal]; -- select current hit } ELSE GOTO RegularSelectMechanism; } ELSE GOTO RegularSelectMechanism; } ELSE GOTO RegularSelectMechanism; EXITS RegularSelectMechanism => GGMouseEvent.SelectSegment[feature, caretPt, gargoyleData]; }; traj => GGMouseEvent.SelectTraj[feature: feature, caretPt: caretPt, gargoyleData: gargoyleData]; topLevel => GGMouseEvent.SelectTopLevel[feature: feature, caretPt: caretPt, gargoyleData: gargoyleData]; ENDCASE => ERROR; -- should have been weeded about before calling this Proc }; EndExtendSelection: PUBLIC MouseProc = { <> <> GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndExtendSelection END.