<> <> <> <> <<>> DIRECTORY AtomButtons, AtomButtonsTypes, CodeTimer, Feedback, FS, GraphicsButton, Imager, IO, Menus, PopUpSelection, Rope, SlackProcess, SV2d, SV3d, SVDraw, SVEditTool, SVEditUser, SVEvent, SVFiles, SVInterfaceTypes, SVMenus, SVModelTypes, SVMouseEvent, SVSceneTypes, SVState, SVUserInput, SVWindow, VFonts, ViewerClasses, ViewerTools; SVMenusImpl: CEDAR PROGRAM IMPORTS AtomButtons, CodeTimer, Feedback, FS, GraphicsButton, Imager, IO, PopUpSelection, Rope, SlackProcess, SVDraw, SVEditTool, SVEditUser, SVEvent, SVFiles, SVMouseEvent, SVState, SVUserInput, SVWindow, VFonts, ViewerTools EXPORTS SVMenus = BEGIN Camera: TYPE = SVModelTypes.Camera; CoordSystem: TYPE = SVModelTypes.CoordSystem; EditToolData: TYPE = SVInterfaceTypes.EditToolData; FeedbackData: TYPE = AtomButtonsTypes.FeedbackData; FileCamera: TYPE = SVSceneTypes.FileCamera; GravityExtentData: TYPE = REF GravityExtentDataObj; GravityExtentDataObj: TYPE = SVInterfaceTypes.GravityExtentDataObj; MouseButton: TYPE = Menus.MouseButton; Plane: TYPE = SV3d.Plane; Point2d: TYPE = SV2d.Point2d; Scene: TYPE = SVSceneTypes.Scene; TwoState: TYPE = AtomButtonsTypes.TwoState; Viewer: TYPE = ViewerClasses.Viewer; SVData: TYPE = SVInterfaceTypes.SVData; entryHeight: CARDINAL = 15; -- height of a line of items entryVSpace: CARDINAL = 2; -- vertical leading between lines entryHSpace: CARDINAL = 2; -- horizontal space between items on a line column1: CARDINAL = 200; -- horizontal space between margin and column 1; column2: CARDINAL = 250; -- horizontal space between margin and column 2. column3: CARDINAL = 500; -- horizontal space between margin and column 3; smallNumberSize: CARDINAL = 60; scalarButtonColumn: CARDINAL = 180; getScalarColumn: CARDINAL = 75; newScalarColumn: CARDINAL = 40; fullColumn: CARDINAL = 600; -- the width of the standard large left column. boldFont: VFonts.Font; -- initialized in Init below; popUpFont: VFonts.Font; -- initialized in Init below; PopUpMenuEntry: TYPE = RECORD [ name: Rope.ROPE, input: LIST OF REF ANY ]; ExtractChoiceList: PROC [menu: LIST OF PopUpMenuEntry] RETURNS [choices: LIST OF Rope.ROPE] = { pos: LIST OF Rope.ROPE; newCell: LIST OF Rope.ROPE; <> IF menu = NIL THEN ERROR; choices _ CONS[menu.first.name, NIL]; pos _ choices; FOR l: LIST OF PopUpMenuEntry _ menu.rest, l.rest UNTIL l = NIL DO newCell _ CONS[l.first.name, NIL]; pos.rest _ newCell; pos _ newCell; ENDLOOP; }; QueuePopUpMenuAction: PROC [label: Rope.ROPE, menu: LIST OF PopUpMenuEntry, svData: SVData, onceOnly: BOOL _ TRUE] = { index: NAT; choices: LIST OF Rope.ROPE _ ExtractChoiceList[menu]; DO index _ PopUpSelection.Request[header: label, choice: choices]; IF index < 0 THEN ERROR; IF index = 0 THEN RETURN; FOR entries: LIST OF PopUpMenuEntry _ menu, entries.rest UNTIL entries = NIL DO IF index = 1 THEN { SVUserInput.EventNotify[svData, entries.first.input]; EXIT; }; index _ index - 1; REPEAT FINISHED => ERROR; ENDLOOP; IF onceOnly THEN RETURN; ENDLOOP; }; BuildControlPanel: PUBLIC PROC [svData: SVData, windowMenu: Menus.Menu, workingDirectory: Rope.ROPE] = { BuildFileMenuLine[svData]; BuildMasterMenuLine[svData]; BuildStyleMenuLine[svData]; BuildGravityLine[svData]; <> BuildAzimuthLine[svData]; BuildSlopeLine[svData]; BuildSlopeLineLine[svData]; BuildSlopePlaneLine[svData]; BuildMeasureLine[svData]; BuildFeedbackLine[svData]; }; <> <<>> BuildFileMenuLine: PROC [svData: SVData] = { <> nextX: INTEGER; interpressMenu: AtomButtons.ButtonLineEntry _ [popUpButton[ "Interpress", LIST[ [LIST[$ToIP], "ToIP", "Writes an interpress master to selected filename", boldFont], [LIST[$StorePoly], "StorePoly", "Stores a polygonal scene representation to selected filename"] ], -1, FALSE, popUpFont]]; svData.height _ svData.height + entryVSpace; <> nextX _ AtomButtons.BuildButtonLine [svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Clear", LIST[LIST[$Clear]], -1, FALSE, NIL, ConfirmClear]], [button["Restore", LIST[LIST[$Restore]], -1, FALSE, NIL, ConfirmReset]], [button["Get", LIST[LIST[$Get]], -1, FALSE, NIL, ConfirmGet]], [button["Store", LIST[LIST[$Store]], -1, FALSE, NIL, ConfirmStore]], [button["Save", LIST[LIST[$Save]]]], [button["Split", LIST[LIST[$Split]]]], [button["Erase", LIST[LIST[$Erase]]]], interpressMenu ]]; nextX _ AtomButtons.BuildUnQueuedButtonLine [svData.outer, nextX + entryHSpace, svData.height, svData, LIST[ ["Script", button, ScriptMenu, NIL, 0, -1, FALSE, NIL, boldFont], ["CastRays", button, CastRaysMenu, NIL, 0, -1, FALSE, NIL, boldFont], ["Revive!", button, ReviveButton] ]]; nextX _ AtomButtons.BuildButtonLine [svData.outer, nextX + entryHSpace, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Refresh!", LIST[LIST[$DrawSceneButton]]]] ]]; svData.height _ svData.height + entryVSpace + entryHeight; }; BuildMasterMenuLine: PROC [svData: SVData] = { << This section implements a set of buttons, text windows, and options listers in this format:>> <> nextX: INTEGER; transformMenu: AtomButtons.ButtonLineEntry _ [popUpButton["Transform", LIST [ [LIST [$RotX, $Do], "RotX", "Rotate selected objects about anchor's x axis"], [LIST [$RotY, $Do], "RotY", "Rotate selected objects about anchor's y axis"], [LIST [$RotZ, $Do], "RotZ", "Rotate selected objects about anchor's z axis"], [LIST [$RotX, $Undo], "UnRotX", "Rotate selected objects about anchor's x axis by negated angle"], [LIST [$RotY, $Undo], "UnRotY", "Rotate selected objects about anchor's y axis by negated angle"], [LIST [$RotZ, $Undo], "UnRotZ", "Rotate selected objects about anchor's z axis by negated angle"], [LIST [$Trans, $Do], "Translate", "Translate selected objects relative to anchor"], [LIST [$Align], "Align", "Rotate selected objects to anchor's orientation or 90 degrees from it"], [LIST [$EvenScale, $Do], "EvenScale", "Scale selected objects about anchor's origin"], [LIST [$Trans, $Undo], "UnTranslate", "Translate selected objects relative to anchor by negated vector"], [LIST [$NoOp], "", "There is no undo for Align."], [LIST [$EvenScale, $Undo], "UnEvenScale", "Scale selected objects about anchor's origin by reciprocal scalar"], [LIST [$Abut], "Abut", "Translate selected objects to anchor's origin"], [LIST [$NormalizeRot], "NormalizeRot", "Rotate selected objects to anchor's orientation"], [LIST [$Normalize], "Normalize", "Move selected objects to anchor's position & orientation"], [LIST [$AbutX], "AbutX", "Translate selected objects to anchor's x=0 plane"], [LIST [$AbutY], "AbutY", "Translate selected objects to anchor's y=0 plane"], [LIST [$AbutZ], "AbutZ", "Translate selected objects to anchor's z=0 plane"] ], -1, FALSE, NIL]]; nextX _ AtomButtons.BuildButtonLine [svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["DrawColor", LIST[LIST[$DrawColor]]]], [button["DrawB&W", LIST[LIST[$DrawBlackAndWhite]]]], transformMenu ]]; nextX _ AtomButtons.BuildUnQueuedButtonLine [svData.outer, nextX + entryHSpace, svData.height, svData, LIST[ ["Shapes", button, ShapesMenu, NIL, 0, -1, FALSE, NIL, boldFont], ["Debug", button, DebugMenu, NIL, 0, -1, FALSE, NIL, boldFont] ]]; svData.height _ svData.height + entryVSpace + entryHeight; }; -- end of BuildMasterMenuLine BuildStyleMenuLine: PROC [svData: SVData] = { nextX: INTEGER; smallStringSize: NAT _ VFonts.StringWidth["WireframeStyle"]; noOpChoice: AtomButtons.PopUpChoice _ [LIST [$NoOp], "", "no-op" ]; quickClickMode: BOOL _ SVState.GetQuickClickMode[]; selectMenu: AtomButtons.ButtonLineEntry _ [popUpButton["Select", LIST [ [LIST [$CycleSelection, $Forward], "CycleSelection", "Select a different object that is near the selected one."], [LIST [$NoOp], "", "Does nothing."], [LIST [$NoOp], "", "Does nothing."], [LIST [$CycleSelection, $Backward], "UnCycleSelection", "Select a different object that is near the selected one."] ], -1, FALSE, popUpFont]]; hotSpotsMenu: AtomButtons.ButtonLineEntry _ [popUpButton["MakeHot", LIST [ [LIST [$MakeHot], "Make Hot (^s) [G]", "Make all selected objects hot"], noOpChoice, [LIST [$MakeCold], "Make Cold (^S) [G]", "Make all selected objects cold"], [LIST [$DropAnchor], "Drop Anchor (^a)", "Drop anchor at caret"], noOpChoice, [LIST [$LiftAnchor], "Lift Anchor (^A)", "Remove anchor"], [LIST [$MakeAllHot], "Make All Hot (^ss)", "Make all objects hot"], noOpChoice, [LIST [$MakeAllCold], "Make All Cold (^SS)", "Make all objects cold"], [LIST [$StandardAlignments], "Standard Alignments", "Restore standard alignments"] ], -1, FALSE, popUpFont, NIL, quickClickMode]]; unitsMenu: AtomButtons.ButtonLineEntry _ [popUpButton["Units", LIST [ [LIST [$InchScaleUnit], "Inches", "Set unit value to 1 inch"], [LIST [$PrintScaleUnit], "ShowValue", "Print current unit value"], [LIST [$PointsScaleUnit], "Points", "Set unit value to 1 point"], [LIST [$RadiusUnitFromSegment], "FromSegment [G]", "Set unit value to length of selected segment"], [LIST [$RadiusUnitFromValue], "FromRadiusValue", "Set unit value from number in RadiusValue"], [LIST [$RadiusUnitFromSelection], "FromSelection [T]", "Set unit value from number in the Tioga selection"], [LIST [$CentimeterScaleUnit], "Centimeters", "Set unit value to 1 centimeter"] ], -1, FALSE, popUpFont, NIL, quickClickMode]]; nextX _ AtomButtons.BuildButtonLine [svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ selectMenu, hotSpotsMenu, unitsMenu, [twoState["ShowColors", LIST[$ToggleShowColors], FALSE, ShowColorsInit]], [button["ViewStyle:", LIST[LIST[$StylePrompt]] ]], [label["Shaded", ViewStyleInSVData, smallStringSize]], [button["Selected", LIST[LIST[$Selected]], -1, FALSE, NIL, NIL, SelectedInSVData]] ]]; svData.height _ svData.height + entryVSpace + entryHeight; }; BuildGravityLine: PROC [svData: SVData] = { nextX: NAT _ 0; svData.hitTest.gravityTypeMenu _ AtomButtons.BuildEnumTypeSelection[viewer: svData.outer, x: 0, y: svData.height, maxWidth: 144, clientData: svData, handleProc: SVUserInput.EventNotify, title: "GravType:", default: "PreferPoints", borderOnButtons: TRUE, style: flipThru, allInOneRow: TRUE, buttonNames: LIST["PreferFaces", "PreferLines", "PreferPoints"], atom: $GravityChoiceChange]; svData.hitTest.gravityType _ pointsPreferred; nextX _ svData.hitTest.gravityTypeMenu.nextx; nextX _ AtomButtons.BuildButtonLine[ svData.outer, nextX + entryHSpace, svData.height, svData, SVUserInput.EventNotify, LIST[ [label["GravExtent:"]] ]]; nextX _ GraphicsButton.BuildGraphicsButton[ container: svData.outer, x: nextX + entryHSpace, y: svData.height, w: 60, -- changed from 72 to make more room in line h: entryHeight, clientData: svData, choices: LIST[ [LIST[$GravityExtentChange, $ValueUp]], [LIST[$GravityExtentChange, $InitialValue]], [LIST[$GravityExtentChange, $ValueDown]]], handleProc: SVUserInput.EventNotify, repaintProc: GravityExtentRepaint, buttonData: NEW[GravityExtentDataObj _ [extent: SVEditUser.GetDefaultGravityExtent[]]], updateProc: GravityExtentInSVData ]; nextX _ AtomButtons.BuildButtonLine[ svData.outer, nextX + 2*entryHSpace, svData.height, svData, SVUserInput.EventNotify, LIST[ [twoState["Gravity", LIST[$ToggleGravity], TRUE, GravityButtonInit]], [twoState["Midpoints", LIST[$ToggleMidpoints], FALSE, MidpointsButtonInit]], [twoState["Heuristics", LIST[$ToggleHeuristics], SVState.GetDefaultHeuristics[], HeuristicsButtonInit]] ]]; svData.height _ svData.height + entryHeight; }; BuildSpecial3DLine: PROC [svData: SVData] = { nextX: INTEGER; bigStringSize: NAT _ VFonts.StringWidth["///Users/Name.pa/Solidviews/PictureName.pic"]; threeNumberSize: NAT _ VFonts.StringWidth["18, 18, 18"]; nextX _ AtomButtons.BuildButtonLine [svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["CoordsMode", LIST[LIST[$ShowCoordsMode]], -1, FALSE, NIL, NIL, ShowCoordsInSVData]], [button["x,y,z:", LIST[LIST[$XYZPrompt]]]], [text["0, 0, 0", XYZViewInSVData, threeNumberSize]] ]]; svData.height _ svData.height + entryVSpace + entryHeight; }; -- end of BuildSpecial3DLine BuildAzimuthLine: PROC [svData: SVData] = { buttonHandle: AtomButtons.SortedButtonHandle; nextX: NAT _ AtomButtons.BuildButtonLine[svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Azimuth:", LIST[LIST[$AzimuthPrompt]] ]], [button["Get!", LIST[LIST[$GetAzimuth]], getScalarColumn ]], [button["Add!", LIST[LIST[$AddAzimuth]] ]], [button["Delete!", LIST[LIST[$DeleteAzimuth]] ]] ]]; buttonHandle _ AtomButtons.CreateSortedButtonViewer[svData.outer, scalarButtonColumn, svData.height]; svData.hitTest.azimuthHandle _ buttonHandle; SVEvent.StandardAzimuths[LIST[$StandardAzimuths], svData]; svData.height _ svData.height + entryHeight; }; BuildSlopeLine: PROC [svData: SVData] = { buttonHandle: AtomButtons.SortedButtonHandle; nextX: NAT _ AtomButtons.BuildButtonLine[svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Slope:", LIST[LIST[$SlopePrompt]] ]], [button["Get!", LIST[LIST[$GetSlope]], getScalarColumn ]], [button["Add!", LIST[LIST[$AddSlope]] ]], [button["Delete!", LIST[LIST[$DeleteSlope]] ]] ]]; buttonHandle _ AtomButtons.CreateSortedButtonViewer[svData.outer, scalarButtonColumn, svData.height]; svData.hitTest.slopeHandle _ buttonHandle; SVEvent.StandardSlopes[LIST[$StandardSlopes], svData]; svData.height _ svData.height + entryHeight; }; BuildSlopeLineLine: PROC [svData: SVData] = { buttonHandle: AtomButtons.SortedButtonHandle; nextX: NAT _ AtomButtons.BuildButtonLine[svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Line:", LIST[LIST[$SlopeLinePrompt]] ]], [button["New!", LIST[LIST[$NewSlopeLine]], newScalarColumn ]], [button["Get!", LIST[LIST[$GetLine]], getScalarColumn ]], [button["Add!", LIST[LIST[$AddSlopeLine]] ]], [button["Delete!", LIST[LIST[$DeleteSlopeLine]] ]] ]]; buttonHandle _ AtomButtons.CreateSortedButtonViewer[svData.outer, scalarButtonColumn, svData.height]; svData.hitTest.slopeLineHandle _ buttonHandle; SVEvent.StandardSlopeLines[LIST[$StandardSlopeLines], svData]; svData.height _ svData.height + entryHeight; }; BuildSlopePlaneLine: PROC [svData: SVData] = { buttonHandle: AtomButtons.SortedButtonHandle; nextX: NAT _ AtomButtons.BuildButtonLine[svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Plane:", LIST[LIST[$SlopePlanePrompt]] ]], [button["New!", LIST[LIST[$NewSlopePlane]], newScalarColumn ]], [button["Get!", LIST[LIST[$GetLine]], getScalarColumn ]], [button["Add!", LIST[LIST[$AddSlopePlane]] ]], [button["Delete!", LIST[LIST[$DeleteSlopePlane]] ]] ]]; buttonHandle _ AtomButtons.CreateSortedButtonViewer[svData.outer, scalarButtonColumn, svData.height]; svData.hitTest.slopePlaneHandle _ buttonHandle; SVEvent.StandardSlopePlanes[LIST[$StandardSlopePlanes], svData]; svData.height _ svData.height + entryHeight; }; BuildMeasureLine: PROC [svData: SVData] = { nextX: NAT _ AtomButtons.BuildButtonLine[svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["AzimuthValue:", LIST[LIST[$MeasureAzimuthHit]] ]], [text["0.0", AzimuthViewInSVData, smallNumberSize]], [button["SlopeValue:", LIST[LIST[$MeasureSlopeHit]] ]], [text["0.0", SlopeViewInSVData, smallNumberSize]] ]]; svData.height _ svData.height + entryHeight; }; BuildFeedbackLine: PROC [svData: SVData] = { nextX: NAT _ AtomButtons.BuildButtonLine[svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [label["Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Line", FeedbackLineInSVData, fullColumn]] ]]; svData.height _ svData.height + entryHeight; }; <<>> <> ConfirmClear: PUBLIC PROC [clientData: REF ANY] = { svData: SVData _ NARROW[clientData]; scene: Scene _ svData.scene; rope: Rope.ROPE; dirty: BOOL; dirty _ svData.outer.newVersion; IF dirty THEN rope _ "Confirm discard of edits" ELSE rope _ "Confirm emptying of viewer"; Feedback.AppendHerald[svData.feedback, rope, oneLiner]; }; ConfirmReset: PUBLIC PROC [clientData: REF ANY] = { svData: SVData _ NARROW[clientData]; scene: Scene _ svData.scene; dirty: BOOL; dirty _ svData.outer.newVersion; IF dirty THEN Feedback.PutFHerald[svData.feedback, oneLiner, "Confirm discard of edits"] ELSE Feedback.PutFHerald[svData.feedback, oneLiner, "Confirm reset of %g", [rope[scene.name]]]; }; -- end of ConfirmReset ConfirmSave: PUBLIC PROC [clientData: REF ANY] = { svData: SVData _ NARROW[clientData]; scene: Scene _ svData.scene; exists: BOOL; rope: Rope.ROPE; exists _ SVFiles.FileExists[scene.name]; IF exists THEN rope _ IO.PutFR["Confirm Save to %g [Old File]", [rope[scene.name]]] ELSE { rope _ IO.PutFR["%g doesn't exist. Use Store", [rope[scene.name]]]; Feedback.Blink[svData.feedback] }; Feedback.Append[svData.feedback, rope, oneLiner]; }; ConfirmStore: PUBLIC PROC [clientData: REF ANY] = { svData: SVData _ NARROW[clientData]; editToolData: EditToolData _ NARROW[svData.editToolData]; scene: Scene _ svData.scene; picName: Rope.ROPE _ ViewerTools.GetSelectionContents[]; fullName, wdir: Rope.ROPE; exists: BOOL; success: BOOL _ TRUE; rope: Rope.ROPE; IF Rope.Length[picName] = 0 THEN { Feedback.Append[svData.feedback, "Please select a file name.", oneLiner]; Feedback.Blink[svData.feedback]; RETURN; }; wdir _ editToolData.originalWorkingDirectory; [fullName,,] _ FS.ExpandName[picName, wdir ! FS.Error => IF error.group = user THEN { Feedback.Append[svData.feedback, Rope.Concat["Store: ", error.explanation], oneLiner]; success _ FALSE; CONTINUE; } ]; exists _ SVFiles.FileExists[fullName]; IF exists THEN rope _ IO.PutFR["Confirm Store of %g [Old File]", [rope[fullName]]] ELSE rope _ IO.PutFR["Confirm Store to %g [New File]", [rope[fullName]]]; Feedback.AppendHerald[svData.feedback, rope, oneLiner]; }; ConfirmGet: PUBLIC PROC [clientData: REF ANY] = { svData: SVData _ NARROW[clientData]; editToolData: EditToolData _ NARROW[svData.editToolData]; scene: Scene _ svData.scene; picName: Rope.ROPE _ ViewerTools.GetSelectionContents[]; fullName, wdir: Rope.ROPE; success: BOOL _ TRUE; dirty: BOOL; IF Rope.Length[picName] = 0 THEN { Feedback.Append[svData.feedback, "Please select a file name.", oneLiner]; Feedback.Blink[svData.feedback]; RETURN; }; wdir _ editToolData.originalWorkingDirectory; [fullName,,] _ FS.ExpandName[picName, wdir ! FS.Error => IF error.group = user THEN { Feedback.Append[svData.feedback, Rope.Concat["Get: ", error.explanation], oneLiner]; success _ FALSE; CONTINUE; } ]; IF NOT success THEN RETURN; dirty _ svData.outer.newVersion; IF dirty THEN Feedback.PutF[svData.feedback, oneLiner, "Confirm discard of edits and load of %g", [rope[fullName]]] ELSE Feedback.PutF[svData.feedback, oneLiner, "Confirm load of %g", [rope[fullName]]]; }; -- end of ConfirmGet <<>> <> ShapesMenu: Menus.ClickProc = { svData: SVData _ NARROW[clientData]; menu: LIST OF PopUpMenuEntry; menu _ LIST [ ["Block", LIST [$AddBlock, $Add]] ]; QueuePopUpMenuAction["Shapes", menu, svData, mouseButton#blue]; }; DebugMenu: Menus.ClickProc = { svData: SVData _ NARROW[clientData]; menu: LIST OF PopUpMenuEntry; menu _ LIST [ ["DrawBoundBoxes", LIST [$DrawBoundBoxes]], ["DrawBoundSpheres", LIST [$DrawBoundSpheres]], ["DrawCoordSystems", LIST [$DrawCoordSystems]], ["DrawPoint", LIST [$DrawPoint]], ["Draw Selection Box", LIST [$DrawSelectionBox]], ["CrossHairs", LIST [$CrossHairs]], ["KillSelections", LIST [$KillSelectionsButton]], ["DeleteJacks", LIST [$DeleteJacksButton]], ["TestGravity", LIST [$TestGravity]], ["Reset Statistics", LIST [$ResetStatistics]], ["Print Statistics", LIST [$PrintStatistics]], ["Raise SIGNAL", LIST [$RaiseSIGNAL]] ]; QueuePopUpMenuAction["Debug", menu, svData, mouseButton#blue]; }; CastRaysMenu: Menus.ClickProc = { svData: SVData _ NARROW[clientData]; menu: LIST OF PopUpMenuEntry _ LIST [ ["RayCast", LIST [$RayCast]], ["StopRays", LIST [$StopRays]], ["ARay", LIST [$ARay]] ]; choices: LIST OF Rope.ROPE _ ExtractChoiceList[menu]; index: NAT _ PopUpSelection.Request[header: "SVCastRays", choice: choices]; SELECT index FROM =0 => RETURN; =1 => SVEvent.RayCast[LIST[$RayCast], svData]; =2 => SVEvent.StopRays[LIST[$StopRays], svData]; =3 => SVEvent.ARay[LIST[$ARay], svData]; ENDCASE => ERROR; <> }; ScriptMenu: Menus.ClickProc = { svData: SVData _ NARROW[clientData]; menu: LIST OF PopUpMenuEntry _ LIST [ ["OpenScript", LIST [$ScriptAction, $Open]], ["AppendToScript", LIST [$ScriptAction, $Append]], ["CloseScript", LIST [$ScriptAction, $Close]], ["PlaybackScript", LIST [$ScriptAction, $Playback]], ["FastPlayScript", LIST [$ScriptAction, $FastPlay]] ]; choices: LIST OF Rope.ROPE _ ExtractChoiceList[menu]; index: NAT _ PopUpSelection.Request[header: "Script", choice: choices]; SELECT index FROM =0 => RETURN; =1 => SVEvent.OpenScript[parent, clientData, mouseButton, shift, control]; =2 => SVEvent.AppendToScript[parent, clientData, mouseButton, shift, control]; =3 => SVEvent.CloseScript[parent, clientData, mouseButton, shift, control]; =4 => SVEvent.PlaybackScript[parent, clientData, mouseButton, shift, control]; =5 => SVEvent.FastPlayScript[parent, clientData, mouseButton, shift, control]; ENDCASE => ERROR; }; ConfirmRayCast: PUBLIC PROC [clientData: REF ANY] = { svData: SVData _ NARROW[clientData]; exists: BOOL; aisFileRope: Rope.ROPE; redRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisFileRope], "-red.ais"]; greenRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisFileRope], "-green.ais"]; blueRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisFileRope], "-blue.ais"]; rope: Rope.ROPE; <> exists _ SVFiles.FileExists[aisFileRope]; rope _ IO.PutFR["Confirm raycast to %g.", [rope[aisFileRope]]]; IF exists THEN rope _ Rope.Concat[rope, " [Old File]"] ELSE rope _ Rope.Concat[rope, " [New File]"]; <<}>> <> <> <> <> <> <<};>> Feedback.AppendHerald[svData.feedback, rope, oneLiner]; }; ReviveButton: Menus.ClickProc = { svData: SVData _ NARROW[clientData]; SVMouseEvent.ResetMouseMachinery[svData]; CodeTimer.ResetTable[CodeTimer.GetTable[$Solidviews]]; SlackProcess.Restart[svData.slackHandle]; svData.refresh.suppressRefresh _ FALSE; svData.aborted _ ALL[FALSE]; IF mouseButton#blue THEN SVWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, svData: svData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE] }; <<>> <