DIRECTORY Atom, Basics, CodeTimer, ColorTool, Feedback, FeedbackTypes, GGAlign, GGBasicTypes, GGCaret, GGDescribe, GGDragTypes, GGEvent, GGHistory, GGHistoryTypes, GGInterfaceTypes, GGModelTypes, GGMouseEvent, GGMultiGravity, GGOutline, GGParent, GGRefresh, GGRefreshTypes, GGScene, GGSegment, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGSliceOps, GGState, GGTraj, GGUserInput, GGUtility, GGWindow, Imager, ImagerTransformation, InputFocus, IO, Menus, PBasics, RealFns, Rope, Vectors2d; GGMouseEventImplB: CEDAR PROGRAM IMPORTS CodeTimer, ColorTool, Feedback, GGAlign, GGCaret, GGDescribe, GGEvent, GGHistory, GGMouseEvent, GGMultiGravity, GGOutline, GGParent, GGRefresh, GGScene, GGSegment, GGSelect, GGSequence, GGSlice, GGSliceOps, GGState, GGTraj, GGUtility, GGWindow, ImagerTransformation, IO, PBasics, Rope, Vectors2d EXPORTS GGMouseEvent, GGInterfaceTypes = BEGIN DragDataObj: PUBLIC TYPE = GGDragTypes.DragDataObj; AlignBag: TYPE = GGInterfaceTypes.AlignBag; AlignmentPoint: TYPE = GGInterfaceTypes.AlignmentPoint; BoundBox: TYPE = GGModelTypes.BoundBox; Caret: TYPE = GGInterfaceTypes.Caret; Color: TYPE = Imager.Color; DefaultData: TYPE = GGModelTypes.DefaultData; ExtendMode: TYPE = GGInterfaceTypes.ExtendMode; FeatureCycler: TYPE = GGInterfaceTypes.FeatureCycler; FeatureData: TYPE = GGModelTypes.FeatureData; MsgRouter: TYPE = FeedbackTypes.MsgRouter; GGData: TYPE = GGInterfaceTypes.GGData; HistoryEvent: TYPE = GGHistoryTypes.HistoryEvent; Joint: TYPE = GGModelTypes.Joint; MouseButton: TYPE = Menus.MouseButton; MouseProc: TYPE = GGMouseEvent.MouseProc; Point: TYPE = GGBasicTypes.Point; RefreshDataObj: PUBLIC TYPE = GGRefreshTypes.RefreshDataObj; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; SelectMode: TYPE = GGModelTypes.SelectMode; Sequence: TYPE = GGModelTypes.Sequence; Slice: TYPE = GGModelTypes.Slice; SliceClass: TYPE = GGModelTypes.SliceClass; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceParts: TYPE = GGModelTypes.SliceParts; StartProc: TYPE = GGMouseEvent.StartProc; TouchGroup: TYPE = GGSegmentTypes.TouchGroup; Traj: TYPE = GGModelTypes.Traj; TrajData: TYPE = GGModelTypes.TrajData; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajParts: TYPE = GGModelTypes.TrajParts; TrajPartType: TYPE = GGModelTypes.TrajPartType; TriggerBag: TYPE = GGAlign.TriggerBag; UserInputProc: TYPE = GGUserInput.UserInputProc; Vector: TYPE = GGBasicTypes.Vector; Problem: SIGNAL [msg: Rope.ROPE] = Feedback.Problem; SetCaretAttractorEndpoint: PUBLIC PROC [ggData: GGData, mapPoint: Point, normal: Vector, testPoint: Point, feature: FeatureData, hitData: REF ANY] = { IF feature=NIL THEN GGCaret.SetAttractor[ggData.caret, mapPoint, normal, NIL] ELSE { shape: REF ANY _ feature.shape; SELECT feature.type FROM slice => { pos: Point; sliceD: SliceDescriptor _ NARROW[shape]; jointD: SliceDescriptor; [jointD, pos, normal] _ GGSliceOps.ClosestJointToHitData[sliceD, mapPoint, testPoint, hitData]; IF Vectors2d.MagnitudeSquared[normal] = 0 THEN { normal _ [0, -1];}; GGCaret.SetAttractor[ggData.caret, pos, normal, jointD]; }; ENDCASE => GGCaret.SetAttractor[ggData.caret, mapPoint, normal, NIL]; }; }; SetStrokeColorRemote: PUBLIC PROC [ggData: GGData, sliceD: SliceDescriptor] RETURNS [doNormalBehavior: BOOL _ FALSE, done: BOOL _ FALSE] = { theirData: GGData _ GGState.GetGGInputFocus[]; theirScene: Scene; ourColor: Imager.Color; success: BOOL _ FALSE; IF theirData = NIL THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "SetStrokeColorRemote failed: Place input focus in a Gargoyle viewer"]; RETURN; } ELSE theirScene _ theirData.scene; [ourColor, success] _ GGSliceOps.GetStrokeColor[sliceD.slice, sliceD.parts]; IF success THEN { GGEvent.LineColorAux[theirData, ourColor, GGDescribe.ColorToRope[ourColor], TRUE, $Set]; SendColorToColorTool[ggData, ourColor]; } ELSE { Feedback.Append[ggData.router, oneLiner, $Complaint, "SetStrokeColorRemote: Select an object with a unique stroke color"]; }; }; SetFillColorRemote: PUBLIC PROC [ggData: GGData, sliceD: SliceDescriptor] RETURNS [doNormalBehavior: BOOL _ FALSE, done: BOOL _ FALSE] = { theirData: GGData _ GGState.GetGGInputFocus[]; theirScene: Scene; ourColor: Imager.Color; success: BOOL _ FALSE; IF theirData = NIL THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "SetFillColorRemote failed: Place input focus in a Gargoyle viewer"]; RETURN; } ELSE theirScene _ theirData.scene; [ourColor, success] _ GGSliceOps.GetFillColor[sliceD.slice, sliceD.parts]; IF success THEN { GGEvent.AreaColorAux[theirData, ourColor, GGDescribe.ColorToRope[ourColor], TRUE, $Set]; SendColorToColorTool[ggData, ourColor]; } ELSE { Feedback.Append[ggData.router, oneLiner, $Complaint, "SetFillColorRemote failed: Select an object with a unique fill color"]; }; }; LocalSymbols: TYPE = REF LocalSymbolsObj; LocalSymbolsObj: TYPE = RECORD [ sliceD: SliceDescriptor, rotation: ImagerTransformation.Transformation, ggData: GGData, currentEvent: HistoryEvent ]; ColorToolIsBound: PROC [ggData: GGData] RETURNS [BOOL _ FALSE] ~ { RETURN[PBasics.IsBound[LOOPHOLE[ColorTool.GetColor]]]; }; SendColorToColorTool: PROC [ggData: GGData, color: Color] = { IF ColorToolIsBound[ggData] THEN { IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "NIL fill colornot sent to ColorTool"] ELSE { noColorTool: BOOL _ FALSE; ColorTool.SetColor[color, NIL ! ColorTool.NoColorToolViewer => { noColorTool _ TRUE; CONTINUE }]; }; }; }; StartSelect: PUBLIC StartProc = { SELECT input.first FROM $StartSelectJoint => ggData.drag.selectState _ joint; $StartSelectSegment => ggData.drag.selectState _ segment; $StartSelectTrajectory => ggData.drag.selectState _ traj; $StartSelectTopLevel => ggData.drag.selectState _ topLevel; ENDCASE => ERROR; IF NOT GGRefresh.EmptyOverlay[ggData] THEN ERROR; GGMouseEvent.SaveSavedState[ggData]; DuringSelect[NIL, ggData, worldPt]; }; DuringSelect: PUBLIC MouseProc = { opRope: Rope.ROPE = "Selecting"; resultPoint: Point; normal: Vector; feature: FeatureData; hitData: REF ANY; CodeTimer.StartInt[$DuringSelect, $Gargoyle]; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, caret: TRUE, selectedCPs: TRUE, attractor: TRUE]; SELECT GGState.GetSelectMode[ggData] FROM joint => [resultPoint, normal, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE]; segment, segmentRange => [resultPoint, normal, feature, hitData] _ GGMultiGravity.LinesPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; traj, topLevel, slice => [resultPoint, normal, feature, hitData] _ GGMultiGravity.FacesPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; none => { resultPoint _ worldPt; normal _ [0, -1]; feature _ NIL; hitData _ NIL; }; ENDCASE => ERROR; GGMouseEvent.SetCaretAttractorEndpoint[ggData, resultPoint, normal, worldPt, feature, hitData]; GGSelect.DeselectAll[ggData.scene, normal]; IF feature#NIL THEN [] _ SelectAndDescribeSlicePart[feature, hitData, ggData, ggData.drag.selectState, opRope] ELSE Feedback.PutF[ggData.router, oneLiner, $DuringMouse, "%g nothing", [rope[opRope]]]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; CodeTimer.StopInt[$DuringSelect, $Gargoyle]; }; -- end DuringSelect EndSelect: PUBLIC MouseProc = { resultPoint: Point; normal: Vector; feature: FeatureData; hitData: REF ANY; featureCycler: GGInterfaceTypes.FeatureCycler; SELECT GGState.GetSelectMode[ggData] FROM joint => featureCycler _ GGMultiGravity.PointsPreferredCycler[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE]; segment => featureCycler _ GGMultiGravity.LinesPreferredCycler[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; ENDCASE => featureCycler _ GGMultiGravity.FacesPreferredCycler[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; GGState.SetSelectionCycler[ggData, featureCycler]; [resultPoint, normal, feature, hitData] _ GGMultiGravity.FirstFeature[featureCycler]; GGMouseEvent.SetCaretAttractorEndpoint[ggData, resultPoint, normal, worldPt, 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; GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; -- The Start and During will already have updated the screen properly }; -- end EndSelect SelectFromFeature: PUBLIC PROC [ggData: GGData, testPoint: Point, point: Point, normal: Vector, feature: FeatureData, hitData: REF ANY] = { selectMode: SelectMode _ GGState.GetSelectMode[ggData]; IF selectMode = none THEN GOTO NoSelectMode; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, caret: TRUE, selectedParts: TRUE, selectedCPs: TRUE, attractor: TRUE]; SetCaretAttractorEndpoint[ggData, point, normal, point, feature, hitData]; GGWindow.NewCaretPos[ggData]; GGSelect.DeselectAll[ggData.scene, normal]; SELECT selectMode FROM joint => EndSelectAux[ggData, point, feature, hitData, joint, "joint"]; segment => EndSelectAux[ggData, point, feature, hitData, segment, "segment"]; traj => EndSelectAux[ggData, point, feature, hitData, traj, "trajectory"]; topLevel => EndSelectAux[ggData, point, feature, hitData, topLevel, "object"]; ENDCASE => ERROR; GGWindow.RestoreScreenAndInvariants[paintAction: $EndSelect, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; EXITS NoSelectMode => { Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectFromFeature failed: unknown selection grain. Make a selection first."]; }; }; 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.PutF[ggData.router, oneLiner, $Feedback, "No near %g found.", [rope[opName]]]; } ELSE { SELECT mode FROM joint => GGState.SetExtendMode[ggData, joint]; segment => GGState.SetExtendMode[ggData, segmentRange]; traj => GGState.SetExtendMode[ggData, traj]; topLevel => GGState.SetExtendMode[ggData, topLevel]; ENDCASE => ERROR; BEGIN sliceD: SliceDescriptor _ SelectSlicePart[feature, hitData, ggData, mode]; featureCycler: FeatureCycler _ GGState.GetSelectionCycler[ggData]; cycleCount: NAT _ featureCycler.count; sliceType: ATOM _ GGSliceOps.GetType[sliceD.slice]; SitTheCaret[ggData.caret, sliceD, hitData, mode]; GGState.SetSliceToExtend[ggData, sliceD]; IF cycleCount > 1 THEN Feedback.PutF[ggData.router, oneLiner, $Feedback, Rope.Concat[GGSliceOps.Describe[sliceD], " selected (%g more)"], [integer[cycleCount-1]]] ELSE Feedback.Append[ggData.router, oneLiner, $Feedback, Rope.Concat[GGSliceOps.Describe[sliceD], " selected"]]; END; }; }; -- end EndSelectAux SelectAndDescribeSlicePart: PROC [feature: FeatureData, hitData: REF ANY, ggData: GGData, mode: SelectMode, opRope: Rope.ROPE] RETURNS [selectedD: SliceDescriptor]= { selectedD _ SelectSlicePart[feature, hitData, ggData, mode]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "%g %g", [rope[opRope]], [rope[GGSliceOps.Describe[selectedD]]] ]; }; SelectSlicePart: PUBLIC PROC [feature: FeatureData, hitData: REF ANY, ggData: GGData, mode: SelectMode] RETURNS [selectedD: SliceDescriptor] = { SELECT feature.type FROM slice => { slice: Slice _ NARROW[feature.shape, SliceDescriptor].slice; selectedD _ GGSliceOps.NewParts[slice, hitData, mode]; GGSelect.SelectSlice[selectedD, ggData.scene, normal]; }; slopeLine, angleLine, distanceLine, intersectionPoint, radiiCircle, midpoint => ERROR; ENDCASE => ERROR Problem[msg: "unimplemented result type"]; }; SitTheCaret: PROC [caret: Caret, sliceD: SliceDescriptor, hitData: REF ANY, mode: SelectMode] = { childD: SliceDescriptor _ NIL; IF GGParent.IsParent[sliceD.slice] THEN { childD _ GGParent.FirstIncludedChild[sliceD.slice, sliceD.parts, leaf, $Traj]; }; IF childD = NIL THEN GGCaret.SitOn[caret, NIL] ELSE { SELECT mode FROM joint => { GGCaret.SitOn[caret, sliceD]; }; segment, traj, topLevel => { jointD: SliceDescriptor; jointD _ GGSliceOps.ClosestJointToHitData[sliceD, caret.point, caret.point, hitData].jointD; GGCaret.SitOn[caret, jointD]; }; ENDCASE => ERROR; }; }; StartDeselect: PUBLIC StartProc = { SELECT input.first FROM $StartDeselectJoint => ggData.drag.selectState _ joint; $StartDeselectSegment => ggData.drag.selectState _ segment; $StartDeselectTrajectory => ggData.drag.selectState _ traj; $StartDeselectTopLevel => ggData.drag.selectState _ topLevel; ENDCASE => ERROR; IF NOT GGRefresh.EmptyOverlay[ggData] THEN ERROR; -- nothing on overlay GGMouseEvent.SaveSavedState[ggData]; ggData.drag.transform _ ImagerTransformation.Scale[1.0]; -- needed for DuringDeselect to work properly DuringDeselect[NIL, ggData, worldPt]; }; DuringDeselect: PUBLIC MouseProc = { opRope: Rope.ROPE = "Deselecting"; resultPoint: Point; normal: Vector; feature: FeatureData; hitData: REF ANY; ggData.drag.currentPoint _ worldPt; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, caret: TRUE, selectedParts: TRUE, selectedCPs: TRUE, attractor: TRUE]; SELECT GGState.GetSelectMode[ggData] FROM joint => [resultPoint, normal, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE]; segment => [resultPoint, normal, feature, hitData] _ GGMultiGravity.LinesPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; ENDCASE => [resultPoint, normal, feature, hitData] _ GGMultiGravity.LinesPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; GGScene.RestoreSelections[ggData.scene]; IF feature#NIL THEN DuringDeselectAux[feature, hitData, resultPoint, ggData, ggData.drag.selectState, opRope] ELSE Feedback.PutF[ggData.router, oneLiner, $DuringMouse, "%g nothing", [rope[opRope]]]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; -- end DuringDeselect DuringDeselectAux: PROC [feature: FeatureData, hitData: REF ANY, caretPt: Point, ggData: GGData, mode: GGModelTypes.SelectMode, opRope: Rope.ROPE] = { description: Rope.ROPE; SELECT feature.type FROM slice => { deselectedD: SliceDescriptor _ SliceDeselectAux[feature, hitData, mode, ggData.scene]; description _ IF deselectedD=NIL THEN "nothing" ELSE GGSliceOps.Describe[deselectedD]; Feedback.PutF[ggData.router, oneLiner, $DuringMouse, "%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] = { shapeD: SliceDescriptor _ NARROW[feature.shape]; sliceD: SliceDescriptor _ GGSelect.FindSelectedSlice[shapeD.slice, normal]; IF sliceD#NIL THEN { newD: SliceDescriptor _ GGSliceOps.NewParts[sliceD.slice, hitData, mode]; diffD: SliceDescriptor _ GGSliceOps.DifferenceParts[sliceD, newD]; GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, scene, normal]; IF NOT GGSliceOps.IsEmptyParts[diffD] THEN GGSelect.SelectSlice[diffD, scene, normal]; deselectedD _ newD; } ELSE deselectedD _ shapeD; -- must have already deselected the slice DuringDeselect }; EndDeselect: PUBLIC MouseProc = { resultPoint: Point; normal: Vector; feature: FeatureData; hitData: REF ANY; SELECT GGState.GetSelectMode[ggData] FROM joint => [resultPoint, normal, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE]; segment => [resultPoint, normal, feature, hitData] _ GGMultiGravity.LinesPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; ENDCASE => [resultPoint, normal, feature, hitData] _ GGMultiGravity.LinesPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, 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; GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; -- The Start and During will already have updated the screen properly 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.PutF[ggData.router, oneLiner, $Feedback, "No near %g found", [rope[selectRope]]]; } ELSE { SELECT feature.type FROM slice => { gone: SliceDescriptor _ SliceDeselectAux[feature, hitData, mode, ggData.scene]; IF gone#NIL AND gone.parts#NIL THEN Feedback.PutF[ggData.router, oneLiner, $Feedback, "%g %g", [rope[GGSliceOps.Describe[gone]]], [rope["deselected"]]]; }; ENDCASE => SIGNAL Problem [msg: IO.PutFR["Unexpected feature type for deselect %g.", [rope[selectRope]]]]; }; }; StartExtendSelect: PUBLIC StartProc = { SELECT input.first FROM $StartExtSelectJoint => GGState.SetExtendMode[ggData, joint]; $StartExtSelectSegment => GGState.SetExtendMode[ggData, segment]; $StartExtSelectTrajectory => GGState.SetExtendMode[ggData, traj]; $StartExtSelectTopLevel => GGState.SetExtendMode[ggData, topLevel]; ENDCASE => ERROR; RETURN StartExtendSelection[input, ggData, worldPt]; }; StartExtendSelection: PUBLIC StartProc = { IF NOT GGRefresh.EmptyOverlay[ggData] THEN ERROR; GGMouseEvent.SaveSavedState[ggData]; -- must do this before any possible aborts occur ggData.drag.currentPoint _ worldPt; ggData.drag.transform _ ImagerTransformation.Scale[1.0]; DuringExtendSelection[LIST[$StartExtendSelection], ggData, worldPt]; }; DuringExtendSelection: PUBLIC MouseProc= { opRope: Rope.ROPE = IF input.first=$EndExtendSelection THEN "Extended to" ELSE "Extending to"; resultPoint: Point; normal: Vector; feature: FeatureData; hitData: REF ANY; extendMode: ExtendMode _ GGState.GetExtendMode[ggData]; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, caret: TRUE, selectedCPs: TRUE, attractor: TRUE]; SELECT extendMode FROM joint => [resultPoint, normal, feature, hitData] _ GGMultiGravity.PointsPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData, FALSE]; segment, segmentRange => [resultPoint, normal, feature, hitData] _ GGMultiGravity.LinesPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; traj, topLevel, slice => [resultPoint, normal, feature, hitData] _ GGMultiGravity.FacesPreferred[worldPt, ggData.hitTest.t, GGAlign.emptyAlignBag, ggData.hitTest.sceneBag, ggData]; none => { resultPoint _ worldPt; normal _ [0, -1]; feature _ NIL; hitData _ NIL; }; ENDCASE => ERROR; SetCaretAttractorEndpoint[ggData, resultPoint, normal, worldPt, feature, hitData]; GGSelect.DeselectAll[ggData.scene, normal]; GGScene.RestoreSelections[ggData.scene]; IF feature#NIL THEN { SELECT extendMode FROM joint, segment, segmentRange, traj, topLevel => DuringExtendSelectionFeedback[feature, hitData, resultPoint, ggData, opRope]; slice, none => NULL; -- NoOp ENDCASE => ERROR; } ELSE Feedback.PutF[ggData.router, oneLiner, $DuringMouse, "%g nothing", [rope[opRope]]]; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; -- end DuringExtendSelection DuringExtendSelectionFeedback: PROC [feature: FeatureData, hitData: REF ANY, caretPt: Point, ggData: GGData, opRope: Rope.ROPE] = { extendMode: ExtendMode _ GGState.GetExtendMode[ggData]; SELECT extendMode FROM joint, segment, traj, topLevel => [] _ SelectAndDescribeSlicePart[feature, hitData, ggData, extendMode, opRope]; segmentRange => { IF ISTYPE[feature.shape, SliceDescriptor] THEN { sliceD: SliceDescriptor _ NARROW[feature.shape]; -- clumsy code traj: Traj; trajToExtend: SliceDescriptor; hitType: GGModelTypes.TrajPartType; segNum, cpNum, jointNum, segToExtendNum: INT; hitPoint: Point; SELECT GGSliceOps.GetType[sliceD.slice] FROM $Outline => [traj, hitType, segNum, cpNum, jointNum, hitPoint] _ GGOutline.UnpackHitData[hitData]; $Traj => { traj _ sliceD.slice; [hitType, segNum, cpNum, jointNum, hitPoint] _ GGTraj.UnpackHitData[hitData]; }; ENDCASE => GOTO RegularSelectMechanism; IF (hitType = segment OR hitType = controlPoint) THEN { [trajToExtend, segToExtendNum] _ GGOutline.UnpackOneSegmentDescriptor[GGState.GetSliceToExtend[ggData]]; IF trajToExtend#NIL AND trajToExtend.slice = traj THEN { -- we're extending segments in the same trajectory seq: TrajParts _ GGSequence.CreateFromSegments[NARROW[traj.data], segToExtendNum, segNum]; GGSelect.SelectSlice[GGSlice.DescriptorFromParts[traj, seq], ggData.scene, normal]; -- select current hit Feedback.PutF[ggData.router, oneLiner, $DuringMouse, "%g %g", [rope[opRope]], [rope[GGUtility.DescribeSegment[traj, segNum] ]] ]; } ELSE { -- you extended to a different traj GGState.SetSliceToExtend[ggData, SelectAndDescribeSlicePart[feature, hitData, ggData, segment, opRope]]; } } 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 = { DuringExtendSelection[LIST[$EndExtendSelection], ggData, worldPt]; GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; -- During should have made the screen OK }; -- end EndExtendSelection StartAddBezier: PUBLIC StartProc = { IF GGCaret.Exists[ggData.caret] THEN { caret: Caret; oldTraj, newTraj: Traj; ancestor, oldOutline: Slice; trajEnd: TrajEnd; newNormalD, newHotD: SliceDescriptor; GGHistory.NewCapture["Add Bezier spline", ggData]; -- capture scene BEFORE UPDATE caret _ ggData.caret; GGMouseEvent.SaveSavedState[ggData]; -- used for abort [oldTraj, newTraj, trajEnd, ancestor] _ UpdateSceneForAddBezier[ggData.scene, worldPt, caret, ggData.defaults, ggData]; oldOutline _ IF oldTraj=NIL THEN NIL ELSE GGParent.GetTopLevelAncestor[oldTraj]; [newNormalD, newHotD] _ GGMouseEvent.UpdateSelectionsForAdd[ggData.scene, oldTraj, newTraj, trajEnd]; GGMouseEvent.UpdateCaretForAdd[caret, ancestor, newNormalD, worldPt]; [] _ GGAlign.UpdateBagsForAdd[oldOutline, newNormalD, trajEnd, ggData]; -- should be ok [] _ GGMouseEvent.StartMotion[ggData: ggData, opName: "add", bagType: $Drag, worldPt: worldPt, saveState: FALSE, needAnchor: FALSE, backgroundOK: TRUE]; -- boundbox may be wrong DuringBezierDrag[NIL, ggData, worldPt]; -- draw it the first time } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "Start Bezier failed: caret required for adding new Bezier"]; }; UpdateSceneForAddBezier: PROC [scene: Scene, worldPt: Point, caret: Caret, defaults: DefaultData, ggData: GGData] RETURNS [oldTraj, newTraj: Traj, trajEnd: TrajEnd, newOutline: Slice] = { caretPoint, newCaretPoint: Point; jointNum: NAT; newSeg, extendFromSeg, newBezier: Segment; chair: SliceDescriptor; thisTraj: SliceDescriptor; thisTrajParts: TrajParts; thisTrajData: TrajData; thisOutlineSlice: Slice; addToBezier: BOOL _ FALSE; sliceDesc: SliceDescriptor _ GGScene.FirstSelectedSlice[scene, leaf, normal, $Outline]; caretPoint _ GGCaret.GetPoint[caret]; newCaretPoint _ GGMouseEvent.DragTheCaret[worldPt, ggData, "Dragging:"]; IF sliceDesc # NIL THEN { -- otherwise nothing selected. thisOutlineSlice _ sliceDesc.slice; thisTraj _ GGParent.FirstIncludedChild[sliceDesc.slice, sliceDesc.parts, first, $Traj]; thisTrajParts _ NARROW[thisTraj.parts]; thisTrajData _ NARROW[thisTraj.slice.data]; IF thisTrajData.role = open AND GGSequence.ContainsJoint[thisTrajParts, 0] THEN { IF GGTraj.FetchSegment[thisTraj.slice, 0].class.type = $Bezier THEN { trajEnd _ lo; addToBezier _ TRUE; }; } ELSE { IF thisTrajData.role = open AND GGSequence.ContainsJoint[thisTrajParts, GGTraj.HiJoint[thisTraj.slice]] THEN { IF GGTraj.FetchSegment[thisTraj.slice, GGTraj.HiSegment[thisTraj.slice]].class.type = $Bezier THEN { trajEnd _ hi; addToBezier _ TRUE; }; }; }; }; IF addToBezier AND ggData.drag.editConstraints # none THEN { -- Lay down a new Bezier and a tangent guide. oldCtrlPt, newCtrlPt: Point; oldTraj _ newTraj _ thisTraj.slice; -- the traj that the Bezier belongs to. extendFromSeg _ GGTraj.FetchSegment[newTraj, IF trajEnd=lo THEN 0 ELSE GGTraj.HiSegment[newTraj]]; IF trajEnd = lo THEN { oldCtrlPt _ extendFromSeg.class.controlPointGet[extendFromSeg, 0]; newCtrlPt _ Vectors2d.Add[extendFromSeg.lo, Vectors2d.VectorFromPoints[oldCtrlPt, extendFromSeg.lo]]; newBezier _ GGSegment.MakeBezier[extendFromSeg.lo, newCtrlPt, newCaretPoint, newCaretPoint, NIL]; -- by the lo in AddSegment. } ELSE { oldCtrlPt _ extendFromSeg.class.controlPointGet[extendFromSeg, 1]; newCtrlPt _ Vectors2d.Add[extendFromSeg.hi, Vectors2d.VectorFromPoints[oldCtrlPt, extendFromSeg.hi]]; newBezier _ GGSegment.MakeBezier[extendFromSeg.hi, newCtrlPt, newCaretPoint, newCaretPoint, NIL]; }; newSeg _ GGSegment.MakeLine[newCaretPoint, worldPt, NIL]; -- ctrl tangent. GGSegment.SetDefaults[newSeg, defaults]; GGSegment.CopyLooks[extendFromSeg, newBezier]; newSeg.strokeWidth _ 1; [] _ GGTraj.AddSegment[newTraj, trajEnd, newBezier, lo]; [] _ GGTraj.AddSegment[newTraj, trajEnd, newSeg, lo]; ggData.drag.bezierDrag.draggingBezier _ TRUE; ggData.drag.bezierDrag.trajEnd _ trajEnd; ggData.drag.bezierDrag.bezierNum _ IF trajEnd=lo THEN 1 ELSE GGTraj.HiSegment[newTraj] - 1; ggData.drag.bezierDrag.traj _ newTraj; ggData.drag.bezierDrag.outlineSlice _ thisOutlineSlice; newOutline _ thisOutlineSlice; -- that the Bezier was in. } ELSE { -- We are not adding to a Bezier in constrained mode, so can only add first tangent guide. newSeg _ GGSegment.MakeLine[caretPoint, worldPt, NIL]; -- maybe drag caret first!!!? GGSegment.SetDefaults[newSeg, defaults]; newSeg.strokeWidth _ 1; IF GGCaret.SittingOnEnd[caret] THEN { -- Extending a Traj [chair, newTraj, jointNum] _ GGMouseEvent.SafelyGetCaretTraj[caret]; oldTraj _ newTraj; trajEnd _ SELECT jointNum FROM 0 => lo, GGTraj.HiJoint[newTraj] => hi, ENDCASE => ERROR; extendFromSeg _ GGTraj.FetchSegment[newTraj, IF trajEnd=lo THEN 0 ELSE GGTraj.HiSegment[newTraj]]; [] _ GGTraj.AddSegment[newTraj, trajEnd, newSeg, lo]; newOutline _ chair.slice; } ELSE { -- create a new traj. oldTraj _ NIL; trajEnd _ hi; newTraj _ GGTraj.CreateTraj[caretPoint]; GGSliceOps.SetStrokeJoint[newTraj, NIL, defaults.strokeJoint, NIL]; [] _ GGTraj.AddSegment[newTraj, trajEnd, newSeg, lo]; newOutline _ GGOutline.CreateOutline[newTraj, defaults.fillColor]; GGScene.AddSlice[scene, newOutline, -1]; }; ggData.drag.bezierDrag.trajEnd _ trajEnd; -- here used to track tangent. ggData.drag.bezierDrag.bezierNum _ IF trajEnd=lo THEN 0 ELSE GGTraj.HiSegment[newTraj]; ggData.drag.bezierDrag.traj _ newTraj; ggData.drag.bezierDrag.outlineSlice _ newOutline; }; }; DuringBezierDrag: PUBLIC MouseProc = { totalDragVector: Vector; mapPoint: Point; mapPoint _ GGMouseEvent.DragTheCaret[worldPt, ggData, "Dragging:"]; totalDragVector _ Vectors2d.Sub[mapPoint, ggData.drag.startPoint]; ggData.drag.transform _ ImagerTransformation.Translate[[totalDragVector.x, totalDragVector.y]]; IF ggData.drag.bezierDrag.draggingBezier THEN { newCP: Point; dragCP: Vector; bezier: Segment _ GGTraj.FetchSegment[ggData.drag.bezierDrag.traj, ggData.drag.bezierDrag.bezierNum]; IF ggData.drag.bezierDrag.trajEnd = lo THEN { dragCP _ Vectors2d.Sub[mapPoint, bezier.lo]; newCP _ Vectors2d.Sub[bezier.lo, dragCP] } ELSE { dragCP _ Vectors2d.Sub[mapPoint, bezier.hi]; newCP _ Vectors2d.Sub[bezier.hi, dragCP]; }; GGSegment.BZControlPointMovedTo[bezier, newCP, IF ggData.drag.bezierDrag.trajEnd = lo THEN 0 ELSE 1]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $DuringDrag, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; -- end DuringBezierDrag ContinueBezierAdd: PUBLIC StartProc = { bezierSetCP, bezierSetJoint, caretPoint, newCaretPoint: Point; trajEnd: TrajEnd; extendFromSeg, newBezier, newSeg: Segment; oldTraj: Traj _ ggData.drag.bezierDrag.traj; tangentSeg: Segment; thisTraj: Traj; hiSegNum: NAT _ GGTraj.HiSegment[oldTraj]; priority: INT; newNormal, newHot: Sequence; delSeq: TrajParts; newOutlines: LIST OF Slice; thisOutlineSlice, oldOutlineSlice: Slice; thisOutline: GGOutline.OutlineData; ancestorD: SliceDescriptor; GGMouseEvent.TransformObjectsAfterMove[ggData.scene, ggData.drag.transform, ggData.drag.editConstraints, NIL]; -- update the tangent line. don't try to record undoable transforms here. A capture event is the current event. GGHistory.PushCurrent[ggData]; -- push captured history event onto history list GGRefresh.MoveOverlayToBackground[ggData]; GGWindow.NewCaretPos[ggData]; GGMouseEvent.SaveSavedState[ggData]; -- used for abort newCaretPoint _ GGMouseEvent.DragTheCaret[worldPt, ggData, "Dragging:"]; -- use Gravity for now. caretPoint _ GGCaret.GetPoint[ggData.caret]; IF ggData.drag.bezierDrag.draggingBezier THEN { IF ggData.drag.bezierDrag.trajEnd = hi THEN tangentSeg _ GGTraj.FetchSegment[oldTraj, ggData.drag.bezierDrag.bezierNum + 1] ELSE tangentSeg _ GGTraj.FetchSegment[oldTraj, 0]; } ELSE tangentSeg _ GGTraj.FetchSegment[oldTraj, ggData.drag.bezierDrag.bezierNum]; IF ggData.drag.bezierDrag.trajEnd = hi THEN { trajEnd _ hi; bezierSetJoint _ tangentSeg.lo; bezierSetCP _ tangentSeg.hi; IF hiSegNum # 0 THEN { extendFromSeg _ GGTraj.FetchSegment[oldTraj, hiSegNum -1]; }; } ELSE { trajEnd _ lo; bezierSetJoint _ tangentSeg.hi; bezierSetCP _ tangentSeg.lo; IF hiSegNum # 0 THEN { extendFromSeg _ GGTraj.FetchSegment[oldTraj, 1]; }; }; oldOutlineSlice _ ggData.drag.bezierDrag.outlineSlice; priority _ GGScene.GetPriority[scene: ggData.scene, slice: oldOutlineSlice]; newBezier _ GGSegment.MakeBezier[bezierSetJoint, bezierSetCP, newCaretPoint, newCaretPoint, NIL]; newSeg _ GGSegment.MakeLine[newCaretPoint, worldPt, NIL]; IF hiSegNum # 0 THEN { -- The traj contains more than just control vector. GGSegment.CopyLooks[extendFromSeg, newBezier]} ELSE GGSegment.SetDefaults[newBezier, ggData.defaults]; GGSegment.SetDefaults[newSeg, ggData.defaults]; newSeg.strokeWidth _ 1; delSeq _ GGSequence.LastSegAndJoint[NARROW[ggData.drag.bezierDrag.traj.data], ggData.drag.bezierDrag.trajEnd]; -- the tangent segment. newOutlines _ GGScene.DeleteSequence[GGSlice.DescriptorFromParts[ggData.drag.bezierDrag.traj, delSeq], ggData.scene].newOutlines; ancestorD _ GGParent.TopLevelDescriptorFromChildDescriptor[GGSlice.DescriptorFromParts[ggData.drag.bezierDrag.traj, delSeq]]; IF newOutlines = NIL THEN { -- Only a control vector in this outline. thisTraj _ GGTraj.CreateTraj[newBezier.lo]; thisOutlineSlice _ GGOutline.CreateOutline[thisTraj, ggData.defaults.fillColor]; GGSliceOps.SetStrokeJoint[thisTraj, NIL, ggData.defaults.strokeJoint, NIL]; [] _ GGTraj.AddSegment[thisTraj, trajEnd, newBezier, lo]; [] _ GGTraj.AddSegment[thisTraj, trajEnd, newSeg, lo]; GGScene.AddSlice[ggData.scene, thisOutlineSlice, priority]; } ELSE { thisOutlineSlice _ newOutlines.first; thisOutline _ NARROW[thisOutlineSlice.data]; thisTraj _ thisOutline.children.first; [] _ GGTraj.AddSegment[thisTraj, trajEnd, newBezier, lo]; [] _ GGTraj.AddSegment[thisTraj, trajEnd, newSeg, lo]; }; ggData.drag.bezierDrag.draggingBezier _ TRUE; ggData.drag.bezierDrag.bezierNum _ IF trajEnd=lo THEN 1 ELSE hiSegNum; ggData.drag.bezierDrag.traj _ thisTraj; ggData.drag.bezierDrag.outlineSlice _ thisOutlineSlice; GGHistory.NewCapture["Add Bezier spline", ggData]; -- capture scene BEFORE UPDATE [newNormal, newHot] _ GGMouseEvent.UpdateSelectionsForAdd[ggData.scene, oldTraj, thisTraj, trajEnd]; GGMouseEvent.UpdateCaretForAdd[ggData.caret, thisOutlineSlice, newNormal, worldPt]; [] _ GGAlign.UpdateBagsForAdd[oldOutlineSlice, ancestorD, trajEnd, ggData]; [] _ GGMouseEvent.ContinueMotion[ggData: ggData, opName: "add", bagType: $Drag, worldPt: worldPt, startBox: NIL]; DuringBezierDrag[NIL, ggData, worldPt]; -- draw it the first time }; EndBezierAdd: PUBLIC MouseProc = { delSeq: TrajParts; newOutlines: LIST OF Slice; point: Point; normal: Vector; newEndJoint: NAT; CodeTimer.StartInt[$EndBezierAdd, $Gargoyle]; SELECT ggData.drag.bezierDrag.trajEnd FROM lo => newEndJoint _ 1; hi => newEndJoint _ GGTraj.HiJoint[ggData.drag.bezierDrag.traj] -1; ENDCASE; point _ GGTraj.FetchJointPos[ggData.drag.bezierDrag.traj, newEndJoint]; normal _ GGTraj.FetchJointNormal[ggData.drag.bezierDrag.traj, newEndJoint]; delSeq _ GGSequence.LastSegAndJoint[NARROW[ggData.drag.bezierDrag.traj.data], ggData.drag.bezierDrag.trajEnd]; -- the tangent segment. [----, newOutlines] _ GGScene.DeleteSequence[GGSlice.DescriptorFromParts[ggData.drag.bezierDrag.traj, delSeq], ggData.scene]; IF newOutlines = NIL THEN { -- we removed the last segment GGCaret.SitOn[ggData.caret, NIL]; } ELSE { jointParts: TrajParts; jointD, outD: SliceDescriptor; shortOutline: Slice; shortTraj: Traj; shortOutline _ newOutlines.first; shortTraj _ GGParent.FirstChild[shortOutline, first, $Traj]; jointParts _ GGSequence.CreateFromJoint[NARROW[shortTraj.data], IF ggData.drag.bezierDrag.trajEnd = lo THEN 0 ELSE newEndJoint]; jointD _ GGSlice.DescriptorFromParts[shortTraj, jointParts]; -- now have traj descriptor. Make an outline descriptor outD _ GGParent.TopLevelDescriptorFromChildDescriptor[jointD]; GGCaret.SitOn[ggData.caret, outD]; GGSelect.SelectSlice[sliceD: outD, scene: ggData.scene, selectClass: normal]; }; GGCaret.SetAttractor[ggData.caret, point, normal, NIL]; ggData.refresh.startBoundBox^ _ GGSliceOps.GetBoundBox[ggData.drag.bezierDrag.traj]^; ggData.drag.bezierDrag.draggingBezier _ FALSE; ggData.drag.bezierDrag.outlineSlice _ NIL; ggData.drag.bezierDrag.traj _ NIL; GGHistory.PushCurrent[ggData]; -- put captured scene on history list GGRefresh.MoveOverlayToBackground[ggData]; GGWindow.NewCaretPos[ggData]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: FALSE]; CodeTimer.StopInt[$EndBezierAdd, $Gargoyle]; }; -- end EndBezierAdd AbortBezierAdd: PUBLIC PROC [input: LIST OF REF ANY, ggData: GGData, worldPt: Point] = { delSeq, partSeq: TrajParts; delD: SliceDescriptor; newOutlines: LIST OF Slice; newEndJoint: NAT; SELECT ggData.drag.bezierDrag.trajEnd FROM lo => newEndJoint _ 1; hi => newEndJoint _ GGTraj.HiJoint[ggData.drag.bezierDrag.traj] -1; ENDCASE; delSeq _ GGSequence.LastSegAndJoint[NARROW[ggData.drag.bezierDrag.traj.data], ggData.drag.bezierDrag.trajEnd]; -- the tangent segment. delD _ GGSlice.DescriptorFromParts[ggData.drag.bezierDrag.traj, delSeq]; IF ggData.drag.bezierDrag.draggingBezier THEN { -- also delete the bezier ggData.drag.bezierDrag.draggingBezier _ FALSE; partSeq _ GGSequence.CreateFromSegment[NARROW[ggData.drag.bezierDrag.traj.data], ggData.drag.bezierDrag.bezierNum]; delD _ GGSequence.Union[delD, GGSlice.DescriptorFromParts[ggData.drag.bezierDrag.traj, partSeq]]; IF ggData.drag.bezierDrag.trajEnd = hi THEN newEndJoint _ newEndJoint -1 ELSE newEndJoint _ newEndJoint +1; }; [----, newOutlines] _ GGScene.DeleteSequence[delD, ggData.scene]; IF newOutlines = NIL THEN { -- we removed the last segment GGCaret.SitOn[ggData.caret, NIL]; } ELSE { jointParts: TrajParts; jointD, outD: SliceDescriptor; shortOutline: Slice; shortTraj: Traj; IF newOutlines.rest # NIL THEN SIGNAL Problem[msg: "failed assertion"]; shortOutline _ newOutlines.first; shortTraj _ GGParent.FirstChild[shortOutline, first, $Traj]; jointParts _ GGSequence.CreateFromJoint[NARROW[shortTraj.data], IF ggData.drag.bezierDrag.trajEnd = lo THEN 0 ELSE newEndJoint]; jointD _ GGSlice.DescriptorFromParts[shortTraj, jointParts]; -- traj descriptor outD _ GGParent.TopLevelDescriptorFromChildDescriptor[jointD]; GGCaret.SitOn[ggData.caret, outD]; GGSelect.SelectSlice[sliceD: outD, scene: ggData.scene, selectClass: normal]; }; GGCaret.SetAttractor[ggData.caret, GGTraj.FetchJointPos[ggData.drag.bezierDrag.traj, newEndJoint], GGTraj.FetchJointNormal[ggData.drag.bezierDrag.traj, newEndJoint], NIL]; ggData.drag.bezierDrag.outlineSlice _ NIL; ggData.drag.bezierDrag.traj _ NIL; GGMouseEvent.FinishAbort[ggData]; }; END. κGGMouseEventImplB.mesa Contents: Once a mouse event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module. Copyright Σ 1986, 1987, 1988, 1989 by Xerox Corporation. All rights reserved. Pier, April 23, 1992 5:04 pm PDT Bier, March 4, 1992 7:33 pm PST Kurlander July 17, 1986 2:40:45 pm PDT Eisenman, August 7, 1987 1:41:04 pm PDT Maureen Stone, October 2, 1987 3:57:53 pm PDT Doug Wyatt, December 18, 1989 2:30:34 pm PST Special Behaviors ELSE IF theirData = ggData THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "SetStrokeColorRemote failed: Place input focus in a non-palette Gargoyle viewer"]; RETURN; } ELSE IF theirData = ggData THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "SetFillColorRemote failed: Place input focus in a non-palette Gargoyle viewer"]; RETURN; } Version of GGStateImpl.ColorToolIsBound, modified to not complain if the ColorTool is absent. Selection Procs While a joint, segment, traj, or top level object is being selected, gravity is forced to be LinesPreferred. 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. Put Caret on a joint (if any). Deselect all. Dispatch to the proper EndSelect handler for final selection. This routine is used, for instance, for CycleSelection 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. The only use for the chair is the StartAdd command, which is a favor to the $Traj class. Thus, we only sit on $Outline and $Traj slices, or $Cluster slices that contain such slices. Deselection Procs While a joint, cp, segment, traj, or top level object is being deselected, gravity is forced to be LinesPreferred. 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. Reselect all. Clear the overlay plane. GGRefresh.MoveOverlayToBackground[ggData]; -- WHY? KAP. April 17, 1992 And Dispatch to the proper EndDeselect handler. GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; -- WHY? KAP April 17, 1992 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. GGCaret.DoNotSit[ggData.caret]; -- simple but not always correct thing to do simply paint new selections directly Bezier Stuff If we have the EndPoint of a Bezier Selected then set up the conditions to drag out a new Bezier in its trajectory. Otherwise we will drag a single tangent for what will become a Bezier. We have added the NEW segment and the bags are correct and static. Some how must look through all selected stuff and see if I have a selected Bezier endjount. If so then addToBezier is set to true. Remember the endjoint of the tangent vector and delete the segment. Replace it with a Bezier using the information for one end and extend the traj. as in AddBezier. Get ready for the drag. Caret is sitting on a Line segment (the tangent segment) that has been appended to the trajectory that is being extended. The endpoint of the Line is selected. ΚΪ˜Icode™šΟnœ}™…KšœN™NKšœ ™ Kšœ™Kšœ#Οk™&Kšœ'™'K™-K™,—K™šž ˜ Jšœ΄žœ+˜α—K˜šœžœž˜ JšžœŒžœ˜―Kšžœ"ž˜.K˜Kšœ žœžœ˜3K˜Kšœ žœ˜+Kšœžœ#˜7Kšœ žœ˜'Kšœžœ˜%Kšœžœ˜Kšœ žœ˜-Kšœ žœ˜/Kšœžœ"˜5Kšœ žœ˜-Kšœ žœ˜*Kšœžœ˜'Kšœžœ˜1Kšœžœ˜!Kšœ žœ˜&Kšœ žœ˜)Kšœžœ˜!Kšœžœžœ!˜˜>K˜Kšœ*˜*Kšœ,˜,Kšœ˜K˜Kšœ žœ˜*Kšœ žœ˜Kšœ˜Kšœ˜Kšœ žœžœ˜K˜)Kšœ#˜#K˜K˜Kšœižœ p˜ίKšŸœ  0˜PKšœ*˜*Kšœ˜Kšœ% ˜6K˜KšœJ ˜aKšœ,˜,K˜šžœ&žœ˜/Kšžœ$žœP˜{Kšžœ.˜2K˜—KšžœM˜QK˜šžœ$žœ˜-Kšœ ˜ Kšœ˜Kšœ˜šžœžœž˜Kšœ:˜:K˜—K˜—šžœ˜K˜ Kšœ˜Kšœ˜šžœžœž˜Kšœ0˜0K˜—K˜—Kšœ6˜6KšœL˜LKšœ\žœ˜aKšœ4žœ˜9šžœžœ 3˜JKšœ.˜.—Kšžœ3˜7Kšœ/˜/Kšœ˜Kšœ$žœF ˜‡Kšœ˜Kšœ}˜}šžœžœžœ )˜EKšœ+˜+KšœP˜PKšœ$žœžœ˜KKšœ9˜9Kšœ6˜6Kšœ;˜;K˜—šžœ˜Kšœ%˜%Kšœžœ˜,Kšœ&˜&Kšœ9˜9Kšœ6˜6K˜—Kšœ(žœ˜-Kšœ#žœ žœžœ ˜FKšœ'˜'Kšœ7˜7K˜Kšœ Ÿ œ ˜QK˜Kšœd˜dKšœS˜SKšœK˜KKšœlžœ˜qKšœžœ ˜AK˜K˜—š œžœ˜"K™yK™%Kšœ˜Kšœ žœžœ˜Kšœ ˜ Kšœ˜Kšœ žœ˜K˜Kšœ-˜-šžœ ž˜*Kšœ˜KšœC˜CKšžœ˜—KšœG˜GKšœK˜KKšœ$žœF ˜‡Kšœ œx˜}šžœžœžœ ˜:Kšœžœ˜!K˜—šžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ!˜!Kšœ<˜˜>Kšœ"˜"KšœM˜MK˜—Kšœ2žœ˜7KšœU˜UKšœ(žœ˜.Kšœ&žœ˜*Kšœžœ˜"K˜KšŸœ  %˜EK˜Kšœ*˜*Kšœ˜Kšœ}žœžœ˜›Kšœ,˜,Kšœ ˜K˜—š œž œ žœžœžœžœ%˜XKšœ˜K˜Kšœ žœžœ˜Kšœ žœ˜K˜šžœ ž˜*Kšœ˜KšœC˜CKšžœ˜—Kšœ$žœF ˜‡KšœH˜Hšžœ'žœ ˜JKšœ(žœ˜.Kšœ'žœF˜sKšœa˜aKšžœ$žœ˜HKšžœ˜"K˜K˜—Kšœ œ<˜Ašžœžœžœ ˜:Kšœžœ˜!K˜—šžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœžœžœžœ"˜GKšœ!˜!Kšœ<˜˜>Kšœ"˜"KšœM˜MK˜—Kšœ¦žœ˜«Kšœ&žœ˜*Kšœžœ˜"Kšœ!˜!K˜—K˜Kšžœ˜—…—‘Ž½R