DIRECTORY GGMouseEvent, BiScrollers, CodeTimer, CubicSplines, Feedback, FeedbackTypes, Geom2D, GGAlign, GGBasicTypes, GGBoundBox, GGCaret, GGControlPanelTypes, GGCoreOps, GGCoreTypes, GGDescribe, GGEmbedTypes, GGEvent, GGHistory, GGHistoryTypes, GGInterfaceTypes, GGMeasure, GGModelTypes, GGParent, GGParseIn, GGRefresh, GGRefreshTypes, GGScene, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGSliceOps, GGState, GGTraj, GGUIUtility, GGUserInput, GGViewerOps, GGWindow, Imager, ImagerBox, ImagerTransformation, IO, Real, Rope, Vectors2d; GGEventImplB: CEDAR PROGRAM IMPORTS GGMouseEvent, BiScrollers, CodeTimer, Feedback, GGAlign, GGBoundBox, GGCaret, GGCoreOps, GGDescribe, GGHistory, GGMeasure, GGParent, GGParseIn, GGRefresh, GGScene, GGSelect, GGSequence, GGSlice, GGSliceOps, GGState, GGTraj, GGUIUtility, GGUserInput, GGViewerOps, GGWindow, ImagerBox, ImagerTransformation, IO, Rope, Vectors2d EXPORTS GGEvent, GGHistoryTypes, GGInterfaceTypes = BEGIN AlignBag: TYPE = GGInterfaceTypes.AlignBag; BiScroller: TYPE = BiScrollers.BiScroller; BoundBox: TYPE = GGModelTypes.BoundBox; Camera: TYPE = GGModelTypes.Camera; Caret: TYPE = GGInterfaceTypes.Caret; Change: PUBLIC TYPE = GGHistory.Change; -- exported to GGHistoryTypes ControlsObj: PUBLIC TYPE = GGControlPanelTypes.ControlsObj; -- exported to GGInterfaceTypes DisplayStyle: TYPE = GGModelTypes.DisplayStyle; EmbedDataObj: PUBLIC TYPE = GGEmbedTypes.EmbedDataObj; -- exported to GGInterfaceTypes FeatureData: TYPE = GGInterfaceTypes.FeatureData; MsgRouter: TYPE = FeedbackTypes.MsgRouter; FilterLists: TYPE = GGAlign.FilterLists; GGData: TYPE = GGInterfaceTypes.GGData; GravityType: TYPE = GGInterfaceTypes.GravityType; HistoryEvent: TYPE = GGHistoryTypes.HistoryEvent; Point: TYPE = GGBasicTypes.Point; RefreshDataObj: PUBLIC TYPE = GGRefreshTypes.RefreshDataObj; Scene: TYPE = GGModelTypes.Scene; SegAndIndex: TYPE = GGSequence.SegAndIndex; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SequenceOfReal: TYPE = REF SequenceOfRealObj; SequenceOfRealObj: TYPE = GGCoreTypes.SequenceOfRealObj; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceParts: TYPE = GGModelTypes.SliceParts; StrokeEnd: TYPE = Imager.StrokeEnd; StrokeJoint: TYPE = Imager.StrokeJoint; Traj: TYPE = GGModelTypes.Traj; TrajData: TYPE = GGModelTypes.TrajData; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajParts: TYPE = GGModelTypes.TrajParts; TriggerBag: TYPE = GGInterfaceTypes.TriggerBag; Transformation: TYPE = ImagerTransformation.Transformation; UserInputProc: TYPE = GGEvent.UserInputProc; Vector: TYPE = GGBasicTypes.Vector; WalkProc: TYPE = GGModelTypes.WalkProc; pointsPerIn: REAL = 72.0; pointsPerCm: REAL = 72.0/2.54; reallyBigReal: REAL = 1.0e37; multipleValues: Rope.ROPE = "multiple values - Aborted!!"; complainAboutIconic: Rope.ROPE = "Viewing transformations not allowed on iconic viewer"; Problem: SIGNAL [msg: Rope.ROPE] = Feedback.Problem; GetArg: PROC [diffOK: BOOL _ FALSE, sel: Rope.ROPE, router: MsgRouter] RETURNS [valid: BOOL, arg, arg2: REAL _ 0.0] ~ { s: IO.STREAM; valid _ SELECT sel.Length[] FROM > 1 => TRUE, > 0 => sel.Fetch[0] IN ['0 .. '9], ENDCASE => FALSE; IF NOT valid THEN RETURN; s _ IO.RIS[sel]; { ENABLE IO.Error, IO.EndOfStream => { valid _ FALSE; Feedback.PutF[router, oneLiner, $Complaint, "Select a number, not %g", IO.refAny[sel]]; CONTINUE}; arg _ arg2 _ s.GetReal[]; IF diffOK AND (NOT s.EndOf[]) AND s.PeekChar[]=': THEN { IF NOT s.GetChar[]=': THEN ERROR; arg2 _ s.GetReal[]; valid _ valid}; IF NOT s.EndOf[] THEN IO.Error[ec: SyntaxError, stream: s]; }; s.Close[]; }; GetBiScroller: PROC[ggData: GGData] RETURNS [bs: BiScrollers.BiScroller] = { iconW, iconH: INT _ 0; w: INT _ GGState.GetWidth[ggData]; h: INT _ GGState.GetHeight[ggData]; [iconW, iconH] _ GGViewerOps.GetIconSize[]; RETURN [IF w>iconW AND h>iconH THEN GGState.GetBiScroller[ggData] ELSE NIL]; -- NIL means viewer is iconic or pathologically small }; ScalePop: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { key: REF ANY _ event.rest.first; sel: Rope.ROPE _ NARROW[event.rest.rest.first]; valid: BOOL; arg, arg2: REAL; [valid, arg, arg2] _ GetArg[TRUE, sel, ggData.router]; IF NOT valid THEN arg _ arg2 _ 2.0; IF key=$Shrink THEN {arg _ 1.0/arg; arg2 _ 1.0/arg2}; BiScrollers.Scale[ bs: bs, op: SELECT key FROM $Magnify, $Shrink => IF arg=arg2 THEN [byArg[arg]] ELSE [diff[arg, arg2]], $Reset => [reset[]], ENDCASE => ERROR, paint: FALSE ]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic]; }; RotatePop: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { key: REF ANY _ event.rest.first; sel: Rope.ROPE _ NARROW[event.rest.rest.first]; valid: BOOL; arg: REAL; [valid, arg] _ GetArg[FALSE, sel, ggData.router]; IF NOT valid THEN arg _ 90; BiScrollers.Rotate[ bs: bs, op: SELECT key FROM $Left => [byArg[arg]], $Right => [byArg[-arg]], $Half => [byArg[180]], $Reset => [reset[]], ENDCASE => ERROR, paint: FALSE ]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic]; }; FitPop: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { cw: INT _ GGState.GetWidth[ggData]; ch: INT _ GGState.GetHeight[ggData]; key: REF ANY _ event.rest.first; limits: Imager.Box; uniformly: BOOL ~ SELECT key FROM $FitUniformly => TRUE, $FitXY => FALSE, ENDCASE => ERROR; [limits.xmin, limits.xmax] _ BiScrollers.ViewLimitsOfImage[bs, X]; [limits.ymin, limits.ymax] _ BiScrollers.ViewLimitsOfImage[bs, Y]; BiScrollers.BoxScale[ bs: bs, from: ImagerBox.RectangleFromBox[limits], to: [0, 0, cw, ch], paint: FALSE, uniformly: uniformly]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic]; }; ResetPop: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { key: REF ANY _ event.rest.first; SELECT key FROM $Vanilla => { bs.style.ChangeTransform[bs: bs, new: bs.class.common.vanilla[bs], ageOp: remember, paint: FALSE]; -- don't set paint=TRUE here so queing works properly GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; -- paint properly }; $VanillaAndCenter => { bs.style.ChangeTransform[bs: bs, new: bs.class.common.vanilla[bs], ageOp: remember, paint: FALSE]; }; $Center => NULL; ENDCASE => ERROR; SELECT key FROM $Center, $VanillaAndCenter => { BiScrollers.Align[ bs: bs, client: [fraction[0.5, 0.5]], viewer: [fraction[0.5, 0.5]], doX: TRUE, doY: TRUE, paint: FALSE, ageOp: remember]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; }; $Vanilla => NULL; ENDCASE => ERROR; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic]; }; EdgePop: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { key: REF ANY _ event.rest.first; loc: fraction BiScrollers.Location _ [fraction[0, 0]]; doX, doY: BOOL _ TRUE; SELECT key FROM $Left => {loc.fx _ 0; doY _ FALSE}; $Right => {loc.fx _ 1; doY _ FALSE}; $Bottom => {loc.fy _ 0; doX _ FALSE}; $Top => {loc.fy _ 1; doX _ FALSE}; $BotLeft => loc _ [fraction[0, 0]]; $MidLeft => loc _ [fraction[0, 0.5]]; $TopLeft => loc _ [fraction[0, 1]]; $BotMiddle => loc _ [fraction[0.5, 0]]; $BotRight => loc _ [fraction[1, 0]]; $MidRight => loc _ [fraction[1, 0.5]]; $TopRight => loc _ [fraction[1, 1]]; $TopMiddle => loc _ [fraction[0.5, 1]]; ENDCASE => ERROR; BiScrollers.Align[bs: bs, client: loc, viewer: loc, doX: doX, doY: doY, paint: FALSE]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic]; }; PrevTransform: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { bs.style.ChangeTransform[ bs: bs, new: bs.style.GetTransforms[bs, previous].clientToViewer, ageOp: remember, paint: FALSE]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; }; }; CenterSel: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { bBox: GGBoundBox.BoundBox _ GGScene.BoundBoxOfSelected[scene: ggData.scene, selectClass: normal]; IF bBox.null THEN { IF GGCaret.Exists[ggData.caret] THEN { caretPos: Point _ GGCaret.GetPoint[ggData.caret]; BiScrollers.Align[ bs: bs, client: [variant: coord[x: caretPos.x, y: caretPos.y]], viewer: [variant: fraction[fx: 0.5, fy: 0.5]], paint: FALSE]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "CenterSel failed: either a selection or a caret is required to center"]; } ELSE { BiScrollers.Align[ bs: bs, client: [variant: coord[x: (bBox.loX+bBox.hiX)/2.0, y: (bBox.loY+bBox.hiY)/2.0]], viewer: [variant: fraction[fx: 0.5, fy: 0.5]], paint: FALSE]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; }; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic]; }; CenterCaret: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { IF GGCaret.Exists[ggData.caret] THEN { caretPos: Point _ GGCaret.GetPoint[ggData.caret]; BiScrollers.Align[ bs: bs, client: [variant: coord[x: caretPos.x, y: caretPos.y]], viewer: [variant: fraction[fx: 0.5, fy: 0.5]], paint: FALSE]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "CenterCaret failed: a caret is required to center"]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic]; }; FitSel: PUBLIC UserInputProc = { bs: BiScrollers.BiScroller = GetBiScroller[ggData]; IF bs#NIL THEN { tbBox, vBox, tvBox: Geom2D.Rect; cToV: ImagerTransformation.Transformation; bBox: GGBoundBox.BoundBox _ GGScene.BoundBoxOfSelected[scene: ggData.scene, selectClass: normal]; IF bBox.null THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "FitSel failed: a selection is required to fit"] ELSE { cToV _ BiScrollers.GetStyle[].GetTransforms[bs].clientToViewer; tbBox _ ImagerTransformation.TransformRectangle[cToV, GGBoundBox.RectangleFromBoundBox[bBox] ]; vBox _ BiScrollers.ViewportBox[bs]; tvBox _ ImagerTransformation.TransformRectangle[cToV, vBox]; BiScrollers.BoxScale[bs: bs, from: tbBox, to: tvBox, paint: FALSE]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; }; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic]; }; SetBiScrollersTransform: PUBLIC UserInputProc = { rope: Rope.ROPE _ NARROW[event.rest.first]; clientToViewer: Imager.Transformation _ GGDescribe.FactoredTransformationFromRope[rope ! GGParseIn.SyntaxError => GOTO SyntaxError]; GGState.SetBiScrollersTransform[ggData, clientToViewer]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "SetBiScrollersTransform failed: select a legal factored transformation for SetBiScrollersTransform"]; }; ShowBiScrollersTransform: PUBLIC UserInputProc = { clientToViewer: Imager.Transformation _ GGState.GetBiScrollersTransform[ggData]; Feedback.PutF[ggData.router, oneLiner, $Show, "BiScrollers transform: %g", [rope[GGDescribe.FactoredTransformationToRope[clientToViewer] ]] ]; }; ScrollBar: UserInputProc = { bs: BiScrollers.BiScroller = GGState.GetBiScroller[ggData]; newEvent: LIST OF REF; newEvent _ CONS[$First, event]; -- so no paint occurs with clearClient = TRUE BiScrollers.DoBSUserAction[bs, newEvent]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; }; OneZoom: UserInputProc = { GGState.BiScrollersTransform[ggData, ggData.embed.scrollDue]; ggData.embed.scrollDue _ ImagerTransformation.Scale[1.0]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; }; identity: Transformation = ImagerTransformation.Scale[1.0]; IsIdentity: PROC [m: Transformation] RETURNS [BOOL] = { RETURN[ImagerTransformation.Equal[m, identity]]; }; OneScroll: UserInputProc = { clientToViewer, viewerToClient: Transformation; caretPoint: Point; caretViewer: Point; caretClient: Point; IF IsIdentity[ggData.embed.scrollDue] THEN RETURN; clientToViewer _ GGState.GetBiScrollersTransform[ggData]; caretPoint _ GGCaret.GetPoint[ggData.caret]; caretViewer _ ImagerTransformation.Transform[clientToViewer, caretPoint]; GGState.BiScrollersTransform[ggData, ggData.embed.scrollDue]; ggData.embed.scrollDue _ ImagerTransformation.Scale[1.0]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; viewerToClient _ GGState.GetBiScrollersTransforms[ggData].viewerToClient; caretClient _ ImagerTransformation.Transform[viewerToClient, caretViewer]; GGMouseEvent.HandleMouse[ggData, LIST[$During, NEW[Point _ caretClient]]]; }; ViewersPaintEntireScene: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; }; ViewersPaintAllPlanes: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[$ViewersPaintAllPlanes, ggData, none, FALSE, TRUE]; }; MakeHot: PUBLIC UserInputProc = { IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "MakeHot failed: select some objects for MakeHot"] ELSE { MakeSliceHot: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSelect.SelectSlice[sliceD, ggData.scene, hot]; }; UpdateTriggerAndAlignBags: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { sliceFeature: FeatureData _ GGAlign.AddSliceFeature[sliceD, triggerBag]; alignObjects: LIST OF FeatureData; alignObjects _ GGAlign.IncrementalNewTrigger[sliceFeature, filterLists, NOT showAlignments, alignBag]; GGRefresh.NoteNewForeground[ggData, alignObjects]; -- fix foreground plane }; showAlignments: BOOL _ GGState.GetShowAlignments[ggData]; triggerBag: TriggerBag _ ggData.hitTest.triggerBag; alignBag: AlignBag _ ggData.hitTest.alignBag; filterLists: FilterLists _ GGState.GetFilterLists[ggData]; CodeTimer.StartInt[$MakeHot, $Gargoyle]; [] _ GGScene.WalkSelectedSlices[ggData.scene, first, MakeSliceHot, normal]; [] _ GGScene.WalkSelectedSlices[ggData.scene, first, UpdateTriggerAndAlignBags, hot]; Feedback.Append[ggData.router, oneLiner, $Feedback, "MakeHot: selected objects made hot"]; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; CodeTimer.StopInt[$MakeHot, $Gargoyle]; }; }; MakeAllHot: PUBLIC UserInputProc = { MakeSliceHot: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { GGSelect.SelectEntireSlice[slice, ggData.scene, hot]; }; triggerBag: TriggerBag _ ggData.hitTest.triggerBag; alignBag: AlignBag _ ggData.hitTest.alignBag; CodeTimer.StartInt[$MakeAllHot, $Gargoyle]; [] _ GGScene.WalkSlices[ggData.scene, first, MakeSliceHot]; Feedback.Append[ggData.router, oneLiner, $Feedback, "MakeAllHot: all objects made hot"]; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, ggData: ggData, remake: triggerBagNotSceneBag, edited: FALSE, okToSkipCapture: FALSE]; CodeTimer.StopInt[$MakeAllHot, $Gargoyle]; }; MakeCold: PUBLIC UserInputProc = { IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "MakeCold failed: select some objects for MakeCold"] ELSE { MakeSliceCold: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, ggData.scene, hot]; }; CodeTimer.StartInt[$MakeCold, $Gargoyle]; [] _ GGScene.WalkSelectedSlices[ggData.scene, first, MakeSliceCold, normal]; Feedback.Append[ggData.router, oneLiner, $Feedback, "MakeCold: selected objects made cold"]; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: FALSE]; CodeTimer.StopInt[$MakeCold, $Gargoyle]; }; }; MakeAllCold: PUBLIC UserInputProc = { MakeSliceCold: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, ggData.scene, hot]; }; CodeTimer.StartInt[$MakeAllCold, $Gargoyle]; [] _ GGScene.WalkSelectedSlices[ggData.scene, first, MakeSliceCold, hot]; Feedback.Append[ggData.router, oneLiner, $Feedback, "MakeCold: all objects made cold"]; GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: FALSE]; CodeTimer.StopInt[$MakeAllCold, $Gargoyle]; }; DropAnchor: PUBLIC UserInputProc = { IF GGCaret.Exists[ggData.caret] THEN { IF GGCaret.Exists[ggData.anchor] THEN GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, anchor: TRUE] ELSE GGRefresh.NullStartBox[ggData]; GGCaret.Copy[to: ggData.anchor, from: ggData.caret]; [] _ GGAlign.CreateAnchorTrigger[ggData.anchor, ggData.hitTest.triggerBag]; Feedback.Append[ggData.router, oneLiner, $Feedback, "DropAnchor: anchor dropped"]; GGWindow.RestoreScreenAndInvariants[paintAction: $AnchorAdded, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "DropAnchor failed: caret needed to drop anchor"]; }; LiftAnchor: PUBLIC UserInputProc = { IF GGCaret.Exists[ggData.anchor] THEN { GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, anchor: TRUE, alignments: TRUE]; GGCaret.Kill[ggData.anchor]; Feedback.Append[ggData.router, oneLiner, $Feedback, "LiftAnchor: anchor lifted"]; GGWindow.RestoreScreenAndInvariants[paintAction: $AnchorRemoved, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: TRUE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "LiftAnchor failed: no anchor"]; }; StandardAlignments: PUBLIC UserInputProc = { StandardSlopes[ggData, event]; StandardAngles[ggData, event]; StandardRadii[ggData, event]; StandardDistances[ggData, event]; IF event.first = $StandardAlignments THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "StandardAlignments: standard alignments set"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE]; }; }; ClearAlignments: PUBLIC UserInputProc = { ClearSlopes[ggData, event]; ClearAngles[ggData, event]; ClearRadii[ggData, event]; ClearDistances[ggData, event]; IF event.first = $ClearAlignments THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "ClearAlignments: alignments cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE]; }; }; AllAlignmentsOff: PUBLIC UserInputProc = { SlopePrompt[ggData, event]; AnglePrompt[ggData, event]; RadiusPrompt[ggData, event]; DistancePrompt[ggData, event]; GGState.SetMidpoints[ggData, FALSE]; IF event.first = $AllAlignmentsOff THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "AllAlignmentsOff: all alignments off"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE]; }; }; InitializeAlignments: PUBLIC UserInputProc = { AllAlignmentsOff[ggData, event]; IF event.first = $InitializeAlignments THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "InitializeAlignments: alignments initialized"]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE]; }; }; DisplayStyleChange: PUBLIC UserInputProc = { forward: BOOL _ event.rest.first = $FlipForward; camera: Camera _ ggData.camera; SetTextDisplayStyle: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { GGSlice.SetTextDisplayStyle[slice, camera.displayStyle, NIL]; }; GGState.CycleDisplayStyle[ggData, forward]; [] _ GGScene.WalkSlices[scene: ggData.scene, level: leaf, walkProc: SetTextDisplayStyle, classType: $Text]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Display style changed"]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; ToggleShowAlignments: PUBLIC UserInputProc = { GGState.SetShowAlignments[ggData, NOT GGState.GetShowAlignments[ggData]]; IF event.first = $ToggleShowAlignments THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE]; }; SetShowAlignments: PUBLIC UserInputProc = { boolRope: Rope.ROPE _ NARROW[event.rest.first]; showAlignments: BOOL _ GGCoreOps.RopeToBool[boolRope]; GGState.SetShowAlignments[ggData, showAlignments]; }; ToggleMidpoints: PUBLIC UserInputProc = { GGState.SetMidpoints[ggData, NOT GGState.GetMidpoints[ggData]]; IF event.first = $ToggleMidpoints THEN GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE]; }; SetMidpoints: PUBLIC UserInputProc = { boolRope: Rope.ROPE _ NARROW[event.rest.first]; setMidpoints: BOOL _ GGCoreOps.RopeToBool[boolRope]; GGState.SetMidpoints[ggData, setMidpoints]; }; ToggleHeuristics: PUBLIC UserInputProc = { GGState.SetHeuristics[ggData, NOT GGState.GetHeuristics[ggData]]; IF event.first = $ToggleHeuristics THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE]; }; SetHeuristics: PUBLIC UserInputProc = { boolRope: Rope.ROPE _ NARROW[event.rest.first]; setHeuristics: BOOL _ GGCoreOps.RopeToBool[boolRope]; GGState.SetHeuristics[ggData, setHeuristics]; }; SetDisplayStyle: PUBLIC UserInputProc = { styleRope: Rope.ROPE _ NARROW[event.rest.first]; style: DisplayStyle _ GGUIUtility.DisplayStyleFromRope[styleRope]; GGState.SetDisplayStyle[ggData, style]; }; ScaleUnitAux: PROC [ggData: GGData, distance: REAL, noisy: BOOL] = { IF distance <=0.0 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SetUnits failed: zero or illegal unit value"] ELSE { currentEvent: HistoryEvent _ GGHistory.NewCurrent["Set scale unit", ggData]; -- start new history event; GGState.SetScaleUnit[ggData, distance, currentEvent]; -- in screen dots GGHistory.PushCurrent[ggData]; IF noisy THEN PrintScaleUnit[ggData, NIL]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE]; }; }; ScaleUnitFromSegment: PUBLIC UserInputProc = { IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]#1 THEN GOTO NoNoNoNoNO ELSE { distance: REAL _ 0.0; -- illegal scale unit firstSliceD: SliceDescriptor _ GGScene.FirstSelectedSlice[ggData.scene, leaf, normal]; segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[firstSliceD]; firstSeg: Segment _ GGSliceOps.NextSegment[firstSliceD.slice, segGen].seg; nextSeg: Segment _ GGSliceOps.NextSegment[firstSliceD.slice, segGen].seg; IF firstSeg=NIL OR nextSeg#NIL THEN GOTO NoNoNoNoNO; distance _ Vectors2d.Distance[firstSeg.lo, firstSeg.hi]; ScaleUnitAux[ggData, distance, TRUE]; }; EXITS NoNoNoNoNO => { Feedback.Append[ggData.router, oneLiner, $Complaint, "UnitsFromSegment failed: select a single segment to set Units"]; }; }; ScaleUnitFromValue: PUBLIC UserInputProc = { radius: REAL; success: BOOL _ FALSE; [radius, success] _ GGState.GetRadiusValue[ggData]; IF success THEN ScaleUnitAux[ggData, radius*ggData.hitTest.scaleUnit, TRUE]; }; ScaleUnitFromSelection: PUBLIC UserInputProc = { distance: REAL _ WITH event.rest.first SELECT FROM real: REF REAL => real^, int: REF INT => REAL[int^], ENDCASE => -1.0; IF distance>reallyBigReal OR distance=LAST[INT] OR distance <= 0.0 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "UnitsFromSelection failed: select a positive real number (in inches) for unit"] ELSE ScaleUnitAux[ggData, distance*72.0, TRUE]; -- screen dots }; SetScaleUnit: PUBLIC UserInputProc = { points: REAL _ NARROW[event.rest.first, REF REAL]^; noisy: ATOM _ NARROW[event.rest.rest.first]; ScaleUnitAux[ggData, points, noisy = $Noisy]; }; InchScaleUnit: PUBLIC UserInputProc = { SetScaleUnit[ggData, LIST[$SetScaleUnit, NEW[REAL _ pointsPerIn], $Quiet]]; }; PrintScaleUnit: PUBLIC UserInputProc = { scale: REAL _ GGState.GetScaleUnit[ggData: ggData]; Feedback.PutF[ggData.router, oneLiner, $Show, "Current scale is %g points = %g inches = %g centimeters", [real[scale]], [real[scale/pointsPerIn]], [real[scale/pointsPerCm]] ]; }; standardSlopeDegrees: LIST OF REAL _ LIST[150.0, 135.0, 120.0, 90.0, 60.0, 45.0, 30.0, 0.0]; StandardSlopes: PUBLIC UserInputProc = { GGState.NewSlopeList[ggData, standardSlopeDegrees]; IF event.first = $StandardSlopes THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Standard slopes installed"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE]; }; }; SetSlopes: PUBLIC UserInputProc = { slopeRope: Rope.ROPE _ NARROW[event.rest.first]; values: LIST OF REAL; on: LIST OF BOOL; [----, values, on] _ GGDescribe.ScalarButtonValuesFromRope[slopeRope]; FOR nextValues: LIST OF REAL _ values, nextValues.rest UNTIL nextValues = NIL DO AddSlopeInternal[ggData, nextValues.first, on.first]; on _ on.rest; ENDLOOP; }; ClearSlopes: PROC [ggData: GGData, event: LIST OF REF ANY] = { GGState.NewSlopeList[ggData, NIL]; IF event.first = $ClearSlopes THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Slopes cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE]; }; }; SlopePrompt: PUBLIC UserInputProc = { GGState.SetAllAlignmentStates[ggData, slope, FALSE]; IF event.first = $SlopePrompt THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Slopes cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; AddSlope: PUBLIC UserInputProc = { slope: REAL; success: BOOL; [slope, success] _ GGState.GetSlopeValue[ggData]; IF NOT success THEN RETURN; [] _ GGState.AddSlope[ggData, slope]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Slope added"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; AddSlopeInternal: PUBLIC PROC [ggData: GGData, degrees: REAL, on: BOOL _ FALSE] = { IF degrees<0.0 THEN degrees _ degrees+180.0; IF degrees=360.0 THEN degrees _ 0.0; ggData.measure.slopeViewValue _ degrees; [] _ GGState.AddSlope[ggData, degrees, on]; }; DeleteSlope: PUBLIC UserInputProc = { GGState.DeleteSelectedAlignments[ggData, slope]; ggData.measure.slopeViewValue _ Real.LargestNumber; -- invalidate cached value Feedback.Append[ggData.router, oneLiner, $Feedback, "Slopes deleted"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; GetSlope: PUBLIC UserInputProc = { IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]<1 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Select one or more segments for GetSlope"] ELSE { DoGetSlope: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR nextSeg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL nextSeg=NIL DO [] _ GGState.AddSlope[ggData, GGMeasure.SlopeOfSegment[nextSeg]]; ENDLOOP; }; [] _ GGScene.WalkSelectedSlices[ggData.scene, leaf, DoGetSlope, normal]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Slopes added"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; ToggleSlope: PUBLIC UserInputProc = { menuValue: REAL; changedToOn: BOOL _ FALSE; paintAction: ATOM; remake: GGWindow.ForegroundParts _ alignBag; CodeTimer.StartInt[$ToggleSlope, $Gargoyle]; [menuValue, changedToOn, paintAction] _ ToggleAux[ggData, event, slope]; IF changedToOn THEN { alignObjects: LIST OF FeatureData; hideAlignments: BOOL _ NOT GGState.GetShowAlignments[ggData]; alignObjects _ GGAlign.IncrementalNewFilter[menuValue, slope, ggData.hitTest.triggerBag, hideAlignments, ggData.hitTest.alignBag]; GGRefresh.NoteNewForeground[ggData, alignObjects]; remake _ none; } ELSE remake _ alignBag; GGWindow.RestoreScreenAndInvariants[paintAction: paintAction, ggData: ggData, remake: remake, edited: TRUE, okToSkipCapture: TRUE]; CodeTimer.StopInt[$ToggleSlope, $Gargoyle]; }; ToggleAux: PROC [ggData: GGData, event: LIST OF REF ANY, type: GGState.AlignmentType] RETURNS [menuValue: REAL _ 777.0, changedToOn: BOOL _ FALSE, paintAction: ATOM] = { argValue: REAL _ WITH event.rest.first SELECT FROM real: REF REAL => real^, int: REF INT => REAL[int^], ENDCASE => Real.LargestNumber; IF argValue>reallyBigReal OR argValue=LAST[INT] THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "ToggleAux: Unreasonable real argument"]; RETURN; }; [menuValue, changedToOn] _ GGState.ToggleAlignment[ggData, argValue, type]; IF changedToOn THEN paintAction _ $NewAlignmentsSelected ELSE paintAction _ $NewAlignmentsDeselected; }; standardAngles: LIST OF REAL _ LIST[90.0, 60.0, 45.0, 30.0, 0.0, -30.0, -45.0, -60.0, -90.0]; StandardAngles: PUBLIC UserInputProc = { GGState.NewAngleList[ggData, standardAngles]; IF event.first = $StandardAngles THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Standard angles installed"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; SetAngles: PUBLIC UserInputProc = { angleRope: Rope.ROPE _ NARROW[event.rest.first]; values: LIST OF REAL; on: LIST OF BOOL; [----, values, on] _ GGDescribe.ScalarButtonValuesFromRope[angleRope]; FOR nextValues: LIST OF REAL _ values, nextValues.rest UNTIL nextValues = NIL DO AddAngleInternal[ggData, nextValues.first, on.first]; on _ on.rest; ENDLOOP; }; ClearAngles: PROC [ggData: GGData, event: LIST OF REF ANY] = { GGState.NewAngleList[ggData, NIL]; IF event.first = $ClearAngles THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Angles cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; AnglePrompt: PUBLIC UserInputProc = { GGState.SetAllAlignmentStates[ggData, angle, FALSE]; IF event.first = $AnglePrompt THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Angles cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; AddAngle: PUBLIC UserInputProc = { angle: REAL; success: BOOL; [angle, success] _ GGState.GetAngleValue[ggData]; IF NOT success THEN RETURN; [] _ GGState.AddAngle[ggData, angle]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Angle added"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; AddAngleInternal: PUBLIC PROC [ggData: GGData, degrees: REAL, on: BOOL _ FALSE] = { IF degrees=360.0 THEN degrees _ 0.0; ggData.measure.angleViewValue _ degrees; [] _ GGState.AddAngle[ggData, degrees, on]; }; DeleteAngle: PUBLIC UserInputProc = { GGState.DeleteSelectedAlignments[ggData, angle]; ggData.measure.angleViewValue _ Real.LargestNumber; -- invalidate cached value Feedback.Append[ggData.router, oneLiner, $Feedback, "Angles deleted"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; GetAngle: PUBLIC UserInputProc = { IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]<1 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Select two or more segments for GetAngle"] ELSE { DoGetAngle: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; firstSeg, secondSeg: Segment _ NIL; degrees: REAL _ 0.0; FOR seg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL seg = NIL DO IF firstSeg=NIL THEN {firstSeg _ seg; LOOP;}; IF secondSeg=NIL THEN secondSeg _ seg; degrees _ GGMeasure.CounterClockwiseBetweenSegments[firstSeg, secondSeg]; [] _ GGState.AddAngle[ggData, degrees]; firstSeg _ secondSeg; secondSeg_ NIL; ENDLOOP; }; [] _ GGScene.WalkSelectedSlices[ggData.scene, leaf, DoGetAngle, normal]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Angles added"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; ToggleAngle: PUBLIC UserInputProc = { menuValue: REAL; changedToOn: BOOL _ FALSE; paintAction: ATOM; remake: GGWindow.ForegroundParts _ alignBag; [menuValue, changedToOn, paintAction] _ ToggleAux[ggData, event, angle]; IF changedToOn THEN { remake _ alignBag; } ELSE remake _ alignBag; GGWindow.RestoreScreenAndInvariants[paintAction: paintAction, ggData: ggData, remake: remake, edited: TRUE, okToSkipCapture: TRUE]; }; standardRadii: LIST OF REAL _ LIST[1.0/18.0, 1.0/9.0, 0.125, 0.25, 1.0/3.0, 0.5, 2.0/3.0, 0.75, 1.0, 2.0, 4.0]; standardRadiiNames: LIST OF Rope.ROPE _ LIST["1/18", "1/9", "1/8", "1/4", "1/3", "1/2", "2/3", "3/4", "1", "2", "4"]; StandardRadii: PUBLIC UserInputProc = { GGState.NewRadiusList[ggData, standardRadiiNames, standardRadii]; IF event.first = $StandardRadii THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Standard radii installed"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; SetRadii: PUBLIC UserInputProc = { radiiRope: Rope.ROPE _ NARROW[event.rest.first]; values: LIST OF REAL; on: LIST OF BOOL; names: LIST OF Rope.ROPE; [names, values, on] _ GGDescribe.ScalarButtonValuesFromRope[radiiRope]; FOR nextValues: LIST OF REAL _ values, nextValues.rest UNTIL nextValues = NIL DO AddRadiusInternal[ggData, names.first, nextValues.first, on.first]; on _ on.rest; names _ names.rest; ENDLOOP; }; ClearRadii: PROC [ggData: GGData, event: LIST OF REF ANY] = { GGState.NewRadiusList[ggData, NIL, NIL]; IF event.first = $ClearRadii THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Radii cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; RadiusPrompt: PUBLIC UserInputProc = { GGState.SetAllAlignmentStates[ggData, radius, FALSE]; IF event.first = $RadiusPrompt THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Radii cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; AddRadius: PUBLIC UserInputProc = { radius: REAL; success: BOOL; [radius, success] _ GGState.GetRadiusValue[ggData]; IF NOT success THEN RETURN; [] _ GGState.AddRadius[ggData, NIL, radius]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Radius added"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; AddRadiusInternal: PUBLIC PROC [ggData: GGData, name: Rope.ROPE, radius: REAL, on: BOOL _ FALSE] = { ggData.measure.radiusViewValue _ radius; [] _ GGState.AddRadius[ggData, name, radius, on]; }; DeleteRadius: PUBLIC UserInputProc = { GGState.DeleteSelectedAlignments[ggData, radius]; ggData.measure.radiusViewValue _ Real.LargestNumber; -- invalidate cached value Feedback.Append[ggData.router, oneLiner, $Feedback, "Radii deleted"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; GetRadius: PUBLIC UserInputProc = { IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]<1 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Select one or more segments for GetRadius"] ELSE { DoGetRadius: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR nextSeg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL nextSeg=NIL DO radius: REAL _ GGMeasure.DistanceBetweenPoints[nextSeg.lo, nextSeg.hi]/ggData.hitTest.scaleUnit; [] _ GGState.AddRadius[ggData, NIL, radius]; ENDLOOP; }; [] _ GGScene.WalkSelectedSlices[ggData.scene, leaf, DoGetRadius, normal]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Radii added"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; ToggleRadius: PUBLIC UserInputProc = { menuValue: REAL; changedToOn: BOOL _ FALSE; paintAction: ATOM; remake: GGWindow.ForegroundParts _ alignBag; [menuValue, changedToOn, paintAction] _ ToggleAux[ggData, event, radius]; IF changedToOn THEN { remake _ alignBag; } ELSE remake _ alignBag; GGWindow.RestoreScreenAndInvariants[paintAction: paintAction, ggData: ggData, remake: remake, edited: TRUE, okToSkipCapture: TRUE]; }; standardDistances: LIST OF REAL = LIST [0.0, 1.0/18.0, 1.0/9.0, 0.5, 1.0]; standardDistanceNames: LIST OF Rope.ROPE = LIST ["0", "1/18", "1/9", "1/2", "1"]; StandardDistances: PUBLIC UserInputProc = { GGState.NewLineDistanceList[ggData, standardDistanceNames, standardDistances]; IF event.first = $StandardDistances THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Standard distances installed"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; SetDistances: PUBLIC UserInputProc = { distanceRope: Rope.ROPE _ NARROW[event.rest.first]; values: LIST OF REAL; on: LIST OF BOOL; names: LIST OF Rope.ROPE; [names, values, on] _ GGDescribe.ScalarButtonValuesFromRope[distanceRope]; FOR nextValues: LIST OF REAL _ values, nextValues.rest UNTIL nextValues = NIL DO AddDistanceInternal[ggData, names.first, nextValues.first, on.first]; on _ on.rest; names _ names.rest; ENDLOOP; }; ClearDistances: PROC [ggData: GGData, event: LIST OF REF ANY] = { GGState.NewLineDistanceList[ggData, NIL, NIL]; IF event.first = $ClearDistances THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Distances cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; DistancePrompt: PUBLIC UserInputProc = { GGState.SetAllAlignmentStates[ggData, lineDistance, FALSE]; IF event.first = $DistancePrompt THEN { Feedback.Append[ggData.router, oneLiner, $Feedback, "Distances cleared"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; AddDistance: PUBLIC UserInputProc = { distance: REAL; success: BOOL; [distance, success] _ GGState.GetLineDistanceValue[ggData]; IF NOT success THEN RETURN; [] _ GGState.AddLineDistance[ggData, NIL, distance]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Distance added"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; AddDistanceInternal: PUBLIC PROC [ggData: GGData, name: Rope.ROPE, distance: REAL, on: BOOL _ FALSE] = { ggData.measure.lineDistViewValue _ distance; [] _ GGState.AddLineDistance[ggData, name, distance, on]; }; DeleteDistance: PUBLIC UserInputProc = { GGState.DeleteSelectedAlignments[ggData, lineDistance]; ggData.measure.lineDistViewValue _ Real.LargestNumber; -- invalidate cached value Feedback.Append[ggData.router, oneLiner, $Feedback, "Distances deleted"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; GetDistance: PUBLIC UserInputProc = { IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]<1 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Select one or more segments for GetDistance"] ELSE { DoGetDist: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR nextSeg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL nextSeg=NIL DO distance: REAL _ GGMeasure.LengthOfSegment[nextSeg]/ggData.hitTest.scaleUnit; [] _ GGState.AddLineDistance[ggData, NIL, distance]; ENDLOOP }; [] _ GGScene.WalkSelectedSlices[ggData.scene, leaf, DoGetDist, normal]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Distances added"]; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE]; }; }; ToggleDistance: PUBLIC UserInputProc = { menuValue: REAL; changedToOn: BOOL _ FALSE; paintAction: ATOM; remake: GGWindow.ForegroundParts _ alignBag; [menuValue, changedToOn, paintAction] _ ToggleAux[ggData, event, lineDistance]; IF changedToOn THEN { remake _ alignBag; } ELSE remake _ alignBag; GGWindow.RestoreScreenAndInvariants[paintAction: paintAction, ggData: ggData, remake: remake, edited: TRUE, okToSkipCapture: TRUE]; }; MeasureSlopeHit: PUBLIC UserInputProc = { [] _ GGState.SelectSlope[ggData]; }; MeasureSlopeFromSelection: PUBLIC UserInputProc = { slope: REAL _ NARROW[event.rest.first, REF REAL]^; IF slope>reallyBigReal THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "SlopeFromSelection failed: select a reasonable value for slope"]; RETURN; }; GGState.SetSlopeValue[ggData, slope]; AddSlope[ggData, LIST[$AddSlope]]; }; MeasureAngleHit: PUBLIC UserInputProc = { [] _ GGState.SelectAngle[ggData]; }; MeasureAngleFromSelection: PUBLIC UserInputProc = { angle: REAL _ NARROW[event.rest.first, REF REAL]^; IF angle>reallyBigReal THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "AngleFromSelection failed: select a reasonable value for angle"]; RETURN; }; GGState.SetAngleValue[ggData, angle]; AddAngle[ggData, LIST[$AddAngle]]; }; MeasureRadiusHit: PUBLIC UserInputProc = { [] _ GGState.SelectRadius[ggData]; }; MeasureRadiusFromSelection: PUBLIC UserInputProc = { radius: REAL _ NARROW[event.rest.first, REF REAL]^; IF radius>reallyBigReal THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "RadiusFromSelection failed: select a reasonable value for radius"]; RETURN; }; GGState.SetRadiusValue[ggData, radius]; AddRadius[ggData, LIST[$AddRadius]]; }; MeasureLineDistHit: PUBLIC UserInputProc = { [] _ GGState.SelectLineDistance[ggData]; }; MeasureLineDistFromSelection: PUBLIC UserInputProc = { lineDist: REAL _ NARROW[event.rest.first, REF REAL]^; IF lineDist>reallyBigReal THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "DistanceFromSelection failed: select a reasonable value for line distance"]; RETURN; }; GGState.SetLineDistanceValue[ggData, lineDist]; AddDistance[ggData, LIST[$AddDistance]]; }; DeleteCaretSegment: PUBLIC UserInputProc = { jointNum, newEndJoint: NAT; traj, shortTraj, smallerOutline: Slice; smallerOutlines: LIST OF Slice; trajEnd: TrajEnd; chairD, trajD: SliceDescriptor; delSeq: TrajParts; bBoxOfTraj: BoundBox; point: Point; normal: Vector; caret: Caret _ ggData.caret; scene: Scene _ ggData.scene; IF GGCaret.SittingOnEnd[caret] THEN { -- delete the joint and segment near the caret success: BOOL _ FALSE; delD: SliceDescriptor; oldOutline: Slice; chairD _ GGCaret.GetChair[caret]; [success, trajD, jointNum] _ GGSliceOps.UnpackJoint[chairD]; IF NOT success THEN ERROR Problem[msg: "Chair not simple descriptor"]; traj _ trajD.slice; oldOutline _ GGParent.GetParent[traj]; bBoxOfTraj _ GGSliceOps.GetBoundBox[traj]; SELECT jointNum FROM 0 => {newEndJoint _ 1; trajEnd _ lo}; GGTraj.HiJoint[traj] => {newEndJoint _ jointNum -1; trajEnd _ hi}; ENDCASE => ERROR Problem[msg: "failed assertion"]; point _ GGTraj.FetchJointPos[traj, newEndJoint]; normal _ GGTraj.FetchJointNormal[traj, newEndJoint]; delSeq _ GGSequence.LastSegAndJoint[NARROW[traj.data, TrajData], trajEnd]; GGHistory.NewCapture["Backspace segment", ggData]; -- capture scene BEFORE UPDATE GGSelect.SaveSelectionsInSliceAllClasses[chairD.slice, scene]; delD _ GGSlice.DescriptorFromParts[traj, delSeq]; smallerOutlines _ GGTraj.DeleteSequence[delD].openTrajOutlines; smallerOutline _ IF smallerOutlines = NIL THEN NIL ELSE smallerOutlines.first; IF smallerOutline = NIL THEN { -- we removed the last segment GGCaret.SitOn[caret, NIL]; IF GGScene.IsTopLevel[oldOutline] THEN { GGScene.DeleteSlice[scene, oldOutline]; } ELSE { cluster: Slice _ GGParent.GetParent[oldOutline]; smallerCluster: Slice _ GGSlice.RemoveChild[cluster, oldOutline]; IF smallerCluster = NIL THEN GGSlice.PruneNullClusters[scene, cluster]; }; } ELSE { jointParts: TrajParts; jointD, outD: SliceDescriptor; priority: INT; IF GGScene.IsTopLevel[oldOutline] THEN { priority _ GGScene.GetPriority[scene, oldOutline]; GGScene.DeleteSlice[scene, oldOutline]; GGScene.AddSlice[scene, smallerOutline, priority]; GGSelect.ReselectSliceAllClasses[smallerOutline, scene]; } ELSE { cluster: Slice _ GGParent.GetParent[oldOutline]; priority _ GGParent.GetChildPriority[cluster, oldOutline]; [] _ GGSlice.RemoveChild[cluster, oldOutline]; GGSlice.AddChildToCluster[cluster, smallerOutline, priority]; GGSelect.ReselectSliceAllClasses[cluster, scene]; }; shortTraj _ GGParent.FirstChild[smallerOutline, first, $Traj]; jointParts _ GGSequence.CreateFromJoint[NARROW[shortTraj.data], IF trajEnd = lo THEN 0 ELSE newEndJoint]; jointD _ GGSlice.DescriptorFromParts[shortTraj, jointParts]; -- traj descriptor outD _ GGParent.TopLevelDescriptorFromChildDescriptor[jointD]; GGCaret.SitOn[ggData.caret, outD]; }; GGCaret.SetAttractor[ggData.caret, point, normal, NIL]; GGRefresh.NullStartBox[ggData]; GGRefresh.EnlargeStartBox[ggData, bBoxOfTraj, NIL]; GGHistory.PushCurrent[ggData]; -- push captured history event onto history list Feedback.Append[ggData.router, oneLiner, $Feedback, "Backspace segment: caret segment deleted"]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: FALSE]; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "Backspace segment failed: place the caret on the end of a trajectory to backspace"]; }; Nop: UserInputProc ~ { }; RegisterEventProcs: PROC = { OPEN GGUserInput; RegisterAction[$OneScroll, OneScroll, rope2, FALSE, FALSE]; RegisterAction[$OneZoom, OneZoom, rope, FALSE, FALSE]; RegisterAction[$ScalePop, ScalePop, rope2]; RegisterAction[$RotatePop, RotatePop, rope2]; RegisterAction[$FitPop, FitPop, none]; RegisterAction[$ResetPop, ResetPop, none]; RegisterAction[$EdgePop, EdgePop, none]; RegisterAction[$PrevTransform, PrevTransform, none]; RegisterAction[$CenterSel, CenterSel, none]; RegisterAction[$CenterCaret, CenterCaret, none]; RegisterAction[$FitSel, FitSel, none]; RegisterAction[$SetBiScrollersTransform, SetBiScrollersTransform, rope]; RegisterAction[$ShowBiScrollersTransform, ShowBiScrollersTransform, none]; RegisterAction[$AlignFracs, ScrollBar, none]; RegisterAction[$Shift, ScrollBar, none]; RegisterAction[$ViewersPaintEntireScene, ViewersPaintEntireScene, none]; RegisterAction[$ViewersPaintAllPlanes, ViewersPaintAllPlanes, none]; RegisterAction[$MakeHot, MakeHot, none]; RegisterAction[$MakeAllHot, MakeAllHot, none]; RegisterAction[$MakeCold, MakeCold, none]; RegisterAction[$MakeAllCold, MakeAllCold, none]; RegisterAction[$DropAnchor, DropAnchor, none]; RegisterAction[$LiftAnchor, LiftAnchor, none]; RegisterAction[$StandardAlignments, StandardAlignments, none]; RegisterAction[$ClearAlignments, ClearAlignments, none]; RegisterAction[$AllAlignmentsOff, AllAlignmentsOff, none]; RegisterAction[$InitializeAlignments, InitializeAlignments, none]; RegisterAction[$ScreenChoiceChange, DisplayStyleChange, none]; RegisterAction[$ToggleShowColors, Nop, none, FALSE]; RegisterAction[$SetShowColors, Nop, none, FALSE]; RegisterAction[$ToggleMidpoints, ToggleMidpoints, none]; RegisterAction[$SetMidpoints, SetMidpoints, none, FALSE]; RegisterAction[$ToggleHeuristics, ToggleHeuristics, none]; RegisterAction[$SetHeuristics, SetHeuristics, none, FALSE]; RegisterAction[$ToggleShowAlignments, ToggleShowAlignments, none]; RegisterAction[$SetShowAlignments, SetShowAlignments, none]; RegisterAction[$SetDisplayStyle, SetDisplayStyle, rope]; RegisterAction[$RadiusUnitFromSegment, ScaleUnitFromSegment, none]; RegisterAction[$RadiusUnitFromValue, ScaleUnitFromValue, none]; RegisterAction[$RadiusUnitFromSelection, ScaleUnitFromSelection, refReal]; RegisterAction[$InchScaleUnit, InchScaleUnit, none]; RegisterAction[$SetScaleUnit, SetScaleUnit, none]; RegisterAction[$PrintScaleUnit, PrintScaleUnit, none]; RegisterAction[$SlopePrompt, SlopePrompt, none]; RegisterAction[$SetSlopes, SetSlopes, none]; RegisterAction[$AddSlope, AddSlope, none]; RegisterAction[$GetSlope, GetSlope, none]; RegisterAction[$ToggleSlope, ToggleSlope, none]; RegisterAction[$DeleteSlope, DeleteSlope, none]; RegisterAction[$AnglePrompt, AnglePrompt, none]; RegisterAction[$SetAngles, SetAngles, none]; RegisterAction[$AddAngle, AddAngle, none]; RegisterAction[$GetAngle, GetAngle, none]; RegisterAction[$ToggleAngle, ToggleAngle, none]; RegisterAction[$DeleteAngle, DeleteAngle, none]; RegisterAction[$RadiusPrompt, RadiusPrompt, none]; RegisterAction[$SetRadii, SetRadii, none]; RegisterAction[$AddRadius, AddRadius, none]; RegisterAction[$GetRadius, GetRadius, none]; RegisterAction[$ToggleRadius, ToggleRadius, none]; RegisterAction[$DeleteRadius, DeleteRadius, none]; RegisterAction[$DistancePrompt, DistancePrompt, none]; RegisterAction[$SetDistances, SetDistances, none]; RegisterAction[$AddDistance, AddDistance, none]; RegisterAction[$GetDistance, GetDistance, none]; RegisterAction[$ToggleDistance, ToggleDistance, none]; RegisterAction[$DeleteDistance, DeleteDistance, none]; RegisterAction[$MeasureSlopeHit, MeasureSlopeHit, none]; RegisterAction[$MeasureSlopeFromSelection, MeasureSlopeFromSelection, refReal]; RegisterAction[$MeasureAngleHit, MeasureAngleHit, none]; RegisterAction[$MeasureAngleFromSelection, MeasureAngleFromSelection, refReal]; RegisterAction[$MeasureRadiusHit, MeasureRadiusHit, none]; RegisterAction[$MeasureRadiusFromSelection, MeasureRadiusFromSelection, refReal]; RegisterAction[$MeasureLineDistHit, MeasureLineDistHit, none]; RegisterAction[$MeasureLineDistFromSelection, MeasureLineDistFromSelection, refReal]; RegisterAction[$DeleteCaretSegment, DeleteCaretSegment, none]; }; RegisterEventProcs[]; END. ΦGGEventImplB.mesa Contents: Once an event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module. Copyright Σ 1988 by Xerox Corporation. All rights reserved. Pier, April 23, 1992 5:11 pm PDT Bier, June 1, 1992 3:35 pm PDT Doug Wyatt, June 24, 1988 10:41:43 am PDT BiScrollers Operations IF key = $Center THEN remember ELSE ignore -- can't express this in BiScrollers.Align Change scale and offsets so that client data previously in `from' covers as much as possible of `to' (from and to in viewer coords). ggData.embed.scrollDue is updated in GGUserImpl.ProcessAndQueueEvent. ggData.embed.scrollDue is updated in GGUserImpl.ProcessAndQueueEvent. PROC [ggData: GGData, event: LIST OF REF ANY]; PROC [ggData: GGData, event: LIST OF REF ANY]; Alignment Operations Make all normal selected slices hot. Fix the trigger bags, object bags, and Foreground plane (for efficiency). Make all slices hot. Make all normal selected slices cold. Find all hot slices and make them cold. 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. Screen style Units Menu Slope Line adds slope from angle viewer in measure line If slopeViewValue was set internally, viewer and value will be consistent. If SlopeValue viewer was set by typein, viewer and value will be inconsistent. only positive slopes, please Gets selected segment slopes, adds to slope menu and turns it on Angle Line adds angle from angle viewer in measure line See comments in AddSlope Gets selected segment angles, adds to angle menu and turns it on Radius Line adds radius from Radius viewer in measure line See comments in AddSlope Distance Line adds distance from LineDistance viewer in measure line See comments in AddSlope Coordinate/Measure Line Miscellaneous Build a descriptor for the new chair. ggData.refresh.startBoundBox^ _ bBoxOfTraj^; Trackball Actions BiScrollers Menu Alignment Operations Setting Parts of the Gargoyle State Unit Line Slope Line Angle Line Radius Line Distance Line Coordinate Line Κ1Λ˜Icode™šΟnœx™€K™˜IK˜Kšœ=˜=Kšœ9˜9KšœLžœžœ˜YK˜KšœI˜IKšœ œ7 œ˜JKšœ!žœ žœ œ˜JK˜K˜—šœžœ˜1Kš žœžœžœžœžœ™.KšœLžœžœ˜YK˜K˜—šœžœ˜/Kš žœžœžœžœžœ™.KšœJžœžœ˜WK˜K˜—K™K™šœžœ˜!Kšžœ-žœh˜›šžœ˜š  œžœžœžœžœ˜MKšœ+Οbœ˜0K˜—š œžœžœžœžœ˜ZJšœH˜HKšœžœžœ ˜"KšœHžœ˜fKšœ3Ÿ˜JK˜K˜—Kšœžœ%˜9Kšœ3˜3Kšœ-˜-Kšœ:˜:K™K˜(Kšœ$™$KšœC‘œ˜KKšœI™IKšœP‘œ˜UK˜ZKšœjžœžœ˜‰K˜'K˜—K˜K˜—š œžœ˜$š  œžœžœžœžœ˜BKšœ0‘œ˜5K˜—K˜Kšœ3˜3Kšœ-˜-K˜Kšœ+˜+Kšœ™Kšœ&‘œ˜;KšœX˜XKšœ{žœžœ˜šKšœ*˜*K˜K˜—šœžœ˜"Kšžœ-žœj˜šžœ˜š  œžœžœžœžœ˜NKšœA‘œ˜FK˜K˜—Kšœ)˜)Kšœ%™%KšœD‘œ˜LKšœ\˜\Kšœqžœžœ˜Kšœ(˜(K˜—K˜K˜—š œžœ˜%š  œžœžœžœžœ˜NKšœF˜FK˜—K˜Kšœ,˜,Kš‘'™'KšœD‘œ˜IKšœW˜WKšœqžœžœ˜Kšœ+˜+K˜K˜—š œžœ˜$šžœžœ˜&šžœžœ7žœ žœ˜pKšžœ ˜$—Kšœ4˜4KšœK˜KKšœR˜RKš œ2‘ œ‘œ žœžœ˜†K˜—Kšžœh˜lK˜K˜—š œžœ˜$šžœžœ˜'Kšœ6žœ žœžœ˜]Kšœ˜KšœQ˜QKšœY‘ œ žœžœ˜ŠK˜—KšžœV˜ZK˜K™—šœžœ˜,Kšœ˜Kšœ˜Kšœ˜Kšœ!˜!šžœ#žœ˜+Kšœc˜cKšœužœžœ˜“K˜—K˜K˜—šœžœ˜)Kšœ˜Kšœ˜Kšœ˜Kšœ˜šžœ žœ˜(Kšœ\˜\Kšœužœžœ˜“K˜—K˜K˜—šœžœ˜*Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ‘ œ žœ˜$šžœ!žœ˜)Kšœ\˜\Kšœužœžœ˜“K˜—K˜K˜—šœžœ˜.Kšœ˜™˜Kšœ ˜ šžœ%žœ˜-Kšœd˜dKšœpžœžœ˜ŽK˜—Kšœ˜—K˜K™ šœžœ˜,Kšœ žœ#˜0Kšœ˜š œžœžœžœžœ˜IKšœ8žœ˜=K˜—Kšœ‘œ˜+Kšœk˜kKšœM˜MKšœjžœžœ˜ˆKšœ˜K˜—šœžœ˜.Kšœ"žœ$˜IKšžœ%žœqžœžœ˜ΊK˜K˜—šœžœ˜+Kšœžœžœ˜/Kšœžœ"˜6Kšœ2˜2K˜K˜—šœžœ˜)Kšœžœ˜?Kšžœ žœežœžœ˜©K˜K˜—š œžœ˜&Kšœžœžœ˜/Kšœžœ"˜4Kšœ+˜+K˜K˜—šœžœ˜*Kšœžœ ˜AKšžœ!žœqžœžœ˜ΆK˜K˜—š œžœ˜'Kšœžœžœ˜/Kšœžœ"˜5Kšœ-˜-K˜K˜—šœžœ˜)Kšœžœžœ˜0KšœB˜BKšœ'˜'K˜—K˜K™ š œžœžœ žœ˜DKšžœžœd˜{šžœ˜Jšœ&‘ œΟtœ Ÿ˜hKšœ6Ÿ˜GKšœ ‘ œ ˜K–§[paintAction: ATOM, gargoyleData: GGInterfaceTypes.GargoyleData, remake: GGWindow.ForegroundParts _ triggerBag, backgndOK: BOOL _ FALSE, edited: BOOL _ TRUE]šžœžœžœ˜*Kšœsžœžœ˜‘K˜—K˜K™—šœžœ˜.Kšžœ;žœžœ ˜Qšžœ˜Kšœ žœŸ˜+KšœV˜VK–([sliceD: GGModelTypes.SliceDescriptor]šœH˜HKšœJ˜JKšœI˜IKš žœ žœžœ žœžœžœ ˜4Kšœ8˜8Kšœžœ˜%K˜—šž˜˜Kšœv˜vK˜——K˜K™—šœžœ˜,Kšœžœ˜ Kšœ žœžœ˜Kšœ3˜3Kšžœ žœ7žœ˜LK˜K˜—šœžœ˜0šœ žœžœžœž˜2Kšœžœžœ ˜Kšœžœžœžœ˜Kšžœ ˜—Kš žœžœ žœžœžœžœ†˜ΝKšžœ%žœŸ˜>K˜K˜—š œžœ˜&Kš œžœžœžœžœ˜3Kšœžœžœ˜,Kšœ-˜-K˜K˜—š œžœ˜'Kšœžœžœžœ˜KK˜K˜—šœžœ˜(K–#[ggData: GGInterfaceTypes.GGData]šœžœ(˜3Kšœ°˜°K˜—K˜K™ Kš œžœžœžœžœ3˜\šœžœ˜(Kšœ3˜3šžœžœ˜'K˜QKšœužœžœ˜“K˜—K˜K˜—š œžœ˜#Kšœžœžœ˜0Kšœžœžœžœ˜Kšœžœžœžœ˜KšœŸœA˜Fš žœ žœžœžœžœžœž˜PJšœ5˜5J˜ Jšžœ˜—K˜K˜—š  œžœžœžœžœžœ˜>Kšœžœ˜"šžœžœ˜$K˜FKšœužœžœ˜“K˜—K˜K˜—š œžœ˜%Kšœ-žœ˜4šžœžœ˜$K˜FKšœužœžœ˜’Kšœ˜—Kšœ˜K˜—šœžœ˜"™-Kš‘J™JKš‘N™N—Kšœžœ˜ Kšœ žœ˜Kšœ1˜1Kšžœžœ žœžœ˜Kšœ%˜%K˜CKšœsžœžœ˜K˜K˜—š œžœžœžœžœžœ˜SKš‘™Kšžœ žœ˜,Kšžœžœ˜$Kšœ(˜(Kšœ+˜+K˜K˜—š œžœ˜%Kšœ0˜0Kšœ4Ÿ˜NK˜FKšœužœžœ˜’Kšœ˜K˜—šœžœ˜"K™@Kšžœ;žœa˜’šžœ˜š  œžœžœžœžœ˜KK–([sliceD: GGModelTypes.SliceDescriptor]šœC˜Cšžœwžœ žœž˜ŽKšœA˜AKšžœ˜—J˜—KšœH˜HKšœD˜DKšœsžœžœ˜K˜—K˜K˜—š œžœ˜%Kšœ žœ˜Kšœ žœžœ˜Kšœ žœ˜Kšœ,˜,Kšœ,˜,KšœH˜Hšžœ žœ˜Kšœžœžœ ˜"Kšœžœžœ#˜=Kšœ‚˜‚Kšœ2˜2Kšœ˜K˜—Kšžœ˜Kšœfžœžœ˜ƒKšœ+˜+K˜K˜—š œžœžœžœžœžœžœ žœžœžœžœ˜©šœ žœžœžœž˜2Kšœžœžœ ˜Kšœžœžœžœ˜Kšžœ˜—š žœžœ žœžœžœ˜6Kšœ^˜^Kšžœ˜K˜—KšœK˜KKšžœ žœ%˜8Kšžœ(˜,K˜—K˜K™ Kš œžœžœžœžœ:˜]šœžœ˜(Kšœ-˜-šžœžœ˜'K˜QKšœužœžœ˜’K˜—K˜K˜—š œžœ˜#Kšœžœžœ˜0Kšœžœžœžœ˜Kšœžœžœžœ˜KšœŸœA˜Fš žœ žœžœžœžœžœž˜PJš‘œ%˜5J˜ Jšžœ˜—K˜K˜—š  œžœžœžœžœžœ˜>Kšœžœ˜"šžœžœ˜$K˜FKšœužœžœ˜’K˜—K˜K˜—š œžœ˜%Kšœ-žœ˜4šžœžœ˜$K˜FKšœužœžœ˜’Kšœ˜—Kšœ˜K˜—šœžœ˜"K™-K™Kšœžœ˜ Kšœ žœ˜Kšœ1˜1Kšžœžœ žœžœ˜Kšœ%˜%KšœC˜CKšœsžœžœ˜K˜K˜—š œžœžœžœžœžœ˜SKšžœžœ˜$Kšœ(˜(Kšœ+˜+K˜K˜—š œžœ˜%Kšœ0˜0Kšœ4Ÿ˜NK˜FKšœužœžœ˜’Kšœ˜K˜—šœžœ˜"K™@šžœ;ž˜AKšœ`˜`—šžœ˜š  œžœžœžœžœ˜KK–([sliceD: GGModelTypes.SliceDescriptor]šœC˜CKšœžœ˜#Kšœ žœ˜šžœsžœžœž˜ˆKšžœ žœžœžœ˜-Kšžœ žœžœ˜&KšœI˜IKšœ'˜'Kšœ˜Kšœ žœ˜Kšžœ˜—J˜—KšœH˜HKšœD˜DKšœsžœžœ˜K˜—K˜K˜—š œžœ˜%Kšœ žœ˜Kšœ žœžœ˜Kšœ žœ˜Kšœ,˜,KšœH˜Hšžœ žœ˜Kšœ˜K˜—Kšžœ˜Kšœfžœžœ˜ƒK˜—K˜K™ Kš œžœžœžœžœM˜oKš œžœžœžœžœI˜uš œžœ˜'KšœA˜Ašžœžœ˜&K˜PKšœužœžœ˜’K˜—K˜K˜—šœžœ˜"Kšœžœžœ˜0Kšœžœžœžœ˜Kšœžœžœžœ˜Kšœžœžœžœ˜KšœG˜Gš žœ žœžœžœžœžœž˜PJš‘œ2˜CJ˜ Jšœ˜Jšžœ˜—K˜K˜K˜—š  œžœžœžœžœžœ˜=Kšœžœžœ˜(šžœžœ˜#KšœE˜EKšœužœžœ˜’K˜—K˜K˜—š œžœ˜&Kšœ.žœ˜5šžœžœ˜%KšœE˜EKšœužœžœ˜’K˜—K˜K˜—š œžœ˜#K™/K™Kšœžœ˜ Kšœ žœ˜Kšœ3˜3Kšžœžœ žœžœ˜Kšœžœ ˜,K˜DKšœsžœžœ˜K˜K˜—šœžœžœžœ žœžœžœ˜dKšœ(˜(Kšœ1˜1K˜K˜—š œžœ˜&Kšœ1˜1Kšœ5Ÿ˜OK˜EKšœužœžœ˜’Kšœ˜K˜—š œžœ˜#šžœ;ž˜AKšœa˜a—šžœ˜š  œžœžœžœžœ˜LK–([sliceD: GGModelTypes.SliceDescriptor]šœC˜Cšžœwžœ žœž˜ŽKšœžœT˜`Kšœžœ ˜,Kšžœ˜—J˜—KšœI˜IKšœC˜CKšœsžœžœ˜Kšœ˜—Kšœ˜K˜—š œžœ˜&Kšœ žœ˜Kšœ žœžœ˜Kšœ žœ˜Kšœ,˜,KšœI˜Išžœ žœ˜Kšœ˜K˜—Kšžœ˜Kšœfžœžœ˜ƒK˜K˜—K˜K™ Kš œžœžœžœžœ$˜JKš œžœžœžœžœ"˜Qšœžœ˜+KšœN˜Nšžœ"žœ˜*K˜TKšœužœžœ˜’K˜—K˜K˜—š œžœ˜&Kšœžœžœ˜3Kšœžœžœžœ˜Kšœžœžœžœ˜Kšœžœžœžœ˜KšœJ˜Jš žœ žœžœžœžœžœž˜PJš‘œ2˜EJ˜ Jšœ˜Jšžœ˜—K˜K˜—š œžœžœžœžœžœ˜AKšœ$žœžœ˜.šžœžœ˜'KšœI˜IKšœužœžœ˜’K˜—K˜K˜—šœžœ˜(Kšœ4žœ˜;šžœžœ˜'KšœI˜IKšœužœžœ˜’K˜—K˜K˜—š œžœ˜%K™6K™Kšœ žœ˜Kšœ žœ˜Kšœ;˜;Kšžœžœ žœžœ˜Kšœ%žœ ˜4KšœF˜FKšœsžœžœ˜K˜K˜—šœžœžœžœ žœžœžœ˜hKšœ,˜,Kšœ9˜9K˜K˜—šœžœ˜(Kšœ7˜7Kšœ7Ÿ˜QKšœI˜IKšœužœžœ˜’Kšœ˜K˜—š œžœ˜%šžœ;ž˜AKšœc˜c—šžœ˜š  œžœžœžœžœ˜JK–([sliceD: GGModelTypes.SliceDescriptor]šœC˜Cšžœwžœ žœž˜ŽKšœ žœ?˜MKšœ%žœ ˜4Kšž˜—J˜—KšœG˜GKšœG˜GKšœsžœžœ˜Kšœ˜—Kšœ˜K˜—šœžœ˜(Kšœ žœ˜Kšœ žœžœ˜Kšœ žœ˜Kšœ,˜,KšœO˜Ošžœ žœ˜Kšœ˜K˜—Kšžœ˜Kšœfžœžœ˜ƒK˜K˜—K˜K™šœžœ˜)Kšœ!˜!K˜K˜—šœžœ˜3Kš œžœžœžœžœ˜2šžœžœ˜Kšœw˜wKšžœ˜K˜—Kšœ%˜%Kšœžœ ˜"K˜K˜—šœžœ˜)Kšœ!˜!K˜K˜—šœžœ˜3Kš œžœžœžœžœ˜2šžœžœ˜Kšœw˜wKšžœ˜K˜—Kšœ%˜%Kšœžœ ˜"K˜K˜—šœžœ˜*Kšœ"˜"K˜K˜—šœžœ˜4Kš œžœžœžœžœ˜3šžœžœ˜Kšœy˜yKšžœ˜K˜—Kšœ'˜'Kšœžœ˜$K˜K˜—šœžœ˜,Kšœ(˜(K˜K˜—šœžœ˜6Kš œ žœžœžœžœ˜5šžœžœ˜ Kšœ‚˜‚Kšžœ˜K˜—Kšœ/˜/Kšœžœ˜(K˜—K™K™ šœžœ˜,Kšœžœ˜Kšœ'˜'Kšœžœžœ˜K˜Kšœ˜Kšœ˜K˜K˜ K˜Kšœ˜K˜K˜šžœžœŸ.˜TKšœ žœžœ˜K˜Kšœ˜Kšœ!˜!Kšœ<˜˜>Kšœ1˜1Kšœ?˜?Kš œžœžœžœžœžœ˜NšžœžœžœŸ˜=Kšœžœ˜šžœ žœ˜(Kšœ'˜'K˜—šžœ˜Kšœ0˜0KšœA˜AKšžœžœžœ+˜GK˜—K˜—šžœ˜Kšœ˜Kšœ˜Kšœ žœ˜šžœ žœ˜(Kšœ2˜2Kšœ'˜'Kšœ2˜2Kšœ8˜8K˜—šžœ˜Kšœ0˜0Kšœ:˜:Kšœ.˜.Kšœ=˜=Kšœ1˜1K˜—Kš‘%™%Kšœ>˜>Kš œ(žœžœžœžœ˜iKšœ=Ÿ˜OKšœ>˜>Kšœ"˜"K˜—Kšœ2žœ˜7Kšœ,™,Jšœ ‘ œ ˜Jšœ ‘œžœ˜3Kšœ ‘ œ Ÿ0˜PKšœ`˜`Kšœ}žœžœ˜›K˜—Kšžœ‹˜Kšœ˜—K˜šœ˜K˜—K˜šœžœ˜Kšžœ ˜K™K™Kšœ-žœžœ˜;Kšœ(žœžœ˜6—™K™Kšœ+˜+Kšœ-˜-Kšœ&˜&Kšœ*˜*Kšœ(˜(Kšœ4˜4Kšœ,˜,Kšœ0˜0Kšœ&˜&KšœH˜HKšœJ˜JKšœ-˜-Kšœ(˜(K˜KšœH˜HKšœD˜DK˜K™Kšœ(˜(Kšœ.˜.Kšœ*˜*Kšœ0˜0Kšœ.˜.Kšœ.˜.Kšœ>˜>Kšœ8˜8Kšœ:˜:KšœB˜BK˜K™#Kšœ>˜>Kšœ-žœ˜4Kšœ*žœ˜1Kšœ8˜8Kšœ2žœ˜9Kšœ:˜:Kšœ4žœ˜;KšœB˜BKšœ<˜˜>KšœU˜UK˜Kšœ>˜>K˜K˜—K˜K˜K˜Kšžœ˜J˜J˜—…—Ιz