DIRECTORY CubicSplines, GGAlign, GGAngle, GGBasicTypes, GGBoundBox, AtomButtons, GGCaret, GGEditTool, GGError, GGEvent, GGGraphicsButton, GGGravity, GGInterface, GGInterfaceTypes, GGMeasure, GGModelTypes, GGObjects, GGOutline, GGRefresh, GGParseIn, GGSegmentTypes, GGSelect, GGSequence, GGTraj, GGUserInput, GGVector, GGViewerOps, GGWindow, IO, List, Real, RealFns, Rope, TiogaButtons, ViewerClasses, ViewerTools; GGEventImplB: CEDAR PROGRAM IMPORTS AtomButtons, GGAlign, GGAngle, GGBoundBox, GGCaret, GGEditTool, GGError, GGGraphicsButton, GGInterface, GGMeasure, GGObjects, GGParseIn, GGSelect, GGRefresh, GGSequence, GGOutline, GGTraj, GGVector, GGUserInput, GGViewerOps, GGWindow, IO, List, RealFns, Rope, TiogaButtons, ViewerTools EXPORTS GGEvent = BEGIN BoundBox: TYPE = GGModelTypes.BoundBox; Caret: TYPE = GGInterfaceTypes.Caret; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; FeatureData: TYPE = GGGravity.FeatureData; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Outline: TYPE = GGModelTypes.Outline; OutlineDescriptor: TYPE = REF OutlineDescriptorObj; OutlineDescriptorObj: TYPE = GGModelTypes.OutlineDescriptorObj; OverlapOrder: TYPE = {incr, decr}; Point: TYPE = GGBasicTypes.Point; ScalarButtonClient: TYPE = AtomButtons.ScalarButtonClient; ScalarButtonHandle: TYPE = AtomButtons.ScalarButtonHandle; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceParts: TYPE = GGModelTypes.SliceParts; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; Traj: TYPE = GGModelTypes.Traj; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajGenerator: TYPE = GGModelTypes.TrajGenerator; SegAndIndex: TYPE = GGSequence.SegAndIndex; TwoState: TYPE = AtomButtons.TwoState; Vector: TYPE = GGBasicTypes.Vector; Viewer: TYPE = ViewerClasses.Viewer; pointsPerIn: REAL = 72.0; pointsPerCm: REAL = 72.0/2.54; Problem: SIGNAL [msg: Rope.ROPE] = GGError.Problem; Top: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; trueEntity: REF ANY; scene: Scene _ gargoyleData.scene; selected: LIST OF REF ANY _ OrderedSelectionList[gargoyleData, decr]; FOR entity: LIST OF REF ANY _ selected, entity.rest UNTIL entity=NIL DO WITH entity.first SELECT FROM slice: Slice => trueEntity _ slice; outline: Outline => trueEntity _ outline; traj: Traj => trueEntity _ GGOutline.OutlineOfTraj[traj]; seq: Sequence => trueEntity _ GGOutline.OutlineOfTraj[seq.traj]; ENDCASE => ERROR; GGObjects.DeleteEntity[scene, trueEntity]; GGObjects.AddEntity[scene, trueEntity, -1]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; Bottom: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; trueEntity: REF ANY; scene: Scene _ gargoyleData.scene; selected: LIST OF REF ANY _ OrderedSelectionList[gargoyleData, incr]; FOR entity: LIST OF REF ANY _ selected, entity.rest UNTIL entity=NIL DO WITH entity.first SELECT FROM slice: Slice => trueEntity _ slice; outline: Outline => trueEntity _ outline; traj: Traj => trueEntity _ GGOutline.OutlineOfTraj[traj]; seq: Sequence => trueEntity _ GGOutline.OutlineOfTraj[seq.traj]; ENDCASE => ERROR; GGObjects.DeleteEntity[scene, trueEntity]; GGObjects.AddEntity[scene, trueEntity, 0]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; UpOne: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; selected: LIST OF REF ANY _ OrderedSelectionList[gargoyleData, incr]; FOR list: LIST OF REF ANY _ selected, list.rest UNTIL list=NIL DO GGObjects.UpOne[gargoyleData.scene, list.first]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; DownOne: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; selected: LIST OF REF ANY _ OrderedSelectionList[gargoyleData, decr]; FOR list: LIST OF REF ANY _ selected, list.rest UNTIL list=NIL DO GGObjects.DownOne[gargoyleData.scene, list.first]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; OrderedSelectionList: PROC [gargoyleData: GargoyleData, order: OverlapOrder] RETURNS [list: LIST OF REF ANY] = { entityGen: EntityGenerator; list _ NIL; entityGen _ GGObjects.TopLevelEntitiesInScene[gargoyleData.scene]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO IF GGSelect.IsSelectedInPart[entity, gargoyleData.scene, normal] THEN list _ CONS[entity, list]; ENDLOOP; IF order=decr THEN list _ List.Reverse[list]; }; LineWidth: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entityGen: GGModelTypes.EntityGenerator; strokeWidth: REAL; bBox: BoundBox; widthRef: REF REAL _ NARROW[event.rest.first]; strokeWidth _ widthRef^; IF strokeWidth < 0.0 THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a positive number for line width", oneLiner]; RETURN; }; GGError.Append[gargoyleData.feedback, IO.PutFR["Selected objects will have line width %1.2f", [real[strokeWidth]]], oneLiner]; bBox _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]; entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM sliceD: SliceDescriptor => sliceD.slice.class.setStrokeWidth[sliceD.slice, sliceD.parts, strokeWidth]; outlineD: OutlineDescriptor => outlineD.slice.class.setStrokeWidth[outlineD.slice, outlineD.parts, strokeWidth]; ENDCASE => ERROR; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: bBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]]; gargoyleData.refresh.startBoundBox^ _ bBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; }; PrintLineWidth: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entity: REF ANY; entityGen: EntityGenerator _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; IF entityGen=NIL OR (entity _ GGObjects.NextEntity[entityGen])=NIL OR GGObjects.NextEntity[entityGen]#NIL THEN GGError.AppendHerald[gargoyleData.feedback, "Select exactly one entity for PrintLineWidth", oneLiner] ELSE WITH entity SELECT FROM outlineD: OutlineDescriptor => GGError.Append[gargoyleData.feedback, IO.PutFR["Line Width = %1.2f", [real[outlineD.slice.class.getStrokeWidth[outlineD.slice, outlineD.parts]]] ], oneLiner]; sliceD: SliceDescriptor => GGError.Append[gargoyleData.feedback, IO.PutFR["Line Width = %1.2f", [real[sliceD.slice.class.getStrokeWidth[sliceD.slice, sliceD.parts]]] ], oneLiner]; ENDCASE => ERROR; }; SelectMatchingWidth: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { epsilon: REAL = 1.0E-3; gargoyleData: GargoyleData _ NARROW[clientData]; width: REAL _ NARROW[event.rest.first, REF REAL]^; trajGen: TrajGenerator _ GGObjects.TrajsInScene[gargoyleData.scene]; IF width<0.0 THEN GOTO SyntaxError; GGSelect.DeselectAll[gargoyleData.scene, normal]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInTraj[traj]; FOR segAndIndex: SegAndIndex _ GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen] UNTIL segAndIndex.seg = NIL DO IF segAndIndex.seg.strokeWidth=width OR ABS[segAndIndex.seg.strokeWidth-width] {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Select a real number >=0.0 for matching width", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; }; DashesFromSelection: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; argRope: Rope.ROPE _ NARROW[event.rest.first]; argStream: IO.STREAM _ IO.RIS[argRope]; pattern: GGBasicTypes.SequenceOfReal; offset, length: REAL; pattern _ GGParseIn.ReadArrayOfReal[argStream]; offset _ GGParseIn.ReadBlankAndReal[argStream]; length _ GGParseIn.ReadBlankAndReal[argStream]; BEGIN entityGen: GGModelTypes.EntityGenerator; bBox: BoundBox; bBox _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]; entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM sliceD: SliceDescriptor => sliceD.slice.class.setDashed[sliceD.slice, sliceD.parts, TRUE, pattern, offset, length]; outlineD: OutlineDescriptor => outlineD.slice.class.setDashed[outlineD.slice, outlineD.parts, TRUE, pattern, offset, length]; ENDCASE => ERROR; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: bBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]]; gargoyleData.refresh.startBoundBox^ _ bBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; END; }; DashesOff: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; BEGIN entityGen: GGModelTypes.EntityGenerator; bBox: BoundBox; bBox _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]; entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM sliceD: SliceDescriptor => sliceD.slice.class.setDashed[sliceD.slice, sliceD.parts, FALSE]; outlineD: OutlineDescriptor => outlineD.slice.class.setDashed[outlineD.slice, outlineD.parts, FALSE]; ENDCASE => ERROR; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: bBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]]; gargoyleData.refresh.startBoundBox^ _ bBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; END; }; Arrows: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; arrowType: INT _ NARROW[event.rest.first, REF INT]^; leftArrows, rightArrows: BOOL; sequenceGen: SequenceGenerator; loIsLeft: BOOL; traj: Traj; SELECT arrowType FROM 0 => { GGError.PutF[gargoyleData.feedback, oneLiner, "Selected objects will have no arrows."]; leftArrows _ FALSE; rightArrows _ FALSE; }; 1 => { GGError.PutF[gargoyleData.feedback, oneLiner, "Selected objects will have left/down arrows."]; leftArrows _ TRUE; rightArrows _ FALSE; }; 2 => { GGError.PutF[gargoyleData.feedback, oneLiner, "Selected objects will have right/up arrows."]; leftArrows _ FALSE; rightArrows _ TRUE; }; 3 => { GGError.PutF[gargoyleData.feedback, oneLiner, "Selected objects will have arrows on both ends."]; leftArrows _ TRUE; rightArrows _ TRUE; }; ENDCASE => { GGError.PutF[gargoyleData.feedback, oneLiner, "Illegal argument to Arrows."]; RETURN; }; sequenceGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[sequenceGen], GGSequence.NextSequence[sequenceGen] UNTIL seq = NIL DO traj _ seq.traj; loIsLeft _ LoIsLeft[traj]; IF loIsLeft THEN GGTraj.SetArrows[seq.traj, leftArrows, rightArrows] ELSE GGTraj.SetArrows[seq.traj, rightArrows, leftArrows]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; }; LoIsLeft: PROC [traj: Traj] RETURNS [BOOL] = { loPoint, hiPoint: Point; loPoint _ GGTraj.FetchJointPos[traj, 0]; hiPoint _ GGTraj.LastJointPos[traj]; SELECT TRUE FROM loPoint.x < hiPoint.x => RETURN[TRUE]; loPoint.x = hiPoint.x AND loPoint.y <= hiPoint.y => RETURN[TRUE]; ENDCASE => RETURN[FALSE]; }; MakeHot: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entityGen: EntityGenerator; outDGen: GGModelTypes.OutlineDescriptorGenerator; sliceDescGen: GGSelect.SliceDescriptorGenerator; entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM cD: SliceDescriptor => GGSelect.SelectSlice[cD.slice, cD.parts, gargoyleData.scene, hot]; oD: OutlineDescriptor => GGSelect.SelectOutline[oD.slice, oD.parts, gargoyleData.scene, hot]; ENDCASE => ERROR; ENDLOOP; outDGen _ GGSelect.SelectedOutlines[gargoyleData.scene, hot]; FOR outlineD: OutlineDescriptor _ GGSelect.NextOutlineDescriptor[outDGen], GGSelect.NextOutlineDescriptor[outDGen] UNTIL outlineD = NIL DO outFeature: FeatureData _ GGAlign.CreateOutlineTrigger[outlineD, gargoyleData.hitTest.currentTriggerBag]; -- fix triggerBag alignObjects: LIST OF FeatureData; alignObjects _ GGAlign.IncrementalFilters[outFeature, gargoyleData.hitTest.currentObjectBag, gargoyleData]; -- fix object bag GGRefresh.NoteNewForeground[alignObjects, gargoyleData]; -- fix foreground plane ENDLOOP; sliceDescGen _ GGSelect.SelectedSlices[gargoyleData.scene, hot]; FOR sliceD: GGSelect.SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO sliceFeature: FeatureData _ GGAlign.CreateSliceTrigger[sliceD, gargoyleData.hitTest.currentTriggerBag]; -- fix triggerBag alignObjects: LIST OF FeatureData; alignObjects _ GGAlign.IncrementalFilters[sliceFeature, gargoyleData.hitTest.currentObjectBag, gargoyleData]; -- fix object bag GGRefresh.NoteNewForeground[alignObjects, gargoyleData]; -- fix foreground plane ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; MakeAllHot: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entityGen: EntityGenerator; outDGen: GGModelTypes.OutlineDescriptorGenerator; entityGen _ GGObjects.TopLevelEntitiesInScene[gargoyleData.scene]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM slice: Slice => { sliceParts: SliceParts _ slice.class.newParts[slice, NIL, topLevel]; GGSelect.SelectSlice[slice, sliceParts, gargoyleData.scene, hot]; }; outline: Outline => { GGSelect.SelectEntireOutline[outline, gargoyleData.scene, hot]; }; ENDCASE => ERROR; ENDLOOP; outDGen _ GGSelect.SelectedOutlines[gargoyleData.scene, hot]; FOR outlineD: OutlineDescriptor _ GGSelect.NextOutlineDescriptor[outDGen], GGSelect.NextOutlineDescriptor[outDGen] UNTIL outlineD = NIL DO outFeature: FeatureData _ GGAlign.CreateOutlineTrigger[outlineD, NARROW[gargoyleData.hitTest.currentTriggerBag]]; alignObjects: LIST OF FeatureData; alignObjects _ GGAlign.IncrementalFilters[outFeature, gargoyleData.hitTest.currentObjectBag, gargoyleData]; GGRefresh.NoteNewForeground[alignObjects, gargoyleData]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; MakeCold: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entityGen: EntityGenerator; entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO GGSelect.DeselectEntity[entity, gargoyleData.scene, hot]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; MakeAllCold: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entityGen: EntityGenerator; entityGen _ GGSelect.SelectedStuff[gargoyleData.scene, hot]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO GGSelect.DeselectEntity[entity, gargoyleData.scene, hot]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ShowHot: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; gargoyleData.camera.hideHot _ FALSE; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; HideHot: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; gargoyleData.camera.hideHot _ TRUE; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DropAnchor: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGCaret.Copy[gargoyleData.anchor, gargoyleData.caret]; [] _ GGAlign.CreateAnchorTrigger[gargoyleData.anchor, gargoyleData.hitTest.currentTriggerBag]; -- anchor can trigger [] _ GGAlign.CreateAnchorTrigger[gargoyleData.anchor, gargoyleData.hitTest.sceneTriggerBag]; -- anchor is itself gravity active GGWindow.RestoreScreenAndInvariants[paintAction: $AnchorAdded, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; KillAnchor: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF GGCaret.Exists[gargoyleData.anchor] THEN { GGCaret.Kill[gargoyleData.anchor]; GGAlign.DeleteAnchorTrigger[gargoyleData.hitTest.currentTriggerBag]; -- don't trigger GGAlign.DeleteAnchorTrigger[gargoyleData.hitTest.sceneTriggerBag]; -- don't be gravity active GGWindow.RestoreScreenAndInvariants[paintAction: $AnchorRemoved, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; StandardAlignments: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; StandardSlopes[event, clientData]; StandardAngles[event, clientData]; StandardRadii[event, clientData]; StandardDistances[event, clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; AllAlignmentsOff: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; SlopePrompt[event, gargoyleData]; AnglePrompt[event, gargoyleData]; RadiusPrompt[event, gargoyleData]; DistancePrompt[event, gargoyleData]; IF AtomButtons.GetButtonState[gargoyleData.hitTest.midpointButton] = on THEN ToggleMidpoints[NIL, gargoyleData]; }; InitializeAlignments: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; AllAlignmentsOff[NIL, gargoyleData]; IF AtomButtons.GetButtonState[gargoyleData.refresh.alignments] = off THEN ToggleAlignments[NIL, gargoyleData]; IF AtomButtons.GetButtonState[gargoyleData.hitTest.gravButton] = off THEN ToggleGravity[NIL, gargoyleData]; IF Rope.Equal[gargoyleData.hitTest.gravityTypeMenu.flipLabel.name, "StrictDistance", TRUE] THEN GravityChoiceChange[LIST[$GravityChoiceChange, $FlipForward], gargoyleData]; InchScaleUnit[NIL, gargoyleData]; IF AtomButtons.GetButtonState[gargoyleData.hitTest.heuristicsButton] = off THEN ToggleHeuristics[NIL, gargoyleData]; }; GravityChoiceChange: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; info: AtomButtons.EnumTypeRef _ gargoyleData.hitTest.gravityTypeMenu; name: Rope.ROPE; IF event.rest.first = $FlipForward THEN AtomButtons.TimeToFlipThru[LIST[$FlipForward, info]] ELSE AtomButtons.TimeToFlipThru[LIST[$FlipBackward, info]]; name _ info.flipLabel.name; SELECT TRUE FROM Rope.Equal[name, "StrictDistance", TRUE] => gargoyleData.hitTest.gravityType _ strictDistance; Rope.Equal[name, "PreferPoints", TRUE] => gargoyleData.hitTest.gravityType _ innerCircle; ENDCASE => ERROR; UpdateGravityChoice[gargoyleData]; }; GravityExtentChange: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; value: REAL; success: BOOL _ TRUE; graphicsState: GGGraphicsButton.GraphicsState _ gargoyleData.hitTest.gravityExtentButton; value _ GGGraphicsButton.GetValue[graphicsState]; SELECT event.rest.first FROM $ValueUp => { IF value < 18432.0 THEN value _ value*2.0 ELSE { GGError.PutF[gargoyleData.feedback, oneLiner, "Can't extend gravity further than 256 inches."]; GGError.Blink[gargoyleData.feedback]; success _ FALSE; }; }; $ValueDown => value _ value/2.0; ENDCASE => value _ GGEditTool.GetDefaultGravityExtent[]; IF success THEN { GGWindow.SetGravityExtent[gargoyleData, value/72.0]; }; }; SetGravityExtent: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; inches: REAL; graphicsState: GGGraphicsButton.GraphicsState _ gargoyleData.hitTest.gravityExtentButton; inches _ NARROW[event.rest.first, REF REAL]^; GGWindow.SetGravityExtent[gargoyleData, inches]; }; UpdateGravityChoice: PROC [clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; SELECT AtomButtons.GetButtonState[gargoyleData.hitTest.gravButton] FROM on => SELECT gargoyleData.hitTest.gravityType FROM strictDistance => GGWindow.SetCursorLooks[strictDistance, gargoyleData]; innerCircle => GGWindow.SetCursorLooks[innerCircle, gargoyleData]; ENDCASE => ERROR; -- SHOULD NOT USE off STATE off => GGWindow.SetCursorLooks[off, gargoyleData]; ENDCASE => ERROR; }; ScreenChoiceChange: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { name: Rope.ROPE; gargoyleData: GargoyleData _ NARROW[clientData]; info: AtomButtons.EnumTypeRef _ gargoyleData.refresh.screenStyle; IF event.rest.first = $FlipForward THEN AtomButtons.TimeToFlipThru[LIST[$FlipForward, info]] ELSE AtomButtons.TimeToFlipThru[LIST[$FlipBackward, info]]; name _ info.flipLabel.name; SELECT TRUE FROM Rope.Equal[name, "PrintFonts", TRUE] => { gargoyleData.camera.quality _ fast; gargoyleData.camera.displayStyle _ print; }; Rope.Equal[name, "ScreenFonts", TRUE] => { gargoyleData.camera.quality _ fast; gargoyleData.camera.displayStyle _ screen; }; Rope.Equal[name, "WYSIWYG", TRUE] => { gargoyleData.camera.quality _ quality; gargoyleData.camera.displayStyle _ print; }; ENDCASE => ERROR; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireViewer, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleShowColors: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; stateInfo: TwoState _ gargoyleData.refresh.showColors; AtomButtons.SwitchState[stateInfo]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireViewer, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleAlignments: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; stateInfo: TwoState _ gargoyleData.refresh.alignments; AtomButtons.SwitchState[stateInfo]; SELECT AtomButtons.GetButtonState[stateInfo] FROM on => gargoyleData.camera.hideAlignments _ FALSE; off => gargoyleData.camera.hideAlignments _ TRUE; ENDCASE => ERROR; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireViewer, gargoyleData: gargoyleData, remake: objectBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleMidpoints: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; stateInfo: TwoState _ gargoyleData.hitTest.midpointButton; AtomButtons.SwitchState[stateInfo]; GGWindow.RestoreScreenAndInvariants[paintAction: $None, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; }; SetMidpointsInternal: PUBLIC PROC [gargoyleData: GargoyleData, on: BOOL] = { stateInfo: TwoState _ gargoyleData.hitTest.midpointButton; wasOn: BOOL _ AtomButtons.GetButtonState[stateInfo] = on; IF wasOn # on THEN AtomButtons.SwitchState[stateInfo]; }; ToggleHeuristics: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; stateInfo: TwoState _ gargoyleData.hitTest.heuristicsButton; AtomButtons.SwitchState[stateInfo]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireViewer, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleGravity: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; stateInfo: TwoState _ gargoyleData.hitTest.gravButton; AtomButtons.SwitchState[stateInfo]; UpdateGravityChoice[gargoyleData]; }; ScaleUnitAux: PROC [gargoyleData: GargoyleData, distance: REAL] = { IF distance <=0.0 THEN { GGError.AppendHerald[gargoyleData.feedback, "Zero or Illegal unit value. Set Units ignored.", oneLiner]; GGError.Blink[gargoyleData.feedback]; } ELSE { gargoyleData.hitTest.scaleUnit _ distance; -- in screen dots GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; ScaleUnitFromSegment: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; seqGen: SequenceGenerator; segGen: SegmentGenerator; seq, next: Sequence; seg, nextSeg: Segment; distance: REAL; seqGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; seq _ GGSequence.NextSequence[seqGen]; next _ GGSequence.NextSequence[seqGen]; IF seq = NIL OR next # NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a single segment to set Units.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; segGen _ GGSequence.SegmentsInSequence[seq]; seg _ GGSequence.NextSegment[segGen]; nextSeg _ GGSequence.NextSegment[segGen]; IF seg = NIL OR nextSeg # NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a single segment to set Units.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; distance _ GGVector.Distance[seg.lo, seg.hi]; ScaleUnitAux[gargoyleData, distance]; }; ScaleUnitFromValue: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; ScaleUnitAux[gargoyleData, gargoyleData.measure.radiusViewValue*gargoyleData.hitTest.scaleUnit]; }; ScaleUnitFromSelection: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; distance: REAL _ NARROW[event.rest.first, REF REAL]^; -- in inches BEGIN IF distance < 0.0 THEN GOTO BadUnit; ScaleUnitAux[gargoyleData, distance*72.0]; -- screen dots EXITS BadUnit => { GGError.Append[gargoyleData.feedback, "Please select a real number (in inches) to be the scale unit.", oneLiner]; GGError.Blink[gargoyleData.feedback]; }; END; }; InchScaleUnit: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; ScaleUnitAux[gargoyleData, pointsPerIn]; -- one inch in screen dots }; CentimeterScaleUnit: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; ScaleUnitAux[gargoyleData, pointsPerCm]; -- 1 cm in screen dots }; PrintScaleUnit: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "Current scale is %1.2f points = %1.2f inches = %1.2f centimeters", [real[gargoyleData.hitTest.scaleUnit]], [real[gargoyleData.hitTest.scaleUnit/pointsPerIn]], [real[gargoyleData.hitTest.scaleUnit/pointsPerCm]] ]; }; StandardSlopes: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; SlopePrompt[event, gargoyleData]; AtomButtons.BuildScalarButtons[gargoyleData.hitTest.slopeHeader, gargoyleData, GGUserInput.MenuNotify, NIL, LIST[ ["", 999.9, LIST[$NoOp, NEW[REAL _ 999.9]], off], -- dummy first button ["150", 150.0, LIST[$ToggleSlope, NEW[REAL _ 150.0]], off], ["135", 135.0, LIST[$ToggleSlope, NEW[REAL _ 135.0]], off], ["120", 120.0, LIST[$ToggleSlope, NEW[REAL _ 120.0]], off], ["90", 90.0, LIST[$ToggleSlope, NEW[REAL _ 90.0]], off], ["60", 60.0, LIST[$ToggleSlope, NEW[REAL _ 60.0]], off], ["45", 45.0, LIST[$ToggleSlope, NEW[REAL _ 45.0]], off], ["30", 30.0, LIST[$ToggleSlope, NEW[REAL _ 30.0]], off], ["0", 0.0, LIST[$ToggleSlope, NEW[REAL _ 0.0]], off] ]]; IF event.first = $StandardSlopes THEN GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; SlopePrompt: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; firstButton: ScalarButtonClient _ gargoyleData.hitTest.slopeHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN ToggleSlope[LIST[NIL, NEW[REAL _ thisButton.value]], gargoyleData]; ENDLOOP; }; AddSlope: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; slope: REAL _ GGViewerOps.GetReal[gargoyleData.measure.slopeView, Real.LargestNumber]; IF slope=Real.LargestNumber THEN { GGError.AppendHerald[gargoyleData.feedback, "Attempt to add illegal slope value", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; slope _ GGAngle.Normalize[slope]; IF slope<0.0 THEN slope _ slope+180.0; IF slope=360.0 THEN slope _ 0.0; IF RealFns.AlmostEqual[slope, gargoyleData.measure.slopeViewValue, -10] THEN slope _ gargoyleData.measure.slopeViewValue ELSE gargoyleData.measure.slopeViewValue _ slope; oldFoundButton _ AtomButtons.AddValueSorted[clientData: gargoyleData, scalarButtonHandle: gargoyleData.hitTest.slopeHeader, value: [NIL, slope, LIST[$ToggleSlope, NEW[REAL _ slope]], on], order: decr]; IF oldFoundButton = NIL THEN { -- a new button was added GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; AddSlopeInternal: PUBLIC PROC [gargoyleData: GargoyleData, degrees: REAL] = { oldFoundButton: AtomButtons.ScalarButtonClient; IF degrees<0.0 THEN degrees _ degrees+180.0; IF degrees=360.0 THEN degrees _ 0.0; gargoyleData.measure.slopeViewValue _ degrees; oldFoundButton _ AtomButtons.AddValueSorted[clientData: gargoyleData, scalarButtonHandle: gargoyleData.hitTest.slopeHeader, value: [NIL, degrees, LIST[$ToggleSlope, NEW[REAL _ degrees]], off], order: decr]; }; DeleteSlope: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; prevButton: ScalarButtonClient _ gargoyleData.hitTest.slopeHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ prevButton.next, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN { TiogaButtons.DeleteButton[thisButton.button]; prevButton.next _ thisButton.next; } ELSE prevButton _ thisButton; ENDLOOP; gargoyleData.measure.slopeViewValue _ Real.LargestNumber; -- invalidate cached value GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; GetSlope: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; seqGen: SequenceGenerator; segGen: SegmentGenerator; seq, next: Sequence; degrees: REAL; seqGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; seq _ GGSequence.NextSequence[seqGen]; next _ GGSequence.NextSequence[seqGen]; IF seq = NIL OR next # NIL THEN { GGError.Append[gargoyleData.feedback, "Select a single sequence for a GetSlope.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO degrees _ GGMeasure.SlopeOfSegment[seg]; oldFoundButton _ AtomButtons.AddValueSorted[gargoyleData, gargoyleData.hitTest.slopeHeader, [NIL, degrees, LIST[$ToggleSlope, NEW[REAL _ degrees]], on], decr]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleSlope: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; slope: REAL; firstButton, pushedButton: ScalarButtonClient; tiogaButton: TiogaButtons.TiogaButton; epsilon: REAL = 0.001; WITH event.rest.first SELECT FROM int: REF INT => slope _ int^; real: REF REAL => slope _ real^; ENDCASE => ERROR; firstButton _ gargoyleData.hitTest.slopeHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF ABS[thisButton.value-slope] < epsilon THEN { pushedButton _ thisButton; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; tiogaButton _ pushedButton.button; IF pushedButton.on THEN { pushedButton.on _ FALSE; TiogaButtons.ChangeButtonLooks[tiogaButton, "", "b"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; } ELSE { pushedButton.on _ TRUE; TiogaButtons.ChangeButtonLooks[tiogaButton, "b", ""]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; StandardAngles: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; AnglePrompt[event, gargoyleData]; AtomButtons.BuildScalarButtons[gargoyleData.hitTest.angleHeader, gargoyleData, GGUserInput.MenuNotify, NIL, LIST[ ["", 999.9, LIST[$NoOp, NEW[REAL _ 999.9]], off], -- dummy first button ["90", 90.0, LIST[$ToggleAngle, NEW[REAL _ 90.0]], off], ["60", 60.0, LIST[$ToggleAngle, NEW[REAL _ 60.0]], off], ["45", 45.0, LIST[$ToggleAngle, NEW[REAL _ 45.0]], off], ["30", 30.0, LIST[$ToggleAngle, NEW[REAL _ 30.0]], off], ["0", 0.0, LIST[$ToggleAngle, NEW[REAL _ 0.0]], off], ["-30", -30.0, LIST[$ToggleAngle, NEW[REAL _ -30.0]], off], ["-45", -45.0, LIST[$ToggleAngle, NEW[REAL _ -45.0]], off], ["-60", -60.0, LIST[$ToggleAngle, NEW[REAL _ -60.0]], off], ["-90", -90.0, LIST[$ToggleAngle, NEW[REAL _ -90.0]], off] ]]; IF event.first = $StandardAngles THEN GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; AnglePrompt: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; firstButton: ScalarButtonClient _ gargoyleData.hitTest.angleHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN ToggleAngle[LIST[NIL, NEW[REAL _ thisButton.value]], gargoyleData]; ENDLOOP; }; AddAngle: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; angle: REAL _ GGViewerOps.GetReal[gargoyleData.measure.angleView, Real.LargestNumber]; IF angle=Real.LargestNumber THEN { GGError.AppendHerald[gargoyleData.feedback, "Attempt to add illegal angle value", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; angle _ GGAngle.Normalize[angle]; IF angle=360.0 THEN angle _ 0.0; IF RealFns.AlmostEqual[angle, gargoyleData.measure.angleViewValue, -10] THEN angle _ gargoyleData.measure.angleViewValue ELSE gargoyleData.measure.angleViewValue _ angle; oldFoundButton _ AtomButtons.AddValueSorted[clientData: gargoyleData, scalarButtonHandle: gargoyleData.hitTest.angleHeader, value: [NIL, angle, LIST[$ToggleAngle, NEW[REAL _ angle]], on], order: decr]; IF oldFoundButton = NIL THEN { -- a button was added GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; } }; AddAngleInternal: PUBLIC PROC [gargoyleData: GargoyleData, degrees: REAL] = { oldFoundButton: AtomButtons.ScalarButtonClient; IF degrees=360.0 THEN degrees _ 0.0; gargoyleData.measure.angleViewValue _ degrees; oldFoundButton _ AtomButtons.AddValueSorted[clientData: gargoyleData, scalarButtonHandle: gargoyleData.hitTest.angleHeader, value: [NIL, degrees, LIST[$ToggleAngle, NEW[REAL _ degrees]], off], order: decr]; }; DeleteAngle: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; prevButton: ScalarButtonClient _ gargoyleData.hitTest.angleHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ prevButton.next, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN { TiogaButtons.DeleteButton[thisButton.button]; prevButton.next _ thisButton.next; } ELSE prevButton _ thisButton; ENDLOOP; gargoyleData.measure.angleViewValue _ Real.LargestNumber; -- invalidate cached value GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; GetAngle: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; seqGen: SequenceGenerator; segGen: SegmentGenerator; seq, next: Sequence; firstSeg, secondSeg: Segment; degrees: REAL; seqGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; seq _ GGSequence.NextSequence[seqGen]; next _ GGSequence.NextSequence[seqGen]; IF seq = NIL OR next # NIL THEN { GGError.Append[gargoyleData.feedback, "Select a single sequence for a GetAngle.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO IF firstSeg=NIL THEN {firstSeg _ seg; LOOP;}; IF secondSeg=NIL THEN secondSeg _ seg; degrees _ GGMeasure.CounterClockwiseBetweenSegments[firstSeg, secondSeg]; oldFoundButton _ AtomButtons.AddValueSorted[gargoyleData, gargoyleData.hitTest.angleHeader, [NIL, degrees, LIST[$ToggleAngle, NEW[REAL _ degrees]], on], decr]; firstSeg _ secondSeg; secondSeg_ NIL; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleAngle: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; angle: REAL; firstButton, pushedButton: ScalarButtonClient; tiogaButton: TiogaButtons.TiogaButton; epsilon: REAL = 0.001; WITH event.rest.first SELECT FROM int: REF INT => angle _ int^; real: REF REAL => angle _ real^; ENDCASE => ERROR; firstButton _ gargoyleData.hitTest.angleHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF ABS[thisButton.value-angle] < epsilon THEN { pushedButton _ thisButton; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; tiogaButton _ pushedButton.button; IF pushedButton.on THEN { pushedButton.on _ FALSE; TiogaButtons.ChangeButtonLooks[tiogaButton, "", "b"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; } ELSE { pushedButton.on _ TRUE; TiogaButtons.ChangeButtonLooks[tiogaButton, "b", ""]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; StandardRadii: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; RadiusPrompt[event, gargoyleData]; AtomButtons.BuildScalarButtons[ gargoyleData.hitTest.radiusHeader, gargoyleData, GGUserInput.MenuNotify, NIL, LIST[ ["", -9999.99, LIST[$NoOp, NEW[REAL _ -9999.99]], off], -- dummy first button ["1/18", 1.0/18.0, LIST[$ToggleRadius, NEW[REAL _ 1.0/18.0]], off], ["1/9", 1.0/9.0, LIST[$ToggleRadius, NEW[REAL _ 1.0/9.0]], off], ["1/8", 0.125, LIST[$ToggleRadius, NEW[REAL _ 0.125]], off], ["1/4", 0.25, LIST[$ToggleRadius, NEW[REAL _ 0.25]], off], ["1/3", 1.0/3.0, LIST[$ToggleRadius, NEW[REAL _ 1.0/3.0]], off], ["1/2", 0.5, LIST[$ToggleRadius, NEW[REAL _ 0.5]], off], ["2/3", 2.0/3.0, LIST[$ToggleRadius, NEW[REAL _ 2.0/3.0]], off], ["3/4", 0.75, LIST[$ToggleRadius, NEW[REAL _ 0.75]], off], ["1", 1.0, LIST[$ToggleRadius, NEW[REAL _ 1.0]], off], ["2", 2.0, LIST[$ToggleRadius, NEW[REAL _ 2.0]], off], ["4", 4.0, LIST[$ToggleRadius, NEW[REAL _ 4.0]], off] ]]; IF event.first = $StandardRadii THEN GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; RadiusPrompt: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; firstButton: ScalarButtonClient _ gargoyleData.hitTest.radiusHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN ToggleRadius[LIST[NIL, NEW[REAL _ thisButton.value]], gargoyleData]; ENDLOOP; }; AddRadius: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; radius: REAL _ GGViewerOps.GetPositiveReal[gargoyleData.measure.radiusView, Real.LargestNumber]; IF radius=Real.LargestNumber THEN { GGError.Append[gargoyleData.feedback, "Attempt to add illegal radius value", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; IF RealFns.AlmostEqual[radius, gargoyleData.measure.radiusViewValue, -10] THEN radius _ gargoyleData.measure.radiusViewValue ELSE gargoyleData.measure.radiusViewValue _ radius; oldFoundButton _ AtomButtons.AddValueSorted[clientData: gargoyleData, scalarButtonHandle: gargoyleData.hitTest.radiusHeader, value: [NIL, radius, LIST[$ToggleRadius, NEW[REAL _ radius]], on], order: incr]; IF oldFoundButton = NIL THEN { -- a new button is added GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; AddRadiusInternal: PUBLIC PROC [gargoyleData: GargoyleData, radius: REAL] = { oldFoundButton: AtomButtons.ScalarButtonClient; gargoyleData.measure.radiusViewValue _ radius; oldFoundButton _ AtomButtons.AddValueSorted[clientData: gargoyleData, scalarButtonHandle: gargoyleData.hitTest.radiusHeader, value: [NIL, radius, LIST[$ToggleRadius, NEW[REAL _ radius]], off], order: incr]; }; DeleteRadius: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; prevButton: ScalarButtonClient _ gargoyleData.hitTest.radiusHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ prevButton.next, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN { TiogaButtons.DeleteButton[thisButton.button]; prevButton.next _ thisButton.next; } ELSE prevButton _ thisButton; ENDLOOP; gargoyleData.measure.radiusViewValue _ Real.LargestNumber; -- invalidate cached value GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; GetRadius: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; sliceDescGen: GGModelTypes.SliceDescriptorGenerator; outDGen: GGModelTypes.OutlineDescriptorGenerator; pointGen: GGModelTypes.PointGenerator; oPointGen: GGModelTypes.OutlinePointGenerator; radius: REAL; pointAndDone: GGModelTypes.PointAndDone; sliceD, nextD: GGModelTypes.SliceDescriptor; outlineD, nextOutlineD: GGModelTypes.OutlineDescriptor; p0, p1: Point; BEGIN sliceDescGen _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; sliceD _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF sliceD = NIL THEN { outDGen _ GGSelect.SelectedOutlines[gargoyleData.scene, normal]; outlineD _ GGSelect.NextOutlineDescriptor[outDGen]; IF outlineD = NIL THEN GOTO Problem; nextOutlineD _ GGSelect.NextOutlineDescriptor[outDGen]; IF nextOutlineD # NIL THEN GOTO Problem; oPointGen _ outlineD.slice.class.pointsInDescriptor[outlineD]; pointAndDone _ outlineD.slice.class.nextPoint[oPointGen]; IF pointAndDone.done THEN GOTO Problem; p0 _ pointAndDone.point; pointAndDone _ outlineD.slice.class.nextPoint[oPointGen]; IF pointAndDone.done THEN GOTO Problem; p1 _ pointAndDone.point; pointAndDone _ outlineD.slice.class.nextPoint[oPointGen]; IF NOT pointAndDone.done THEN GOTO Problem; } ELSE { nextD _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF nextD # NIL THEN GOTO Problem; pointGen _ sliceD.slice.class.pointsInDescriptor[sliceD]; pointAndDone _ sliceD.slice.class.nextPoint[pointGen]; IF pointAndDone.done THEN GOTO Problem; p0 _ pointAndDone.point; pointAndDone _ sliceD.slice.class.nextPoint[pointGen]; IF pointAndDone.done THEN GOTO Problem; p1 _ pointAndDone.point; pointAndDone _ sliceD.slice.class.nextPoint[pointGen]; IF NOT pointAndDone.done THEN GOTO Problem; }; EXITS Problem => { GGError.Append[gargoyleData.feedback, "Select a single segment for GetRadius.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; END; radius _ GGMeasure.DistanceBetweenPoints[p0, p1]/gargoyleData.hitTest.scaleUnit; oldFoundButton _ AtomButtons.AddValueSorted[gargoyleData, gargoyleData.hitTest.radiusHeader, [NIL, radius, LIST[$ToggleRadius, NEW[REAL _ radius]], on], incr]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleRadius: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; radius: REAL; epsilon: REAL = 0.001; firstButton, pushedButton: ScalarButtonClient; tiogaButton: TiogaButtons.TiogaButton; WITH event.rest.first SELECT FROM int: REF INT => radius _ int^; real: REF REAL => radius _ real^; ENDCASE => ERROR; firstButton _ gargoyleData.hitTest.radiusHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF ABS[thisButton.value-radius] < epsilon THEN { pushedButton _ thisButton; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; tiogaButton _ pushedButton.button; IF pushedButton.on THEN { pushedButton.on _ FALSE; TiogaButtons.ChangeButtonLooks[tiogaButton, "", "b"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; } ELSE { pushedButton.on _ TRUE; TiogaButtons.ChangeButtonLooks[tiogaButton, "b", ""]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; StandardDistances: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; DistancePrompt[event, gargoyleData]; AtomButtons.BuildScalarButtons[gargoyleData.hitTest.distanceHeader, gargoyleData, GGUserInput.MenuNotify, NIL, LIST[ ["", -9999.99, LIST[$NoOp, NEW[REAL _ -9999.99]], off], -- dummy first button ["0", 0.0, LIST[$ToggleDistance, NEW[REAL _ 0.0]], off], ["1/18", 1.0/18.0, LIST[$ToggleDistance, NEW[REAL _ 1.0/18.0]], off], ["1/9", 1.0/9.0, LIST[$ToggleDistance, NEW[REAL _ 1.0/9.0]], off], ["1/2", 0.5, LIST[$ToggleDistance, NEW[REAL _ 0.5]], off], ["1", 1.0, LIST[$ToggleDistance, NEW[REAL _ 1.0]], off] ]]; IF event.first = $StandardDistances THEN GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DistancePrompt: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; firstButton: ScalarButtonClient _ gargoyleData.hitTest.distanceHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN ToggleDistance[LIST[NIL, NEW[REAL _ thisButton.value]], gargoyleData]; ENDLOOP; }; AddDistance: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; distance: REAL _ GGViewerOps.GetReal[gargoyleData.measure.lineDistView, Real.LargestNumber]; IF distance=Real.LargestNumber THEN { GGError.Append[gargoyleData.feedback, "Attempt to add illegal line distance value", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; IF RealFns.AlmostEqual[distance, gargoyleData.measure.lineDistViewValue, -10] THEN distance _ gargoyleData.measure.lineDistViewValue ELSE gargoyleData.measure.lineDistViewValue _ distance; oldFoundButton _ AtomButtons.AddValueSorted[clientData: gargoyleData, scalarButtonHandle: gargoyleData.hitTest.distanceHeader, value: [NIL, distance, LIST[$ToggleDistance, NEW[REAL _ distance]], on], order: incr]; IF oldFoundButton=NIL THEN { -- a new button is added GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; AddDistanceInternal: PUBLIC PROC [gargoyleData: GargoyleData, distance: REAL] = { oldFoundButton: AtomButtons.ScalarButtonClient; gargoyleData.measure.lineDistViewValue _ distance; oldFoundButton _ AtomButtons.AddValueSorted[clientData: gargoyleData, scalarButtonHandle: gargoyleData.hitTest.distanceHeader, value: [NIL, distance, LIST[$ToggleDistance, NEW[REAL _ distance]], off], order: incr]; }; DeleteDistance: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; prevButton: ScalarButtonClient _ gargoyleData.hitTest.distanceHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ prevButton.next, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN { TiogaButtons.DeleteButton[thisButton.button]; prevButton.next _ thisButton.next; } ELSE prevButton _ thisButton; ENDLOOP; gargoyleData.measure.lineDistViewValue _ Real.LargestNumber; -- invalidate cached value GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; GetDistance: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; seqGen: SequenceGenerator; segGen: SegmentGenerator; seq, next: Sequence; dist: REAL; seqGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; seq _ GGSequence.NextSequence[seqGen]; next _ GGSequence.NextSequence[seqGen]; IF seq = NIL OR next # NIL THEN { GGError.Append[gargoyleData.feedback, "Select a single sequence for a GetDistance.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO dist _ GGMeasure.LengthOfSegment[seg]/gargoyleData.hitTest.scaleUnit; oldFoundButton _ AtomButtons.AddValueSorted[gargoyleData, gargoyleData.hitTest.distanceHeader, [NIL, dist, LIST[$ToggleDistance, NEW[REAL _ dist]], on], incr]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleDistance: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; dist: REAL; epsilon: REAL = 0.001; firstButton, pushedButton: ScalarButtonClient; tiogaButton: TiogaButtons.TiogaButton; WITH event.rest.first SELECT FROM int: REF INT => dist _ int^; real: REF REAL => dist _ real^; ENDCASE => ERROR; firstButton _ gargoyleData.hitTest.distanceHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF ABS[thisButton.value-dist] < epsilon THEN { pushedButton _ thisButton; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; tiogaButton _ pushedButton.button; IF pushedButton.on THEN { pushedButton.on _ FALSE; TiogaButtons.ChangeButtonLooks[tiogaButton, "", "b"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; } ELSE { pushedButton.on _ TRUE; TiogaButtons.ChangeButtonLooks[tiogaButton, "b", ""]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; MeasureSlopeHit: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; viewer: Viewer _ gargoyleData.measure.slopeView; ViewerTools.SetSelection[viewer]; }; MeasureAngleHit: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; viewer: Viewer _ gargoyleData.measure.angleView; ViewerTools.SetSelection[viewer]; }; MeasureRadiusHit: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; viewer: Viewer _ gargoyleData.measure.radiusView; ViewerTools.SetSelection[viewer]; }; MeasureLineDistHit: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; viewer: Viewer _ gargoyleData.measure.lineDistView; ViewerTools.SetSelection[viewer]; }; DeleteCaretSegment: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; chair: REF ANY; jointNum, newEndJoint: NAT; traj, shortTraj: Traj; trajEnd: TrajEnd; shortOutline: Outline; outlineD: OutlineDescriptor; delSeq: Sequence; bBoxOfTraj: BoundBox; newOutlines: LIST OF Outline; caret: Caret _ gargoyleData.caret; point: Point; repaintBox: BoundBox _ GGCaret.BoundBoxOfCaret[caret, gargoyleData]; -- start with old caret IF GGCaret.SittingOnEnd[caret] THEN { -- delete the joint and segment near the caret chair _ GGCaret.GetChair[caret]; outlineD _ NARROW[chair]; [traj: traj, jointNum: jointNum] _ GGOutline.UnpackSimpleDescriptorOld[outlineD]; bBoxOfTraj _ GGTraj.GetBoundBox[traj]; SELECT jointNum FROM 0 => {newEndJoint _ 1; trajEnd _ lo}; GGTraj.HiJoint[traj] => {newEndJoint _ jointNum -1; trajEnd _ hi}; ENDCASE => SIGNAL Problem[msg: "failed assertion"]; point _ GGTraj.FetchJointPos[traj, newEndJoint]; delSeq _ GGSequence.LastSegAndJoint[traj, trajEnd]; [----, newOutlines] _ GGInterface.DeleteSequence[delSeq, gargoyleData.scene]; IF newOutlines = NIL THEN { -- we removed the last segment GGCaret.SitOn[caret, NIL]; } ELSE { jointSeq: Sequence; jointParts: SliceParts; jointD: OutlineDescriptor; IF newOutlines.rest # NIL THEN SIGNAL Problem[msg: "failed assertion"]; shortOutline _ newOutlines.first; shortTraj _ GGOutline.FenceOfOutline[shortOutline]; IF trajEnd = lo THEN jointSeq _ GGSequence.CreateFromJoint[shortTraj, 0] ELSE jointSeq _ GGSequence.CreateFromJoint[shortTraj, newEndJoint]; jointParts _ GGOutline.PartsFromSequence[shortOutline, jointSeq]; jointD _ NEW[OutlineDescriptorObj _ [shortOutline, jointParts]]; GGCaret.SitOn[gargoyleData.caret, jointD]; }; GGCaret.SetAttractor[gargoyleData.caret, point, NIL]; GGBoundBox.EnlargeByBox[repaintBox, bBoxOfTraj]; -- repaint deleted traj GGBoundBox.EnlargeByBox[repaintBox, GGCaret.BoundBoxOfCaret[caret, gargoyleData] ]; gargoyleData.refresh.startBoundBox^ _ repaintBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; } ELSE { GGError.Append[gargoyleData.feedback, "Place the caret on the end of a trajectory to BackSpace.", oneLiner]; }; }; END. zGGEventImplB.mesa Last edited by Bier on January 28, 1987 3:34:27 pm PST Contents: Once an event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module. Pier, January 15, 1987 2:43:35 pm PST Overlap Operations traverse the scene.entities from beginning (back) to end (front) Style Operations FOR slice: Slice _ GGObjects.NextSlice[sliceGen], GGObjects.NextSlice[sliceGen] UNTIL slice = NIL DO SLICES CAN'T ENUMERATE THEIR PARTS!! ENDLOOP; ENABLE GGParseIn.SyntaxError, GGParseIn.RopeNotOnTop; Alignment Operations Make sequences and slices hot. Fix the trigger bags, object bags, and Foreground plane (for efficiency). Repaint Update the hot and current trigger bags. Does AllAlignmentsOff, turns alignment processing on, sets the gravity extent to a default value, turns gravity on, sets gravity type to PreferPoints, resets the radius unit and turns heuristics on. This is done before creating or playing a session log to get repeatable results. GravityExtentChange[LIST[$GravityExtentChange, $InitialValue], gargoyleData]; Gravity Operations Units Menu Slope Line adds slope from angle viewer in measure line If the slopeViewValue was set internally, the viewer and the value will be consistent. If the SlopeValue viewer was set by typein, the viewer and the value will be inconsistent. only positive slopes, please put the most accurate value we have into variable slope only positive slopes, please NEVER delete very first button Gets selected segment slope, adds to slope menu and turns it on Angle Line adds angle from angle viewer in measure line See comments in AddSlope put the most accurate value we have into variable angle NEVER delete very first button Gets selected segment angle, adds to angle menu and turns it on Radius Line adds radius from Radius viewer in measure line See comments in AddSlope put the most accurate value we have into variable radius NEVER delete very first button GetRadius: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; seqGen: SequenceGenerator; segGen: SegmentGenerator; seq, next: Sequence; radius: REAL; seqGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; seq _ GGSequence.NextSequence[seqGen]; next _ GGSequence.NextSequence[seqGen]; IF seq = NIL OR next # NIL THEN { GGError.Append[gargoyleData.feedback, "Select a single segment for GetRadius.", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO radius _ GGVector.Distance[seg.lo, seg.hi]/gargoyleData.hitTest.scaleUnit; oldFoundButton _ AtomButtons.AddValueSorted[gargoyleData, gargoyleData.hitTest.radiusHeader, [NIL, radius, LIST[$ToggleRadius, NEW[REAL _ radius]], on], incr]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, gargoyleData: gargoyleData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; Distance Line adds distance from LineDistance viewer in measure line See comments in AddSlope put the most accurate value we have into variable distance NEVER delete very first button Coordinate/Measure Line Miscellaneous Pier, October 21, 1986 9:20:05 pm PDT changed all "edited: TRUE" to "edited: FALSE" in all NewAlignment* procs Ê=ȘIcode™Kšœ6™6šœ€™€Kšœ%™%—K™šÏk ˜ KšœÌœF˜”K˜—šÏn œœ˜Kšœìœ0˜¥Kšœ ˜—˜Kšœ œ˜'Kšœœ˜%Kšœœ ˜5Kšœ œ˜*Kšœœ!˜3Kšœ œ˜%Kšœœœ˜3Kšœœ%˜?Kšœœ˜"Kšœœ˜!Kšœœ"˜:Kšœœ"˜:Kšœœ˜!Kšœ œ˜'Kšœœ!˜7Kšœ œ˜'Kšœœ"˜9Kšœœ˜!Kšœœ ˜5Kšœ œ˜+Kšœœ˜3Kšœœ˜Kšœ œ˜%Kšœœ˜1Kšœ œ˜+Kšœ œ˜&Kšœœ˜#Kšœœ˜$K˜Kšœ œ˜Kšœ œ ˜K˜—Kšžœœ œ˜3K˜K™šžœœœ œœœœœœ˜BKšœœ ˜0Kšœ œœ˜Kšœ"˜"Kš œ œœœœ,˜E•StartOfExpansion#[g: GGModelTypes.EntityGenerator]šœ œœœœœœ˜Gšœœ˜Kšœ#˜#Kšœ)˜)Kšœ9˜9Kšœ@˜@Kšœœ˜—Kšœ*˜*Kšœ+˜+Kšœ˜—Kšœ}œ œœ˜«Kšœ˜K˜—šžœœœ œœœœœœ˜EKšœœ ˜0Kšœ œœ˜Kšœ"˜"Kš œ œœœœ,˜E–#[g: GGModelTypes.EntityGenerator]šœ œœœœœœ˜Gšœœ˜Kšœ#˜#Kšœ)˜)Kšœ9˜9Kšœ@˜@Kšœœ˜—Kšœ*˜*Kšœ*˜*Kšœ˜—Kšœ}œ œœ˜«Kšœ˜K˜—šžœœœ œœœœœœ˜DKšœœ ˜0Kš œ œœœœ,˜E–#[g: GGModelTypes.EntityGenerator]šœœœœœœœ˜AKšœ0˜0Kšœ˜—Kšœ}œ œœ˜«Kšœ˜K˜—šžœœœ œœœœœœ˜FKšœœ ˜0Kš œ œœœœ,˜E–#[g: GGModelTypes.EntityGenerator]šœœœœœœœ˜AKšœ2˜2Kšœ˜—Kšœ}œ œœ˜«Kšœ˜K˜—šžœœ3œœœœœ˜pK™@J˜Kšœœ˜ KšœB˜Bš œ œœDœ œ˜lKšœ?œœ˜`Kšœ˜—K–[list: LIST OF REF ANY]šœ œ˜-K˜—K˜K™šž œœœ œœœœœœ˜HKšœœ ˜0Jšœ(˜(Kšœ œ˜Kšœ˜Kšœ œœœ˜.Kšœ˜šœœ˜Kšœa˜aKšœ˜K˜—Kšœ&œV˜~K˜JšœA˜AJšœ?˜?š œ œœDœ œ˜lšœœ˜Jšœf˜fJšœp˜pJšœœ˜—Jšœ˜J˜—Kšœc˜cKšœ,˜,Kšœ†œ œœ˜µK˜K˜—šžœœœ œœœœœœ˜MKšœœ ˜0Kšœœœ˜KšœP˜PKšœ œœ,œœ!œœf˜Ôšœœœ˜KšœEœv˜½KšœAœp˜³Kšœœ˜—K˜K˜—šžœœœ œœœœœœ˜RKšœ œ ˜Kšœœ ˜0Kš œœœœœ˜2KšœD˜DKšœ œœ ˜#Kšœ1˜1šœGœœ˜]Kšœ;˜;šœkœœ˜Œšœ#œœ,œ˜]KšœF˜FKšœ9˜9Kšœ˜—Kšœ˜—Kšœ˜—šœMœ œ™dKš œœ œœœ™$Kšœ™—K–Û[feedback: ViewerClasses.Viewer, msgType: GGError.MsgType, format: ROPE _ NIL, v1: IO.Value _ [null[]], v2: IO.Value _ [null[]], v3: IO.Value _ [null[]], v4: IO.Value _ [null[]], v5: IO.Value _ [null[]]]šœh˜hKšœyœ œœ˜¨š˜Kšœ%œoœ'˜Ç—K˜K˜—šžœœœ œœœœœœ˜RKšœœ ˜0Kšœœœ˜.Kš œ œœœœ ˜'K˜%Kšœœ˜Kšœ/™5Kšœ/˜/Kšœ/˜/Kšœ/˜/š˜Jšœ(˜(Kšœ˜JšœA˜AJšœ?˜?š œ œœDœ œ˜lšœœ˜JšœTœ˜sJšœ^œ˜}Jšœœ˜—Jšœ˜J˜—Kšœc˜cKšœ,˜,Kšœ†œ œœ˜µKšœ˜—K˜K˜—šž œœœ œœœœœœ˜HKšœœ ˜0š˜Jšœ(˜(Kšœ˜JšœA˜AJšœ?˜?š œ œœDœ œ˜lšœœ˜JšœTœ˜[Jšœ^œ˜eJšœœ˜—Jšœ˜J˜—Kšœc˜cKšœ,˜,Kšœ†œ œœ˜µKšœ˜—K˜K˜K˜—šžœœœ œœœœœœ˜EKšœœ ˜0Kš œ œœœœ˜4Kšœœ˜K˜Jšœ œ˜J˜ J˜Jšœ ˜šœ˜JšœW˜WJšœ œ˜Jšœœ˜J˜—šœ˜Jšœ^˜^Jšœ œ˜Jšœœ˜J˜—˜Jšœ]˜]Jšœ œ˜Jšœœ˜J˜—˜Jšœa˜aJšœ œ˜Jšœœ˜J˜—šœ˜ JšœM˜MJšœ˜J˜J˜—KšœE˜Ešœ\œœ˜qK˜Kšœ˜Kšœ œ4˜DKšœ5˜9Kšœ˜—Kšœ}œ œœ˜¬Kšœ˜K˜—šžœœœœ˜.K˜Kšœ(˜(Kšœ$˜$šœœ˜Kšœœœ˜&Kšœœœœ˜AKšœœœ˜—K˜—K˜K™šžœœœ œœœœœœ˜FKšœœ ˜0Kšœ˜Kšœ1˜1Jšœ0˜0Kšœ?˜?KšÏb™š œ œœDœ œ˜lšœœ˜KšœY˜YKšœ]˜]Kšœœ˜—Kšœ˜—KšŸI™IKšœ8Ÿœ˜=šœpœ œ˜ŠKšœ"Ÿœ4Ïc˜{Kšœœœ ˜"KšœŸœC ˜}Kšœ9 ˜P—Kšœ˜Jšœ;Ÿœ˜@šœ{œ œ˜“Jšœ$Ÿœ2 ˜yKšœœœ ˜"KšœŸœE ˜Kšœ9 ˜PJšœ˜—KšŸ™Kšœyœ œœ˜§K˜K˜—šž œœœ œœœœœœ˜IKšœœ ˜0Kšœ˜Kšœ1˜1KšœB˜Bš œ œœDœ œ˜lšœœ˜šœ˜Kšœ5œ ˜DKšœA˜AK˜—˜Kšœ?˜?K˜—Kšœœ˜—Kšœ˜KšŸ(™(—Kšœ8Ÿœ˜=šœpœ œ˜ŠKšœ"Ÿœ œ*˜qKšœœœ ˜"KšœŸœB˜kKšœ8˜8—Kšœ˜Kšœœ œœ˜­K˜K˜—šžœœœ œœœœœœ˜GKšœœ ˜0Kšœ˜Kšœ7Ÿœ˜?š œ œœDœ œ˜lKšœ9˜9—Kšœ˜Kšœ€œ œœ˜®K˜K˜—šž œœœ œœœœœœ˜JKšœœ ˜0Kšœ˜Kšœ7Ÿœ˜<š œ œœDœ œ˜lKšœ9˜9—Kšœ˜Kšœ€œ œœ˜®K˜K˜—šžœœœ œœœœœœ˜FKšœœ ˜0Kšœœ˜$Kšœyœ œœ˜§K˜K˜—šžœœœ œœœœœœ˜FKšœœ ˜0Kšœœ˜#Kšœzœ œœ˜¨K˜K˜—šž œœœ œœœœœœ˜IKšœœ ˜0Kšœ6˜6Kšœ_ ˜tKšœ] "˜Kšœyœ œœ˜§K˜K˜—šž œœœ œœœœœœ˜IKšœœ ˜0šœ%œ˜-Kšœ"˜"KšœU˜UKšœ]˜]Kšœ|œ œœ˜ªK˜—K˜K™—šžœœœ œœœœœœ˜QKšœœ ˜0Kšœ"˜"Kšœ"˜"Kšœ!˜!Kšœ%˜%Kšœ…œ œœ˜³K˜K˜—šžœœœ œœœœœœ˜OKšœœ ˜0Kšœ!˜!Kšœ!˜!Kšœ"˜"Kšœ$˜$KšœFœœ˜pK˜K˜—šžœœœ œœœœœœ˜SKšœ˜™˜Kšœœ ˜0Kšœœ˜$KšœCœœ˜nKšœœ5™MKšœCœœ˜kKšœSœœœ4˜¬Kšœœ˜!KšœIœœ˜tKšœ˜—K˜K™šžœœœ œœœœœœ˜RKšœœ ˜0KšœE˜EKšœ œ˜šœ!˜'Kšœœ˜4—šœ˜Kšœœ˜6—Kšœ˜šœœ˜Kšœ#œ7˜^Kšœ!œ4˜YKšœœ˜—Kšœ"˜"K˜K˜—šžœœœ œœœœœœ˜RKšœœ ˜0Kšœœ˜ Kšœ œœ˜KšœY˜YKšœ1˜1šœ˜šœ ˜ Kšœœ˜)šœ˜Kšœ_˜_Kšœ%˜%Kšœ œ˜K˜—K˜—Kšœ ˜ Kšœ1˜8—šœ œ˜Kšœ4˜4K˜—K˜K˜—šžœœœ œœœœœœ˜OKšœœ ˜0Kšœœ˜ KšœY˜YKšœ œœœ˜-Kšœ0˜0K˜K˜—šžœœœœ˜3Kšœœ ˜0šœ=˜Gšœœ"˜2KšœH˜HKšœB˜BKšœœ ˜-—Kšœ2˜2Kšœœ˜—K˜—K˜šžœœœ œœœœœœ˜QKšœ œ˜Kšœœ ˜0KšœA˜Ašœ!˜'Kšœœ˜4—šœ˜Kšœœ˜6—Kšœ˜šœœ˜šœœ˜)Kšœ#˜#Kšœ)˜)Kšœ˜—šœ œ˜*Kšœ#˜#Kšœ*˜*Kšœ˜—šœœ˜&Kšœ&˜&Kšœ)˜)Kšœ˜—Kšœœ˜—Kšœzœ œœ˜©Kšœ˜K˜—šžœœœ œœœœœœ˜OKšœœ ˜0Kšœ6˜6Kšœ#˜#Kšœzœ œœ˜©K˜K˜—šžœœœ œœœœœœ˜OKšœœ ˜0Kšœ6˜6Kšœ#˜#šœ'˜1Kšœ+œ˜1Kšœ,œ˜1Kšœœ˜—Kšœœ œœ˜®K˜K˜—šžœœœ œœœœœœ˜NKšœœ ˜0Kšœ:˜:Kšœ#˜#Kšœsœ œœ˜¢K˜K˜—šžœœœ"œ˜LKšœ:˜:Kšœœ.˜9Kšœ œ$˜6K˜K˜—šžœœœ œœœœœœ˜OKšœœ ˜0Kšœ<˜˜>Jšœ9˜9Jšœœœ ˜'Jšœ˜Jšœ9˜9Jšœœœ ˜'Jšœ˜Jšœ9˜9Jšœœœœ ˜+J˜—šœ˜Jšœ3˜3Jšœ œœœ ˜!Jšœ9˜9Jšœ6˜6Jšœœœ ˜'Jšœ˜Jšœ6˜6Jšœœœ ˜'Jšœ˜Jšœ6˜6Jšœœœœ ˜+J˜—š˜šœ ˜ KšœZ˜ZKšœ%˜%Kšœ˜K˜——šœ˜J˜——KšœP˜PKš œ^œ œœœ˜ŸKšœƒœ œœ˜±Kšœ˜K˜K˜—šž œœœ œœœœœœ˜KKšœœ ˜0Kšœœ˜ Kšœ œ ˜Kšœ.˜.Kšœ&˜&šœœ˜!Kšœœœ˜Kšœœœ˜!Kšœœ˜—Kšœ>˜>šœ?œœ˜[šœœ$œ˜0Kšœ˜Kšœ˜K˜——š˜Kšœœ˜—Kšœ˜Kšœ"˜"šœœ˜Kšœœ˜Kšœ5˜5Kšœ…œ œœ˜³K˜—šœ˜Kšœœ˜Kšœ5˜5Kšœƒœ œœ˜±K˜—K˜—K˜K™ šžœœœ œœœœœœ˜PKšœœ ˜0Kšœ$˜$šœjœœ˜tKšœœœœ ˜NKšœ œœœ˜8Kšœœœœ˜EKšœœœœ˜BKšœ œœœ˜:Kšœ œœœ˜7K˜—šœ"˜(Kšœ…œ œœ˜³—K˜K˜—šžœœœ œœœœœœ˜MKšœœ ˜0KšœT˜Tšœ?œœ˜[Kš œœœœœœ%˜\Kšœ˜—K˜K˜—šž œœœ œœœœœœ˜JKšœœ ˜0K™6Kšœ/˜/K™Kšœ œN˜\šœœ˜%K–B[gargoyleData: REF ANY, msg: ROPE, msgType: GGError.MsgType]šœ^˜^Kšœ%˜%Kšœ˜K˜K˜—Kšœ:™:KšœLœ3œ3˜¼Kš œ‡œ œœœŸœ˜Õšœœœ ˜5Kšœƒœ œœ˜±K˜—K˜K˜—šžœœœ(œ˜QKšœ/˜/Kšœ2˜2Kš œ‡œ œœœŸœ˜ÖK˜K˜—šžœœœ œœœœœœ˜MKšœœ ˜0K™KšœS˜SšœCœœ˜_šœœ˜Kšœ-˜-Kšœ"˜"K˜—Kšœ˜Kšœ˜—Kšœ= ˜WKšœ…œ œœ˜³Kšœ˜K˜—šž œœœ œœœœœœ˜JKšœœ ˜0Kšœ/˜/Kšœ˜Kšœ˜Kšœ˜Kšœœ˜ Kšœ@˜@Kšœ&˜&Kšœ'˜'š œœœœœ˜!Kšœ_˜_Kšœ%˜%Kšœ˜K˜—Kšœ,˜,šœOœœ˜dKšœE˜EKš œ`œœœœ˜ŸKšœ˜—Kšœƒœ œœ˜±Kšœ˜K˜—šžœœœ œœœœœœ˜MKšœœ ˜0Kšœœ˜ Kšœ œ ˜Kšœ.˜.Kšœ&˜&šœœ˜!Kšœœœ˜Kšœœœ˜Kšœœ˜—Kšœ@˜@šœ?œœ˜[šœœ"œ˜.Kšœ˜Kšœ˜K˜——š˜Kšœœ˜—Kšœ˜Kšœ"˜"šœœ˜Kšœœ˜Kšœ5˜5Kšœ…œ œœ˜³K˜—šœ˜Kšœœ˜Kšœ5˜5Kšœƒœ œœ˜±K˜—K˜—K˜K™šžœœœ œœœœœœ˜NKšœœ ˜0Kšœ0˜0Kšœ!˜!K˜K˜—šžœœœ œœœœœœ˜NKšœœ ˜0Kšœ0˜0Kšœ!˜!K˜K˜—šžœœœ œœœœœœ˜OKšœœ ˜0Kšœ1˜1Kšœ!˜!K˜K˜—šžœœœ œœœœœœ˜QKšœœ ˜0Kšœ3˜3Kšœ!˜!K˜—K˜K™ šžœœœ œœœœœœ˜QKšœœ ˜0Kšœœœ˜Kšœœ˜Kšœ˜K˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœ œœ ˜Kšœ"˜"K˜ KšœE ˜\šœœ .˜TKšœ ˜ Kšœ œ˜K˜QKšœ&˜&šœ ˜Kšœ%˜%KšœB˜BKšœœ"˜3—Kšœ0˜0Kšœ3˜3Kšœ œH˜Mšœœœ ˜:Kšœœ˜K˜—šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœœœœ"˜GKšœ!˜!Kšœ3˜3Kšœœ4˜HKšœ?˜CKšœA˜AKšœ œ4˜@Kšœ*˜*K˜—Kšœ0œ˜5K˜Kšœ1 ˜HKšœS˜SKšœ2˜2KšœŒœ œœ˜ºK˜—šœ˜Kšœl˜lK˜—Kšœ˜—K˜Kšœ˜™%K™I—K™—…—ã².ô