DIRECTORY CubicSplines, GGAlign, GGAngle, GGBasicTypes, GGBoundBox, GGButtons, GGCaret, GGEditTool, GGError, GGEvent, GGGraphicsButton, GGGravity, GGInterface, GGInterfaceTypes, GGModelTypes, GGObjects, GGOutline, GGRefresh, GGSegmentTypes, GGSelect, GGSequence, GGTraj, GGUserInput, GGVector, GGViewerOps, GGWindow, IO, List, Real, RealFns, Rope, TiogaButtons, ViewerClasses, ViewerTools; GGEventImplB: CEDAR PROGRAM IMPORTS GGAlign, GGAngle, GGBoundBox, GGButtons, GGCaret, GGEditTool, GGError, GGGraphicsButton, GGInterface, GGObjects, 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 = GGButtons.ScalarButtonClient; ScalarButtonHandle: TYPE = GGButtons.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 = GGButtons.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];}; }; 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 GGButtons.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 GGButtons.GetButtonState[gargoyleData.refresh.alignments] = off THEN ToggleAlignments[NIL, gargoyleData]; IF GGButtons.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 GGButtons.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: GGButtons.EnumTypeRef _ gargoyleData.hitTest.gravityTypeMenu; name: Rope.ROPE; IF event.rest.first = $FlipForward THEN GGButtons.TimeToFlipThru[LIST[$FlipForward, info]] ELSE GGButtons.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 GGButtons.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: GGButtons.EnumTypeRef _ gargoyleData.refresh.screenStyle; IF event.rest.first = $FlipForward THEN GGButtons.TimeToFlipThru[LIST[$FlipForward, info]] ELSE GGButtons.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; GGButtons.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; GGButtons.SwitchState[stateInfo]; SELECT GGButtons.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; GGButtons.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 _ GGButtons.GetButtonState[stateInfo] = on; IF wasOn # on THEN GGButtons.SwitchState[stateInfo]; }; ToggleHeuristics: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; stateInfo: TwoState _ gargoyleData.hitTest.heuristicsButton; GGButtons.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; GGButtons.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]; GGButtons.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: GGButtons.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 _ GGButtons.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: GGButtons.ScalarButtonClient; IF degrees<0.0 THEN degrees _ degrees+180.0; IF degrees=360.0 THEN degrees _ 0.0; gargoyleData.measure.slopeViewValue _ degrees; oldFoundButton _ GGButtons.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: GGButtons.ScalarButtonClient; seqGen: SequenceGenerator; segGen: SegmentGenerator; seq, next: Sequence; direction: Vector; 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 direction _ GGVector.VectorFromPoints[seg.lo, seg.hi]; degrees _ GGAngle.Normalize[GGVector.AngleFromVector[direction]]; IF degrees<0.0 THEN degrees _ degrees+180.0; IF degrees=360.0 THEN degrees _ 0.0; oldFoundButton _ GGButtons.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]; GGButtons.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: GGButtons.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 _ GGButtons.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: GGButtons.ScalarButtonClient; IF degrees=360.0 THEN degrees _ 0.0; gargoyleData.measure.angleViewValue _ degrees; oldFoundButton _ GGButtons.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: GGButtons.ScalarButtonClient; seqGen: SequenceGenerator; segGen: SegmentGenerator; seq, next: Sequence; v1, v2: Vector; 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; v1 _ GGVector.VectorFromPoints[firstSeg.lo, firstSeg.hi]; v2 _ GGVector.VectorFromPoints[secondSeg.lo, secondSeg.hi]; degrees _ GGAngle.Normalize[GGVector.AngleCCWBetweenVectors[v1: v1, v2: v2]]; IF degrees=360.0 THEN degrees _ 0.0; oldFoundButton _ GGButtons.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]; GGButtons.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: GGButtons.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 _ GGButtons.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: GGButtons.ScalarButtonClient; gargoyleData.measure.radiusViewValue _ radius; oldFoundButton _ GGButtons.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: GGButtons.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 _ GGVector.Distance[p0, p1]/gargoyleData.hitTest.scaleUnit; oldFoundButton _ GGButtons.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]; GGButtons.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: GGButtons.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 _ GGButtons.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: GGButtons.ScalarButtonClient; gargoyleData.measure.lineDistViewValue _ distance; oldFoundButton _ GGButtons.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: GGButtons.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 _ GGVector.Distance[seg.lo, seg.hi]/gargoyleData.hitTest.scaleUnit; oldFoundButton _ GGButtons.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. ^GGEventImplB.mesa Last edited by Bier on January 19, 1987 10:19:55 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; 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 only positive slopes, please 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: GGButtons.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 _ GGButtons.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 ʘ>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šœB˜BKš œ\œ œœœ˜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šœ$˜$šœhœœ˜rKšœœœœ ˜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šœH˜HKš œ^œœœœ˜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™—…—Û<$»