<> <> <> <> <<>> DIRECTORY AtomButtons, AtomButtonsTypes, Buttons, CodeTimer, Feedback, FS, GraphicsButton, Imager, IO, Menus, PopUpSelection, Rope, SlackProcess, SV2d, SV3d, SVDraw, SVEditUser, SVEvent, SVFiles, SVInterfaceTypes, SVMenus, SVModelTypes, SVMouseEvent, SVSceneTypes, SVUserInput, SVWindow, VFonts, ViewerClasses, ViewerTools; SVMenusImpl: CEDAR PROGRAM IMPORTS AtomButtons, Buttons, CodeTimer, Feedback, FS, GraphicsButton, Imager, IO, PopUpSelection, Rope, SlackProcess, SVDraw, SVEditUser, SVEvent, SVFiles, SVMouseEvent, 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; MouseButton: TYPE = Menus.MouseButton; Plane: TYPE = SV3d.Plane; Point2d: TYPE = SV2d.Point2d; Scene: TYPE = SVSceneTypes.Scene; 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; fullColumn: CARDINAL = 600; -- the width of the standard large left column. boldFont: 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]; BuildGravityLine[svData]; BuildSpecial3DLine[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, boldFont ]]; 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, 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] ]]; svData.height _ svData.height + entryVSpace + entryHeight; }; 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] }; BuildMasterMenuLine: PROC [svData: SVData] = { << This section implements a set of buttons, text windows, and options listers in this format:>> <> nextX: INTEGER; nextX _ AtomButtons.BuildUnQueuedButtonLine [svData.outer, 0, svData.height, svData, LIST[ ["Debug", button, DebugMenu, NIL, 0, -1, FALSE, NIL, boldFont] ]]; nextX _ AtomButtons.BuildButtonLine [svData.outer, nextX, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Refresh!", LIST[LIST[$DrawSceneButton]]]], [button["DrawColor", LIST[LIST[$DrawColor]]]], [button["DrawB&W", LIST[LIST[$DrawBlackAndWhite]]]], [button["KillSelections", LIST[LIST[$KillSelectionsButton]]]], [button["DeleteJacks", LIST[LIST[$DeleteJacksButton]]]] ]]; svData.height _ svData.height + entryVSpace + entryHeight; }; -- end of BuildMasterMenuLine GravityExtentData: TYPE = REF GravityExtentDataObj; GravityExtentDataObj: TYPE = SVInterfaceTypes.GravityExtentDataObj; GravityExtentRepaint: PROC [dc: Imager.Context, clientData: REF ANY, buttonData: REF ANY, button: Viewer] = { caretPoint: Point2d; ged: GravityExtentData _ NARROW[buttonData]; extent: REAL _ ged.extent; Imager.TranslateT[dc, [button.ww, button.wh/2.0]]; caretPoint _ [-extent, 0.0]; SVDraw.DrawCaret[dc, caretPoint]; }; 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["StrictDistance", "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 ]; [svData.hitTest.gravButton, nextX] _ AtomButtons.BuildTwoStateButton[viewer: svData.outer, x: nextX + 2*entryHSpace, y: svData.height, clientData: svData, handleProc: SVUserInput.EventNotify, name: "Gravity", action: LIST[$ToggleGravity], init: on]; [svData.hitTest.midpointButton, nextX] _ AtomButtons.BuildTwoStateButton[viewer: svData.outer, x: nextX + entryHSpace, y: svData.height, clientData: svData, handleProc: SVUserInput.EventNotify, name: "Midpoints", action: LIST[$ToggleMidpoints], init: off]; <<[svData.hitTest.heuristicsButton, nextX] _>> <> <> <> <> <> <> svData.height _ svData.height + entryHeight; }; BuildSpecial3DLine: PROC [svData: SVData] = { << This section implements a set of buttons, text windows, and options listers in this format:>> < Style: x,y,z: Selected 2Buffer>> < Kill Selections DeleteJacks>> nextX: INTEGER; bigStringSize: NAT _ VFonts.StringWidth["///Users/Name.pa/Solidviews/PictureName.pic"]; smallStringSize: NAT _ VFonts.StringWidth["WireframeStyle"]; threeNumberSize: NAT _ VFonts.StringWidth["18, 18, 18"]; nextX _ AtomButtons.BuildButtonLine [svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Style:", LIST[LIST[$StylePrompt]] ]], [label["Shaded", SceneStyleInSVData, smallStringSize]], [button["CoordsMode", LIST[LIST[$ShowCoordsMode]], -1, FALSE, NIL, NIL, ShowCoordsInSVData]], [button["x,y,z:", LIST[LIST[$XYZPrompt]]]], [text["0, 0, 0", XYZViewInSVData, threeNumberSize]], [button["Selected", LIST[LIST[$Selected]], -1, FALSE, NIL, NIL, SelectedInSVData]], [button["2Buffer", LIST[LIST[$DoubleBuffer]], -1, FALSE, NIL, NIL, DoubleBufferInSVData]] ]]; svData.height _ svData.height + entryVSpace + entryHeight; }; -- end of BuildSpecial3DLine 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 <<>> <> 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]], ["TestGravity", LIST [$TestGravity]], ["Reset Statistics", LIST [$ResetStatistics]], ["Print Statistics", LIST [$PrintStatistics]] ]; 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; }; <> <> <> <> <<["ToIP", LIST [$ToIP]],>> <<["StorePoly", LIST [$StorePoly]]>> <<];>> <> <<};>> 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]; }; <<>> <> GravityExtentInSVData: AtomButtonsTypes.UpdateGraphicsButtonProc = { svData: SVData _ NARROW[clientData]; svData.hitTest.gravityExtentButton _ stateInfo; }; <> FeedbackLineInSVData: AtomButtonsTypes.InitButtonProc = { svData: SVData _ NARROW[clientData]; feedback: FeedbackData _ Feedback.RegisterFeedback[button, $Solidviews]; svData.feedback _ feedback; }; <<>> <> ShowCoordsInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.textSection.showCoords _ button; }; SceneStyleInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.textSection.viewStyle _ button; }; SelectedInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.textSection.selected _ button; }; XYZViewInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.textSection.xyz _ button; }; DoubleBufferInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.textSection.doubleBuffer _ button; Buttons.SetDisplayStyle[svData.textSection.doubleBuffer, $WhiteOnBlack]; }; Init: PROC = { boldFont _ VFonts.EstablishFont[family: "Helvetica", size: 10, bold: TRUE, italic: FALSE, defaultOnFailure: TRUE]; }; Init[]; END.